输入子系统设备通告各种事件通过input_report_XXX族函数
/* include/linux/input.h */
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_KEY, code, !!value);
}
static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_REL, code, value);
}
static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_ABS, code, value);
}
static inline void input_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
}
可以看到,这四个函数都调用了input_event。这些API 其实都是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)) {
spin_lock_irqsave(&dev->event_lock, flags);
add_input_randomness(type, code, value);//由于输入事件具有随机性,因此用输入事件来增加内核熵池的熵
input_handle_event(dev, type, code, value);//调用事件分发函数input_handle_event,做进一步的传递
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
首先,先判断设备产生的这个事件是否合法.如果合法,流程转入到input_handle_event()中.
/* driver/input/input.c */
#define INPUT_IGNORE_EVENT 0
#define INPUT_PASS_TO_HANDLERS 1
#define INPUT_PASS_TO_DEVICE 2
#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
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_SYN:
switch (code) {
case SYN_CONFIG:
disposition = INPUT_PASS_TO_ALL;
break;
case SYN_REPORT:
if (!dev->sync) {
dev->sync = 1;
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case SYN_MT_REPORT:
dev->sync = 0;
disposition = INPUT_PASS_TO_HANDLERS;
break;
}
break;
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);
}
disposition = INPUT_PASS_TO_HANDLERS;//标记消息传递方向
}
break;
case EV_SW:
if (is_event_supported(code, dev->swbit, SW_MAX) &&
!!test_bit(code, dev->sw) != value) {
__change_bit(code, dev->sw);
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case EV_ABS:
if (is_event_supported(code, dev->absbit, ABS_MAX)) {//检查绝对坐标轴是否驱动所支持的
if (test_bit(code, input_abs_bypass)) {
disposition = INPUT_PASS_TO_HANDLERS;
break;
}
value = input_defuzz_abs_event(value,
dev->abs[code], dev->absfuzz[code]);//根据当前报告的值和上次报告的值确定传给处理程序的绝对值大小
if (dev->abs[code] != value) {//如果本次需要报告的绝对值和上次不同,则将事件传递给处理函数
dev->abs[code] = value;
disposition = INPUT_PASS_TO_HANDLERS;
}
}
break;
case EV_REL:
if (is_event_supported(code, dev->relbit, REL_MAX) && value)//检查相对坐标轴是否被驱动所支持
disposition = INPUT_PASS_TO_HANDLERS;
break;
case EV_MSC:
if (is_event_supported(code, dev->mscbit, MSC_MAX))
disposition = INPUT_PASS_TO_ALL;
break;
case EV_LED:
if (is_event_supported(code, dev->ledbit, LED_MAX) &&
!!test_bit(code, dev->led) != value) {
__change_bit(code, dev->led);
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_SND:
if (is_event_supported(code, dev->sndbit, SND_MAX)) {
if (!!test_bit(code, dev->snd) != !!value)
__change_bit(code, dev->snd);
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_REP:
if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
dev->rep[code] = value;
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_FF:
if (value >= 0)
disposition = INPUT_PASS_TO_ALL;
break;
case EV_PWR:
disposition = INPUT_PASS_TO_ALL;
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);
}
在这里,我们忽略掉具体事件的处理.到最后,如果该事件需要input device 来完成的,就会将disposition 设置成INPUT_PASS_TO_DEVICE.如果需要handler 来完成的,就将dispostion 设为INPUT_PASS_TO_HANDLERS.如果需要两者都参与,将disposition 设置为INPUT_PASS_TO_ALL.需要输入设备参与的,回调设备的event 函数.如果需要handler 参与的.调用input_pass_event()
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct input_handle *handle;
rcu_read_lock();
handle = rcu_dereference(dev->grab);//获取独占设备的handle的指针
if (handle)
handle->handler->event(handle, type, code, value);//如果有独占设备的handle,则仅仅将事件传给独占的handle对应的handler
else
list_for_each_entry_rcu(handle, &dev->h_list, d_node)//遍历与此设备连接的每一个handle
if (handle->open)//如果handle已经打开
handle->handler->event(handle,
type, code, value);//将事件分发给handler的事件处理函数
rcu_read_unlock();
}
如果input device 被强制指定了handler,则调用该handler 的event 函数.结合handle 注册的分析.我们知道.会将handle 挂到input device 的h_list 链表上.如果没有为input device 强制指定handler.就会遍历input device->h_list 上的handle 成员.如果该handle 被打开,则调用与输入设备对应的handler 的event()函数.注意,只有在handle 被打开的情况下才会接收到事件.另外,输入设备的handler 强制设置一般是用带EVIOCGRAB 标志的ioctl 来完成的.如下是发图的方示总结evnet 的处理过程: