在分析1里,我们看到了input_dev、input_handler以及input_handle三者之间的联系和实现的原理。下面我们看下具体event事件的处理流程。我们的driver中一般是使用input_report_key()来上报事件,然后再以input_sync()来结束这次的上报事件。input_report_key()里使用的是input_event()来完成这步的操作,关于input_event(),
先是判断本次事件是否被支持,若支持的话则调用input_handle_event(),input_handle_event()里面主要就是匹配传过来的事件类型及按键类型,然后针对不同的类型选择合适的处理方式。最后我们根据具体需要处理的类型进行处理。若需要输入设备参与的,我们回调设备的event(),即dev->event(dev,type,code,value),若需要handler处理的,我们使用input_pass_event(dev,type,code,value)。关于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);
-
if (handle)
-
handle->handler->event(handle, type, code, value);
-
else
-
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
-
if (handle->open)
-
handle->handler->event(handle,type, code, value);
-
rcu_read_unlock();
-
}
这段代码我们仔细看看,它根据获得的handle值进行执行,这里grab的类型是input_handle,若具体的handle已存在则直接调用handler的event,否则遍历整个input_dev的h_list上的handle成员,如果handle被打开,则调用与输入设备相对应的handler的event。
input_pass_event()中最后会调用handler的event(),handler中绑定了具体的connect()的终极执行者为evdev_event(),所以最终将跳转到evdev_event()执行,再然后根据具体判断跳转到evdev_pass_event(),看看此函数都做了些什么:
-
static void evdev_pass_event(struct evdev_client *client,struct input_event *event)
-
{
-
-
spin_lock(&client->buffer_lock);
-
-
client->buffer[client->head++] = *event;
-
-
client->head &= EVDEV_BUFFER_SIZE - 1;
-
spin_unlock(&client->buffer_lock);
-
-
kill_fasync(&client->fasync, SIGIO, POLL_IN);
-
}
我们可以清楚的看到,具体的事件被存放在buffer中,而将head加1操作,这里的加1预示报告事件的操作完成,至此一个事件就完成了,返回调用的系统中(一般是一个中断的完成),根据head值,知道hend!=tail了,直接唤醒等待队列进行操作。这里的操作就是具体的我们定义的input_handler中的fops,此fops的类型为file_operations,它里面提供了evdev_read,供我们的app来read。至此事件处理告一段落。上面是input子系统重要的一些实现code,下面再从上至下做一个宏观的总结。
阅读(454) | 评论(0) | 转发(0) |