input子系统

来源:互联网 发布:龙信数据怎么样 编辑:程序博客网 时间:2024/06/06 00:51

1、简介

1.1 概述

为输入设备(按键、键盘、触摸屏)的驱动规范完成上报输入信息任务的子系统。input是对字符设备驱动的另一种封装。
input子系统在驱动中不是必须的,它的存在只是规范了上报输入信息这一任务,减少驱动与应用开发工程师的沟通成本。
input子系统是输入设备驱动一个标准,一个约定俗成的规范,几乎所有输入设备驱动都是使用input来上报输入信息的

在Linux中,Input子系统由三大部分组成,它们是Input子系统核心层、Input子系统事件处理层和Input子系统设备驱动层。在通常情况下,Input子系统核心层和Input子系统事件处理层都已经实现了,而作为驱动开发者,我们仅仅只需要完成Input子系统设备驱动层。

1.2 编写流程

1、定义一个input_dev结构体
2、申请input_dev内存空间并初始化
3、填充input_dev部分成员
4、向core注册一个input_dev
5、获取键码并上报按键(一般在中断里)
注:input是对字符设备驱动的封装,它在底层实现了file_operations这一套机制而不用我们去填充了,只需按照以上流程即可完成驱动

1.3 主要结构体

//linux/input.hstruct input_dev{    const char *name;       //设备名    const char *phys;       //设备在系统中路径    const char *uniq;    struct input_id id;     //用于匹配input hander参数    unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];    //设备所支持事件类型,主要有EV_SYNC,EV_KEY,EV_REL,EV_ABS等                    unsigned long evbit[BITS_TO_LONGS(EV_CNT)];        //按键所对应的位图                              unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];                         //相对坐标对应位图    unsigned long relbit[BITS_TO_LONGS(REL_CNT)];                           /绝对坐标对应位图    unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];                           unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];    unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];    unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];    unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];    unsigned long swbit[BITS_TO_LONGS(SW_CNT)];    unsigned int hint_events_per_packet;    unsigned int keycodemax;    unsigned int keycodesize;    void *keycode;    int (*setkeycode)(struct input_dev *dev,  const struct input_keymap_entry *ke,  unsigned int *old_keycode);    int (*getkeycode)(struct input_dev *dev, struct input_keymap_entry *ke);    struct ff_device *ff;    unsigned int repeat_key;    struct timer_list timer;    int rep[REP_CNT];    struct input_mt_slot *mt;    int mtsize;    int slot;    int trkid;    struct input_absinfo *absinfo;    //按键对应的键值    unsigned long key[BITS_TO_LONGS(KEY_CNT)];                                     //LED对应的指示灯状态    unsigned long led[BITS_TO_LONGS(LED_CNT)];                                      unsigned long snd[BITS_TO_LONGS(SND_CNT)];    unsigned long sw[BITS_TO_LONGS(SW_CNT)];    int (*open)(struct input_dev *dev);                                             void (*close)(struct input_dev *dev);    int (*flush)(struct input_dev *dev, struct file *file);    //事件处理函数,主要是接收用户下发的命令,如点亮led;    int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);    struct input_handle __rcu *grab;    spinlock_t event_lock;    struct mutex mutex;    unsigned int users;    bool going_away;    bool sync;    struct device dev;    //设备所支持的input handle;     struct list_headh_list;                        struct list_headnode;};

evbit的值主要有

EV_SYN 同步事件EV_KEY 按键事件EV_REL 相对坐标事件EV_ABS 绝对坐标事件

keybit的值主要有

#define     KEY_Q                   16#define     KEY_W                   17#define     KEY_E                   18#define     KEY_R                   19#define     KEY_T                   20

1.3.2 input_dev的赋值

1.3.2.1 直接赋值

evbit[0]= BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY);keybit[BIT_WORD(KEY_D)] |= BIT_MASK(KEY_D);

1.3.2.2 函数赋值

set_bit(nr,addr);参数nr:要置1的那个位;参数addr:数组首地址set_bit( EV_SYN , evbit);set_bit( EV_KEY , evbit);set_bit( KEY_D , keybit);

1.4 主要方法

//申请、初始化input_devstruct input_dev *input_allocate_device(void);//注册input_devint input_register_device(struct input_dev *dev);//注销input_devvoid input_unregister_device(struct input_dev *dev);//上报input_report_key(struct input_dev *dev, unsigned int code, int value);code: 键码(填充结构体时已经注册支持)value:按下1 或 抬起0//同步input_sync(struct input_dev *dev);

2、demo 基于iTop4412

不完整的demo 主要介绍input使用流程

#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/uaccess.h>#include <linux/device.h>#include <asm/io.h>#include <linux/interrupt.h>#include <linux/irq.h>#include <mach/gpio.h>#include <plat/gpio-cfg.h>#include <linux/workqueue.h>#include <linux/delay.h>#include <linux/platform_device.h>#include <asm/atomic.h>#include <linux/input.h>#define DEMO_DEBUG#ifdef  DEMO_DEBUG#define dem_dbg(fmt, arg...)        printk(KERN_WARNING fmt, ##arg)#else#define dem_dbg(fmt, arg...)        printk(KERN_DEBUG fmt, ##arg)#endif#define KEY_CODE    KEY_LEFTstatic struct input_dev *input_key;static int open_flag = 0;static int dev_id = 123;static int irq;//中断回调static irqreturn_t eint9_interrupt(int irq, void *dev_id) {    int gpio_val = 0;    printk("%s(%d)\n", __FUNCTION__, __LINE__);    /*延时去抖的改进,两次获取电平,如果是抖动直接返回*/    gpio_val = gpio_get_value(EXYNOS4_GPX1(1));    msleep(50);    if(gpio_val != gpio_get_value(EXYNOS4_GPX1(1)))        return IRQ_HANDLED;    if(gpio_val == 0){  //汇报按下事件        input_report_key(input_key, KEY_CODE, 1);    }else{  //汇报抬起事件        input_report_key(input_key, KEY_CODE, 0);    }    //汇报同步事件    input_sync(input_key);    return IRQ_HANDLED;}static int key_open(struct input_dev *dev){    dem_dbg("==> %s\n", __FUNCTION__);    if(open_flag++ == 0)        enable_irq(IRQ_EINT(19));       //打开中断    return 0;}static void key_close(struct input_dev *dev){    dem_dbg("==> %s\n", __FUNCTION__);    if(open_flag-- == 0)        disable_irq(IRQ_EINT(19));  }static int key_probe(struct platform_device *pdev){    int retval;    struct resource *res = NULL;    res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);    if (res == NULL) {        dem_dbg("==> no memory resource specified\n");        return PTR_ERR(res);    }    irq = res->start;    //申请中断    retval = request_irq(irq, eint9_interrupt,            IRQ_TYPE_EDGE_FALLING /*IRQF_TRIGGER_FALLING*/, "eint9", (void *)&dev_id);    if (retval < 0) {        printk("Request IRQ %d failed, %d\n", IRQ_EINT(9), retval);        goto exit;    }    disable_irq(irq);   //中断关闭    //1 申请input_dev结构体变量空间    input_key = input_allocate_device();    if (!input_key) {        dem_dbg("==> allocate input device failed!\n");        retval = -ENOMEM;        goto input_alloc_err;    }    //2 input_dev结构体变量初始化    input_key->name = "key";            //查看cat /proc/bus/input/devices    input_key->phys = "inputkey";    input_key->id.bustype = BUS_HOST;    input_key->id.vendor = 0x0001;    input_key->id.product = 0x0001;    input_key->id.version = 0x0100;    //指定input设备所支持的事件:按键事件、同步事件、连续长按键事件    input_key->evbit[0] = BIT(EV_KEY) | BIT(EV_SYN) | BIT(EV_REP);    //指定input设备支持汇报的键值: KEY_CODE宏指定的KEY_LEFT    set_bit(KEY_CODE, input_key->keybit);    input_key->open =   key_open;    input_key->close = key_close;    //3 input_dev结构体的注册    retval = input_register_device(input_key);    if (retval) {        dem_dbg("==> Failed to register input device!\n");        goto input_regs_err;    }    return 0;input_regs_err:    input_free_device(input_key);input_alloc_err:    free_irq(irq, (void *)&dev_id);exit:    return retval;}static int key_remove(struct platform_device *dev){    dem_dbg("==> in module exit function\n");    free_irq(irq, (void *)&dev_id);    //4 input_dev结构体的注销和释放    input_unregister_device(input_key);    input_free_device(input_key);    return 0;}static struct platform_driver key_driver = {    .probe = key_probe,    .remove = key_remove,    .driver = {        .owner = THIS_MODULE,        .name = "demo_input",    },};static int __init demo_init(void){       dem_dbg("==>demo_init\n");    return platform_driver_register(&key_driver);}static void __exit demo_exit(void){    dem_dbg("==>demo_exit\n");    platform_driver_unregister(&key_driver);}module_init(demo_init);module_exit(demo_exit);MODULE_LICENSE("Dual BSD/GPL");
原创粉丝点击