@zifehng
2017-05-26T13:44:26.000000Z
字数 3559
阅读 1668
kernel
input
之前在写驱动时使用如下方式上报一次EV_LED类型事件,使用getevent命令测试却一直接收不到事件。
input_event(input_dev, EV_LED, LED_MISC, 1);
input_sync(input_dev);
因为赶工无法深究原因,只能先参考普通按键上报方式(在上报抬起、按下两个事件后再上报同步事件)试着修改,结果上层收到了事件,测试通过。
input_event(input_dev, EV_LED, LED_MISC, 0);
input_event(input_dev, EV_LED, LED_MISC, 1);
input_sync(input_dev);
事后我猜想event事件是被过滤掉了:
1. 被getevent命令过滤;
2. 被内核input子系统过滤。
对于第一种猜想,我自己采用最简单的阻塞式读取方法,实现了一个C程序去轮询设备节点,却依然无法获取event事件,再结合getevent源码分析,可以排除getevnt命令过滤的可能性;
剩下的可能就是input子系统本身过滤了event事件,于是我从事件上报的入口函数input_event()分析,将事件上报流程梳理了一遍,希望从中找出答案。
代码分析流程:
input_event() -> input_handle_event() -> input_get_disposition()
-> input_pass_values()
首先从入口函数input_event()开始分析:
void input_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
unsigned long flags;
/* 检测设备evbit位图是否支持事件总类型 */
if (is_event_supported(type, dev->evbit, EV_MAX)) {
spin_lock_irqsave(&dev->event_lock, flags);
/* 处理event事件 */
input_handle_event(dev, type, code, value);
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
input_event()接口参数列表:
参数 | 描述 |
---|---|
dev | 上报事件的设备 |
type | 事件总类型 |
code | 事件子类型 |
value | 事件值 |
经过设备evbit位图判断后,event事件被传递至input_handle_event()函数进一步处理:
static void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
int disposition;
/* 获取event事件的描述符 */
disposition = input_get_disposition(dev, type, code, value);
/* 如果描述符包含“INPUT_PASS_TO_DEVICE”,调用设备自定义接口处理event事件 */
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
dev->event(dev, type, code, value);
if (!dev->vals)
return;
/* 如果描述符包含“INPUT_PASS_TO_HANDLERS”,event事件继续走通用上报流程 */
if (disposition & INPUT_PASS_TO_HANDLERS) {
struct input_value *v;
if (disposition & INPUT_SLOT) {
v = &dev->vals[dev->num_vals++];
v->type = EV_ABS;
v->code = ABS_MT_SLOT;
v->value = dev->mt->slot;
}
/* 缓存event事件 */
v = &dev->vals[dev->num_vals++];
v->type = type;
v->code = code;
v->value = value;
}
/* 如果描述符包含“INPUT_FLUSH”,刷新设备缓冲区,上报之前缓存的event事件 */
if (disposition & INPUT_FLUSH) {
if (dev->num_vals >= 2)
/* 上报event事件 */
input_pass_values(dev, dev->vals, dev->num_vals);
dev->num_vals = 0;
/* 如果缓存的event事件超过上限,也进行上报处理 */
} else if (dev->num_vals >= dev->max_vals - 2) {
dev->vals[dev->num_vals++] = input_value_sync;
/* 上报event事件 */
input_pass_values(dev, dev->vals, dev->num_vals);
dev->num_vals = 0;
}
}
描述符宏定义:
描述符宏定义 | 值 | 作用 |
---|---|---|
INPUT_IGNORE_EVENT | 0 | 忽略该事件 |
INPUT_PASS_TO_HANDLERS | 1 | 事件由handler处理 |
INPUT_PASS_TO_DEVICE | 2 | 事件由设备处理 |
INPUT_SLOT | 4 | 多点触摸事件标记 |
INPUT_FLUSH | 8 | 刷新设备的事件缓冲区 |
INPUT_PASS_TO_ALL | (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) | 事件由handler与设备同时处理 |
在input_handle_event()函数里,描述符disposition决定了event事件的后续处理流程,很有可能是因为描述符的原因,event事件被过滤不做任何处理,接下来我们分析input_get_disposition()函数,看看描述符是怎么生成的:
static int input_get_disposition(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
/* 描述符默认值为“INPUT_IGNORE_EVENT” */
int disposition = INPUT_IGNORE_EVENT;
/* 根据event事件的总类型决定描述符 */
switch (type) {
......
/* 同步事件 */
case EV_SYN:
switch (code) {
case SYN_CONFIG:
disposition = INPUT_PASS_TO_ALL;
break;
case SYN_REPORT:
disposition = INPUT_PASS_TO_HANDLERS | INPUT_FLUSH;
break;
case SYN_MT_REPORT:
disposition = INPUT_PASS_TO_HANDLERS;
break;
}
break;
/* EV_LED事件 */
case EV_LED:
/* 判断ledbit位图与led位图 */
if (is_event_supported(code, dev->ledbit, LED_MAX) &&
!!test_bit(code, dev->led) != !!value) {
/* 对led位图中LED_MISC事件的位值进行反置 */
__change_bit(code, dev->led);
disposition = INPUT_PASS_TO_ALL;
}
break;
/* 其他事件 */
......
}
return disposition;
}
在处理EV_LED事件时,可以看到必须满足两个条件才能获得描述符“INPUT_PASS_TO
_ALL”:
第一个条件的结果毫无疑问为“true”,我们重点分析第二个条件:
!!test_bit(code, dev->led)
读取led位图位置,__change_bit(code, dev->led)
反置led位图位置,这两个相呼应的操作要求:在一次上报事件的周期内,EV_LED事件的“value”布尔值必须经过“true”和“false”的变化才能获取到描述符“INPUT_PASS_TO_ALL”,否则事件将被过滤不做任何处理。