zoukankan      html  css  js  c++  java
  • 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
Copyright © 2011-2022 走看看