以gsensor器件为例:
1、Gsensor
上报ABS_ DISTANCE
后,接着上报sync
事件,当event core
检测到sync
事件时,认为一包event
数据完成【参考下文代码得出】。
static void XXX_pls_report_dps(unsigned char data, struct input_dev *input)
{
……
input_report_abs(input, ABS_DISTANCE, dps_data);
input_sync(input);
}
**2、 input_report_abs
被转化为 input_event + EV_ABS
事件形式上报:
input_sync
被转化为 input_event + EV_SYN
事件形式上报**
input_report_abs(input, ABS_DISTANCE, dps_data) ----> input_event(dev, EV_ABS, code, value)
input_sync(input) ----->input_event(dev, EV_SYN, SYN_REPORT, 0)
3、input_event
函数解析
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)) {
//首先会判断该输入设备是否支持给type类型的事件;如果设备要支持某种类型的事件,需要在设备注册前使用__set_bit(EV_type, input_dev->evbit)
函数设置input_dev
支持EV_type
类型事件。
`spin_lock_irqsave(&dev->event_lock, flags);`
// 中断保护自旋锁,保护一次input event事件上报完成后,下一次获取到中断保护自旋锁事件才可被处理。如果没有获取到自旋锁,则线程一直在此等待完成。
input_handle_event(dev, type, code, value);
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
4、 input_handle_event(dev, type, code, value);
static void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
int disposition;
disposition = input_get_disposition(dev, type, code, value);
//判断事件的处理方式,注意观察disposition 变量的使用;此函数稍后分析。
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
dev->event(dev, type, code, value);
if (!dev->vals)
return;
if (disposition & INPUT_PASS_TO_HANDLERS) {
//如果事件允许进入后续的handler 处理,则先将事件加入到设备事件数组中(dev->vals)
struct input_value *v;
if (disposition & INPUT_SLOT) {
// `INPUT_SLOT` 多点输入设备,如`Touchpanel`。
v = &dev->vals[dev->num_vals++];
v->type = EV_ABS;
v->code = ABS_MT_SLOT;
v->value = dev->mt->slot;
}
v = &dev->vals[dev->num_vals++];
v->type = type;
v->code = code;
v->value = value;
}
if (disposition & INPUT_FLUSH) {
// INPUT_FLUSH
标志设备输入事件发送dev->vals
数组将被下次事件覆盖
f (dev->num_vals >= 2)
input_pass_values(dev, dev->vals, dev->num_vals);
// 重点handler
后续处理
dev->num_vals = 0;
} else if (dev->num_vals >= dev->max_vals - 2) {
dev->vals[dev->num_vals++] = input_value_sync;
input_pass_values(dev, dev->vals, dev->num_vals);
dev->num_vals = 0;
}
}
5、 input_get_disposition(dev, type, code, value)重要函数,判定事件的处理方式。
static int input_get_disposition(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
int disposition = INPUT_IGNORE_EVENT;
switch (type) {
……..
case EV_ABS:
if (is_event_supported(code, dev->absbit, ABS_MAX))
//判断设备是否支持ABS
输入事件;如设备要支持,需要在注册输入设备前调用 input_set_capability(input_dev, EV_ABS, ABS_DISTANCE)
【表示设备支持ABS_DISTANCE(code)
的EV_ABS (type)
事件 】
`disposition = input_handle_abs_event(dev, code, &value);`
//此函数会根据输入事件的code值及 absinfo[code].value
(设备abs原始值)判定对于此次事件的处理方式,注意如果:初始化的absinfo[code].value
值与设备初次上包的值一致,则设备第一次的上报事件将被忽略。
break;
……
return disposition;
}
6、input_pass_values(dev, dev->vals, dev->num_vals) —> input_to_handler(handle, vals, count) —-> handler->events(handle, vals, count)—> evdev_events(handle,input_value, count) —>evdev_pass_values(evdev_client, input_value, count,ktime_t , ktime_t)
input_to_handler( )
函数首先调用handler->filter
函数对上报的事件进行过滤,可以客制化此函数来过滤需要忽略的事件。之后调用handler->events
函数对过滤后的事件进行处理。handler->events
会调用evdev_events
函数。
evdev_events()
函数在evdev.c文件中,它调用evdev_pass_values
函数。evdev_pass_values
函数进行两步重要处理:首先将事件按发送顺序放入evdev_client->buffer
中(环形buf);之后如果事件type=EV_SYN,code=SYN_REPORT
,则有可能执行两种动作: 1、调用kill_fasync向指定的fasync_struct
进程发送SIGIO信号【该进程属于用户进程,及应用层进程】;2、使用wake_up_interruptible
函数唤醒以阻塞方式获取输入事件进程。在执行这两种动作的同时会将evdev_client->buffer
中的client->packet_head
包头重新指向buffer的头部。自此input event
在kernel
中上报的流程进行完毕。接下来分析用户层是怎样从kenerl
层获取input event
事件的。
7、 上层获取input event
事件的方式可以查看getevent
命令(system/ core/toolbox)
Getevent命令实现中以非阻塞的方式打开input设备,然后以poll的方式获取input设备状态;每次poll结束时会对poll的返回状态进行分析,返回有POLLIN状态时会调用read函数获取设备的input event事件。
应用层的poll函数会间接的调用kernel层的evdev_poll函数,evdev_poll函数中当 client->packet_head 包头不等 client->tail 时返回POLLIN状态;从getevent进入读取设备状态环节,应用层的read 函数回调调用到设备层的evdev_read函数,evdev_read函数会将kernel层的inpet event数据copy到用户空间;如果getevent是以阻塞方式打开input设备的话,evdev_read函数中读取完输入事件后需要等待evdev->wait事件被唤醒后才可能返回。
8、 补充自动repeat事件配
Repeat事件是指相同key事件的多次上报,在input device注册过程中会进行repeat事件相关的timer、回调函数、延时启动时间、启动周期等设置。当key事件按下的时程序中自动启动repeat 事件监测timer,无论哪个key事件被释放则此timer被终止。当timer超时后会调input_repeat_key此函数首先会再次发送 repeat_key 和 syn 事件,注意repeat_key 的value值为2、sync事件的value为1,与通常的键值不同此值表示为repeat;随后重新启动repeat timer。