文档库 最新最全的文档下载
当前位置:文档库 › 张栖银详谈Linux输入子系统

张栖银详谈Linux输入子系统

2015
张栖银详谈 Linux 输入子系统
张栖银 飞翔软件科技有限公司 2015/9/11

张栖银详谈 Linux 输入子系统 有任何问题可联系:zh5202@https://www.wendangku.net/doc/b514404211.html,


一、input 子系统介绍 ..................................................................................................................... 1 1.1 系统介绍............................................................................................................................ 1 1.2 input 子系统的引入 ........................................................................................................... 1 1.3 input 子系统的优点 ........................................................................................................... 2 1.4 input 子系统与字符设备实现比较 ................................................................................... 2 1.5 input 子系统与字符设备与应用层数据交互比较 ........................................................... 2 二、input 子系统实现 ..................................................................................................................... 4 2.1 input 子系统框架 ............................................................................................................... 4 2.2 input 子系统实现 ............................................................................................................... 6 2.2.1 输入子系统的注册................................................................................................. 6 2.2.2 输入子系统之 input_handler 的注册 .................................................................... 8 2.2.3 输入子系统之 input_dev 的注册 .......................................................................... 9 2.2.4 输入子系统之 input_handler 与 input_dev 的连接 ........................................... 10 2.2.5 输入子系统之数据结构框架 ............................................................................... 15 2.2.6 输入子系统之 input_dev 的事件上报 ................................................................ 16 三、input 子系统接口 ................................................................................................................... 18 3.1 input_dev 分配接口 ................................................................................................. 18 3.2 input_dev 注册接口 ................................................................................................. 18 3.3 input_handler 注册接口 ........................................................................................... 18 3.4 input_handle 注册接口 ............................................................................................ 19 3.5 事件上报接口.......................................................................................................... 19 四、input 子系统实例 ................................................................................................................... 19 4.1 输入子系统驱动编写流程 ...................................................................................... 19 4.2 驱动程序实现.......................................................................................................... 19 4.2 测试程序实现.......................................................................................................... 23
1

张栖银详谈 Linux 输入子系统 有任何问题可联系:zh5202@https://www.wendangku.net/doc/b514404211.html,
一、input 子系统介绍
1.1 系统介绍
本文是基于 linux-2.6.32 2.6.32 内核进行分析的,如果使用的是其他版本的内核,其内核调用 的函数可能有所不同,但是其实现原理是相通的。
1.2 input 子系统的引入
以前我们写一些输入设备 (键盘、 鼠标等) 的驱动都是采用字符设备、 混杂设备处理的。 问题由此而来,Linux 开源社区的大神们看到了这大量输入设备如此分散不堪,有木有可以 实现一种机制,可以对分散的、不同类别的输入设备进行统一的驱动,所以才出现了输入子 系统。 输入设备(如按键、键 输入设备(如按键、键盘,触摸屏,鼠标等)是典型的字符设备,其 ,其主设备号固定为 13,其一般的工作机制是在底层在按键、触摸、鼠标点击等动作发生时产生一个中断(或驱 动通过 timer 定时查询) ,然后 CPU 通过 SPI、IIC 或者外部存储器总线读取键值、坐标等数 据,放在一个缓冲区,字符设备驱动管理该缓冲区,而驱动的 read()接口让用户可以读取键 值、坐标等数据,其过程如图 ,其过程如图 1.1 所示。
图 1.1 input 子系统数据流向图 在 Linux 中,输入子系统是由输入子系统设备驱动层、输入子系统核心层( 中,输入子系统是由 输入子系统核心层(input core) 和输入子系统事件处理层( (Event handler)组成,如图 1.2 所示。其中设备驱动层提供对硬 设备驱动层提供对硬 件各寄存器的读写访问和将底层硬件对用户输入访问的响应转换为标准的输入事件, 再通过 核心层提交给事件处理层; ; 而核心层对下提供了设备驱动层的编程接口, 而核心层对下提供了设备驱动层的编程接口, 对上又提供了事件 处理层的编程接口; 而事件处理层就为我们用户空间的应用程序提供了统一访问设备的接口 事件处理层就为我们用户空间的应用程序提供了统一访问设备的接口 和驱动层提交来的事件处理。 和驱动层提交来的事件处理。 所以这使得我们输入设备的驱动部分不在用户关心对设备文件 的操作,而是要关心对各硬件寄存器的操作和提交的输入事件。
图 1.2 输入子系统结构图
1

张栖银详谈 Linux 输入子系统 有任何问题可联系:zh5202@https://www.wendangku.net/doc/b514404211.html,
1.3 input 子系统的优点
输入子系统的引入,也为我们带来了许多的好处: ? 统一了物理形态各异的相似的输入设备的处理功能。 例如, 各种鼠标, 不论 PS/2、 USB、 还是蓝牙,都被同样处理。 ? 提供了用于分发输入报告给用户应用程序的简单的事件(event)接口。你的驱动不必 创建、 管理/dev 节点以及相关的访问方法。 因此它能够很方便的调用输入 API 以发送鼠 标移动、键盘按键,或触摸事件给用户空间。X windows 这样的应用程序能够无缝地运 行于输入子系统提供的 event 接口之上。 ? 抽取出了输入驱动的通用部分,简化了驱动,并提供了一致性。例如,输入子系统提供 了一个底层驱动(称为 serio)的集合,支持对串口和键盘控制器等硬件输入的访问。 注:更多详细描述可参见《精通 Linux 设备驱动程序开发》这本书。 更重要的是,input 子系统的引入,使我们在具体的开发中可以在输入硬件设备更换的 情况下保持应用不做任何修改。
1.4 input 子系统与字符设备实现比较
在进行字符设备驱动程序开发的过程中,我们的实现步骤如下: ? 申请一个字符设备号:可以自己指定,也可系统自动分配; ? 构造一个 file_operations 结构体,其包含对设备的所有操作; ? 实现 file_operations 结构体中的成员函数; ? 将字符设备注册进系统中:register_chrdev(); ? 创建设备类和设备节点:class_create()、device_create(); ? 告诉内核入口与出口函数:module_init()、module_exit(); 输入子系统与混杂设备驱动一样, 也是一个典型的字符设备, 那么其注册的过程与字符 设备驱动一样, 也必须经过上面的这些步骤。 只是输入子系统中的输入设备一般只接收输入 设备的中断和获取输入设备的数据,而不输出数据到输入设备而已。 在输入子系统中,将字符设备驱动分为了三个部分:与硬件操作相关的设备驱动层(由 驱动工程师实现) 、 输入子系统核心层 (input core) 和输入子系统事件处理层 (Event handler) , 其中后面两个部分都已经由系统帮我们实现了。 其实后面两个部分可以把它看作是一个整体, 就是与硬件操作无关的软件部分。那么我们实现 input 设备驱动的过程为: ? 申请一个输入设备结构体:input_allocate_device(); ? 设置输入设备支持的事务类型:set_bit(xxx,devp->evbit); ? 设置输入设备支持的具体哪些事务:set_bit(xxx,devp->xxxbit); ? 注册输入设备到输入子系统:input_register_device(devp); ? 实现具体的硬件相关操作,如注册中断等,并在中断处理函数中通知事务已发生: input_event()、input_sync(); 也就是说:无论输入子系统多么强大、封装的多么的好,与硬件相关的操作还是得我们 亲自实现。
1.5 input 子系统与字符设备与应用层数据交互比较
编写过字符设备驱动的人都知道,应用程序与驱动直线实现数据交互就是通过应用 API 的 read()、 write()调用, 从而产生一个 SWI 软件中断, 然后通过主设备好找到对应的 struct cdev 结构体实体,从而找到具体硬件设备的 struct file_operations 结构体,然后具体调用底层的 drv_read()、 drv_write(), 我们就是在具体的 drv_read()和 drv_write()中实现对硬件的操作的,
2

张栖银详谈 Linux 输入子系统 有任何问题可联系:zh5202@https://www.wendangku.net/doc/b514404211.html,
其过程如下: read()—>swi_read()—>drv_read()—>硬件操作 那么对应到输入子系统呢?前面已经说了, 输入子系统也是字符设备, 那么它也必须经 历上面的这些步骤, 只是中间穿插了几个查找具体输入设备的过程 (毕竟将所有的输入设备 都加入到输入子系统,就不止一个设备了)而已。那么是如何穿插的呢: 首先在 input.c(输入子系统的核心)文件的打开函数中找到具体的 input_handler,然 后取出具体 input_handler 中的 fops(也即 struct file_operations 结构体)填充 struct file 中的 f_op 成员,那么之后应用调用 read()、write()函数就是调用具体 input_handler 指向的 struct file_operations 结构体中的成员了;最后再调用 fops 中的 open()函数打开具体的函数: struct input_handler *handler; handler = input_table[iminor(inode) >> 5]; old_fops = file->f_op; file->f_op = new_fops; err = new_fops->open(inode, file); 这里说明一下:input.c 是 input 子系统的核心,内核已经实现,各种 input_handler(包 含 open、release、read、write、ioctl、fasync、poll 等,即硬件处理函数)也由系统抽象出 来帮我们实现了,后面会讲解其具体实现过程。 通过前面的介绍,不太理解也没有关系。你只需要记住,其实输入子系统就是一个典型 的字符设备,它也逃不过字符设备的框架,其应用与驱动交互的流程也和字符设备驱动一 样,没有什么不同就是了(要从心里小瞧它) 。 要想搞明白输入子系统的框架, 只需要弄明白应用程序是如何与具体的硬件设备驱动进 行交互的就行了。而这个过程如下其实就是主设备号 13 的字符设备、 input_handler 、 input_handle 和 input_dev 几个的关系: ? Linux 系统启动时注册输入子系统(注册主设备号为 13 的字符设备) ; ? 应用程序调用 open(),对应调用输入子系统的 input_open_file(); ? input_open_file()找到对应的 input_handler,并调用其中的 open(); ? 应用程序调用 read()函数,对应调用 open()中找到的 input_handler 中的 read()函数,阻 塞; ? 驱动收到硬件访问需求,进入中断处理函数,对应到 input_dev; ? 驱动调用 input_event()上报事件,上报过程为:通过 input_dev 找到 input_handle,再 通过 input_handle 找到匹配的 input_handler, 然后调用该 input_handler 的 event()函数, 该函数即是唤醒对应 read()、write()函数的实现; 详细过程如下三条线路所示: ? open()—>input_open_file()—>input_handler->fops->open() ? read()/write()/ioctl()—>input_handler->fops->read()/write()/ioctl() ? 硬 件 — >input_dev 的 中 断 处 理 程 序 — >input_event() —>input_handle->input_handler->event() 注意:->是指针;—>是下一步调用。 从应用到底层的匹配过程是通过 input_handler, 具体驱动中是通过静态全局指针数组变 量 input_table[]实现的;而硬件到应用程序的匹配过程是通过 input_handle 结构体找到对应 的 input_handler,从而实现数据传输的,具体到代码就是通过 input_handler->connect()函数 将 input_dev、input_handler 和 input_handle 三者进行绑定的,三者绑定的关系如图 1.3 所 示。
3

张栖银详谈 Linux 输入子系统 有任何问题可联系:zh5202@https://www.wendangku.net/doc/b514404211.html,
图 1.3 input_dev、input_handler 与 input_handle 之间的关系
二、input 子系统实现
本章节将详细讲解 input 子系统的框架,也就是 input 子系统中如何实现应用层数据与 底层硬件之间的数据交互、底层硬件(input_dev)如何与系统实现的驱动(input_handler) 关联等。
2.1 input 子系统框架
正如前面的介绍,input 子系统将所有的输入设备统称为像鼠标输入、键盘输入、joydev 输入等,将输入的数据封装成统一的事务格式(struct input_event)上传到应用,而将具体 的硬件设备分离出来(这才是我们要做的事) ,如图 2.1 所示。
图 2.1 input 系统分层 在如上的系统分层结构下,我们的应用程序就可以不用关心获取到的数据是来源于 SPI 的键盘、还是 IIC 的键盘,它只需要关心获取到数据的具体含义就行了,这样就保证了更换 不同的硬件设备,而不用修改一行应用程序代码,如图 2.2 所示。
4

张栖银详谈 Linux 输入子系统 有任何问题可联系:zh5202@https://www.wendangku.net/doc/b514404211.html,
图 2.2 应用程序与 input 子系统设备的关系 那么按照如上的思想,我们可以很明确的看出 input 子系统的框架包含三个层次: 子系统的框架包含三个层次:设备 驱动层 (input dev) 、 输入子系统核心层 (input core) 和输入子系统事件处理层 输入子系统事件处理层 (Event handler) , 正如前面所提到的。这三个层次的框架及对应到 这三个层次的框架及对应到 Linux 内核的源码关系如图 2.3 所示。
图 2.3 input 子系统框架及源码对应关系 接下来的内容,将以 evdev.c 和 gpio_keys.c 为例详细介绍 input 子系统的实现过程,主 要包括: 1.输入子系统的注册; 2.输入子系统 input_handler 的注册; 3.输入子系统 input_dev 的注册; 4.输入子系统 input_handler 与 input_dev 的连接; 5.输入子系统 input_dev 的事件上报;
5

相关文档