zoukankan      html  css  js  c++  java
  • Linux/Android——input_handler之evdev (四)【转】

    本文转载自:

      在前文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:

    [objc] view plain copy
     
    1. static int __init evdev_init(void)  
    2. {  
    3.     return input_register_handler(&evdev_handler);  
    4. }  


    这个初始化就是往input核心中注册一个input_handler类型的evdev_handler,调用的是input.c提供的接口,input_handler结构前文有介绍,看下evdev_handler的赋值:

    [objc] view plain copy
     
    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. };  


    赋值各个函数指针!

    input_register_handler:

     可以看到上面的evdev handler 就是调用这个接口注册到input核心中的,同样evdev.c同目录下也还有其它的handler,有兴趣可以看看它们的init函数,都是会调用到这个接口去注册的.

    [objc] view plain copy
     
    1. /** 
    2.  * input_register_handler - register a new input handler 
    3.  * @handler: handler to be registered 
    4.  * 
    5.  * This function registers a new input handler (interface) for input 
    6.  * devices in the system and attaches it to all input devices that 
    7.  * are compatible with the handler. 
    8.  */  
    9. int input_register_handler(struct input_handler *handler)  
    10. {  
    11.     struct input_dev *dev;  
    12.     int retval;  
    13.   
    14.     retval = mutex_lock_interruptible(&input_mutex);  
    15.     if (retval)  
    16.         return retval;  
    17.   
    18.     INIT_LIST_HEAD(&handler->h_list);  
    19.   
    20.     if (handler->fops != NULL) {  
    21.         if (input_table[handler->minor >> 5]) {  
    22.             retval = -EBUSY;  
    23.             goto out;  
    24.         }  
    25.         input_table[handler->minor >> 5] = handler; //给input.c定义的全局handler 数组赋值,evdev handler的次设备号为64,这里除以32,赋值在input_table[2]  
    26.     }  
    27.   
    28.     list_add_tail(&handler->node, &input_handler_list);  //添加进handler 链表  
    29.   
    30.     list_for_each_entry(dev, &input_dev_list, node)   //同样遍历input_dev这个链表,依次调用下面的input_attach_handler去匹配input_dev,这个跟input_dev注册的时候的情形类似  
    31.         input_attach_handler(dev, handler);  
    32.   
    33.     input_wakeup_procfs_readers();  
    34.   
    35.  out:  
    36.     mutex_unlock(&input_mutex);  
    37.     return retval;  
    38. }  

    input核心中保存的handler数组:

    [objc] view plain copy
     
    1. static struct input_handler *input_table[8];  

    这是保存注册到input核心中的handler数组,因为在之前input注册的时候注册的字符设备主设备号为13.字符设备的次设备号为0~255,可以有256个设备,

    这里后面会看到一个handler可以connect处理32个input设备,所以input体系中,最多拥有8个handler

    这个匹配过程和上一篇中的过程是一样的,最后匹配上的话会调用匹配上的handler 中connect指针指向的函数.

    另外可以注意的是evdev是匹配所有设备的,因为:

    [objc] view plain copy
     
    1. static const struct input_device_id evdev_ids[] = {  
    2.     { .driver_info = 1 },   /* Matches all devices */  
    3.     { },            /* Terminating zero entry */  
    4. };  


    如果没有特定的handler添加进handler链表,那么在匹配的时候,只要有这个evdev的handler,最后都会匹配到evdev,这个具体可以去看看上篇的匹配过程.

    我这边调试的是usb触摸屏,所以用的是evdev的handler,下面看下evdev的connect.

    evdev_connect:

     注册的evdev_handler中connect指向的函数为evdev_connect:

    [objc] view plain copy
     
    1. /* 
    2.  * Create new evdev device. Note that input core serializes calls 
    3.  * to connect and disconnect so we don't need to lock evdev_table here. 
    4.  */  
    5. static int evdev_connect(struct input_handler *handler, struct input_dev *dev,  
    6.              const struct input_device_id *id)  
    7. {  
    8.     struct evdev *evdev;  
    9.     int minor;  
    10.     int error;  
    11.   
    12.     for (minor = 0; minor < EVDEV_MINORS; minor++)  
    13.         if (!evdev_table[minor])  
    14.             break;  
    15.   
    16.     if (minor == EVDEV_MINORS) {  
    17.         pr_err("no more free evdev devices ");  
    18.         return -ENFILE;  
    19.     }  
    20.   
    21. // 可以看到这里evdev handler匹配连接好的设备都以evdev 类型存在这个evdev_table数组的,这个数组大小为32个,这就是我上面说到的,为什么只有8个handler  
    22.   
    23. //这里是判断evdev的32个位置中是否有空  
    24.   
    25.     evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); //为上面定义的*evdev分配内存空间  
    26.     if (!evdev)  
    27.         return -ENOMEM;  
    28.   
    29.     INIT_LIST_HEAD(&evdev->client_list); //以下都是对这个 evdev的初始化了  
    30.     spin_lock_init(&evdev->client_lock);  
    31.     mutex_init(&evdev->mutex);  
    32.     init_waitqueue_head(&evdev->wait);  
    33.   
    34.     dev_set_name(&evdev->dev, "event%d", minor);  //给这个evdev命名  
    35.     evdev->exist = true;  
    36.     evdev->minor = minor;   // 以minor为索引赋值  
    37.   
    38.     evdev->handle.dev = input_get_device(dev);  //evdev中的handle变量的初始化 ,后面分析这个handle ,这里面保存的就是已经匹配成功的input_dev 和 handler  
    39.     evdev->handle.name = dev_name(&evdev->dev);  
    40.     evdev->handle.handler = handler;  
    41.     evdev->handle.private = evdev;  
    42.   
    43.     evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);  
    44.     evdev->dev.class = &input_class;  
    45.     evdev->dev.parent = &dev->dev;  
    46.     evdev->dev.release = evdev_free;  
    47.     device_initialize(&evdev->dev);  
    48.   
    49.     error = input_register_handle(&evdev->handle); //把这个evdev中初始化好的handle 注册到input核心中去,代表一个匹配成功的组合  
    50.     if (error)  
    51.         goto err_free_evdev;  
    52.   
    53.     error = evdev_install_chrdev(evdev);  //把这个初始化好的evdev添加到上面说到过的evdev_table数组,以minor索引序号  
    54.     if (error)  
    55.         goto err_unregister_handle;  
    56.   
    57.     error = device_add(&evdev->dev); //把这个device 添加到/sys/class/input/下面,所以我们可以看到/dev/input下面看到:event0~31 字样字符设备文件,这就是在上面命名的  
    58.     if (error)  
    59.         goto err_cleanup_evdev;  
    60.   
    61.     return 0;  
    62.   
    63.  err_cleanup_evdev:  
    64.     evdev_cleanup(evdev);  
    65.  err_unregister_handle:  
    66.     input_unregister_handle(&evdev->handle);  
    67.  err_free_evdev:  
    68.     put_device(&evdev->dev);  
    69.     return error;  
    70. }  



    evdev:

    这里的evdev变量的结构如下:

    [objc] view plain copy
     
    1. struct evdev  
    2. {  
    3.     int open; //打开标志  
    4.     int minor; //次设备号  
    5.     struct input_handle handle; //包含的handle  
    6.     wait_queue_head_t wait; //等待队列  
    7.   
    8.     struct evdev_client __rcu *grab; //强制绑定的evdev_client结构  
    9.     struct list_head client_list; //evdev_client 链表,这说明一个evdev设备可以处理多个evdev_client,可以有多个进程访问evdev设备  
    10.   
    11.     spinlock_t client_lock; /* protects client_list */  
    12.     struct mutex mutex;  
    13.     struct device dev;  
    14.     bool exist;  
    15. };  



    关于这个结构变量我的理解是抽象出来一个设备,代表一个input_dev与其匹配好的handler的组合(handle),可以看作提供给事件处理层的一个封装.

    input_handle:

    这个代表一个匹配成功的input dev和 handler组合,定义在input.h中,每个evdev中包含一个input_handle,并且注册到input核心中:

    [objc] view plain copy
     
    1. /** 
    2.  * struct input_handle - links input device with an input handler 
    3.  * @private: handler-specific data 
    4.  * @open: counter showing whether the handle is 'open', i.e. should deliver 
    5.  *    events from its device 
    6.  * @name: name given to the handle by handler that created it 
    7.  * @dev: input device the handle is attached to 
    8.  * @handler: handler that works with the device through this handle 
    9.  * @d_node: used to put the handle on device's list of attached handles 
    10.  * @h_node: used to put the handle on handler's list of handles from which 
    11.  *    it gets events 
    12.  */  
    13. struct input_handle {  
    14.   
    15.     voidvoid *private;  //指向上面封装的evdev  
    16.   
    17.     int open;  
    18.     const charchar *name;  
    19.   
    20.     struct input_dev *dev;   //input 设备  
    21.     struct input_handler *handler;  // 一个input的handler  
    22.   
    23.     struct list_head    d_node;  //链表结构  
    24.     struct list_head    h_node;  
    25. };  

    input_register_handle:

     看看这个handle的注册,不要和handler搞混淆了,这不是一个概念~

    [objc] view plain copy
     
    1. /** 
    2.  * input_register_handle - register a new input handle 
    3.  * @handle: handle to register 
    4.  * 
    5.  * This function puts a new input handle onto device's 
    6.  * and handler's lists so that events can flow through 
    7.  * it once it is opened using input_open_device(). 
    8.  * 
    9.  * This function is supposed to be called from handler's 
    10.  * connect() method. 
    11.  */  
    12. int input_register_handle(struct input_handle *handle)  
    13. {  
    14.     struct input_handler *handler = handle->handler;  
    15.     struct input_dev *dev = handle->dev;  //取出两个成员  
    16.   
    17. ...  
    18.   
    19.     /* 
    20.      * Filters go to the head of the list, normal handlers 
    21.      * to the tail. 
    22.      */  
    23.     if (handler->filter)  
    24.         list_add_rcu(&handle->d_node, &dev->h_list);  
    25.     else  
    26.         list_add_tail_rcu(&handle->d_node, &dev->h_list);  
    27.   
    28. //把这个handle的d_node 加到对应input_dev的h_list链表里面  
    29.   
    30. ...  
    31.   
    32.     list_add_tail_rcu(&handle->h_node, &handler->h_list);  
    33.   
    34. //把这个handle的h_node 加到对应input_handler的h_list链表里面  
    35.   
    36. ...  
    37.   
    38. }  

    这个注册是把handle 本身的链表加入到它自己的input_dev 以及 input_handler的h_list链表中,这样以后就可以通过h_list遍历到这个handle,

    这样就实现了三者的绑定联系.

    另外在evdev中还有个结构:

    [objc] view plain copy
     
    1. struct evdev_client {  
    2.     unsigned int head;  //buffer数组的索引头  
    3.     unsigned int tail;   //buffer数组的索引尾  
    4.     unsigned int packet_head; /* [future] position of the first element of next packet */  
    5.     spinlock_t buffer_lock; /* protects access to buffer, head and tail */  
    6.     struct wake_lock wake_lock;  
    7.     bool use_wake_lock;  
    8.     char name[28];  
    9.     struct fasync_struct *fasync;    //异步通知函数  
    10.     struct evdev *evdev;  //包含一个evdev变量  
    11.     struct list_head node;  //链表  
    12.     unsigned int bufsize;  
    13.     struct input_event buffer[];   //input_event数据结构的数组,input_event代表一个事件,基本成员:类型(type),编码(code),值(value)  
    14. };  

    这个结构会在evdev被打开的时候 创建,这里关于evdev的初始以及在input系统中承接作用暂时介绍到这里,

    前文 Linux/Android——输入子系统input_event传递 (二) 中有记录从设备驱动传递上来的event是怎么到input核心,然后接着往上传递的,接下来就是用到evdev传递了.下篇介绍.

  • 相关阅读:
    viso图插入Word中大片空白解决办法
    面向对象设计模式中的单例模式和工厂模式
    面向对象知识整理
    require和include的区别及自动加载的定义
    面向对象的三大特性及定义
    重写和重载的区别 (部分内容转自竹木人)
    面向对象的基本概念
    PHP json_encode( ) 函数介绍
    js页面跳转常用的几种方式
    js中页面刷新和页面跳转的方法总结 [ 转自欢醉同学 ]
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/7808477.html
Copyright © 2011-2022 走看看