一、获取设备信息
App通过调用ioctl获取设备信息,ioctl的函数原型如下:
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);
有些驱动程序对request的格式有要求,request的格式如下,之前学习过ioctl:
// include/uapi/asm-generic/ioctl.h
#define _IOC_NRSHIFT 0
#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) //_IOC_TYPESHIFT = 8
#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) //_IOC_SIZESHIFT = 8 + 8 =16
#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) //_IOC_DIRSHIFT = 16 + 13 = 29
#define _IOC(dir,type,nr,size) \
(((dir) << _IOC_DIRSHIFT) | \ //bit31~bit30 2位为 “区别读写” 区,作用是区分是读取命令还是写入命令。
((type) << _IOC_TYPESHIFT) | \ //bit29~bit15 14位为 "数据大小" 区,表示 ioctl() 中的 arg 变量传送的内存大小。
((nr) << _IOC_NRSHIFT) | \ //bit20~bit08 8位为 “魔数"(也称为"幻数")区,这个值用以与其它设备驱动程序的 ioctl 命令进行区别。
((size) << _IOC_SIZESHIFT)) //bit07~bit00 8位为 "区别序号" 区,是区分命令的命令顺序序号。
- dir有不同的位来表示读还是写,或者读写
#ifndef _IOC_NONE
# define _IOC_NONE 0U
#endif
#ifndef _IOC_WRITE
# define _IOC_WRITE 1U //1是写
#endif
#ifndef _IOC_READ
# define _IOC_READ 2U //2是读
#endif
- size表示这个ioctl能传输数据的最大字节数
- type、nr的含义由具体的驱动程序决定
比如要读取输入设备evbit时,ioctl的request要写为
EVIOCGBIT(0, size)
,size的大小可以由你决定:
你想读多少字节就设置为多少,这个宏的定义如下:
// include/uapi/linux/input.h
#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + (ev), len) /* get event bits */
二、编写代码
获取输入设备的基本信息:
#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
char *ev_names[] = {
"EV_SYN ",
"EV_KEY ",
"EV_REL ",
"EV_ABS ",
"EV_MSC ",
"EV_SW ",
"NULL ",
"NULL ",
"NULL ",
"NULL ",
"NULL ",
"NULL ",
"NULL ",
"NULL ",
"NULL ",
"NULL ",
"NULL ",
"EV_LED ",
"EV_SND ",
"NULL ",
"EV_REP ",
"EV_FF ",
"EV_PWR ",
};
int main(int argc, char *argv[])
{
int fd, err, len, i, bit;
unsigned char byte;
struct input_id id;
unsigned int evbit[2];
if(argc != 2) {
printf("Usage: %s <dev>\n", argv[0]);
return -1;
}
fd = open(argv[1], O_RDWR);
if(fd < 0) {
printf("open %s err\n", argv[1]);
return -1;
}
err = ioctl(fd, EVIOCGID, &id);
if(err == 0) {
printf("bustype = 0x%x\n", id.bustype);
printf("vendor = 0x%x\n", id.vendor);
printf("product = 0x%x\n", id.product);
printf("version = 0x%x\n", id.version);
}
len = ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), &evbit);
if(len > 0 && len <= sizeof(evbit)) {
printf("support ev type: ");
for(i=0;i<len;i++) {
byte = ((unsigned char *)evbit)[i];
for(bit=0;bit<8;bit++) {
if(byte & (1<<bit)) {
printf("%s ", ev_names[i*8+bit]);
}
}
}
printf("\n");
}
return 0;
}
三、调试代码
[email protected]:/home/debian# ./get_input_info /dev/input/event2
bustype = 0x18 #这里打印的信息和cat /proc/bus/input/devices一致
vendor = 0x416
product = 0x1001
version = 0x200
support ev type: EV_SYN EV_KEY EV_ABS #支持的类型