Linux uinput驱动分析

来源:互联网 发布:火车票代理软件 编辑:程序博客网 时间:2024/05/10 17:20
Linux版本:linux-3.13.3


uinput是Linux提供的一个可以在用户空间创建input设备的驱动程序,init部分代码如下:
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
原创粉丝点击