现在的位置: 首页 > 操作系统 > 正文

linux设备驱动之input子系统 key-gpio

2018年05月27日 操作系统 ⁄ 共 2707字 ⁄ 字号 评论关闭

/***********************************************************

*硬件平台:mini6410

*系统:linux2.6.36

***********************************************************/

 

        最近在看宋宝华老师写的linux设备驱动开发详解,了解了设备驱动的分层思想以及主机驱动和设备驱动的分离思想,突然觉得人类是如此强大,思想是如此的重要。

        看到12章中有关于gpiokey的例子,于是就想仔细的研究一下,在我的板子上跑跑试试。

 

        S3C64XX_GPN(5)被LCD占用,所以在驱动加载时,提示error-16,即EBUSY,注释掉后方可使用。

        设备节点“/dev/input/event0”,应用程序需要使用此节点方可对其进行访问。

 

首先来了解一下input subsystem的结构以及工作流程 

        输入设备是典型的字符设备,其一般的工作原理是底层在按键、触摸等动作发生时产生一个中断,然后cpu通过SPI、I2C或外部存储器总线读取键值、坐标等数据,放入一个缓冲区,字符设备驱动管理该缓冲区,而驱动的read()接口让用户可以读取键值、坐标等数据。input subsystem用来统一处理数据输入设备“键盘、鼠标、触摸屏”等。

        中断、读键值/坐标值是设备相关的,输入事件的缓冲区管理以及字符设备驱动的file_operations接口对输入设备是通用的。基于此,内核设计了输入子系统,由核心层处理公共的工作。

        在Linux中,输入子系统是由输入子系统设备驱动层、输入子系统核心层(Input Core)和输入子系统事件处理层(Event Handler)组成。其中设备驱动层提供对硬件各寄存器的读写访问和将底层硬件对用户输入访问的响应转换为标准的输入事件,再通过核心层提交给事件处理层;而核心层对下提供了设备驱动层的编程接口,对上又提供了事件处理层的编程接口;而事件处理层就为我们用户空间的应用程序提供了统一访问设备的接口和驱动层提交来的事件处理。所以这使得我们输入设备的驱动部分不在用关心对设备文件的操作,而是要关心对各硬件寄存器的操作和提交的输入事件。

 

                                            input subsystem架构

如上图所示,Input Core用来协调硬件的input事件和用户层应用之间的通讯,下图详细说明了它的内部层次结构

 

 

 

输入子系统设备驱动层实现原理
     在Linux中,Input设备用input_dev结构体描述,定义在input.h中。设备的驱动只需按照如下步骤就可实现了。
     1).在驱动模块加载函数中设置Input设备支持input子系统的哪些事件;
     2).将Input设备注册到input子系统中;
     3).在Input设备发生输入操作时(如:键盘被按下/抬起、触摸屏被触摸/抬起/移动、鼠标被移动/单击/抬起时等),提交所发生的事件及对应的键值/坐标等状态。

驱动设计流程如下图所示

 input子系统驱动设计流程

下面来看看与驱动设计有关的API函数

 

分配一个输入设备
        struct input_dev *input_allocate_device*(void);

注册一个输入设备
        int input_register_device(struct input_dev *dev);

事件支持

Set_bit告诉input子系统它支持哪些事件
Set_bit(EV_KEY,button_dev.evbit)
Struct input_dev中有两个成员,一个是evbit;一个是keybit.分别用来表示设备所支持的事件类型和按键类型。

事件类型
Linux中输入设备的事件类型有(这里只列出了常用的一些,更多请看linux/input.h中):

EV_SYN 0x00 同步事件
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 力反馈

报告事件
Void input_event(struct input_dev *dev,unsigned int type,unsigned int code,int value);//报告指定type,code的输入事件
Void input_report_key(struct input_dev *dev,unsigned int code,int value);//报告键值
Void input_report_rel(struct input_dev *dev,unsigned int code,int value);//报告相对坐标
Void input_report_abs(struct input_dev *dev,unsigned int code,int value);//报告绝对坐标
Void input_sync(struct input_dev *dev);//报告同步事件

在触摸屏驱动设计中,一次坐标及按下状态的整个报告过程如下:
Input_report_abs(input_dev,ABS_X,x);//X坐标
Input_report_abs(input_dev,ABS_Y,y);//Y坐标
Input_report_abs(input_dev,ABS_PRESSURE,pres);//压力
input_sync(struct input_dev *dev);//同步

释放与注销设备
Void input_free_device(struct input_dev *dev);
Void input_unregister_device(struct input_dev *);

在内核中,input_dev表示一个input设备,

                    input_handler表示input设备的接口

        linux内核的drivers/input/keyboard/gpio_keys.c基于input架构实现了一个通用的GPIO按键驱动。该驱动基于platform_driver架构,名为“gpio-keys”。它将硬件相关信息屏蔽在板文件platform_device的platform_data中,因此驱动可应用于各个处理器,具有良好的跨平台性。

 

 

 

抱歉!评论已关闭.