Linux输入子系统框架分析(1)
在Linux下的输入设备键盘、触摸屏、鼠标等都能够用输入子系统来实现驱动。输入子系统分为三层,核心层和设备驱动层。事件层。核心层和事件层由Linux输入子系统本身实现,设备驱动层由我们实现。我们在设备驱动层将输入事件上报给核心层input.c,核心层找到匹配的事件层,将事件交给事件层处理,事件层处理完后传递到用户空间。
我们终于要搞清楚的是在用户空间调用open和read终于在内核中是如何处理的,向内核上报的事件又是谁处理的,处理完后是如何传递到用户空间的?


上面两个图是输入子系统的框架。
以下以按键驱动为例分析输入子系统的工作流程。
设备驱动层:
在设备驱动层的init入口函数中调用input_allocate_device(),分配返回一个input_dev结构体,填充该结构体,调用input_register_device(button_dev),注冊设备。跟踪input_register_device例如以下:
list_add_tail(&dev->node, &input_dev_list);将input_dev结构体放进input_dev_list链表中
list_for_each_entry(handler, &input_handler_list, node)遍历input_handler_list链表中的每个handler
input_attach_handler(dev, handler);将input_dev和handler比較
input_match_device(handler->id_table, dev);<*input.c*>
handler->connect(handler, dev, id);<*input.c*>比較的方式是通过对照handler的id_table和input_dev。若找
到匹配的handler。则调用handler的connect方法。
在evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)中调用了
input_register_handle,调用handle之前填充handle中成员dev和handler结构体。
evdev->handle.dev = input_get_device(dev);
evdev->handle.handler = handler;
在input_register_handle中list_add_tail_rcu(&handle->d_node, &dev->h_list)list_add_tail(&handle->h_node, &h andler->h_list)两个函数将handle增加进handler和dev的h_list链表中。
通过dev->h_list能够找到handle。通过
handle找到handle.handler,同理。通过handler->h_list能够找到handle,再找到handle.dev。
关键的问题来了?handler究竟是什么?由谁注冊的?handler是事件层调用核心层的函数注冊的。
事件层:(evdev.c,keyboard.c,ts.c)
static struct input_handler evdev_handler = {//handler结构体
.event
= evdev_event,
.connect
= evdev_connect,
.disconnect
= evdev_disconnect,
.fops = &evdev_fops,
.minor
= EVDEV_MINOR_BASE,
.name = "evdev",
.id_table
= evdev_ids,
};
在evdev_init(void)入口函数中调用input_register_handler(&evdev_handler)来注冊handler,注冊的handler会放入input_table[ ]数组中。
核心层:(input.c)
核心层的入口函数input_init(void)注冊设备input。
当在应用层调用open时会在内核中调用input_open_file(struct inode *inode, struct file *file)。依据handler =
input_table[iminor(inode) >> 5];依据打开的文件的次设备号从数组input_table中得到已注冊的相应的handler。
new_fops = fops_get(handler->fops)从handler中得到新的fop。
file->f_op = new_fops;
err = new_fops->open(inode, file);open终于调用的是handler->fops->open。
原来的设备驱动的open等方法是自
己写的。如今输入子系统中的事件层帮我们写好了open等设备方法。同理在应用层调用read会调用事件层中的
read。即handler->fops->read,即evdev_fops.read,在read中会堵塞。直到在设备驱动层中过input_report_key
上报事件:
input_event(dev, EV_KEY, code, !!value);
input_handle_event(dev, type, code, value);
input_pass_event(dev, type, code, value);
handle->handler->event(handle,type, code, value);调用handler中的event事件方法。处理完上报的事
件后,唤醒休眠的read,再read出事件的处理结果。
总结:
在用户空间调用open将终于调用事件层中handler的fops的open设备方法。详细是匹配到evdev.c还是keyboard.c的handler要依据设备驱动init入口函数中填充的input_dev结构体的id_table。
用户空间调用read将调用handler的read。
在设备驱动中通过input_event上报事件到核心层。终于调用相应的handler的event方法来处理事件,处理完后通过read传递到用户空间。
这样就搞清楚了open是谁调用的?read是谁调用的?
Linux输入子系统框架分析(1)的更多相关文章
- 7.Linux 输入子系统分析
为什么要引入输入子系统? 在前面我们写了一些简单的字符设备的驱动程序,我们是怎么样打开一个设备并操作的呢? 一般都是在执行应用程序时,open一个特定的设备文件,如:/dev/buttons .... ...
- Linux输入子系统详解
input输入子系统框架 linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler).输入子系统核心层(Input ...
- Linux USB驱动框架分析 【转】
转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...
- linux输入子系统之按键驱动
上一节中,我们讲解了Linux input子系统的框架,到内核源码里详细分析了输入子系统的分离分层的框架等. 上一节文章链接:http://blog.csdn.net/lwj103862095/ar ...
- linux驱动基础系列--linux spi驱动框架分析
前言 主要是想对Linux 下spi驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.设备模型等也不进行详细说明原理.如果有任何错误地方,请指出,谢谢! spi ...
- Linux USB驱动框架分析【转】
转自:http://blog.csdn.net/jeffade/article/details/7701431 Linux USB驱动框架分析(一) 初次接触和OS相关的设备驱动编写,感觉还挺有意思的 ...
- Linux输入子系统(Input Subsystem)
Linux输入子系统(Input Subsystem) http://blog.csdn.net/lbmygf/article/details/7360084 input子系统分析 http://b ...
- linux输入子系统
linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler).输入子系统核心层(InputCore)和输入子系统设备驱 ...
- linux输入子系统概念介绍
在此文章之前,我们讲解的都是简单的字符驱动,涉及的内容有字符驱动的框架.自动创建设备节点.linux中断.poll机制.异步通知.同步互斥.非阻塞.定时器去抖动. 上一节文章链接:http://blo ...
随机推荐
- server client 套接字连接
server端: 1. 阻塞型套接字,不能满足多个客户端同时访问 import socket server = socket.socket() server.bind((""127 ...
- JavaEE 之 DBCP
1.DBCP a.定义:DBCP(DataBase Connection Pool)数据库连接池,是java数据库连接池的一种,由Apache开发,通过数据库连接池,可以让程序自动管理数据库连接的释放 ...
- Largest Rectangle in a Histogram POJ - 2559 (单调栈)
Description A histogram is a polygon composed of a sequence of rectangles aligned at a common base l ...
- gitment Error:validation failed错误解决办法
点击Initialize comments 突然跳转出一个错误Error:validation failed 经查阅之后发现 issue的标签label有长度限制!labels的最大长度限制是50个字 ...
- POJ 2594 Treasure Exploration (Floyd+最小路径覆盖)
<题目链接> 题目大意: 机器人探索宝藏,有N个点,M条边.问你要几个机器人才能遍历所有的点. 解题分析: 刚开始还以为是最小路径覆盖的模板题,但是后面才知道,本题允许一个点经过多次,这与 ...
- docker+springboot+elasticsearch+kibana+elasticsearch-head整合(详细说明 ,看这一篇就够了)
一开始是没有打算写这一篇博客的,但是看见好多朋友问关于elasticsearch的坑,决定还是写一份详细的安装说明与简单的测试demo,只要大家跟着我的步骤一步步来,100%是可以测试成功的. 一. ...
- 004.Ceph块设备基础使用
一 基础准备 参考<002.Ceph安装部署>文档部署一个基础集群: 新增节点主机名及IP在deploy节点添加解析: [root@deploy ~]# echo "172.24 ...
- javaScript函数节流与函数防抖
javaScript函数节流与防抖之区别 函数防抖(debounce)与函数节流(throttle)都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟.假死或卡顿 ...
- python基础一 ------如何对元组各个元素进行命名
对元组各个元素进行命名 1,通过对元组索引值的命名 2,通过标准库中的collections.nametuple替代内置touple 通过对元组索引值的命名 好比在c中的defined详细见代码 na ...
- 【DWM1000】 code 解密8一 TAG接收blink response 信号
在分析这个部分前,目前我看到DWM1000 的资料,data可以分为blink和一般无线数据,后面有内容我们再扩充, 上面我们已经看到接收到blink触发的事件为 case SIG_RX_BLINK ...