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_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,现在来看看:
- 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;
- /* No load-on-demand here? */
- 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. Usually NULL ->open means "nothing special",
- * not "no device". Oh, well...
- */
- if (!new_fops || !new_fops->open) {
- fops_put(new_fops);
- err = -ENODEV;
- goto out;
- }
- 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:
- 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; //通过节点算出 minor序号,这个在connect 生成event%d 时有+操作,所以减去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]; // 这个数组就是以minor为索引,存每次匹配上的evdev
- ...
- bufsize = evdev_compute_buffer_size(evdev->handle.dev); //往下都是 分配初始化一个evdev_client 变量
- 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); //将这个client加入到evdev的client_list链表中
- error = evdev_open_device(evdev); // 这里深入打开,传入的是设备匹配成功时在evdev_handler中创建的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++) { //判断是否打开了,初始分配kzalloc,所以open为0,没有打开的话,这里继续调用打开,open计数为1
- 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; //取对应的input_dev
- int retval;
- retval = mutex_lock_interruptible(&dev->mutex);
- if (retval)
- return retval;
- if (dev->going_away) {
- retval = -ENODEV;
- goto out;
- }
- 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) {
- /*
- * Make sure we are not delivering any more events
- * through this handle
- */
- 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; //这个客户端结构在打开的时候分配并保存在file->private_data中
- struct evdev *evdev = client->evdev;
- struct input_event event;
- int retval;
- 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)
- return retval;
- //如果能执行上面这条语句说明有事件传来或者,设备被关闭了,或者内核发过来终止信号
- if (!evdev->exist)
- return -ENODEV;
- while (retval + input_event_size() <= count && evdev_fetch_next_event(client, &event))
- {
- // evdev_fetch_next_event这个函数遍历client里面的input_event buffer数组
- 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 获取的input事件
- ...
- }
EventHub:
源码位于/frameworks/base/services/input/EventHub.cpp
这个里面其它的先不管,这里先介绍下跟本篇有关系的
- size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
- ...
- for (;;) {
- ...
- scanDevicesLocked(); //这个往里走就是通过EventHub::openDeviceLocked 打开*DEVICE_PATH = "/dev/input" 这个设备 ,最终用的open,实际到kernel层就是input设备注册的open
- ...
- int32_t readSize = read(device->fd, readBuffer, //这里的device->fd就是/dev/input/event%d这个设备文件,就是从这里读取出event的buffer
- sizeof(struct input_event) * capacity);
- ...
- }
- ..
- }
这里的read实际上的操作就是上面介绍的 evdev_read 函数!
至此,kernel层的设备以及事件与android这边的frameworks的input服务处理之间就联系起来了,这里frameworks这边稍微提一下,后续分析细节!
Linux/Android——input系统之 kernel层 与 frameworks层交互 (五)【转】的更多相关文章
- Linux/Android——Input系统之frameworks层InputManagerService (六)【转】
本文转载自:http://blog.csdn.net/u013491946/article/details/72638954 版权声明:免责声明: 本人在此发文(包括但不限于汉字.拼音.拉丁字母)均为 ...
- Linux/Android——Input系统之InputReader (七)【转】
本文转载自:http://blog.csdn.net/jscese/article/details/42739197 在前文Linux/Android——Input系统之frameworks层Inpu ...
- Linux/Android——Input系统之InputMapper 处理 (八)【转】
本文转载自:http://blog.csdn.net/jscese/article/details/43561773 前文Linux/Android——Input系统之InputReader (七)介 ...
- input系统——android input系统
AndroidInput系统--JNI NativeInputManager InputManger InputReader AndroidInput系统--InputReader AndroidIn ...
- Linux/Android——input子系统核心 (三)【转】
本文转载自:http://blog.csdn.net/jscese/article/details/42123673 之前的博客有涉及到linux的input子系统,这里学习记录一下input模块. ...
- Linux 下Input系统应用编程实战
作者:杨源鑫(也是我们的校园代理) 经授权转载于公众号嵌入式开发圈,有些许修改. 什么是input子系统?不管是什么操作系统,都有一个程序用于管理各种输入设备,哪些是输入设备?比如,电脑键盘.鼠标,智 ...
- Linux/Android——input_handler之evdev (四) 【转】
转自:http://blog.csdn.net/u013491946/article/details/72638919 版权声明:免责声明: 本人在此发文(包括但不限于汉字.拼音.拉丁字母)均为随意敲 ...
- Linux & Android 多点触摸协议
Linux & Android 多点触摸协议 Android4.0多点触摸入门 1 KERNEL 对于触摸屏的驱动我们简单的划分为两个主要的部分,一个是注册,另一个是上报. 1.1 注册 单点 ...
- Linux/Android——输入子系统input_event传递 (二)【转】
本文转载自:http://blog.csdn.net/jscese/article/details/42099381 在前文Linux/Android——usb触摸屏驱动 - usbtouchscre ...
随机推荐
- 笔试算法题(56):快速排序实现之非递归实现,最小k值选择(non-recursive version, Minimal Kth Selection of Quick Sort)
议题:快速排序实现之五(非递归实现,短序列优先处理,减少递归栈大小) 分析: 算法原理:此算法实现适用于系统栈空间不足够快速排序递归调用的需求,从而使用非递归实现快速排序算法:使用显示下推栈存储快速排 ...
- 五段实用的js高级技巧
技巧一之setTimeout. 应用案例:比如你想一个函数循环执行10次,怎么办?以前通常是先setInterval,然后clearInterval,技巧一就是克服这个问题 复制代码 代码如下: (f ...
- PHP:GD库 图片水印处理
文章来源:http://www.cnblogs.com/hello-tl/p/7592974.html <?php /** * 处理图片类 * 1.添加文字水印 * 2.添加图片水印 * 3.压 ...
- 利用类装饰器自定制property实现延迟计算
class LazyProperty: ''' hello,我是非数据描述符(没有定义__set__,不然是大哥数据描述符了--!) ''' def __init__(self, func): pri ...
- oracle 11g完全卸载
oracle 11g release2的完全卸载方式与前些版本有了改变,自带了一个卸载批处理文件——deinstall.bat.(这个工具可以从oracle的home进行完全的卸载,不管是单实例ora ...
- 竞赛Noi_Linux使用总结(vim)
刚换完Linux,趁着教练给的改题时间(T2确实猛)自己上网找了好多博客,发现很多跟竞赛有关的内容是碎片化的,从最基本的如何用vim写代码.编译.运行,再到怎么改设置使打代码时手感强一些,最后学对拍, ...
- npm run build 打包后,如何查看效果
我们用vue-cli搭建的项目执行npm build后本地打开页面空白,如果才能查看npm run build之后的结果呢 首先我们看一下提示 Tip: built files are meant t ...
- PLSQLDeveloper安装与配置(详细图文)
PLSQLDeveloper安装与配置(详细图文) 听语音 | 浏览:21912 | 更新:2016-10-24 17:12 1 2 3 4 5 6 7 分步阅读 在公司做项目时需要使用PLSQL D ...
- Flask(4):wtforms组件 & 数据库连接池 DBUtils
wtforms 组件的作用: --- 生成 HTML 标签 --- form 表单验证 示例代码: app.py from flask import Flask, render_template, r ...
- Codeforces713D. Animals and Puzzle
$n<=1000,m<=1000$,$n*m$的01矩阵,给$t<=1000000$个询问,每次问一个矩形中最大的1正方形的边长. 先想想不考虑“一个矩形中”的限制,那记$f(i,j ...