linux input子系统代码阅读简单记录

    技术2022-05-19  19

    网上可以找到很多关于linux输入子系统的分析和代码导读,这些文章看的再多,都只是别人的总结,自己始终都是需要看源代码的。对代码的理解,想长时间的记住,是不现实的,干脆把阅读分析时的顺序记录下来,如果以后再次看这部分的代码,参照这个阅读顺序,应该回忆的也会快一些。

     

    1. /linux-2.6.38/include/linux/input.h 和 /linux-2.6.38/drivers/input/input.c 文件

     

    1.1 核心的3个结构,struct input_dev,struct input_handler,struct input_handle,用面向对象的思路来看,这3个是核心的父类。

     

    struct input_handler结构对应字符设备,换句话说,在用户空间,当使用 /dev/input/event0 等设备文件的时候,对应的内核代码入口点,就是由struct input_handler实现。

     

    struct input_dev结构是对具体的硬件设备的抽象,通常都会处理中断程序,把用户的输入传递到struct input_handler。

     

    struct input_handle结构的功能,是把struct input_dev连接到struct input_handler上,可以在看代码的过程中逐步体会。

     

    1.2 这3个核心父类的主要api接口

    struct input_dev *input_allocate_device(void);

    void input_free_device(struct input_dev *dev);

     

    int __must_check input_register_device(struct input_dev *);

    void input_unregister_device(struct input_dev *);

     

    void input_reset_device(struct input_dev *);

     

    int __must_check input_register_handler(struct input_handler *);

    void input_unregister_handler(struct input_handler *);

     

    int input_handler_for_each_handle(struct input_handler *, void *data,

     int (*fn)(struct input_handle *, void *));

     

    int input_register_handle(struct input_handle *);

    void input_unregister_handle(struct input_handle *);

     

    int input_grab_device(struct input_handle *);

    void input_release_device(struct input_handle *);

     

    int input_open_device(struct input_handle *);

    void input_close_device(struct input_handle *);

     

    int input_flush_device(struct input_handle *handle, struct file *file);

     

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

    void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value);

     

    1.3 在input子系统中,有两个全局性的链表,static LIST_HEAD(input_dev_list); 和 static LIST_HEAD(input_handler_list);

     

    1.3.1 void input_reset_device(struct input_dev *)函数就是把一个input_dev添加到input_dev_list链表上,同时,还会在input_handler_list链表中找到和这个input_dev相匹配的struct input_handler,并且把相匹配的input_dev和input_handler 连接(connect)起来(通过input_handle建立连接关系)。当连接上之后,input_dev上发生的中断事件,就可以传递到input_handler,进而传递到用户空间。

     

    1.3.2 int __must_check input_register_handler(struct input_handler *)函数就是把一个struct input_handler添加到input_handler_list链表上,同时,会从input_dev_list中找出所有的可以和它匹配的input_dev,并且把相匹配的input_dev和input_handler 连接(connect)起来(通过input_handle建立连接关系)。当连接上之后,input_dev上发生的中断事件,就可以传递到input_handler,进而传递到用户空间。

     

    1.3.3 前面提到的“并且把他们connect起来",是由struct input_handler的一个api函数来实现的,函数原型为int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);用面向对象的思路来看,这是一个虚函数,需要由struct input_handler的每一个子类来具体实现。

     

    2. /linux-2.6.38/drivers/input/evdev.c 文件 (或者是/linux-2.6.38/drivers/input/mousedev.c,鼠标类设备对应的input_handler)

     

    evdev.c中,实现了一个struct input_handler的子类,代码片段如下:

    static struct input_handler evdev_handler = {

    .event = evdev_event,

    .connect = evdev_connect,

    .disconnect = evdev_disconnect,

    .fops = &evdev_fops,

    .minor = EVDEV_MINOR_BASE,

    .name = "evdev",

    .id_table = evdev_ids,

    };

     

    还实现了struct input_handle的子类,代码片段如下:

    struct evdev {

    int open;

    int minor;

    struct input_handle handle;

    wait_queue_head_t wait;

    struct evdev_client __rcu *grab;

    struct list_head client_list;

    spinlock_t client_lock; /* protects client_list */

    struct mutex mutex;

    struct device dev;

    bool exist;

    };

    每当有一个struct input_dev 被connect到evdev_handler上的时候,都会构造一个evdev,将这个input_dev和evdev_handler连接上。

     

    每当有一个用户空间程序使用到这个struct input_dev的时候,都会构造一个struct evdev_client并且添加到evdev->client_list链表上,这样做的目的是让多个用户进程共享同一个输入设备,每个进程都会得到同样的一份数据。

     

    3. /linux-2.6.38/drivers/input/keyboard/gpio_keys.c 和 /linux-2.6.38/arch/x86/platform/mrst/mrst.c 文件。(或者/linux-2.6.38/drivers/input/touchscreen/intel-mid-touch.c文件)

     

    在gpio_keys.c中,实现了struct input_dev的子类,代码片段如下:

    struct gpio_keys_drvdata {

    struct input_dev *input;

    struct mutex disable_lock;

    unsigned int n_buttons;

    int (*enable)(struct device *dev);

    void (*disable)(struct device *dev);

    struct gpio_button_data data[0];

    };

     

    mrst.c文件中则是定义了相关的硬件资源。

     

    在gpio_keys.c的gpio_keys_probe(struct platform_device *pdev)函数中,会调用input_register_device函数进行注册。

     

    4. 开发驱动程序的时候,针对一个具体的输入设备,通常都仅仅是继承struct input_dev,并用input_register_device进行注册。内核程序中,已经实现了好几个struct input_handler的子类(类似前面2中的介绍),一般都不需要修改,也不需要扩充。

     


    最新回复(0)