Linux input子系统分析 事件传递过程
2013-11-28 21:20
344 查看
三. 事件传递过程(以s3c2410_ts为例)
1. 事件产生
当按下触摸屏时,进入触摸屏按下中断,开始ad转换,ad转换完成进入ad完成中断,在这个终端中将事件发送出去,调用
input_report_abs(dev, ABS_X, xp);
input_report_abs(dev, ABS_Y, yp); 这两个函数调用了 input_event(dev, EV_ABS, code, value)
所有的事件报告函数都调用这个函数。
2. 事件报告
(1) input_event 函数分析,这个函数定义在input.c中
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);
}
}
(2) input_handle_event 函数分析,这个函数定义在input.c中
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);
}
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);
}
这个函数主要是根据事件类型的不同,做相应的处理。这里之关心EV_KEY类型,其他函数和事件传递关系不大,只要关心,disposition这个是事件处理的方式,默认的是INPUT_IGNORE_EVENT,忽略这个事件,如果是INPUT_PASS_TO_HANDLERS则是传递给事件处理器,如果是INPUT_PASS_TO_DEVICE,则是传递给设备处理,触摸屏驱动没有定义这个。下面分析input_pass_event函数。
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
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。
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle,
type, code, value);
// 调用相关的事件处理器的event函数,进行事件的处理
rcu_read_unlock();
}
下面分析 evdev事件处理器的event函数
static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
struct input_event event;
do_gettimeofday(&event.time);
event.type = type;
event.code = code;
event.value = value;
//将传过来的事件,赋值给input_event结构
rcu_read_lock();
client = rcu_dereference(evdev->grab);
//如果evdev绑定了client那么,处理这个客户端,触摸屏驱动没有绑定
if (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 函数
static void evdev_pass_event(struct evdev_client *client,
struct input_event *event)
{
/*
* 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);
kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
可以看出, evdev_pass_event函数最终将事件传递给了用户端的client结构中的input_event数组中,只需将这个input_event数组复制给用户空间,进程就能收到触摸屏按下的信息了。具体处理由具体的应用程序来完成。
1. 事件产生
当按下触摸屏时,进入触摸屏按下中断,开始ad转换,ad转换完成进入ad完成中断,在这个终端中将事件发送出去,调用
input_report_abs(dev, ABS_X, xp);
input_report_abs(dev, ABS_Y, yp); 这两个函数调用了 input_event(dev, EV_ABS, code, value)
所有的事件报告函数都调用这个函数。
2. 事件报告
(1) input_event 函数分析,这个函数定义在input.c中
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);
}
}
(2) input_handle_event 函数分析,这个函数定义在input.c中
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);
}
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);
}
这个函数主要是根据事件类型的不同,做相应的处理。这里之关心EV_KEY类型,其他函数和事件传递关系不大,只要关心,disposition这个是事件处理的方式,默认的是INPUT_IGNORE_EVENT,忽略这个事件,如果是INPUT_PASS_TO_HANDLERS则是传递给事件处理器,如果是INPUT_PASS_TO_DEVICE,则是传递给设备处理,触摸屏驱动没有定义这个。下面分析input_pass_event函数。
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
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。
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle,
type, code, value);
// 调用相关的事件处理器的event函数,进行事件的处理
rcu_read_unlock();
}
下面分析 evdev事件处理器的event函数
static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
struct input_event event;
do_gettimeofday(&event.time);
event.type = type;
event.code = code;
event.value = value;
//将传过来的事件,赋值给input_event结构
rcu_read_lock();
client = rcu_dereference(evdev->grab);
//如果evdev绑定了client那么,处理这个客户端,触摸屏驱动没有绑定
if (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 函数
static void evdev_pass_event(struct evdev_client *client,
struct input_event *event)
{
/*
* 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);
kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
可以看出, evdev_pass_event函数最终将事件传递给了用户端的client结构中的input_event数组中,只需将这个input_event数组复制给用户空间,进程就能收到触摸屏按下的信息了。具体处理由具体的应用程序来完成。
相关文章推荐
- linux input子系统分析--子系统核心.事件处理层.事件传递过程
- Linux input子系统分析---5、事件传递过程
- Linux Input子系统分析之eventX设备创建和事件传递
- Linux input子系统分析 事件处理层分析
- Android系统之事件处理子系统启动过程的学习和分析
- input子系统四之事件处理过程分析
- 事件传递和响应者链条原理分析
- Android输入子系统之应用程序注册消息监听过程分析
- u-boot与linux内核间的参数传递过程分析
- 触摸事件的顺序,事件传递过程
- Linux input子系统实例分析(二)
- Linux input子系统分析---4、事件处理层分析
- Linux内核源码分析--内核启动命令行的传递过程(Linux-3.0 ARMv7)
- spring事件驱动过程分析
- Jquery Ajax学习实例7-Ajax所有过程事件分析示例
- Vue框架Element的事件传递broadcast和dispatch方法分析
- 消息传递机制的具体实现过程(分析源码之后的总结)
- Android事件传递机制(更加深入的了解事件的触发过程)
- Linux内核--网络栈实现分析(二)--数据包的传递过程(上)
- Android事件传递机制(更加深入的了解事件的触发过程)