输入事件驱动---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系统支持的输入设备繁多,例如键盘.鼠标.触摸屏.手柄或者是一些输入设备像体感输入等等 ...
随机推荐
- centos7 开启防火墙端口 firewalld
systemctl start firewalld firewall-cmd --zone=public --add-port=3306/tcp --permanent firewall-cmd -- ...
- ElasticSearch
ElaticSearch简介: ES是一个搜索引擎,基于当前最先进,最高效的全功能开源搜索引擎框架lucene ES还有许多功能: 分布式实时文件存储,并将每一个字段都编入索引,使其可以被搜索 近实时 ...
- 为什么要配置sdk-tools/platform-toools?
为了方便使用Android SDK包含的开发工具,我们在系统环境变量中的Path设置Android SDK的安装目录下的tools目录. Android SDK中: platform-tools里有a ...
- tk画图
Page 387 of chapter 7 """ 6-23 page 343 play media files """ def odd() ...
- Android隐藏状态栏、导航栏
Android隐藏状态栏.导航栏 private void hideStatusNavigationBar(){ if(Build.VERSION.SDK_INT<16){ this.getWi ...
- 最新IP地址数据库Dat格式-高性能高并发版(2017年1月)
最新IP地址数据库->Dat格式 高性能格式->qqzeng-ip.dat 国内版-20170101-Dat 版 国外版-20170101-Dat 版 ...
- EF Core 1.0 和 SQLServer 2008 分页的问题
EF Core 1.0 在sqlserver2008分页的时候需要指定用数字分页. EF Core1.0 生成的分页语句中使用了 Featch Next.这个语句只有在SqlServer2012的时候 ...
- windows下使用火狐浏览器插件AutoProxy+MyEnTunnel+SSH访问海外站点(转)
windows下使用火狐浏览器插件AutoProxy+MyEnTunnel+SSH访问海外站点 平时需要查阅一些技术资料,光走VPN太浪费流量,所以这儿教大家一种使用火狐浏览器的插件 AutoPr ...
- Windows7下的免费虚拟机(微软官方虚拟机)
前言: 不是说windows7自带的虚拟机最好用,而是他是正式版的,免费的,只要你是windows7用户,就可以免费使用: 其实我最推荐的还是Vmware: 微软为什么提供免费的虚拟机呢? 因为vis ...
- 自己动手写ORM框架
提起ORM框架,大家都很熟悉,网上流行的ORM框架有很多,其中出名的有一些,不出名的更是数不胜数. 下面是自己实现的一个简单的ORM框架,实现了常用的增删查改功能,供大家研究ORM实现原理. 功能描述 ...