转自:http://blog.csdn.net/colorant/archive/2007/04/12/1561837.aspx
1 输入子系统架构Overview
输入子系统(Input Subsystem)的架构如下图所示
输入子系统由 输入子系统核心层( Input Core ),驱动层和事件处理层(Event Handler)三部份组成。一个输入事件,如鼠标移动,键盘按键按下,joystick的移动等等通过 Driver -> InputCore -> Eventhandler -> userspace 的顺序到达用户空间传给应用程序。
其中Input Core 即 Input Layer 由 driver/input/input.c及相关头文件实现。对下提供了设备驱动的接口,对上提供了Event Handler层的编程接口。
1.1 主要数据结构
表 1 Input Subsystem main data structure
数据结构
|
用途
|
定义位置
|
具体数据结构的分配和初始化
|
Struct input_dev
|
驱动层物理Input设备的基本数据结构
|
Input.h
|
通常在具体的设备驱动中分配和填充具体的设备结构
|
Struct Evdev
Struct Mousedev
Struct Keybdev…
|
Event Handler层逻辑Input设备的数据结构
|
Evdev.c
Mousedev.c
Keybdev.c
|
Evdev.c/Mouedev.c …中分配
|
Struct Input_handler
|
Event Handler的结构
|
Input.h
|
Event Handler层,定义一个具体的Event Handler。
|
Struct Input_handle
|
用来创建驱动层Dev和Handler链表的链表项结构
|
Input.h
|
Event Handler层中分配,包含在Evdev/Mousedev…中。
|
1.2 输入子系统架构示例图
图2 输入子系统架构示例图
2 输入链路的创建过程
由于input子系统通过分层将一个输入设备的输入过程分隔为独立的两部份:驱动到Input Core,Input Core到Event Handler。所以整个链路的这两部分的接口的创建是独立的。
2.1 硬件设备的注册
驱动层负责和底层的硬件设备打交道,将底层硬件对用户输入的响应转换为标准的输入事件以后再向上发送给Input Core。
驱动层通过调用Input_register_device函数和Input_unregister_device函数来向输入子系统中注册和注销输入设备。
这两个函数调用的参数是一个Input_dev结构,这个结构在driver/input/input.h中定义。驱动层在调用Input_register_device之前需要填充该结构中的部分字段
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
struct input_dev ex1_dev;
static int __init ex1_init(void)
{
/* extra safe initialization */
memset(&ex1_dev, 0, sizeof(struct input_dev));
init_input_dev(&ex1_dev);
/* set up descriptive labels */
ex1_dev.name = "Example 1 device";
/* phys is unique on a running system */
ex1_dev.phys = "A/Fake/Path";
ex1_dev.id.bustype = 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 register 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 Handler层需要先注册一类设备的输入事件处理函数及相关接口
以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_register_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_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE);
printk(KERN_INFO "mice: PS/2 mouse device common for all mice/n");
return 0;
}
在Mousedev_init中调用input.c中定义的input_register_handler来注册一个鼠标类型的Handler. 这里的Handler不是具体的用户可以操作的设备,而是鼠标类设备的统一的处理函数接口。
2.2.2 设备节点的创建
接下来,mousedev_init函数调用input_register_minor注册一个通用mice设备,这才是与用户相关联的具体的设备接口。 然而这里在init函数中创建一个通用的Mice设备只是鼠标类Event Handler层的特例。在其它类型的EventHandler层中,并不一定会创建一个通用的设备。
标准的流程见是硬件驱动向Input子系统注册一个硬件设备后,在input_register_device中调用已经注册的所有类型的Input Handler的connect函数,每一个具体的Connect函数会根据注册设备所支持的事件类型判断是否与自己相关,如果相关就调用 input_register_minor创建一个具体的设备节点。
void input_register_device(struct input_dev *dev)
{
……
while (handler) {
if ((handle = handler->connect(handler, dev)))
input_link_handle(handle);
handler = handler->next;
}
}
此外如果已经注册了一些硬件设备,此后再注册一类新的Input Handler,则同样会对所有已注册的Device调用新的Input Handler的Connect函数已确定是否需要创建新的设备节点:
void input_register_handler(struct input_handler *handler)
{
……
while (dev) {
if ((handle = handler->connect(handler, dev)))
input_link_handle(handle);
dev = dev->next;
}
}
从上面的分析中可以看到一类Input Handler可以和多个硬件设备相关联,创建多个设备节点。而一个设备也可能与多个Input Handler相关联,创建多个设备节点。
直观起见,物理设备,Input Handler,逻辑设备之间的多对多关系可见下图:
图3 物理设备,Input Handler,逻辑设备关系图
3 设备的打开和读写
用户程序通过Input Handler层创建的设备节点的Open,read,write等函数打开和读写输入设备。
3.1 Open
设备节点的Open函数,首先会调用一类具体的Input Handler的Open函数,处理一些和该类型设备相关的通用事务,比如初始化事件缓冲区等。然后通过Input.c中的 input_open_device函数调用驱动层中具体硬件设备的Open函数。
3.2 Read
大多数Input Handler的Read函数等待在Event Layer层逻辑设备的wait队列上。当设备驱动程序通过调用Input_event函数将输入以事件的形式通知给输入子系统的时候,相关的Input Handler的event函数被调用,该event函数填充事件缓冲区后将等待队列唤醒。
在驱动层中,读取设备输入的一种可能的实现机制是扫描输入的函数睡眠在驱动设备的等待队列上,在设备驱动的中断函数中唤醒等待队列,而后扫描输入函数将设备输入包装成事件的形式通知给输入子系统。
3.3 Write
2.4内核中没有固定的模式,根据具体的Input Handler,可能不实现,也可能通过调用Input_event将写入的数据以事件的形式再次通知给输入子系统,或者调用设备驱动的Write函数等等。
2.6内核的代码中,通过调用Input_event将写入的数据以事件的形式再次通知给输入子系统,而后在Input.c中根据事件的类型,将需要反馈给物理设备的事件通过调用物理设备的Event函数传给设备驱动处理,如EV_LED事件:
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
......
case EV_LED:
if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
return;
change_bit(code, dev->led);
if (dev->event) dev->event(dev, type, code, value);
break;
......
}
4 其它
本文中对Input子系统架构的分析主要是基于2.4.20内核,在2.6内核中对Input子系统做了很大的扩充增加了对许多设备的支持(如触摸屏,键盘等)。不过整体的框架还是一致的。
另,参考了linux journal上的两篇文章:
The Linux USB Input Subsystem, Part I | Linux Journal
Using the Input Subsystem, Part II | Linux Journal
分享到:
相关推荐
Linux输入子系统的流程结构图,给你一个对于Linux下的输入子系统一个清晰地认识。
evdev 该软件包提供了对Linux中通用输入事件接口的绑定。 evdev接口用于将内核中生成的事件... Uinput允许用户空间程序创建和处理可将事件直接注入输入子系统的输入设备。 说明文件: 发展: 包裹: 变更日志:
戈朗·埃夫杰夫该软件包将Go语言绑定提供给Linux中的通用输入事件接口。 evdev接口用于将内核中生成的事件通过通常位于/ dev / input /中的字符设备直接传递到用户空间。 说明文件: 发展:
python库。资源全名:evdev-0.3.3.tar.gz
用于 Raspberry Pi GPIO 的基于中断的 evdev 输入驱动程序 这是用于 Raspberry Pi 单板计算机的 Linux 内核模块,它通过通用输入事件接口 (evdev) 在 GPIO 输入引脚上公开边缘检测事件。 建造 这些步骤假设您正在...
lua-evdev:Lua模块,用于从devinputeventXX节点读取Linux输入事件
资源分类:Python库 所属语言:Python 资源全名:evdev_prepared-0.2.3.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
The Xorg Evdev Driver package contains Generic Linux input driver for the Xorg X server. It handles keyboard, mouse, touchpads and wacom devices, though for touchpad and wacom advanced handling, ...
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,亲测可用
官方离线安装包,亲测可用
扫描仪 关于 这是一款基于和现成条码扫描器的个人购物和库存跟踪设备,可以选择共享和贡献产品条码的(POD) 数据库,作为一部分项目。...用于golang-evdev 的Github 用户gvalkov ,这在 Go 中实现input_event 结构证
官方离线安装包,亲测可用
Vigilem::Evdev::Stat 确定evdev是否在这个系统上的状态安装 $ gem install vigilem-evdev-stat用法 require 'vigilem/evdev/stat' Vigilem :: Evdev :: Stat . default . available?
资源来自pypi官网。 资源全名:evdev_prepared-0.2.2.tar.gz
Liquid Galaxy Interactive Spaces 活动,可创建虚拟 evdev 输入设备并从路线合成输入事件。 版权所有 (C) 2015 Google Inc. 版权所有 (C) 2015 End Point Corporation 根据 Apache 许可,版本 2.0(“许可”)...
活动,从 evdev 输入设备读取事件并发布到路线。 版权所有 (C) 2015 Google Inc. 版权所有 (C) 2015 End Point Corporation 根据 Apache 许可,版本 2.0(“许可”)获得许可; 除非遵守许可,否则您不得使用此文件...
Liquid Galaxy Interactive Spaces 活动,用于分离和聚合不同类型的输入事件。 版权所有 (C) 2015 Google Inc. 版权所有 (C) 2015 End Point Corporation 根据 Apache 许可,版本 2.0(“许可”)获得许可; 除非...
EvDev:功能齐全的Dockerized开发环境
xorg-server xf86-input-evdev xf86-video-fbdev xf86-video-modesetting xf86-video-ati 从源代码构建guix guix environment guix cd ~/guix ./bootstrap && ./configure --localstatedir=/var --with-libgcrypt-...