首页 理论教育深入剖析Linux内核:输入设备框架解析

深入剖析Linux内核:输入设备框架解析

【摘要】:1框架总体设计从输入设备框架的需求可知,内核的整个输入流程应该分为下层的各种输入设备和上层与用户的控制信息交互两个方面。从图6-1可见,输入设备系统框架的核心部分从底到上分为input driver,input core和event handler三个部分。应用层则要根据输入设备的事件进行相应的操作,为了给应用层统一的接口,输入设备框架对于输入事件进行了规范。

1ᤫ框架总体设计

从输入设备框架的需求可知,内核的整个输入流程应该分为下层的各种输入设备和上层与用户的控制信息交互两个方面。所以输入设备框架重要的工作应该是在管理下层的各种输入设备和上层的控制信息交互处理实体,并为用户层提供统一的服务,内部框架还需要能够在输入设备和用户的控制信息两者之间建立有效的通道,从而进行信息交互。

根据这些目标,输入设备框架的总体设计如图6-1所示。

从图6-1可见,输入设备系统框架的核心部分从底到上分为input driver,input core和event handler三个部分。详细介绍如下:

●input driver主要负责下层物理输入设备的驱动及管理,每个具体的驱动都会对物理设备进行实际的操作。

●event handler主要负责为应用层提供获得设备输入的信息,将输入事件以标准形式提供给应用层,并接受应用层的控制。

●Input core主要负责对Input driver和Event handler进行管理,将二者进行匹配并在二者之间建立通信的通道。总的来说起到连接和桥梁的作用。

从图6-1可见,对为用户开放的设备文件,每个event handler会有不同的设备文件,需要注意的是在/dev/input/目录下的文件才是属于输入设备系统框架生成的,而console和tty属于终端设备类,并不属于输入设备系统框架对用户层开放的设备。这也就是说,输入事件的接收者不是必须产生针对用户的输入,只要关心输入事件的模块就可以注册event han-dler,这一点很重要,也为许多功能开放了监测输入设备输入进行控制的接口,可以在内核内部就根据用户的某些输入做特定的控制。

根据以上的三个部分的功能可见,如果设备文件是由输入设备框架创建的,则相应的应用层的接口只有event handler,所有与应用层的交互都是通过event handler来完成。event handler需要对应用层的使用者进行管理,其中evdev handler的管理模式如图6-2所示。

978-7-111-49426-3-Chapter06-1.jpg

图6-1 输入设备Input系统框架总体设计

978-7-111-49426-3-Chapter06-2.jpg

图6-2 evdev handler用户管理模式图

从图6-2可见,每个操作文件的进程都会对应一个evdev_client,框架将对与之连接的输入设备上传的输入事件分别传入evdev_client进行缓冲与管理,保证用户进程的统一视角,evdev_client则由evdev统一管理。struct evdev在evdev handler中代表一个eventX文件,而struct evdev由event handler指向的表示连接通道管理实体input_handle中的private指示,这样就完成了从抽象的handler管理到实体的handler的转换,进而使得系统从下层的设备层到上层的应用层的通路都是畅通的。

2ᤫ主要管理实体及功能

按照子系统三部分的划分,管理实体大体也分为三种,首先来看看系统对于下层input device的管理实体,细节如下:

978-7-111-49426-3-Chapter06-3.jpg

978-7-111-49426-3-Chapter06-4.jpg

978-7-111-49426-3-Chapter06-5.jpg

从input_dev中可见,它的属性兼容了各种输入设备,主要是在底层记录输入的数据和状态,便于进行一定的重复以及同时多事件(同时按键)的合并处理。

接下来是对于上层event handler的管理实体,细节如下:

978-7-111-49426-3-Chapter06-6.jpg

从上面的input handler分析可见,其中主要内容是操作接口,并且也包含了与应用层的接口file_operations文件操作。

接下来是管理input_dev和input_handler关联的实体input_handle,具体的信息如下:

978-7-111-49426-3-Chapter06-7.jpg

这三部分管理实体最终会根据实际情况连接成如图6-3所示的形式。

978-7-111-49426-3-Chapter06-8.jpg

图6-3 管理实体关系

从图6-3可见,中间的圆点代表input_handle,相应的名字是设备名,而对于input_dev和input_handler都可以是一对多的关系,需要注意的是所有的设备都会绑定evdev,也就是说evdev是接受所有设备绑定的。框架会有两个链表分别管理input_dev和input_handle。另外如kdb和sysrq这两个event handler都属于内核内部的event handler,用于内部模块对输入事件的监听。

事件是输入设备的数据流核心,整个输入设备系统的处理都是围绕这些事件进行的。不同类型的设备相应的事件也是不同的。应用层则要根据输入设备的事件进行相应的操作,为了给应用层统一的接口,输入设备框架对于输入事件进行了规范。

首先系统规范了事件类型。具体内容如下:

●EV_SYN:用于标记分段的事件,如坐标分为xyz,实际是三个子事件作为一个整体,通过SYN可将它们组合进行处理。另在multitouch的输入设备根据EV_SYN定义了规范,将多点同时的操作分组上报。

●EV_KEY:用于支持按键的事件,主要表示按键的状态转换。

●EV_REL:相对位移事件,主要用于鼠标这类设备。

●EV_ABS:绝对位置事件,主要用于触摸屏这类设备。

●EV_MSC:杂项事件,基本是将硬件信息直接上报由应用层处理,如传送扫描码。

●EV_SW:表示一些laptop中二值的状态。

●EV_LED:表示LED的开关。

●EV_SND:表示一些单音的输出。

●EV_REP:用于自动重复的事件。

●EV_FF:强制feedback事件给输入设备。

●EV_PWR:开关键的相关事件。

●EV_FF_STATUS:从设备返回的强制feedbak的状态信息。(www.chuimin.cn)

从这些事件可以看出,对于输入设备框架中考虑到PC、laptop等各种类型的输入设备,还可以反馈给设备需要的指示以及声音的相关操作,以反映用户的操作状态。典型的嵌入式设备前五种事件基本就能够涵盖相应的需求。每类事件的具体code信息可见input.h,其中有详细的定义。

3ᤫinput device和event handler的管理

输入设备子系统最重要的实体就是代表input device的input_dev和代表event handler的input_handler。接下来看看系统是如何对它们进行管理的。

通常框架层都需要实体的注册接口,来提供添加新的实体,先来看看input_dev的注册细节:

978-7-111-49426-3-Chapter06-9.jpg

978-7-111-49426-3-Chapter06-10.jpg

978-7-111-49426-3-Chapter06-11.jpg

从代码中可见,input device的内部属性都是为了各种类型的输入设备准备的,另外内核还提供了统一的操作接口来进行keycode的设置,这些基本属于标准操作。而相应设备的分配通过input_allocate_device来执行。

其中比较重要的就是与event handler的绑定,下面来分析一下具体的操作:

978-7-111-49426-3-Chapter06-12.jpg

从中可见主要就进行了两个操作:检查匹配和建立连接。下面分析一下匹配的流程:

978-7-111-49426-3-Chapter06-13.jpg

978-7-111-49426-3-Chapter06-14.jpg

可见在设备与handler的匹配中尽力进行匹配,而且允许进行宽泛的匹配,对于输入设备系统中最宽泛的匹配就是evdev handler,相应的id表如下:

978-7-111-49426-3-Chapter06-15.jpg

可见相应设置很简单,只要driver_info设置为1即可。

匹配之后的操作就是将input device与event handle建立连接,会调用event handler的connect接口函数,主要的工作是建立input_handle,并通过input_register_handle将相关网状连接建立起来。

系统的事件是如何传送的呢?通过input_event来进行事件的传送,具体如下:

978-7-111-49426-3-Chapter06-16.jpg

input_handle_event会根据具体的事件类型来判断是向上层event handler发送还是发送给input device或者两者都发送,进而进行对应的发送处理(主要是调用对应的接口函数)。向event handler转发最终通过input_pass_event来实现。

978-7-111-49426-3-Chapter06-17.jpg

978-7-111-49426-3-Chapter06-18.jpg

由于框架层提供诸如auto repeat等功能,所以也会使用input_pass_event来进行事件的传送。

为了设备操作方便,系统还基于input_event进行了封装,为不同类型的事件提供了事件转发操作的标准接口,接口如下:

978-7-111-49426-3-Chapter06-19.jpg

可见框架为了开发者的方便做了不少工作,这样统一的接口可以降低代码冗余度。整体上框架对input device和event handler的管理除了实体的管理外还负责事件的转发工作。

4ᤫ设备号管理及设备文件创建

对为应用层提供服务的框架,设备文件相关的管理是十分重要的,这里分析输入设备框架相关的实现。首先作为字符设备的子类型输入设备会统一注册文件操作接口,用于输入设备打开的管理。具体就是input_fops:

978-7-111-49426-3-Chapter06-20.jpg

从input_fops中可见其主要的操作就是open,具体的分析如下:

978-7-111-49426-3-Chapter06-21.jpg

978-7-111-49426-3-Chapter06-22.jpg

从分析可见,输入设备系统对应的设备文件使用统一的主设备号,而子设备号是与event handler相关的,不同的handler管理不同的子设备号。再来看看event handler的注册接口:

978-7-111-49426-3-Chapter06-23.jpg

978-7-111-49426-3-Chapter06-24.jpg

这里不仅包括对event handler的管理,由于event handler还要作为用户的接口,还要进行子设备的分配,只是输入框架已经提前预分配好了,每个handler管理32个设备。

最后再来看具体的evdev handler的connect操作:

978-7-111-49426-3-Chapter06-25.jpg

978-7-111-49426-3-Chapter06-26.jpg

978-7-111-49426-3-Chapter06-27.jpg

可见具体的设备号管理还是在event handler内部进行的。从实现中设备的层次设置可以了解到,设备的层次关系的添加是逐层进行的,这部分工作由各层独立完成。