linux键盘input_event浅析【转】
转自:http://blog.csdn.net/tdstds/article/details/18710965
input_event(mxckbd_dev, EV_KEY, mxckpd_keycodes[scancode], 0);
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
unsigned long flags;
// 判断是否支持此种事件类型和事件类型中的编码类型
if(is_event_supported(type, dev->evbit, EV_MAX))
{
spin_lock_irqsave(&dev->event_lock, flags);
// 对系统随机熵池有贡献,因为这个也是一个随机过程
add_input_randomness(type, code, value);
// 这个函数是事件处理的关键函数
input_handle_event(dev, type, code, value);
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
***********************************************************************************************
static inline int is_event_supported(unsigned int code, unsigned long *bm, unsigned int max)
{
return code <= max && test_bit(code, bm);
}
static inline int test_bit(int nr, const volatile unsigned long *addr)
{
return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
}
***********************************************************************************************
void add_input_randomness(unsigned int type, unsigned int code, unsigned int value)
{
static unsigned char last_value;
/* ignore autorepeat and the like */
if (value == last_value)
return;
DEBUG_ENT("input event\n");
last_value = value;
add_timer_randomness(&input_timer_state, (type << 4) ^ code ^ (code >> 4) ^ value);
}
***********************************************************************************************
static void input_handle_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
int disposition = INPUT_IGNORE_EVENT;
switch (type)
{
...
case EV_KEY:
if (is_event_supported(code, dev->keybit, KEY_MAX) && !!test_bit(code, dev->key) != value)
{
if (value != 2)
{
__change_bit(code, dev->key);
if (value)
input_start_autorepeat(dev, code);
else
input_stop_autorepeat(dev);
}
// INPUT_PASS_TO_HANDLERS: 事件处理的方式是传递给事件处理器
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
...
}
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
dev->sync = 0;
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
dev->event(dev, type, code, value);
if (disposition & INPUT_PASS_TO_HANDLERS)
input_pass_event(dev, type, code, value);
}
static void input_pass_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct input_handler *handler;
struct input_handle *handle;
rcu_read_lock();
handle = rcu_dereference(dev->grab);
//如果是绑定的handle,则调用绑定的handler->event函数
if (handle)
handle->handler->event(handle, type, code, value);
else
{
//如果没有绑定,则遍历dev的h_list链表,寻找handle,如果handle已经打开,说明有进程读取设备关联的evdev。
bool filtered = false;
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
{
if (!handle->open)
continue;
handler = handle->handler;
if (!handler->filter)
{
if (filtered)
break;
// 调用相关的事件处理器的event函数,进行事件的处理
handler->event(handle, type, code, value);
}
else if(handler->filter(handle, type, code, value))
filtered = true;
}
}
rcu_read_unlock();
}
static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) // evdev.c
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
struct input_event event;
struct timespec ts;
ktime_get_ts(&ts);
// 将传过来的事件,赋值给input_event结构
event.time.tv_sec = ts.tv_sec;
event.time.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
event.type = type;
event.code = code;
event.value = value;
rcu_read_lock();
client = rcu_dereference(evdev->grab);
if (client) // 如果evdev绑定了client那么,处理这个客户端,触摸屏驱动没有绑定
evdev_pass_event(client, &event);
else // // 遍历client链表,调用evdev_pass_event函数
list_for_each_entry_rcu(client, &evdev->client_list, node)
evdev_pass_event(client, &event);
rcu_read_unlock();
wake_up_interruptible(&evdev->wait); //唤醒等待的进程
}
// evdev_pass_event函数最终将事件传递给了用户端的client结构中的input_event数组中,只需将这个input_event数组
// 复制给用户空间,进程就能收到触摸屏按下的信息了。具体处理由具体的应用程序来完成。
static void evdev_pass_event(struct evdev_client *client, struct input_event *event) // evdev.c
{
/*
* Interrupts are disabled, just acquire the lock
*/
spin_lock(&client->buffer_lock);
client->buffer[client->head++] = *event; // 将事件赋值给客户端的input_event 数组
client->head &= EVDEV_BUFFER_SIZE - 1;
spin_unlock(&client->buffer_lock);
if (event->type == EV_SYN)
kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
***********************************************************************************************
linux键盘input_event浅析【转】的更多相关文章
- Linux模块机制浅析
Linux模块机制浅析 Linux允许用户通过插入模块,实现干预内核的目的.一直以来,对linux的模块机制都不够清晰,因此本文对内核模块的加载机制进行简单地分析. 模块的Hello World! ...
- Linux 设备模型浅析之 uevent 篇(2)
Linux 设备模型浅析之 uevent 篇 本文属本人原创,欢迎转载,转载请注明出处.由于个人的见识和能力有限,不可能面 面俱到,也可能存在谬误,敬请网友指出,本人的邮箱是 yzq.seen@gma ...
- linux内核cfs浅析
linux调度器的一般原理请参阅<linux进程调度浅析>.之前的调度器cfs之前的linux调度器一般使用用户设定的静态优先级,加上对于进程交互性的判断来生成动态优先级,再根据动态优先级 ...
- Linux 键盘输入#的时候变成£
/********************************************************************************* * Linux 键盘输入#的时候变 ...
- Linux模块机制浅析_转
Linux模块机制浅析 转自:http://www.cnblogs.com/fanzhidongyzby/p/3730131.htmlLinux允许用户通过插入模块,实现干预内核的目的.一直以来,对l ...
- Linux进程IPC浅析[进程间通信SystemV共享内存]
Linux进程IPC浅析[进程间通信SystemV共享内存] 共享内存概念,概述 共享内存的相关函数 共享内存概念,概述: 共享内存区域是被多个进程共享的一部分物理内存 多个进程都可把该共享内存映射到 ...
- 【ARM-Linux开发】Linux模块机制浅析
Linux模块机制浅析 Linux允许用户通过插入模块,实现干预内核的目的.一直以来,对linux的模块机制都不够清晰,因此本文对内核模块的加载机制进行简单地分析. 模块的Hello World! ...
- 13.Linux键盘驱动 (详解)
版权声明:本文为博主原创文章,未经博主允许不得转载. 在上一节分析输入子系统内的intput_handler软件处理部分后,接下来我们开始写input_dev驱动 本节目标: 实现键盘驱动,让开发板的 ...
- 13.Linux键盘按键驱动 (详解)
在上一节分析输入子系统内的intput_handler软件处理部分后,接下来我们开始写input_dev驱动 本节目标: 实现键盘驱动,让开发板的4个按键代表键盘中的L.S.空格键.回车键 1.先来介 ...
随机推荐
- 数据库事物 jdbc事物 spring事物 隔离级别:脏幻不可重复读
1.数据库事物: 事物的概念 a给b打100块钱的例子 2.jdbc事物: 通过下面代码实现 private Connection conn = null; private PreparedState ...
- Java pdf转String 并修正格式
在尝试pdf转成String的时候,首先用python的pdfminer和pdfminer3k去尝试转换,然后资料看不太懂,就尝试用了java, 以下是java的pdfbox写的pdf转String函 ...
- UIScrollView浏览一组图片,且图片与图片之间有间隔
---恢复内容开始--- UIScrollView是可以浏览一组view的,只要将其属性 pagingEnabled设置为true就可以了.具体过程是这样的, 1:将一组图片按照从左到右的顺序添加到U ...
- 单点登录(二)----实战------简单搭建CAS---测试认证方式搭建CAS
我们在上一篇文章中已经介绍了cas以及它的工作流程. 单点登录(一)-----理论-----单点登录SSO的介绍和CAS+选型 本章我们开始动手搭建一个完整的cas服务实现2个web之间的单点登录. ...
- java 操作命令行
目的:用java进行调用ab压测 window: cmd ab.exe linux: sh ab.sh 命令: abs -n 500 -c 10 https://www.baidu.com/ > ...
- Android Data Binding(数据绑定)用户指南
Android Data Binding(数据绑定)用户指南 http://www.jianshu.com/p/b1df61a4df77 https://github.com/LyndonChin/M ...
- laravel 获取所有表名
$tables = DB::connection()->getDoctrineSchemaManager()->listTableNames(); 需要 doctrine/dbal 扩展, ...
- 清除.svn文件(windows & linux)
如何清除文件夹中的.svn信息 1:来由 当需要在某个svn版本控制下添加某个包时, 常常是在另一个版本控制下sync过来, 但这是这个包是在别的版本控制下, 每个目录下都有版本控制文件.svn, 如 ...
- Service Fabric —— Actor / Stateless Service 概念
作者:潘罡 (Van Pan) @ Microsoft 上一节我们谈到了Stateful Service.在Service Fabric中,Stateful Service是理解Micro Servi ...
- No module named 'urllib.request'; 'urllib' is not a package
想学爬虫urllib的设置代理服务器,于是把之前跳过没学的urllib捡起来,敲了段简单的代码,如下 import urllib.request url = "http://www.baid ...