Linux/Android——input系統之 kernel層 與 frameworks層交互 (五)【轉】

本文轉載自:http://blog.csdn.net/jscese/article/details/42291149node

 以前的四篇博文記錄的都是linux中的input體系相關的東西,最底層以我調試的usb觸摸屏的設備驅動爲例,貼出連接:linux

Linux/Android——usb觸摸屏驅動 - usbtouchscreen (一)android

Linux/Android——輸入子系統input_event傳遞 (二)數組

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

Linux/Android——input_handler之evdev (四)async

在第二篇有記錄input體系總體脈絡,博文順序也差很少是從下往上,這些都沒有涉及到android這邊的內容,這篇記錄一下kernel與android的framework層的關聯.函數

 

                                            撰寫不易,轉載需註明出處:http://blog.csdn.net/jscese/article/details/42291149#t6oop

 

在kernel啓動徹底以後,input以及evdev都已初始化完,先看在kernel中打開input核心設備的接口input_open_file,fetch

也是android這邊frameworks首先會調用到的地方,至於怎麼調用到的,後面分析this

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這邊稍微提一下,後續分析細節!

相關文章
相關標籤/搜索