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. unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //事件类型标志位
  7. unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //键盘事件标志位
  8. unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //相对位移事件标志位
  9. unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //绝对位移事件标志位
  10. unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; //杂项事件标志位
  11. unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; //led指示灯标志位
  12. unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; //声音事件
  13. unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; //强制反馈事件
  14. unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; //开关事件标志位
  15. unsigned int hint_events_per_packet;
  16. unsigned int keycodemax; //键盘码表大小
  17. unsigned int keycodesize; //键盘码大小
  18. void *keycode; //键盘码表指针
  19. int (*setkeycode)(struct input_dev *dev,unsigned int scancode, unsigned int keycode); //设置键盘码
  20. int (*getkeycode)(struct input_dev *dev,unsigned int scancode, unsigned int *keycode); //获取键盘码
  21. int (*setkeycode_new)(struct input_dev *dev,const struct input_keymap_entry *ke,unsigned int *old_keycode);
  22. int (*getkeycode_new)(struct input_dev *dev,struct input_keymap_entry *ke);
  23. struct ff_device *ff; //强制反馈设备
  24. unsigned int repeat_key; //重复按键标志位
  25. struct timer_list timer; //定时器
  26. int rep[REP_CNT]; //重复次数
  27. struct input_mt_slot *mt;
  28. int mtsize;
  29. int slot;
  30. struct input_absinfo *absinfo;
  31. unsigned long key[BITS_TO_LONGS(KEY_CNT)]; //
  32. unsigned long led[BITS_TO_LONGS(LED_CNT)]; //
  33. unsigned long snd[BITS_TO_LONGS(SND_CNT)]; //
  34. unsigned long sw[BITS_TO_LONGS(SW_CNT)]; //
  35. int (*open)(struct input_dev *dev); //open方法
  36. void (*close)(struct input_dev *dev); //close方法
  37. int (*flush)(struct input_dev *dev, struct file *file);
  38. int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
  39. struct input_handle __rcu *grab;
  40. spinlock_t event_lock;
  41. struct mutex mutex;
  42. unsigned int users;
  43. bool going_away;
  44. bool sync;
  45. struct device dev; //设备文件
  46. struct list_head h_list; //input_handler处理器链表头
  47. struct list_head node; //input_device设备链表头
  48. };

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. err = class_register(&input_class); //注册类 创建"/sys/input"
  5. if (err) {
  6. printk(KERN_ERR "input: unable to register input_dev class\n");
  7. return err;
  8. }
  9. err = input_proc_init(); //初始化"/proc/bus/input"接口
  10. if (err)
  11. goto fail1;
  12. err = register_chrdev(INPUT_MAJOR, "input", &input_fops); //注册所有输入字符设备,并捆绑input_fops
  13. if (err) {
  14. printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
  15. goto fail2;
  16. }
  17. return 0;
  18. fail2: input_proc_exit();
  19. fail1: class_unregister(&input_class);
  20. return err;
  21. }

2. /proc 接口

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

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

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. 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);
  7. //打印I:总线类型,厂商id,产品id,版本号
  8. seq_printf(seq, "N: Name=\"%s\"\n", dev->name ? dev->name : ""); //打印N:输入设备名
  9. seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : ""); //打印P:phys
  10. seq_printf(seq, "S: Sysfs=%s\n", path ? path : ""); //打印S:sysfs文件系统下的路径
  11. seq_printf(seq, "U: Uniq=%s\n", dev->uniq ? dev->uniq : ""); //打印U:uniq
  12. seq_printf(seq, "H: Handlers="); //打印H:input_handler处理器名
  13. list_for_each_entry(handle, &dev->h_list, d_node) //遍历处理器链表
  14. seq_printf(seq, "%s ", handle->name);
  15. seq_putc(seq, '\n');
  16. input_seq_print_bitmap(seq, "EV", dev->evbit, EV_MAX); //打印EV:事件类型位图
  17. if (test_bit(EV_KEY, dev->evbit)) //打印各种具体事件的事件位图
  18. input_seq_print_bitmap(seq, "KEY", dev->keybit, KEY_MAX);
  19. if (test_bit(EV_REL, dev->evbit))
  20. input_seq_print_bitmap(seq, "REL", dev->relbit, REL_MAX);
  21. if (test_bit(EV_ABS, dev->evbit))
  22. input_seq_print_bitmap(seq, "ABS", dev->absbit, ABS_MAX);
  23. if (test_bit(EV_MSC, dev->evbit))
  24. input_seq_print_bitmap(seq, "MSC", dev->mscbit, MSC_MAX);
  25. if (test_bit(EV_LED, dev->evbit))
  26. input_seq_print_bitmap(seq, "LED", dev->ledbit, LED_MAX);
  27. if (test_bit(EV_SND, dev->evbit))
  28. input_seq_print_bitmap(seq, "SND", dev->sndbit, SND_MAX);
  29. if (test_bit(EV_FF, dev->evbit))
  30. input_seq_print_bitmap(seq, "FF", dev->ffbit, FF_MAX);
  31. if (test_bit(EV_SW, dev->evbit))
  32. input_seq_print_bitmap(seq, "SW", dev->swbit, SW_MAX);
  33. seq_putc(seq, '\n');
  34. kfree(path);
  35. return 0;
  36. }

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

  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. I: Bus=0017 Vendor=0001 Product=0001 Version=0100
  11. N: Name="Macintosh mouse button emulation"
  12. P: Phys=
  13. S: Sysfs=/devices/virtual/input/input1
  14. U: Uniq=
  15. H: Handlers=mouse0 event1
  16. B: EV=7
  17. B: KEY=70000 0 0 0 0 0 0 0 0
  18. 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. seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name); //打印N:Number=序号 name=设备名
  6. if (handler->filter)
  7. seq_puts(seq, " (filter)");
  8. if (handler->fops)
  9. seq_printf(seq, " Minor=%d", handler->minor); //打印Minor=次设备号
  10. seq_putc(seq, '\n');
  11. return 0;
  12. }

我的打印是

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


三. 分配input_dev

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

四. 设置输入设备类型

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

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. { }, /* Terminating entry */
  32. };

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. id = input_match_device(handler, dev); //匹配input_handler和input_dev获取input_device_id
  6. if (!id)
  7. return -ENODEV;
  8. error = handler->connect(handler, dev, id); //匹配到则调用其input_handler的连接方法
  9. if (error && error != -ENODEV)
  10. printk(KERN_ERR"input: failed to attach handler %s to device %s,error: %d\n",handler->name, kobject_name(&dev->dev.kobj), error);
  11. return error;
  12. }

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

八. 事件的处理

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

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. case SYN_REPORT:
  11. if (!dev->sync) {
  12. dev->sync = true;
  13. disposition = INPUT_PASS_TO_HANDLERS;
  14. }
  15. break;
  16. case SYN_MT_REPORT:
  17. dev->sync = false;
  18. disposition = INPUT_PASS_TO_HANDLERS;
  19. break;
  20. }
  21. break;
  22. case EV_KEY: //键盘事件
  23. if (is_event_supported(code, dev->keybit, KEY_MAX) && !!test_bit(code, dev->key) != value) {
  24. if (value != 2) {
  25. __change_bit(code, dev->key);
  26. if (value)
  27. input_start_autorepeat(dev, code);
  28. else
  29. input_stop_autorepeat(dev);
  30. }
  31. disposition = INPUT_PASS_TO_HANDLERS;
  32. }
  33. break;
  34. case EV_SW: //开关事件
  35. if (is_event_supported(code, dev->swbit, SW_MAX) &&!!test_bit(code, dev->sw) != value) {
  36. __change_bit(code, dev->sw);
  37. disposition = INPUT_PASS_TO_HANDLERS;
  38. }
  39. break;
  40. case EV_ABS: //绝对位移事件
  41. if (is_event_supported(code, dev->absbit, ABS_MAX))
  42. disposition = input_handle_abs_event(dev, src_handler,code, &value);
  43. break;
  44. case EV_REL: //相对位移事件
  45. if (is_event_supported(code, dev->relbit, REL_MAX) && value)
  46. disposition = INPUT_PASS_TO_HANDLERS;
  47. break;
  48. case EV_MSC: //杂项事件
  49. if (is_event_supported(code, dev->mscbit, MSC_MAX))
  50. disposition = INPUT_PASS_TO_ALL;
  51. break;
  52. case EV_LED: //led事件
  53. if (is_event_supported(code, dev->ledbit, LED_MAX) &&
  54. !!test_bit(code, dev->led) != value) {
  55. __change_bit(code, dev->led);
  56. disposition = INPUT_PASS_TO_ALL;
  57. }
  58. break;
  59. case EV_SND: //声音事件
  60. if (is_event_supported(code, dev->sndbit, SND_MAX)) {
  61. if (!!test_bit(code, dev->snd) != !!value)
  62. __change_bit(code, dev->snd);
  63. disposition = INPUT_PASS_TO_ALL;
  64. }
  65. break;
  66. case EV_REP: //重复事件
  67. if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
  68. dev->rep[code] = value;
  69. disposition = INPUT_PASS_TO_ALL;
  70. }
  71. break;
  72. case EV_FF: //强制反馈事件
  73. if (value >= 0)
  74. disposition = INPUT_PASS_TO_ALL;
  75. break;
  76. case EV_PWR: //电源事件
  77. disposition = INPUT_PASS_TO_ALL;
  78. break;
  79. }
  80. if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
  81. dev->sync = false;
  82. if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
  83. dev->event(dev, type, code, value); //根据事件类型不同,部分事件会先调用到input_dev的事件处理函数
  84. if (disposition & INPUT_PASS_TO_HANDLERS)
  85. input_pass_event(dev, src_handler, type, code, value); //直接传递事件给对应事件的输入处理器处理
  86. }

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. list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
  12. if (!handle->open)
  13. continue;
  14. handler = handle->handler;
  15. if (handler == src_handler)
  16. continue;
  17. if (!handler->filter) {
  18. if (filtered)
  19. break;
  20. handler->event(handle, type, code, value);
  21. } else if (handler->filter(handle, type, code, value))
  22. filtered = true;
  23. }
  24. }
  25. rcu_read_unlock();
  26. }


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值