框架
Linux系统支持的输入设备繁多,例如键盘、鼠标、触摸屏、手柄或者是一些输入设备像体感输入等等,Linux系统是如何管理如此之多的不同类型、不同原理、不同的输入信息的输入设备的呢?其实就是通过input输入子系统这套软件体系来完成的。从整体上来说,input输入子系统分为3层:上层(输入事件驱动层)、中层(输入核心层)、下层(输入设备驱动层),如下图:
- input driver :主要实现对硬件设备的读写访问,中断设置,并把硬件产生的事件转换为核心层定义的规范提交给事件处理层。
input device driver 设备驱动程序
input event driver事件驱动程序
注意:事件驱动程穿是标准的,对所有的瑜入类都是可用的,所以,我们不需实现事件驱动,为内核里边已经支持所有的事件驱动;我们需实现的是输入设备备驱动程序 - input core :承上启下。为设备驱动层提供了规范和接口;通知事件处理层对事件进行处理;
- event handler :提供用户编程的接口(设备节点),并处理驱动层提交的数据处理。
三个重要结构体
struct input_dev
//表示的是一个具体的输入设备,描述设备能够产生什么数据 struct input_dev { const char *name;//sysfs中给用户看的信息 const char *phys; const char *uniq; struct input_id id; unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; /*evbit实际是一个位表,描述输入设备能够产生什么数据类型*/ unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];//能够表示768个bit,直接用24个long来表示, //KEY_CNT=768 BITS_TO_LONGS=nr/32 768/32=24 //表示能够产生哪种按键 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 *mt; struct input_absinfo *absinfo; unsigned long key[BITS_TO_LONGS(KEY_CNT)]; 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); 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; struct device dev;//继承device对象 struct list_head h_list; struct list_head node;//表示节点 unsigned int num_vals; unsigned int max_vals; struct input_value *vals; bool devres_managed; };
struct input_handler
struct input_handler { void *private; void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); void (*events)(struct input_handle *handle, const struct input_value *vals, unsigned int count); bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value); bool (*match)(struct input_handler *handler, struct input_dev *dev); int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); void (*disconnect)(struct input_handle *handle); void (*start)(struct input_handle *handle); bool legacy_minors; int minor; const char *name; const struct input_device_id *id_table; struct list_head h_list; struct list_head node; };
struct input_handle
struct input_handle { void *private; int open; const char *name; struct input_dev *dev; struct input_handler *handler; struct list_head d_node; struct list_head h_node; };
- input_dev代表底层的设备,所有设备的input_dev对象保存在一个全局的lnput_dev队列里。
- input_handler代表某类入设备的处理方法,比如说是专门处理入设备产成的Event〈事件〉,所有的input_handler存放在input_handler队里
- 一个input_dev可以有多个input_handler,
- lnput_handle用来关联某个input_dev和某个input_handler。每个input_handle都会生成一个文件节点,比如"/dev/input/event0、1、2、3…"。通过input handle可以找到对应的input handler和input_dev