一、擷取裝置資訊
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 #支援的類型