标签:get 异步 依次 tac parent 编码 _id 输入子系统 handle
本文转载自:
在前文Linux/Android——input子系统核心 (三) 中概括了总体的结构,以及介绍了input核心的职责,其中有说道注册input设备时会去匹配已有的事件处理器handler,
而这个handler也是存放在一个链表里面的,这里介绍下input子系统中的事件处理input_handler机制.
撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/42238377#t6
evdev:
/kernel/drivers/input下众多事件处理器handler其中的一个,可以看下源码/kernel/drivers/input/evdev.c中的模块init:
- static int __init evdev_init(void)
- {
- return input_register_handler(&evdev_handler);
- }
这个初始化就是往input核心中注册一个input_handler类型的evdev_handler,调用的是input.c提供的接口,input_handler结构前文有介绍,看下evdev_handler的赋值:
- static struct input_handler evdev_handler = {
- .event = evdev_event,
- .connect = evdev_connect,
- .disconnect = evdev_disconnect,
- .fops = &evdev_fops,
- .minor = EVDEV_MINOR_BASE,
- .name = "evdev",
- .id_table = evdev_ids,
- };
赋值各个函数指针!
input_register_handler:
可以看到上面的evdev handler 就是调用这个接口注册到input核心中的,同样evdev.c同目录下也还有其它的handler,有兴趣可以看看它们的init函数,都是会调用到这个接口去注册的.
- int input_register_handler(struct input_handler *handler)
- {
- struct input_dev *dev;
- int retval;
-
- retval = mutex_lock_interruptible(&input_mutex);
- if (retval)
- return retval;
-
- INIT_LIST_HEAD(&handler->h_list);
-
- if (handler->fops != NULL) {
- if (input_table[handler->minor >> 5]) {
- retval = -EBUSY;
- goto out;
- }
- input_table[handler->minor >> 5] = handler;
- }
-
- 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();
-
- out:
- mutex_unlock(&input_mutex);
- return retval;
- }
input核心中保存的handler数组:
- static struct input_handler *input_table[8];
这是保存注册到input核心中的handler数组,因为在之前input注册的时候注册的字符设备主设备号为13.字符设备的次设备号为0~255,可以有256个设备,
这里后面会看到一个handler可以connect处理32个input设备,所以input体系中,最多拥有8个handler
这个匹配过程和上一篇中的过程是一样的,最后匹配上的话会调用匹配上的handler 中connect指针指向的函数.
另外可以注意的是evdev是匹配所有设备的,因为:
- static const struct input_device_id evdev_ids[] = {
- { .driver_info = 1 },
- { },
- };
如果没有特定的handler添加进handler链表,那么在匹配的时候,只要有这个evdev的handler,最后都会匹配到evdev,这个具体可以去看看上篇的匹配过程.
我这边调试的是usb触摸屏,所以用的是evdev的handler,下面看下evdev的connect.
evdev_connect:
注册的evdev_handler中connect指向的函数为evdev_connect:
- static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
- const struct input_device_id *id)
- {
- struct evdev *evdev;
- int minor;
- int error;
-
- for (minor = 0; minor < EVDEV_MINORS; minor++)
- if (!evdev_table[minor])
- break;
-
- if (minor == EVDEV_MINORS) {
- pr_err("no more free evdev devices\n");
- return -ENFILE;
- }
-
-
-
- evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
- if (!evdev)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&evdev->client_list);
- spin_lock_init(&evdev->client_lock);
- mutex_init(&evdev->mutex);
- init_waitqueue_head(&evdev->wait);
-
- dev_set_name(&evdev->dev, "event%d", minor);
- evdev->exist = true;
- evdev->minor = minor;
-
- 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, EVDEV_MINOR_BASE + 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;
-
- error = evdev_install_chrdev(evdev);
- if (error)
- goto err_unregister_handle;
-
- error = device_add(&evdev->dev);
- if (error)
- goto err_cleanup_evdev;
-
- return 0;
-
- err_cleanup_evdev:
- evdev_cleanup(evdev);
- err_unregister_handle:
- input_unregister_handle(&evdev->handle);
- err_free_evdev:
- put_device(&evdev->dev);
- return error;
- }
evdev:
这里的evdev变量的结构如下:
- struct evdev
- {
- int open;
- int minor;
- 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;
- bool exist;
- };
关于这个结构变量我的理解是抽象出来一个设备,代表一个input_dev与其匹配好的handler的组合(handle),可以看作提供给事件处理层的一个封装.
input_handle:
这个代表一个匹配成功的input dev和 handler组合,定义在input.h中,每个evdev中包含一个input_handle,并且注册到input核心中:
- struct input_handle {
-
- voidvoid *private;
-
- int open;
- const charchar *name;
-
- struct input_dev *dev;
- struct input_handler *handler;
-
- struct list_head d_node;
- struct list_head h_node;
- };
input_register_handle:
看看这个handle的注册,不要和handler搞混淆了,这不是一个概念~
- int input_register_handle(struct input_handle *handle)
- {
- struct input_handler *handler = handle->handler;
- struct input_dev *dev = handle->dev;
-
- ...
-
-
- if (handler->filter)
- list_add_rcu(&handle->d_node, &dev->h_list);
- else
- list_add_tail_rcu(&handle->d_node, &dev->h_list);
-
-
- ...
-
- list_add_tail_rcu(&handle->h_node, &handler->h_list);
-
-
- ...
-
- }
这个注册是把handle 本身的链表加入到它自己的input_dev 以及 input_handler的h_list链表中,这样以后就可以通过h_list遍历到这个handle,
这样就实现了三者的绑定联系.
另外在evdev中还有个结构:
- struct evdev_client {
- unsigned int head;
- unsigned int tail;
- unsigned int packet_head;
- spinlock_t buffer_lock;
- struct wake_lock wake_lock;
- bool use_wake_lock;
- char name[28];
- struct fasync_struct *fasync;
- struct evdev *evdev;
- struct list_head node;
- unsigned int bufsize;
- struct input_event buffer[];
- };
这个结构会在evdev被打开的时候 创建,这里关于evdev的初始以及在input系统中承接作用暂时介绍到这里,
前文 Linux/Android——输入子系统input_event传递 (二) 中有记录从设备驱动传递上来的event是怎么到input核心,然后接着往上传递的,接下来就是用到evdev传递了.下篇介绍.
Linux/Android——input_handler之evdev (四)【转】
标签:get 异步 依次 tac parent 编码 _id 输入子系统 handle
原文地址:http://www.cnblogs.com/zzb-Dream-90Time/p/7808477.html