输入事件驱动---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系统支持的输入设备繁多,例如键盘.鼠标.触摸屏.手柄或者是一些输入设备像体感输入等等 ...
随机推荐
- 。。。IO流学习之二。。。
fileReader的用法: import static org.junit.Assert.*; import java.io.File; import java.io.FileNotFoundExc ...
- java.sql.SQLException: ORA-00942: 表或视图不存在
1.检查JDBC数据源是否配置正确:2.检查表或视图名称是否写错:3.检查Java中数据源的数据库用户是否具有引用该表或视图的权限:
- 邓博泽 java最全的DateUtil工具类
package com.kld.yijie.web.util; import org.slf4j.Logger;import org.slf4j.LoggerFactory; import java. ...
- Java多线程开发系列之四:玩转多线程(线程的控制1)
在前文中我们已经学习了:线程的基本情况.如何创建多线程.线程的生命周期.利用已有知识我们已经可以写出如何利用多线程处理大量任务这样简单的程序.但是当应用场景复杂时,我们还需要从管理控制入手,更好的操纵 ...
- linux环境下学习使用pro*c/c++工具
1.proc是oracle用来预编译嵌入SQL语句的c程序. 2.如何使用proc工具 在Linux环境下,首先确保gcc编译器正常使用,安装oracle数据库或者客户端,一般就会默认安装pro*c/ ...
- python学习笔记之基础一(第一天)
1. python字符介绍 在C语言中没有字符串,只有字符 在python中的字符串hello,在C语言中是以字符数组在内存存放['h','e','l','l','o'],如果对字符串修改,则是在内存 ...
- Map三种遍历方式
Map三种遍历方式 package decorator; import java.util.Collection; import java.util.HashMap; import java.util ...
- 上海有线通下载exe会302转发请求
起因: 做的软件用的clickonce,在公网的clickonce下载exe时一直报错,在vpn环境下没问题.错误提示如下: + HTTP redirect is not allowed for ap ...
- [T-SQL]INSERT INTO SELECT 与 SELECT INTO FROM
1.INSERT INTO SELECT 语法:INSERT INTO Table2(field1,field2,...) select value1,value2,... from Table1 要 ...
- Linux驱动程序学习【转】
本文转载自: 一直在学习驱动,对于下面这篇文章,本人觉得简洁明了,基本符合我们学习驱动的进度与过程,现转发到自己的博客,希望能与更多的朋友分享. 了解Linux驱动程序技巧学习的方法很重要,学习lin ...