Linux uinput驱动分析

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_COMPAT
864         .compat_ioctl   = uinput_compat_ioctl,
865 #endif
866         .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 as
412          * 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 successfully
445                  * we are still going to return EFAULT instead of partial
446                  * count to let userspace know that it got it's buffers
447                  * 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
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值