Linux uinput驱动分析
来源:互联网 发布:火车票代理软件 编辑:程序博客网 时间:2024/05/10 17:20
Linux版本:linux-3.13.3
877 static int __init uinput_init(void)878 {879 return misc_register(&uinput_misc);880 }在uinput_init函数中,调用misc_register创建了一个混杂设备,所谓混杂设备本质上主设备号为10的一个字符设备,uinput_misc定义如下:
869 static struct miscdevice uinput_misc = {870 .fops = &uinput_fops,871 .minor = UINPUT_MINOR,872 .name = UINPUT_NAME,873 };uinput_fops定义如下:
855 static const struct file_operations uinput_fops = {856 .owner = THIS_MODULE,857 .open = uinput_open,858 .release = uinput_release,859 .read = uinput_read,860 .write = uinput_write,861 .poll = uinput_poll,862 .unlocked_ioctl = uinput_ioctl,863 #ifdef CONFIG_COMPAT864 .compat_ioctl = uinput_compat_ioctl,865 #endif866 .llseek = no_llseek,867 };在uinput应用程序中,我们首先是调用的open系统调用,uinput_open函数实现如下:
289 static int uinput_open(struct inode *inode, struct file *file)290 {291 struct uinput_device *newdev;292 293 newdev = kzalloc(sizeof(struct uinput_device), GFP_KERNEL);294 if (!newdev)295 return -ENOMEM;296 297 mutex_init(&newdev->mutex);298 spin_lock_init(&newdev->requests_lock);299 init_waitqueue_head(&newdev->requests_waitq);300 init_waitqueue_head(&newdev->waitq);301 newdev->state = UIST_NEW_DEVICE;302 303 file->private_data = newdev;304 nonseekable_open(inode, file);305 306 return 0;307 }其实质是调用kzalloc创建了一个struct uinput_device结构,初始化了struct uinput_device结构中的一些成员。然后再看uinput_ioctl函数:
842 static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)843 {844 return uinput_ioctl_handler(file, cmd, arg, (void __user *)arg);845 }直接调用了uinput_ioctl_handler函数。
在uinput_ioctl_handler函数中,我们只看我们需要的键盘部分:
687 if (!udev->dev) {688 retval = uinput_allocate_device(udev);689 if (retval)690 goto out;691 }初始时,struct uinput_device中的dev成员值为NULL,那么会调用uinput_allocate_device函数去创建。
348 static int uinput_allocate_device(struct uinput_device *udev)349 {350 udev->dev = input_allocate_device();351 if (!udev->dev)352 return -ENOMEM;353 354 udev->dev->event = uinput_dev_event;355 input_set_drvdata(udev->dev, udev);356 357 return 0;358 }
在uinput_allocate_device函数中,调用input_allocate_device函数去分配了input设备,并设置了它的event为uinput_dev_event。回到ioctl函数中。693 switch (cmd) {694 case UI_DEV_CREATE:695 retval = uinput_create_device(udev);696 break;697 698 case UI_DEV_DESTROY:699 uinput_destroy_device(udev);700 break;701 702 case UI_SET_EVBIT:703 retval = uinput_set_bit(arg, evbit, EV_MAX);704 break;705 706 case UI_SET_KEYBIT:707 retval = uinput_set_bit(arg, keybit, KEY_MAX);708 break;在应用程序中,调用了两次ioctl函数:
ret = ioctl(fd, UI_SET_EVBIT, EV_KEY);ret = ioctl(fd, UI_SET_EVBIT, EV_SYN);即最后设置了struct input_dev结构中的evbit,而evbit中的位表示支持的时间类型。
ret = ioctl(fd, UI_SET_KEYBIT, KEY_D);设置了struct input_dev结构中的keybit,keybit表示支持的按键键值,这里只支持了KEY_D按键。
然后看write函数:
459 static ssize_t uinput_write(struct file *file, const char __user *buffer,460 size_t count, loff_t *ppos)461 {462 struct uinput_device *udev = file->private_data;463 int retval;464 465 if (count == 0)466 return 0;467 468 retval = mutex_lock_interruptible(&udev->mutex);469 if (retval)470 return retval;471 472 retval = udev->state == UIST_CREATED ?473 uinput_inject_events(udev, buffer, count) :474 uinput_setup_device(udev, buffer, count);475 476 mutex_unlock(&udev->mutex);477 478 return retval;479 }在wirte函数中,由于此时我们还没有创建input设备,所以此时uinput设备的状态不是UIST_CREATED,所以为首先调用uinput_setup_device函数。
360 static int uinput_setup_device(struct uinput_device *udev,361 const char __user *buffer, size_t count)362 {363 struct uinput_user_dev *user_dev;364 struct input_dev *dev;365 int i;366 int retval;367 368 if (count != sizeof(struct uinput_user_dev))369 return -EINVAL;370 371 if (!udev->dev) {372 retval = uinput_allocate_device(udev);373 if (retval)374 return retval;375 }376 377 dev = udev->dev;378 379 user_dev = memdup_user(buffer, sizeof(struct uinput_user_dev));380 if (IS_ERR(user_dev))381 return PTR_ERR(user_dev);382 383 udev->ff_effects_max = user_dev->ff_effects_max;384 385 /* Ensure name is filled in */386 if (!user_dev->name[0]) {387 retval = -EINVAL;388 goto exit;389 }390 391 kfree(dev->name);392 dev->name = kstrndup(user_dev->name, UINPUT_MAX_NAME_SIZE,393 GFP_KERNEL);394 if (!dev->name) {395 retval = -ENOMEM;396 goto exit;397 }398 399 dev->id.bustype = user_dev->id.bustype;400 dev->id.vendor = user_dev->id.vendor;401 dev->id.product = user_dev->id.product;402 dev->id.version = user_dev->id.version;403 404 for (i = 0; i < ABS_CNT; i++) {405 input_abs_set_max(dev, i, user_dev->absmax[i]);406 input_abs_set_min(dev, i, user_dev->absmin[i]);407 input_abs_set_fuzz(dev, i, user_dev->absfuzz[i]);408 input_abs_set_flat(dev, i, user_dev->absflat[i]);409 }410 411 /* check if absmin/absmax/absfuzz/absflat are filled as412 * told in Documentation/input/input-programming.txt */413 if (test_bit(EV_ABS, dev->evbit)) {414 retval = uinput_validate_absbits(dev);415 if (retval < 0)416 goto exit;417 if (test_bit(ABS_MT_SLOT, dev->absbit)) {418 int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;419 input_mt_init_slots(dev, nslot, 0);420 } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {421 input_set_events_per_packet(dev, 60);422 }423 }424 425 udev->state = UIST_SETUP_COMPLETE;426 retval = count;427 428 exit:429 kfree(user_dev);430 return retval;431 }那自然是获取应用层创建的struct uinput_user_dev,初始化struct input_dev中的成员。
ret = ioctl(fd, UI_DEV_CREATE);然后注册struct input_dev设备。
254 static int uinput_create_device(struct uinput_device *udev)255 {256 struct input_dev *dev = udev->dev;257 int error;258 259 if (udev->state != UIST_SETUP_COMPLETE) {260 printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);261 return -EINVAL;262 }263 264 if (udev->ff_effects_max) {265 error = input_ff_create(dev, udev->ff_effects_max);266 if (error)267 goto fail1;268 269 dev->ff->upload = uinput_dev_upload_effect;270 dev->ff->erase = uinput_dev_erase_effect;271 dev->ff->playback = uinput_dev_playback;272 dev->ff->set_gain = uinput_dev_set_gain;273 dev->ff->set_autocenter = uinput_dev_set_autocenter;274 }275 276 error = input_register_device(udev->dev);277 if (error)278 goto fail2;279 280 udev->state = UIST_CREATED;281 282 return 0;283 284 fail2: input_ff_destroy(dev);285 fail1: uinput_destroy_device(udev);286 return error;287 }
最后调用input_register_device注册了一个input设备,input设备创建完成。最后是调用write发送数据。
input设备已经创建,那在write函数中自然是调用uinput_inject_events函数。
433 static ssize_t uinput_inject_events(struct uinput_device *udev,434 const char __user *buffer, size_t count)435 {436 struct input_event ev;437 size_t bytes = 0;438 439 if (count != 0 && count < input_event_size())440 return -EINVAL;441 442 while (bytes + input_event_size() <= count) {443 /*444 * Note that even if some events were fetched successfully445 * we are still going to return EFAULT instead of partial446 * count to let userspace know that it got it's buffers447 * all wrong.448 */449 if (input_event_from_user(buffer + bytes, &ev))450 return -EFAULT;451 452 input_event(udev->dev, ev.type, ev.code, ev.value);453 bytes += input_event_size();454 }455 456 return bytes;457 }
最后调用input_event函数将报告发送给input层。最后总结一下,在open函数中,分配了一个uinput_device设备,调用ioctl去注册一个input设备,注册input设备调用的是input_register_device函数,最后在write函数调用input_event发送报告。
0 0
- Linux uinput驱动分析
- linux uinput 分析。
- linux uinput 分析。
- 【RFB】Linux uinput 分析,虚拟鼠标,键盘
- 【RFB】Linux uinput 分析,虚拟鼠标,键盘
- Linux /dev/uinput
- Linux /dev/uinput
- uinput
- 使用UInput模拟系统键盘鼠标动作 UInput driver分析
- 使用UInput模拟系统键盘鼠标动作 UInput driver分析
- Linux使用uinput实现虚拟鼠标
- Linux 使用uinput创建虚拟input设备
- Android系统利用uinput设备驱动实现虚拟输入设备
- 利用虚拟键盘驱动uinput向系统发送按键指令
- Android系统利用uinput设备驱动实现虚拟输入设备
- Linux网卡驱动分析
- Linux网卡驱动分析
- linux音频驱动分析
- Java获取当前的时间
- 应用 Valgrind 发现 Linux 程序的内存问题
- 书籍阅读(持续更新)
- [March]总结和规划
- union赋值及小端系统
- Linux uinput驱动分析
- jquey XMLHttpRequest cannot load url.Origin null is not allowed by Access-Control-Allow-Origin
- DFS——The die is cast
- C++类的方法设计
- 纯java读取apk信息
- java中参数传递
- jQuery在IE8下的append方法缺陷
- bsh for android : URL Connect Test
- tabhost学习精要