现在的位置: 首页 > 综合 > 正文

linux uinput 分析。

2013年08月02日 ⁄ 综合 ⁄ 共 3326字 ⁄ 字号 评论关闭

linux uinput

本文以 2.6.22.7 的kernel 为基础。
首先 uinput 是一个字符设备, 其次它还是一个 input 设备。另外它可以是一个鼠标或者键盘设备。

从 init 部分说起吧。

static const struct file_operations uinput_fops = {
    .owner        = THIS_MODULE,
    .open        = uinput_open,
    .release    = uinput_release,
    .read        = uinput_read,
    .write        = uinput_write,
    .poll        = uinput_poll,
    .unlocked_ioctl    = uinput_ioctl,
};

static struct miscdevice uinput_misc = {
    .fops        = &uinput_fops,
    .minor        = UINPUT_MINOR,
    .name        = UINPUT_NAME,
};

static int __init uinput_init(void)
{
    return misc_register(&uinput_misc);
}

首先说说 miscdevice, 很方便的东西,对 device 做了简单的包装,
当 misc_register 的时候就完成了 设备的 注册安装一类的东东, 不用自己再操心了。真是懒人的设计阿。
所有的 misc 设备公用同一个主设备号,在 misc_init 中,
static int __init misc_init(void)
{
#ifdef CONFIG_PROC_FS
    struct proc_dir_entry *ent;

    ent = create_proc_entry("misc", 0, NULL);
    if (ent)
        ent->proc_fops = &misc_proc_fops;
#endif
    misc_class = class_create(THIS_MODULE, "misc");
    if (IS_ERR(misc_class))
        return PTR_ERR(misc_class);

    if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
        printk("unable to get major %d for misc devices/n",
               MISC_MAJOR);
        class_destroy(misc_class);
        return -EIO;
    }
    return 0;
}
register_chrdev 接口真 BT ,
__register_chrdev_region(major, 0, 256, name);
直接占用了 0 到 255 的次设备号,注册 misc 类型设备的时候,直接从里面取就是了。
而在 misc_open 通过设备节点把 file_operations 指向对应的设备驱动上去, 很良好的设计, 呵呵。
有点类似其他总线的设计, 但是只有 device_list, 没有 driver_list, 当然也不需要。
不在 misc 上浪费时间了。 接下来再到 uinput 中去。
从uinput_open 说起吧, uinput_open 其实啥事情都没干。。做了一些简单的初始化工作。

要创建一个 input 设备,我们在调用input_register_device 前需要设置 好input_dev的各种属性。
而设置input_dev的属性在 uinput_setup_device 接口中, 但驱动怎么知道你想模拟什么设备呢?
又需要通过 uinput_ioctl 设置先。 很糟糕的设计。 用户若是不知道这些流程,如何能使用这个模拟驱动?
下面是一个使用 uinput 的用户态程序:

int setup_uinput_device(char *device)
{
                // Temporary variable
                int i=0;
                // Open the input device
                //uinp_fd = open("/dev/input/uinput", O_WRONLY | O_NDELAY);
                uinp_fd = open(device, O_WRONLY | O_NDELAY);

               if (uinp_fd == 0)
                  {
                        printf("Unable to open /dev/input/uinput/n");
                        return -1;
                  }

                memset(&uinp,0,sizeof(uinp)); // Intialize the uInput device to NULL
                strncpy(uinp.name, "HID Keyboard Device", strlen("HID Keyboard Device"));
                uinp.id.version = 4;
                uinp.id.bustype = BUS_USB;
                uinp.id.product = 1;
                uinp.id.vendor = 1;
                // Setup the uinput device
                ioctl(uinp_fd, UI_SET_EVBIT, EV_KEY);
                ioctl(uinp_fd, UI_SET_EVBIT, EV_REL);
                ioctl(uinp_fd, UI_SET_RELBIT, REL_X);
                ioctl(uinp_fd, UI_SET_RELBIT, REL_Y);

            for (i=0; i < 256; i++) {
                ioctl(uinp_fd, UI_SET_KEYBIT, i);
            }
           ioctl(uinp_fd, UI_SET_KEYBIT, BTN_MOUSE);
           ioctl(uinp_fd, UI_SET_KEYBIT, BTN_TOUCH);
           ioctl(uinp_fd, UI_SET_KEYBIT, BTN_MOUSE);
           ioctl(uinp_fd, UI_SET_KEYBIT, BTN_LEFT);
           ioctl(uinp_fd, UI_SET_KEYBIT, BTN_MIDDLE);
           ioctl(uinp_fd, UI_SET_KEYBIT, BTN_RIGHT);
           ioctl(uinp_fd, UI_SET_KEYBIT, BTN_FORWARD);
           ioctl(uinp_fd, UI_SET_KEYBIT, BTN_BACK);
 
          write(uinp_fd, &uinp, sizeof(uinp));
          if (ioctl(uinp_fd, UI_DEV_CREATE))
           {
                        printf("Unable to create UINPUT device.");
                        return -1;
           }
            return 1;
}

很变态的流程, 先用 ioctl 设置参数(模拟鼠标,键盘), 再 write, 在第一次 write 的时候创建 inputdev,
然后 ioctl 调用 UI_DEV_CREATE 向系统注册 . BT............
今天先写到这里拉。。

抱歉!评论已关闭.