输入子系统学习笔记之源码分析2_数据结构分析
1. 输入子系统数据机构分析
分析输入子系统,我是从输入子系统中的数据结构关系以及连接设备驱动层和事件处理层分析的,如果了解了输入子系统的数据结构关系和输入子系统预留给我们的编程接口,那么基本上掌握了输入子系统了。下面是输入子系统的系统数据结构图:
由上图可知,input子系统分为3层,最上一层是event handler,中间层是Input core,底层是input driver。input driver把event report到input core层,input core对event进行分发,传到 event handler,相应的event handler层把event 放到event buffer中,等待应用程序读取!这就是input的基本思想,现在结合上图分析输入子系统3个重要的数据结构,因为这3个数据结构又有牵连,所以把关联的部分最后画图简单明了的表示出来。
struct input_handler { void *private; //事件处理 void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); // 如果设备驱动程序与事件处理程序匹配,那么调用connect 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); const struct file_operations *fops; int minor; // 次设备号 const char *name; const struct input_device_id *id_table; const struct input_device_id *blacklist; struct list_head h_list; //h_list是一个链表头,用来把handle挂载在这个上 struct list_head node; //这个node是用来连到iput_handler_list上 };
struct input_dev { void *private; const char *name; const char *phys; const char *uniq; struct input_id id;//与input_handler匹配时会用到 unsigned long evbit[NBITS(EV_MAX)]; //支持所有的事件类型 unsigned long keybit[NBITS(KEY_MAX)];//支持按键事件 unsigned long relbit[NBITS(REL_MAX)];//支持相对位移事件 unsigned long absbit[NBITS(ABS_MAX)];//支持绝对位移事件 unsigned long mscbit[NBITS(MSC_MAX)]; //支持其它事件 unsigned long ledbit[NBITS(LED_MAX)];//支持led时间 unsigned long sndbit[NBITS(SND_MAX)];//支持声音事件 unsigned long ffbit[NBITS(FF_MAX)]; //支持受力事件 unsigned long swbit[NBITS(SW_MAX)];//支持开关机时间 unsigned int keycodemax; unsigned int keycodesize; void *keycode; int (*setkeycode)(struct input_dev *dev, int scancode, int keycode); int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode); struct ff_device *ff; unsigned int repeat_key; struct timer_list timer; int state; int sync; int abs[ABS_MAX + 1];//绝对坐标上报的当前值 int rep[REP_MAX + 1];//这个参数主要是处理重复按键 unsigned long key[NBITS(KEY_MAX)]; unsigned long led[NBITS(LED_MAX)]; unsigned long snd[NBITS(SND_MAX)]; unsigned long sw[NBITS(SW_MAX)]; int absmax[ABS_MAX + 1]; int absmin[ABS_MAX + 1]; int absfuzz[ABS_MAX + 1]; int absflat[ABS_MAX + 1]; 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 *grab; struct mutex mutex; /* serializes open and close operations */ unsigned int users; struct class_device cdev; union { /* temporarily so while we switching to struct device */ struct device *parent; } dev; struct list_head h_list;//h_list 是一个链表头,用来把handle挂载在这个头上 struct list_head node; //这个node是用来练到input_dev_list上的 };
struct input_handle { void *private; int open; const char *name; struct input_dev *dev; //指向input_dev struct input_handler *handler;//指向input_handler struct list_head d_node; //连到input_dev的h_list上 struct list_head h_node; //连到input_handler的h_list上 };
上面三个结构体构成的链表有一个共同的特点,它们不是将数据结构塞入链表,而是将链表节点塞入数据结构。意思就是不在链表中包含数据,而是在数据结构中包含节点,这也是linux内核在链表实现的方式上独树一帜,与众不同的地方,而这样带来的好处是可以避免为每个数据项类型定义自己的链表的麻烦。正式由于这种表达方式,因此这三个数据结构的关系看起来有点乱! 那么就用图表示出来,看起来应该会明了很多吧!三者的关系如下所示:
图1
图2
图 3
从图1,图2中可以很清楚的看到一个handler可以和多个硬件相关联,一个硬件设备可以和多个handler相关联。比如说:一个触目屏设备可以作为一个even设备,作为一个鼠标设备,作为一个触目屏设备,所以一个设备需要和多个事件处理驱动进行连接。而一个事件驱动也不只为一个设备服务,比如:一个触摸事件驱动可能要为A,B,C 3个设备提供上层驱动,所以需要这样一对多的连接关系。(分析代码可知,一个事件驱动里面最多可以关联32个设备,因此,不同事件驱动的的起始次设备号相隔32,这个需要注意!)
图3 可以看出input_handle是连接input_device 和 input_handler的桥梁,如图中的箭头所示从input_device可以通过 input_handl 找到 input_handler,同样的input_handler可以通过 input_handle找到 input_device。
输入子系统系统框图 ,图1,图2,图3 基本上可以表现出输入子系统的数据结构网图,如果掌握了这几张图,那么在分析输入子系统将轻松很多。
这次写到这,明天接着写输入子系统的工作流程!^_^