1.前言
本文主要对Linux下的input子系统进行介绍
2. 软件架构
图 input子系统结构图
input子系统主要包括三个部分:设备驱动层、核心层和事件层。我们可以分别理解为:具体的输入设备、过度设备和逻辑设备。对于用户空间来说与之直接交互的只有逻辑设备也就是事件层。
Input子系统主要包含两条路径(主要讲述第一条路径):
- 第一条路径
设备驱动层捕获事件并向核心层报告->核心层将事件交由事件层处理->用户空间读取事件层处理的数据
- 第二条路径
用户空间写入事件数据->事件层生成事件->调用核心层传递事件信息给驱动层->设备驱动层驱动硬件设备
3.系统组件之间的关联
图 input_dev input_handle input_handler之间的关联
通常input_dev、 input_handle、input_handler三者的关系如上图所示。
- input_dev
input_dev通过node链接进全局链表input_dev_list中;通过h_list将与其关联的所有input_handle链接起来,这说明每个input_dev可能会有多个handle与其连接
- input_handler
input_handler通过node节点链接进全局链表input_handler_list中;通过h_list将与其关联的所有input_handle链接起来,这说明每个input_handler可能会有多个handle与其连接
4. 系统组件
4.1 input_handle
Elemete Name | input_handle |
Path | include/linux/input.h |
Responsiblities |
用于连接input_dev和input_handler,由input_handler创建 |
Attributions |
|
Operations |
4.2 input_dev
Elemete Name | input_dev |
Path | include/linux/input.h |
Responsiblities |
代表一个input设备,如按键设备、触摸屏设备等 |
Attributions |
name:const char *类型,input设备的名字 phys:const char *类型,/sys/目录下的文件节点名,如/sys/class/input/event0 uniq:const char *类型,设备的唯一标识码,需要设备支持 struct input_id id; 设备的ID,包括生产商,产品好,版本号 unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; 设备支持哪些事件 unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; 这个设备支持哪些按键和button 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)]; 设备上的LED unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; 设备的声音支持相关,如蜂鸣器等 unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; 设备所支持的强反馈事件,如马达等 unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; 设备是否支持开关,如iphone上的静音开关 unsigned int hint_events_per_packet; 设备打包事件暗含的数目,一般发生在EV_SYN和SYN_REPORT之间的事件数目,input_handler需要据此预估buffer大小来存放事件 unsigned int keycodemax; 按键码表的大小,用来存放按键码,实际的按键码个数可能小于此 unsigned int keycodesize; 实际上存放在按键码表中的按键码数目 void *keycode; 扫描码到按键码的映射,对ADC按键扫描码可以理解为某个按键的ADC值,按键码有音量加,音量减等 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; repeat_key保存了上次按下的按键,用于软件自动重发 struct timer_list timer; 软件重发的定时器,包括按键按下多长时间启动自动重发功能,每隔多长时间重发一次 int rep[REP_CNT]; 用于自动重发的参数值保存 struct input_mt *mt; struct input_absinfo *absinfo; unsigned long key[BITS_TO_LONGS(KEY_CNT)]; 反应当前key/button设备的状态,如按下还是抬起 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); 这个方法由第一个用户在调用input_open_device时被调用,驱动中此时需要已经开启 poll线程,并可以上报事件,其它用户调用时将只把user计数加1 void (*close)(struct input_dev *dev); 最后一个用户调用input_close_device时将调用此函数,驱动需要实现做一个善后工作 int (*flush)(struct input_dev *dev, struct file *file); int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); 主要用于input_handler接收用户层的操作事件,对input_dev进行操作,如对led和ff设备的操作 struct input_handle __rcu *grab; 一旦grab不为空,则说明此input_handle将成为此input_dev的唯一事件处理者 spinlock_t event_lock; 用于input core接收或处理此input_dev的事件 struct mutex mutex; 用于保证open、close、flush方法的串行执行 unsigned int users; input_handler执行input_open_device的次数 bool going_away; 标示input_dev在执行unregister的过程中,此时执行input_open_device将失败 struct device dev; 设备驱动模型device struct list_head h_list; 用于链接此input_dev的所有input_handle struct list_head node; 用于将此input_dev加入到全局input_dev_list中 unsigned int num_vals; 当前队列中有多少个frame在排队,每个frame可以理解成EV_SYN和SYN_REPORT之间的事件 unsigned int max_vals; 一个frame中可以包含的最大事件个数??? struct input_value *vals; 入队到当前队列的数组???? bool devres_managed; 指示设备资源是否由设备资源框架进行管理 |
Operations |