输入子系统
常见的输入设备:
- keyboard 键盘
- mouse 鼠标
- touchcreen 触摸屏
- joystick 游戏杆
实现步骤简析
共同点:
- 驱动层:设备号的注册申请、创建设备节点、硬件初始化(以及其他有关硬件初始化)、实现fop、阻塞、用户交互的接口函数read、write等。
- 应用层:通过文件io接口和指定的接收缓冲区格式(struct input_event)对设备模块.ko文件进行读写,输入设备节点均位于/dev/input目录下,里面记录了输入设备具体信息,也可用cat对设备文件输出信息进行监控。
差异化:硬件操作的初始化步骤不同
内核驱动框架分层思想
- input handler 数据处理层:当匹配成功后核心管理层转到处理层调用connect方法,创建设备结点,注册字符设备并完成fop:实现用户交互的方法,将数据封装为input_event交给用户,用户用指定格式接收:数据来源于input device层。
- input core 核心管理层:维护两条链表,一条记录处理层一条记录设备层,当两者之一注册加入链表时,会遍历另一条链表进行匹配,若成功则申请注册统一输入设备的主设备号13(次设备号不同),注册类,将各设备层中的设备与对应设备数据处理层的方法通过链表联系起来,作为数据传输的中间层。
- input device 设备层:抽象出一个对象,描述输入设备信息,初始化输入设备硬件、获取到硬件数据,根据需求对事件进行上报,input event方法。
其中,我们只需要对输入设备层进编写,数据处理和核心管理层均在内核已完成实现。
源码文件在目录linux/drivers/input下。
例如:evdev.c —按键对应的数据处理层、mousedev.c—鼠标对应的数据处理层、joydev.c—鼠标杆对应的数据处理层;
核心层为 input.c文件
对于内核生成的部分,是通过Make menuconfig中由用户进行配置编译的。
菜单中:
Generic input layer (needed for keyboard, mouse, …) //核心层
Mouse interface//数据处理层
驱动框架
对于输入设备层,我们在设备树文件exynos4412-itop-elite.dts中增加一个表示按键的输入设备节点。
key_int_node{
compatible = "test_key";
interrupt-parent = <&gpx1>;//继承于gpx1
interrupts = <2 0>;//中断号为2, 0表示不指定触发方式
};
在驱动中获取设备树某一结点的所有孩子结点信息:
//获取到设备树中的结点
struct device_node *np = of_find_node_by_path(结点名);
if(!np){
printk("dts:find node failed\n");
}
struct device_node *cnp;
struct device_node *prev = NULL;
char *key_name;
u32 code;
int gpiono;
do{
//获取当前结点的所有孩子
cnp = of_get_next_child(np, prev);
if(!cnp){
//获取中断号
int irqno = irq_of_parse_and_map(np, 0);
printk("irqno = %d\n", irqno);
of_property_read_string(cnp, 孩子结点的字符串变量名, &key_name);
of_property_read_u32(cnp, 孩子结点的无符号32位变量名, &code);
gpiono = of_get_named_gpio(cnp, "gpio", 0);
prev = cnp;
}
else
break;
}while(1);
在输入子系统中,文件io已经在内核中做好了,对于阻塞、轮询等机制可忽略,因此我们只需完成基本的中断申请、中断处理函数、输入事件上报等核心代码,其中按键按下规定为键值1,使得驱动编写十分简化。
添加输入设备的信息
(若不知道,用户很难得知该设备节点event所对应的硬件):
设备信息文件位于/sys/class/input/event目录下,通过cat查看设备描述信息,从而进行操作,对输入设备以下属性进行初始化。
const char *name;
const char *phys;
const char *uniq;
struct input_id id;
另外一种设置bit的方法(set_bit)
inputdev->keybit[BIT_WORD(KEY_POWER)] |= BIT_MASK(KEY_POWER);
相当于:
inputdev->keybit[ xx/32 ] |= 1 << xx%32;