Linux输入子系统事件报告传递机制
上一节我们分析了输入设备如何与handler连接的过程,当两者连接上后,剩下的工作就是如何报告事件即事件报告如何传递, 输入子系统设备报告各种事件通过
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);
{
input_event(dev, EV_KEY, code, !!value);
//将按键的value转化为布尔类型的值。所以按键传给input core的value是0(释放)或者1(按下)
}
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_report_ff_status(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_FF_STATUS, code, value);
}
static inline void input_report_switch(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_SW, 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_report_ff_status(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_FF_STATUS, code, value);
}
static inline void input_report_switch(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_SW, code, !!value);
}
static inline void input_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
}
static inline void input_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
}
上面几个函数都是调用了input_event()函数,下面就让我们看看input_event的实现
/**
* input_event() - report new input event
* @dev: device that generated the event
* @type: type of the event
* @code: event code
* @value: value of the event
*
* This function should be used by drivers implementing various input
* devices to report input events. See also input_inject_event().
*
* NOTE: input_event() may be safely used right after input device was
* allocated with input_allocate_device(), even before it is registered
* with input_register_device(), but the event will not reach any of the
* input handlers. Such early invocation of input_event() may be used
* to 'seed' initial state of a switch or initial position of absolute
* axis, etc.
*/
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_event() - report new input event
* @dev: device that generated the event
* @type: type of the event
* @code: event code
* @value: value of the event
*
* This function should be used by drivers implementing various input
* devices to report input events. See also input_inject_event().
*
* NOTE: input_event() may be safely used right after input device was
* allocated with input_allocate_device(), even before it is registered
* with input_register_device(), but the event will not reach any of the
* input handlers. Such early invocation of input_event() may be used
* to 'seed' initial state of a switch or initial position of absolute
* axis, etc.
*/
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
#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_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_ABS:
if (is_event_supported(code, dev->absbit, ABS_MAX))
disposition = input_handle_abs_event(dev, code, &value);
break;
case EV_REL:
if (is_event_supported(code, dev->relbit, REL_MAX) && value)
disposition = INPUT_PASS_TO_HANDLERS;
break;
}
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
dev->sync = false;
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_handle_event分发事件有两个方向:驱动的回调函数dev->event和input core的input_pass_event。
接着看看input_pass_event实现,
/*
* Pass event first through all filters and then, if event has not been
* filtered out, through all open handles. This function is called with
* dev->event_lock held and interrupts disabled.
*/
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct input_handler *handler;
struct input_handle *handle;
rcu_read_lock();
handle = rcu_dereference(dev->grab); //获取独占设备的handle的指针。如果有独占设备的handle,则仅仅将事件传给独占的handle对应的handler
if (handle)
handle->handler->event(handle, type, code, value);//这里直接调用了handler事件驱动对应的XX_event函数,这个XX_event函数把事件数据包传递给了handler,当应用程序使用XX_read时就可以读取到这些数据包。
else {
bool filtered = false;
list_for_each_entry_rcu(handle, &dev->h_list, d_node) { //遍历与此设备连接的每一个handle
if (!handle->open) //如果hnadle已经被打开
continue;
handler = handle->handler;
if (!handler->filter) {
if (filtered)
break;
handler->event(handle, type, code, value); //将事件分发给handler的事件处理函数
} else if (handler->filter(handle, type, code, value))
filtered = true;
}
}
rcu_read_unlock();
}
* Pass event first through all filters and then, if event has not been
* filtered out, through all open handles. This function is called with
* dev->event_lock held and interrupts disabled.
*/
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct input_handler *handler;
struct input_handle *handle;
rcu_read_lock();
handle = rcu_dereference(dev->grab); //获取独占设备的handle的指针。如果有独占设备的handle,则仅仅将事件传给独占的handle对应的handler
if (handle)
handle->handler->event(handle, type, code, value);//这里直接调用了handler事件驱动对应的XX_event函数,这个XX_event函数把事件数据包传递给了handler,当应用程序使用XX_read时就可以读取到这些数据包。
else {
bool filtered = false;
list_for_each_entry_rcu(handle, &dev->h_list, d_node) { //遍历与此设备连接的每一个handle
if (!handle->open) //如果hnadle已经被打开
continue;
handler = handle->handler;
if (!handler->filter) {
if (filtered)
break;
handler->event(handle, type, code, value); //将事件分发给handler的事件处理函数
} else if (handler->filter(handle, type, code, value))
filtered = true;
}
}
rcu_read_unlock();
}
到这里,input core分发事件的任务已经完成,接下来由各个handler处理接收到的事件,也就是事件处理驱动。