============================================
作者:yuanlulu
http://blog.csdn.net/yuanlulu
版权没有,但是转载请保留此段声明
============================================
第2章 输入子系统的事件驱动
上一章已经说过输入子系统分为三层,最上面的一层是事件处理层,我们暂时称它为事件驱动,这是相对于上一章的设备驱动来讲的。
上一章介绍了设备驱动注册时要与匹配的handler连接,报告的事件也会分发给连接的handler,这一章介绍handler的相关操作。
2.1 重要的数据结构
首先介绍input_handle,这个结构体用来连接input_dev和input_handler。它的代码如程序清单 2.1<!--[if gte mso 9]><![endif]-->所示。
程序清单 <!--[if supportFields]> STYLEREF 1 /s <![endif]-->2<!--[if supportFields]><![endif]-->.<!--[if supportFields]> SEQ 程序清单 /* ARABIC /s 1 <![endif]-->1<!--[if supportFields]><![endif]--> input_handle
/* include/linux/input.h */
struct input_handle {
void*private; <!--[if supportFields]> = 1 /* GB2 <![endif]-->⑴<!--[if supportFields]><![endif]-->
intopen; <!--[if supportFields]> = 2 /* GB2 <![endif]-->⑵<!--[if supportFields]><![endif]-->
constchar *name; <!--[if supportFields]> = 3 /* GB2 <![endif]-->⑶<!--[if supportFields]><![endif]-->
structinput_dev *dev; <!--[if supportFields]> = 4 /* GB2 <![endif]-->⑷<!--[if supportFields]><![endif]-->
structinput_handler *handler; <!--[if supportFields]> = 5 /* GB2 <![endif]-->⑸<!--[if supportFields]><![endif]-->
structlist_head d_node; <!--[if supportFields]> = 6 /* GB2 <![endif]-->⑹<!--[if supportFields]><![endif]-->
structlist_head h_node; <!--[if supportFields]> = 7 /* GB2 <![endif]-->⑺<!--[if supportFields]><![endif]-->
};
各个成员的含义如下:
<!--[if supportFields]> =1 /* GB2 <![endif]-->⑴<!--[if supportFields]><![endif]-->私有数据指针。
<!--[if supportFields]> =2 /* GB2 <![endif]-->⑵<!--[if supportFields]><![endif]-->记录本设备被打开的次数。
<!--[if supportFields]> =3 /* GB2 <![endif]-->⑶<!--[if supportFields]><![endif]-->创建此handle的handler所赋予的名字。
<!--[if supportFields]> =4 /* GB2 <![endif]-->⑷<!--[if supportFields]><![endif]-->指向附着的input_dev。
<!--[if supportFields]> =5 /* GB2 <![endif]-->⑸<!--[if supportFields]><![endif]-->指向创建此handle的handler。
<!--[if supportFields]> =6 /* GB2 <![endif]-->⑹<!--[if supportFields]><![endif]-->链表节点,用来加入附着的input_dev。
<!--[if supportFields]> =7 /* GB2 <![endif]-->⑺<!--[if supportFields]><![endif]-->链表节点,用来加入附着的input_handler。
在程序清单 1.11<!--[if gte mso 9]><![endif]-->中,我们看到input_dev和input_handler匹配过程中用到了input_device_id。它的代码如程序清单 2.2<!--[if gte mso 9]><![endif]-->所示。
程序清单 <!--[if supportFields]> STYLEREF 1 /s <![endif]-->2<!--[if supportFields]><![endif]-->.<!--[if supportFields]> SEQ 程序清单 /* ARABIC /s 1 <![endif]-->2<!--[if supportFields]><![endif]--> input_device_id
/* include/linux/mod_devicetable.h */
struct input_device_id {
kernel_ulong_tflags; <!--[if supportFields]> = 1 /* GB2 <![endif]-->⑴<!--[if supportFields]><![endif]-->
__u16bustype; <!--[if supportFields]> = 2 /* GB2 <![endif]-->⑵<!--[if supportFields]><![endif]-->
__u16vendor;
__u16product;
__u16version;
kernel_ulong_tevbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1]; <!--[if supportFields]> = 3 /* GB2 <![endif]-->⑶<!--[if supportFields]><![endif]-->
kernel_ulong_tkeybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];
kernel_ulong_trelbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];
kernel_ulong_tabsbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];
kernel_ulong_tmscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];
kernel_ulong_tledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];
kernel_ulong_tsndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];
kernel_ulong_tffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];
kernel_ulong_tswbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];
kernel_ulong_tdriver_info; <!--[if supportFields]> = 4 /* GB2 <![endif]-->⑷<!--[if supportFields]><![endif]-->
};
各个成员的含义如下:
<!--[if supportFields]> =1 /* GB2 <![endif]-->⑴<!--[if supportFields]><![endif]-->定义需要匹配input_id的哪些域(使用方法参考程序清单 1.11<!--[if gte mso 9]><![endif]-->)。
<!--[if supportFields]> =2 /* GB2 <![endif]-->⑵<!--[if supportFields]><![endif]-->对应input_id的四个数据域。
<!--[if supportFields]> =3 /* GB2 <![endif]-->⑶<!--[if supportFields]><![endif]-->存储支持事件的位图,与input_dev中的同名数据成员功能一致。
<!--[if supportFields]> =4 /* GB2 <![endif]-->⑷<!--[if supportFields]><![endif]-->指示结构体中是否含有驱动信息。
input_handler这个结构体是事件驱动的主体,每一种处理方式对应一个handler结构体。它的定义如程序清单 2.3<!--[if gte mso 9]><![endif]-->所示。
程序清单 <!--[if supportFields]> STYLEREF 1 /s <![endif]-->2<!--[if supportFields]><![endif]-->.<!--[if supportFields]> SEQ 程序清单 /* ARABIC /s 1 <![endif]-->3<!--[if supportFields]><![endif]--> input_handler
/* include/linux/input.h */
struct input_handler {
void*private; <!--[if supportFields]> = 1 /* GB2 <![endif]-->⑴<!--[if supportFields]><![endif]-->
void(*event)(struct input_handle *handle, unsigned int type, unsigned int code, intvalue); <!--[if supportFields]> = 2 /* GB2 <![endif]-->⑵<!--[if supportFields]><![endif]-->
int(*connect)(struct input_handler *handler, struct input_dev *dev, const structinput_device_id *id); <!--[if supportFields]> = 3 /* GB2 <![endif]-->⑶<!--[if supportFields]><![endif]-->
void(*disconnect)(struct input_handle *handle); <!--[if supportFields]> = 4 /* GB2 <![endif]-->⑷<!--[if supportFields]><![endif]-->
void(*start)(struct input_handle *handle); <!--[if supportFields]> = 5 /* GB2 <![endif]-->⑸<!--[if supportFields]><![endif]-->
const structfile_operations *fops; <!--[if supportFields]> = 6 /* GB2 <![endif]-->⑹<!--[if supportFields]><![endif]-->
intminor; <!--[if supportFields]> = 7 /* GB2 <![endif]-->⑺<!--[if supportFields]><![endif]-->
constchar *name; <!--[if supportFields]> = 8 /* GB2 <![endif]-->⑻<!--[if supportFields]><![endif]-->
conststruct input_device_id *id_table; <!--[if supportFields]> = 9 /* GB2 <![endif]-->⑼<!--[if supportFields]><![endif]-->
conststruct input_device_id *blacklist; <!--[if supportFields]> = 10 /* GB2 <![endif]-->⑽<!--[if supportFields]><![endif]-->
structlist_head h_list; <!--[if supportFields]> = 11 /* GB2 <![endif]-->⑾<!--[if supportFields]><![endif]-->
structlist_head node; <!--[if supportFields]> = 12 /* GB2 <![endif]-->⑿<!--[if supportFields]><![endif]-->
};
每个成员的具体解释如下:
<!--[if supportFields]> =1 /* GB2 <![endif]-->⑴<!--[if supportFields]><![endif]-->私有数据指针。
<!--[if supportFields]> =2 /* GB2 <![endif]-->⑵<!--[if supportFields]><![endif]-->事件处理函数指针。设备驱动报告的事件最终由这个函数来处理(参考程序清单 1.14<!--[if gte mso 9]><![endif]-->)。
<!--[if supportFields]> =3 /* GB2 <![endif]-->⑶<!--[if supportFields]><![endif]-->连接handler和input_dev的函数指针。
<!--[if supportFields]> =4 /* GB2 <![endif]-->⑷<!--[if supportFields]><![endif]-->断开连接函数指针。
<!--[if supportFields]> =5 /* GB2 <![endif]-->⑸<!--[if supportFields]><![endif]-->为给定的handle启动handler函数指针。
<!--[if supportFields]> =6 /* GB2 <![endif]-->⑹<!--[if supportFields]><![endif]-->文件操作结构体。
<!--[if supportFields]> =7 /* GB2 <![endif]-->⑺<!--[if supportFields]><![endif]-->这个handler可以使用的32个次设备号的最小值。
<!--[if supportFields]> =8 /* GB2 <![endif]-->⑻<!--[if supportFields]><![endif]-->此handler的名字。
<!--[if supportFields]> =9 /* GB2 <![endif]-->⑼<!--[if supportFields]><![endif]-->可以处理的input_device_ids列表(用法参考程序清单 1.11<!--[if gte mso 9]><![endif]-->)。
<!--[if supportFields]> =10 /* GB2 <![endif]-->⑽<!--[if supportFields]><![endif]-->需要被忽略的input_device_ids列表。
<!--[if supportFields]> =11 /* GB2 <![endif]-->⑾<!--[if supportFields]><![endif]-->用来连接handle的链表链表节点。每个与此handler相关的handle都放入此链表。
<!--[if supportFields]> =12 /* GB2 <![endif]-->⑿<!--[if supportFields]><![endif]-->用来放入全局handler链表的节点。
2.2 input_handler的注册
首先介绍存放注册的input_handler所用的数据结构。如所程序清单 2.4<!--[if gte mso 9]><![endif]-->示。
程序清单 <!--[if supportFields]> STYLEREF 1 /s <![endif]-->2<!--[if supportFields]><![endif]-->.<!--[if supportFields]> SEQ 程序清单 /* ARABIC /s 1 <![endif]-->4<!--[if supportFields]><![endif]--> input core全局数据
/* driver/input/input.c */
static LIST_HEAD(input_dev_list); /* 设备链表头 */
static LIST_HEAD(input_handler_list); /* handler链表头 */
static DEFINE_MUTEX(input_mutex); /* 保护以上两个链表 */
static struct input_handler *input_table[8]; /*存放注册的input_handler的指针数组*/
程序清单 1.9<!--[if gte mso 9]><![endif]-->中<!--[if supportFields]> = 4 /* GB2 <![endif]-->⑷<!--[if supportFields]><![endif]-->处注册的input_dev结构体加入到上面的input_dev_list当中,下面将要介绍的注册input_handler,其实就是将input_hangler加入到input_handler_list当中。input_table中存放进行文件操作的handler,使用它们次设备号的最高三比特在input_table中寻址,因此每个handler最多支持32个设备节点。由上面的代码可以看出输入子系统最多允许8个进行文件操作的input_handler同时存在。
input_register_handler的代码如程序清单 2.5<!--[if gte mso 9]><![endif]-->所示。
程序清单 <!--[if supportFields]> STYLEREF 1 /s <![endif]-->2<!--[if supportFields]><![endif]-->.<!--[if supportFields]> SEQ 程序清单 /* ARABIC /s 1 <![endif]-->5<!--[if supportFields]><![endif]--> input_register_handler
int input_register_handler(struct input_handler*handler)
{
structinput_dev *dev;
intretval;
retval =mutex_lock_interruptible(&input_mutex);
if(retval)
returnretval;
INIT_LIST_HEAD(&handler->h_list); <!--[if supportFields]> = 1 /* GB2 <![endif]-->⑴<!--[if supportFields]><![endif]-->
if(handler->fops != NULL) { <!--[if supportFields]> = 2 /* GB2 <![endif]-->⑵<!--[if supportFields]><![endif]-->
if(input_table[handler->minor >> 5]) { <!--[if supportFields]> = 3 /* GB2 <![endif]-->⑶<!--[if supportFields]><![endif]-->
retval= -EBUSY;
gotoout;
}
input_table[handler->minor>> 5] = handler; <!--[if supportFields]> = 4 /* GB2 <![endif]-->⑷<!--[if supportFields]><![endif]-->
}
list_add_tail(&handler->node,&input_handler_list); <!--[if supportFields]> = 5 /* GB2 <![endif]-->⑸<!--[if supportFields]><![endif]-->
list_for_each_entry(dev,&input_dev_list, node) <!--[if supportFields]> = 6 /* GB2 <![endif]-->⑹<!--[if supportFields]><![endif]-->
input_attach_handler(dev,handler); <!--[if supportFields]> = 7 /* GB2 <![endif]-->⑺<!--[if supportFields]><![endif]-->
input_wakeup_procfs_readers();
out:
mutex_unlock(&input_mutex);
returnretval;
}
EXPORT_SYMBOL(input_register_handler);
程序含义如下:
<!--[if supportFields]> =1 /* GB2 <![endif]-->⑴<!--[if supportFields]><![endif]-->初始化handler中的链表节点,为加入input_handler_list做准备。
<!--[if supportFields]> =2 /* GB2 <![endif]-->⑵<!--[if supportFields]><![endif]-->如果此handler需要进行文件操作。
<!--[if supportFields]> =3 /* GB2 <![endif]-->⑶<!--[if supportFields]><![endif]-->如果相应的次设备号段被占用。
<!--[if supportFields]> =4 /* GB2 <![endif]-->⑷<!--[if supportFields]><![endif]-->将handler注册进input_table。
<!--[if supportFields]> =5 /* GB2 <![endif]-->⑸<!--[if supportFields]><![endif]-->将handler加入input_handler_list链表。
<!--[if supportFields]> =6 /* GB2 <![endif]-->⑹<!--[if supportFields]><![endif]-->遍历input_dev_list链表中的每一个input_dev结构体。
<!--[if supportFields]> =7 /* GB2 <![endif]-->⑺<!--[if supportFields]><![endif]-->将handler与每一个input_dev进行匹配。
input_attach_handler的代码如程序清单 1.10<!--[if gte mso 9]><![endif]-->所示,这里不再赘述。
总结一下input_handler的注册过程:见自己加入input_handler_list和input_table,然后与input_dev_list中的input_dev比较并与匹配的建立连接。
参考<!--[if supportFields]> REF _Ref282153330 /r/h <![endif]-->1.4<!--[if gte mso 9]><![endif]--><!--[if supportFields]><![endif]--><!--[if supportFields]> REF _Ref282153346 /h <![endif]-->input_dev的注册<!--[if gte mso 9]><![endif]--><!--[if supportFields]><![endif]-->这一节,我们发现input_dev和input_handler都是将自己加入各自的链表,然后再和对方链表中匹配的进行连接。