理论:
输入子系统由来
在Linux中, 应用层对于输入设备(鼠标、键盘、触摸屏等)的操作无非都是open、read、write、ioctl,然后调用驱动层的xxx_open、xxx_read、xxx_write、xxx_ioctl去操作具体的硬件输入设备。如果按照传统的思路,每个输入设备都按照这个套路写这些open、read等,是不是太过于累赘了。所以Linux就定义了一套标准,来标准化这些输入设备驱动,这个标准就叫做输入子系统。通过这个标准,写驱动的人不在重复的写xxx_open、xxx_read等通用代码,而只用完成各个输入设备不同的部分(注册不同的输入设备, 上报不同的输入事件,操作不同的硬件等)。
输入子系统框架
在Linux中,输入子系统是由输入子系统设备驱动层、输入子系统核心层(Input Core)和输入子系统事件处理层(Event Handler)组成。其中设备驱动层提供对硬件各寄存器的读写访问和将底层硬件对用户输入访问的响应转换为标准的输入事件,再通过核心层提交给事件处理层;而核心层对下提供了设备驱动层的编程接口,对上又提供了事件处理层的编程接口;而事件处理层就为我们用户空间的应用程序提供了统一访问设备的接口和驱动层提交来的事件处理。所以这使得我们输入设备的驱动部分不在用关心对设备文件的操作,而是要关心对各硬件寄存器的操作和提交的输入事件。下面用图形来描述一下这三者的关系吧!(转)
Linux输入子系统的结构体:
应用空间:
open(“/dev/input/eventx”)
内核空间:
输入子系统设备驱动
向输入系统核心注册一个具体类型的输入设备,检测输入事件的发生,并上报输入事件到输入子系统事件处理层。
输入子系统核心
提供各个输入设备的注册接口,设备驱动上报事件到事件处理层的桥梁。
输入子系统事件处理层
接收设备驱动上报的输入事件,提供应用层访问设备统一的接口(open, read等),将事件通过接口传递到用户空间。
底层硬件:
鼠标 键盘 触摸屏等
通过输入系统的这个框架发现,我们需要做的事情就是对于不同的输入设备,写出对应的设备驱动,并向输入系统核心注册这个输入设备当检测到有输入事件发生,将输入事件上报到输入子系统事件处理层就OK了。
具体操作:
首先,对触摸屏数据的采集是采用i2c接口或者spi接口,本例子以i2c接口为例,那么首先要熟悉i2c驱动的框架。
1. 注册一个i2c_driver结构体,去匹配i2c_device机构体(i2c_device可以通过添加board_info,设备树等方式创建,这里不做详细介绍)
/* 分配/设置i2c_driver */
static struct i2c_driver mts_driver = {
.driver = {
.name = "my_mts",
.owner = THIS_MODULE,
},
.id_table = mts_id_table,
.probe = mts_probe,
.remove = mts_remove,
};
static const struct i2c_device_id mts_id_table[] = {
{ "my_mts", 0 },
{}
};
/* 注册i2c_driver */
i2c_add_driver(&mts_driver);
2. 在i2c的probe函数中分配、设置、注册一个input_dev结构体。
static int mts_probe(struct i2c_client *client, const struct i2c_device_id *id) {
ts_client = client; //记录i2c_client
/* 2.1分配input_dev结构体 */
struct input_dev * ts_dev = input_allocate_device();
/* 2.2设置这个input_dev结构体 */
//设置这个输入设备能产生哪类事件 -- 能产生同步事件EV_SYN 和 绝对坐标事件EV_ABS
set_bit(EV_SYN, ts_dev->evbit);
set_bit(EV_ABS, ts_dev->evbit);
//能产生这类事件中的哪些具体事件 -- X轴坐标ABS_MT_POSITION_X Y轴坐标ABS_MT_POSITION_Y 和触点的ID ABS_MT_TRACKING_ID
set_bit(ABS_MT_TRACKING_ID, ts_dev->absbit); //对于多点触摸屏,每一个触点都有一个ABS_MT_TRACKING_ID
set_bit(ABS_MT_POSITION_X, ts_dev->absbit);
set_bit(ABS_MT_POSITION_Y, ts_dev->absbit);
//这些事件的范围
//支持多少个触点,具体支持多少个,由具体硬件手册决定
input_set_abs_params(ts_dev, ABS_MT_TRACKING_ID, 0, MTS_MAX_ID, 0, 0);
//X轴和Y轴的最大值,由硬件手册看触摸屏分辨率决定
input_set_abs_params(ts_dev, ABS_MT_POSITION_X, 0, MTS_MAX_X, 0, 0);
input_set_abs_params(ts_dev, ABS_MT_POSITION_Y, 0, MTS_MAX_Y, 0,