从上一篇简单的按键驱动,我们基本上知道了input设备的驱动是怎么编写的,但细心的同胞们可能已经发现问题了,在前面的驱动中,驱动即没有注册成字符驱动、也没有注册成块设备、更没有注册成网络设备,其实我们前面提到过,在“事件处理层”中注册了字符设备的文件操作接口。应该是说了,不信你可以再仔细看看前两篇文章,开个玩笑。问题来了,我们怎么打开由于驱动程序而注册的字符设备呢?好吧,在这里我就直接说了,因为还有许多东西没说,可能设备的名字为什么是那样,或者为什么注册在那个地方?后面的文章会慢慢了解开谜团,这里我们先假设你就是写应用层程序的人,你不用关心驱动的编写以及input子系统的整个框架!
在/dev/input下面可以看到如下的设备,我的电脑上的如下:
在把event0详细看一下ls -l event0 ,结构如下:
上面的时间不准了啊,哈哈,可以看到是主设备号为13,此设备号为64的字符设备,那如果我们要打开设备,路径就是:/dev/input/event0 ,注意这里以注册设备后实际出现的event*为准,你可以先注册后,看看,然后再卸载看看,就知道到底注册的设备是哪个了。比如说我实际注册的设备就为event2。好吧,现在既然知道了怎么打开设备,那我就把测试程序贴出来,再进一步做解释吧。
#include<stdio.h>
#include<stdlib.h>
#include<linux/input.h>
#include<errno.h>
#include<sys/time.h>
#include<sys/types.h>
#include<fcntl.h>
int main(void)
{
int buttons_fd;
int key_value,i=0,count;
struct input_event ev_key; //input_event表示输入事件的结构体,这里定义一个按键输入事件的结构体,当然名字就随便了
buttons_fd = open("/dev/input/event2",O_RDWR); //打开设备,注意打开路径
if(buttons_fd < 0){
perror("open device buttons failure!\n");
exit(1);
}
for(;;){
count = read(buttons_fd, &ev_key, sizeof(struct input_event));//读取按键的实际值
for(i = 0;i < (int)count/sizeof(struct input_event); i++)
if(EV_KEY==ev_key.type) //判断是不是按键类型的事件,这里跟驱动是遥相呼应的
printf("type:%d,code:%d,value:%d\n",ev_key.type, ev_key.code, ev_key.value); //如果是按键事件,就看实际的值了,就是在中断函数中上报的值了
if(EV_SYN==ev_key.type) //判断是不是同步事件了,这个是系统默认的,当然就是了
printf("syn event\n");
}
close(buttons_fd);
return 0;
}
这就是按键驱动的测试程序,其实跟普通的字符程序一样,这里要注意的是input_event这个数据结构,它就是表示事件本身的,这个结构在linux-3.0.8/include/input/input.h中,这里贴出来啊。
struct input_event {
struct timeval time; //发生事件的事件
__u16 type; //事件的类型
__u16 code; //事件码
__s32 value; //事件值
};
刚开始的时候,咱们提到过,在驱动里面没有注册设备,也没有注册设备的名字,那event*是怎么生成的呢,这就涉及到了input子系统的内部实现了,这个不仅要从应用层往下看,而且从驱动层往上看。好吧,既然咱们这篇是从应用层讨论的,那咱们就从先从应用层往下看吧,看看,到底input子系统的神秘面纱下藏了多少神秘而又精明的东东,下篇见喽!