输入事件驱动---evdev_handler的大致实现流程(修整版)
一、input输入子系统框架
下 图是input输入子系统框架,输入子系统由输入子系统核心层(input core),驱动层和事件处理层(Event Handler)三部分组成。一个输入事件,比如滑动触摸屏都是通过input driver -> input core -> event handler -> user space 到达用户空间传给应用程序。
event hander事件处理层主要和用户空间交互,接收用户空间下发的file operation操作命令,生成/dev/input/xx设备节点供用户空间进行file operations操作;
input core层负责管理系统中的input dev设备 和input hander事件处理,并起到承上启下作用,负责输入设备和input handler之间信息传输;
input driver为具体用户设备驱动,输入设备由struct input-dev 结构表示,并由input_register_device和input_unregister_device来注册和卸载;
输入子系统结构方框图如下图:

二、输入事件驱动--->evdev_handler的实现大致分析
Linux
输入子系统已经建立好了几个handler,用来处理几类常见的事件,如鼠标、键盘、摇杆等。其中最为基础的是evdev_handler,它是在
driver/input/evdev.c中实现的。它能够接收任意类型的事件,任意id的设备都可以和它匹配连接,它对应的设备节点为/dev/eventX,次设备号的范围为64~95。
evdev输入事件驱动,为输入子系统提供了一个默认的事件处理方法。其接收来自底层驱动的大多数事件,并使用相应的逻辑对其进行处理。
module_exit(evdev_exit);//初始化evdev_handlerstatic int __init evdev_init(void){
return input_register_handler(&evdev_handler);}
/**一般事件驱动定义了evdev_handler结构表示自己,
*并尝试去找到与handler中id_table相匹配的输入设备。*/static struct input_handler evdev_handler = {.event = evdev_event,
其中有:#define EVDEV_MINOR_BASE 64
.id_table = evdev_ids,};
MODULE_DEVICE_TABLE(input, evdev_ids);
static const struct input_device_id evdev_ids[] = {{ .driver_info = 1 },/* Matches all devices */{ },/* Terminating zero entry */};/**不管是事件驱动还是输入设备驱动在初始化时注册自身到全局链表中,并尝试与对应的输入设备驱动或事件驱动连接,*最终的操作都是调用事件驱动的XX_connect(...)完成两者的连接的。*/static int evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id){struct evdev *evdev;int minor;int error;
for (minor = 0; minor < EVDEV_MINORS; minor++)if (!evdev_table[minor])break;
其中有定义:int open;
char name[16];
wait_queue_head_t wait;
spinlock_t client_lock; /* protects client_list */
struct device dev;
表示evdev_handler所表示的32个设备,这个循环为了找到空的一项
if (minor == EVDEV_MINORS) { //return -ENFILE;}
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);if (!evdev)return -ENOMEM;
INIT_LIST_HEAD(&evdev->client_list); //初始化spin_lock_init(&evdev->client_lock);mutex_init(&evdev->mutex);init_waitqueue_head(&evdev->wait);
dev_set_name(&evdev->dev, "event%d", minor); //event对应节点号,event0/evdev->minor = minor;
evdev->handle.dev = input_get_device(dev); //挂载到对evdev中handle的初始化,这些初始化的目的是使input_dev和input_handler联系起来。evdev->handle.name = dev_name(&evdev->dev);evdev->handle.handler = handler;evdev->handle.private = evdev;
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); //生成设备号evdev->dev.class = &input_class; //input的class类下evdev->dev.parent = &dev->dev;evdev->dev.release = evdev_free;device_initialize(&evdev->dev); //设备初始化
/*input_register_handle()最终完成了两者的连接,具体实现可研究其实现源码。input_register_handle -登记一个新的 input handle,此功能将一个新的而一旦打开使用input_open_device(),events事件可以随时跟随。*/error = input_register_handle(&evdev->handle); //error = evdev_install_chrdev(evdev); //初始化字符设备if (error)goto err_unregister_handle;
error = device_add(&evdev->dev); //添加一个设备if (error)goto err_cleanup_evdev;
return 0;
err_cleanup_evdev: evdev_cleanup(evdev);err_unregister_handle: input_unregister_handle(&evdev->handle);err_free_evdev: put_device(&evdev->dev);return error;}
对主设备号为INPUT_MAJOR的设备结点进行操作,会将操作集转换成handler的操作集。在evdev_handler中定义了一个fops集合,被赋值为evdev_fops的指针,static int evdev_open(struct inode *inode, struct file *file)
{
struct evdev *evdev;
struct evdev_client *client;
int i = iminor(inode) - EVDEV_MINOR_BASE; //得到了在evdev_table[]中的序号
int error;
if (i >= EVDEV_MINORS)
return -ENODEV;
error = mutex_lock_interruptible(&evdev_table_mutex);
if (error)
return error;
if (evdev)
mutex_unlock(&evdev_table_mutex);
其中:
int head;
spinlock_t buffer_lock; /* protects access to buffer, head and tail */
struct list_head node;
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;
input_open_device打开evdev对应的handle
if (retval)
}
return retval;
if (error)
goto err_free_client;
err_free_client:
evdev_detach_client(evdev, client);
kfree(client);
err_put_evdev:
put_device(&evdev->dev);
return error;
}
return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0);}
static long evdev_ioctl_handler(struct file *file, unsigned int cmdvoid __user *p, int compat_mode){struct evdev_client *client = file->private_data;struct evdev *evdev = client->evdev;int retval;retval = mutex_lock_interruptible(&evdev->mutex);if (retval)return retval;if (!evdev->exist) {retval = -ENODEV;goto out;}retval = evdev_do_ioctl(file, cmd, p, compat_mode); out:mutex_unlock(&evdev->mutex);return retval;}
static long evdev_do_ioctl(struct file *file, unsigned int cmd,
void __user *p, int compat_mode)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
struct input_dev *dev = evdev->handle.dev;
struct input_absinfo abs;
struct ff_effect effect;
int __user *ip = (int __user *)p;
unsigned int i, t, u, v;
unsigned int size;
int error;
/* First we check for fixed-length commands */
switch (cmd) {
case EVIOCGVERSION:
/* 设置重复类事件 */
%
输入事件驱动---evdev_handler的大致实现流程(修整版)的更多相关文章
- Android 输入管理服务-输入事件到达之后的处理流程
接上一篇博客"Android 输入管理服务启动过程的流程".这两天分析了Android 输入管理服务接收到输入事件之后的处理流程,详细流程例如以下面两图所看到的: 接下图
- 面试突击72:输入URL之后会执行什么流程?
在浏览器中输入 URL 之后,它会执行以下几个流程: 执行 DNS 域名解析: 封装 HTTP 请求数据包: 封装 TCP 请求数据包: 建立 TCP 连接(3 次握手): 参数从客户端传递到服务器端 ...
- springboot 大致启动流程
SpringApplication的run方法的实现是我们本次旅程的主要线路,该方法的主要流程大体可以归纳如下: 1) 如果我们使用的是SpringApplication的静态run方法,那么,这个方 ...
- Java-->发牌流程修改版
--> 这一次要封装得狠一点... package com.xm.ddz; // 每一张牌的属性 public class Card { private String flowerColor; ...
- struts2框架的大致处理流程
1,浏览器发送请求,例如请求 /mypage.action /report/myreport.pdf等. 2,核心控制器FilterDispatcher根据请求决定调用合适的Action. 3,Web ...
- tp 大致执行流程
http://www.thinkphp.cn/code/305.html http://document.thinkphp.cn/manual_3_2.html#wechat
- Shiro在Web环境下集成Spring的大致工作流程
1,Shiro提供了对Web环境的支持,其通过一个 ShiroFilter 入口来拦截需要安全控制的URL,然后进行相应的控制. ①配置的 ShiroFilter 实现类为:org.spri ...
- input输入子系统
一.什么是input输入子系统? 1.Linux系统支持的输入设备繁多,例如键盘.鼠标.触摸屏.手柄或者是一些输入设备像体感输入等等,Linux系统是如何管理如此之多的不同类型.不同原理.不同的输入信 ...
- INPUT输入子系统【转】
转自:https://www.cnblogs.com/deng-tao/p/6094049.html 1.Linux系统支持的输入设备繁多,例如键盘.鼠标.触摸屏.手柄或者是一些输入设备像体感输入等等 ...
随机推荐
- HTML5--div、span超出部分省略号显示
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 基于webpack使用ES6新特性(转载)
本文转载自: http://www.tuicool.com/articles/vye2ea6
- mysql 性能优化方案1
网 上有不少mysql 性能优化方案,不过,mysql的优化同sql server相比,更为麻烦与复杂,同样的设置,在不同的环境下 ,由于内存,访问量,读写频率,数据差异等等情况,可能会出现不同的结果 ...
- JavaScript语言精粹读书笔记 - JavaScript函数
JavaScript是披着C族语言外衣的LISP,除了词法上与C族语言相似以外,其他几乎没有相似之处. JavaScript 函数: 函数包含一组语句,他们是JavaScript的基础模块单元,用于代 ...
- 关于获取web应用的文件路径的注意事项
今天在把数据写入文件时遇到了一个问题,指定的文件获取不到.一开始是这样的 URL url = XXX.class.getClassLoader().getResource(fileName);File ...
- 深入理解JavaScript闭包【译】
在<高级程序设计>中,对于闭包一直没有很好的解释,在stackoverflow上翻出了一篇很老的<JavaScript closure for dummies>(2016)~ ...
- 《C++ API设计》作者Martin Reddy访谈问题征集
Martin Reddy博士是软件行业的一名老兵,有着15年以上的从业经验,共撰写过40多篇论文,拥有3项软件专利,并与他人合著了Level of Detail for 3D Graphics.另外, ...
- Eclipse断点调试方法
1. 条件断点 断点大家都比较熟悉,在Eclipse Java 编辑区的行头双击就会得到一个断点,代码会运行到此处时停止. 条件断点,顾名思义就是一个有一定条件的断点,只有满足了用户设置的条件,代码才 ...
- mysql基础安全
- IOS响应式编程框架ReactiveCocoa(RAC)使用示例
ReactiveCocoa是响应式编程(FRP)在iOS中的一个实现框架,它的开源地址为:https://github.com/ReactiveCocoa/ReactiveCocoa# :在网上看了几 ...