linux输入子系统(6)---evdev_handler的实现

<!--[if !supportLists]-->2.3 <!--[endif]-->evdev_handler的实现

Linux输入子系统已经建立好了几个handler,用来处理几类常见的事件,如鼠标、键盘、摇杆等。其中最为基础的是evdev_handler,它是在driver/input/evdev.c中实现的。它能够接收任意类型的事件,任意id的设备都可以和它匹配连接,它对应的设备节点为/dev/eventX,次设备号的范围为6495

<!--[if !supportLists]-->2.3.1 <!--[endif]-->初始化和input_device_id

<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span> REF _Ref282157243 \h <span style='mso-element:field-separator'></span></span><![endif]-->程序清单 2.6<!--[if gte mso 9]><xml> <w:data>08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F005200650066003200380032003100350037003200340033000000</w:data> </xml><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->所示。

程序清单 <!--[if supportFields]><span style='mso-bookmark: _Ref282157243'><span style='mso-bookmark:_Ref282157239'></span></span><span style='mso-element:field-begin'></span><span style='mso-bookmark:_Ref282157243'><span style='mso-bookmark:_Ref282157239'><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;</span>STYLEREF 1 \s <span style='mso-element:field-separator'></span></span></span></span><![endif]-->2<!--[if supportFields]><span style='mso-bookmark:_Ref282157243'><span style='mso-bookmark:_Ref282157239'></span></span><span style='mso-element:field-end'></span><![endif]-->.<!--[if supportFields]><span style='mso-bookmark:_Ref282157243'><span style='mso-bookmark:_Ref282157239'></span></span><span style='mso-element:field-begin'></span><span style='mso-bookmark:_Ref282157243'><span style='mso-bookmark:_Ref282157239'><span lang=EN-US> SEQ </span></span></span><span style='mso-bookmark:_Ref282157243'><span style='mso-bookmark:_Ref282157239'><span style='font-family:黑体;mso-ascii-font-family:Arial'>程序清单</span><span lang=EN-US> \* ARABIC \s 1 <span style='mso-element:field-separator'></span></span></span></span><![endif]-->6<!--[if supportFields]><span style='mso-bookmark:_Ref282157243'><span style='mso-bookmark:_Ref282157239'></span></span><span style='mso-element:field-end'></span><![endif]--> evdev_handler

/* driver/input/evdev.c */

static const struct input_device_id evdev_ids[] = {

{ .driver_info = 1 }, /* Matches all devices */

{ }, /* Terminating zero entry */

};

MODULE_DEVICE_TABLE(input, evdev_ids);

static struct input_handler evdev_handler = {

.event = evdev_event,

.connect = evdev_connect,

.disconnect = evdev_disconnect,

.fops = &evdev_fops,

.minor = EVDEV_MINOR_BASE,

.name = "evdev",

.id_table = evdev_ids,

};

static int __init evdev_init(void)

{

return input_register_handler(&evdev_handler);

}

static void __exit evdev_exit(void)

{

input_unregister_handler(&evdev_handler);

}

module_init(evdev_init);

module_exit(evdev_exit);

初始化的过程非常简单,就是将evdev_handler进行注册,注册的过程已经在<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span> REF _Ref282158677 \r \h <span style='mso-element:field-separator'></span></span><![endif]-->2.2<!--[if gte mso 9]><xml> <w:data>08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F005200650066003200380032003100350038003600370037000000</w:data> </xml><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->小节讲过了。

evdev_handler只初始化了id_table根据程序清单 1.11<!--[if gte mso 9]><xml> <w:data>08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F005200650066003200380032003000320030003800360038000000</w:data> </xml><![endif]--><!--[if supportFields]><span lang=DE style='mso-ansi-language:DE'><span style='mso-element:field-begin'></span> = 1 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=DE style='mso-ansi-language:DE'><span style='mso-element:field-end'></span></span><![endif]-->步的分析,我们可以知道这样的input_device_id可以和任意的设备id相匹配。

<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span> REF _Ref282158677 \r \h <span style='mso-element:field-separator'></span></span><![endif]-->2.2<!--[if gte mso 9]><xml> <w:data>08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F005200650066003200380032003100350038003600370037000000</w:data> </xml><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->小节我们知道次设备号的最高3比特用来对每个handlerinput_table中寻址,那么每个handler拥有的次设备号数就是最低5比特对应的个数,共32个。所以evdev_handler最多能够支持32个输入设备与之建立连接。

<!--[if !supportLists]-->2.3.2 <!--[endif]-->建立连接

evdev_handler建立连接的函数原型如下:

static int evdev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);

它的主要任务是申请一个input_handle结构体将handlerdev连接起来。同时建立连接的设备占用一个次设备号,这个次设备号是6495中空闲的最小值,如果没有空闲的次设备号可用则连接失败。

<!--[if !supportLists]-->2.3.3 <!--[endif]-->打开设备节点

由于每个与evdev_handler建立连接的设备都占用了设备号,所以可以建立对应他们的设备节点。每次打开设备节点,都建立一个fifo环形消息缓冲区,能够存储64个消息。

<!--[if !supportLists]-->2.3.4 <!--[endif]-->用户空间读写消息

用户空间可以往evdev_handler连接的设备节点上写入消息,写入数据的格式如程序清单 1.2<!--[if gte mso 9]><xml> <w:data>08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F005200650066003200380031003900390039003500300036000000</w:data> </xml><![endif]-->,写入的长度是数据的字节数。缓冲区写满之后从头开始写,直接覆盖之前的消息并且不会通知用户程序。由于写入消息是通过input core分发的,所以写入的无效消息根本不会进入消息缓冲区。

另外需要注意,虽然每个打开节点的线程都有一个消息缓冲区,写入的消息却会传给打开同一节点的每一个线程。同时也会传给同一个input_dev对应的其它设备节点。

读取消息则只从自己的消息缓冲区中读取。读取的消息格式也是如程序清单 1.2<!--[if gte mso 9]><xml> <w:data>08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F005200650066003200380031003900390039003500300036000000</w:data> </xml><![endif]-->中的input_event一样。每个消息只能被读一次。

<!--[if !supportLists]-->2.3.5 <!--[endif]-->事件处理

evdev_handlerinput core接收到一个事件之后会将它发送给独占设备的线程(如果有)或者所有打开设备的线程。事件分发之前会先打包成input_event的格式,并加上时间戳。

<!--[if !supportLists]-->2.3.6 <!--[endif]-->同步消息

每个input_dev都默认支持同步事件(EV_SYN)。但是evdev_handler并不使用用同步事件,只是将它作为一个一般的事件写入缓冲区。由于每次的写入都是及时的,所以也不需要同步。

<!--[if !supportLists]-->2.3.7 <!--[endif]-->evdev_handler适用范围

evdev_handler仅仅将消息打包成input_event的格式,此外不做任何处理。所有设备发送的事件报告都能为用户空间所见。需要直接使用设备原始事件的程序可以读取eventX,对于鼠标类或者更复杂的设备,evdev_handler并不合适。

你可能感兴趣的:(数据结构,xml,linux)