10.3 uinput

uinput 简介

uinput 是一个内核驱动,应用程序通过它可以在内核中模拟一个输入设备,其设备文件名是 /dev/uinput 或 /dev/input/uinput。

uinput 使用

使用 uinput 时遵循以下步骤:

  1. 通过 open 打开 uinput 设备
  2. 通过 ioctl 设置属性位图
  3. 通过 ioctl 设置事件类型位图和对应的事件码位图
  4. 通过 ioctl 设置ID和名称
  5. 通过 ioctl 创建输入设备
  6. 通过 write 上报输入事件
  7. 通过 close 关闭 uinput 设备

使能 uinput

在内核源码目录通过 make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- menuconfig 打开配置菜单,然后选择 User level driver support ,路径如下:

	-> Device Drivers
		-> Input device support
			-> Miscellaneous devices
				<M> User level driver support

如果选择编译成模块,其生成 ko 文件位于内核目录的 drivers/input/misc/中,文件名是uinput.ko

编程实践

在应用层中使用 uinput 在内核中模拟一个按键输入设备,程序流程如下:

  1. 打开 uinput 设备
  2. 设置属性位图、事件类型位图、事件码位图
  3. 设置ID和名称
  4. 创建输入设备
  5. 周期上报按键事件
    完整的代码如下所示:
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

void emit(int fd, int type, int code, int val)
{
	struct input_event ie;

	ie.type = type;
	ie.code = code;
	ie.value = val;
	//以下参数忽略
	ie.time.tv_sec = 0;
	ie.time.tv_usec = 0;

	//上报输入事件
	write(fd, &ie, sizeof(ie));
}

int main(int argc, const char *argv[])
{
	int fd;
	struct uinput_setup usetup;
	const char *name = "/dev/uinput";

	if(argc >= 2)
		name = argv[1];

	//打开 uinput 设备
	fd = open(name, O_WRONLY);
	if(fd < 0)
	{
		perror("open");
		return -1;
	}

	//设置属性位图
	if(ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_BUTTONPAD) < 0)
	{
		close(fd);
		perror("UI_SET_PROPBIT");
		return -1;
	}

	//设置事件类型位图和对应的事件码位图
	if(ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0)
	{
		close(fd);
		perror("UI_SET_EVBIT");
		return -1;
	}
	if(ioctl(fd, UI_SET_KEYBIT, KEY_0) < 0)
	{
		close(fd);
		perror("UI_SET_KEYBIT");
		return -1;
	}

	//设置ID和名称
	memset(&usetup, 0, sizeof(usetup));
	usetup.id.bustype = BUS_USB;
	usetup.id.vendor = 0x1234;
	usetup.id.product = 0x5678;
	strcpy(usetup.name, "Example device");
	if(ioctl(fd, UI_DEV_SETUP, &usetup) < 0)
	{
		close(fd);
		perror("UI_DEV_SETUP");
		return -1;
	}

	//创建输入设备
	if(ioctl(fd, UI_DEV_CREATE) < 0)
	{
		close(fd);
		perror("UI_DEV_CREATE");
		return -1;
	}

	while(1)
	{
		emit(fd, EV_KEY, KEY_0, 1);
		emit(fd, EV_SYN, SYN_REPORT, 0);
		usleep(500*1000);
		emit(fd, EV_KEY, KEY_0, 0);
		emit(fd, EV_SYN, SYN_REPORT, 0);
		usleep(500*1000);
	}

	//close(fd);
}

测试程序参考10.1Linux输入子系统介绍中的按键测试程序

上机测试

  1. 修改内核,使能 uinput
  2. 在这里下载代码,并进行编译,得到 uinput_app.out 和 test_app.out 两个可执行程序。
  3. 执行命令 ./uinput_app.out ,此时会通过 uinput 在内核空间创建一个按键输入设备。
    在这里插入图片描述
  4. 打开另一个终端,执行命令 ./test_app.out /dev/input/event0 ,运行测试程序,其中 /dev/input/event0 为按键输入设备的文件名,由系统自动生成,需要根据实际情况确定,此时测试程序会输出按键状态。
    10.3 uinput_第1张图片

你可能感兴趣的:(linux,嵌入式硬件,驱动开发,arm开发)