Input event 分析

以gsensor器件为例:

1、Gsensor上报ABS_ DISTANCE后,接着上报sync事件,当event core 检测到sync事件时,认为一包event数据完成【参考下文代码得出】。

    static void XXX_pls_report_dps(unsigned char data, struct input_dev *input)

{   
         ……
         input_report_abs(input, ABS_DISTANCE, dps_data);
         input_sync(input);
}

**2、 input_report_abs 被转化为 input_event + EV_ABS 事件形式上报:
input_sync被转化为 input_event + EV_SYN 事件形式上报**

input_report_abs(input, ABS_DISTANCE, dps_data) ---->input_event(dev, EV_ABS, code, value)
input_sync(input) ----->input_event(dev, EV_SYN, SYN_REPORT, 0)

3、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)) {

//首先会判断该输入设备是否支持给type类型的事件;如果设备要支持某种类型的事件,需要在设备注册前使用__set_bit(EV_type, input_dev->evbit)函数设置input_dev支持EV_type类型事件。

       `spin_lock_irqsave(&dev->event_lock, flags);` 

// 中断保护自旋锁,保护一次input event事件上报完成后,下一次获取到中断保护自旋锁事件才可被处理。如果没有获取到自旋锁,则线程一直在此等待完成。

           input_handle_event(dev, type, code, value);
           spin_unlock_irqrestore(&dev->event_lock, flags);
        }
}

4、 input_handle_event(dev, type, code, value);

static void input_handle_event(struct input_dev *dev,
                   unsigned int type, unsigned int code, int value)
{
    int disposition;

    disposition = input_get_disposition(dev, type, code, value);

//判断事件的处理方式,注意观察disposition 变量的使用;此函数稍后分析。

if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
        dev->event(dev, type, code, value);

    if (!dev->vals)
        return;

    if (disposition & INPUT_PASS_TO_HANDLERS) {

//如果事件允许进入后续的handler 处理,则先将事件加入到设备事件数组中(dev->vals)

    struct input_value *v;

        if (disposition & INPUT_SLOT) { 
   // `INPUT_SLOT` 多点输入设备,如`Touchpanel`。            
            v = &dev->vals[dev->num_vals++];
            v->type = EV_ABS;
            v->code = ABS_MT_SLOT;
            v->value = dev->mt->slot;
        }

        v = &dev->vals[dev->num_vals++];
        v->type = type;
        v->code = code;
        v->value = value;
    }
    if (disposition & INPUT_FLUSH) {

// INPUT_FLUSH 标志设备输入事件发送dev->vals 数组将被下次事件覆盖

f (dev->num_vals >= 2)
            input_pass_values(dev, dev->vals, dev->num_vals);  

// 重点handler后续处理

dev->num_vals = 0;
    } else if (dev->num_vals >= dev->max_vals - 2) {
        dev->vals[dev->num_vals++] = input_value_sync;
        input_pass_values(dev, dev->vals, dev->num_vals);
        dev->num_vals = 0;
    }

}

5、 input_get_disposition(dev, type, code, value)重要函数,判定事件的处理方式。

static int input_get_disposition(struct input_dev *dev,
              unsigned int type, unsigned int code, int value)
{
    int disposition = INPUT_IGNORE_EVENT;

    switch (type) {

       ……..
    case EV_ABS:
        if (is_event_supported(code, dev->absbit, ABS_MAX)) 

//判断设备是否支持ABS输入事件;如设备要支持,需要在注册输入设备前调用 input_set_capability(input_dev, EV_ABS, ABS_DISTANCE)【表示设备支持ABS_DISTANCE(code)EV_ABS (type)事件 】

    `disposition = input_handle_abs_event(dev, code, &value);`

//此函数会根据输入事件的code值及 absinfo[code].value(设备abs原始值)判定对于此次事件的处理方式,注意如果:初始化的absinfo[code].value 值与设备初次上包的值一致,则设备第一次的上报事件将被忽略。

        break;
       ……
    return disposition;
}

6、input_pass_values(dev, dev->vals, dev->num_vals) —> input_to_handler(handle, vals, count) —-> handler->events(handle, vals, count)—> evdev_events(handle,input_value, count) —>evdev_pass_values(evdev_client, input_value, count,ktime_t , ktime_t)

input_to_handler( )函数首先调用handler->filter函数对上报的事件进行过滤,可以客制化此函数来过滤需要忽略的事件。之后调用handler->events 函数对过滤后的事件进行处理。handler->events 会调用evdev_events 函数。

evdev_events()函数在evdev.c文件中,它调用evdev_pass_values函数。evdev_pass_values函数进行两步重要处理:首先将事件按发送顺序放入evdev_client->buffer中(环形buf);之后如果事件type=EV_SYN,code=SYN_REPORT,则有可能执行两种动作: 1、调用kill_fasync向指定的fasync_struct进程发送SIGIO信号【该进程属于用户进程,及应用层进程】;2、使用wake_up_interruptible函数唤醒以阻塞方式获取输入事件进程。在执行这两种动作的同时会将evdev_client->buffer中的client->packet_head包头重新指向buffer的头部。自此input eventkernel中上报的流程进行完毕。接下来分析用户层是怎样从kenerl层获取input event事件的。

7、 上层获取input event 事件的方式可以查看getevent 命令(system/ core/toolbox)

Getevent命令实现中以非阻塞的方式打开input设备,然后以poll的方式获取input设备状态;每次poll结束时会对poll的返回状态进行分析,返回有POLLIN状态时会调用read函数获取设备的input event事件。

应用层的poll函数会间接的调用kernel层的evdev_poll函数,evdev_poll函数中当 client->packet_head 包头不等 client->tail 时返回POLLIN状态;从getevent进入读取设备状态环节,应用层的read 函数回调调用到设备层的evdev_read函数,evdev_read函数会将kernel层的inpet event数据copy到用户空间;如果getevent是以阻塞方式打开input设备的话,evdev_read函数中读取完输入事件后需要等待evdev->wait事件被唤醒后才可能返回。

8、 补充自动repeat事件配

Repeat事件是指相同key事件的多次上报,在input device注册过程中会进行repeat事件相关的timer、回调函数、延时启动时间、启动周期等设置。当key事件按下的时程序中自动启动repeat 事件监测timer,无论哪个key事件被释放则此timer被终止。当timer超时后会调input_repeat_key此函数首先会再次发送 repeat_key 和 syn 事件,注意repeat_key 的value值为2、sync事件的value为1,与通常的键值不同此值表示为repeat;随后重新启动repeat timer。

猜你喜欢

转载自blog.csdn.net/hello_yj/article/details/45058099
今日推荐