• Linux/Android——input系统之 kernel层 与 frameworks层交互 (五)【转】


    本文转载自:http://blog.csdn.net/jscese/article/details/42291149

     之前的四篇博文记录的都是linux中的input体系相关的东西,最底层以我调试的usb触摸屏的设备驱动为例,贴出链接:

    Linux/Android——usb触摸屏驱动 - usbtouchscreen (一)

    Linux/Android——输入子系统input_event传递 (二)

    Linux/Android——input子系统核心 (三) 

    Linux/Android——input_handler之evdev (四)

    在第二篇有记录input体系整体脉络,博文顺序也差不多是从下往上,这些都没有涉及到android这边的内容,这篇记录一下kernel与android的framework层的关联.

                                                撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/42291149#t6

    在kernel启动完全之后,input以及evdev都已初始化完,先看在kernel中打开input核心设备的接口input_open_file,

    也是android这边frameworks首先会调用到的地方,至于怎么调用到的,后面分析

    input_open_file:

    在第三篇input核心中,有介绍到注册input这个设备的时候,fops中就有这个input_open_file,现在来看看:

    [objc] view plain copy
     
    1. static int input_open_file(struct inode *inode, struct file *file)  
    2. {  
    3.     struct input_handler *handler;  
    4.     const struct file_operations *old_fops, *new_fops = NULL;  
    5.     int err;  
    6.   
    7.     err = mutex_lock_interruptible(&input_mutex);  
    8.     if (err)  
    9.         return err;  
    10.   
    11.     /* No load-on-demand here? */  
    12.     handler = input_table[iminor(inode) >> 5];   //根据索引节点求次设备号除以32,找对应的绑定的事件处理器handler,这里如果得到的次设备号是64~96之间 即为evdev的handler,这个input_table数组的维护在上篇有介绍  
    13.     if (handler)  
    14.         new_fops = fops_get(handler->fops); //获取handler的fops  
    15.   
    16.     mutex_unlock(&input_mutex);  
    17.   
    18.     /* 
    19.      * That's _really_ odd. Usually NULL ->open means "nothing special", 
    20.      * not "no device". Oh, well... 
    21.      */  
    22.     if (!new_fops || !new_fops->open) {  
    23.         fops_put(new_fops);  
    24.         err = -ENODEV;  
    25.         goto out;  
    26.     }  
    27.   
    28.     old_fops = file->f_op;  
    29.     file->f_op = new_fops;  //如果事件处理器有 file_operarions 就赋值给现在的file->f_op ,替换了原来的  
    30.     err = new_fops->open(inode, file);  //这里调用的是 事件处理器file方法中的open方法,  
    31.     if (err) {  
    32.         fops_put(file->f_op);  
    33.         file->f_op = fops_get(old_fops);  
    34.     }  
    35.     fops_put(old_fops);  
    36. out:  
    37.     return err;  
    38. }  


    这里如果是打开evdev的,调用到的是evdev_handler中的evdev_fops的open方法!

    evdev_fops:

     前文有介绍evdev_handler的功能与注册,这里看下这个handler注册的方法:

    [objc] view plain copy
     
    1. static const struct file_operations evdev_fops = {  
    2.     .owner      = THIS_MODULE,  
    3.     .read       = evdev_read,  
    4.     .write      = evdev_write,  
    5.     .poll       = evdev_poll,  
    6.     .open       = evdev_open,  
    7.     .release    = evdev_release,  
    8.     .unlocked_ioctl = evdev_ioctl,  
    9. #ifdef CONFIG_COMPAT  
    10.     .compat_ioctl   = evdev_ioctl_compat,  
    11. #endif  
    12.     .fasync     = evdev_fasync,  
    13.     .flush      = evdev_flush,  
    14.     .llseek     = no_llseek,  
    15. };  


    都是字面意思,前文也提到匹配connect的时候,在evdev_connect中注册生成了 /sys/class/input/event%d ,

    这个字符设备文件就是连接kernel与framework的桥梁了!

    可以看到这里有个evdev_open方法,这个方法就是打开设备文件的

    evdev_open:

    [objc] view plain copy
     
    1. static int evdev_open(struct inode *inode, struct file *file)  
    2. {  
    3.     struct evdev *evdev;  
    4.     struct evdev_client *client;  
    5.     int i = iminor(inode) - EVDEV_MINOR_BASE;  //通过节点算出 minor序号,这个在connect 生成event%d 时有+操作,所以减去BASE  
    6.     unsigned int bufsize;  
    7.     int error;  
    8.   
    9.     if (i >= EVDEV_MINORS)  
    10.         return -ENODEV;  
    11.   
    12.     error = mutex_lock_interruptible(&evdev_table_mutex);  
    13.     if (error)  
    14.         return error;  
    15.     evdev = evdev_table[i]; // 这个数组就是以minor为索引,存每次匹配上的evdev  
    16.   
    17. ...  
    18.   
    19.     bufsize = evdev_compute_buffer_size(evdev->handle.dev);  //往下都是 分配初始化一个evdev_client 变量  
    20.   
    21.     client = kzalloc(sizeof(struct evdev_client) +  
    22.                 bufsize * sizeof(struct input_event),  
    23.              GFP_KERNEL);  
    24.   
    25.     if (!client) {  
    26.         error = -ENOMEM;  
    27.         goto err_put_evdev;  
    28.     }  
    29.   
    30.     client->bufsize = bufsize;  
    31.     spin_lock_init(&client->buffer_lock);  
    32.     snprintf(client->name, sizeof(client->name), "%s-%d",  
    33.             dev_name(&evdev->dev), task_tgid_vnr(current));  
    34.     client->evdev = evdev;  
    35.     evdev_attach_client(evdev, client);  //将这个client加入到evdev的client_list链表中  
    36.   
    37.     error = evdev_open_device(evdev); // 这里深入打开,传入的是设备匹配成功时在evdev_handler中创建的evdev  
    38.   
    39. ...  
    40.   
    41. }  


    继续看

    [objc] view plain copy
     
    1. static int evdev_open_device(struct evdev *evdev)  
    2. {  
    3.     int retval;  
    4.   
    5.     retval = mutex_lock_interruptible(&evdev->mutex);  
    6.     if (retval)  
    7.         return retval;  
    8.   
    9.     if (!evdev->exist)  
    10.         retval = -ENODEV;  
    11.     else if (!evdev->open++) {  //判断是否打开了,初始分配kzalloc,所以open为0,没有打开的话,这里继续调用打开,open计数为1  
    12.         retval = input_open_device(&evdev->handle);  
    13.         if (retval)  
    14.             evdev->open--;  
    15.     }  
    16.   
    17.     mutex_unlock(&evdev->mutex);  
    18.     return retval;  
    19. }  


    可以看到这里绕了一圈,由最开始的input_open_file,最后又回到input核心中去了。调用到input.c中的接口,传入的是设备当初匹配成功的组合handle

    input_open_device:

    [objc] view plain copy
     
    1. int input_open_device(struct input_handle *handle)  
    2. {  
    3.     struct input_dev *dev = handle->dev;  //取对应的input_dev  
    4.     int retval;  
    5.   
    6.     retval = mutex_lock_interruptible(&dev->mutex);  
    7.     if (retval)  
    8.         return retval;  
    9.   
    10.     if (dev->going_away) {  
    11.         retval = -ENODEV;  
    12.         goto out;  
    13.     }  
    14.   
    15.     handle->open++;  // handle数++ ,上面是evdev的open++ 不一样  
    16.   
    17.     if (!dev->users++ && dev->open)   // 这个dev没有被其它进程占用,并且设备有open方法  
    18.         retval = dev->open(dev); //调用input_dev设备的open方法 ,这个是在设备驱动注册这个input_dev时初始化的  
    19.   
    20.     if (retval) {  //失败处理情况  
    21.         dev->users--;  
    22.         if (!--handle->open) {  
    23.             /* 
    24.              * Make sure we are not delivering any more events 
    25.              * through this handle 
    26.              */  
    27.             synchronize_rcu();  
    28.         }  
    29.     }  
    30.   
    31.  out:  
    32.     mutex_unlock(&dev->mutex);  
    33.     return retval;  
    34. }  


    这里最终是调用设备驱动注册input_dev时的open方法,现在返回看看我这边注册usbtouchscreen时的input_dev 的open方法:

    [objc] view plain copy
     
    1. input_dev->open = usbtouch_open;  


    这个再往下就是设备驱动干的事了。。这里就不分析usbtouch_open 做了什么了,无非是一些初始化操作之类的

    到这里打开设备这一步就完成了!

    evdev_read:

    这个是evdev设备的读取函数,注册在fops里:

    [objc] view plain copy
     
    1. static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)  
    2. {  
    3.     struct evdev_client *client = file->private_data; //这个客户端结构在打开的时候分配并保存在file->private_data中  
    4.     struct evdev *evdev = client->evdev;  
    5.     struct input_event event;  
    6.     int retval;  
    7.   
    8.     if (count < input_event_size())  
    9.         return -EINVAL;  
    10. //这条语句提示,用户进程每次读取设备的字节数,不要少于input_event结构的大小  
    11.     if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))  
    12.         return -EAGAIN;  
    13. //head等于tail说明目前还没有事件传回来,如果设置了非阻塞操作,则会立刻返回  
    14.     retval = wait_event_interruptible(evdev->wait, client->head != client->tail || !evdev->exist);  
    15. //没有事件就会睡在evdev的等待队列上了,等待条件是有事件到来或者设备不存在了(设备关闭的时候,清这个标志)  
    16.     if (retval)  
    17.         return retval;  
    18. //如果能执行上面这条语句说明有事件传来或者,设备被关闭了,或者内核发过来终止信号  
    19.     if (!evdev->exist)  
    20.         return -ENODEV;  
    21.   
    22.     while (retval + input_event_size() <= count && evdev_fetch_next_event(client, &event))  
    23.     {  
    24. // evdev_fetch_next_event这个函数遍历client里面的input_event buffer数组  
    25.         if (input_event_to_user(buffer + retval, &event))  
    26. //将事件复制到用户空间  
    27.             return -EFAULT;  
    28.   
    29.         retval += input_event_size();  
    30.     }  
    31.   
    32.     return retval; //返回复制的数据字节数  
    33. }  

    接下来看android的frameworks层 怎么去打开这个input 设备文件的.

    framework层相关的处理机制,后续的博文会详细分析,这里只是简单的记录一下与kernel中这些接口的交互,好对android input的运作体系有个整体的概念 !

    InputReader:

     这个的源码在/frameworks/base/services/input/InputReader.cpp 这个在第二篇,总的脉络图上有,属于input service中一部分,看名字就知道这是一个读取input事件的.

    等待输入事件到来的自然会是个loop结构设计.

    [objc] view plain copy
     
    1. bool InputReaderThread::threadLoop() {  
    2.     mReader->loopOnce();  
    3.     return true;  
    4. }  


    然后看一下这个loopOnce:

    [objc] view plain copy
     
    1. void InputReader::loopOnce() {  
    2.     int32_t oldGeneration;  
    3.     int32_t timeoutMillis;  
    4.   
    5. ...  
    6.   
    7.    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); //这里就是关键了,通过另外一个中间者EventHub 获取的input事件  
    8.   
    9. ...  
    10.   
    11. }  



    EventHub:

    源码位于/frameworks/base/services/input/EventHub.cpp

    这个里面其它的先不管,这里先介绍下跟本篇有关系的

    [objc] view plain copy
     
    1. size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {  
    2.   
    3. ...  
    4.   
    5.     for (;;) {  
    6.   
    7. ...  
    8.   
    9.             scanDevicesLocked(); //这个往里走就是通过EventHub::openDeviceLocked  打开*DEVICE_PATH = "/dev/input" 这个设备 ,最终用的open,实际到kernel层就是input设备注册的open  
    10.   
    11. ...  
    12.   
    13.     int32_t readSize = read(device->fd, readBuffer, //这里的device->fd就是/dev/input/event%d这个设备文件,就是从这里读取出event的buffer  
    14.                         sizeof(struct input_event) * capacity);  
    15.   
    16. ...  
    17.   
    18.  }  
    19.   
    20. ..  
    21.   
    22. }  



    这里的read实际上的操作就是上面介绍的 evdev_read 函数!

    至此,kernel层的设备以及事件与android这边的frameworks的input服务处理之间就联系起来了,这里frameworks这边稍微提一下,后续分析细节!

  • 相关阅读:
    最近要看的项目
    Lavarel Route::resource
    架构,性能
    Unity ToLua & LuaFramework_UGUI学习笔记(zz)
    Unity UI 布局
    Introduction to Unity UI
    Unity more efficient find
    unity UI如何开启(显示)或者关闭(隐藏)Panel界面最好?
    Unity Canvas vs Panel
    Unity实现新手引导圆形遮罩
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/7808518.html
Copyright © 2020-2023  润新知