基于input子系统的驱动分析
input子系统本质多个模块构成的一个体系,用来实现:对鼠标、键盘、按键这类输入设备驱动的管理。这里所谓的输入设备,是狭义上的,仅仅指人机交互用的输入设备。传感器这种输入设备不属于该范围。
下图是input子系统的结构
值得注意的是,虽然事件处理层主要有event类型的、mouse类型的、key类型的,但是event类型兼容所有的输入设备,并有取代其他类型的趋势。可以认为,所有的设备在/dev/input下,都是以event*命名的
下图是系统工作的具体流程
1.事件处理层分析
事件处理层负责接受驱动层的汇报上来的数据,然后打包成标准格式再给应用层。此外设备文件也是事件处理层负责创建的。
- 应用层可以打开/dev/input/eventx,即可读取到标准格式的输入事件包struct input_event
- struct input_event是一个标准的格式包,由事件处理层创建并传递给应用层。当一个输入事件发生时,会发送多个input_event,形成一帧数据。下面是
<linux/input.h>
中定义的input_event原型。
struct input_event {
struct timeval time;//表示输入事件发生时间点
__u16 type;//输入事件类型
__u16 code;//输入事件编码值
__s32 value;//操作值
};
- input_event内元素值对应的含义,在
<linux/input.h>
中定义
2.核心层(input.c)分析
- input.c中是input设备框架,它是一个模块,该模块加载函数做的事情非常典型,主要还是注册类和注册设备
/*该模块加载函数做的事情非常典型,主要还是注册类和注册设备*/
static int __init input_init(void)
{
/*无关代码就不贴了*/
...
/*注册了一个叫input的类*/
err = class_register(&input_class);
/*无关代码就不贴了*/
...
/*注册input设备,所有的input设备的主设备号都为13*/
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
/*无关代码就不贴了*/
...
}
- 所有的input设备公用一个主设备号(都是13),它们之间以次设备号互相区分。所以在框架中使用register_chrdev注册了一个主设备号为13的设备,而在事件处理层中创建设备文件主设备号都为13,次设备号不同
3.驱动分析
下图是驱动的具体流程
其本质是:驱动只需通过上报读到的硬件状态给事件处理层,其他的都由事件处理层负责。应用层只需读取/dev/input/event*即可
下面是具体的源码,以最常见的按键驱动为例
- 该驱动基于platform总线,相关知识详见platform总线驱动详尽分析
此外还用到了中断,相关知识详见内核的中断机制
源码:
#include <linux/input.h>
#include <linux/module.h>