转《Linux input子系统分析之一:软件层次》

本文转自:https://blog.csdn.net/yueqian_scut/article/details/47903853



输入输出是用户和产品交互的手段,因此输入驱动开发在Linux驱动开发中很常见。同时,input子系统的分层架构思想在Linux驱动设计中极具代表性和先进性,因此对Linux input子系统进行深入分析很有意义。

一、input子系统知识点

完整的input子系统分析包括以下几方面:

1) 软件层次

2) 输入子系统分层(input_handler,input_core, input_device)

3) 输入设备(TS)驱动开发

4) evdev handler分析

5) input设备模型视图(sysfs)和运行映象(procfs)

6) tslib分析

7) 应用框架的事件处理分析

笔者一向主张学习嵌入式应尽可能培养具备分析Linux软件架构的大局观。本文将从需求的角度去分析Linux输入所涉及的应用和内核层的相关模块所承担的角色和完成的功能,让开发人员能够对Linux驱动的所涉及的整个软件层次有清晰的认识。其他知识点将在后文进行阐述,敬请关注。

二、软件层次分析

Linux输入所涉及的软件层次如下图:


基于Linux内核的应用框架常见于Android和QT。由于Android4.2对触屏驱动的支持发生过重大的变化(将tslib完成的任务抛给驱动层来完成),所以我们以较为简单的QT框架来说明Linux输入的调用过程。假设有以下基于QT的通讯录应用场景,我们重点分析查询这个button控件的输入响应过程。


1.APP即通讯录应用,输入姓名拼音首字母,然后点击查询,输出结果(姓名和电话号码)。APP在QT creator可视化开发环境上使用所见即所得的方式拖入Button控件作为“查询”按钮。APP不需要关注按钮的显示,也不需要关心用户通过何种方式按下按钮,只需要做的是对按钮的单击事件进行响应,即通过姓名首字母来对姓名数据库进行查询并输出到结构框中。

2.QT应用框架需要完成APP开发所不需要关注的事情,即对输入事件进行封装处理、分发事件到目标控件、完成目标控件的状态变化和图像显示,当然还包括窗口的管理。上述应用图示是一个LCD屏显示页面,LCD的坐标点在左上角,如下图:


对于QT应用框架来说,用户点击了屏幕,QT的事件处理会收到一个坐标事件,即相对LCD坐标原点的触点坐标(x,y)。QT会对该坐标进行分析,在当前焦点窗口系统中检测该坐标落到哪个控件的显示范围。明显,“查询”按键在窗口中有坐标范围,由左上角和右下角两个坐标点确定其范围。如果判断用户触控的坐标落到该范围,QT即会分发一个单击事件给“查询”按键控件,最终QT通过回调的方式调用APP开发中编写的查询逻辑函数,并输出到结果框中。

3.Tslib,从名称来看就可明确其是触摸屏TS场景的一个中间库。其主要完成触控坐标消息的去抖、滤波和校准等功能。其最核心的功能是从触摸屏坐标系到LCD显示屏坐标系的线性转换。电子产品的触摸屏一般包括触摸屏和显示屏两个部分,触摸屏在显示屏之上,有电阻和电容分压原理之分。在TS驱动实现中,触摸屏的坐标原点是在屏幕的左下角,即驱动向TSLIB提供的基于左下角为原点的坐标系坐标,而TSLIB需要向QT应用框架提供基于左上角为原点的坐标系统坐标,因此TSLIB需要完成坐标系的转换。如下图:


另外,触摸屏的分辨率和LCD显示屏的分辨率也有可能不一样,因此坐标的转换还要考虑分辨率的因素。

4.C library,Tslib必须通过open,read这些标准c接口访问内核层驱动,而这些接口最终都会使用syscall指令跳转到内核态。

5.VFS,open、read等接口通过syscall系统调用层最终会调用到vfs_open、vfs_read等接口。Open所带参数为输入设备文件名,如/dev/input/event1,vfs_open通过lookup在dentry链表中找到该设备文件对应的inode,进而分析出该文件是一个字符设备文件,交由字符设备驱动框架的chardev_open进行处理,最终获得输入子系统(主设备号都是13)对应的input-core层定义的file_operations,并封装到所在进程的file结构中,最后向应用层返回file对应的句柄fd,而read则是通过该file_operations进行读转发和访问操作。

6.字符设备驱动框架层。chardev_open通过设备文件对应的inode读出对应的主设备号是13,并在字符设备驱动全局链表cdev_map中找到主设备号13对应的file_operations, 即输入子系统初始化时向系统注册的input_fops。如下图:


如何访问不同的输入设备,如触摸屏和按键等等,是由input_fops的open来负责。input_fops即为input-core的组成部分。

7.输入子系统,输入子系统对linux的输入设备驱动进行了高度抽象,最终分成了三层,包括input核心层、input事件处理层和input设备驱动层。如下图:


1)所有的输入设备的主设备号都是13,其通过次设备来将输入设备进行分类,如下图:


2)对于应用层来说,其并不关心输入设备驱动层,其只关心输入事件处理层,即关注哪种类型的输入设备。

3)系统初始化时,事件处理层(input-handler)向input-core注册自己,并告知input-core其能处理底层设备驱动的类型和能力,例如event_handler事件处理(evdev.c)能够处理触摸屏和按键驱动。

4)当输入设备驱动input-device向input-core注册时,input-core会给其匹配合适的事件处理层input-handler,最终用input-handle来关联两者,并在input-handler的控制下生成用户访问的字符设备文件,如如/dev/input/event0对应的次设备号即是64。

8.input核心层,有了以上的分析,我们再继续分析input-core的input_open_file,假如设备文件名为/dev/input/event0,那次设备号即64,input_open_file通过次设备号得到对应的事件处理层event_handler,并交给该handler进行管理。

9.input事件处理层,event_handler根据次设备号可以得到该输入驱动在其管理设备数组中evdev_table的偏移(为0),进而得到对应的input_handle,最终找到关联的输入设备驱动input-device。

10.input设备驱动层,输入设备驱动层的open会进行硬件初始化等。

11.VFS层以下我们着重分析了驱动的open过程,接下来我们来分析一下触屏消息的产生和读取过程。

1)可以想象出在QT应用框架中会有一个高优先级的线程一直在等待读取触摸和按键消息。当没有消息产生时,该线程处于休眠状态。

2)当用户触屏时,触摸屏会产生一个外部硬件中断,在输入设备驱动的中断处理中会读取触屏坐标,并向其对应的input-handler汇报,而input-handler在分析该消息是否是重复消息等过程后向打开该handler的线程发送信号量进行唤醒,并将该触屏消息填入线程的消息队列。

3)QT应用框架线程会通过tslib的接口来读取该消息,最终获得LCD坐标系坐标,并进行后续处理。

 

备注:输入子系统分层(input_handler, input_core, input_device)、输入设备(TS)驱动开发、evdev handler分析、input设备模型视图(sysfs)和运行映象(procfs)、tslib机制分析、应用框架的事件处理分析等系列知识待后续补充。谢谢!

 

同时,我们还应该看到,触摸屏可能是I2C总线接口、UART接口、USB接口等等,因此触摸屏设备驱动层不仅作为一个input_device存在,还有可能作为一个I2C设备而存在等等。而I2C设备驱动又需要对I2C子系统进行分析。继续努力吧~~

猜你喜欢

转载自blog.csdn.net/amwha/article/details/79868238