原文地址:
应用控制硬件设备与硬件事件传递给应用:
驱动层传递数据或事件到应用层可通过sk_buff广播出去,广播完之后就成了应用层对某一类事件的处理内核已完成无需关心(netlink);应用层传递数据到驱动层进而控制硬件设备一般往/dev或/sys目录下读写内容即可。
输入设备总类繁杂,包括按键,键盘,触摸屏,鼠标,摇杆等等,它们本身都是字符设备,不过内核为了能将这些设备的共性抽象出来,简化驱动的开发,建立了一个Input子系统。Input子系统分为三层,从下至上分别是输入设备驱动层,输入核心层以及输入事件驱动层。这三层中的输入核心层和输入事件驱动层都是内核已经完成了的,因此需要我们完成的只有输入设备驱动层。考虑输入设备主要的工作过程都是 动作产生(按键,触屏……)-->产生中断-->读取数值(键值,坐标……)-->将数值传递给应用程序。最后一个步骤就属于事件的处理,对于同一类设备,他们的处理方式都是相同的,因此内核已在事件驱动层为我们做好了,不需我们操心,而产生中断-->读取数值是因设备而异的,需要我们根据具体的设备来编写驱动。一个大致的工作流程就是,input device向上层报告-->input core接收报告,并根据在注册input device时建立好的连接选择哪一类handler来处理事件-->通过handler将数据存放在相应的dev(evdev,mousedev…)实例的缓冲区中,等待应用程序来读取。当然,有时候也需要从应用层向设备层逆向传递,比如控制一些和设备相关的LED,蜂鸣器等。设备驱动层,输入核心层和事件处理层之间的关系可以用下图来阐释:
下面来看看Input子系统的关键数据结构
-
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 (*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;
-
-
spinlock_t event_lock;
-
struct mutex mutex;
-
-
unsigned int users;
-
int going_away;
-
-
struct device dev;
-
-
struct list_head h_list;
-
struct list_head node;
-
};
-
struct input_handler {
-
-
void *private;
-
-
-
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
-
-
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;
-
const struct input_device_id *blacklist;
-
-
struct list_head h_list;
-
struct list_head node;
-
};
-
struct input_handle {
-
-
void *private;
-
-
int open;
-
const char *name;
-
-
struct input_dev *dev;
-
struct input_handler *handler;
-
-
struct list_head d_node;
-
struct list_head h_node;
-
};
我们可以看到,input_device和input_handler中都有一个h_list,而input_handle拥有指向input_dev和input_handler的指针,也就是说input_handle是用来关联input_dev和input_handler的,那么为什么一个input_device和input_handler
中拥有的是h_list而不是一个handle呢?因为一个device可能对应多个handler,而一个handler也不能只处理一个device,比如说一个鼠标,它可以对应even handler,也可以对应mouse handler,因此当其注册时与系统中的handler进行匹配,就有可能产生两个实例,一个是evdev,另一个是mousedev,而任何一个实例中都只有一个handle。至于以何种方式来传递事件,就由用户程序打开哪个实例来决定。后面一个情况很容易理解,一个事件驱动不能只为一个甚至一种设备服务,系统中可能有多种设备都能使用这类handler,比如event handler就可以匹配所有的设备。在input子系统中,有8种事件驱动,每种事件驱动最多可以对应32个设备,因此dev实例总数最多可以达到256个。下一节将以even handler为例介绍设备注册以及打开的过程。
阅读(906) | 评论(0) | 转发(0) |