aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/usbhid/hiddev.c286
1 files changed, 150 insertions, 136 deletions
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 5fc4019956ba..95cc192bc7af 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -393,6 +393,153 @@ static unsigned int hiddev_poll(struct file *file, poll_table *wait)
393/* 393/*
394 * "ioctl" file op 394 * "ioctl" file op
395 */ 395 */
396static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg)
397{
398 struct hid_device *hid = hiddev->hid;
399 struct hiddev_report_info rinfo;
400 struct hiddev_usage_ref_multi *uref_multi = NULL;
401 struct hiddev_usage_ref *uref;
402 struct hid_report *report;
403 struct hid_field *field;
404 int i;
405
406 uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
407 if (!uref_multi)
408 return -ENOMEM;
409 uref = &uref_multi->uref;
410 if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
411 if (copy_from_user(uref_multi, user_arg,
412 sizeof(*uref_multi)))
413 goto fault;
414 } else {
415 if (copy_from_user(uref, user_arg, sizeof(*uref)))
416 goto fault;
417 }
418
419 switch (cmd) {
420 case HIDIOCGUCODE:
421 rinfo.report_type = uref->report_type;
422 rinfo.report_id = uref->report_id;
423 if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
424 goto inval;
425
426 if (uref->field_index >= report->maxfield)
427 goto inval;
428
429 field = report->field[uref->field_index];
430 if (uref->usage_index >= field->maxusage)
431 goto inval;
432
433 uref->usage_code = field->usage[uref->usage_index].hid;
434
435 if (copy_to_user(user_arg, uref, sizeof(*uref)))
436 goto fault;
437
438 kfree(uref_multi);
439 return 0;
440
441 default:
442 if (cmd != HIDIOCGUSAGE &&
443 cmd != HIDIOCGUSAGES &&
444 uref->report_type == HID_REPORT_TYPE_INPUT)
445 goto inval;
446
447 if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
448 field = hiddev_lookup_usage(hid, uref);
449 if (field == NULL)
450 goto inval;
451 } else {
452 rinfo.report_type = uref->report_type;
453 rinfo.report_id = uref->report_id;
454 if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
455 goto inval;
456
457 if (uref->field_index >= report->maxfield)
458 goto inval;
459
460 field = report->field[uref->field_index];
461
462 if (cmd == HIDIOCGCOLLECTIONINDEX) {
463 if (uref->usage_index >= field->maxusage)
464 goto inval;
465 } else if (uref->usage_index >= field->report_count)
466 goto inval;
467
468 else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
469 (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
470 uref->usage_index + uref_multi->num_values > field->report_count))
471 goto inval;
472 }
473
474 switch (cmd) {
475 case HIDIOCGUSAGE:
476 uref->value = field->value[uref->usage_index];
477 if (copy_to_user(user_arg, uref, sizeof(*uref)))
478 goto fault;
479 goto goodreturn;
480
481 case HIDIOCSUSAGE:
482 field->value[uref->usage_index] = uref->value;
483 goto goodreturn;
484
485 case HIDIOCGCOLLECTIONINDEX:
486 kfree(uref_multi);
487 return field->usage[uref->usage_index].collection_index;
488 case HIDIOCGUSAGES:
489 for (i = 0; i < uref_multi->num_values; i++)
490 uref_multi->values[i] =
491 field->value[uref->usage_index + i];
492 if (copy_to_user(user_arg, uref_multi,
493 sizeof(*uref_multi)))
494 goto fault;
495 goto goodreturn;
496 case HIDIOCSUSAGES:
497 for (i = 0; i < uref_multi->num_values; i++)
498 field->value[uref->usage_index + i] =
499 uref_multi->values[i];
500 goto goodreturn;
501 }
502
503goodreturn:
504 kfree(uref_multi);
505 return 0;
506fault:
507 kfree(uref_multi);
508 return -EFAULT;
509inval:
510 kfree(uref_multi);
511 return -EINVAL;
512 }
513}
514
515static noinline int hiddev_ioctl_string(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg)
516{
517 struct hid_device *hid = hiddev->hid;
518 struct usb_device *dev = hid_to_usb_dev(hid);
519 int idx, len;
520 char *buf;
521
522 if (get_user(idx, (int __user *)user_arg))
523 return -EFAULT;
524
525 if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
526 return -ENOMEM;
527
528 if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {
529 kfree(buf);
530 return -EINVAL;
531 }
532
533 if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {
534 kfree(buf);
535 return -EFAULT;
536 }
537
538 kfree(buf);
539
540 return len;
541}
542
396static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 543static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
397{ 544{
398 struct hiddev_list *list = file->private_data; 545 struct hiddev_list *list = file->private_data;
@@ -402,8 +549,6 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
402 struct hiddev_collection_info cinfo; 549 struct hiddev_collection_info cinfo;
403 struct hiddev_report_info rinfo; 550 struct hiddev_report_info rinfo;
404 struct hiddev_field_info finfo; 551 struct hiddev_field_info finfo;
405 struct hiddev_usage_ref_multi *uref_multi = NULL;
406 struct hiddev_usage_ref *uref;
407 struct hiddev_devinfo dinfo; 552 struct hiddev_devinfo dinfo;
408 struct hid_report *report; 553 struct hid_report *report;
409 struct hid_field *field; 554 struct hid_field *field;
@@ -470,30 +615,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
470 } 615 }
471 616
472 case HIDIOCGSTRING: 617 case HIDIOCGSTRING:
473 { 618 return hiddev_ioctl_string(hiddev, cmd, user_arg);
474 int idx, len;
475 char *buf;
476
477 if (get_user(idx, (int __user *)arg))
478 return -EFAULT;
479
480 if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
481 return -ENOMEM;
482
483 if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {
484 kfree(buf);
485 return -EINVAL;
486 }
487
488 if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {
489 kfree(buf);
490 return -EFAULT;
491 }
492
493 kfree(buf);
494
495 return len;
496 }
497 619
498 case HIDIOCINITREPORT: 620 case HIDIOCINITREPORT:
499 usbhid_init_reports(hid); 621 usbhid_init_reports(hid);
@@ -578,121 +700,13 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
578 return 0; 700 return 0;
579 701
580 case HIDIOCGUCODE: 702 case HIDIOCGUCODE:
581 uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); 703 /* fall through */
582 if (!uref_multi)
583 return -ENOMEM;
584 uref = &uref_multi->uref;
585 if (copy_from_user(uref, user_arg, sizeof(*uref)))
586 goto fault;
587
588 rinfo.report_type = uref->report_type;
589 rinfo.report_id = uref->report_id;
590 if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
591 goto inval;
592
593 if (uref->field_index >= report->maxfield)
594 goto inval;
595
596 field = report->field[uref->field_index];
597 if (uref->usage_index >= field->maxusage)
598 goto inval;
599
600 uref->usage_code = field->usage[uref->usage_index].hid;
601
602 if (copy_to_user(user_arg, uref, sizeof(*uref)))
603 goto fault;
604
605 kfree(uref_multi);
606 return 0;
607
608 case HIDIOCGUSAGE: 704 case HIDIOCGUSAGE:
609 case HIDIOCSUSAGE: 705 case HIDIOCSUSAGE:
610 case HIDIOCGUSAGES: 706 case HIDIOCGUSAGES:
611 case HIDIOCSUSAGES: 707 case HIDIOCSUSAGES:
612 case HIDIOCGCOLLECTIONINDEX: 708 case HIDIOCGCOLLECTIONINDEX:
613 uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); 709 return hiddev_ioctl_usage(hiddev, cmd, user_arg);
614 if (!uref_multi)
615 return -ENOMEM;
616 uref = &uref_multi->uref;
617 if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
618 if (copy_from_user(uref_multi, user_arg,
619 sizeof(*uref_multi)))
620 goto fault;
621 } else {
622 if (copy_from_user(uref, user_arg, sizeof(*uref)))
623 goto fault;
624 }
625
626 if (cmd != HIDIOCGUSAGE &&
627 cmd != HIDIOCGUSAGES &&
628 uref->report_type == HID_REPORT_TYPE_INPUT)
629 goto inval;
630
631 if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
632 field = hiddev_lookup_usage(hid, uref);
633 if (field == NULL)
634 goto inval;
635 } else {
636 rinfo.report_type = uref->report_type;
637 rinfo.report_id = uref->report_id;
638 if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
639 goto inval;
640
641 if (uref->field_index >= report->maxfield)
642 goto inval;
643
644 field = report->field[uref->field_index];
645
646 if (cmd == HIDIOCGCOLLECTIONINDEX) {
647 if (uref->usage_index >= field->maxusage)
648 goto inval;
649 } else if (uref->usage_index >= field->report_count)
650 goto inval;
651
652 else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
653 (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
654 uref->usage_index + uref_multi->num_values > field->report_count))
655 goto inval;
656 }
657
658 switch (cmd) {
659 case HIDIOCGUSAGE:
660 uref->value = field->value[uref->usage_index];
661 if (copy_to_user(user_arg, uref, sizeof(*uref)))
662 goto fault;
663 goto goodreturn;
664
665 case HIDIOCSUSAGE:
666 field->value[uref->usage_index] = uref->value;
667 goto goodreturn;
668
669 case HIDIOCGCOLLECTIONINDEX:
670 kfree(uref_multi);
671 return field->usage[uref->usage_index].collection_index;
672 case HIDIOCGUSAGES:
673 for (i = 0; i < uref_multi->num_values; i++)
674 uref_multi->values[i] =
675 field->value[uref->usage_index + i];
676 if (copy_to_user(user_arg, uref_multi,
677 sizeof(*uref_multi)))
678 goto fault;
679 goto goodreturn;
680 case HIDIOCSUSAGES:
681 for (i = 0; i < uref_multi->num_values; i++)
682 field->value[uref->usage_index + i] =
683 uref_multi->values[i];
684 goto goodreturn;
685 }
686
687goodreturn:
688 kfree(uref_multi);
689 return 0;
690fault:
691 kfree(uref_multi);
692 return -EFAULT;
693inval:
694 kfree(uref_multi);
695 return -EINVAL;
696 710
697 case HIDIOCGCOLLECTIONINFO: 711 case HIDIOCGCOLLECTIONINFO:
698 if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) 712 if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))