1、Linux ioctl函数
int ioctl(int fd, unsigned long request, ...);
返回值:-1 失败,0 成功
fd :文件句柄
request :控制命令的整数值,用于指定要执行的具体操作。这个参数通常是一个设备特定的宏或常量,用于确定所请求的操作类型。
... :不定长参数
2、函数实例
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <unistd.h>
#include <sys/select.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#define BITS_PER_LONG 32
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
static int test_bit(int nr, const volatile unsigned long *addr)
{
return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
}
int main (int argc, char ** argv){
int fd;
int i;
unsigned long *evtype_b = malloc(sizeof(unsigned long));
if(argc != 2){
printf("Usage: %s <dev> \n", argv[0]);
}
fd = open(argv[1], O_RDWR | O_NONBLOCK);
if(fd < 0){
printf("open %s err = %s\n", argv[1],strerror(errno));
return 0;
} else {
printf("open %s success \n",argv[1]);
}
char buffer[80];
/*获取设备名称*/
if (ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
printf("1.EVIOCGNAME failed %s\n",strerror(errno));
} else {
printf("1.EVIOCGNAME --- %s \n", buffer);
}
/*获取驱动版本*/
int driverVersion;
if (ioctl(fd, EVIOCGVERSION, &driverVersion)) {
printf("2.EVIOCGVERSION failed %s\n",strerror(errno));
} else {
printf("2.EVIOCGVERSION --- %d \n", driverVersion);
}
/*获取input Id*/
struct input_id inputId;
if (ioctl(fd, EVIOCGID, &inputId)) {
printf("3.EVIOCGID failed %s\n",strerror(errno));
} else {
printf("3.EVIOCGID --- %u %u %u %u \n",inputId.bustype, inputId.product,inputId.vendor,inputId.version);
}
//获取设备物理位置
memset(buffer,0,sizeof(buffer));
if (ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
printf("4.EVIOCGPHYS failed %s\n",strerror(errno));
} else {
printf("4.EVIOCGPHYS --- %s \n", buffer);
}
// Get device unique id.
memset(buffer,0,sizeof(buffer));
if (ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
printf("5.EVIOCGUNIQ failed %s\n",strerror(errno));
} else {
printf("5.EVIOCGPHYS --- %s \n", buffer);
}
/*获取支持的输入输出类型*/
memset(evtype_b, 0, sizeof(evtype_b));
if (ioctl(fd, EVIOCGBIT(0, EV_MAX), evtype_b) < 0) {
perror("evdev ioctl");
}
printf("6.EVIOCGBIT EV_TYPE --- %d \n", EV_MAX);
for (i = 0; i < EV_MAX; i++) {
if (test_bit(i, evtype_b)) {
/* the bit is set in the event types list */
printf(" Event type 0x%04x \n", i);
switch (i)
{
case EV_SYN :
printf(" (Synch Events) \n");
break;
case EV_KEY :
printf(" (Keys or Buttons) \n");
break;
case EV_REL :
printf(" (Relative Axes) \n");
break;
case EV_ABS :
printf(" (Absolute Axes) \n");
break;
case EV_MSC :
printf(" (Miscellaneous) \n");
break;
case EV_LED :
printf(" (LEDs) \n");
break;
case EV_SND :
printf(" (Sounds) \n");
break;
case EV_REP :
printf(" (Repeat) \n");
break;
case EV_FF :
case EV_FF_STATUS:
printf(" (Force Feedback) \n");
break;
case EV_PWR:
printf(" (Power Management) \n");
break;
default:
printf(" (Unknown: 0x%04x) \n",i);
}
}
}
/*获取支持的EV_KEY类型*/
memset(evtype_b, 0, sizeof(evtype_b));
printf("7.EVIOCGBIT EV_KEY: %d \n", KEY_MAX);
if (ioctl(fd, EVIOCGBIT(EV_KEY, KEY_MAX), evtype_b) < 0) {
perror("evdev ioctl");
}
for (i = 0; i < KEY_MAX; i++) {
if (test_bit(i, evtype_b)) {
switch (i){
case KEY_POWER:
printf(" (KEY_POWER) \n");
break;
case KEY_ENTER:
printf(" (KEY_ENTER) \n");
break;
case KEY_HOME:
printf(" (KEY_HOME) \n");
break;
case KEY_W:
printf(" (KEY_W) \n");
break;
case KEY_E:
printf(" (KEY_E) \n");
break;
case KEY_O:
printf(" (KEY_O) \n");
break;
case KEY_P:
printf(" (KEY_P) \n");
break;
default:
printf(" (Unknown Key: 0x%04x) \n",i);
}
}
}
if(evtype_b != NULL){
free(evtype_b);
}
close(fd);
return 0;
}
3、注意事项
获取EVIOCGBIT相关参数时,长度可传入的参数参考kernel-4.14/drivers/input/evdev.c 代码,EV_KEY传入长度为KEY_MAX
ioctl(fd, EVIOCGBIT(EV_KEY, KEY_MAX), evtype_b)
static int handle_eviocgbit(struct input_dev *dev,
unsigned int type, unsigned int size,
void __user *p, int compat_mode)
{
unsigned long *bits;
int len;
switch (type) {
case 0: bits = dev->evbit; len = EV_MAX; break;
case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
case EV_REL: bits = dev->relbit; len = REL_MAX; break;
case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
case EV_SW: bits = dev->swbit; len = SW_MAX; break;
default: return -EINVAL;
}
return bits_to_user(bits, len, size, p, compat_mode);
}
4、代码运行效果
编译二进制文件,运行到手机端
/system/bin # ./ioctl /dev/input/event3
open /dev/input/event3 success
1.EVIOCGNAME --- ant_det
2.EVIOCGVERSION --- 65537
3.EVIOCGID --- 0 0 0 0
4.EVIOCGPHYS failed No such file or directory
5.EVIOCGUNIQ failed No such file or directory
6.EVIOCGBIT EV_TYPE --- 31
Event type 0x0000
(Synch Events)
Event type 0x0001
(Keys or Buttons)
7.EVIOCGBIT EV_KEY: 767
(Unknown Key: 0x0001)