Linux/Android——input系统之 kernel层 与 frameworks层交互 (五)
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 print ?- staticintinput_open_file(structinode*inode,structfile*file)
- {
- structinput_handler*handler;
- conststructfile_operations*old_fops,*new_fops=NULL;
- interr;
- err=mutex_lock_interruptible(&input_mutex);
- if(err)
- returnerr;
- /*Noload-on-demandhere?*/
- handler=input_table[iminor(inode)>>5];//根据索引节点求次设备号除以32,找对应的绑定的事件处理器handler,这里如果得到的次设备号是64~96之间即为evdev的handler,这个input_table数组的维护在上篇有介绍
- if(handler)
- new_fops=fops_get(handler->fops);//获取handler的fops
- mutex_unlock(&input_mutex);
- /*
- *That's_really_odd.UsuallyNULL->openmeans"nothingspecial",
- *not"nodevice".Oh,well...
- */
- if(!new_fops||!new_fops->open){
- fops_put(new_fops);
- err=-ENODEV;
- gotoout;
- }
- old_fops=file->f_op;
- file->f_op=new_fops;//如果事件处理器有file_operarions就赋值给现在的file->f_op,替换了原来的
- err=new_fops->open(inode,file);//这里调用的是事件处理器file方法中的open方法,
- if(err){
- fops_put(file->f_op);
- file->f_op=fops_get(old_fops);
- }
- fops_put(old_fops);
- out:
- returnerr;
- }
这里如果是打开evdev的,调用到的是evdev_handler中的evdev_fops的open方法!
evdev_fops:
前文有介绍evdev_handler的功能与注册,这里看下这个handler注册的方法:
[objc] view plain copy print ?- staticconststructfile_operationsevdev_fops={
- .owner=THIS_MODULE,
- .read=evdev_read,
- .write=evdev_write,
- .poll=evdev_poll,
- .open=evdev_open,
- .release=evdev_release,
- .unlocked_ioctl=evdev_ioctl,
- #ifdefCONFIG_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:
[objc] view plain copy print ? - staticintevdev_open(structinode*inode,structfile*file)
- {
- structevdev*evdev;
- structevdev_client*client;
- inti=iminor(inode)-EVDEV_MINOR_BASE;//通过节点算出minor序号,这个在connect生成event%d时有+操作,所以减去BASE
- unsignedintbufsize;
- interror;
- if(i>=EVDEV_MINORS)
- return-ENODEV;
- error=mutex_lock_interruptible(&evdev_table_mutex);
- if(error)
- returnerror;
- evdev=evdev_table[i];//这个数组就是以minor为索引,存每次匹配上的evdev
- ...
- bufsize=evdev_compute_buffer_size(evdev->handle.dev);//往下都是分配初始化一个evdev_client变量
- client=kzalloc(sizeof(structevdev_client)+
- bufsize*sizeof(structinput_event),
- GFP_KERNEL);
- if(!client){
- error=-ENOMEM;
- gotoerr_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);//将这个client加入到evdev的client_list链表中
- error=evdev_open_device(evdev);//这里深入打开,传入的是设备匹配成功时在evdev_handler中创建的evdev
- ...
- }
继续看 [objc] view plain copy print ?
- staticintevdev_open_device(structevdev*evdev)
- {
- intretval;
- retval=mutex_lock_interruptible(&evdev->mutex);
- if(retval)
- returnretval;
- if(!evdev->exist)
- retval=-ENODEV;
- elseif(!evdev->open++){//判断是否打开了,初始分配kzalloc,所以open为0,没有打开的话,这里继续调用打开,open计数为1
- retval=input_open_device(&evdev->handle);
- if(retval)
- evdev->open--;
- }
- mutex_unlock(&evdev->mutex);
- returnretval;
- }
可以看到这里绕了一圈,由最开始的input_open_file,最后又回到input核心中去了。调用到input.c中的接口,传入的是设备当初匹配成功的组合handle
input_open_device:
[objc] view plain copy print ? - intinput_open_device(structinput_handle*handle)
- {
- structinput_dev*dev=handle->dev;//取对应的input_dev
- intretval;
- retval=mutex_lock_interruptible(&dev->mutex);
- if(retval)
- returnretval;
- if(dev->going_away){
- retval=-ENODEV;
- gotoout;
- }
- handle->open++;//handle数++,上面是evdev的open++不一样
- if(!dev->users++&&dev->open)//这个dev没有被其它进程占用,并且设备有open方法
- retval=dev->open(dev);//调用input_dev设备的open方法,这个是在设备驱动注册这个input_dev时初始化的
- if(retval){//失败处理情况
- dev->users--;
- if(!--handle->open){
- /*
- *Makesurewearenotdeliveringanymoreevents
- *throughthishandle
- */
- synchronize_rcu();
- }
- }
- out:
- mutex_unlock(&dev->mutex);
- returnretval;
- }
这里最终是调用设备驱动注册input_dev时的open方法,现在返回看看我这边注册usbtouchscreen时的input_dev 的open方法: [objc] view plain copy print ?
- input_dev->open=usbtouch_open;
这个再往下就是设备驱动干的事了。。这里就不分析usbtouch_open 做了什么了,无非是一些初始化操作之类的
到这里打开设备这一步就完成了!
evdev_read:
这个是evdev设备的读取函数,注册在fops里:
[objc] view plain copy print ?- staticssize_tevdev_read(structfile*file,char__user*buffer,size_tcount,loff_t*ppos)
- {
- structevdev_client*client=file->private_data;//这个客户端结构在打开的时候分配并保存在file->private_data中
- structevdev*evdev=client->evdev;
- structinput_eventevent;
- intretval;
- if(count<input_event_size())
- return-EINVAL;
- //这条语句提示,用户进程每次读取设备的字节数,不要少于input_event结构的大小
- if(client->head==client->tail&&evdev->exist&&(file->f_flags&O_NONBLOCK))
- return-EAGAIN;
- //head等于tail说明目前还没有事件传回来,如果设置了非阻塞操作,则会立刻返回
- retval=wait_event_interruptible(evdev->wait,client->head!=client->tail||!evdev->exist);
- //没有事件就会睡在evdev的等待队列上了,等待条件是有事件到来或者设备不存在了(设备关闭的时候,清这个标志)
- if(retval)
- returnretval;
- //如果能执行上面这条语句说明有事件传来或者,设备被关闭了,或者内核发过来终止信号
- if(!evdev->exist)
- return-ENODEV;
- while(retval+input_event_size()<=count&&evdev_fetch_next_event(client,&event))
- {
- //evdev_fetch_next_event这个函数遍历client里面的input_eventbuffer数组
- if(input_event_to_user(buffer+retval,&event))
- //将事件复制到用户空间
- return-EFAULT;
- retval+=input_event_size();
- }
- returnretval;//返回复制的数据字节数
- }
接下来看android的frameworks层 怎么去打开这个input 设备文件的.
framework层相关的处理机制,后续的博文会详细分析,这里只是简单的记录一下与kernel中这些接口的交互,好对android input的运作体系有个整体的概念 !
InputReader:
这个的源码在/frameworks/base/services/input/InputReader.cpp 这个在第二篇,总的脉络图上有,属于input service中一部分,看名字就知道这是一个读取input事件的.
等待输入事件到来的自然会是个loop结构设计.
[objc] view plain copy print ?- boolInputReaderThread::threadLoop(){
- mReader->loopOnce();
- returntrue;
- }
然后看一下这个loopOnce: [objc] view plain copy print ?
- voidInputReader::loopOnce(){
- int32_toldGeneration;
- int32_ttimeoutMillis;
- ...
- size_tcount=mEventHub->getEvents(timeoutMillis,mEventBuffer,EVENT_BUFFER_SIZE);//这里就是关键了,通过另外一个中间者EventHub获取的input事件
- ...
- }
EventHub:
源码位于/frameworks/base/services/input/EventHub.cpp
这个里面其它的先不管,这里先介绍下跟本篇有关系的
- size_tEventHub::getEvents(inttimeoutMillis,RawEvent*buffer,size_tbufferSize){
- ...
- for(;;){
- ...
- scanDevicesLocked();//这个往里走就是通过EventHub::openDeviceLocked打开*DEVICE_PATH="/dev/input"这个设备,最终用的open,实际到kernel层就是input设备注册的open
- ...
- int32_treadSize=read(device->fd,readBuffer,//这里的device->fd就是/dev/input/event%d这个设备文件,就是从这里读取出event的buffer
- sizeof(structinput_event)*capacity);
- ...
- }
- ..
- }
这里的read实际上的操作就是上面介绍的 evdev_read 函数!
至此,kernel层的设备以及事件与android这边的frameworks的input服务处理之间就联系起来了,这里frameworks这边稍微提一下,后续分析细节!
更多相关文章
- 如何实现对Android设备进行文本的模拟输入
- ADB 工具
- Android图形合成和显示系统---基于高通MSM8k MDP4平台
- android WebView总结
- Android事件处理分析+Android事件处理 +Android输入事件流程
- Android之系统给我们提供的常见的Activity
- android 笔记 --- 获取Android系统的唯一识别码
- Android内核和驱动篇-Android内核介绍
- android WebView总结