1. 总论
2. 导航
3. 实例
3.1 键盘
3.2 触摸屏
1. 总论
Input子系统为一些常用的小规模数据传输的设备提供统一的数据上报系统,把数据以统一的格式上传到用户空间。适用于Input子系统的设备有摇杆、鼠标、键盘、触摸屏,Misc等。
2. 导航
Input子系统配置步骤如下,
2.1 申请和初始化input设备 input_allocate_device();
设备的数据结构里存放一个struct input_dev类型的结构,用于存放input设备。该结构定义于/include/linux/input.c,
2.2 设置input与设备相关的bit位
linux为input的设备提供以上不同类型的事件,每一类事件比如keybit[],其中的每一位代表一个事件,比如按键的上、下、左、右等。
驱动程序里只要对设备相关的事件设置对应的bit位即可。
2.3 注册input设备 input_register_device(input_dev);
2.4 上报数据 input_report_xxx(input_dev, code, value)
驱动程序将设备数据value通过input_report_xxx()的方式上报给input核心层,核心层完成将数据从内核空间上传到用户空间。
xxx表示事件的类型,比如键盘事件就是input_report_key(), code代表按键的类型(由input系统定义),value代表该按键的状态(通过驱动得到数据);触摸屏事件就是input_report_abs(),code代表触摸的类型(由input系统定义),比如压力,或者x轴,y轴,value代表压力值或坐标值(通过驱动得到数据)。
下面进入input核心层,看看数据具体是如何上报的,以input_report_key()为例,
最终调用了回调函数handle->handler->event(); 注意到handle这个数据结构,它是struct input_dev里的一个成员,而struct input_dev在设备驱动初始化的时候被唯一地申请并注册,这里的handle就是用来指代这个input设备,即键盘,这样,回调函数handle->handler->event()就可以通过这个handle找到指定的键盘设备。
struct evdev *evdev里存放的就是通过handle从底层得到的设备驱动的数据结构
struct evdev_client *client为最终用户空间可以访问的数据结构,其中存放了事件类型type,数据类型code和数据数值value。
下图为一个上层应用的例子,
3. 实例
3.1 键盘
1)橙色部分为系统初始化后得到的platform_device结构的数据,包括,键盘控制器的物理地址,中断号,以及键盘矩阵对应的键值等。
2)蓝色部分就是通过input子系统注册的键盘设备驱动,分别完成了上文提到的1,2,3步,即申请input,设置input相关bit,注册input。
注意到粉红色的代码所实现的,就把把键盘矩阵对应的键值(按键类型code)申报到input子系统中相对应的bit位中,具体地,
如图所示,确认键的矩阵坐标(0,0),左键对应的矩阵坐标(2,0),
首先,系统初始化时对这些矩阵坐标配置键值(按键类型code),(0,0)配置为confirm,(2,0)配置为left,然后把键值存放到platform_device里,接着,驱动程序提取键值,并将其赋给input系统中相对应的位,这些位定义于/include/linux/input.h。
3)绿色部分就是上文提到的第4步-上报数据。
当有键按下或者弹起,驱动程序引发中断函数,即键盘扫描函数。
通过键盘控制器的寄存器得到按下或弹起键的矩阵坐标(row, col),再由坐标得到相对应的键值(按键类型code),最后由input_report_key(input, code, value)完成数据的上报。注意上报完数据后要用input_sync()同步。
3.2 触摸屏
1)橙色部分为系统初始化后得到的platform_device结构的数据,主要为芯片上的引脚申请GPIO口,电路图如下图所示,
2)蓝色部分就是通过input子系统注册的触摸屏设备驱动,即申请input,设置input相关bit,注册input设备。这里主要设置了触摸屏的压力pressure以及坐标轴X,Y事件。
3)上报数据。
触摸笔按下产生中断,触发中断处理函数,唤醒一个读取和解析触摸屏坐标数据的线程(之所以使用线程,是因为读取和解析数据的开销比较大),最终通过input子系统上报坐标值。同样,用input_sync()同步。