diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/hid/usbhid/hiddev.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/hid/usbhid/hiddev.c')
-rw-r--r-- | drivers/hid/usbhid/hiddev.c | 297 |
1 files changed, 134 insertions, 163 deletions
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 681e620eb95b..7c1188b53c3e 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c | |||
@@ -29,7 +29,6 @@ | |||
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/smp_lock.h> | ||
33 | #include <linux/input.h> | 32 | #include <linux/input.h> |
34 | #include <linux/usb.h> | 33 | #include <linux/usb.h> |
35 | #include <linux/hid.h> | 34 | #include <linux/hid.h> |
@@ -67,8 +66,6 @@ struct hiddev_list { | |||
67 | struct mutex thread_lock; | 66 | struct mutex thread_lock; |
68 | }; | 67 | }; |
69 | 68 | ||
70 | static struct usb_driver hiddev_driver; | ||
71 | |||
72 | /* | 69 | /* |
73 | * Find a report, given the report's type and ID. The ID can be specified | 70 | * Find a report, given the report's type and ID. The ID can be specified |
74 | * indirectly by REPORT_ID_FIRST (which returns the first report of the given | 71 | * indirectly by REPORT_ID_FIRST (which returns the first report of the given |
@@ -245,15 +242,20 @@ static int hiddev_release(struct inode * inode, struct file * file) | |||
245 | list_del(&list->node); | 242 | list_del(&list->node); |
246 | spin_unlock_irqrestore(&list->hiddev->list_lock, flags); | 243 | spin_unlock_irqrestore(&list->hiddev->list_lock, flags); |
247 | 244 | ||
245 | mutex_lock(&list->hiddev->existancelock); | ||
248 | if (!--list->hiddev->open) { | 246 | if (!--list->hiddev->open) { |
249 | if (list->hiddev->exist) { | 247 | if (list->hiddev->exist) { |
250 | usbhid_close(list->hiddev->hid); | 248 | usbhid_close(list->hiddev->hid); |
251 | usbhid_put_power(list->hiddev->hid); | 249 | usbhid_put_power(list->hiddev->hid); |
252 | } else { | 250 | } else { |
251 | mutex_unlock(&list->hiddev->existancelock); | ||
253 | kfree(list->hiddev); | 252 | kfree(list->hiddev); |
253 | kfree(list); | ||
254 | return 0; | ||
254 | } | 255 | } |
255 | } | 256 | } |
256 | 257 | ||
258 | mutex_unlock(&list->hiddev->existancelock); | ||
257 | kfree(list); | 259 | kfree(list); |
258 | 260 | ||
259 | return 0; | 261 | return 0; |
@@ -303,17 +305,21 @@ static int hiddev_open(struct inode *inode, struct file *file) | |||
303 | list_add_tail(&list->node, &hiddev->list); | 305 | list_add_tail(&list->node, &hiddev->list); |
304 | spin_unlock_irq(&list->hiddev->list_lock); | 306 | spin_unlock_irq(&list->hiddev->list_lock); |
305 | 307 | ||
308 | mutex_lock(&hiddev->existancelock); | ||
306 | if (!list->hiddev->open++) | 309 | if (!list->hiddev->open++) |
307 | if (list->hiddev->exist) { | 310 | if (list->hiddev->exist) { |
308 | struct hid_device *hid = hiddev->hid; | 311 | struct hid_device *hid = hiddev->hid; |
309 | res = usbhid_get_power(hid); | 312 | res = usbhid_get_power(hid); |
310 | if (res < 0) { | 313 | if (res < 0) { |
311 | res = -EIO; | 314 | res = -EIO; |
312 | goto bail; | 315 | goto bail_unlock; |
313 | } | 316 | } |
314 | usbhid_open(hid); | 317 | usbhid_open(hid); |
315 | } | 318 | } |
319 | mutex_unlock(&hiddev->existancelock); | ||
316 | return 0; | 320 | return 0; |
321 | bail_unlock: | ||
322 | mutex_unlock(&hiddev->existancelock); | ||
317 | bail: | 323 | bail: |
318 | file->private_data = NULL; | 324 | file->private_data = NULL; |
319 | kfree(list); | 325 | kfree(list); |
@@ -370,8 +376,10 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun | |||
370 | /* let O_NONBLOCK tasks run */ | 376 | /* let O_NONBLOCK tasks run */ |
371 | mutex_unlock(&list->thread_lock); | 377 | mutex_unlock(&list->thread_lock); |
372 | schedule(); | 378 | schedule(); |
373 | if (mutex_lock_interruptible(&list->thread_lock)) | 379 | if (mutex_lock_interruptible(&list->thread_lock)) { |
380 | finish_wait(&list->hiddev->wait, &wait); | ||
374 | return -EINTR; | 381 | return -EINTR; |
382 | } | ||
375 | set_current_state(TASK_INTERRUPTIBLE); | 383 | set_current_state(TASK_INTERRUPTIBLE); |
376 | } | 384 | } |
377 | finish_wait(&list->hiddev->wait, &wait); | 385 | finish_wait(&list->hiddev->wait, &wait); |
@@ -512,7 +520,7 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, | |||
512 | (uref_multi->num_values > HID_MAX_MULTI_USAGES || | 520 | (uref_multi->num_values > HID_MAX_MULTI_USAGES || |
513 | uref->usage_index + uref_multi->num_values > field->report_count)) | 521 | uref->usage_index + uref_multi->num_values > field->report_count)) |
514 | goto inval; | 522 | goto inval; |
515 | } | 523 | } |
516 | 524 | ||
517 | switch (cmd) { | 525 | switch (cmd) { |
518 | case HIDIOCGUSAGE: | 526 | case HIDIOCGUSAGE: |
@@ -588,163 +596,168 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
588 | { | 596 | { |
589 | struct hiddev_list *list = file->private_data; | 597 | struct hiddev_list *list = file->private_data; |
590 | struct hiddev *hiddev = list->hiddev; | 598 | struct hiddev *hiddev = list->hiddev; |
591 | struct hid_device *hid = hiddev->hid; | 599 | struct hid_device *hid; |
592 | struct usb_device *dev; | ||
593 | struct hiddev_collection_info cinfo; | 600 | struct hiddev_collection_info cinfo; |
594 | struct hiddev_report_info rinfo; | 601 | struct hiddev_report_info rinfo; |
595 | struct hiddev_field_info finfo; | 602 | struct hiddev_field_info finfo; |
596 | struct hiddev_devinfo dinfo; | 603 | struct hiddev_devinfo dinfo; |
597 | struct hid_report *report; | 604 | struct hid_report *report; |
598 | struct hid_field *field; | 605 | struct hid_field *field; |
599 | struct usbhid_device *usbhid = hid->driver_data; | ||
600 | void __user *user_arg = (void __user *)arg; | 606 | void __user *user_arg = (void __user *)arg; |
601 | int i, r; | 607 | int i, r = -EINVAL; |
602 | 608 | ||
603 | /* Called without BKL by compat methods so no BKL taken */ | 609 | /* Called without BKL by compat methods so no BKL taken */ |
604 | 610 | ||
605 | /* FIXME: Who or what stop this racing with a disconnect ?? */ | 611 | mutex_lock(&hiddev->existancelock); |
606 | if (!hiddev->exist || !hid) | 612 | if (!hiddev->exist) { |
607 | return -EIO; | 613 | r = -ENODEV; |
614 | goto ret_unlock; | ||
615 | } | ||
608 | 616 | ||
609 | dev = hid_to_usb_dev(hid); | 617 | hid = hiddev->hid; |
610 | 618 | ||
611 | switch (cmd) { | 619 | switch (cmd) { |
612 | 620 | ||
613 | case HIDIOCGVERSION: | 621 | case HIDIOCGVERSION: |
614 | return put_user(HID_VERSION, (int __user *)arg); | 622 | r = put_user(HID_VERSION, (int __user *)arg) ? |
623 | -EFAULT : 0; | ||
624 | break; | ||
615 | 625 | ||
616 | case HIDIOCAPPLICATION: | 626 | case HIDIOCAPPLICATION: |
617 | if (arg < 0 || arg >= hid->maxapplication) | 627 | if (arg < 0 || arg >= hid->maxapplication) |
618 | return -EINVAL; | 628 | break; |
619 | 629 | ||
620 | for (i = 0; i < hid->maxcollection; i++) | 630 | for (i = 0; i < hid->maxcollection; i++) |
621 | if (hid->collection[i].type == | 631 | if (hid->collection[i].type == |
622 | HID_COLLECTION_APPLICATION && arg-- == 0) | 632 | HID_COLLECTION_APPLICATION && arg-- == 0) |
623 | break; | 633 | break; |
624 | 634 | ||
625 | if (i == hid->maxcollection) | 635 | if (i < hid->maxcollection) |
626 | return -EINVAL; | 636 | r = hid->collection[i].usage; |
627 | 637 | break; | |
628 | return hid->collection[i].usage; | ||
629 | 638 | ||
630 | case HIDIOCGDEVINFO: | 639 | case HIDIOCGDEVINFO: |
631 | dinfo.bustype = BUS_USB; | 640 | { |
632 | dinfo.busnum = dev->bus->busnum; | 641 | struct usb_device *dev = hid_to_usb_dev(hid); |
633 | dinfo.devnum = dev->devnum; | 642 | struct usbhid_device *usbhid = hid->driver_data; |
634 | dinfo.ifnum = usbhid->ifnum; | 643 | |
635 | dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor); | 644 | dinfo.bustype = BUS_USB; |
636 | dinfo.product = le16_to_cpu(dev->descriptor.idProduct); | 645 | dinfo.busnum = dev->bus->busnum; |
637 | dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice); | 646 | dinfo.devnum = dev->devnum; |
638 | dinfo.num_applications = hid->maxapplication; | 647 | dinfo.ifnum = usbhid->ifnum; |
639 | if (copy_to_user(user_arg, &dinfo, sizeof(dinfo))) | 648 | dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor); |
640 | return -EFAULT; | 649 | dinfo.product = le16_to_cpu(dev->descriptor.idProduct); |
641 | 650 | dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice); | |
642 | return 0; | 651 | dinfo.num_applications = hid->maxapplication; |
652 | |||
653 | r = copy_to_user(user_arg, &dinfo, sizeof(dinfo)) ? | ||
654 | -EFAULT : 0; | ||
655 | break; | ||
656 | } | ||
643 | 657 | ||
644 | case HIDIOCGFLAG: | 658 | case HIDIOCGFLAG: |
645 | if (put_user(list->flags, (int __user *)arg)) | 659 | r = put_user(list->flags, (int __user *)arg) ? |
646 | return -EFAULT; | 660 | -EFAULT : 0; |
647 | 661 | break; | |
648 | return 0; | ||
649 | 662 | ||
650 | case HIDIOCSFLAG: | 663 | case HIDIOCSFLAG: |
651 | { | 664 | { |
652 | int newflags; | 665 | int newflags; |
653 | if (get_user(newflags, (int __user *)arg)) | 666 | |
654 | return -EFAULT; | 667 | if (get_user(newflags, (int __user *)arg)) { |
668 | r = -EFAULT; | ||
669 | break; | ||
670 | } | ||
655 | 671 | ||
656 | if ((newflags & ~HIDDEV_FLAGS) != 0 || | 672 | if ((newflags & ~HIDDEV_FLAGS) != 0 || |
657 | ((newflags & HIDDEV_FLAG_REPORT) != 0 && | 673 | ((newflags & HIDDEV_FLAG_REPORT) != 0 && |
658 | (newflags & HIDDEV_FLAG_UREF) == 0)) | 674 | (newflags & HIDDEV_FLAG_UREF) == 0)) |
659 | return -EINVAL; | 675 | break; |
660 | 676 | ||
661 | list->flags = newflags; | 677 | list->flags = newflags; |
662 | 678 | ||
663 | return 0; | 679 | r = 0; |
680 | break; | ||
664 | } | 681 | } |
665 | 682 | ||
666 | case HIDIOCGSTRING: | 683 | case HIDIOCGSTRING: |
667 | mutex_lock(&hiddev->existancelock); | 684 | r = hiddev_ioctl_string(hiddev, cmd, user_arg); |
668 | if (hiddev->exist) | 685 | break; |
669 | r = hiddev_ioctl_string(hiddev, cmd, user_arg); | ||
670 | else | ||
671 | r = -ENODEV; | ||
672 | mutex_unlock(&hiddev->existancelock); | ||
673 | return r; | ||
674 | 686 | ||
675 | case HIDIOCINITREPORT: | 687 | case HIDIOCINITREPORT: |
676 | mutex_lock(&hiddev->existancelock); | ||
677 | if (!hiddev->exist) { | ||
678 | mutex_unlock(&hiddev->existancelock); | ||
679 | return -ENODEV; | ||
680 | } | ||
681 | usbhid_init_reports(hid); | 688 | usbhid_init_reports(hid); |
682 | mutex_unlock(&hiddev->existancelock); | 689 | r = 0; |
683 | 690 | break; | |
684 | return 0; | ||
685 | 691 | ||
686 | case HIDIOCGREPORT: | 692 | case HIDIOCGREPORT: |
687 | if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) | 693 | if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) { |
688 | return -EFAULT; | 694 | r = -EFAULT; |
695 | break; | ||
696 | } | ||
689 | 697 | ||
690 | if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT) | 698 | if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT) |
691 | return -EINVAL; | 699 | break; |
692 | 700 | ||
693 | if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) | 701 | report = hiddev_lookup_report(hid, &rinfo); |
694 | return -EINVAL; | 702 | if (report == NULL) |
703 | break; | ||
695 | 704 | ||
696 | mutex_lock(&hiddev->existancelock); | 705 | usbhid_submit_report(hid, report, USB_DIR_IN); |
697 | if (hiddev->exist) { | 706 | usbhid_wait_io(hid); |
698 | usbhid_submit_report(hid, report, USB_DIR_IN); | ||
699 | usbhid_wait_io(hid); | ||
700 | } | ||
701 | mutex_unlock(&hiddev->existancelock); | ||
702 | 707 | ||
703 | return 0; | 708 | r = 0; |
709 | break; | ||
704 | 710 | ||
705 | case HIDIOCSREPORT: | 711 | case HIDIOCSREPORT: |
706 | if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) | 712 | if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) { |
707 | return -EFAULT; | 713 | r = -EFAULT; |
714 | break; | ||
715 | } | ||
708 | 716 | ||
709 | if (rinfo.report_type == HID_REPORT_TYPE_INPUT) | 717 | if (rinfo.report_type == HID_REPORT_TYPE_INPUT) |
710 | return -EINVAL; | 718 | break; |
711 | 719 | ||
712 | if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) | 720 | report = hiddev_lookup_report(hid, &rinfo); |
713 | return -EINVAL; | 721 | if (report == NULL) |
722 | break; | ||
714 | 723 | ||
715 | mutex_lock(&hiddev->existancelock); | 724 | usbhid_submit_report(hid, report, USB_DIR_OUT); |
716 | if (hiddev->exist) { | 725 | usbhid_wait_io(hid); |
717 | usbhid_submit_report(hid, report, USB_DIR_OUT); | ||
718 | usbhid_wait_io(hid); | ||
719 | } | ||
720 | mutex_unlock(&hiddev->existancelock); | ||
721 | 726 | ||
722 | return 0; | 727 | r = 0; |
728 | break; | ||
723 | 729 | ||
724 | case HIDIOCGREPORTINFO: | 730 | case HIDIOCGREPORTINFO: |
725 | if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) | 731 | if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) { |
726 | return -EFAULT; | 732 | r = -EFAULT; |
733 | break; | ||
734 | } | ||
727 | 735 | ||
728 | if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) | 736 | report = hiddev_lookup_report(hid, &rinfo); |
729 | return -EINVAL; | 737 | if (report == NULL) |
738 | break; | ||
730 | 739 | ||
731 | rinfo.num_fields = report->maxfield; | 740 | rinfo.num_fields = report->maxfield; |
732 | 741 | ||
733 | if (copy_to_user(user_arg, &rinfo, sizeof(rinfo))) | 742 | r = copy_to_user(user_arg, &rinfo, sizeof(rinfo)) ? |
734 | return -EFAULT; | 743 | -EFAULT : 0; |
735 | 744 | break; | |
736 | return 0; | ||
737 | 745 | ||
738 | case HIDIOCGFIELDINFO: | 746 | case HIDIOCGFIELDINFO: |
739 | if (copy_from_user(&finfo, user_arg, sizeof(finfo))) | 747 | if (copy_from_user(&finfo, user_arg, sizeof(finfo))) { |
740 | return -EFAULT; | 748 | r = -EFAULT; |
749 | break; | ||
750 | } | ||
751 | |||
741 | rinfo.report_type = finfo.report_type; | 752 | rinfo.report_type = finfo.report_type; |
742 | rinfo.report_id = finfo.report_id; | 753 | rinfo.report_id = finfo.report_id; |
743 | if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) | 754 | |
744 | return -EINVAL; | 755 | report = hiddev_lookup_report(hid, &rinfo); |
756 | if (report == NULL) | ||
757 | break; | ||
745 | 758 | ||
746 | if (finfo.field_index >= report->maxfield) | 759 | if (finfo.field_index >= report->maxfield) |
747 | return -EINVAL; | 760 | break; |
748 | 761 | ||
749 | field = report->field[finfo.field_index]; | 762 | field = report->field[finfo.field_index]; |
750 | memset(&finfo, 0, sizeof(finfo)); | 763 | memset(&finfo, 0, sizeof(finfo)); |
@@ -763,10 +776,9 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
763 | finfo.unit_exponent = field->unit_exponent; | 776 | finfo.unit_exponent = field->unit_exponent; |
764 | finfo.unit = field->unit; | 777 | finfo.unit = field->unit; |
765 | 778 | ||
766 | if (copy_to_user(user_arg, &finfo, sizeof(finfo))) | 779 | r = copy_to_user(user_arg, &finfo, sizeof(finfo)) ? |
767 | return -EFAULT; | 780 | -EFAULT : 0; |
768 | 781 | break; | |
769 | return 0; | ||
770 | 782 | ||
771 | case HIDIOCGUCODE: | 783 | case HIDIOCGUCODE: |
772 | /* fall through */ | 784 | /* fall through */ |
@@ -775,57 +787,52 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
775 | case HIDIOCGUSAGES: | 787 | case HIDIOCGUSAGES: |
776 | case HIDIOCSUSAGES: | 788 | case HIDIOCSUSAGES: |
777 | case HIDIOCGCOLLECTIONINDEX: | 789 | case HIDIOCGCOLLECTIONINDEX: |
778 | mutex_lock(&hiddev->existancelock); | 790 | r = hiddev_ioctl_usage(hiddev, cmd, user_arg); |
779 | if (hiddev->exist) | 791 | break; |
780 | r = hiddev_ioctl_usage(hiddev, cmd, user_arg); | ||
781 | else | ||
782 | r = -ENODEV; | ||
783 | mutex_unlock(&hiddev->existancelock); | ||
784 | return r; | ||
785 | 792 | ||
786 | case HIDIOCGCOLLECTIONINFO: | 793 | case HIDIOCGCOLLECTIONINFO: |
787 | if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) | 794 | if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) { |
788 | return -EFAULT; | 795 | r = -EFAULT; |
796 | break; | ||
797 | } | ||
789 | 798 | ||
790 | if (cinfo.index >= hid->maxcollection) | 799 | if (cinfo.index >= hid->maxcollection) |
791 | return -EINVAL; | 800 | break; |
792 | 801 | ||
793 | cinfo.type = hid->collection[cinfo.index].type; | 802 | cinfo.type = hid->collection[cinfo.index].type; |
794 | cinfo.usage = hid->collection[cinfo.index].usage; | 803 | cinfo.usage = hid->collection[cinfo.index].usage; |
795 | cinfo.level = hid->collection[cinfo.index].level; | 804 | cinfo.level = hid->collection[cinfo.index].level; |
796 | 805 | ||
797 | if (copy_to_user(user_arg, &cinfo, sizeof(cinfo))) | 806 | r = copy_to_user(user_arg, &cinfo, sizeof(cinfo)) ? |
798 | return -EFAULT; | 807 | -EFAULT : 0; |
799 | return 0; | 808 | break; |
800 | 809 | ||
801 | default: | 810 | default: |
802 | |||
803 | if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ) | 811 | if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ) |
804 | return -EINVAL; | 812 | break; |
805 | 813 | ||
806 | if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) { | 814 | if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) { |
807 | int len; | 815 | int len = strlen(hid->name) + 1; |
808 | if (!hid->name) | ||
809 | return 0; | ||
810 | len = strlen(hid->name) + 1; | ||
811 | if (len > _IOC_SIZE(cmd)) | 816 | if (len > _IOC_SIZE(cmd)) |
812 | len = _IOC_SIZE(cmd); | 817 | len = _IOC_SIZE(cmd); |
813 | return copy_to_user(user_arg, hid->name, len) ? | 818 | r = copy_to_user(user_arg, hid->name, len) ? |
814 | -EFAULT : len; | 819 | -EFAULT : len; |
820 | break; | ||
815 | } | 821 | } |
816 | 822 | ||
817 | if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) { | 823 | if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) { |
818 | int len; | 824 | int len = strlen(hid->phys) + 1; |
819 | if (!hid->phys) | ||
820 | return 0; | ||
821 | len = strlen(hid->phys) + 1; | ||
822 | if (len > _IOC_SIZE(cmd)) | 825 | if (len > _IOC_SIZE(cmd)) |
823 | len = _IOC_SIZE(cmd); | 826 | len = _IOC_SIZE(cmd); |
824 | return copy_to_user(user_arg, hid->phys, len) ? | 827 | r = copy_to_user(user_arg, hid->phys, len) ? |
825 | -EFAULT : len; | 828 | -EFAULT : len; |
829 | break; | ||
826 | } | 830 | } |
827 | } | 831 | } |
828 | return -EINVAL; | 832 | |
833 | ret_unlock: | ||
834 | mutex_unlock(&hiddev->existancelock); | ||
835 | return r; | ||
829 | } | 836 | } |
830 | 837 | ||
831 | #ifdef CONFIG_COMPAT | 838 | #ifdef CONFIG_COMPAT |
@@ -847,6 +854,7 @@ static const struct file_operations hiddev_fops = { | |||
847 | #ifdef CONFIG_COMPAT | 854 | #ifdef CONFIG_COMPAT |
848 | .compat_ioctl = hiddev_compat_ioctl, | 855 | .compat_ioctl = hiddev_compat_ioctl, |
849 | #endif | 856 | #endif |
857 | .llseek = noop_llseek, | ||
850 | }; | 858 | }; |
851 | 859 | ||
852 | static char *hiddev_devnode(struct device *dev, mode_t *mode) | 860 | static char *hiddev_devnode(struct device *dev, mode_t *mode) |
@@ -894,7 +902,7 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) | |||
894 | hiddev->exist = 1; | 902 | hiddev->exist = 1; |
895 | retval = usb_register_dev(usbhid->intf, &hiddev_class); | 903 | retval = usb_register_dev(usbhid->intf, &hiddev_class); |
896 | if (retval) { | 904 | if (retval) { |
897 | err_hid("Not able to get a minor for this device."); | 905 | hid_err(hid, "Not able to get a minor for this device\n"); |
898 | hid->hiddev = NULL; | 906 | hid->hiddev = NULL; |
899 | kfree(hiddev); | 907 | kfree(hiddev); |
900 | return -1; | 908 | return -1; |
@@ -914,52 +922,15 @@ void hiddev_disconnect(struct hid_device *hid) | |||
914 | 922 | ||
915 | mutex_lock(&hiddev->existancelock); | 923 | mutex_lock(&hiddev->existancelock); |
916 | hiddev->exist = 0; | 924 | hiddev->exist = 0; |
917 | mutex_unlock(&hiddev->existancelock); | ||
918 | 925 | ||
919 | usb_deregister_dev(usbhid->intf, &hiddev_class); | 926 | usb_deregister_dev(usbhid->intf, &hiddev_class); |
920 | 927 | ||
921 | if (hiddev->open) { | 928 | if (hiddev->open) { |
929 | mutex_unlock(&hiddev->existancelock); | ||
922 | usbhid_close(hiddev->hid); | 930 | usbhid_close(hiddev->hid); |
923 | wake_up_interruptible(&hiddev->wait); | 931 | wake_up_interruptible(&hiddev->wait); |
924 | } else { | 932 | } else { |
933 | mutex_unlock(&hiddev->existancelock); | ||
925 | kfree(hiddev); | 934 | kfree(hiddev); |
926 | } | 935 | } |
927 | } | 936 | } |
928 | |||
929 | /* Currently this driver is a USB driver. It's not a conventional one in | ||
930 | * the sense that it doesn't probe at the USB level. Instead it waits to | ||
931 | * be connected by HID through the hiddev_connect / hiddev_disconnect | ||
932 | * routines. The reason to register as a USB device is to gain part of the | ||
933 | * minor number space from the USB major. | ||
934 | * | ||
935 | * In theory, should the HID code be generalized to more than one physical | ||
936 | * medium (say, IEEE 1384), this driver will probably need to register its | ||
937 | * own major number, and in doing so, no longer need to register with USB. | ||
938 | * At that point the probe routine and hiddev_driver struct below will no | ||
939 | * longer be useful. | ||
940 | */ | ||
941 | |||
942 | |||
943 | /* We never attach in this manner, and rely on HID to connect us. This | ||
944 | * is why there is no disconnect routine defined in the usb_driver either. | ||
945 | */ | ||
946 | static int hiddev_usbd_probe(struct usb_interface *intf, | ||
947 | const struct usb_device_id *hiddev_info) | ||
948 | { | ||
949 | return -ENODEV; | ||
950 | } | ||
951 | |||
952 | static /* const */ struct usb_driver hiddev_driver = { | ||
953 | .name = "hiddev", | ||
954 | .probe = hiddev_usbd_probe, | ||
955 | }; | ||
956 | |||
957 | int __init hiddev_init(void) | ||
958 | { | ||
959 | return usb_register(&hiddev_driver); | ||
960 | } | ||
961 | |||
962 | void hiddev_exit(void) | ||
963 | { | ||
964 | usb_deregister(&hiddev_driver); | ||
965 | } | ||