input系统,内核里面比较简单的子系统,也比较常用,
一、框架
input 子系统 linux 为输入设备(键盘,鼠标,触摸屏等)提供了统一的接口。它的框架有三层组成,设备驱动层(drivers),核心层,事件处理层,如下图所示。其实看了源码就会发现,所谓的 input 子系统本质也就是字符设备而已,不过内核将常用的设备接口封装在里面了,直接使用就行了。
二、输入核心层
输入核心层在整个框架中处于承上启下的作用,它提供的功能
在/sys/class/ 下创建一个类 名字叫做 input,在/proc下面建立相关的文件,注册一个字符设备 input
向设备驱动层提供注册函数 input_register_device
向事件处理层提供注册函数 input_register_handler
提供匹配函数 input_attach_handler 用于建立 input_dev 和 input_handler 之间的连接,并对其进行管理。
提供上报中转接口 input_event
1、相关数据结构
每一个 input_handler 结构都是一类事件处理接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 struct input_handler { void *private; void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); void (*events)(struct input_handle *handle, const struct input_value *vals, unsigned int count); bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value); bool (*match)(struct input_handler *handler, struct input_dev *dev); int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); void (*disconnect)(struct input_handle *handle); void (*start)(struct input_handle *handle); bool legacy_minors; int minor; const char *name; const struct input_device_id *id_table ; struct list_head h_list ; struct list_head node ; };
在老式的 2.6 内核, input_handler 在内核中由 input_table 管理,它是在 input.c 中的全局数组,表示支持的输入设备类型最多有8类,其中包含 mousedev,joydev,evdev 等。 input 子系统的主设备号固定为 INPUT_MAJOR 这个宏被初始化为 13 ,次设备号为 0~255,input_table 数组有8个 input_handler,这 8 个input_handler 将 256 个设备号划分为8份,即每一个 input_handler 最多支持 32个字符设备节点。evdev 的次设备号起始为 EVDEV_MINOR_BASE ,这个宏被初始化为 64,因此 evdev 对应的 table 数组项为 input_table[2]。
而新的内核则使用了更加方便的方式,直接将 input_handler 的管理由核心层移交给事件处理层来管理,使用 input_handle 来动态管理。每个连接成功的 input_handler 和 input_dev 都会动态创建一个 input_handle 来管理,当卸载时释放掉这个结构就可以了。
能够支持哪一些输入设备,用于匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 struct input_device_id { #define INPUT_DEVICE_ID_MATCH_BUS 1 #define INPUT_DEVICE_ID_MATCH_VENDOR 2 #define INPUT_DEVICE_ID_MATCH_PRODUCT 4 #define INPUT_DEVICE_ID_MATCH_VERSION 8 kernel_ulong_t flags; __u16 bustype; __u16 vendor; __u16 product; __u16 version; kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1 ]; kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1 ]; kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1 ]; kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1 ]; kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1 ]; kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1 ]; kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1 ]; kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1 ]; kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1 ]; kernel_ulong_t propbit[INPUT_DEVICE_ID_PROP_MAX / BITS_PER_LONG + 1 ]; kernel_ulong_t driver_info; };
每一个 input_dev 都是一个具体的硬件设备,里面包含该硬件设备的信息和处理函数,该结构也是驱动要处理的结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 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)]; 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; 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 *mt ; struct input_absinfo *absinfo ; 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 ; spinlock_t event_lock; struct mutex mutex ; unsigned int users; bool going_away; struct device dev ; struct list_head h_list ; struct list_head node ; unsigned int num_vals; unsigned int max_vals; struct input_value *vals ; bool devres_managed; };
用于连接上面的 input_dev 和 input_handler
1 2 3 4 5 6 7 8 9 10 11 12 13 struct input_handle { void *private; int open; const char *name; struct input_dev *dev ; struct input_handler *handler ; struct list_head d_node ; struct list_head h_node ; };
上报的事件由 input_event 描述
1 2 3 4 5 6 struct input_event { struct timeval time ; __u16 type; __u16 code; __s32 value; };
2、三角关系
对于每一个和 input_handler 匹配成功的 input_dev 内核都会在connect函数中创建一个 input_handle 结构,用于建立以及维护input_handler和input_dev之间的联系。input_handle作为 input_dev 和 input_handler 沟通的桥梁。建立联系的过程如下:
调用 input_register_handler 注册 input_dev 结构
在 input_register_handler 中遍历 input_handler_list 中所有的 input_handler,对每一个 input_hander 调用 input_attach_handler 进行匹配 (提示:这说明input_dev可以和多个input_hander 匹配成功)
匹配成功则调用 input_handler.connect函数
connect 函数中将 input_dev 和 input_handler 赋值给 input_handle.dev 和 input_handle.handler
调用 input_register_handle 将 handle->d_node 链入 handle->dev->h_list 同时将 handle->h_node 链入 handler->h_list
于是 input_dev 可以利用 input_dev.h_list 中保存的d_node 找到 input_handle 结构从而找到对应的 input_handle.handler 中保存的 input_handler 结构,同理 input_hander 也可以借助 input_handle 找到对应 的input_dev。上述只是简单的描述了三者的关系,而input_dev和input_handler,并不是简单的一对一的关系,而是多对多的关系。 。
3、核心层相关接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 int input_register_handler (struct input_handler *handler) { struct input_dev *dev ; int error; error = mutex_lock_interruptible(&input_mutex); if (error) return error; INIT_LIST_HEAD(&handler->h_list); list_add_tail(&handler->node, &input_handler_list); list_for_each_entry(dev, &input_dev_list, node) input_attach_handler(dev, handler); input_wakeup_procfs_readers(); mutex_unlock(&input_mutex); return 0 ; } EXPORT_SYMBOL(input_register_handler);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 static int input_attach_handler (struct input_dev *dev, struct input_handler *handler) { const struct input_device_id *id ; int error; id = input_match_device(handler, dev); if (!id) return -ENODEV; error = handler->connect(handler, dev, id); if (error && error != -ENODEV) pr_err("failed to attach handler %s to device %s, error: %d\n" , handler->name, kobject_name(&dev->dev.kobj), error); return error; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 static const struct input_device_id *input_match_device (struct input_handler *handler, struct input_dev *dev) { const struct input_device_id *id ; for (id = handler->id_table; id->flags || id->driver_info; id++) { if (input_match_device_id(dev, id) && (!handler->match || handler->match(handler, dev))) { return id; } } return NULL ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 bool input_match_device_id (const struct input_dev *dev, const struct input_device_id *id) { if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) if (id->bustype != dev->id.bustype) return false ; if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) if (id->vendor != dev->id.vendor) return false ; if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT) if (id->product != dev->id.product) return false ; if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION) if (id->version != dev->id.version) return false ; if (!bitmap_subset(id->evbit, dev->evbit, EV_MAX) || !bitmap_subset(id->keybit, dev->keybit, KEY_MAX) || !bitmap_subset(id->relbit, dev->relbit, REL_MAX) || !bitmap_subset(id->absbit, dev->absbit, ABS_MAX) || !bitmap_subset(id->mscbit, dev->mscbit, MSC_MAX) || !bitmap_subset(id->ledbit, dev->ledbit, LED_MAX) || !bitmap_subset(id->sndbit, dev->sndbit, SND_MAX) || !bitmap_subset(id->ffbit, dev->ffbit, FF_MAX) || !bitmap_subset(id->swbit, dev->swbit, SW_MAX) || !bitmap_subset(id->propbit, dev->propbit, INPUT_PROP_MAX)) { return false ; } return true ; } EXPORT_SYMBOL(input_match_device_id);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 int input_register_device (struct input_dev *dev) { struct input_devres *devres = NULL ; struct input_handler *handler ; unsigned int packet_size; const char *path; int error; if (test_bit(EV_ABS, dev->evbit) && !dev->absinfo) { dev_err(&dev->dev, "Absolute device without dev->absinfo, refusing to register\n" ); return -EINVAL; } if (dev->devres_managed) { devres = devres_alloc(devm_input_device_unregister, sizeof (*devres), GFP_KERNEL); if (!devres) return -ENOMEM; devres->input = dev; } __set_bit(EV_SYN, dev->evbit); __clear_bit(KEY_RESERVED, dev->keybit); input_cleanse_bitmasks(dev); packet_size = input_estimate_events_per_packet(dev); if (dev->hint_events_per_packet < packet_size) dev->hint_events_per_packet = packet_size; dev->max_vals = dev->hint_events_per_packet + 2 ; dev->vals = kcalloc(dev->max_vals, sizeof (*dev->vals), GFP_KERNEL); if (!dev->vals) { error = -ENOMEM; goto err_devres_free; } if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) input_enable_softrepeat(dev, 250 , 33 ); if (!dev->getkeycode) dev->getkeycode = input_default_getkeycode; if (!dev->setkeycode) dev->setkeycode = input_default_setkeycode; error = device_add(&dev->dev); if (error) goto err_free_vals; path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); pr_info("%s as %s\n" , dev->name ? dev->name : "Unspecified device" , path ? path : "N/A" ); kfree(path); error = mutex_lock_interruptible(&input_mutex); if (error) goto err_device_del; list_add_tail(&dev->node, &input_dev_list); list_for_each_entry(handler, &input_handler_list, node) input_attach_handler(dev, handler); input_wakeup_procfs_readers(); mutex_unlock(&input_mutex); if (dev->devres_managed) { dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n" , __func__, dev_name(&dev->dev)); devres_add(dev->dev.parent, devres); } return 0 ; err_device_del: device_del(&dev->dev); err_free_vals: kfree(dev->vals); dev->vals = NULL ; err_devres_free: devres_free(devres); return error; } EXPORT_SYMBOL(input_register_device);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 int input_register_handle (struct input_handle *handle) { struct input_handler *handler = handle->handler; struct input_dev *dev = handle->dev; int error; error = mutex_lock_interruptible(&dev->mutex); if (error) return error; if (handler->filter) list_add_rcu(&handle->d_node, &dev->h_list); else list_add_tail_rcu(&handle->d_node, &dev->h_list); mutex_unlock(&dev->mutex); list_add_tail_rcu(&handle->h_node, &handler->h_list); if (handler->start) handler->start(handle); return 0 ; } EXPORT_SYMBOL(input_register_handle);
三、evdev 分析
常用的 input_handler 内核都已经为我们做好了,这里来分析最最常用的 evdev。
1、数据结构
1) evdev
1 2 3 4 5 6 7 8 9 10 11 12 struct evdev { int open; / 对被打开的设备进行计数 struct input_handle handle ; wait_queue_head_t wait; struct evdev_client __rcu *grab ; struct list_head client_list ; spinlock_t client_lock; struct mutex mutex ; struct device dev ; struct cdev cdev ; bool exist; };
2)evdev_client
1 2 3 4 5 6 7 8 9 10 11 12 13 14 struct evdev_client { unsigned int head; unsigned int tail; unsigned int packet_head; spinlock_t buffer_lock; struct fasync_struct *fasync ; struct evdev *evdev ; struct list_head node ; unsigned int clk_type; bool revoked; unsigned long *evmasks[EV_CNT]; unsigned int bufsize; struct input_event buffer []; };
2、evdev 的注册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 static const struct input_device_id evdev_ids [] = { { .driver_info = 1 }, { }, }; MODULE_DEVICE_TABLE(input, evdev_ids); static struct input_handler evdev_handler = { .event = evdev_event, .events = evdev_events, .connect = evdev_connect, .disconnect = evdev_disconnect, .legacy_minors = true , .minor = EVDEV_MINOR_BASE, .name = "evdev" , .id_table = evdev_ids, }; static int __init evdev_init (void ) { return input_register_handler(&evdev_handler); }
3、与设备建立连接
当有设备匹配成功时,直接调用 evdev_connect 函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 static int evdev_connect (struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { struct evdev *evdev ; int minor; int dev_no; int error; minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true ); if (minor < 0 ) { error = minor; pr_err("failed to reserve new minor: %d\n" , error); return error; } evdev = kzalloc(sizeof (struct evdev), GFP_KERNEL); if (!evdev) { error = -ENOMEM; goto err_free_minor; } INIT_LIST_HEAD(&evdev->client_list); spin_lock_init(&evdev->client_lock); mutex_init(&evdev->mutex); init_waitqueue_head(&evdev->wait); evdev->exist = true ; dev_no = minor; if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS) dev_no -= EVDEV_MINOR_BASE; dev_set_name(&evdev->dev, "event%d" , dev_no); evdev->handle.dev = input_get_device(dev); evdev->handle.name = dev_name(&evdev->dev); evdev->handle.handler = handler; evdev->handle.private = evdev; 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); if (error) goto err_free_evdev; cdev_init(&evdev->cdev, &evdev_fops); error = cdev_device_add(&evdev->cdev, &evdev->dev); if (error) goto err_cleanup_evdev; return 0 ; err_cleanup_evdev: evdev_cleanup(evdev); input_unregister_handle(&evdev->handle); err_free_evdev: put_device(&evdev->dev); err_free_minor: input_free_minor(minor); return error; }
在建立连接时将创建字符设备,提供的接口如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 static const struct file_operations evdev_fops = { .owner = THIS_MODULE, .read = evdev_read, .write = evdev_write, .poll = evdev_poll, .open = evdev_open, .release = evdev_release, .unlocked_ioctl = evdev_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = evdev_ioctl_compat, #endif .fasync = evdev_fasync, .llseek = no_llseek, };
4、打开设备
当上层打开对应的字符设备接口时回调流程如下
1 2 3 4 static int evdev_open --> static int evdev_open_device --> int input_open_device --> dev->open(dev);
当我们打开一个 evdev 节点的时候最终会调用对应的设备的 open 回调函数
5、读取数据
当 以 O_NONBLOCK 读取数据时,读取不到数据进入休眠。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 static ssize_t evdev_read (struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; struct input_event event ; size_t read = 0 ; int error; if (count != 0 && count < input_event_size()) return -EINVAL; for (;;) { if (!evdev->exist || client->revoked) return -ENODEV; if (client->packet_head == client->tail && (file->f_flags & O_NONBLOCK)) return -EAGAIN; if (count == 0 ) break ; while (read + input_event_size() <= count && evdev_fetch_next_event(client, &event)) { if (input_event_to_user(buffer + read, &event)) return -EFAULT; read += input_event_size(); } if (read) break ; if (!(file->f_flags & O_NONBLOCK)) { error = wait_event_interruptible(evdev->wait, client->packet_head != client->tail || !evdev->exist || client->revoked); if (error) return error; } } return read; }
四、事件上报
所谓事件上报,不过是将要上报的事件准备好,然后唤醒前面 evdev_read 休眠的进程,将数据返回给用户空间。调用流程如下感兴趣可以跟一下源码。
1 2 3 4 5 6 7 8 9 void input_event --> static void input_handle_event --> static void input_pass_values --> static unsigned int input_to_handler --> handler->event --> static void evdev_event --> static void evdev_events --> static void evdev_pass_values --> wake_up_interruptible(&evdev->wait);
内核已经将上报的接口封装好了,如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 static inline void input_report_key (struct input_dev *dev, unsigned int code, int value) { input_event(dev, EV_KEY, code, !!value); } static inline void input_report_rel (struct input_dev *dev, unsigned int code, int value) { input_event(dev, EV_REL, code, value); } static inline void input_report_abs (struct input_dev *dev, unsigned int code, int value) { input_event(dev, EV_ABS, code, value); } static inline void input_report_switch (struct input_dev *dev, unsigned int code, int value) { input_event(dev, EV_SW, code, !!value); } static inline void input_sync (struct input_dev *dev) { input_event(dev, EV_SYN, SYN_REPORT, 0 ); } static inline void input_mt_sync (struct input_dev *dev) { input_event(dev, EV_SYN, SYN_MT_REPORT, 0 ); } void input_set_capability (struct input_dev *dev, unsigned int type, unsigned int code) ;
参考问章 https://www.136.la/tech/show-60258.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 int main (int argc, char **argv) { int fd; struct input_event ev ; char name[80 ]; fd = open("/dev/input/event5" , O_RDWR); if (fd < 0 ) { printf ("open err\n" ); return 0 ; } ioctl(fd, EVIOCGNAME(sizeof (name) - 1 ), name); printf ("find device name = %s\n" , name); while (1 ) { read(fd, &ev, sizeof (struct input_event)); switch (ev.type) { case EV_SYN: printf ("-------------------------\n" ); break ; case EV_KEY: printf ("key down / up: %d \n" ,ev.code ); break ; case EV_REL: printf ("mouse: " ); if (ev.code == REL_X) { printf (" x -- %d\n" , ev.value); } else if (ev.code == REL_Y) { printf (" y -- %d\n" , ev.value); } break ; case EV_ABS: printf ("ts: " ); if (ev.code == ABS_MT_POSITION_X) { printf (" x -- %d\n" , ev.value); x = ev.value; } else if (ev.code == ABS_MT_POSITION_Y) { printf (" y -- %d\n" , ev.value); y = ev.value; } else if (ev.code == ABS_PRESSURE) { printf (" pressure: %d\n" , ev.value); } break ; } } close(fd); return 0 ; }