天天看點

編寫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			#支援的類型
           

繼續閱讀