aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/usbhid/hiddev.c
diff options
context:
space:
mode:
authorValentine Barshak <vbarshak@mvista.com>2010-12-06 10:16:11 -0500
committerJiri Kosina <jkosina@suse.cz>2010-12-07 09:45:50 -0500
commit33d6eb570b1f3fe5ba93cef465c5be66535c2c9a (patch)
treef863fc60990f851bb7d9af3d9b4791c80634becb /drivers/hid/usbhid/hiddev.c
parent1a8e8fab790ea7af81b8f964fdec706ad1ec2271 (diff)
HID: Consolidate device existence checks in hiddev_ioctl
Currently, if the device has been removed before hiddev_ioctl(), the -EIO is returned. If it's removed while hiddev_ioctl() is in progress, some commands are still processed fine, others return -ENODEV. This change takes the "existancelock" before processing ioctl commands and releases it at the end. If the device has been removed, always returns -ENODEV. Signed-off-by: Valentine Barshak <vbarshak@mvista.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/usbhid/hiddev.c')
-rw-r--r--drivers/hid/usbhid/hiddev.c287
1 files changed, 103 insertions, 184 deletions
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index ffee7f205fd5..a9935f6709f7 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -587,221 +587,167 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
587 struct hiddev_list *list = file->private_data; 587 struct hiddev_list *list = file->private_data;
588 struct hiddev *hiddev = list->hiddev; 588 struct hiddev *hiddev = list->hiddev;
589 struct hid_device *hid; 589 struct hid_device *hid;
590 struct usb_device *dev;
591 struct hiddev_collection_info cinfo; 590 struct hiddev_collection_info cinfo;
592 struct hiddev_report_info rinfo; 591 struct hiddev_report_info rinfo;
593 struct hiddev_field_info finfo; 592 struct hiddev_field_info finfo;
594 struct hiddev_devinfo dinfo; 593 struct hiddev_devinfo dinfo;
595 struct hid_report *report; 594 struct hid_report *report;
596 struct hid_field *field; 595 struct hid_field *field;
597 struct usbhid_device *usbhid;
598 void __user *user_arg = (void __user *)arg; 596 void __user *user_arg = (void __user *)arg;
599 int i, r; 597 int i, r = -EINVAL;
600 598
601 /* Called without BKL by compat methods so no BKL taken */ 599 /* Called without BKL by compat methods so no BKL taken */
602 600
603 /* FIXME: Who or what stop this racing with a disconnect ?? */ 601 mutex_lock(&hiddev->existancelock);
604 if (!hiddev->exist) 602 if (!hiddev->exist) {
605 return -EIO; 603 r = -ENODEV;
604 goto ret_unlock;
605 }
606
607 hid = hiddev->hid;
606 608
607 switch (cmd) { 609 switch (cmd) {
608 610
609 case HIDIOCGVERSION: 611 case HIDIOCGVERSION:
610 return put_user(HID_VERSION, (int __user *)arg); 612 r = put_user(HID_VERSION, (int __user *)arg) ?
613 -EFAULT : 0;
614 break;
611 615
612 case HIDIOCAPPLICATION: 616 case HIDIOCAPPLICATION:
613 mutex_lock(&hiddev->existancelock); 617 if (arg < 0 || arg >= hid->maxapplication)
614 if (!hiddev->exist) { 618 break;
615 r = -ENODEV;
616 goto ret_unlock;
617 }
618
619 hid = hiddev->hid;
620 if (arg < 0 || arg >= hid->maxapplication) {
621 r = -EINVAL;
622 goto ret_unlock;
623 }
624 619
625 for (i = 0; i < hid->maxcollection; i++) 620 for (i = 0; i < hid->maxcollection; i++)
626 if (hid->collection[i].type == 621 if (hid->collection[i].type ==
627 HID_COLLECTION_APPLICATION && arg-- == 0) 622 HID_COLLECTION_APPLICATION && arg-- == 0)
628 break; 623 break;
629 624
630 if (i == hid->maxcollection) 625 if (i < hid->maxcollection)
631 r = -EINVAL;
632 else
633 r = hid->collection[i].usage; 626 r = hid->collection[i].usage;
634 goto ret_unlock; 627 break;
635 628
636 case HIDIOCGDEVINFO: 629 case HIDIOCGDEVINFO:
637 mutex_lock(&hiddev->existancelock); 630 {
638 if (!hiddev->exist) { 631 struct usb_device *dev = hid_to_usb_dev(hid);
639 r = -ENODEV; 632 struct usbhid_device *usbhid = hid->driver_data;
640 goto ret_unlock; 633
634 dinfo.bustype = BUS_USB;
635 dinfo.busnum = dev->bus->busnum;
636 dinfo.devnum = dev->devnum;
637 dinfo.ifnum = usbhid->ifnum;
638 dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
639 dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
640 dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
641 dinfo.num_applications = hid->maxapplication;
642
643 r = copy_to_user(user_arg, &dinfo, sizeof(dinfo)) ?
644 -EFAULT : 0;
645 break;
641 } 646 }
642 647
643 hid = hiddev->hid;
644 dev = hid_to_usb_dev(hid);
645 usbhid = hid->driver_data;
646
647 dinfo.bustype = BUS_USB;
648 dinfo.busnum = dev->bus->busnum;
649 dinfo.devnum = dev->devnum;
650 dinfo.ifnum = usbhid->ifnum;
651 dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
652 dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
653 dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
654 dinfo.num_applications = hid->maxapplication;
655 mutex_unlock(&hiddev->existancelock);
656
657 if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
658 return -EFAULT;
659
660 return 0;
661
662 case HIDIOCGFLAG: 648 case HIDIOCGFLAG:
663 if (put_user(list->flags, (int __user *)arg)) 649 r = put_user(list->flags, (int __user *)arg) ?
664 return -EFAULT; 650 -EFAULT : 0;
665 651 break;
666 return 0;
667 652
668 case HIDIOCSFLAG: 653 case HIDIOCSFLAG:
669 { 654 {
670 int newflags; 655 int newflags;
671 if (get_user(newflags, (int __user *)arg)) 656
672 return -EFAULT; 657 if (get_user(newflags, (int __user *)arg)) {
658 r = -EFAULT;
659 break;
660 }
673 661
674 if ((newflags & ~HIDDEV_FLAGS) != 0 || 662 if ((newflags & ~HIDDEV_FLAGS) != 0 ||
675 ((newflags & HIDDEV_FLAG_REPORT) != 0 && 663 ((newflags & HIDDEV_FLAG_REPORT) != 0 &&
676 (newflags & HIDDEV_FLAG_UREF) == 0)) 664 (newflags & HIDDEV_FLAG_UREF) == 0))
677 return -EINVAL; 665 break;
678 666
679 list->flags = newflags; 667 list->flags = newflags;
680 668
681 return 0; 669 r = 0;
670 break;
682 } 671 }
683 672
684 case HIDIOCGSTRING: 673 case HIDIOCGSTRING:
685 mutex_lock(&hiddev->existancelock); 674 r = hiddev_ioctl_string(hiddev, cmd, user_arg);
686 if (hiddev->exist) 675 break;
687 r = hiddev_ioctl_string(hiddev, cmd, user_arg);
688 else
689 r = -ENODEV;
690ret_unlock:
691 mutex_unlock(&hiddev->existancelock);
692 return r;
693 676
694 case HIDIOCINITREPORT: 677 case HIDIOCINITREPORT:
695 mutex_lock(&hiddev->existancelock);
696 if (!hiddev->exist) {
697 mutex_unlock(&hiddev->existancelock);
698 return -ENODEV;
699 }
700 hid = hiddev->hid;
701 usbhid_init_reports(hid); 678 usbhid_init_reports(hid);
702 mutex_unlock(&hiddev->existancelock); 679 r = 0;
703 680 break;
704 return 0;
705 681
706 case HIDIOCGREPORT: 682 case HIDIOCGREPORT:
707 if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) 683 if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
708 return -EFAULT; 684 r = -EFAULT;
685 break;
686 }
709 687
710 if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT) 688 if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT)
711 return -EINVAL; 689 break;
712 690
713 mutex_lock(&hiddev->existancelock);
714 if (!hiddev->exist) {
715 r = -ENODEV;
716 goto ret_unlock;
717 }
718
719 hid = hiddev->hid;
720 report = hiddev_lookup_report(hid, &rinfo); 691 report = hiddev_lookup_report(hid, &rinfo);
721 if (report == NULL) { 692 if (report == NULL)
722 r = -EINVAL; 693 break;
723 goto ret_unlock;
724 }
725 694
726 usbhid_submit_report(hid, report, USB_DIR_IN); 695 usbhid_submit_report(hid, report, USB_DIR_IN);
727 usbhid_wait_io(hid); 696 usbhid_wait_io(hid);
728 mutex_unlock(&hiddev->existancelock);
729 697
730 return 0; 698 r = 0;
699 break;
731 700
732 case HIDIOCSREPORT: 701 case HIDIOCSREPORT:
733 if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) 702 if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
734 return -EFAULT; 703 r = -EFAULT;
704 break;
705 }
735 706
736 if (rinfo.report_type == HID_REPORT_TYPE_INPUT) 707 if (rinfo.report_type == HID_REPORT_TYPE_INPUT)
737 return -EINVAL; 708 break;
738
739 mutex_lock(&hiddev->existancelock);
740 if (!hiddev->exist) {
741 r = -ENODEV;
742 goto ret_unlock;
743 }
744 709
745 hid = hiddev->hid;
746 report = hiddev_lookup_report(hid, &rinfo); 710 report = hiddev_lookup_report(hid, &rinfo);
747 if (report == NULL) { 711 if (report == NULL)
748 r = -EINVAL; 712 break;
749 goto ret_unlock;
750 }
751 713
752 usbhid_submit_report(hid, report, USB_DIR_OUT); 714 usbhid_submit_report(hid, report, USB_DIR_OUT);
753 usbhid_wait_io(hid); 715 usbhid_wait_io(hid);
754 mutex_unlock(&hiddev->existancelock);
755 716
756 return 0; 717 r = 0;
718 break;
757 719
758 case HIDIOCGREPORTINFO: 720 case HIDIOCGREPORTINFO:
759 if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) 721 if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
760 return -EFAULT; 722 r = -EFAULT;
761 723 break;
762 mutex_lock(&hiddev->existancelock);
763 if (!hiddev->exist) {
764 r = -ENODEV;
765 goto ret_unlock;
766 } 724 }
767 725
768 hid = hiddev->hid;
769 report = hiddev_lookup_report(hid, &rinfo); 726 report = hiddev_lookup_report(hid, &rinfo);
770 if (report == NULL) { 727 if (report == NULL)
771 r = -EINVAL; 728 break;
772 goto ret_unlock;
773 }
774 729
775 rinfo.num_fields = report->maxfield; 730 rinfo.num_fields = report->maxfield;
776 mutex_unlock(&hiddev->existancelock);
777
778 if (copy_to_user(user_arg, &rinfo, sizeof(rinfo)))
779 return -EFAULT;
780 731
781 return 0; 732 r = copy_to_user(user_arg, &rinfo, sizeof(rinfo)) ?
733 -EFAULT : 0;
734 break;
782 735
783 case HIDIOCGFIELDINFO: 736 case HIDIOCGFIELDINFO:
784 if (copy_from_user(&finfo, user_arg, sizeof(finfo))) 737 if (copy_from_user(&finfo, user_arg, sizeof(finfo))) {
785 return -EFAULT; 738 r = -EFAULT;
739 break;
740 }
741
786 rinfo.report_type = finfo.report_type; 742 rinfo.report_type = finfo.report_type;
787 rinfo.report_id = finfo.report_id; 743 rinfo.report_id = finfo.report_id;
788 mutex_lock(&hiddev->existancelock);
789 if (!hiddev->exist) {
790 r = -ENODEV;
791 goto ret_unlock;
792 }
793 744
794 hid = hiddev->hid;
795 report = hiddev_lookup_report(hid, &rinfo); 745 report = hiddev_lookup_report(hid, &rinfo);
796 if (report == NULL) { 746 if (report == NULL)
797 r = -EINVAL; 747 break;
798 goto ret_unlock;
799 }
800 748
801 if (finfo.field_index >= report->maxfield) { 749 if (finfo.field_index >= report->maxfield)
802 r = -EINVAL; 750 break;
803 goto ret_unlock;
804 }
805 751
806 field = report->field[finfo.field_index]; 752 field = report->field[finfo.field_index];
807 memset(&finfo, 0, sizeof(finfo)); 753 memset(&finfo, 0, sizeof(finfo));
@@ -819,12 +765,10 @@ ret_unlock:
819 finfo.physical_maximum = field->physical_maximum; 765 finfo.physical_maximum = field->physical_maximum;
820 finfo.unit_exponent = field->unit_exponent; 766 finfo.unit_exponent = field->unit_exponent;
821 finfo.unit = field->unit; 767 finfo.unit = field->unit;
822 mutex_unlock(&hiddev->existancelock);
823 768
824 if (copy_to_user(user_arg, &finfo, sizeof(finfo))) 769 r = copy_to_user(user_arg, &finfo, sizeof(finfo)) ?
825 return -EFAULT; 770 -EFAULT : 0;
826 771 break;
827 return 0;
828 772
829 case HIDIOCGUCODE: 773 case HIDIOCGUCODE:
830 /* fall through */ 774 /* fall through */
@@ -833,57 +777,36 @@ ret_unlock:
833 case HIDIOCGUSAGES: 777 case HIDIOCGUSAGES:
834 case HIDIOCSUSAGES: 778 case HIDIOCSUSAGES:
835 case HIDIOCGCOLLECTIONINDEX: 779 case HIDIOCGCOLLECTIONINDEX:
836 mutex_lock(&hiddev->existancelock); 780 r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
837 if (hiddev->exist) 781 break;
838 r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
839 else
840 r = -ENODEV;
841 mutex_unlock(&hiddev->existancelock);
842 return r;
843 782
844 case HIDIOCGCOLLECTIONINFO: 783 case HIDIOCGCOLLECTIONINFO:
845 if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) 784 if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) {
846 return -EFAULT; 785 r = -EFAULT;
847 786 break;
848 mutex_lock(&hiddev->existancelock);
849 if (!hiddev->exist) {
850 r = -ENODEV;
851 goto ret_unlock;
852 } 787 }
853 788
854 hid = hiddev->hid; 789 if (cinfo.index >= hid->maxcollection)
855 if (cinfo.index >= hid->maxcollection) { 790 break;
856 r = -EINVAL;
857 goto ret_unlock;
858 }
859 791
860 cinfo.type = hid->collection[cinfo.index].type; 792 cinfo.type = hid->collection[cinfo.index].type;
861 cinfo.usage = hid->collection[cinfo.index].usage; 793 cinfo.usage = hid->collection[cinfo.index].usage;
862 cinfo.level = hid->collection[cinfo.index].level; 794 cinfo.level = hid->collection[cinfo.index].level;
863 mutex_lock(&hiddev->existancelock);
864 795
865 if (copy_to_user(user_arg, &cinfo, sizeof(cinfo))) 796 r = copy_to_user(user_arg, &cinfo, sizeof(cinfo)) ?
866 return -EFAULT; 797 -EFAULT : 0;
867 return 0; 798 break;
868 799
869 default: 800 default:
870
871 if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ) 801 if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)
872 return -EINVAL; 802 break;
873 803
874 if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) { 804 if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) {
875 int len; 805 int len;
876 806
877 mutex_lock(&hiddev->existancelock);
878 if (!hiddev->exist) {
879 r = -ENODEV;
880 goto ret_unlock;
881 }
882
883 hid = hiddev->hid;
884 if (!hid->name) { 807 if (!hid->name) {
885 r = 0; 808 r = 0;
886 goto ret_unlock; 809 break;
887 } 810 }
888 811
889 len = strlen(hid->name) + 1; 812 len = strlen(hid->name) + 1;
@@ -891,22 +814,15 @@ ret_unlock:
891 len = _IOC_SIZE(cmd); 814 len = _IOC_SIZE(cmd);
892 r = copy_to_user(user_arg, hid->name, len) ? 815 r = copy_to_user(user_arg, hid->name, len) ?
893 -EFAULT : len; 816 -EFAULT : len;
894 goto ret_unlock; 817 break;
895 } 818 }
896 819
897 if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) { 820 if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
898 int len; 821 int len;
899 822
900 mutex_lock(&hiddev->existancelock);
901 if (!hiddev->exist) {
902 r = -ENODEV;
903 goto ret_unlock;
904 }
905
906 hid = hiddev->hid;
907 if (!hid->phys) { 823 if (!hid->phys) {
908 r = 0; 824 r = 0;
909 goto ret_unlock; 825 break;
910 } 826 }
911 827
912 len = strlen(hid->phys) + 1; 828 len = strlen(hid->phys) + 1;
@@ -914,10 +830,13 @@ ret_unlock:
914 len = _IOC_SIZE(cmd); 830 len = _IOC_SIZE(cmd);
915 r = copy_to_user(user_arg, hid->phys, len) ? 831 r = copy_to_user(user_arg, hid->phys, len) ?
916 -EFAULT : len; 832 -EFAULT : len;
917 goto ret_unlock; 833 break;
918 } 834 }
919 } 835 }
920 return -EINVAL; 836
837ret_unlock:
838 mutex_unlock(&hiddev->existancelock);
839 return r;
921} 840}
922 841
923#ifdef CONFIG_COMPAT 842#ifdef CONFIG_COMPAT