Input之我见01——设备驱动初探

Input之我见01——设备驱动初探

在我们日常接触的计算机模型中,可以抽象成输入模块、输出模块和运算单元。随着技术不断发展革新,输入、输出设备都有着不同程度的发展。尤其是输入设备,让人机交互有了很大变化。在Android系统中,对于输出设备事件是处理是基本linux的输入子系统,同时也有了自己的特征。我试图通过自己整理资料、研究代码、调试跟踪来理清之间的脉络,同时也是Android系统一个从底层到上层的脉络。由于某些方面的局限,也许无法能解决你心中所有疑问,希望对你有所启发。如果文中有不错误疏漏的,也欢迎你提意见。
该小节先讲Linux Input子系统的内容

先看一下Linux Input子系统架构图

在Kernel里面主要分三层,设备驱动层、Input Core、事件驱动层。

相关数据结构

  • 静态数据结构
存储Input设备的信息,主要位于input.h
  1. struct input_id {
  2. __u16 bustype;
  3. __u16 vendor;
  4. __u16 product;
  5. __u16 version;
  6. };
input_event用于存储每一次传输的数据,这是个固定大小的结构体。
  1. struct input_event {
  2. struct timeval time;
  3. __u16 type;
  4. __u16 code;
  5. __s32 value;
  6. };
其中type定义在Kernel(3.14)的Input子系统中,定义如下18种Input事件,常用的也就是前面5,6种
  1. /* Events */
  2. #define EV_SYN 0x00 //用于同步
  3. #define EV_KEY 0x01 //用于按键,遥控器等,键值的输入设备
  4. #define EV_REL 0x02 //相对事件,用于鼠标的输入
  5. #define EV_ABS 0x03 //绝对事件,用于触摸屏
  6. #define EV_MSC 0x04
  7. #define EV_LED 0x11
  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
在Android7.0的EventHub中,对底层的事件类型,作了自己的分类,但有相应的对应关系
  1. EventHub.h
  2. /*
  3. * Input device classes.
  4. */
  5. enum {
  6. /* The input device is a keyboard or has buttons. */
  7. INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001,
  8. /* The input device is an alpha-numeric keyboard (not just a dial pad). */
  9. INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002,
  10. /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */
  11. INPUT_DEVICE_CLASS_TOUCH = 0x00000004,
  12. ...
  13. };

  • 动态数据结构
在Input事件驱动层,以dvdev为例
input_handler:input管理者
  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. ......
  10. struct list_head h_list;
  11. struct list_head node;
  12. };
input_handle:input设备的句柄
  1. struct input_handle {
  2. void *private;
  3. int open;
  4. const char *name;
  5. struct input_dev *dev;
  6. struct input_handler *handler;
  7. struct list_head d_node;
  8. struct list_head h_node;
  9. };
input_dev:input设备
  1. struct input_dev {
  2. const char *name;
  3. const char *phys;
  4. const char *uniq;
  5. struct input_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. ....
  10. int (*setkeycode)(struct input_dev *dev,
  11. const struct input_keymap_entry *ke,
  12. unsigned int *old_keycode);
  13. int (*getkeycode)(struct input_dev *dev,
  14. struct input_keymap_entry *ke);
  15. ...
  16. unsigned long key[BITS_TO_LONGS(KEY_CNT)];
  17. unsigned long led[BITS_TO_LONGS(LED_CNT)];
  18. unsigned long snd[BITS_TO_LONGS(SND_CNT)];
  19. unsigned long sw[BITS_TO_LONGS(SW_CNT)];
  20. int (*open)(struct input_dev *dev);
  21. void (*close)(struct input_dev *dev);
  22. int (*flush)(struct input_dev *dev, struct file *file);
  23. int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
  24. struct input_handle __rcu *grab;
  25. ...
  26. struct device dev;
  27. struct list_head h_list;
  28. struct list_head node;
  29. };
这三者Input_dev,hander,与Hande的关系
应该很清楚了吧,这里只以其中的一个input_dev和handler为例画出来的图,其他的以此类推。其中input_dev_list和input_handler_list是两条全局的链表,每当调用input_register_device函数时会将Input设备加入到input_dev_list链表的尾部;每当调用input_register_handler函数时会将handler加入到input_handler_list链表的尾部;每当调用input_register_handle函数时会将handle加入到其对应的Input设备的h_list链表的尾部,并且还会该handle加入到其对应的handler的h_list链表的尾部。

Input设备驱动

总共有三个核心的函数
input_register_handler(&evdev_handler);
input_register_handle(&evdev->handle);
input_register_device(remote->input);
前面两个是在事件驱动层的evdev.c的init函数和connect函数中调用;最后一个是在设备驱动中注册的。
我们从最底层的input_register_device分析起,以IR遥控器驱动为例
在probe函数中,进行input_register_device把该input设备注册进全局的input_dev_list链表
  1. input_register_device(remote->input);
=》
  1. int input_register_device(struct input_dev *dev)
  2. {
  3. ...
  4. //添加到全局设备
  5. error = device_add(&dev->dev);
  6. ...
  7. //添加到设备链表
  8. list_add_tail(&dev->node, &input_dev_list);
  9. //遍历input_handler_list链表,以node为关键字,把dev加入到handler_list中
  10. list_for_each_entry(handler, &input_handler_list, node)
  11. input_attach_handler(dev, handler);
在input_attach_handler中,
  1. static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
  2. {
  3. id = input_match_device(handler, dev);
  4. if (!id)
  5. return -ENODEV;
  6. ...
  7. error = handler->connect(handler, dev, id);
  8. ...
  9. return error;
  10. }
通过id进行匹配,第一次的话hander链表中没有dev对应的handler,就进行connect,其实是调用input_register_handle()。把input_dev,input_handler,input_handle关联起来。
注册完成之后,一般就调用这两个函数发送数据到input子系统中
  1. input_event(dev, EV_KEY, scancode, type);
  2. input_sync(dev);
主要看input_event
=》
input_handle_event(dev, type, code, value);
=》
input_pass_event(dev, type, code, value);
=》
handle->handler->event(handle, type, code, value);
在input_register_handler的时候,为dev分配了一个handler,并与handle进行关联了,此时就直接进入event函数了。
  1. static void evdev_event(struct input_handle *handle,
  2. unsigned int type, unsigned int code, int value)
  3. {
  4. struct evdev *evdev = handle->private;
  5. struct evdev_client *client;
  6. struct input_event event;
  7. event.type = type;
  8. event.code = code;
  9. event.value = value;
  10. ...
  11. client = rcu_dereference(evdev->grab);
  12. if (client)
  13. evdev_pass_event(client, &event);
  14. else
  15. list_for_each_entry_rcu(client, &evdev->client_list, node)
  16. evdev_pass_event(client, &event);
  17. ...
  18. if (type == EV_SYN && code == SYN_REPORT)
  19. wake_up_interruptible(&evdev->wait);
  20. }
把事件通过evdev_pass_event传递给client,如果是同步事件的话,就调用wait,唤醒相应的监听进行。
Comments are closed.
TOP