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

来源:互联网 发布:三菱plc编程视频教程 编辑:程序博客网 时间:2024/05/26 02:55

网上可以找到很多关于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中的介绍),一般都不需要修改,也不需要扩充。

 

原创粉丝点击