linux input输入子系统分析《一》:初识input输入子系统

主要讲述本人在学习Linux内核input子系统的全部过程,如有分析不当,多谢指正。以下交流方式,文章欢迎转载,保留联系信息,以便交流。

邮箱:eabi010@gmail.com

主页:(爱嵌论坛——嵌入式技术学习交流)

博客:blog.csdn.net/ielife

1开发环境

主 机:ubuntu10.04

开发板:mini2440

内 核:linux-2.6.22.6

编译器:arm-linux-gcc(3.4.5)

2linux输入子系统

本节从整体上讲解了输入子系统的框架结构。有助于读者从整体上认识linux的输入子系统。在陷入代码分析的过程中,通过本节的知识能够找准方向,明白原理。

本节重点:

本节难点:

输入子系统的事件处理机制 输入子系统的驱动工作流程2.1 初识linux输入子系统

linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler)、输入子系统核心层(InputCore)和输入子系统设备驱动层。

对于输入子系统设备驱动层而言,主要实现对硬件设备的读写访问,中断设置,并把硬件产生的事件转换为核心层定义的规范提交给事件处理层。

对于核心层而言,为设备驱动层提供了规范和接口。设备驱动层只要关心如何驱动硬件并获得硬件数据(例如按下的按键数据),然后调用核心层提供的接口,核心层会自动把数据提交给事件处理层。

对于事件处理层而言,则是用户编程的接口(设备节点),并处理驱动层提交的数据处理。

对于linux输入子系统的框架结构如下图1所示:

图1 linux输入子系统框架结构

由上图所展现的内容就是linux输入子系统的分层结构。

/dev/input目录下显示的是已经注册在内核中的设备编程接口,用户通过open这些设备文件来打开不同的输入设备进行硬件操作。

事件处理层为不同硬件类型提供了用户访问及处理接口。例如当我们打开设备/dev/input/mice时,会调用到事件处理层的Mouse Handler来处理输入事件,这也使得设备驱动层无需关心设备文件的操作,因为Mouse Handler已经有了对应事件处理的方法。

输入子系统由内核代码drivers/input/input.c构成,它的存在屏蔽了用户到设备驱动的交互细节,为设备驱动层和事件处理层提供了相互通信的统一界面。

下图2简单描述了linux输入子系统的事件处理机制:

图2 linux输入子系统事件处理机制

由上图可知输入子系统核心层提供的支持以及如何上报事件到input event drivers。

作为输入设备的驱动开发者,需要做以下几步:

在驱动加载模块中,设置你的input设备支持的事件类型,类型参见表1设置

注册中断处理函数,例如键盘设备需要编写按键的抬起、放下,触摸屏设备需要编写按下、抬起、绝对移动,鼠标设备需要编写单击、抬起、相对移动,并且需要在必要的时候提交硬件数据(键值/坐标/状态等等)

将输入设备注册到输入子系统中

表1 Linux输入子系统支持的数据类型

EV_SYN 0x00同步事件

EV_KEY 0x01按键事件

EV_REL 0x02相对坐标(如:鼠标移动,报告相对最后一次位置的偏移)

EV_ABS 0x03绝对坐标(如:触摸屏或操作杆,报告绝对的坐标位置)

EV_MSC 0x04其它

EV_SW 0x05开关

EV_LED 0x11按键/设备灯

EV_SND 0x12声音/警报

EV_REP 0x14重复

EV_FF 0x15力反馈

EV_PWR 0x16电源

EV_FF_STATUS 0x17力反馈状态

EV_MAX 0x1f事件类型最大个数和提供位掩码支持

由表1可知,设备所能表示的事件种类,一个设备可以选择一个或多个事件类型上报给输入子系统。

Linux输入子系统提供了设备驱动层上报输入事件的函数,在include/linux/input.h中:

voidinput_report_key(struct input_dev *dev, unsigned int code, int value); //上报按键事件

voidinput_report_rel(struct input_dev *dev, unsigned int code, int value); //上报相对坐标事件

voidinput_report_abs(struct input_dev *dev, unsigned int code, int value); //上报绝对坐标事件

……

当提交输入设备产生的输入事件之后,需要调用下面的函数来通知输入子系统,以处理设备产生的完整事件:

void input_sync(struct input_dev *dev);

2.2 输入设备驱动的简单案例

在Linux内核文档的documentation/input下,有一个input-programming.txt文件,讲解了编写输入设备驱动程序的核心步骤。

提供的案例代码描述了一个button设备,产生的事件通过BUTTON_PORT引脚获取,当有按下/释放发生时,BUTTON_IRQ被触发,以下是驱动的源代码:

#include <linux/input.h>#include <linux/module.h> #include <linux/init.h> #include <asm/irq.h> #include <asm/io.h> static struct input_dev *button_dev; static void button_interrupt(int irq, void*dummy, struct pt_regs *fp) {input_report_key(button_dev, BTN_1, inb(BUTTON_PORT) & 1);input_sync(button_dev); }static int __init button_init(void) {int error;if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button",NULL)) {printk(KERN_ERR"button.c: Can’t allocate irq %d\n", button_irq);return -EBUSY;}button_dev = input_allocate_device();if (!button_dev) {printk(KERN_ERR"button.c: Not enough memory\n");error = -ENOMEM;goto err_free_irq;}button_dev->evbit[0] = BIT(EV_KEY);button_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);error = input_register_device(button_dev);if (error) {printk(KERN_ERR"button.c: Failed to register device\n");goto err_free_dev;}return 0; err_free_dev:input_free_device(button_dev); err_free_irq:free_irq(BUTTON_IRQ, button_interrupt);return error; } static void __exit button_exit(void) {input_unregister_device(button_dev);free_irq(BUTTON_IRQ, button_interrupt);}module_init(button_init);module_exit(button_exit);

编写基于输入子系统的设备驱动程序需要包含<linux/input.h>,因为它包含了输入子系统的接口和所有的宏定义,这些内容在编写输入设备驱动程序时需要用到。

button_init函数说明:

为何是一个人?也有善意的提醒:

linux input输入子系统分析《一》:初识input输入子系统

相关文章:

你感兴趣的文章:

标签云: