uinput模块分析 -- 1 初识uinput

本文详细介绍了Linux内核中的uinput模块,该模块允许用户空间模拟输入设备事件。通过分析input子系统的代码,特别是`input_handle_event`函数,探讨了事件传递的机制。文中通过一个用户空间的uinput_key_test示例程序展示了如何创建虚拟输入设备并发送键盘事件。实验结果显示,使用uinput模块成功创建了一个新的input设备,并观察到了EV_KEY和EV_SYN类型的上报事件。此外,还讨论了uinput在Android中的可能应用。

kernel/Documentation/input/uinput.rst 内核文档中对uinput介绍如下:

uinput是一个内核模块,可以从用户空间模拟输入设备。 通过写入 /dev/uinput(或 /dev/input/uinput)设备,进程可以创建具有特定功能的虚拟输入设备。 一旦创建了该虚拟设备,该进程便可以通过它发送事件,这些事件将传递给用户空间和内核用户。

本来的计划是把input的框架分析一遍,再加上几个案例可以了。但是这里为什么会去分析uipnut?

在分析input子系统框架的时候,有这样的代码

static void input_handle_event(struct input_dev *dev,
			       unsigned int type, unsigned int code, int value)
{
        ...
	if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
		dev->event(dev, type, code, value);
        ...
}

这个代码的疑惑之处在于,事件是device产生的为什么要传给device分析,还有就是dev->event这个方法,没有找到赋值的地方。

于是为了这个dev->event,就去搜内核代码,在uinput.c里面发现有赋值,但是这个uinput是什么?于是百度加上找内核文档,才有个去分析uinput的想法。

另外android 有个input命令,可以上报模拟事件,是不是使用了uinput模块?由于手里没有android代码,暂时放一边。。。

内核文档有模拟按键上报的用户空间的代码,我们分析一下,通过应用代码入门,然后去看驱动代码的实现,这样来学习uinput

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/uinput.h>

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

        ie.type = type;
        ie.code = code;
        ie.value = val;
        /* timestamp values below are ignored */
        ie.time.tv_sec = 0;
        ie.time.tv_usec = 0;

        write(fd, &ie, sizeof(ie));
}

int main(void)
{
        struct uinput_setup usetup;

        int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);


        /*
         * The ioctls below will enable the device that is about to be
         * created, to pass key events, in this case the space key.
         */
        ioctl(fd, UI_SET_EVBIT, EV_KEY);
        ioctl(fd, UI_SET_KEYBIT, KEY_SPACE);

        memset(&usetup, 0, sizeof(usetup));
        usetup.id.bustype = BUS_USB;
        usetup.id.vendor = 0x1234; /* sample vendor */
        usetup.id.product = 0x5678; /* sample product */
        strcpy(usetup.name, "Example device");

        ioctl(fd, UI_DEV_SETUP, &usetup);
        ioctl(fd, UI_DEV_CREATE);
        /*
         * On UI_DEV_CREATE the kernel will create the device node for this
         * device. We are inserting a pause here so that userspace has time
         * to detect, initialize the new device, and can start listening to
         * the event, otherwise it will not notice the event we are about
         * to send. This pause is only needed in our example code!
         */
        sleep(10);

        /* Key press, report the event, send key release, and report again */
        emit(fd, EV_KEY, KEY_SPACE, 1);
        emit(fd, EV_SYN, SYN_REPORT, 0);
        emit(fd, EV_KEY, KEY_SPACE, 0);
        emit(fd, EV_SYN, SYN_REPORT, 0);

        /*
         * Give userspace some time to read the events before we destroy the
         * device with UI_DEV_DESTOY.
         */
        sleep(10);

        ioctl(fd, UI_DEV_DESTROY);
        close(fd);

        return 0;
}

编译后实际测试如下:

1,确认当前的input设备

[root@RV1126_RV1109:/userdata]# cat /proc/bus/input/devices 
I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="adc-keys"
P: Phys=adc-keys/input0
S: Sysfs=/devices/platform/adc-keys/input/input0
U: Uniq=
H: Handlers=event0 
B: PROP=0
B: EV=3
B: KEY=800 600 0 0 2

I: Bus=0018 Vendor=dead Product=beef Version=28bb
N: Name="goodix-ts"
P: Phys=input/ts
S: Sysfs=/devices/virtual/input/input1
U: Uniq=
H: Handlers=event1 
B: PROP=2
B: EV=b
B: KEY=400 0 0 0 2000000 1000 40000800 0 0 0 0
B: ABS=6618000 3

2,运行测试程序,可以看到多个一个input设备,对应/dev/input/event2

[root@RV1126_RV1109:/userdata]# ./uinput_key_test &
[root@RV1126_RV1109:/userdata]# cat /proc/bus/input/devices 
I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="adc-keys"
P: Phys=adc-keys/input0
S: Sysfs=/devices/platform/adc-keys/input/input0
U: Uniq=
H: Handlers=event0 
B: PROP=0
B: EV=3
B: KEY=800 600 0 0 2

I: Bus=0018 Vendor=dead Product=beef Version=28bb
N: Name="goodix-ts"
P: Phys=input/ts
S: Sysfs=/devices/virtual/input/input1
U: Uniq=
H: Handlers=event1 
B: PROP=2
B: EV=b
B: KEY=400 0 0 0 2000000 1000 40000800 0 0 0 0
B: ABS=6618000 3

I: Bus=0003 Vendor=1234 Product=5678 Version=0000
N: Name="Example device"
P: Phys=
S: Sysfs=/devices/virtual/input/input5
U: Uniq=
H: Handlers=event2 
B: PROP=0
B: EV=3
B: KEY=2000000 0

3,获取上报事件


[root@RV1126_RV1109:/userdata]# hexdump  /dev/input/event2
0000000 45f6 5984 1d3a 0009 0001 0039 0001 0000
0000010 45f6 5984 1d3a 0009 0000 0000 0000 0000
0000020 45f6 5984 1d67 0009 0001 0039 0000 0000
0000030 45f6 5984 1d67 0009 0000 0000 0000 0000
hexdump: /dev/input/event2: No such device
0000040
[1]+  Done                       ./uinput_key_test
[root@RV1126_RV1109:/userdata]# 

可以看到上报的事件是EV_KEY和EV_SYN,EV_KEY对应键值是0x39,对应KEY_SPACE

另外可以看到应用程序里面并没有填上报事件的时间,但是现在看起来驱动里面把时间加上了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dianlong_lee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值