没有合适的资源?快使用搜索试试~ 我知道了~
如图 7.1:(1) 硬件驱动层负责操作具体的硬件设备,这层的代码是针对具体的驱动程序的,比如你的设备是触摸输入设备,还是鼠标输入设备,还是键盘输入设备,这些不
资源详情
资源评论
资源推荐
http://blog.csdn.net/alan445947767/article/details/41047757
Linux Input 子系统
什么是 Linux Input 子系统呢?顾名思义,就是输入子系统。这不是废话吗?说了等于没说。
换句话说,Linux 系统下把键盘、鼠标、触摸屏、游戏句柄等等设备都当做是输入设备。作为
一个输入设备,好处可大了。因为 Linux 输入子系统已经帮输入设备完成很大一部分通用的
处理功能了。就比如说,以前我们写字符设备驱动时的读写函数,这些都不用驱动工程师去编
写了,输入子系统已经帮我们写好了。这种思想,在 Linux 内核多了去呢!
Input 子系统层次框架
输入(Input)子系统是分层架构的,总共分为 3 层,从上到下分别是:事件处理层(Event
Handler)、输入子系统核心层(Input Core)、硬件驱动层(Input Driver)。如图 7.1:
(1) 硬件驱动层负责操作具体的硬件设备,这层的代码是针对具体的驱动程序的,比如你
的设备是触摸输入设备,还是鼠标输入设备,还是键盘输入设备,这些不同的设备,自然有不同
的硬件操作,驱动工程师往往只需要完成这层的代码编写。
(2) 输入子系统核心层是链接其他两层之间的纽带与桥梁,向下提供硬件驱动层的接口,
向上提供事件处理层的接口。
(3) 事件处理厂负责与用户程序打交道,将硬件驱动层传来的事件报告给用户程序。
各层之间通信的基本单位就是事件,任何一个输入设备的动作都可以抽象成一种事件,如
键盘的按下,触摸屏的按下,鼠标的移动等。事件有三种属性:类型(type),编码(code),值
(value),Input 子系统支持的所有事件都定义在 input.h 中,包括所有支持的类型,所属类型支
持的编码等。事件传送的方向是 硬件驱动层-->子系统核心-->事件处理层-->用户空间。
三个重要的结构体
输入设备(input_dev)
Linux 系统里,使用 input_dev 结构体抽象一个输入设备,编写硬件驱动就是主要围绕这
个结构体而进行的。由于它的成员比较多,这里只挑最重点的讲解。其他成员请参考
include/linux/input.h
struct input_dev {
const char *name;
/* 标识设备驱动特征,如总线类型、生产厂商、产品类型、版本 */
struct input_id id;
/* 表示能产生哪类事件 */
unsigned long evbit[NBITS(EV_MAX)];
/* 表示能产生哪些按键 */
unsigned long keybit[NBITS(KEY_MAX)];
/* 表示能产生哪些相对位移事件, x,y,滚轮 */
unsigned long relbit[NBITS(REL_MAX)];
/* 表示能产生哪些绝对位移事件, x,y */
unsigned long absbit[NBITS(ABS_MAX)];
struct device dev;
/* 用来链接他所支持的 input_handle 结构,然后用
* input_handle 找到里面的 input_handler
*/
struct list_head h_list;
/* 链接到 input_handler_list,这个链表
* 链接了所有注册到内核的事件处理器
*/
struct list_head node;
...
}
input_dev 结构体里有几个数组也是非常重要的,都是我们写硬件驱动需要进行设置的,
所以我们务必认识一下它们。
(1) evbit[BITS_TO_LONGS(EV_CNT)]数组,这个数组以位掩码的形式,代表了这个设备支持
哪类事件,比如:
#define EV_SYN 0x00 //同步类
#define EV_KEY 0x01 //按键类
#define EV_REL 0x02 //相对位移类
#define EV_ABS 0x03 //绝对位移类
#define EV_MSC 0x04
#define EV_SW 0x05
#define EV_LED 0x11
#define EV_SND 0x12
#define EV_REP 0x14 //重复类
#define EV_FF 0x15
#define EV_PWR 0x16
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
#define EV_CNT (EV_MAX+1)
(2) keybit[BITS_TO_LONGS(KEY_CNT)]数组,这个数组也是以位掩码的形式,代表这个设备
支持哪些按键,比如:
#define KEY_ESC 1
#define KEY_1 2
#define KEY_2 3
#define KEY_3 4
#define KEY_TAB 15
#define KEY_ENTER 28
#define KEY_A 30
#define KEY_B 48
#define KEY_C 46
......
(3) relbit[BITS_TO_LONGS(REL_CNT)]数组,这个数组也是以位掩码的形式,代表这个设备支
持哪些相对位移事件,比如:
#define REL_X 0x00
#define REL_Y 0x01
#define REL_Z 0x02
#define REL_WHEEL 0x08 //滚轮
......
(4) absbit[BITS_TO_LONGS(ABS_CNT)]数组,这个数组也是以位掩码的形式,代表这个设备
支持哪些绝对位移事件,比如:
#define ABS_X 0x00
#define ABS_Y 0x01
事件处理器(input_handler)
input_handler 属于输入子系统三层中的事件处理层的一个重要结构体。主要成员有:其
他成员请参考 include/linux/input.h
struct input_handler {
/* 当事件处理器接收到了来自 input 设备传来的
* 事件时调用的处理函数,负责处理事件。
*/
void (*event)(struct input_handle *handle,unsigned int type, unsigned int code, int
value);
/* 当一个 input 设备注册到内核的时候被调用,将事件处理器与输入设备
* 联系起来的函数,也就是将 input_dev 和 input_handler 配对的函数。
*/
int (*connect)(struct input_handler *handler, struct input_dev *dev,const struct
input_device_id *id);
/* 与 connect 相反 */
void (*disconnect)(struct input_handle *handle);
/* 文件操作集,因为事件处理器要完成读写功能 */
const struct file_operations *fops;
/* 事件处理器所支持的 input 设备 */
const struct input_device_id *id_table;
/* 链接他所支持的 input_handle 结构,然后用
* input_handle 找到里面的 input_dev
*/
struct list_head h_list;
/* 链接到 input_handler_list,这个链表
* 链接了所有注册到内核的事件处理器
*/
struct list_head node;
};
事件沟通者(input_handle)
之所以称 input_handle(注意了,不是事件处理器 input_handler)为事件沟通者,是因为它
代 表 一 个 成 功 配 对 的 input_dev 和 input_handler 。 主 要 成 员 有 : 其 他 成 员 请 参 考
include/linux/input.h
struct input_handle {
/* 每个配对的事件处理器都会分配一个对应的设备结构,
* 如 evdev 事件处理器的 evdev 结构,注意这个结构与
* 设备驱动层的 input_dev 不同,初始化 handle 时,保存到这里。
*/
void *private;
/* 指向 input_dev 结构体实例 */
struct input_dev *dev;
/* 指向 input_handler 结构体实例 */
struct input_handler *handler;
/* input_handle 通过 d_node 连接到了 input_dev 上的 h_list 链表上 */
struct list_head d_node;
/* input_handle 通过 h_node 连接到了 input_handler 的 h_list 链表 */
struct list_head h_node;
};
三个结构体之间的关系
input_dev 是硬件驱动层,代表一个 input 设备。通过全局的 input_dev_list 链接在一起。设备注
册的时候实现这个操作。
input_handler 是事件处理层,代表一个事件处理器。通过全局的 input_handler_list 链接在一起。
事件处理器注册的时候实现这个操作(事件处理器一般内核自带,一般不需要我们来写)
input_handle 个人认为属于核心层,代表一个配对的 input 设备与 input 事件处理器。它没有一
个全局的链表,它注册的时候将自己分别挂在了 input_dev 和 input_handler 的 h_list 上了。通过
input_dev 和 input_handler 就可以找到 input_handle 在设备注册和事件处理器, 注册的时候都要进
行配对工作,配对后就会实现链接。通过 input_handle 也可以找到 input_dev 和 input_handler。
Input 子系统核心层分析
前面我们说过,子系统核心的功能是:向下提供硬件驱动层的接口,向上提供事件处理层
的接口。子系统的核心文件在 drivers/input/input.c,这文件代码量有 2000+行,我们也不可能
每一个函数都去分析一遍,只把重点抓出来。前面讲的三个重要的数据结构都会对应一个注
册函数,他们都定义在子系统核心的 input.c 文件中。
主要有三个注册函数:
/* 向内核注册一个 input 设备 */
int input_register_device(struct input_dev *dev)
/* 向内核注册一个事件处理器 */
int input_register_handler(struct input_handler *handler)
/* 向内核注册一个 handle 结构 */
int input_register_handle(struct input_handle *handle)
剩余26页未读,继续阅读
药罐子也有未来
- 粉丝: 16
- 资源: 300
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0