linux input设备驱动

一. 输入设备结构体

     1. input_dev 输入设备

  1. struct input_dev {  
  2.     const char *name;       //设备名  
  3.     const char *phys;       //设备系统层的物理路径  
  4.     const char *uniq;       //  
  5.     struct input_id id; //输入设备id 总线类型;厂商编号,产品id,产品版本  
  6.   
  7.     unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //事件类型标志位  
  8.     unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];   //键盘事件标志位  
  9.     unsigned long relbit[BITS_TO_LONGS(REL_CNT)];   //相对位移事件标志位  
  10.     unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];   //绝对位移事件标志位  
  11.     unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];   //杂项事件标志位  
  12.     unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];   //led指示灯标志位  
  13.     unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];   //声音事件  
  14.     unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; //强制反馈事件  
  15.     unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; //开关事件标志位  
  16.   
  17.     unsigned int hint_events_per_packet;  
  18.     unsigned int keycodemax;        //键盘码表大小  
  19.     unsigned int keycodesize;       //键盘码大小  
  20.     void *keycode;          //键盘码表指针  
  21.   
  22.     int (*setkeycode)(struct input_dev *dev,unsigned int scancode, unsigned int keycode);   //设置键盘码  
  23.     int (*getkeycode)(struct input_dev *dev,unsigned int scancode, unsigned int *keycode);  //获取键盘码  
  24.     int (*setkeycode_new)(struct input_dev *dev,const struct input_keymap_entry *ke,unsigned int *old_keycode);   
  25.     int (*getkeycode_new)(struct input_dev *dev,struct input_keymap_entry *ke);  
  26.   
  27.     struct ff_device *ff;   //强制反馈设备  
  28.     unsigned int repeat_key;    //重复按键标志位  
  29.     struct timer_list timer;    //定时器  
  30.     int rep[REP_CNT];       //重复次数  
  31.     struct input_mt_slot *mt;  
  32.     int mtsize;  
  33.     int slot;  
  34.     struct input_absinfo *absinfo;  
  35.     unsigned long key[BITS_TO_LONGS(KEY_CNT)];  //  
  36.     unsigned long led[BITS_TO_LONGS(LED_CNT)];  //  
  37.     unsigned long snd[BITS_TO_LONGS(SND_CNT)];  //  
  38.     unsigned long sw[BITS_TO_LONGS(SW_CNT)];    //  
  39.   
  40.     int (*open)(struct input_dev *dev);     //open方法  
  41.     void (*close)(struct input_dev *dev);   //close方法  
  42.     int (*flush)(struct input_dev *dev, struct file *file);  
  43.     int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);  
  44.   
  45.     struct input_handle __rcu *grab;  
  46.     spinlock_t event_lock;  
  47.     struct mutex mutex;  
  48.     unsigned int users;  
  49.     bool going_away;  
  50.     bool sync;  
  51.     struct device dev;      //设备文件  
  52.     struct list_head    h_list; //input_handler处理器链表头  
  53.     struct list_head    node;   //input_device设备链表头  
  54. };  

      2. input_handler 输入处理器

  1. struct input_handler {  
  2.     void *private;  //私有数据  
  3.     void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);    //事件处理  
  4.     bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);   //过滤器  
  5.     bool (*match)(struct input_handler *handler, struct input_dev *dev);    //设备匹配  
  6.     int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); //设备连接  
  7.     void (*disconnect)(struct input_handle *handle);    //设备断开连接  
  8.     void (*start)(struct input_handle *handle);  
  9.     const struct file_operations *fops; //输入操作函数集  
  10.     int minor;  //次设备号  
  11.     const char *name;   //设备名  
  12.     const struct input_device_id *id_table; //输入设备 id表  
  13.     struct list_head    h_list; //input_handler处理器链表头  
  14.     struct list_head    node;   //input_device设备链表头  
  15. };  

 

二. 输入系统初始化

     1 input_init

  1. static int __init input_init(void)  
  2. {  
  3.     int err;  
  4.   
  5.     err = class_register(&input_class); //注册类 创建"/sys/input"   
  6.     if (err) {  
  7.         printk(KERN_ERR "input: unable to register input_dev class\n");  
  8.         return err;  
  9.     }  
  10.   
  11.     err = input_proc_init();    //初始化"/proc/bus/input"接口  
  12.     if (err)  
  13.         goto fail1;  
  14.   
  15.     err = register_chrdev(INPUT_MAJOR, "input", &input_fops);   //注册所有输入字符设备,并捆绑input_fops  
  16.     if (err) {  
  17.         printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);  
  18.         goto fail2;  
  19.     }  
  20.   
  21.     return 0;  
  22.   
  23.  fail2: input_proc_exit();  
  24.  fail1: class_unregister(&input_class);  
  25.     return err;  
  26. }  

     2. /proc 接口

     2.1 创建/proc/bus/input下的文件

  1. static int __init input_proc_init(void)  
  2. {  
  3.     struct proc_dir_entry *entry;  
  4.   
  5.     proc_bus_input_dir = proc_mkdir("bus/input", NULL); //创建"/proc/bus/input"  
  6.     if (!proc_bus_input_dir)  
  7.         return -ENOMEM;  
  8.   
  9.     entry = proc_create("devices", 0, proc_bus_input_dir,&input_devices_fileops);   //创建"/proc/bus/input/devices"  
  10.     if (!entry)  
  11.         goto fail1;  
  12.   
  13.     entry = proc_create("handlers", 0, proc_bus_input_dir,&input_handlers_fileops); //创建"/proc/bus/input/handlers"  
  14.     if (!entry)  
  15.         goto fail2;  
  16.   
  17.     return 0;  
  18.   
  19.  fail2: remove_proc_entry("devices", proc_bus_input_dir);  
  20.  fail1: remove_proc_entry("bus/input", NULL);  
  21.     return -ENOMEM;  
  22. }  

     2.2 devices文件 

  1. static const struct file_operations input_devices_fileops = {  
  2.     .owner      = THIS_MODULE,  
  3.     .open       = input_proc_devices_open,  
  4.     .poll       = input_proc_devices_poll,  
  5.     .read       = seq_read,  
  6.     .llseek     = seq_lseek,  
  7.     .release    = seq_release,  
  8. };  

    2.2.1 限于篇幅及省略啰嗦

这里当我们去cat /proc/bus/input/devices时候,会调用input_proc_devices_open函数,接着调用seq_open(file, &input_devices_seq_ops),捆绑了input_devices_seq_ops操作函数集,

其seq_operations函数集中声明了.show方法为input_devices_seq_show,该方法打印了些信息到seq文件,接着cat命令会调用read方法,read方法会调用.show方法,

接着把打印到文件的信息复制用户空间的缓冲区中.这里主要看看.show方法吧

     2.2.2 input_devices_seq_show

  1. static int input_devices_seq_show(struct seq_file *seq, void *v)  
  2. {  
  3.     struct input_dev *dev = container_of(v, struct input_dev, node);    //获取到输入设备结构体  
  4.     const char *path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); //获取在/sys下的路径  
  5.     struct input_handle *handle;  
  6.   
  7.     seq_printf(seq, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n",dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version);  
  8.     //打印I:总线类型,厂商id,产品id,版本号   
  9.     seq_printf(seq, "N: Name=\"%s\"\n", dev->name ? dev->name : "");  //打印N:输入设备名  
  10.     seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : "");  //打印P:phys  
  11.     seq_printf(seq, "S: Sysfs=%s\n", path ? path : ""); //打印S:sysfs文件系统下的路径  
  12.     seq_printf(seq, "U: Uniq=%s\n", dev->uniq ? dev->uniq : "");  //打印U:uniq  
  13.     seq_printf(seq, "H: Handlers=");    //打印H:input_handler处理器名  
  14.   
  15.     list_for_each_entry(handle, &dev->h_list, d_node)    //遍历处理器链表  
  16.         seq_printf(seq, "%s ", handle->name);  
  17.     seq_putc(seq, '\n');  
  18.   
  19.     input_seq_print_bitmap(seq, "EV", dev->evbit, EV_MAX);   //打印EV:事件类型位图  
  20.     if (test_bit(EV_KEY, dev->evbit))                    //打印各种具体事件的事件位图  
  21.         input_seq_print_bitmap(seq, "KEY", dev->keybit, KEY_MAX);      
  22.     if (test_bit(EV_REL, dev->evbit))  
  23.         input_seq_print_bitmap(seq, "REL", dev->relbit, REL_MAX);  
  24.     if (test_bit(EV_ABS, dev->evbit))  
  25.         input_seq_print_bitmap(seq, "ABS", dev->absbit, ABS_MAX);  
  26.     if (test_bit(EV_MSC, dev->evbit))  
  27.         input_seq_print_bitmap(seq, "MSC", dev->mscbit, MSC_MAX);  
  28.     if (test_bit(EV_LED, dev->evbit))  
  29.         input_seq_print_bitmap(seq, "LED", dev->ledbit, LED_MAX);  
  30.     if (test_bit(EV_SND, dev->evbit))  
  31.         input_seq_print_bitmap(seq, "SND", dev->sndbit, SND_MAX);  
  32.     if (test_bit(EV_FF, dev->evbit))  
  33.         input_seq_print_bitmap(seq, "FF", dev->ffbit, FF_MAX);  
  34.     if (test_bit(EV_SW, dev->evbit))  
  35.         input_seq_print_bitmap(seq, "SW", dev->swbit, SW_MAX);  
  36.   
  37.     seq_putc(seq, '\n');  
  38.   
  39.     kfree(path);  
  40.     return 0;  
  41. }  

打印效果大致如下:因设备不同而异

  1. cat devices   
  2. I: Bus=0019 Vendor=0000 Product=0001 Version=0000  
  3. N: Name="Power Button"        
  4. P: Phys=LNXPWRBN/button/input0  
  5. S: Sysfs=/devices/LNXSYSTM:00/LNXPWRBN:00/input/input0  
  6. U: Uniq=  
  7. H: Handlers=kbd event0   
  8. B: EV=3  
  9. B: KEY=100000 0 0 0  
  10.   
  11. I: Bus=0017 Vendor=0001 Product=0001 Version=0100  
  12. N: Name="Macintosh mouse button emulation"  
  13. P: Phys=  
  14. S: Sysfs=/devices/virtual/input/input1  
  15. U: Uniq=  
  16. H: Handlers=mouse0 event1   
  17. B: EV=7  
  18. B: KEY=70000 0 0 0 0 0 0 0 0  
  19. B: REL=3  

这里可以根据Bus值得知该输入设备是基于什么总线的

  1. #define BUS_PCI     0x01  
  2. #define BUS_ISAPNP      0x02  
  3. #define BUS_USB     0x03  
  4. #define BUS_HIL     0x04  
  5. #define BUS_BLUETOOTH   0x05  
  6. #define BUS_VIRTUAL 0x06  
  7. #define BUS_ISA     0x10  
  8. #define BUS_I8042       0x11  
  9. #define BUS_XTKBD       0x12  
  10. #define BUS_RS232       0x13  
  11. #define BUS_GAMEPORT    0x14  
  12. #define BUS_PARPORT 0x15  
  13. #define BUS_AMIGA       0x16  
  14. #define BUS_ADB     0x17  
  15. #define BUS_I2C     0x18  
  16. #define BUS_HOST        0x19  
  17. #define BUS_GSC     0x1A  
  18. #define BUS_ATARI       0x1B  
  19. #define BUS_SPI     0x1C  

 

     2.3 handlers文件

  1. static const struct file_operations input_handlers_fileops = {  
  2.     .owner      = THIS_MODULE,  
  3.     .open       = input_proc_handlers_open,  
  4.     .read       = seq_read,  
  5.     .llseek     = seq_lseek,  
  6.     .release    = seq_release,  
  7. };  

     2.3.1 
这里当我们去cat /proc/bus/input/handlers时候,会调用input_proc_handlers_open函数,接着调用seq_open(file, &input_handlers_seq_ops),捆绑了input_handlers_seq_ops操作函数集,
其seq_operations函数集中声明了.show方法为input_handlers_seq_show,该方法打印了些信息到seq文件,接着cat命令会调用read方法,read方法会调用.show方法,
接着把打印到文件的信息复制用户空间的缓冲区中.这里主要看看.show方法吧

  1. static int input_handlers_seq_show(struct seq_file *seq, void *v)  
  2. {  
  3.     struct input_handler *handler = container_of(v, struct input_handler, node);    //获得输入处理器  
  4.     union input_seq_state *state = (union input_seq_state *)&seq->private;  
  5.   
  6.     seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);   //打印N:Number=序号 name=设备名  
  7.     if (handler->filter)  
  8.         seq_puts(seq, " (filter)");  
  9.     if (handler->fops)  
  10.         seq_printf(seq, " Minor=%d", handler->minor);        //打印Minor=次设备号  
  11.     seq_putc(seq, '\n');  
  12.   
  13.     return 0;  
  14. }  

我的打印是

  1. cat handlers   
  2. N: Number=0 Name=rfkill  
  3. N: Number=1 Name=kbd  
  4. N: Number=2 Name=mousedev Minor=32  
  5. N: Number=3 Name=evdev Minor=64  

     3. 字符设备接口

     3.1 主设备号

  1. #define INPUT_MAJOR     13  

     3.2 input_fops

  1. static const struct file_operations input_fops = {  
  2.     .owner = THIS_MODULE,  
  3.     .open = input_open_file,    //打开方法  
  4.     .llseek = noop_llseek,    
  5. };  

    3.2.1 input_open_file

  1. static int input_open_file(struct inode *inode, struct file *file)  
  2. {  
  3.     struct input_handler *handler;  
  4.     const struct file_operations *old_fops, *new_fops = NULL;  
  5.     int err;  
  6.   
  7.     err = mutex_lock_interruptible(&input_mutex);  
  8.     if (err)  
  9.         return err;  
  10.   
  11.     /* No load-on-demand here? */  
  12.     handler = input_table[iminor(inode) >> 5];    //根据节点算出次设备号,并在全局input_table找到输入处理器  
  13.     if (handler)  
  14.         new_fops = fops_get(handler->fops);  //获取输入操作函数集指针  
  15.   
  16.     mutex_unlock(&input_mutex);  
  17.   
  18.     /* 
  19.      * That's _really_ odd. Usually NULL ->open means "nothing special", 
  20.      * not "no device". Oh, well... 
  21.      */  
  22.     if (!new_fops || !new_fops->open) {  //判断输入操作函数集的存在且存在open方法  
  23.         fops_put(new_fops);   
  24.         err = -ENODEV;  
  25.         goto out;  
  26.     }  
  27.   
  28.     old_fops = file->f_op;   //获取文件的操作函数集指针  
  29.     file->f_op = new_fops;   //替换为输入操作函数集指针  
  30.   
  31.     err = new_fops->open(inode, file);   //调用输入操作函数集的open方法  
  32.     if (err) {  
  33.         fops_put(file->f_op);  
  34.         file->f_op = fops_get(old_fops);  
  35.     }  
  36.     fops_put(old_fops);  
  37. out:  
  38.     return err;  
  39. }  


三. 分配input_dev

  1. struct input_dev *input_allocate_device(void)  
  2. {  
  3.     struct input_dev *dev;  
  4.   
  5.     dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);    //分配内存  
  6.     if (dev) {  
  7.         dev->dev.type = &input_dev_type; //设置设备文件  
  8.         dev->dev.class = &input_class;   //设置类  
  9.         device_initialize(&dev->dev);    //初始化设备文件  
  10.         mutex_init(&dev->mutex);  
  11.         spin_lock_init(&dev->event_lock);  
  12.         INIT_LIST_HEAD(&dev->h_list);    //初始化input_handler链表头  
  13.         INIT_LIST_HEAD(&dev->node);  
  14.         __module_get(THIS_MODULE);  
  15.     }  
  16.   
  17.     return dev;  
  18. }  

四. 设置输入设备类型

      1.设置标志位的辅助宏

  1. #define setbit(a, i)    (((u8 *)a)[(i)/NBBY] |= 1<<((i)%NBBY))    //设置标志位(eg:setbit(EV_KEY,my_input_dev.evbit))  
  2. #define clrbit(a, i)    (((u8 *)a)[(i)/NBBY] &= ~(1<<((i)%NBBY))) //清除标志位(eg:setbit(REL_Z,my_input_dev.relbit))  
  3. #define isset(a, i) (((const u8 *)a)[(i)/NBBY] & (1<<((i)%NBBY)))     //检测某标志位是否设置  
  4. #define isclr(a, i) ((((const u8 *)a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)  //检测某标志位是否清除  

      2.设置事件类型标志位ev_bit

  1. #define EV_SYN          0x00    //同步事件  
  2. #define EV_KEY          0x01    //键盘事件  
  3. #define EV_REL          0x02    //相对位移事件  
  4. #define EV_ABS          0x03    //绝对位移事件  
  5. #define EV_MSC          0x04    //杂项事件  
  6. #define EV_SW           0x05    //开关事件  
  7. #define EV_LED          0x11    //led指示灯事件  
  8. #define EV_SND          0x12    //声音事件  
  9. #define EV_REP          0x14    //重复事件  
  10. #define EV_FF           0x15    //强制反馈事件  
  11. #define EV_PWR          0x16  
  12. #define EV_FF_STATUS        0x17  
  13. #define EV_MAX          0x1f  
  14. #define EV_CNT          (EV_MAX+1  

      3.设置对应事件的标志位

标志位的值在include/linux/Input.h中有详细定义

五. 注册注销输入设备

     1.1 注册输入设备

  1. int input_register_device(struct input_dev *dev)  
  2. {  
  3.     static atomic_t input_no = ATOMIC_INIT(0);  //原子变量,标记注册的个数  
  4.     struct input_handler *handler;  
  5.     const char *path;  
  6.     int error;  
  7.   
  8.     __set_bit(EV_SYN, dev->evbit);   //添加同步事件  
  9.     __clear_bit(KEY_RESERVED, dev->keybit);  //清除保留键  
  10.     input_cleanse_bitmasks(dev);    //清除位掩码  
  11.     init_timer(&dev->timer); //初始化定时器  
  12.     if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {  //若没设置重复延时和重复周期  
  13.         dev->timer.data = (long) dev;        //设置定时器数据  
  14.         dev->timer.function = input_repeat_key;  //设置定时器中断响应函数  
  15.         dev->rep[REP_DELAY] = 250;   //设置延时时间  
  16.         dev->rep[REP_PERIOD] = 33;   //设置重复周期  
  17.     }  
  18.     if (!dev->getkeycode && !dev->getkeycode_new) //若没定义获取键盘码的函数  
  19.         dev->getkeycode_new = input_default_getkeycode;  //则设置为系统默认的获取键盘码函数  
  20.     if (!dev->setkeycode && !dev->setkeycode_new) //若没定义设置键盘码的函数  
  21.         dev->setkeycode_new = input_default_setkeycode;  //则设置为系统默认的设置键盘码函数  
  22.     dev_set_name(&dev->dev, "input%ld",(unsigned long) atomic_inc_return(&input_no) - 1);    //设置输入设备名字-->"/sys/class/input/input%d"  
  23.     error = device_add(&dev->dev);   //添加设备  
  24.     if (error)  
  25.         return error;  
  26.     path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);  
  27.     printk(KERN_INFO "input: %s as %s\n",dev->name ? dev->name : "Unspecified device", path ? path : "N/A");  
  28.     kfree(path);  
  29.     error = mutex_lock_interruptible(&input_mutex);  
  30.     if (error) {  
  31.         device_del(&dev->dev);  
  32.         return error;  
  33.     }  
  34.     list_add_tail(&dev->node, &input_dev_list);  //将其设备添加到全局输入设备链表  
  35.     list_for_each_entry(handler, &input_handler_list, node) //遍历全局输入处理器链表  
  36.         input_attach_handler(dev, handler); //匹配input_dev和input_handler  
  37.     input_wakeup_procfs_readers();  
  38.     mutex_unlock(&input_mutex);  
  39.     return 0;  
  40. }  

     1.2 注销输入设备

  1. void input_unregister_device(struct input_dev *dev)  
  2. {  
  3.     struct input_handle *handle, *next;  
  4.     input_disconnect_device(dev);   //断开设备连接  
  5.     mutex_lock(&input_mutex);  
  6.     list_for_each_entry_safe(handle, next, &dev->h_list, d_node) //遍历输入处理器链表  
  7.         handle->handler->disconnect(handle);  //查找到对应项并调用其断开连接函数  
  8.     WARN_ON(!list_empty(&dev->h_list));  
  9.     del_timer_sync(&dev->timer); //移除定时器  
  10.     list_del_init(&dev->node);       //逆初始化设备  
  11.     input_wakeup_procfs_readers();    
  12.     mutex_unlock(&input_mutex);  
  13.     device_unregister(&dev->dev);    //注销设备  
  14. }  

六. 输入处理器

     1.输入处理器的驱动,内核已经帮我们设计好了 eg:evdev.c,tsdev.c,joydev.c,keyboard.c,mousedev.c

     2. 以mousedev.c为蓝本分析下处理器驱动的设计

     2.1 mousedev_handler的定义

  1. static struct input_handler mousedev_handler = {  
  2.     .event =    mousedev_event, //事件处理函数(设备上报输入事件给到处理器,处理器调用此函数解析)  
  3.     .connect =  mousedev_connect,   //连接(处理器和设备匹配后调用)  
  4.     .disconnect =   mousedev_disconnect,    //断开  
  5.     .fops =     &mousedev_fops, //操作函数集  
  6.     .minor =        MOUSEDEV_MINOR_BASE,    //次设备号  
  7.     .name =     "mousedev"//设备名  
  8.     .id_table = mousedev_ids,  
  9. };  

    2.1.1  mousedev_ids

input_device_id的结构体在处理器与设备匹配的时候会用上,mousedev_ids罗列了鼠标的大致分类,flags标记了需要匹配的事件类型

  1. static const struct input_device_id mousedev_ids[] = {  
  2.     {  
  3.         .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,  
  4.         .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) },  
  5.         .keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) },  
  6.         .relbit = { BIT_MASK(REL_X) | BIT_MASK(REL_Y) },  
  7.     },  /* A mouse like device, at least one button,two relative axes */  
  8.     {  
  9.         .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_RELBIT,  
  10.         .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) },  
  11.         .relbit = { BIT_MASK(REL_WHEEL) },  
  12.     },  /* A separate scrollwheel */  
  13.     {  
  14.         .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,  
  15.         .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },  
  16.         .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },  
  17.         .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },  
  18.     },  /* A tablet like device, at least touch detection,two absolute axes */  
  19.     {  
  20.         .flags = INPUT_DEVICE_ID_MATCH_EVBIT |INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,  
  21.         .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },  
  22.         .keybit = { [BIT_WORD(BTN_TOOL_FINGER)] =BIT_MASK(BTN_TOOL_FINGER) },  
  23.         .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |BIT_MASK(ABS_PRESSURE) |BIT_MASK(ABS_TOOL_WIDTH) },  
  24.     },  /* A touchpad */  
  25.     {  
  26.         .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT |INPUT_DEVICE_ID_MATCH_ABSBIT,  
  27.         .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },  
  28.         .keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) },  
  29.         .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },  
  30.     },  /* Mouse-like device with absolute X and Y but ordinaryclicks, like hp ILO2 High Performance mouse */  
  31.   
  32.     { },    /* Terminating entry */  
  33. };  

     2.2 处理器的注册

  1. int input_register_handler(struct input_handler *handler)  
  2. {  
  3.     struct input_dev *dev;  
  4.     int retval;  
  5.     retval = mutex_lock_interruptible(&input_mutex);  
  6.     if (retval)  
  7.         return retval;  
  8.     INIT_LIST_HEAD(&handler->h_list);    //初始化处理器链表头  
  9.     if (handler->fops != NULL) {  
  10.         if (input_table[handler->minor >> 5]) {    //判断是否已经注册  
  11.             retval = -EBUSY;  
  12.             goto out;  
  13.         }  
  14.         input_table[handler->minor >> 5] = handler;    //填充全局input_table表  
  15.     }  
  16.     list_add_tail(&handler->node, &input_handler_list);  //添加输入处理器到全局输入处理器链表  
  17.     list_for_each_entry(dev, &input_dev_list, node) //遍历全局输入设链表  
  18.         input_attach_handler(dev, handler);     //匹配input_device和input_handler  
  19.     input_wakeup_procfs_readers();  
  20.  out:  
  21.     mutex_unlock(&input_mutex);  
  22.     return retval;  
  23. }  

     2.3 处理器的注销

  1. void input_unregister_handler(struct input_handler *handler)  
  2. {  
  3.     struct input_handle *handle, *next;  
  4.     mutex_lock(&input_mutex);  
  5.     list_for_each_entry_safe(handle, next, &handler->h_list, h_node)  
  6.         handler->disconnect(handle); //调用断开连接函数  
  7.     WARN_ON(!list_empty(&handler->h_list));  
  8.     list_del_init(&handler->node);   //删除输入设备链表  
  9.     if (handler->fops != NULL)  
  10.         input_table[handler->minor >> 5] = NULL;   //清空全局输入处理器表  
  11.     input_wakeup_procfs_readers();  
  12.     mutex_unlock(&input_mutex);  
  13. }  


七. 设备的匹配

     1.在输入设备或者输入处理器注册的时候都会遍历全局链表input_handler_list或input_dev_list并调用input_attach_handler寻找匹配项

  1. static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)  
  2. {  
  3.     const struct input_device_id *id;  
  4.     int error;  
  5.   
  6.     id = input_match_device(handler, dev);  //匹配input_handler和input_dev获取input_device_id  
  7.     if (!id)  
  8.         return -ENODEV;  
  9.   
  10.     error = handler->connect(handler, dev, id);  //匹配到则调用其input_handler的连接方法  
  11.     if (error && error != -ENODEV)  
  12.         printk(KERN_ERR"input: failed to attach handler %s to device %s,error: %d\n",handler->name, kobject_name(&dev->dev.kobj), error);  
  13.   
  14.     return error;  
  15. }  

     2.input_match_device

  1. static const struct input_device_id *input_match_device(struct input_handler *handler,struct input_dev *dev)  
  2. {  
  3.     const struct input_device_id *id;  
  4.     int i;  
  5.   
  6.     for (id = handler->id_table; id->flags || id->driver_info; id++) {  
  7.   
  8.         if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)  
  9.             if (id->bustype != dev->id.bustype)   //判断总线类型  
  10.                 continue;  
  11.   
  12.         if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)  
  13.             if (id->vendor != dev->id.vendor) //判断厂商id  
  14.                 continue;  
  15.   
  16.         if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)  
  17.             if (id->product != dev->id.product)   //判断产品id  
  18.                 continue;  
  19.   
  20.         if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)  
  21.             if (id->version != dev->id.version)   //判断版本  
  22.                 continue;  
  23.   
  24.         MATCH_BIT(evbit,  EV_MAX);  //匹配各个标志位  
  25.         MATCH_BIT(keybit, KEY_MAX);  
  26.         MATCH_BIT(relbit, REL_MAX);  
  27.         MATCH_BIT(absbit, ABS_MAX);  
  28.         MATCH_BIT(mscbit, MSC_MAX);  
  29.         MATCH_BIT(ledbit, LED_MAX);  
  30.         MATCH_BIT(sndbit, SND_MAX);  
  31.         MATCH_BIT(ffbit,  FF_MAX);  
  32.         MATCH_BIT(swbit,  SW_MAX);  
  33.   
  34.         if (!handler->match || handler->match(handler, dev))  //若input_handler存在match方法则调用其方法  
  35.             return id;  
  36.     }  
  37.   
  38.     return NULL;  
  39. }  

八. 事件的处理

     1.设备需要上报事件(一般在中断处理函数中上报)

  1. static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)    //上报键盘事件  
  2. {  
  3.     input_event(dev, EV_KEY, code, !!value);  
  4. }  
  5.   
  6. static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)    //上报相对位移事件  
  7. {  
  8.     input_event(dev, EV_REL, code, value);  
  9. }  
  10.   
  11. static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)    //上报绝对位移事件  
  12. {  
  13.     input_event(dev, EV_ABS, code, value);  
  14. }  
  15.   
  16. static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value)  //上报强制反馈事件  
  17. {  
  18.     input_event(dev, EV_FF_STATUS, code, value);  
  19. }  
  20.   
  21. static inline void input_report_switch(struct input_dev *dev, unsigned int code, int value)     //上报开关事件  
  22. {  
  23.     input_event(dev, EV_SW, code, !!value);  
  24. }  
  25.   
  26. static inline void input_sync(struct input_dev *dev)    //上报同步事件----在上报完其他事件后必须上报同步事件通知对应的输入处理器  
  27. {  
  28.     input_event(dev, EV_SYN, SYN_REPORT, 0);  
  29. }  

     2.所有上报事件都会调用到input_event函数

  1. void input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)  
  2. {  
  3.     unsigned long flags;  
  4.     if (is_event_supported(type, dev->evbit, EV_MAX)) {  //判断对应的input_dev是否支持该事件  
  5.         spin_lock_irqsave(&dev->event_lock, flags);  
  6.         add_input_randomness(type, code, value);  
  7.         input_handle_event(dev, NULL, type, code, value);   //输入事件处理句柄  
  8.         spin_unlock_irqrestore(&dev->event_lock, flags);  
  9.     }  
  10. }  

     3.input_handle_event函数

  1. static void input_handle_event(struct input_dev *dev,struct input_handler *src_handler,unsigned int type, unsigned int code, int value)  
  2. {  
  3.     int disposition = INPUT_IGNORE_EVENT;  
  4.     switch (type) { //判断事件类型  
  5.     case EV_SYN:    //同步事件  
  6.         switch (code) {  
  7.         case SYN_CONFIG:  
  8.             disposition = INPUT_PASS_TO_ALL;    //这里有个宏#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)  
  9.             break;  
  10.   
  11.         case SYN_REPORT:  
  12.             if (!dev->sync) {  
  13.                 dev->sync = true;  
  14.                 disposition = INPUT_PASS_TO_HANDLERS;  
  15.             }  
  16.             break;  
  17.         case SYN_MT_REPORT:  
  18.             dev->sync = false;  
  19.             disposition = INPUT_PASS_TO_HANDLERS;  
  20.             break;  
  21.         }  
  22.         break;  
  23.   
  24.     case EV_KEY:    //键盘事件  
  25.         if (is_event_supported(code, dev->keybit, KEY_MAX) && !!test_bit(code, dev->key) != value) {  
  26.   
  27.             if (value != 2) {  
  28.                 __change_bit(code, dev->key);  
  29.                 if (value)  
  30.                     input_start_autorepeat(dev, code);  
  31.                 else  
  32.                     input_stop_autorepeat(dev);  
  33.             }  
  34.   
  35.             disposition = INPUT_PASS_TO_HANDLERS;  
  36.         }  
  37.         break;  
  38.   
  39.     case EV_SW: //开关事件  
  40.         if (is_event_supported(code, dev->swbit, SW_MAX) &&!!test_bit(code, dev->sw) != value) {  
  41.             __change_bit(code, dev->sw);  
  42.             disposition = INPUT_PASS_TO_HANDLERS;  
  43.         }  
  44.         break;  
  45.   
  46.     case EV_ABS:    //绝对位移事件  
  47.         if (is_event_supported(code, dev->absbit, ABS_MAX))  
  48.             disposition = input_handle_abs_event(dev, src_handler,code, &value);  
  49.   
  50.         break;  
  51.   
  52.     case EV_REL:    //相对位移事件  
  53.         if (is_event_supported(code, dev->relbit, REL_MAX) && value)  
  54.             disposition = INPUT_PASS_TO_HANDLERS;  
  55.   
  56.         break;  
  57.   
  58.     case EV_MSC:    //杂项事件  
  59.         if (is_event_supported(code, dev->mscbit, MSC_MAX))  
  60.             disposition = INPUT_PASS_TO_ALL;  
  61.   
  62.         break;  
  63.   
  64.     case EV_LED:    //led事件  
  65.         if (is_event_supported(code, dev->ledbit, LED_MAX) &&  
  66.             !!test_bit(code, dev->led) != value) {  
  67.   
  68.             __change_bit(code, dev->led);  
  69.             disposition = INPUT_PASS_TO_ALL;  
  70.         }  
  71.         break;  
  72.   
  73.     case EV_SND:    //声音事件  
  74.         if (is_event_supported(code, dev->sndbit, SND_MAX)) {  
  75.   
  76.             if (!!test_bit(code, dev->snd) != !!value)  
  77.                 __change_bit(code, dev->snd);  
  78.             disposition = INPUT_PASS_TO_ALL;  
  79.         }  
  80.         break;  
  81.   
  82.     case EV_REP:    //重复事件  
  83.         if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {  
  84.             dev->rep[code] = value;  
  85.             disposition = INPUT_PASS_TO_ALL;  
  86.         }  
  87.         break;  
  88.   
  89.     case EV_FF: //强制反馈事件  
  90.         if (value >= 0)  
  91.             disposition = INPUT_PASS_TO_ALL;  
  92.         break;  
  93.   
  94.     case EV_PWR:    //电源事件  
  95.         disposition = INPUT_PASS_TO_ALL;  
  96.         break;  
  97.     }  
  98.   
  99.     if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)  
  100.         dev->sync = false;  
  101.   
  102.     if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)  
  103.         dev->event(dev, type, code, value);  //根据事件类型不同,部分事件会先调用到input_dev的事件处理函数  
  104.   
  105.     if (disposition & INPUT_PASS_TO_HANDLERS)  
  106.         input_pass_event(dev, src_handler, type, code, value);  //直接传递事件给对应事件的输入处理器处理  
  107. }  

    4.input_pass_event

  1. static void input_pass_event(struct input_dev *dev,struct input_handler *src_handler,unsigned int type, unsigned int code, int value)  
  2. {  
  3.     struct input_handler *handler;  
  4.     struct input_handle *handle;  
  5.     rcu_read_lock();  
  6.     handle = rcu_dereference(dev->grab);  
  7.     if (handle)  
  8.         handle->handler->event(handle, type, code, value);    //调用处理器的event方法  
  9.     else {  
  10.         bool filtered = false;  
  11.   
  12.         list_for_each_entry_rcu(handle, &dev->h_list, d_node) {  
  13.             if (!handle->open)  
  14.                 continue;  
  15.   
  16.         handler = handle->handler;  
  17.   
  18.         if (handler == src_handler)  
  19.             continue;  
  20.   
  21.         if (!handler->filter) {  
  22.             if (filtered)  
  23.                 break;  
  24.             handler->event(handle, type, code, value);  
  25.   
  26.         } else if (handler->filter(handle, type, code, value))  
  27.                 filtered = true;  
  28.         }  
  29.     }  
  30.   
  31.     rcu_read_unlock();  
  32. }  


  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值