天天看点

编写App获取设备信息一、获取设备信息二、编写代码三、调试代码

一、获取设备信息

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			#支持的类型
           

继续阅读