输入子系统
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1 输入子系统架构Overview
输入子系统(Input Subsyst em)的架构如下图所示
输入子系统由输入子系统核心层( Input Core ),驱动层和事件处理层(Event Handler)三部份组成。一个输入事件,如鼠标移动,键盘按键按下,joystick的移动等等通过 Driver -> Input Core -> Eventhandler -> userspac e 的顺序到达用户空间传给应用程序。
其中Input Core 即 Input Layer 由 driver/input/input.c及相关头文件实现。对下提供了设备驱动的接口,对上提供了Event Handler层的编程接口。
1.1 主要数据结构
表 1Input Subsystem main data struct ure
1.2 输入子系统架构示例图
图2 输入子系统架构示例图
2 输入链路的创建过程
由于input子系统通过分层将一个输入设备的输入过程分隔为独立的两部份:驱动到Input Core,Input Core到Event Handler。所以整个链路的这两部分的接口的创建是独立的。
2.1 硬件设备的注册
驱动层负责和底层的硬件设备打交道,将底层硬件对用户输入的响应转换为标准的输入事件以后再向上发送给Input Core。
驱动层通过调用Input_register_device函数和Input_unregist er_device函数来向输入子系统中注册和注销输入设备。
这两个函数调用的参数是一个Input_dev结构,这个结构在driver/input/input.h中定义。驱动层在调用Input_regist er_device之前需要填充该结构中的部分字段
#include
#include
#include
MODULE_LICENSE("GPL");
struct input_dev ex1_dev;
static int __init ex1_init(void)
{
/* extra safe initialization */
memset(&ex1_dev, 0, sizeof(st ruct input_dev));
init_input_dev(&ex1_dev);
/* set up descriptive labels */
ex1_ = "Example 1 device";
/* phys is unique on a running system */
ex1_dev.phys = "A/Fake/Path";
ex1_dev.id.bust ype = BUS_HOST;
ex1_dev.id.vendor = 0x0001;
ex1_dev.id.product = 0x0001;
ex1_dev.id.version = 0x0100;
/* this device has two keys (A and B) */
set_bit(EV_KEY, ex1_dev.evbit);
set_bit(KEY_B, ex1_dev.keybit);
set_bit(KEY_A, ex1_dev.keybit);
/* and finally regist er with the input core */
input_register_device(&ex1_dev);
return 0;
}
其中比较重要的是evbit字段用来定义该输入设备可以支持的(产生和响应)的事件的类型。
包括:
Ø EV_RST 0x00 Reset
Ø EV_KEY 0x01 按键
Ø EV_REL 0x02 相对坐标
Ø EV_ABS 0x03 绝对坐标
Ø EV_MSC 0x04 其它
Ø EV_LED 0x11 LED
Ø EV_SND 0x12 声音
Ø EV_REP 0x14 Repeat
Ø EV_FF 0x15 力反馈
一个设备可以支持一个或多个事件类型。每个事件类型下面还需要设置具体的触发事件,比如EV_KEY事件,支持哪些按键等。
2.2 Event Handler层
2.2.1 注册Input Handler
驱动层只是把输入设备注册到输入子系统中,在驱动层的代码中本身并不创建设备结点。应用程序用来与设备打交道的设备结点的创建由Event Handler层调用Input core中的函数来实现。而在创建具体的设备节点之前,Event Handle r层需要先注册一类设备的输入事件处理函数及相关接口
以MouseDev Handler为例:
static struct input_handler mousedev_handler = {
event: mousedev_event,
connect: mousedev_connect,
disconnect: mousedev_disconnect,
fops: &mousedev_fops,
minor: MOUSEDEV_MINOR_BASE,
};
static int __init mousedev_init(void)
{
input_regist er_handler(&mousedev_handler);
memset(&mousedev_mix, 0, sizeof(struct mousedev));z
init_waitqueue_head(&mousedev_mix.wait);
mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
mousedev_mix.exist = 1;
mousedev_mix.minor = MOUSEDEV_MIX;
mousedev_mix.devfs = input_regist er_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE);
printk(KERN_INF O "mice: PS/2 mouse device common for all mice\n");
return 0;
}
在Mousedev_init中调用input.c中定义的input_regist er_handler来注册一个鼠标类型的Handler. 这里的Ha ndler不是具体的用户可以操作的设备,而是鼠标类设备的统一的处理函数接口。
2.2.2 设备节点的创建
接下来,mousedev_init函数调用input_register_minor注册一个通用mice设备,这才是与用户相关联的具体的设备接口。然而这里在init函数中创建一个通用的Mice设备只是鼠标类Event Handler层的特例。在其它类型的Eve ntHandler层中,并不一定会创建一个通用的设备。
标准的流程见是硬件驱动向Input子系统注册一个硬件设备后,在input_regist er_device中调用已经注册的所有类型的Input Handler的connect函数,每一个具体的Connect函数会根据注册设备所支持的事件类型判断是否与自己相关,如果相关就调用input_regist er_minor创建一个具体的设备节点。
void input_register_device(st ruct input_dev *dev)
{
……
while (handler) {
if ((handle = handler->connect(handler, dev)))
input_link_handle(handle);
handler = handler->next;
}
}
此外如果已经注册了一些硬件设备,此后再注册一类新的Input Handler,则同样会对所有已注册的Device调用新的Input Handler的Connect函数已确定是否需要创建新的设备节点: