这几天在android上移植了sensor(compass+gsensor),虽然以前TP也是input系统,但只在driver处理,而sensor除了在driver处理还要在HAL处理,HAL处于input subsystem的上层,通过看HAL,对input子系统有了更全面的认识。sensor的数据流是sensor ic ---》driver---》input system----》HAL,其中,input system是由linux系统提供的,我们要完成driver和HAL。这里主要说一下input device在用户空间的接口,主要有三个位置分别如下
1.设备结点
/dev/input
crw-rw---- root input 13, 682012-03-28 16:16 event4
crw-rw---- root input 13, 702012-03-28 16:16 event6
crw-rw---- root input 13, 692012-03-28 16:16 event5
crw-rw---- root input 13, 672012-03-28 16:16 event3
crw-rw---- root input 13, 662012-03-28 16:16 event2
crw-rw---- root input 13, 652012-03-28 16:16 event1
crw-rw---- root input 13, 642012-03-28 16:16 event0
这些全是字符设备,通过这些字符设备节点可以在用户空间导出了原生event,转化成input_event,允许用户程序操作任何event,不会遗失任何信息。要读取相应inputdevice的数据,首先你必须获得input设备的文件描述符。获取方法如下
//这里的inputName必须与driver中注册input设备时制定的name一致,通过这个name就可以找到fd,
//从而读取数据
//注册时定义data->input_dev_compass->name= "ami30x_compass";
int SensorBase::openInput(const char*inputName) {
int fd = -1;
const char *dirname = "/dev/input";
char devname[PATH_MAX];
char *filename;
DIR *dir;
struct dirent *de;
dir = opendir(dirname);
if(dir == NULL)
return -1;
strcpy(devname, dirname);
filename = devname +strlen(devname);
*filename++ = '/';
while((de = readdir(dir))) {
if(de->d_name[0] == '.' &&
(de->d_name[1] =='\0' ||
(de->d_name[1]== '.' && de->d_name[2] == '\0')))
continue;
strcpy(filename, de->d_name);
fd = open(devname, O_RDONLY);
if (fd>=0) {
char name[80];
//通过给设别结点发送ioctrl来获取相应的name,如果匹配则查找到
if (ioctl(fd,EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
name[0] = '\0';
}
if (!strcmp(name,inputName)) {
strcpy(input_name,filename);
break;
} else {
close(fd);
fd = -1;
}
}
}
closedir(dir);
LOGE_IF(fd<0, "couldn'tfind '%s' input device", inputName);
return fd;
}
只要得到了这个fd,就可以与设备交互了,一般有3个接口可以使用
1)IOCTRL
系统提供的IOCTRL如下
include/linux/input.h
#define EVIOCGVERSION _IOR('E',0x01, int) /* get driver version */
#define EVIOCGID _IOR('E', 0x02,struct input_id) /* get device ID */
#define EVIOCGREP _IOR('E',0x03, int[2]) /* get repeat settings */
#define EVIOCSREP _IOW('E',0x03, int[2]) /* set repeat settings */
#define EVIOCGKEYCODE _IOR('E',0x04, int[2]) /* get keycode */
#define EVIOCSKEYCODE _IOW('E',0x04, int[2]) /* set keycode */
#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */
#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */
#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */
#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */
#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */
#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */
#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */
#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */
#define EVIOCGABS(abs) _IOR('E',0x40 + abs, struct input_absinfo) /* get abs value/limits */
#define EVIOCSABS(abs) _IOW('E',0xc0 + abs, struct input_absinfo) /* set abs value/limits */
#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send aforce effect to a force feedback device */
#define EVIOCRMFF _IOW('E',0x81, int) /* Erase a force effect */
#define EVIOCGEFFECTS _IOR('E', 0x84,int) /*Report number of effects playable at the sametime*/
#define EVIOCGRAB _IOW('E',0x90, int) /* Grab/Release device */
值得一提的是EVIOCGNAME,通过ioctl命令EVIOCGNAME,能获取dev/input/event*对应的DeviceName,如ioctl(fd,EVIOCGNAME(sizeof(name)), name)
注意这个一般只是从系统中获取inputdevice的注册信息,不会与硬件通信。
2)获取设备的event通过char设备的read function
如rb=read(fd,ev,sizeof(structinput_event)*64)
3)给设备发送信息通过write(如点亮键盘的numlock led)
write(fd, &ev, sizeof(struct input_event));
这些ioctrl和readwirte系统都已经实现,我们只要注册后,通过fd就可以使用,不需要在driver再实现fops。
2.查看input class 信息
/sys/devices/virtual/input/input*
自己进去看看好了
3.查看设备信息
/proc/bus/input/
# cat /proc/bus/input/devices
I: Bus=0018 Vendor=0000 Product=0000Version=0000
N: Name="ft5xxx"
P: Phys=
S:Sysfs=/devices/i2c-0/0-0038/input/input4
U: Uniq=
H: Handlers=event4 cpufreq
B: EV=b
B: KEY=400 0 4 0 0 0 0 0 0 0 0
B: ABS=2650000 3
I: Bus=0000 Vendor=0000 Product=0000Version=0000
N: Name="msm7627_sku2_keypad"
P: Phys=
S: Sysfs=/devices/virtual/input/input5
U: Uniq=
H: Handlers=kbd event5 cpufreq
B: EV=3
B: KEY=c0000 0 0 0
参考:
强烈建议看一看,看完以上三篇文章,基本对input subsystem会有比较全面的认识,包括driver层如何注册,input core如何处理及APP层如何处理接受到的event。