标签:传递 process 一点 generated err string use 交互 fbi
本文转载自:http://blog.csdn.net/jscese/article/details/42123673
之前的博客有涉及到linux的input子系统,这里学习记录一下input模块.
input子系统,作为管理输入设备与系统进行交互的中枢,任何的输入设备驱动都要通过input向内核注册其设备,
常用的输入设备也就是鼠标,键盘,触摸屏。
稍微细分一点整个输入体系,就是 硬件驱动层,input核心中转层,事件处理层.层次之间传递都以event事件的形式,这其中input连接上下层,分别提供接口.
之前有分析usbtouchscreen的驱动,也就是硬件驱动部分,这里简单记录一下input核心中转处理 input.c .
撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/42123673
input_init:
源码位于/kernel/drivers/input/input.c ,模块初始调用口subsys_initcall(input_init),
由kernel启动的时候由kernel_init——>do_basic_setup();——>do_initcalls调用到,这个启动逻辑,后续有机会去学习一下,
这里首先调用到初始函数:
- 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(INPUT_MAJOR, "input", &input_fops);
- 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;
- }
这就是最开始的初始化过程了.
可以看下注册方法函数:
- static const struct file_operations input_fops = {
- .owner = THIS_MODULE,
- .open = input_open_file,
- .llseek = noop_llseek,
- };
这里面关注open file方法即可,后面分析。
input.c中还有很多其它的接口以及全局数据,后面陆续联通,先从设备驱动最先调用到的注册 input_register_device
input_register_device:
-
- int input_register_device(struct input_dev *dev)
- {
- static atomic_t input_no = ATOMIC_INIT(0);
-
- struct input_handler *handler;
- const charchar *path;
- int error;
-
- __set_bit(EV_SYN, dev->evbit);
-
-
-
- init_timer(&dev->timer);
- if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
- dev->timer.data = (long) dev;
- dev->timer.function = input_repeat_key;
- dev->rep[REP_DELAY] = 250;
- dev->rep[REP_PERIOD] = 33;
-
- }
-
- if (!dev->getkeycode)
- dev->getkeycode = input_default_getkeycode;
- if (!dev->setkeycode)
- dev->setkeycode = input_default_setkeycode;
-
- dev_set_name(&dev->dev, "input%ld",
- (unsigned long) atomic_inc_return(&input_no) - 1);
-
- error = device_add(&dev->dev);
-
- if (error)
- return error;
-
- path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
- printk(KERN_INFO "input: %s as %s\n",
- dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
- kfree(path);
-
- error = mutex_lock_interruptible(&input_mutex);
- if (error) {
- device_del(&dev->dev);
- return error;
- }
-
- 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);
-
- return 0;
- }
可以看到前面都是一些初始设置,加入到input.c 的全局input_dev 链表里面,同时下面就行匹配对应handler的时候需要遍历 handler 链表:
- static LIST_HEAD(input_dev_list);
- static LIST_HEAD(input_handler_list);
可以看到用到了一个list_for_each_entry, 刚开始看到还没看懂,这是一个宏定义,原型是在/kernel/include/linux/list.h:
- #define list_for_each_entry(pos, head, member) \
- for (pos = list_entry((head)->next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = list_entry(pos->member.next, typeof(*pos), member))
input_attach_handler(dev, handler)则是匹配这个要注册dev的handler:
- 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;
- }
可以看下匹配 id 的结构:
- 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;
- };
有两个函数input_match_device 以及 下面的 connect需要了解:
input_match_device:
- static const struct input_device_id *input_match_device(struct input_handler *handler,
- struct input_dev *dev)
- {
- const struct input_device_id *id;
- int i;
-
- for (id = handler->id_table; id->flags || id->driver_info; id++) {
-
- if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
- if (id->bustype != dev->id.bustype)
- continue;
-
- if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
- if (id->vendor != dev->id.vendor)
- continue;
-
- if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
- if (id->product != dev->id.product)
- continue;
-
- if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
- if (id->version != dev->id.version)
- continue;
-
- MATCH_BIT(evbit, EV_MAX);
- MATCH_BIT(keybit, KEY_MAX);
- MATCH_BIT(relbit, REL_MAX);
- MATCH_BIT(absbit, ABS_MAX);
- MATCH_BIT(mscbit, MSC_MAX);
- MATCH_BIT(ledbit, LED_MAX);
- MATCH_BIT(sndbit, SND_MAX);
- MATCH_BIT(ffbit, FF_MAX);
- MATCH_BIT(swbit, SW_MAX);
-
- if (!handler->match || handler->match(handler, dev))
- return id;
- }
-
- return NULL;
- }
MATCH_bit 原型:
- #define MATCH_BIT(bit, max) \
- for (i = 0; i < BITS_TO_LONGS(max); i++) \
- if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
- break; \
- if (i != BITS_TO_LONGS(max)) \
- continue;
可以看到这么多步的目的除了初始以及添加input_dev到链表,就是为了去匹配 input_handler_list 中对应的handler ,
匹配的最终是需要比对handler以及input_dev中的 id,其中input_dev 中的id类型为 input_id :
- struct input_id {
- __u16 bustype;
- __u16 vendor;
- __u16 product;
- __u16 version;
- };
这跟上面 input_handler 结构里面的 input_device_id 匹配id 变量,来确认 handler!
在最开始的时候就有提到,整个input输入体系,分三个层次,现在的input核心层做的事就是:
在硬件驱动层调用 input_register_device时 ,往内核注册驱动的同时,根据硬件的相关id去匹配 适用的事件处理层(input_handler)!
这里匹配上之后就会调用对应 input_handler 的connect 函数。
input_handler:
input_dev 变量代表的是硬件设备,前文Linux/Android——输入子系统input_event传递 (二)中有介绍
input_handler 变量代表的是事件处理器
同样在input.h 中定义:
- struct input_handler {
-
- voidvoid *private;
-
- void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
- 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);
-
- const struct file_operations *fops;
- int minor;
- const charchar *name;
-
- const struct input_device_id *id_table;
-
- struct list_head h_list;
- struct list_head node;
- };
这个结构详细的含义,注释有。
这个结构里面暂时只需要理解的:
注册input_dev ,在事件处理数据链表里面匹配上 input_handler ,就会调用其 *connect 函数指针 进行连接,
将input_dev 跟 input_handler 进行绑定, 后续的运作事件的handler处理将会走这个input_handler的 *event !
在上篇input_event 传递中最后调用到event阶段.
这里简单记录到这里,下篇介绍input_handler 的处理机制~
Linux/Android——input子系统核心 (三)【转】
标签:传递 process 一点 generated err string use 交互 fbi
原文地址:http://www.cnblogs.com/zzb-Dream-90Time/p/7808452.html