evdev[输入事件驱动],为输入子系统提供了一个默认的事件处理方法。其接收来自底层驱动的大多数事件,并使用相应的逻辑对其进行处理。
evdev从底层接收事件信息,将其反映到sys文件系统中,用户程序通过对sys文件系统的操作,就能够达到处理事件的能力。
1. evdev的初始化
evdev以模块的方式被组织在内核中,也具有初始化函数和卸载函数。evdev的初始化主要完成一些注册工作,使内核认识evdev的存在。
evdev模块定义在/drivers/input/evdev.c文件中,该模块的初始化函数是evdev_init()。在初始化函数中注册了一个evdev_handler结构体,用来对一些通用的抽象事件进行统一处理,函数的代码如下
static int __init evdev_init(void)
{
/*将evdev_handler注册到系统中*/
return input_register_handler(&evdev_handler);
}
static void __exit evdev_exit(void)
{
input_unregister_handler(&evdev_handler);
}
module_init(evdev_init);
module_exit(evdev_exit);
第03行,调用input_register_handler()函数注册了evdev_handler事件处理器,input_register_handler()函数在前面已经详细解释过,这里将对其参数evdev_handler进行分析,其定义如下:
static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
第06行,定义了minor为EVDEV_MINOR_BASE(64)。因为一个handler可以处理32个设备,所以evdev_handler所能处理的设备文件范围为(13,64)~(13,64+32),其中13是所有输入设备的主设备号。
第08行,定义了id_table结构。回忆前面几节的内容,由input_attach_handler()函数可知,input_dev与handler匹配成功的关键,在于handler中的blacklist和id_talbe.。Evdev_handler只定义了id_table,其定义如下:
static const struct input_device_id evdev_ids[] = {
{iver_info = 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */
};
evdev_ids没有定义flags,也没有定义匹配属性值。这个evdev_ids的意思就是:evdev_handler可以匹配所有input_dev设备,也就是所有的input_dev发出的事件,都可以由evdev_handler来处理。
先来看两个结构体struct evdev, struct evdev_client:
struct evdev {
int open;
int minor; //在evdev_table中的索引
struct input_handle handle; //连接input_dev和input_handler
wait_queue_head_t wait;
struct evdev_client __rcu *grab; // 用户每调用一次open,将创建一个evdev_client
struct list_head client_list;
spinlock_t client_lock; /* protects client_list */
struct mutex mutex;
struct device dev;
bool exist;
};
struct evdev_client {
unsigned int head;
unsigned int tail;
unsigned int packet_head; /* [future] position of the first element of next packet */
spinlock_t buffer_lock; /* protects access to buffer, head and tail */
struct wake_lock wake_lock;
char name[28];
struct fasync_struct *fasync;
struct evdev *evdev;
struct list_head node;
unsigned int bufsize;
struct input_event buffer[]; //存放所有这个设备产生的input_event,由evdev_event写入
};
另外,从前面的分析可以知道,匹配成功之后会调用handler->connect()函数,对该函数的介绍如下:
static int evdev_connect(str