linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler)、输入子系统核心层(InputCore)和输入子系统设备驱动层。
输入子系统由输入子系统核心层( Input Core ),驱动层和事件处理层(Event Handler)三部份组成。
一个输入事件,从具体设备的device driver---> input driver -> Input core -> Event handler -> userspace 到达用户空间传给应用程序。
主要功能
Event handler对应一个名为input_handler的结构体,该结构体内含的主要成员如下
.id_table 一个存放该handler所支持的设备id的表(其实内部存放的是EV_xxx事件,用于判断device是否支持该事件)
.fops 该handler的file_operation
.connect 连接该handler跟所支持device的函数
.disconnect 断开该连接
.event 事件处理函数,让device调用
h_list 也是一个链表,该链表保存着该handler到所支持的所有device的中间站:handle结构体的指针
device是纯硬件操作层,包含不同的硬件接口处理,如gpio等
对于每种不同的具体硬件操作,都对应着不同的input_dev结构体
该结构体内部也包含着一个h_list
对于handler和device,分别用链表input_handler_list和input_device_list进行维护,
当handler或者device增加或减少的时候,分别往这两链表增加或删除节点。
input_dev 这是input设备基本的设备结构,每个input驱动程序中都必须分配初始化这样一个结构,成员比较多
struct input_dev {
const char *name;
const char *phys;
const char *uniq;
struct input_id id;
unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
unsigned int hint_events_per_packet;
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
int (*setkeycode)(struct input_dev *dev,
const struct input_keymap_entry *ke,
unsigned int *old_keycode);
int (*getkeycode)(struct input_dev *dev,
struct input_keymap_entry *ke);
struct ff_device *ff;
unsigned int repeat_key;
struct timer_list timer;
int rep[REP_CNT];
struct input_mt *mt;
struct input_absinfo *absinfo;
unsigned long key[BITS_TO_LONGS(KEY_CNT)];
unsigned long led[BITS_TO_LONGS(LED_CNT)];
unsigned long snd[BITS_TO_LONGS(SND_CNT)];
unsigned long sw[BITS_TO_LONGS(SW_CNT)];
int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev);
int (*flush)(struct input_dev *dev, struct file *file);
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
struct input_handle __rcu *grab;
spinlock_t event_lock;
struct mutex mutex;
unsigned int users;
bool going_away;
struct device dev;
struct list_head h_list;
struct list_head node;
unsigned int num_vals;
unsigned int max_vals;
struct input_value *vals;
bool devres_managed;
};
(1)多个位图数组
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //事件支持的类型
// 下面是每种类型支持的编码
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //按键
unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //绝对坐标,其中触摸屏驱动使用的就是这个
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
(2) struct input_id id 成员
struct input_id {
__u16 bustype; //总线类型
__u16 vendor; //生产厂商
__u16 product; //产品类型
__u16 version; //版本
};
如果需要特定的事件处理器来处理这个设备的话,这几个就非常重要,因为子系统核心是通过他们,将设备驱动与事件处理层联系起来的。但是因为安卓系统大部分的输入设备驱动匹配的事件处理器为evdev,所有这个初始化也无关紧要。
input_handler 这是事件处理器的数据结构,代表一个事件处理器
struct input_handler {
void *private;
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
void (*events)(struct input_handle *handle,
const struct input_value *vals, unsigned int count);
bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
bool (*match)(struct input_handler *handler, struct input_dev *dev);
int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
void (*disconnect)(struct input_handle *handle);
void (*start)(struct input_handle *handle);
bool legacy_minors;
int minor;
const char *name;
const struct input_device_id *id_table;
struct list_head h_list;
struct list_head node;
};
(1)几个操作函数
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
void (*disconnect)(struct input_handle *handle); void (*start)(struct input_handle *handle);
event 函数是当事件处理器接收到了来自input设备传来的事件时调用的处理函数,负责处理事件,非常重要。
connect 函数是当一个input设备模块注册到内核的时候调用的,将事件处理器与输入设备联系起来的函数,也就是将input_dev和input_handler配对的函数。
disconnect 函数实现connect相反的功能。
(2) 一个id
const struct input_device_id *id_table; //这个是事件处理器所支持的input设备
这个数组都会用在connect函数中,input_device_id结构与input_id结构类似,但是input_device_id有一个flag,用来让程序选择比较哪项,如:busytype,vendor还是其他。
struct input_device_id {
kernel_ulong_t flags;
__u16 bustype;
__u16 vendor;
__u16 product;
__u16 version;
kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];
kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];
kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];
kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];
kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];
kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];
kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];
kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];
kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];
kernel_ulong_t driver_info;
};
input_handle 结构体代表一个成功配对的input_dev和input_handler
struct input_handle {
/*每个配对的事件处理器都会分配一个对应的设备结构,如evdev事件处理器的evdev结构,
注意这个结构与设备驱动层的input_dev不同,初始化handle时,保存到这里。*/
void *private;
int open; //打开标志,每个input_handle 打开后才能操作,这个一般通过事件处理器的open方法间接设置
const char *name;
struct input_dev *dev; //关联的input_dev结构
struct input_handler *handler; //关联的input_handler结构
struct list_head d_node; //input_handle通过d_node连接到了input_dev上的h_list链表上
struct list_head h_node; //input_handle通过h_node连接到了input_handler的h_list链表上
};
input_dev 是硬件驱动层,代表一个input设备
input_handler 是事件处理层,代表一个事件处理器
input_handle 属于核心层,代表一个配对的input设备与input事件处理器
input_dev 通过全局的input_dev_list链接在一起。设备注册的时候实现这个操作。
input_handler 通过全局的input_handler_list链接在一起。事件处理器注册的时候实现这个操作(事件处理器一般内核自带,一般不需要我们来写)
input_hande 没有一个全局的链表,它注册的时候将自己分别挂在了input_dev 和 input_handler 的h_list上了。
通过input_dev 和input_handler就可以找到input_handle 在设备注册和事件处理器, 注册的时候都要进行配对工作,配对后就会实现链接。
通过input_handle也可以找到input_dev和input_handler。
注:三者之间的关系可以参考前面介绍的input子系统框架图
struct evdev {
int exist;
int open; //打开标志
int minor; //次设备号
struct input_handle handle; //关联的input_handle
wait_queue_head_t wait; //等待队列,当进程读取设备,而没有事件产生的时候,进程就会睡在其上面
struct evdev_client *grab; //强制绑定的evdev_client结构,这个结构后面再分析
struct list_head client_list; //evdev_client 链表,这说明一个evdev设备可以处理多个evdev_client,可以有多个进程访问evdev设备
spinlock_t client_lock; /* protects client_list */
struct mutex mutex;
struct device dev; //device结构,说明这是一个设备结构
};
evdev结构体在配对成功的时候生成,由handler->connect生成,对应设备文件为sys/class/input/event(n)。
如触摸屏驱动的event0,这个设备是用户空间要访问的设备,可以理解它是一个虚拟设备,因为没有对应的硬件,但是通过handle->dev 就可以找到input_dev结构。这个设备结构生成之后保存在evdev_table中,索引值是minor。
注:需要注意evdev结构体------->sys/class/input/event(n) input_dev结构-------->sys/class/input/input(n)
sdm660_64:/sys/class/input # ls
event0 event16 event23 event30 input1 input17 input24 input4
event1 event17 event24 event4 input10 input18 input25 input5
event10 event18 event25 event5 input11 input19 input26 input6
event11 event19 event26 event6 input12 input2 input27 input7
event12 event2 event27 event7 input13 input20 input28 input8
event13 event20 event28 event8 input14 input21 input29 input9
event14 event21 event29 event9 input15 input22 input3 mice
event15 event22 event3 input0 input16 input23 input30 mouse0
sdm660_64:/sys/class/input #
struct evdev_client {
struct input_event buffer[EVDEV_BUFFER_SIZE];
//这个是一个input_event数据结构的数组,input_event代表一个事件,基本成员:类型(type),编码(code),值(value)
int head; //针对buffer数组的索引
int tail; //针对buffer数组的索引,当head与tail相等的时候,说明没有事件
spinlock_t buffer_lock; /* protects access to buffer, head and tail */
struct fasync_struct *fasync; //异步通知函数
struct evdev *evdev; //evdev设备
struct list_head node; // evdev_client 链表项
};
这个结构在进程打开event0设备的时候调用evdev的open方法,在open中创建这个结构,并初始化。在关闭设备文件的时候释放这个结构。
static const struct input_device_id evdev_ids[] = {
{ .driver_info = 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */
};
MODULE_DEVICE_TABLE(input, evdev_ids);
static struct input_handler evdev_handler = {
.event = evdev_event,
.events = evdev_events,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.legacy_minors = true,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
struct evdev { //每次与evdev_handler 配对成功都会创建这个机构体 而且对应一个eventx
int open;
struct input_handle handle;
wait_queue_head_t wait;
struct evdev_client __rcu *grab;
struct list_head client_list;
spinlock_t client_lock; /* protects client_list */
struct mutex mutex;
struct device dev;
struct cdev cdev;
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;
bool use_wake_lock;
char name[28];
struct fasync_struct *fasync;
struct evdev *evdev;
struct list_head node;
int clkid;
bool revoked;
unsigned int bufsize;
struct input_event buffer[];
};