本文轉載自: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,如今來看看:
- static int input_open_file(struct inode *inode, struct file *file)
- {
- struct input_handler *handler;
- const struct file_operations *old_fops, *new_fops = NULL;
- int err;
-
- err = mutex_lock_interruptible(&input_mutex);
- if (err)
- return err;
-
-
- handler = input_table[iminor(inode) >> 5];
- if (handler)
- new_fops = fops_get(handler->fops);
-
- mutex_unlock(&input_mutex);
-
-
- if (!new_fops || !new_fops->open) {
- fops_put(new_fops);
- err = -ENODEV;
- goto out;
- }
-
- old_fops = file->f_op;
- file->f_op = new_fops;
- err = new_fops->open(inode, file);
- if (err) {
- fops_put(file->f_op);
- file->f_op = fops_get(old_fops);
- }
- fops_put(old_fops);
- out:
- return err;
- }
這裏若是是打開evdev的,調用到的是evdev_handler中的evdev_fops的open方法!
evdev_fops:
前文有介紹evdev_handler的功能與註冊,這裏看下這個handler註冊的方法:
- static const struct file_operations evdev_fops = {
- .owner = THIS_MODULE,
- .read = evdev_read,
- .write = evdev_write,
- .poll = evdev_poll,
- .open = evdev_open,
- .release = evdev_release,
- .unlocked_ioctl = evdev_ioctl,
- #ifdef CONFIG_COMPAT
- .compat_ioctl = evdev_ioctl_compat,
- #endif
- .fasync = evdev_fasync,
- .flush = evdev_flush,
- .llseek = no_llseek,
- };
都是字面意思,前文也提到匹配connect的時候,在evdev_connect中註冊生成了 /sys/class/input/event%d ,
這個字符設備文件就是鏈接kernel與framework的橋樑了!
能夠看到這裏有個evdev_open方法,這個方法就是打開設備文件的
evdev_open:
- static int evdev_open(struct inode *inode, struct file *file)
- {
- struct evdev *evdev;
- struct evdev_client *client;
- int i = iminor(inode) - EVDEV_MINOR_BASE;
- unsigned int bufsize;
- int error;
-
- if (i >= EVDEV_MINORS)
- return -ENODEV;
-
- error = mutex_lock_interruptible(&evdev_table_mutex);
- if (error)
- return error;
- evdev = evdev_table[i];
-
- ...
-
- bufsize = evdev_compute_buffer_size(evdev->handle.dev);
-
- client = kzalloc(sizeof(struct evdev_client) +
- bufsize * sizeof(struct input_event),
- GFP_KERNEL);
-
- if (!client) {
- error = -ENOMEM;
- goto err_put_evdev;
- }
-
- client->bufsize = bufsize;
- spin_lock_init(&client->buffer_lock);
- snprintf(client->name, sizeof(client->name), "%s-%d",
- dev_name(&evdev->dev), task_tgid_vnr(current));
- client->evdev = evdev;
- evdev_attach_client(evdev, client);
-
- error = evdev_open_device(evdev);
-
- ...
-
- }
繼續看
- static int evdev_open_device(struct evdev *evdev)
- {
- int retval;
-
- retval = mutex_lock_interruptible(&evdev->mutex);
- if (retval)
- return retval;
-
- if (!evdev->exist)
- retval = -ENODEV;
- else if (!evdev->open++) {
- retval = input_open_device(&evdev->handle);
- if (retval)
- evdev->open--;
- }
-
- mutex_unlock(&evdev->mutex);
- return retval;
- }
能夠看到這裏繞了一圈,由最開始的input_open_file,最後又回到input核心中去了。調用到input.c中的接口,傳入的是設備當初匹配成功的組合handle
input_open_device:
- int input_open_device(struct input_handle *handle)
- {
- struct input_dev *dev = handle->dev;
- int retval;
-
- retval = mutex_lock_interruptible(&dev->mutex);
- if (retval)
- return retval;
-
- if (dev->going_away) {
- retval = -ENODEV;
- goto out;
- }
-
- handle->open++;
-
- if (!dev->users++ && dev->open)
- retval = dev->open(dev);
-
- if (retval) {
- dev->users--;
- if (!--handle->open) {
-
- synchronize_rcu();
- }
- }
-
- out:
- mutex_unlock(&dev->mutex);
- return retval;
- }
這裏最終是調用設備驅動註冊input_dev時的open方法,如今返回看看我這邊註冊usbtouchscreen時的input_dev 的open方法:
- input_dev->open = usbtouch_open;
這個再往下就是設備驅動乾的事了。。這裏就不分析usbtouch_open 作了什麼了,無非是一些初始化操做之類的
到這裏打開設備這一步就完成了!
evdev_read:
這個是evdev設備的讀取函數,註冊在fops裏:
- static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
- {
- struct evdev_client *client = file->private_data;
- struct evdev *evdev = client->evdev;
- struct input_event event;
- int retval;
-
- if (count < input_event_size())
- return -EINVAL;
- if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))
- return -EAGAIN;
- retval = wait_event_interruptible(evdev->wait, client->head != client->tail || !evdev->exist);
- if (retval)
- return retval;
- if (!evdev->exist)
- return -ENODEV;
-
- while (retval + input_event_size() <= count && evdev_fetch_next_event(client, &event))
- {
- if (input_event_to_user(buffer + retval, &event))
- return -EFAULT;
-
- retval += input_event_size();
- }
-
- return retval;
- }
接下來看android的frameworks層 怎麼去打開這個input 設備文件的.
framework層相關的處理機制,後續的博文會詳細分析,這裏只是簡單的記錄一下與kernel中這些接口的交互,好對android input的運做體系有個總體的概念 !
InputReader:
這個的源碼在/frameworks/base/services/input/InputReader.cpp 這個在第二篇,總的脈絡圖上有,屬於input service中一部分,看名字就知道這是一個讀取input事件的.
等待輸入事件到來的天然會是個loop結構設計.
- bool InputReaderThread::threadLoop() {
- mReader->loopOnce();
- return true;
- }
而後看一下這個loopOnce:
- void InputReader::loopOnce() {
- int32_t oldGeneration;
- int32_t timeoutMillis;
-
- ...
-
- size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
-
- ...
-
- }
EventHub:
源碼位於/frameworks/base/services/input/EventHub.cpp
這個裏面其它的先無論,這裏先介紹下跟本篇有關係的
- size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
-
- ...
-
- for (;;) {
-
- ...
-
- scanDevicesLocked();
-
- ...
-
- int32_t readSize = read(device->fd, readBuffer,
- sizeof(struct input_event) * capacity);
-
- ...
-
- }
-
- ..
-
- }
這裏的read實際上的操做就是上面介紹的 evdev_read 函數!
至此,kernel層的設備以及事件與android這邊的frameworks的input服務處理之間就聯繫起來了,這裏frameworks這邊稍微提一下,後續分析細節!