linux kernel input event处理流程

linux kernel input event处理流程

input驱动会调用input_register_device()来注册device到input framework;

input设备驱动接收到时间输入事件时(接收的方式一般是硬件interrupt),会call input_event()上报给input framework;

input framework然后会将此input event callback给向它注册了handler的人,注册handler的API为input_register_handler(),然后handler再处理此input event。

1. 向input framework注册input device/input_register_device()

drivers/input/misc/hisi_powerkey.c

static int hi65xx_powerkey_probe(struct platform_device *pdev)
{
    struct device *dev = &pdev->dev;
    struct input_dev *input;
    int irq, i, error;

    input = devm_input_allocate_device(dev);
    if (!input) {
        dev_err(dev, "failed to allocate input device
");
        return -ENOMEM;
    }

    input->phys = "hisi_on/input0";
    input->name = "HISI 65xx PowerOn Key";

    input_set_capability(input, EV_KEY, KEY_POWER);
    input_set_capability(input, EV_KEY, KEY_RESTART);

    for (i = 0; i < ARRAY_SIZE(hi65xx_irq_info); i++) {

        irq = platform_get_irq_byname(pdev, hi65xx_irq_info[i].name);
        if (irq < 0)
            return irq;

        error = devm_request_any_context_irq(dev, irq,
                             hi65xx_irq_info[i].handler,
                             IRQF_ONESHOT,
                             hi65xx_irq_info[i].name,
                             input);
        if (error < 0) {
            dev_err(dev, "couldn't request irq %s: %d
",
                hi65xx_irq_info[i].name, error);
            return error;
        }
    }

    error = input_register_device(input);
    if (error) {
        dev_err(dev, "failed to register input device: %d
", error);
        return error;
    }

    device_init_wakeup(dev, 1);

    return 0;
}

2. 向input framework上报input event

static irqreturn_t hi65xx_power_press_isr(int irq, void *q)
{
    struct input_dev *input = q;

    pm_wakeup_event(input->dev.parent, MAX_HELD_TIME);
    input_report_key(input, KEY_POWER, 1);
    input_sync(input);

    return IRQ_HANDLED;
}

static irqreturn_t hi65xx_power_release_isr(int irq, void *q)
{
    struct input_dev *input = q;

    pm_wakeup_event(input->dev.parent, MAX_HELD_TIME);
    input_report_key(input, KEY_POWER, 0);
    input_sync(input);

    return IRQ_HANDLED;
}

static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)

对于按键input event,input_report_key()参数value的值含义如下:

0: release
1: press
2: repeat

通过input_report_key()上报input event,input framework并不会马上处理此input event,而是将这些event收集在一个数组里,等input device driver call了input_sync()时才会将这些收集起来的event一起callback给handler。

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

    /* filter-out events from inhibited devices */
    if (dev->inhibited)
        return;

    disposition = input_get_disposition(dev, type, code, &value);
    if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
        add_input_randomness(type, code, value);

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

    if (!dev->vals)
        return;

    if (disposition & INPUT_PASS_TO_HANDLERS) {
        struct input_value *v;

        if (disposition & INPUT_SLOT) { //一般是触摸屏类输入设备
            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_sync()时将会有INPUT_FLUSH flag,调用input_pass_values()将收集到的event一起发给handler处理
        if (dev->num_vals >= 2)
            input_pass_values(dev, dev->vals, dev->num_vals);
        dev->num_vals = 0;
        /*
         * Reset the timestamp on flush so we won't end up
         * with a stale one. Note we only need to reset the
         * monolithic one as we use its presence when deciding
         * whether to generate a synthetic timestamp.
         */
        dev->timestamp[INPUT_CLK_MONO] = ktime_set(0, 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;
    }

}

void input_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)

input_event()参数解析:

1. type,即event type,它可能的type列举如下。比如如果是key event,则type为EV_KEY;执行input_sync()时,type为EV_SYN;

include/uapi/linux/input-event-codes.h

/*
 * Event types
 */

#define EV_SYN            0x00
#define EV_KEY            0x01
#define EV_REL            0x02
#define EV_ABS            0x03
#define EV_MSC            0x04
#define EV_SW            0x05
#define EV_LED            0x11
#define EV_SND            0x12
#define EV_REP            0x14
#define EV_FF            0x15
#define EV_PWR            0x16
#define EV_FF_STATUS        0x17
#define EV_MAX            0x1f
#define EV_CNT            (EV_MAX+1)

2. code,比如type为key event时,code为key code,比如按下power key时,此时key code为0x74(power key code为0x74)

key event code值的定义都在include/uapi/linux/input-event-codes.h

3. value,比如为key event时,它的取值含义如下:

0: release

1: press
2: repeat

三、执行handler callback function

注册handler

drivers/input/mousedev.c

static int __init mousedev_init(void)
{
    int error;

    mousedev_mix = mousedev_create(NULL, &mousedev_handler, true);
    if (IS_ERR(mousedev_mix))
        return PTR_ERR(mousedev_mix);

    error = input_register_handler(&mousedev_handler);
    if (error) {
        mousedev_destroy(mousedev_mix);
        return error;
    }

    mousedev_psaux_register();

    pr_info("PS/2 mouse device common for all mice
");

    return 0;
}

在input_register_device()时,input framework会遍历input_handler_list链表,调用input_attach_handler(),此函数会调用input_match_device(),此函数根据handler里的id_table来match input device driver,如果match,则attach handler成功:

static const struct input_device_id mousedev_ids[] = {
    {
        .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
                INPUT_DEVICE_ID_MATCH_KEYBIT |
                INPUT_DEVICE_ID_MATCH_RELBIT,
        .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) },
        .keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) },
        .relbit = { BIT_MASK(REL_X) | BIT_MASK(REL_Y) },
    },    /* A mouse like device, at least one button,
           two relative axes */
    {
        .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
                INPUT_DEVICE_ID_MATCH_RELBIT,
        .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) },
        .relbit = { BIT_MASK(REL_WHEEL) },
    },    /* A separate scrollwheel */
    {
        .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
                INPUT_DEVICE_ID_MATCH_KEYBIT |
                INPUT_DEVICE_ID_MATCH_ABSBIT,
        .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
        .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
        .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
    },    /* A tablet like device, at least touch detection,
           two absolute axes */
    {
        .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
                INPUT_DEVICE_ID_MATCH_KEYBIT |
                INPUT_DEVICE_ID_MATCH_ABSBIT,
        .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
        .keybit = { [BIT_WORD(BTN_TOOL_FINGER)] =
                BIT_MASK(BTN_TOOL_FINGER) },
        .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
                BIT_MASK(ABS_PRESSURE) |
                BIT_MASK(ABS_TOOL_WIDTH) },
    },    /* A touchpad */
    {
        .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
            INPUT_DEVICE_ID_MATCH_KEYBIT |
            INPUT_DEVICE_ID_MATCH_ABSBIT,
        .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
        .keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) },
        .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
    },    /* Mouse-like device with absolute X and Y but ordinary
           clicks, like hp ILO2 High Performance mouse */

    { },    /* Terminating entry */
};

MODULE_DEVICE_TABLE(input, mousedev_ids);

static struct input_handler mousedev_handler = {
    .event        = mousedev_event,
    .connect    = mousedev_connect,
    .disconnect    = mousedev_disconnect,
    .legacy_minors    = true,
    .minor        = MOUSEDEV_MINOR_BASE,
    .name        = "mousedev",
    .id_table    = mousedev_ids,
};

一个实例input event上报处理flow如下:

[ 530.761427] xxx_event_handler+0x64/0xdc [xxx]
[ 530.765795] input_to_handler+0x178/0x1d8
[ 530.769810] input_pass_values+0x164/0x17c
[ 530.773910] input_handle_event+0x8b8/0xb34
[ 530.778099] input_event+0x94/0xf8
 
 
在命令行下执行getevent可以获取当前有哪些input device注册到了系统:

console:/ # getevent
could not get driver version for /dev/input/mice, Not a typewriter
add device 1: /dev/input/event0
name: "xxx KEYPAD"
add device 2: /dev/input/event1
name: "xxx IR Receiver"

 
getevent -l
//按下IR RIGHT key,然后松开:

/dev/input/event1: EV_MSC MSC_SCAN 00807f1a
/dev/input/event1: EV_KEY KEY_RIGHT DOWN
/dev/input/event1: EV_SYN SYN_REPORT 00000000
/dev/input/event1: EV_KEY KEY_RIGHT UP
/dev/input/event1: EV_SYN SYN_REPORT 00000000

 
 
 
 
 
 
原文地址:https://www.cnblogs.com/aspirs/p/15259896.html