linux键盘input_event浅析【转】
2016-01-07 11:15
579 查看
转自:/article/2159704.html
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);
}
***********************************************************************************************
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 sed简单使用
- linux下安装gcc详解
- Ubuntu/Debian操作系统与RedHat/CentOS系统的细节区别(未完结)
- linux没有那个文件或目录
- Linux系统下使用uname命令显示系统和硬件信息
- LINUX监控一:监控命令
- linux&window-命令行
- centos6.7安装jira
- centos中查找出大文件命令汇总
- linux安装dns
- linux 内存使用
- linux 文件系统 (一) 文件系统、文件结构、虚拟文件系统的定义及作用、VFS与文件系统的关系
- linux内核启动2_setup_arch函数
- 1.Linux应用编程---文件I/O(open、read、write、lseek、close)
- linux下符号链接和硬链接的区别
- Centos6.5 VNC 配置
- CentOS7 卸载KDE桌面
- CentOS7下LVS+Keepalived实现高性能高可用负载均衡
- Linux系统中列出PCI设备和USB设备的命令详解
- Linux 日常高频操作整理