input子系统详解

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

对于输入子系统设备驱动层而言,主要实现对硬件设备的读写访问,中断设置,并把硬件产生的事件转换为核心层定义的规范提交给事件处理层。即将底层的硬件输入转化为统一事件形式,想输入核心(Input Core)汇报。

对于核心层而言,为设备驱动层提供了规范和接口。设备驱动层只要关心如何驱动硬件并获得硬件数据(例如按下的按键数据),然后调用核心层提供的接口,核心层会自动把数据提交给事件处理层。承上启下。为驱动层提供输入设备注册与操作接口,如:input_register_device;通知事件处理层对事件进行处理;在/Proc下产生相应的设备信息

对于事件处理层而言,则是用户编程的接口(设备节点),并处理驱动层提交的数据处理。和用户空间交互。(Linux中在用户空间将所有的设备都当初文件来处理,由于在一般的驱动程序中都有提供fops接口,以及在/dev下生成相应的设备文件nod,这些操作在输入子系统中由事件处理层完成)

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

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

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

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

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

由上图可知输入子系统核心层提供的支持以及如何上报事件到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);

设备描述:

input_dev结构

实现设备驱动核心工作是:向系统报告按键、触摸屏等输入事件(event,通过input_event结构描述),不再需要关心文件操作接口。驱动报告事件经过inputCore和Eventhandler到达用户空间。

注册输入设备函数:

int input_register_device(struct input_dev *dev)

注销输入设备函数:

void input_unregister_device(struct input_dev *dev)

驱动实现——初始化(事件支持):

set_bit()告诉input输入子系统支持哪些事件,哪些按键。例如:

set_bit(EV_KEY,button_dev.evbit) (其中button_dev是struct input_dev类型)

struct input_dev中有两个成员为:

evbit:

事件类型(包括

EV_RST,EV_REL,EV_MSC,EV_KEY,EV_ABS,EV_REP等)

keybit:

按键类型(当事件类型为EV_KEY时包括

BTN_LEFT,BTN_0,BTN_1,BTN_MIDDLE等)

驱动实现——报告事件:

用于报告EV_KEY,EV_REL,EV_ABS事件的函数分别为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)

驱动实现——报告结束:

input_sync()同步用于告诉input core子系统报告结束。

实例:触摸屏设备驱动中,一次点击的整个报告过程如下:

input_reprot_abs(input_dev,ABS_X,x); //x坐标

input_reprot_abs(input_dev,ABS_Y,y); // y坐标

input_reprot_abs(input_dev,ABS_PRESSURE,1);

input_sync(input_dev);//同步结束

实例分析(按键中断程序):

//按键初始化

static int __init button_init(void)

{//申请中断

if(request_irq(BUTTON_IRQ,button_interrupt,0,”button”,NUll))

  return –EBUSY;

set_bit(EV_KEY,button_dev.evbit); //支持EV_KEY事件

set_bit(BTN_0,button_dev.keybit); //支持设备两个键

set_bit(BTN_1,button_dev.keybit); //

input_register_device(&button_dev);//注册input设备

}

/在按键中断中报告事件/

Static void button_interrupt(int irq,void *dummy,struct pt_regs *fp)

{

input_report_key(&button_dev,BTN_0,inb(BUTTON_PORT0));//读取寄存器BUTTON_PORT0的值

input_report_key(&button_dev,BTN_1,inb(BUTTON_PORT1));

input_sync(&button_dev);

}

总结:input子系统仍然是字符设备驱动程序,但是代码量减少很多,input子系统只需要完成两个工作:初始化和事件报告(这里在linux中是通过中断来实现的)。读者不妨用sourceinsignt 输入input_init去搜关于输入子系统的实现

原文链接:input子系统详解

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值