驱动程序
1. 申请设备,设置input设备支持的事件类型(比如EV_ABS,EV_KEY)
input_allocate_device函数分配了一个 input_dev 结构体
button_dev = input_allocate_device();
button_dev->evbit[0] = BIT_MASK(EV_KEY);/*设置按键信息*/
button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
2.注册中断处理函数
例如键盘设备需要编写按键的抬起、放下,触摸屏设备需要编写按下、抬起、绝对移动,鼠标设备需要编写单击、抬起、相对移动,并且需要在必要的时候提交硬件数据(键值/坐标/状态等等)
中断程序中上报输入事件
input_report_key(button_dev, BTN_0, inb(BUTTON_PORT) & 1);
"input_dev->name 就是给上层open 的 /dev/input/enventX"
"/sys/class/input/inputX/"; --- name ---eventX
3.将输入设备注册到输入子系统中
input_register_device()函数是输入子系统核心(input core)提供的函数。该函数将input_dev结构体注册到输入子系统核心中,(注册过程是个匹配过程)
input_register_device
=> input_attach_handler
=>input_match_device
匹配过程
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
const struct input_device_id *id; // 定义一个input_device_id 的指针
int error;
id = input_match_device(handler, dev); // 通过这个函数进行handler与input设备的匹配工作
if (!id)
return -ENODEV;
error = handler->connect(handler, dev, id); // 匹配成功则调用 handler 中的 connect 函数进行连接
if (error && error != -ENODEV)
printk(KERN_ERR
"input: failed to attach handler %s to device %s, "
"error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error);
return error;
过滤
采用EV_ABS方式传送,input机制会过滤掉相同的值,所以会出现丢值的现象。如果采用EV_REL方式就可以解决这个问题了
disposition = input_handle_abs_event(dev, code, &value);//这里调用的input_handle_abs_event会将上次值和这次值相同的事件过滤掉
用户程序
设备的打开和读写
用户程序通过Input Handler层创建的设备节点的Open,read,write等函数打开和读写输入设备。
系统中有哪些输入设备
add device 2: /dev/input/event1 gsensor
name: "lsm303dlhc_mag"
add device 4: /dev/input/event4 keyboard
name: "7x27a_kp"
add device 5: /dev/input/event3 tp
name: "ft5x0x_ts"
add device 6: /dev/input/event2 psensor 和lsensor
name: "tmd2771x"
输入子系统的架构
分为三层
1、核心层 input.c
2、设备层 Gpio_keys.c
设备层涉及底层硬件
3、事件处理层 Evdev.c
事件处理层为纯软件的东西,事件处理层文件主要是用来支持输入设备并与用户空间交互,,这部分代码一般不需要我们自己去编写,因为Linux内核已经自带有一些事件处理器,可以支持大部分输入设备,比如evdev.c、mousedev.c、joydev.c等。
1)当我们按下鼠标左键的时候就会触发中断(中断是早就注册好的),
就会去执行中断所绑定的处理函数,在函数中就会去读取硬件寄存器来判断按下的是哪个按键和状态
2)将按键信息上报给input core层
3) input core层处理好了之后就会上报给input event层
4)在这里会将我们的输入事件封装成一个input_event结构体放入一个缓冲区中
5)应用层read就会将缓冲区中的数据读取出去。


