输入子系统:
1、定义:Linux系统支持的输入设备繁多,例如键盘、鼠标、触摸屏、手柄或者是一些输入设备像体感输入等等,Linux系统是如何管理如此之多的不同类型、不同原理、不同的输入信息的输入设备的呢?其实就是通过input输入子系统这套软件体系来完成的。
2、组成:输入子系统由驱动层、输入子系统核心、事件处理层三部分组成。
驱动层:将底层的硬件输入转化为统一事件形式,向输入核心(Input Core)汇报。
输入子系统核心:承上启下。为驱动层提供输入设备注册与操作接口,如:input_register_device;通知事件处理层对事件进行处理;在/Proc下产生相应的设备信息
事件处理层:主要是和用户空间交互。(Linux中在用户空间将所有的设备都当初文件来处理,由于在一般的驱动程序中都有提供fops接口,以及在/dev下生成相应的设备文件nod,这些操作在输入子系统中由事件处理层完成)
3、框架:
一个大致的工作流程就是,input device向上层报告–>input core接收报告,并根据在注册input device时建立好的连接选择哪一类handler来处理事件–>通过handler将数据存放在相应的 dev(evdev,mousedev…)实例的缓冲区中,等待应用程序来读取。
4、数据结构
struct input_dev 设备结构体,记录了设备的信息和支持的事件
struct input_dev {
const char *name; //设备名
const char *phys; //设备节点名称
const char *uniq; // 唯一的ID号,
struct input_id id; // 输入设备ID,用于和event handler 匹配
unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; //bitmap of device properties and quirks
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //设备支持的事件类型
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //按键 ex:上下左右 home
unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //相对坐标 ex 鼠标
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //绝对坐标 ex 触摸屏
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; //其他功能
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; //指示灯
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; //声音或警报
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; //作用力
unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; //开关
unsigned int hint_events_per_packet; /* average number of events generated by the device in a packet (between EV_SYN/SYN_REPORT events). Used by event handlers to estimate size of the buffer needed to hold events.*/
unsigned int keycodemax; //设备支持最大按键值个数
unsigned int keycodesize; //每个按键字节大小
void *keycode; //按键池,指向按键值数组首地址
int (*setkeycode)(struct input_dev *dev,
const struct input_keymap_entry *ke,
unsigned int *old_keycode); //修改按键值
int (*getkeycode)(struct input_dev *dev,
struct input_keymap_entry *ke); //获取按键值
struct ff_device *ff; //强制更新输入设备的部分内容
unsigned int repeat_key; //重复按键的键值
struct timer_list timer; //连击时定时器
int rep[REP_CNT]; //重复按键参数值
struct input_mt_slot *mt; //pointer to multitouch state
int mtsize;
int slot;
int trkid;
struct input_absinfo *absinfo; /* array of struct input_absinfo elements holding information about absolute axes (current value, min, max, flat, fuzz, resolution) */
unsigned long key[BITS_TO_LONGS(KEY_CNT)]; //记录状态
unsigned long led[BITS_TO_LONGS(LED_CNT)];
unsigned long snd[BITS_TO_LONGS(SND_CNT)];
unsigned long sw[BITS_TO_LONGS(SW_CNT)];
int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev);
int (*flush)(struct input_dev *dev, struct file *file); //输入设备断开后刷新函数
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); //事件处理
struct input_handle __rcu *grab; //类似私有指针,可以访问到事件处理接口event
spinlock_t event_lock; //自旋锁
struct mutex mutex; //用于open close函数的连续访问互斥
unsigned int users; //设备使用计数
bool going_away; //不知
bool sync; //是否上传同步ok
struct device dev; //设备结构体
struct list_head h_list; //handle list
struct list_head node; // input dev list
};
struct input_handler:用来标识输入事件处理
1 struct input_handler {
2
3 void *private;
4
5 void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);/*event用于处理事件*/
6 void (*events)(struct input_handle *handle,
7 const struct input_value *vals, unsigned int count);
8 bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
9 bool (*match)(struct input_handler *handler, struct input_dev *dev);
10 int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);/*connect用于建立handler和device的联系*/
11 void (*disconnect)(struct input_handle *handle);/*disconnect用于解除handler和device的联系*/
12 void (*start)(struct input_handle *handle);
13
14 bool legacy_minors;
15 int minor;//次设备号
16 const char *name;
17
18 const struct input_device_id *id_table;//用于和input_dev匹配
19
20 struct list_head h_list;//用于链接和此input_handler相关的input_handle
21 struct list_head node;//用于将该input_handler链入input_handler_list
22 };
input_handle:用来链接input_dev和input_handler
1 struct input_handle {
2
3 void *private;
4
5 int open;//记录设备的打开次数(有多少个应用程序访问设备)
6 const char *name;
7
8 struct input_dev *dev;//指向所属的device
9 struct input_handler *handler;//指向所属的handler
10
11 struct list_head d_node;//用于将此input_handle链入所属input_dev的h_list链表
12 struct list_head h_node;//用于将此input_handle链入所属input_handler的h_list链表
13 };
input_event:数据包 和 上传数据包`
struct input_event {
struct timeval time; //时间
__u16 type; // 数据类型: 按键数据/绝对数据/相对数据
__u16 code; // 类型中某个特定数据: 比如 上键,下键, 回车键,...
__s32 value; // 状态: 按下会抬起
};
struct input_device_id :设备id
struct input_device_id {
2
3 kernel_ulong_t flags; // 这个flag 表示我们的这个 input_device_id 是用来匹配下面的4个情况的哪一项
4 // flag == 1表示匹配总线 2表示匹配供应商 4表示匹配产品 8表示匹配版本
5 __u16 bustype;
6 __u16 vendor;
7 __u16 product;
8 __u16 version;
9
10 kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];
11 kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];
12 kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];
13 kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];
14 kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];
15 kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];
16 kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];
17 kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];
18 kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];
19
20 kernel_ulong_t driver_info;
21 };
5、主要函数:
1 static int __init input_init(void)
2 {
3 int err;
4
5 input_init_abs_bypass();
6
7 err = class_register(&input_class); // 创建设备类 /sys/class/input
8 if (err) {
9 printk(KERN_ERR "input: unable to register input_dev class\n");
10 return err;
11 }
12
13 err = input_proc_init(); // proc文件系统相关的初始化
14 if (err)
15 goto fail1;
16
17 err = register_chrdev(INPUT_MAJOR, "input", &input_fops); // 注册字符设备驱动 主设备号13 input_fops 中只实现了open函数,所以他的原理其实和misc其实是一样的
18 if (err) {
19 printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
20 goto fail2;
21 }
22
23 return 0;
24
25 fail2: input_proc_exit();
26 fail1: class_unregister(&input_class);
27 return err;
28 }
1 static int input_open_file(struct inode *inode, struct file *file)
2 {
3 struct input_handler *handler; // 定义一个input_handler指针
4 const struct file_operations *old_fops, *new_fops = NULL; // 定义两个file_operations指针
5 int err;
6
7 err = mutex_lock_interruptible(&input_mutex);
8 if (err)
9 return err;
10
11 /* No load-on-demand here? */
12 handler = input_table[iminor(inode) >> 5]; // 通过次设备号在 input_table 数组中找到对应的 handler
13 if (handler)
14 new_fops = fops_get(handler->fops); // 将handler 中的fops 指针赋值给 new_fops
15
16 mutex_unlock(&input_mutex);
17
18 /*
19 * That's _really_ odd. Usually NULL ->open means "nothing special",
20 * not "no device". Oh, well...
21 */
22 if (!new_fops || !new_fops->open) {
23 fops_put(new_fops);
24 err = -ENODEV;
25 goto out;
26 }
27
28 old_fops = file->f_op; // 将 file->fops 先保存到 old_fops 中,以便出错时能够恢复
29 file->f_op = new_fops; // 用new_fops 替换 file 中 fops
30
31 err = new_fops->open(inode, file); // 执行 file->open 函数
32 if (err) {
33 fops_put(file->f_op);
34 file->f_op = fops_get(old_fops);
35 }
36 fops_put(old_fops);
37 out:
38 return err;
39 }
1 struct input_dev *input_allocate_device(void)
2 {
3 struct input_dev *dev; // 定义一个 input_dev 指针
4
5 dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); // 申请分配内存
6 if (dev) {
7 dev->dev.type = &input_dev_type; // 确定input设备的 设备类型 input_dev_type
8 dev->dev.class = &input_class; // 确定input设备所属的设备类 class
9 device_initialize(&dev->dev); // input设备的初始化
10 mutex_init(&dev->mutex); // 互斥锁初始化
11 spin_lock_init(&dev->event_lock); // 自旋锁初始化
12 INIT_LIST_HEAD(&dev->h_list); // input_dev -> h_list 链表初始化
13 INIT_LIST_HEAD(&dev->node); // input_dev -> node 链表初始化
14
15 __module_get(THIS_MODULE);
16 }
17
18 return dev;
19 }
1 int input_register_device(struct input_dev *dev) // 注册input输入设备
2 {
3 static atomic_t input_no = ATOMIC_INIT(0);
4 struct input_handler *handler; // 定义一个 input_handler 结构体指针
5 const char *path;
6 int error;
7
8 /* Every input device generates EV_SYN/SYN_REPORT events. */
9 __set_bit(EV_SYN, dev->evbit); // 每一个input输入设备都会发生这个事件
10
11 /* KEY_RESERVED is not supposed to be transmitted to userspace. */
12 __clear_bit(KEY_RESERVED, dev->keybit); // 清除KEY_RESERVED 事件对应的bit位,也就是不传输这种类型的事件
13
14 /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
15 input_cleanse_bitmasks(dev); // 确保input_dev中的用来记录事件的变量中没有提到的位掩码是干净的。
16
17 /*
18 * If delay and period are pre-set by the driver, then autorepeating
19 * is handled by the driver itself and we don't do it in input.c.
20 */
21 init_timer(&dev->timer);
22 if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
23 dev->timer.data = (long) dev;
24 dev->timer.function = input_repeat_key;
25 dev->rep[REP_DELAY] = 250;
26 dev->rep[REP_PERIOD] = 33;
27 }
28
29 if (!dev->getkeycode)
30 dev->getkeycode = input_default_getkeycode;
31
32 if (!dev->setkeycode)
33 dev->setkeycode = input_default_setkeycode;
34
35 dev_set_name(&dev->dev, "input%ld", // 设置input设备对象的名字 input+数字
36 (unsigned long) atomic_inc_return(&input_no) - 1);
37
38 error = device_add(&dev->dev); // 添加设备 例如: /sys/devices/virtual/input/input0
39 if (error)
40 return error;
41
42 path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); // 获取input设备对象所在的路径 /sys/devices/virtual/input/input_xxx
43 printk(KERN_INFO "input: %s as %s\n",
44 dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
45 kfree(path);
46
47 error = mutex_lock_interruptible(&input_mutex);
48 if (error) {
49 device_del(&dev->dev);
50 return error;
51 }
52
53 list_add_tail(&dev->node, &input_dev_list); // 链表挂接: 将 input_dev->node 作为节点挂接到 input_dev_list 链表上
54
55 list_for_each_entry(handler, &input_handler_list, node) // 遍历input_handler_list 链表上的所有handler
56 input_attach_handler(dev, handler); // 将handler与input设备进行匹配
57
58 input_wakeup_procfs_readers(); // 更新proc 文件系统
59
60 mutex_unlock(&input_mutex);
61
62 return 0;
63 }
1 int input_register_device(struct input_dev *dev) // 注册input输入设备
2 {
3 static atomic_t input_no = ATOMIC_INIT(0);
4 struct input_handler *handler; // 定义一个 input_handler 结构体指针
5 const char *path;
6 int error;
7
8 /* Every input device generates EV_SYN/SYN_REPORT events. */
9 __set_bit(EV_SYN, dev->evbit); // 每一个input输入设备都会发生这个事件
10
11 /* KEY_RESERVED is not supposed to be transmitted to userspace. */
12 __clear_bit(KEY_RESERVED, dev->keybit); // 清除KEY_RESERVED 事件对应的bit位,也就是不传输这种类型的事件
13
14 /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
15 input_cleanse_bitmasks(dev); // 确保input_dev中的用来记录事件的变量中没有提到的位掩码是干净的。
16
17 /*
18 * If delay and period are pre-set by the driver, then autorepeating
19 * is handled by the driver itself and we don't do it in input.c.
20 */
21 init_timer(&dev->timer);
22 if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
23 dev->timer.data = (long) dev;
24 dev->timer.function = input_repeat_key;
25 dev->rep[REP_DELAY] = 250;
26 dev->rep[REP_PERIOD] = 33;
27 }
28
29 if (!dev->getkeycode)
30 dev->getkeycode = input_default_getkeycode;
31
32 if (!dev->setkeycode)
33 dev->setkeycode = input_default_setkeycode;
34
35 dev_set_name(&dev->dev, "input%ld", // 设置input设备对象的名字 input+数字
36 (unsigned long) atomic_inc_return(&input_no) - 1);
37
38 error = device_add(&dev->dev); // 添加设备 例如: /sys/devices/virtual/input/input0
39 if (error)
40 return error;
41
42 path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); // 获取input设备对象所在的路径 /sys/devices/virtual/input/input_xxx
43 printk(KERN_INFO "input: %s as %s\n",
44 dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
45 kfree(path);
46
47 error = mutex_lock_interruptible(&input_mutex);
48 if (error) {
49 device_del(&dev->dev);
50 return error;
51 }
52
53 list_add_tail(&dev->node, &input_dev_list); // 链表挂接: 将 input_dev->node 作为节点挂接到 input_dev_list 链表上
54
55 list_for_each_entry(handler, &input_handler_list, node) // 遍历input_handler_list 链表上的所有handler
56 input_attach_handler(dev, handler); // 将handler与input设备进行匹配
57
58 input_wakeup_procfs_readers(); // 更新proc 文件系统
59
60 mutex_unlock(&input_mutex);
61
62 return 0;
63 }
1 static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
2 {
3 const struct input_device_id *id; // 定义一个input_device_id 的指针
4 int error;
5
6 id = input_match_device(handler, dev); // 通过这个函数进行handler与input设备的匹配工作
7 if (!id)
8 return -ENODEV;
9
10 error = handler->connect(handler, dev, id); // 匹配成功则调用 handler 中的 connect 函数进行连接
11 if (error && error != -ENODEV)
12 printk(KERN_ERR
13 “input: failed to attach handler %s to device %s, ”
14 “error: %d\n”,
15 handler->name, kobject_name(&dev->dev.kobj), error);
16
17 return error;
18 }
19
22 static const struct input_device_id *input_match_device(struct input_handler *handler,
23 struct input_dev *dev)
24 {
25 const struct input_device_id *id; // 定义一个 input_device_id 指针
26 int i;
27
28 for (id = handler->id_table; id->flags || id->driver_info; id++) { // 依次遍历handler->id_table 所指向的input_device_id 数组中的各个元素
29 // 依次进行下面的匹配过程
30 if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) // 匹配总线
31 if (id->bustype != dev->id.bustype)
32 continue;
33
34 if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) // 匹配供应商
35 if (id->vendor != dev->id.vendor)
36 continue;
37
38 if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT) // 匹配产品
39 if (id->product != dev->id.product)
40 continue;
41
42 if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION) // 匹配版本
43 if (id->version != dev->id.version)
44 continue;
45
46 // 下面的这些是匹配我们上传的事件是否属实
47 MATCH_BIT(evbit, EV_MAX);
48 MATCH_BIT(keybit, KEY_MAX);
49 MATCH_BIT(relbit, REL_MAX);
50 MATCH_BIT(absbit, ABS_MAX);
51 MATCH_BIT(mscbit, MSC_MAX);
52 MATCH_BIT(ledbit, LED_MAX);
53 MATCH_BIT(sndbit, SND_MAX);
54 MATCH_BIT(ffbit, FF_MAX);
55 MATCH_BIT(swbit, SW_MAX);
56
57 if (!handler->match || handler->match(handler, dev))
58 return id; // 如果数组中的某个匹配成功了就返回他的地址
59 }
60
61 return NULL;
62 }
1 int input_register_handler(struct input_handler *handler) // 向核心层注册handler
2 {
3 struct input_dev *dev; // 定义一个input_dev 指针
4 int retval;
5
6 retval = mutex_lock_interruptible(&input_mutex);
7 if (retval)
8 return retval;
9
10 INIT_LIST_HEAD(&handler->h_list); // 初始化 handler->h_list 链表
11
12 if (handler->fops != NULL) { // 如果 handler -> fops 存在
13 if (input_table[handler->minor >> 5]) { // 如果input_table 数组中没有该handler 的位置了 则返回
14 retval = -EBUSY;
15 goto out;
16 }
17 input_table[handler->minor >> 5] = handler; // 将 handler 指针存放在input_table 数组中去
18 }
19
20 list_add_tail(&handler->node, &input_handler_list); // 将 handler 通过 handler -> node 节点 挂接到 input_handler_list 链表上
21
22 list_for_each_entry(dev, &input_dev_list, node) // 遍历 input_dev_list 链表下挂接的所有的 input_dev 设备
23 input_attach_handler(dev, handler); // 然后进行匹配
24
25 input_wakeup_procfs_readers(); // 更新proc 文件系统
26
27 out:
28 mutex_unlock(&input_mutex);
29 return retval;
30 }