在介绍触摸屏驱动之前,先来认识一下这个input子系统。在学习触摸屏之前,我几乎完全没有听说过input子系统这个概念,现在就让我们一起来揭开它神秘的面纱吧。

     在我们的Linux系统中,按键、触摸屏、鼠标等输入型设备都可以利用input接口函数来实现设备驱动。

 

一.系统架构

 

 

左边部分是我们驱动工程师应该完成的部分,而input core 和handlers 是内核已经提供好的,我们只需要根据input core 所要求的接口编写driver部分即可。那我们的驱动实际做了什么工作呢?它完成的工作其实很简单,将底层的硬件输入转化为同一事件形式,向input core汇报。input core起了承上启下的作用,它为驱动层提供输入设备注册与操作接口,如input_register_device;通知handlers 对事件进行处理;在/PROC 下产生相应的设备信息。而handlers 则主要和我们的用户空间打交道。我们知道Linux在用户空间将所有设备当成文件来处理,在一般的驱动程序中都有提供fops接口,以及在/dev下生成相应的设备文件,而在输入子系统中,这些工作都是由handlers 完成。

 

 

二.设备描述

在Linux内核中,input设备用input_dev结构体描述,使用input子系统实现输入设备驱动的时候,驱动的核心工作就是向系统报告按键、触摸屏、键盘、鼠标等输入事件(event,通过input_event结构体描述),不再需要关心文件操作接口,因为Input子系统已经完成了文件操作接口。驱动报告的时间经过inputcore 和handlers 最终到达用户空间。其实它仍然是一个字符设备,只是划分方法不一样罢了。

 

三.设备注册/注销

注册输入设备的函数

int input_register_device(struct input_dev *dev)

 

注销输入设备的函数

void input_unregister_device(struce input_dev *dev)

 

四.驱动实现——事件支持

设备驱动通过set_bit()告诉input子系统它支持哪些时间,哪些按键。

例子:

set_bit(EV_KEY, button_dev.evbit)

其中我们关注第二个参数button_dev,它是一个input_dev 结构体,有两个成员:

evbit:事件类型

keybit:按键类型

 

常见事件类型:EV_KEY 按键

                          EV_REL 相对坐标

                          EV_ABS 绝对坐标

 

当事件类型为EV_KEY时,还需指明按键类型:

BTN_LEFT 鼠标左键

BTN_RIGHT 鼠标右键

BTN_MIDDLE 鼠标中键

BTN_0 数字0键

BTN_1 数字1键

 

上述set_bit函数实则完成了把EV_KEY赋值到button_dev.evbit

 

五.驱动实现——报告事件

用于报告EV_KEY事件的函数

void input_report_key(struct input_dev *dev, unsigned int code, int value)

需要注意的参数如下:

code : 事件的代码,如果事件是ev_key,该代码则为设备的键盘代码。例如鼠标按键代码为0x110~0x116,其中0x110(BTN_LEFT),0x111(BTN_RIGHT),0x112(BTN_MIDDLE)。其它带按摩含义参考include/linux/input.h文件

value : 事件的值,如果事件的类型是EV_KEY,当按键按下时值为1,松开时为0。

 

六.驱动实现——报告结束

input_sync()用于告诉input core 此次报告已经结束,能够根据上报的信息往后面处理了,不然input core还在傻傻地等待着我们的驱动呢。

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

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, 1);  //报告状态

input_sync(input_dev);  //同步(结束)

 

七.实例分析

下面是按键驱动的简单例子,并不完整:

[c-sharp]
static void button_interrupt(int irq, void *dummy, struct pt_regs *fp)  
  1. {  
  2.     //有可能是0号键或者1号键产生中断,所以都要往input_core报告  
  3.     input_report_key(&button_dev, BTN_0, inb(BUTTON_PORT0));  
  4.     input_report_key(&button_dev, BTN_1, inb(BUTTON_PORT1));  
  5.     input_sync(&button_dev);  
  6. }  
  7.   
  8. static int __initbutton_init(void)  
  9. {  
  10.     if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL))  
  11.         return -EBUSY;  
  12.   
  13.     set_bit(EV_KEY, button_dev.evbit)  //支持EV_KEY事件  
  14.     set_bit(BTN_0, button_dev.keybit);  //设备支持两个键  
  15.     set_bit(BTN_1, button_dev.keybit);  
  16.     input_register_device(&button_dev);  //注册input设备    
  17. }  

只要之前了解过键盘驱动程序的朋友,都对文件操作ops有印象吧?所有的read、ioctl 等操作函数都要我们自己去编写,而使用input子系统之后,这些工作内核都为我们做好了,舒心吧?

 

下面再给出应用程序的代码

[c-sharp]
 
#include <stdio.h> 
  1. #include <stdlib.h> 
  2. #include <unistd.h> 
  3. #include <sys/ioctl.h> 
  4. #include <sys/types.h> 
  5. #include <sys/stat.h> 
  6. #include <fcntl.h> 
  7. #include <sys/select.h> 
  8. #include <sys/time.h> 
  9. #include <errno.h> 
  10. #include <linux/input.h>  
  11.   
  12. int main(void)  
  13. {  
  14.     int buttons_fd;  
  15.     int key_value,i=0,count;  
  16.   
  17.     struct input_event ev_key;  
  18.   
  19.     buttons_fd = open("/dev/event0", O_RDWR);  
  20.     if (buttons_fd < 0) {  
  21.         perror("open device buttons");  
  22.         exit(1);  
  23.     }  
  24.   
  25.     for (;;) {  
  26.         count = read(buttons_fd,&ev_key,sizeof(struct input_event));  
  27.   
  28.                 //读出所有的事件,通过事件类型判断出是否我们的键盘输入事件,再通过按键编号和  
  29.                   //键值就可以判断出是某一个键按下或弹起的状态  
  30.         for(i=0; i<(int)count/sizeof(struct input_event); i++)    
  31.             if(EV_KEY==ev_key.type)  
  32.                 printf("type:%d,code:%d,value:%d/n", ev_key.type,ev_key.code,ev_key.value);  
  33.   
  34.             if(EV_SYN==ev_key.type)  
  35.                 printf("syn event/n/n");  
  36.     }  
  37.   
  38.     close(buttons_fd);  
  39.     return 0;  
  40. }  

 

到此为止,input子系统的介绍就告一段落了,下一篇博文的触摸屏驱动就是建立在这个input子系统之上搭建而成的,事先了解一下这个是相当有必要的。不是有这么一句话么:磨刀不误砍柴工!

Logo

开源、云原生的融合云平台

更多推荐