Linux输入子系统分析(三)

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);
            //将按键的value转化为布尔类型的值。所以按键传给input corevalue0(释放)或者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_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_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->eventinput coreinput_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();
}
到这里,input core分发事件的任务已经完成,接下来由各个handler处理接收到的事件,也就是事件处理驱动。
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值