这次研究linux输入子系统
内核参考文档:linux_src_path/Documentation/input/input.txt
通过中断或者Timer定时查询将CPU通过SPI、I2C或外部储存器总线读取的键值,坐标等数据放入一个缓冲区,字符设备管理这个缓冲区, 驱动的read()接口让用户可以读取键值、坐标等数据。显然,中断、读取键值是与设备相关的,而输入事件 的缓冲区管理以及字符设备驱动的file_operations接口则对输入设备是通用的。所以设计了输入子系统。
层次分析
APP: /dev/input/xxxx
----------------------------------
kernel: 事件处理层 struct input_handler
负责创建设备文件以及将上报的事件传递到用户空间。
evdev.c
----------------------------------
input核心层
struct input_handle
提供相关结构体 + api
input.c
----------------------------------
input驱动层:
struct input_dev
input输入设备的驱动
----------------------------------
hardware: 鼠标 键盘 key....
通过 input driver -> Input core ->event handler -> userspace 到达用户空间传给应用程序。
驱动层:将底层的硬件输入转化为统一事件形式,向输入核心(Input Core)汇报。
驱动层主要操作:
1.struct input_dev my_dev = input_alloc_device(); 分配
2.input_register_device(my_dev); 注册
(1)list_add_tail(&dev->node, &input_dev_list); 将my_dev 添加到input_dev_list链表中
(2)list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler); 匹配input_dev 和 handler结构体 成功调用handler->connect函数
核心层 input.c major=13
作用:承上启下, 为驱动层 提供输入设备注册与操作接口,如:input_register_device;通知事件处理层对事件进行处理;在/Proc下产生相应的设备信息。
核心层主要功能: 1.提供核心API
2.err = class_register(&input_class); 注册输入设备类
3.err = register_chrdev(INPUT_MAJOR, "input", &input_fops); 申请设备号
事件处理层 evdev.c
作用:主要是和用户空间交互。(Linux中在用户空间将所有的设备都当初文件来处理,由于在一般的驱动程序中都有提供fops接口,以及在/dev下会生成相应的设备文件node,这些操作在输入子系统中由事件处理层完成)。
事件处理层:处理事件
1.input_register_handler(&evdev_handler);
(1)list_add_tail(&handler->node, &input_handler_list); 将handler参加到 input_handler_list 链表中
(2)list_for_each_entry(dev, &input_dev_list, node) 遍历input_dev_list链表中的struct input_dev结构体
input_attach_handler(dev, handler); 匹配input_dev 和 handler结构体 成功调用evdev_handler->connect函数。handler->connect:
evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);
evdev->dev.class = &input_class;
evdev->dev.parent = &dev->dev;
evdev->dev.release = evdev_free;
device_initialize(&evdev->dev);
error = input_register_handle(&evdev->handle); //字符设备注册
cdev_init(&evdev->cdev, &evdev_fops);
evdev->cdev.kobj.parent = &evdev->dev.kobj;
error = cdev_add(&evdev->cdev, evdev->dev.devt, 1);
error = device_add(&evdev->dev);
evdev_fops中 read函数 会有等待队列阻塞 ,直到驱动层调用input_event()函数,唤醒等待队列.
应用层程序编写:
(1)open:input的设备节点
(2)read: 将input上报的事件存储起来,再解析
(3)分析事件
Linux中输入设备的事件类型有
EV_SYN 0x00 同步事件
EV_KEY 0x01 按键事件,如KEY_VOLUMEDOWN
EV_REL 0x02 相对坐标, 如shubiao上报的坐标
EV_ABS 0x03 绝对坐标,如触摸屏上报的坐标
EV_MSC 0x04 其它
EV_LED 0x11 LED
EV_SND 0x12 声音
EV_REP 0x14 Repeat
EV_FF 0x15 力反馈
~~~~~~~~~~~~~~~~~~~~~~~~
EV_PWR 电源
EV_FF_STATUS 状态