赞
踩
按键、鼠标、键盘、触摸屏等都属于输入(input)设备,Linux 内核为此专门做了一个叫做 input子系统的框架来处理输入事件。输入设备本质上还是字符设备,只是在此基础上套上了 input 框架,用户只需要负责上报输入事件,比如按键值、坐标等信息,input 核心层负责处理这些事件。
按键输入、键盘、鼠标、触摸屏等都属于输入设备,不同的输入设备所代表的含义不同,按键和键盘就是代表按键信息,鼠标和触摸屏代表坐标信息,因此在应用层的处理就不同,对于驱动编写者而言不需要去关心应用层的事情,我们只需要按照要求上报这些输入事件即可。为此 input 子系统分为 input 驱动层、input 核心层、input 事件处理层,最终给用户空间提供可访问的设备节点。
目的:简化驱动开发人员操作,驱动开发者只需上报事件,至于事件如何处理并提供给应用层使用则无需关心。
左边就是最底层的具体设备,比如按键、USB 键盘/鼠标等,中间部分属于Linux 内核空间,分为驱动层、核心层和事件层,最右边的就是用户空间,所有的输入设备以文件的形式供用户应用程序使用,可以看出 input 子系统用到了我们前面讲解的驱动分层模型。
我们编写驱动程序的时候只需要关注中间的驱动层、核心层和事件层,这三个层的分工如下:
核心层和事件层之间通过一些接口和数据结构进行交互,以实现输入事件的传递和处理。
也就是说input子系统的核心层和事件层已经写好,驱动开发者只需要按照要求上报事件给核心层即可,无需关心事件的处理和传递,这也体现出驱动分层的思想。
input 核心层会向 Linux 内核注册一个字符设备,大家找到 drivers/input/input.c 这个文件,input.c 就是 input 输入子系统的核心层。
- struct class input_class = {
- name = "input",
- devnode = input_devnode,
- };
- ......
- static int __init input_init(void)
- {
- int err;
- err = class_register(&input_class);// 向内核注册一个类
- if (err) {
- pr_err("unable to register input_dev class\n");
- return err;
- }
-
- err = input_proc_init();
- if (err)
- goto fail1;
-
- err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0),// 注册字符设备
- INPUT_MAX_CHAR_DEVICES, "input");
- if (err) {
- pr_err("unable to register char major %d", INPUT_MAJOR);
- goto fail2;
- }
-
- return 0;
-
- fail2: input_proc_exit();
- fail1: class_unregister(&input_class);
- return err;
- }

注释1:注册一个 input 类,这样系统启动以后就会在 /sys/class 目录下有一个 input 子目录。
注释2:注册一个字符设备,主设备号为 INPUT_MAJOR,INPUT_MAJOR 定义在 include/uapi/linux/major.h 文件中:
#define INPUT_MAJOR 13
因此,input 子系统的所有设备主设备号都为 13,我们在使用 input 子系统处理输入设备的时候就不需要去注册字符设备了,我们只需要向系统注册一个 input_device 即可。(不需要自行注册字符设备,但需要提供一个input_device)
使用 input 子系统的时候我们只需要注册一个 input 设备即可,input_dev 结构体表示 input 设备:
- struct input_dev {
- const char *name;
- const char *phys;
- const char *uniq;
- struct input_id id;
-
- unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
-
- unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; /* 事件类型的位图 */
- unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; /* 按键值的位图 */
- unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; /* 相对坐标的位图 */
- unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; /* 绝对坐标的位图 */
- unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; /* 杂项事件的位图 */
- unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; /*LED 相关的位图 */
- unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];/* sound 有关的位图 */
- unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; /* 压力反馈的位图 */
- unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; /*开关状态的位图 */
-
- bool devres_managed;
- };

evbit 表示输入事件类型,另外几个位图是该事件的对应值,比如 keybit 就是按键事件使用的
位图,可选事件类型定义在 include/uapi/linux/input.h 文件中:
- #define EV_SYN 0x00 /* 同步事件 */
- #define EV_KEY 0x01 /* 按键事件 */
- #define EV_REL 0x02 /* 相对坐标事件 */
- #define EV_ABS 0x03 /* 绝对坐标事件 */
- #define EV_MSC 0x04 /* 杂项(其他)事件 */
- #define EV_SW 0x05 /* 开关事件 */
- #define EV_LED 0x11 /* LED */
- #define EV_SND 0x12 /* sound(声音) */
- #define EV_REP 0x14 /* 重复事件 */
- #define EV_FF 0x15 /* 压力事件 */
- #define EV_PWR 0x16 /* 电源事件 */
- #define EV_FF_STATUS 0x17 /* 压力状态事件 */
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。