Linux函数学习 ioctl

发布于:2024-04-18 ⋅ 阅读:(15) ⋅ 点赞:(0)

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)