Linux下的Input子系统(一)

版权所有,转载请说明转自 http://my.csdn.net/weiqing1981127

一.系统理论

1.1 Input子系统概述

Input子系统是对不同类型的输入设备进行统一处理的驱动程序。一个输入事件,如按键,是通过驱动层到系统核心层到事件处理层到用户空间的顺序到达用户空间并传给应用程序使用。

Input子系统由驱动层、输入子系统核心层和事件处理层三部分组成。此子系统主要包括两类驱动程序:事件驱动程序和设备驱动程序。事件驱动程序负责和应用程序的接口,而设备驱动程序负责和底层输入设备的通信。输入事件驱动程序包括mousedevevdevjoydev,键盘等。事件驱动程序是标准的,对所有的输入设备都是可用的,所以要实现的是设备驱动程序而不是事件驱动程序,设备驱动程序可用利用一个已经存在的、合适的事件驱动程序通过输入核心和用户应用程序接口。事件驱动程序和设备驱动程序都可以利用输入核心层为之服务。

我想先从宏观上介绍下输入子系统的构造和联系,然后根据自己编写的基于Mini2440的添加了Input子系统的按键设备驱动实例和应用层测试程序实例,分析整个Input系统如何从驱动层到系统核心层到事件处理层到用户空间来完成工作的。

1.2 Input子系统几个重要数据结构

输入子系统主要涉及input_devinput_handlerinput_handle等数据结构。其中input_dev是物理输入设备的基本数据结构,包括设备相关的一些信息。 input_handler是事件处理结构体,定义怎么处理事件的逻辑。input_handle是用来创建input_devinput_handler之间关系的结构体。

首先让我们了解下input_devinput_handlerinput_handle之间的关系吧。

struct input_handle {

void *private; //表示handler的特定数据

int open; //表示handle是否正在被使用

const char *name; //handle

struct input_dev *dev; //handle相连的input_dev

struct input_handler *handler; //handle相连的input_handler

struct list_head d_node; //handle结构体的该节点将与input_dev相连

struct list_head h_node; //handle结构体的该节点将与input_handler相连

};

struct input_dev {

const char *name;

const char *phys;

const char *uniq;

struct input_id id;

unsigned long evbit[BITS_TO_LONGS(EV_CNT)];

unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];

unsigned long relbit[BITS_TO_LONGS(REL_CNT)];

unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];

unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];

unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];

unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];

unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];

unsigned long swbit[BITS_TO_LONGS(SW_CNT)];

unsigned int keycodemax;

unsigned int keycodesize;

void *keycode;

int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);

int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);

struct ff_device *ff;

unsigned int repeat_key;

struct timer_list timer;

int sync;

int abs[ABS_MAX + 1];

int rep[REP_MAX + 1];

unsigned long key[BITS_TO_LONGS(KEY_CNT)];

unsigned long led[BITS_TO_LONGS(LED_CNT)];

unsigned long snd[BITS_TO_LONGS(SND_CNT)];

unsigned long sw[BITS_TO_LONGS(SW_CNT)];

int absmax[ABS_MAX + 1];

int absmin[ABS_MAX + 1];

int absfuzz[ABS_MAX + 1];

int absflat[ABS_MAX + 1];

int absres[ABS_MAX + 1];

int (*open)(struct input_dev *dev);

void (*close)(struct input_dev *dev);

int (*flush)(struct input_dev *dev, struct file *file);

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

struct input_handle *grab; //grab是强制为input devicehandler

spinlock_t event_lock;

struct mutex mutex;

unsigned int users;

bool going_away;

struct device dev;

struct list_head h_list; //handled_node就是挂在input_dev这里的h_list;

struct list_head node; //挂在input_dev本身的链表input_dev_list

};

struct input_handler {

void *private;

//event函数是向子系统报告后内核最终需要调用的函数

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

//connect函数是input_devinput_handler相匹配的函数

int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);

void (*disconnect)(struct input_handle *handle);

void (*start)(struct input_handle *handle);

const struct file_operations *fops; //操作函数

int minor;

const char *name;

const struct input_device_id *id_table; //handler支持项

const struct input_device_id *blacklist; //handler不支持项

struct list_head h_list; /handleh_node就是挂在input_handler这里的h_list;

struct list_head node; //挂在input_handler本身的链表input_handler_list

};

总结下input_devinput_handlerinput_handle三者的关系吧。总共其实有四个链表,第一个链表就是input_dev本身的链表input_dev_list,该链表上挂接了所有的input_dev,主要通过input_dev->node挂接在input_dev_list上。第二个链表是input_handler本身的链表input_handler_list,该链表上挂接了所有的input_handler,主要通过input_handler->node挂接在input_handler_list上。第三个链表是input_devinput_handle之间的链表,主要是通过input_handle->d_node挂在input_dev-> h_list链表上实现。第四个链表是input_handlerinput_handle之间的链表,主要是通过input_handle->h_node挂在input_handler-> h_list链表上实现。

好了,我们再了解下input_devinput_handlerinput_handle分别在什么时候被创建的吧。

input_dev是在设备驱动层初始化函数中通过分配input_dev空间然后调用input_register_device注册进内核的。input_handle是在事件驱动层初始化函数中通过调用input_register_handler注册进内核的。那么input_handle什么时候被注册进内核的呢?这个问题的答案有两个情况。其一,当注册input_dev时,系统会在input_handler_list寻找匹配的input_handler,如果找到了就调用input_handler->evdev_connect函数中的input_register_handle函数完成input_handle注册,并将这个input_handle与相应的input_devinput_handler相连。其二,当注册input_handler时,系统会在input_dev_list寻找匹配的input_dev,如果找到了就调用input_handler->evdev_connect函数中的input_register_handle函数完成input_handle注册,并将这个input_handle与相应的input_devinput_handler相连。

1.3 Input子系统核心层和事件处理层函数概述

接着让我们先了解下核心层和事件驱动层几个比较重要的函数。

Input核心层input.c中主要我们需要关注的函数是input_event input_allocate_device input_open_device input_register_device input_register_handler input_register_handleinput_open_file

Input事件驱动层Evdev.c主要是input_handler中定义的函数evdev_eventevdev_connect,包括file_operations

你可能感兴趣的:(Linux下的Input子系统(一))