概述
很多分析输入子系统的文章已经讲得很清楚了,这里主要是记录自己的学习过程。参考的几篇文章:
输入子系统学习笔记之按键实例编程
输入子系统学习笔记之源码分析1_框架性分析
输入子系统学习笔记之源码分析2_数据结构分析
输入子系统学习笔记之源码分析3_流程分析
三个重要结构体的说明参考输入子系统学习笔记之源码分析2_数据结构分析,很重要,输入子系统就是靠这三个结构体建立联系的。
drivers/input/input.c中有如下定义:
a. 声明了input_dev_list链表头,在input_register_device()函数中将input_dev结构体加入链表中。
input_register_device(struct input_dev *dev)
-->list_add_tail(&dev->node, &input_dev_list);
b. 声明了input_handler_list链表头,在input_register_handler()函数中将input_handler结构体加入链表中。
input_register_handler(struct input_handler *handler)
-->list_add_tail(&handler->node, &input_handler_list);
c. 定义input_handler指针数组,每个input_handler支持32个input_dev设备。
1 #define INPUT_DEVICES 256 2 static LIST_HEAD(input_dev_list); 3 static LIST_HEAD(input_handler_list); 4 static struct input_handler *input_table[8];
1. input_register_handler()的函数分析
事件处理程序是标准的,对于所有的输入类是通用的。所以一般而言我们要实现的设备驱动程序,而不是事件处理程序。
一般情况下,内核启动后就已经构造好了input_handler_list链表,如下图左侧部分。
调用input_register_handler()的函数一般位于evdev.c,joydev.c ,mousedev.c...等函数中的 xxx_init(void)函数中。
1 static struct input_handler evdev_handler = { 2 .event = evdev_event, 3 .connect = evdev_connect, 4 .disconnect = evdev_disconnect, 5 .fops = &evdev_fops, 6 .minor = EVDEV_MINOR_BASE, 7 .name = "evdev", 8 .id_table = evdev_ids, 9 }; 10 11 static int __init evdev_init(void) 12 { 13 return input_register_handler(&evdev_handler); 14 15 }
1 int input_register_handler(struct input_handler *handler) 2 { 3 struct input_dev *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); 11 12 if (handler->fops != NULL) { 13 if (input_table[handler->minor >> 5]) { 14 retval = -EBUSY; 15 goto out; 16 } 17 input_table[handler->minor >> 5] = handler; 18 } 19 20 list_add_tail(&handler->node, &input_handler_list); 21 22 list_for_each_entry(dev, &input_dev_list, node) 23 input_attach_handler(dev, handler); 24 25 input_wakeup_procfs_readers(); 26 27 out: 28 mutex_unlock(&input_mutex); 29 return retval; 30 }
2. input_register_device()函数分析
写一个符合输入子系统框架的驱动一般分为四步:a. 分配一个input_dev结构体;b. 设置;c. input_register_device()注册;d. 硬件相关的代码
1 struct input_dev *input; 2 static int gq_key_init(void) 3 { 4 // 1 allocate input_dev struct 5 input = input_allocate_device(); 6 7 // 2 set 8 // 2.1 set which event to generate 9 __set_bit(EV_KEY, input->evbit); 10 // 2.2 set which keys to generate 11 __set_bit(KEY_L,input->keybit); 12 __set_bit(KEY_S,input->keybit); 13 __set_bit(KEY_ENTER,input->keybit); 14 __set_bit(KEY_LEFTSHIFT,input->keybit); 15 16 // 3 register 17 input_register_device(input); 18 19 // 4 hardware 20 return 0; 21 }
系统没调用一次input_register_device()函数就在input_dev_list链表上添加一个input_dev结构体,如下图左侧。
1 int input_register_device(struct input_dev *dev) 2 { 3 static atomic_t input_no = ATOMIC_INIT(0); 4 struct input_handler *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); 10 11 /* KEY_RESERVED is not supposed to be transmitted to userspace. */ 12 __clear_bit(KEY_RESERVED, dev->keybit); 13 14 /* Make sure that bitmasks not mentioned in dev->evbit are clean. */ 15 input_cleanse_bitmasks(dev); 16 17 if (!dev->hint_events_per_packet) 18 dev->hint_events_per_packet = 19 input_estimate_events_per_packet(dev); 20 21 /* 22 * If delay and period are pre-set by the driver, then autorepeating 23 * is handled by the driver itself and we don't do it in input.c. 24 */ 25 init_timer(&dev->timer); 26 if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) { 27 dev->timer.data = (long) dev; 28 dev->timer.function = input_repeat_key; 29 dev->rep[REP_DELAY] = 250; 30 dev->rep[REP_PERIOD] = 33; 31 } 32 33 if (!dev->getkeycode) 34 dev->getkeycode = input_default_getkeycode; 35 36 if (!dev->setkeycode) 37 dev->setkeycode = input_default_setkeycode; 38 39 dev_set_name(&dev->dev, "input%ld", 40 (unsigned long) atomic_inc_return(&input_no) - 1); 41 42 error = device_add(&dev->dev); 43 if (error) 44 return error; 45 46 path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); 47 pr_info("%s as %sn", 48 dev->name ? dev->name : "Unspecified device", 49 path ? path : "N/A"); 50 kfree(path); 51 52 error = mutex_lock_interruptible(&input_mutex); 53 if (error) { 54 device_del(&dev->dev); 55 return error; 56 } 57 58 list_add_tail(&dev->node, &input_dev_list); 59 60 list_for_each_entry(handler, &input_handler_list, node) 61 input_attach_handler(dev, handler); 62 63 input_wakeup_procfs_readers(); 64 65 mutex_unlock(&input_mutex); 66 67 return 0; 68 }
3. input_attach_handler()函数分析
input_register_handler()与input_register_device()函数中都会调用input_attach_handler()函数来匹配input_handler与input_device。
在input_register_handler()中会遍历整个input_dev_list中的input_device与当前注册的input_handler相匹配。
在input_register_device()中会遍历整个input_handler_list中的input_handler与当前注册的input_dev相匹配。
input_attach_handler()中做两件事情:a.查看input_handler与input_device是否匹配;b.若匹配则调用handler->connect(handler,dev,id);
1 static int input_attach_handler(struct input_dev *dev, struct input_handler *handler) 2 { 3 const struct input_device_id *id; 4 int error; 5 6 id = input_match_device(handler, dev); 7 if (!id) 8 return -ENODEV; 9 10 error = handler->connect(handler, dev, id); 11 if (error && error != -ENODEV) 12 pr_err("failed to attach handler %s to device %s, error: %dn", 13 handler->name, kobject_name(&dev->dev.kobj), error); 14 15 return error; 16 }
4. input_match_device()函数分析
这里用到两个结构体,input_device结构体中有struct
input_id id;
struct input_handler 结构体中有const
struct
input_device_id *id_table;
是否匹配主要是检测input_device_id中的数组成员与input_device中对应的数组成员是否一致。
struct input_id { __u16 bustype; __u16 vendor; __u16 product; __u16 version; }; struct input_device_id { 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 driver_info; };
1 static const struct input_device_id *input_match_device(struct input_handler *handler, 2 struct input_dev *dev) 3 { 4 const struct input_device_id *id; 5 int i; 6 7 for (id = handler->id_table; id->flags || id->driver_info; id++) 8 { 9 10 if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) 11 if (id->bustype != dev->id.bustype) 12 continue; 13 14 if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) 15 if (id->vendor != dev->id.vendor) 16 continue; 17 18 if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT) 19 if (id->product != dev->id.product) 20 continue; 21 22 if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION) 23 if (id->version != dev->id.version) 24 continue; 25 26 MATCH_BIT(evbit, EV_MAX); 27 MATCH_BIT(keybit, KEY_MAX); 28 MATCH_BIT(relbit, REL_MAX); 29 MATCH_BIT(absbit, ABS_MAX); 30 MATCH_BIT(mscbit, MSC_MAX); 31 MATCH_BIT(ledbit, LED_MAX); 32 MATCH_BIT(sndbit, SND_MAX); 33 MATCH_BIT(ffbit, FF_MAX); 34 MATCH_BIT(swbit, SW_MAX); 35 36 if (!handler->match || handler->match(handler, dev)) 37 return id; 38 } 39 40 return NULL; 41 }
5. handler->connect(handler, dev, id)函数分析
这里以evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)为例分析连接建立的过程。
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)
-->evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);//分配一个struct input_handle
-->evdev->handle.dev = input_get_device(dev);//指向input_dev
-->evdev->handle.handler = handler;//指向input_handler
-->error = input_register_handle(&evdev->handle);
-->list_add_tail_rcu(&handle->d_node, &dev->h_list);//与input_dev关联
-->list_add_tail_rcu(&handle->h_node, &handler->h_list);//与input_handler关联
建立连接后handler与device就通过handle关联起来了
1 struct input_handle { 2 3 void *private; 4 5 int open; 6 const char *name; 7 8 struct input_dev *dev; 9 struct input_handler *handler; 10 11 struct list_head d_node; 12 struct list_head h_node; 13 };
转载于:https://www.cnblogs.com/yangjiguang/p/6042197.html
最后
以上就是魁梧高跟鞋为你收集整理的输入子系统(二)函数调用分析的全部内容,希望文章能够帮你解决输入子系统(二)函数调用分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复