Input子系统上报按键--模板,让开发更简易

Posted 太阳德生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Input子系统上报按键--模板,让开发更简易相关的知识,希望对你有一定的参考价值。

        按键多是采用GPIO检测的,有用GPIO电平触发的,也有用边沿触发的,这都只是中断的触发方式不一样,为了保证采集的可靠性,可以采用延时处理,比如触发中断了后30ms以后我再读一下这个GPIO的值是不是还是跟预期一样的,如果不一样,可能就要丢弃这次的IRQ处理。在延迟处理线程里面要获取按键的值,按照定义对照,上报到系统上去,通过input_report_key(),前面当然需要一个input设备,采用input_register_device(),如何注册IRQ处理。

         整个处理比较简单,有这样的一个小模板,我们在开发的时候速度会快很多,有了模板,基本的框架肯定是不会错的,错可能就错在我们后面加的一些代码上:)调试定位也会更加清晰。这样做模块不大好的地方,降低了开发难度,长期依赖可能会造成开发水平的下降:)所以要经常复习,多学习!模块总体来说是好的,降低一些体力劳动工作量!让精力留在更需要关注的地方,搞清楚了原理,其实就都只是那么回事。

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/of.h>                   /* For DT*/
#include <linux/platform_device.h>      /* For platform devices */
#include <linux/gpio/consumer.h>        /* For GPIO Descriptor interface */
#include <linux/input.h>
#include <linux/interrupt.h>


struct btn_data {
    struct gpio_desc *btn_gpiod;
    struct input_dev *i_dev;
    struct platform_device *pdev;
    int irq;
};

static int btn_open(struct input_dev *i_dev)
{
    pr_info("input device opened()\\n");
    return 0;
}

static void btn_close(struct input_dev *i_dev)
{
    pr_info("input device closed()\\n");
}

static irqreturn_t packt_btn_interrupt(int irq, void *dev_id)
{
    struct btn_data *priv = dev_id;

    input_report_key(priv->i_dev, BTN_0, gpiod_get_value(priv->btn_gpiod) & 1);
    input_sync(priv->i_dev);
    return IRQ_HANDLED;
}

static const struct of_device_id btn_dt_ids[] = {
    { .compatible = "packt,input-button", },
    { /* sentinel */ }
};

static int btn_probe(struct platform_device *pdev)
{
    struct btn_data *priv;
    struct gpio_desc *gpiod;
    struct input_dev *i_dev;
    int ret;

    priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
    if (!priv)
        return -ENOMEM;

    i_dev = input_allocate_device();
    if (!i_dev)
        return -ENOMEM;

    i_dev->open = btn_open;
    i_dev->close = btn_close;
    i_dev->name = "Packt Btn";
    i_dev->dev.parent = &pdev->dev;
    priv->i_dev = i_dev;
    priv->pdev = pdev;

    /* Declare the events generated by this driver */
    set_bit(EV_KEY, i_dev->evbit);
    set_bit(BTN_0, i_dev->keybit); /* buttons */

    /* We assume this GPIO is active high */
    gpiod = gpiod_get(&pdev->dev, "button", GPIOD_IN);
    if (IS_ERR(gpiod))
        return -ENODEV;

    priv->irq = gpiod_to_irq(priv->btn_gpiod);
    priv->btn_gpiod = gpiod;

    ret = input_register_device(priv->i_dev);
    if (ret) {
        pr_err("Failed to register input device\\n");
        goto err_input;
    }

    ret = request_any_context_irq(priv->irq,
                    packt_btn_interrupt,
                    (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),
                    "packt-input-button", priv);
    if (ret < 0) {
        dev_err(&pdev->dev,
            "Unable to acquire interrupt for GPIO line\\n");
        goto err_btn;
    }

    platform_set_drvdata(pdev, priv);
    return 0;

err_btn:
    gpiod_put(priv->btn_gpiod);
err_input:
    input_free_device(i_dev);
    return ret;
}

static int btn_remove(struct platform_device *pdev)
{
    struct btn_data *priv;
    priv = platform_get_drvdata(pdev);
    input_unregister_device(priv->i_dev);
    input_free_device(priv->i_dev);
    free_irq(priv->irq, priv);
    gpiod_put(priv->btn_gpiod);
    return 0;
}

static struct platform_driver mypdrv = {
    .probe      = btn_probe,
    .remove     = btn_remove,
    .driver     = {
        .name     = "input-button",
        .of_match_table = of_match_ptr(btn_dt_ids),  
        .owner    = THIS_MODULE,
    },
};
module_platform_driver(mypdrv);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("John Madieu <john.madieu@gmail.com>");
MODULE_DESCRIPTION("Input device (IRQ based)");

以上是关于Input子系统上报按键--模板,让开发更简易的主要内容,如果未能解决你的问题,请参考以下文章

i.MX6ULL驱动开发 | 21 - 按键驱动使用 input 子系统上报事件

i.MX6ULL驱动开发 | 21 - 按键驱动使用 input 子系统上报事件

Linux——Linux驱动之使用输入子系统设计按键驱动实战(输入子系统基本概念代码获取上报信息相关函数解析)

基于输入子系统的按键驱动程序

android 虚拟按键是通过哪种机制上报的?

Android input命令