| .. | .. |
|---|
| 44 | 44 | |
|---|
| 45 | 45 | #include "usb.h" |
|---|
| 46 | 46 | |
|---|
| 47 | +#ifdef CONFIG_PM |
|---|
| 48 | +#define MAYBE_CAP_SUSPEND USBDEVFS_CAP_SUSPEND |
|---|
| 49 | +#else |
|---|
| 50 | +#define MAYBE_CAP_SUSPEND 0 |
|---|
| 51 | +#endif |
|---|
| 52 | + |
|---|
| 47 | 53 | #define USB_MAXBUS 64 |
|---|
| 48 | 54 | #define USB_DEVICE_MAX (USB_MAXBUS * 128) |
|---|
| 49 | 55 | #define USB_SG_SIZE 16384 /* split-size for large txs */ |
|---|
| 50 | 56 | |
|---|
| 51 | | -/* Mutual exclusion for removal, open, and release */ |
|---|
| 52 | | -DEFINE_MUTEX(usbfs_mutex); |
|---|
| 57 | +/* Mutual exclusion for ps->list in resume vs. release and remove */ |
|---|
| 58 | +static DEFINE_MUTEX(usbfs_mutex); |
|---|
| 53 | 59 | |
|---|
| 54 | 60 | struct usb_dev_state { |
|---|
| 55 | 61 | struct list_head list; /* state list */ |
|---|
| .. | .. |
|---|
| 60 | 66 | struct list_head async_completed; |
|---|
| 61 | 67 | struct list_head memory_list; |
|---|
| 62 | 68 | wait_queue_head_t wait; /* wake up if a request completed */ |
|---|
| 69 | + wait_queue_head_t wait_for_resume; /* wake up upon runtime resume */ |
|---|
| 63 | 70 | unsigned int discsignr; |
|---|
| 64 | 71 | struct pid *disc_pid; |
|---|
| 65 | 72 | const struct cred *cred; |
|---|
| 66 | | - void __user *disccontext; |
|---|
| 73 | + sigval_t disccontext; |
|---|
| 67 | 74 | unsigned long ifclaimed; |
|---|
| 68 | 75 | u32 disabled_bulk_eps; |
|---|
| 69 | | - bool privileges_dropped; |
|---|
| 70 | 76 | unsigned long interface_allowed_mask; |
|---|
| 77 | + int not_yet_resumed; |
|---|
| 78 | + bool suspend_allowed; |
|---|
| 79 | + bool privileges_dropped; |
|---|
| 71 | 80 | }; |
|---|
| 72 | 81 | |
|---|
| 73 | 82 | struct usb_memory { |
|---|
| .. | .. |
|---|
| 90 | 99 | unsigned int ifnum; |
|---|
| 91 | 100 | void __user *userbuffer; |
|---|
| 92 | 101 | void __user *userurb; |
|---|
| 102 | + sigval_t userurb_sigval; |
|---|
| 93 | 103 | struct urb *urb; |
|---|
| 94 | 104 | struct usb_memory *usbm; |
|---|
| 95 | 105 | unsigned int mem_usage; |
|---|
| .. | .. |
|---|
| 207 | 217 | { |
|---|
| 208 | 218 | struct usb_memory *usbm = NULL; |
|---|
| 209 | 219 | struct usb_dev_state *ps = file->private_data; |
|---|
| 220 | + struct usb_hcd *hcd = bus_to_hcd(ps->dev->bus); |
|---|
| 210 | 221 | size_t size = vma->vm_end - vma->vm_start; |
|---|
| 211 | 222 | void *mem; |
|---|
| 212 | 223 | unsigned long flags; |
|---|
| .. | .. |
|---|
| 240 | 251 | usbm->vma_use_count = 1; |
|---|
| 241 | 252 | INIT_LIST_HEAD(&usbm->memlist); |
|---|
| 242 | 253 | |
|---|
| 243 | | - if (remap_pfn_range(vma, vma->vm_start, |
|---|
| 244 | | - virt_to_phys(usbm->mem) >> PAGE_SHIFT, |
|---|
| 245 | | - size, vma->vm_page_prot) < 0) { |
|---|
| 246 | | - dec_usb_memory_use_count(usbm, &usbm->vma_use_count); |
|---|
| 247 | | - return -EAGAIN; |
|---|
| 254 | + if (hcd->localmem_pool || !hcd_uses_dma(hcd)) { |
|---|
| 255 | + if (remap_pfn_range(vma, vma->vm_start, |
|---|
| 256 | + virt_to_phys(usbm->mem) >> PAGE_SHIFT, |
|---|
| 257 | + size, vma->vm_page_prot) < 0) { |
|---|
| 258 | + dec_usb_memory_use_count(usbm, &usbm->vma_use_count); |
|---|
| 259 | + return -EAGAIN; |
|---|
| 260 | + } |
|---|
| 261 | + } else { |
|---|
| 262 | + if (dma_mmap_coherent(hcd->self.sysdev, vma, mem, dma_handle, |
|---|
| 263 | + size)) { |
|---|
| 264 | + dec_usb_memory_use_count(usbm, &usbm->vma_use_count); |
|---|
| 265 | + return -EAGAIN; |
|---|
| 266 | + } |
|---|
| 248 | 267 | } |
|---|
| 249 | 268 | |
|---|
| 250 | 269 | vma->vm_flags |= VM_IO; |
|---|
| .. | .. |
|---|
| 564 | 583 | |
|---|
| 565 | 584 | /* Now carefully unlink all the marked pending URBs */ |
|---|
| 566 | 585 | rescan: |
|---|
| 567 | | - list_for_each_entry(as, &ps->async_pending, asynclist) { |
|---|
| 586 | + list_for_each_entry_reverse(as, &ps->async_pending, asynclist) { |
|---|
| 568 | 587 | if (as->bulk_status == AS_UNLINK) { |
|---|
| 569 | 588 | as->bulk_status = 0; /* Only once */ |
|---|
| 570 | 589 | urb = as->urb; |
|---|
| .. | .. |
|---|
| 582 | 601 | { |
|---|
| 583 | 602 | struct async *as = urb->context; |
|---|
| 584 | 603 | struct usb_dev_state *ps = as->ps; |
|---|
| 585 | | - struct siginfo sinfo; |
|---|
| 586 | 604 | struct pid *pid = NULL; |
|---|
| 587 | 605 | const struct cred *cred = NULL; |
|---|
| 588 | 606 | unsigned long flags; |
|---|
| 589 | | - int signr; |
|---|
| 607 | + sigval_t addr; |
|---|
| 608 | + int signr, errno; |
|---|
| 590 | 609 | |
|---|
| 591 | 610 | spin_lock_irqsave(&ps->lock, flags); |
|---|
| 592 | 611 | list_move_tail(&as->asynclist, &ps->async_completed); |
|---|
| 593 | 612 | as->status = urb->status; |
|---|
| 594 | 613 | signr = as->signr; |
|---|
| 595 | 614 | if (signr) { |
|---|
| 596 | | - clear_siginfo(&sinfo); |
|---|
| 597 | | - sinfo.si_signo = as->signr; |
|---|
| 598 | | - sinfo.si_errno = as->status; |
|---|
| 599 | | - sinfo.si_code = SI_ASYNCIO; |
|---|
| 600 | | - sinfo.si_addr = as->userurb; |
|---|
| 615 | + errno = as->status; |
|---|
| 616 | + addr = as->userurb_sigval; |
|---|
| 601 | 617 | pid = get_pid(as->pid); |
|---|
| 602 | 618 | cred = get_cred(as->cred); |
|---|
| 603 | 619 | } |
|---|
| 604 | 620 | snoop(&urb->dev->dev, "urb complete\n"); |
|---|
| 605 | 621 | snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length, |
|---|
| 606 | 622 | as->status, COMPLETE, NULL, 0); |
|---|
| 607 | | - if ((urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN) |
|---|
| 623 | + if (usb_urb_dir_in(urb)) |
|---|
| 608 | 624 | snoop_urb_data(urb, urb->actual_length); |
|---|
| 609 | 625 | |
|---|
| 610 | 626 | if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET && |
|---|
| .. | .. |
|---|
| 615 | 631 | spin_unlock_irqrestore(&ps->lock, flags); |
|---|
| 616 | 632 | |
|---|
| 617 | 633 | if (signr) { |
|---|
| 618 | | - kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred); |
|---|
| 634 | + kill_pid_usb_asyncio(signr, errno, addr, pid, cred); |
|---|
| 619 | 635 | put_pid(pid); |
|---|
| 620 | 636 | put_cred(cred); |
|---|
| 621 | 637 | } |
|---|
| .. | .. |
|---|
| 629 | 645 | |
|---|
| 630 | 646 | spin_lock_irqsave(&ps->lock, flags); |
|---|
| 631 | 647 | while (!list_empty(list)) { |
|---|
| 632 | | - as = list_entry(list->next, struct async, asynclist); |
|---|
| 648 | + as = list_last_entry(list, struct async, asynclist); |
|---|
| 633 | 649 | list_del_init(&as->asynclist); |
|---|
| 634 | 650 | urb = as->urb; |
|---|
| 635 | 651 | usb_get_urb(urb); |
|---|
| .. | .. |
|---|
| 699 | 715 | destroy_async_on_interface(ps, ifnum); |
|---|
| 700 | 716 | } |
|---|
| 701 | 717 | |
|---|
| 702 | | -/* The following routines are merely placeholders. There is no way |
|---|
| 703 | | - * to inform a user task about suspend or resumes. |
|---|
| 704 | | - */ |
|---|
| 718 | +/* We don't care about suspend/resume of claimed interfaces */ |
|---|
| 705 | 719 | static int driver_suspend(struct usb_interface *intf, pm_message_t msg) |
|---|
| 706 | 720 | { |
|---|
| 707 | 721 | return 0; |
|---|
| .. | .. |
|---|
| 712 | 726 | return 0; |
|---|
| 713 | 727 | } |
|---|
| 714 | 728 | |
|---|
| 729 | +/* The following routines apply to the entire device, not interfaces */ |
|---|
| 730 | +void usbfs_notify_suspend(struct usb_device *udev) |
|---|
| 731 | +{ |
|---|
| 732 | + /* We don't need to handle this */ |
|---|
| 733 | +} |
|---|
| 734 | + |
|---|
| 735 | +void usbfs_notify_resume(struct usb_device *udev) |
|---|
| 736 | +{ |
|---|
| 737 | + struct usb_dev_state *ps; |
|---|
| 738 | + |
|---|
| 739 | + /* Protect against simultaneous remove or release */ |
|---|
| 740 | + mutex_lock(&usbfs_mutex); |
|---|
| 741 | + list_for_each_entry(ps, &udev->filelist, list) { |
|---|
| 742 | + WRITE_ONCE(ps->not_yet_resumed, 0); |
|---|
| 743 | + wake_up_all(&ps->wait_for_resume); |
|---|
| 744 | + } |
|---|
| 745 | + mutex_unlock(&usbfs_mutex); |
|---|
| 746 | +} |
|---|
| 747 | + |
|---|
| 715 | 748 | struct usb_driver usbfs_driver = { |
|---|
| 716 | 749 | .name = "usbfs", |
|---|
| 717 | 750 | .probe = driver_probe, |
|---|
| 718 | 751 | .disconnect = driver_disconnect, |
|---|
| 719 | 752 | .suspend = driver_suspend, |
|---|
| 720 | 753 | .resume = driver_resume, |
|---|
| 754 | + .supports_autosuspend = 1, |
|---|
| 721 | 755 | }; |
|---|
| 722 | 756 | |
|---|
| 723 | 757 | static int claimintf(struct usb_dev_state *ps, unsigned int ifnum) |
|---|
| .. | .. |
|---|
| 960 | 994 | return ret; |
|---|
| 961 | 995 | } |
|---|
| 962 | 996 | |
|---|
| 963 | | -static int match_devt(struct device *dev, void *data) |
|---|
| 964 | | -{ |
|---|
| 965 | | - return dev->devt == (dev_t) (unsigned long) data; |
|---|
| 966 | | -} |
|---|
| 967 | | - |
|---|
| 968 | 997 | static struct usb_device *usbdev_lookup_by_devt(dev_t devt) |
|---|
| 969 | 998 | { |
|---|
| 970 | 999 | struct device *dev; |
|---|
| 971 | 1000 | |
|---|
| 972 | | - dev = bus_find_device(&usb_bus_type, NULL, |
|---|
| 973 | | - (void *) (unsigned long) devt, match_devt); |
|---|
| 1001 | + dev = bus_find_device_by_devt(&usb_bus_type, devt); |
|---|
| 974 | 1002 | if (!dev) |
|---|
| 975 | 1003 | return NULL; |
|---|
| 976 | 1004 | return to_usb_device(dev); |
|---|
| .. | .. |
|---|
| 992 | 1020 | |
|---|
| 993 | 1021 | ret = -ENODEV; |
|---|
| 994 | 1022 | |
|---|
| 995 | | - /* Protect against simultaneous removal or release */ |
|---|
| 996 | | - mutex_lock(&usbfs_mutex); |
|---|
| 997 | | - |
|---|
| 998 | 1023 | /* usbdev device-node */ |
|---|
| 999 | 1024 | if (imajor(inode) == USB_DEVICE_MAJOR) |
|---|
| 1000 | 1025 | dev = usbdev_lookup_by_devt(inode->i_rdev); |
|---|
| 1001 | | - |
|---|
| 1002 | | - mutex_unlock(&usbfs_mutex); |
|---|
| 1003 | | - |
|---|
| 1004 | 1026 | if (!dev) |
|---|
| 1005 | 1027 | goto out_free_ps; |
|---|
| 1006 | 1028 | |
|---|
| .. | .. |
|---|
| 1021 | 1043 | INIT_LIST_HEAD(&ps->async_completed); |
|---|
| 1022 | 1044 | INIT_LIST_HEAD(&ps->memory_list); |
|---|
| 1023 | 1045 | init_waitqueue_head(&ps->wait); |
|---|
| 1046 | + init_waitqueue_head(&ps->wait_for_resume); |
|---|
| 1024 | 1047 | ps->disc_pid = get_pid(task_pid(current)); |
|---|
| 1025 | 1048 | ps->cred = get_current_cred(); |
|---|
| 1026 | 1049 | smp_wmb(); |
|---|
| 1050 | + |
|---|
| 1051 | + /* Can't race with resume; the device is already active */ |
|---|
| 1027 | 1052 | list_add_tail(&ps->list, &dev->filelist); |
|---|
| 1028 | 1053 | file->private_data = ps; |
|---|
| 1029 | 1054 | usb_unlock_device(dev); |
|---|
| .. | .. |
|---|
| 1049 | 1074 | usb_lock_device(dev); |
|---|
| 1050 | 1075 | usb_hub_release_all_ports(dev, ps); |
|---|
| 1051 | 1076 | |
|---|
| 1077 | + /* Protect against simultaneous resume */ |
|---|
| 1078 | + mutex_lock(&usbfs_mutex); |
|---|
| 1052 | 1079 | list_del_init(&ps->list); |
|---|
| 1080 | + mutex_unlock(&usbfs_mutex); |
|---|
| 1053 | 1081 | |
|---|
| 1054 | 1082 | for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed); |
|---|
| 1055 | 1083 | ifnum++) { |
|---|
| .. | .. |
|---|
| 1057 | 1085 | releaseintf(ps, ifnum); |
|---|
| 1058 | 1086 | } |
|---|
| 1059 | 1087 | destroy_all_async(ps); |
|---|
| 1060 | | - usb_autosuspend_device(dev); |
|---|
| 1088 | + if (!ps->suspend_allowed) |
|---|
| 1089 | + usb_autosuspend_device(dev); |
|---|
| 1061 | 1090 | usb_unlock_device(dev); |
|---|
| 1062 | 1091 | usb_put_dev(dev); |
|---|
| 1063 | 1092 | put_pid(ps->disc_pid); |
|---|
| .. | .. |
|---|
| 1073 | 1102 | return 0; |
|---|
| 1074 | 1103 | } |
|---|
| 1075 | 1104 | |
|---|
| 1076 | | -static int proc_control(struct usb_dev_state *ps, void __user *arg) |
|---|
| 1105 | +static int do_proc_control(struct usb_dev_state *ps, |
|---|
| 1106 | + struct usbdevfs_ctrltransfer *ctrl) |
|---|
| 1077 | 1107 | { |
|---|
| 1078 | 1108 | struct usb_device *dev = ps->dev; |
|---|
| 1079 | | - struct usbdevfs_ctrltransfer ctrl; |
|---|
| 1080 | 1109 | unsigned int tmo; |
|---|
| 1081 | 1110 | unsigned char *tbuf; |
|---|
| 1082 | 1111 | unsigned wLength; |
|---|
| 1083 | 1112 | int i, pipe, ret; |
|---|
| 1084 | 1113 | |
|---|
| 1085 | | - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) |
|---|
| 1086 | | - return -EFAULT; |
|---|
| 1087 | | - ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.bRequest, |
|---|
| 1088 | | - ctrl.wIndex); |
|---|
| 1114 | + ret = check_ctrlrecip(ps, ctrl->bRequestType, ctrl->bRequest, |
|---|
| 1115 | + ctrl->wIndex); |
|---|
| 1089 | 1116 | if (ret) |
|---|
| 1090 | 1117 | return ret; |
|---|
| 1091 | | - wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */ |
|---|
| 1118 | + wLength = ctrl->wLength; /* To suppress 64k PAGE_SIZE warning */ |
|---|
| 1092 | 1119 | if (wLength > PAGE_SIZE) |
|---|
| 1093 | 1120 | return -EINVAL; |
|---|
| 1094 | 1121 | ret = usbfs_increase_memory_usage(PAGE_SIZE + sizeof(struct urb) + |
|---|
| .. | .. |
|---|
| 1100 | 1127 | ret = -ENOMEM; |
|---|
| 1101 | 1128 | goto done; |
|---|
| 1102 | 1129 | } |
|---|
| 1103 | | - tmo = ctrl.timeout; |
|---|
| 1130 | + tmo = ctrl->timeout; |
|---|
| 1104 | 1131 | snoop(&dev->dev, "control urb: bRequestType=%02x " |
|---|
| 1105 | 1132 | "bRequest=%02x wValue=%04x " |
|---|
| 1106 | 1133 | "wIndex=%04x wLength=%04x\n", |
|---|
| 1107 | | - ctrl.bRequestType, ctrl.bRequest, ctrl.wValue, |
|---|
| 1108 | | - ctrl.wIndex, ctrl.wLength); |
|---|
| 1109 | | - if (ctrl.bRequestType & 0x80) { |
|---|
| 1110 | | - if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, |
|---|
| 1111 | | - ctrl.wLength)) { |
|---|
| 1112 | | - ret = -EINVAL; |
|---|
| 1113 | | - goto done; |
|---|
| 1114 | | - } |
|---|
| 1134 | + ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, |
|---|
| 1135 | + ctrl->wIndex, ctrl->wLength); |
|---|
| 1136 | + if ((ctrl->bRequestType & USB_DIR_IN) && ctrl->wLength) { |
|---|
| 1115 | 1137 | pipe = usb_rcvctrlpipe(dev, 0); |
|---|
| 1116 | | - snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0); |
|---|
| 1138 | + snoop_urb(dev, NULL, pipe, ctrl->wLength, tmo, SUBMIT, NULL, 0); |
|---|
| 1117 | 1139 | |
|---|
| 1118 | 1140 | usb_unlock_device(dev); |
|---|
| 1119 | | - i = usb_control_msg(dev, pipe, ctrl.bRequest, |
|---|
| 1120 | | - ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, |
|---|
| 1121 | | - tbuf, ctrl.wLength, tmo); |
|---|
| 1141 | + i = usb_control_msg(dev, pipe, ctrl->bRequest, |
|---|
| 1142 | + ctrl->bRequestType, ctrl->wValue, ctrl->wIndex, |
|---|
| 1143 | + tbuf, ctrl->wLength, tmo); |
|---|
| 1122 | 1144 | usb_lock_device(dev); |
|---|
| 1123 | 1145 | snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, |
|---|
| 1124 | 1146 | tbuf, max(i, 0)); |
|---|
| 1125 | | - if ((i > 0) && ctrl.wLength) { |
|---|
| 1126 | | - if (copy_to_user(ctrl.data, tbuf, i)) { |
|---|
| 1147 | + if ((i > 0) && ctrl->wLength) { |
|---|
| 1148 | + if (copy_to_user(ctrl->data, tbuf, i)) { |
|---|
| 1127 | 1149 | ret = -EFAULT; |
|---|
| 1128 | 1150 | goto done; |
|---|
| 1129 | 1151 | } |
|---|
| 1130 | 1152 | } |
|---|
| 1131 | 1153 | } else { |
|---|
| 1132 | | - if (ctrl.wLength) { |
|---|
| 1133 | | - if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) { |
|---|
| 1154 | + if (ctrl->wLength) { |
|---|
| 1155 | + if (copy_from_user(tbuf, ctrl->data, ctrl->wLength)) { |
|---|
| 1134 | 1156 | ret = -EFAULT; |
|---|
| 1135 | 1157 | goto done; |
|---|
| 1136 | 1158 | } |
|---|
| 1137 | 1159 | } |
|---|
| 1138 | 1160 | pipe = usb_sndctrlpipe(dev, 0); |
|---|
| 1139 | | - snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, |
|---|
| 1140 | | - tbuf, ctrl.wLength); |
|---|
| 1161 | + snoop_urb(dev, NULL, pipe, ctrl->wLength, tmo, SUBMIT, |
|---|
| 1162 | + tbuf, ctrl->wLength); |
|---|
| 1141 | 1163 | |
|---|
| 1142 | 1164 | usb_unlock_device(dev); |
|---|
| 1143 | | - i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, |
|---|
| 1144 | | - ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, |
|---|
| 1145 | | - tbuf, ctrl.wLength, tmo); |
|---|
| 1165 | + i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl->bRequest, |
|---|
| 1166 | + ctrl->bRequestType, ctrl->wValue, ctrl->wIndex, |
|---|
| 1167 | + tbuf, ctrl->wLength, tmo); |
|---|
| 1146 | 1168 | usb_lock_device(dev); |
|---|
| 1147 | 1169 | snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0); |
|---|
| 1148 | 1170 | } |
|---|
| 1149 | 1171 | if (i < 0 && i != -EPIPE) { |
|---|
| 1150 | 1172 | dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL " |
|---|
| 1151 | 1173 | "failed cmd %s rqt %u rq %u len %u ret %d\n", |
|---|
| 1152 | | - current->comm, ctrl.bRequestType, ctrl.bRequest, |
|---|
| 1153 | | - ctrl.wLength, i); |
|---|
| 1174 | + current->comm, ctrl->bRequestType, ctrl->bRequest, |
|---|
| 1175 | + ctrl->wLength, i); |
|---|
| 1154 | 1176 | } |
|---|
| 1155 | 1177 | ret = i; |
|---|
| 1156 | 1178 | done: |
|---|
| .. | .. |
|---|
| 1160 | 1182 | return ret; |
|---|
| 1161 | 1183 | } |
|---|
| 1162 | 1184 | |
|---|
| 1163 | | -static int proc_bulk(struct usb_dev_state *ps, void __user *arg) |
|---|
| 1185 | +static int proc_control(struct usb_dev_state *ps, void __user *arg) |
|---|
| 1186 | +{ |
|---|
| 1187 | + struct usbdevfs_ctrltransfer ctrl; |
|---|
| 1188 | + |
|---|
| 1189 | + if (copy_from_user(&ctrl, arg, sizeof(ctrl))) |
|---|
| 1190 | + return -EFAULT; |
|---|
| 1191 | + return do_proc_control(ps, &ctrl); |
|---|
| 1192 | +} |
|---|
| 1193 | + |
|---|
| 1194 | +static int do_proc_bulk(struct usb_dev_state *ps, |
|---|
| 1195 | + struct usbdevfs_bulktransfer *bulk) |
|---|
| 1164 | 1196 | { |
|---|
| 1165 | 1197 | struct usb_device *dev = ps->dev; |
|---|
| 1166 | | - struct usbdevfs_bulktransfer bulk; |
|---|
| 1167 | 1198 | unsigned int tmo, len1, pipe; |
|---|
| 1168 | 1199 | int len2; |
|---|
| 1169 | 1200 | unsigned char *tbuf; |
|---|
| 1170 | 1201 | int i, ret; |
|---|
| 1171 | 1202 | |
|---|
| 1172 | | - if (copy_from_user(&bulk, arg, sizeof(bulk))) |
|---|
| 1173 | | - return -EFAULT; |
|---|
| 1174 | | - ret = findintfep(ps->dev, bulk.ep); |
|---|
| 1203 | + ret = findintfep(ps->dev, bulk->ep); |
|---|
| 1175 | 1204 | if (ret < 0) |
|---|
| 1176 | 1205 | return ret; |
|---|
| 1177 | 1206 | ret = checkintf(ps, ret); |
|---|
| 1178 | 1207 | if (ret) |
|---|
| 1179 | 1208 | return ret; |
|---|
| 1180 | | - if (bulk.ep & USB_DIR_IN) |
|---|
| 1181 | | - pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f); |
|---|
| 1209 | + if (bulk->ep & USB_DIR_IN) |
|---|
| 1210 | + pipe = usb_rcvbulkpipe(dev, bulk->ep & 0x7f); |
|---|
| 1182 | 1211 | else |
|---|
| 1183 | | - pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f); |
|---|
| 1184 | | - if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) |
|---|
| 1212 | + pipe = usb_sndbulkpipe(dev, bulk->ep & 0x7f); |
|---|
| 1213 | + if (!usb_maxpacket(dev, pipe, !(bulk->ep & USB_DIR_IN))) |
|---|
| 1185 | 1214 | return -EINVAL; |
|---|
| 1186 | | - len1 = bulk.len; |
|---|
| 1215 | + len1 = bulk->len; |
|---|
| 1187 | 1216 | if (len1 >= (INT_MAX - sizeof(struct urb))) |
|---|
| 1188 | 1217 | return -EINVAL; |
|---|
| 1189 | 1218 | ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); |
|---|
| .. | .. |
|---|
| 1199 | 1228 | ret = -ENOMEM; |
|---|
| 1200 | 1229 | goto done; |
|---|
| 1201 | 1230 | } |
|---|
| 1202 | | - tmo = bulk.timeout; |
|---|
| 1203 | | - if (bulk.ep & 0x80) { |
|---|
| 1204 | | - if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) { |
|---|
| 1205 | | - ret = -EINVAL; |
|---|
| 1206 | | - goto done; |
|---|
| 1207 | | - } |
|---|
| 1231 | + tmo = bulk->timeout; |
|---|
| 1232 | + if (bulk->ep & 0x80) { |
|---|
| 1208 | 1233 | snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0); |
|---|
| 1209 | 1234 | |
|---|
| 1210 | 1235 | usb_unlock_device(dev); |
|---|
| .. | .. |
|---|
| 1213 | 1238 | snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, tbuf, len2); |
|---|
| 1214 | 1239 | |
|---|
| 1215 | 1240 | if (!i && len2) { |
|---|
| 1216 | | - if (copy_to_user(bulk.data, tbuf, len2)) { |
|---|
| 1241 | + if (copy_to_user(bulk->data, tbuf, len2)) { |
|---|
| 1217 | 1242 | ret = -EFAULT; |
|---|
| 1218 | 1243 | goto done; |
|---|
| 1219 | 1244 | } |
|---|
| 1220 | 1245 | } |
|---|
| 1221 | 1246 | } else { |
|---|
| 1222 | 1247 | if (len1) { |
|---|
| 1223 | | - if (copy_from_user(tbuf, bulk.data, len1)) { |
|---|
| 1248 | + if (copy_from_user(tbuf, bulk->data, len1)) { |
|---|
| 1224 | 1249 | ret = -EFAULT; |
|---|
| 1225 | 1250 | goto done; |
|---|
| 1226 | 1251 | } |
|---|
| .. | .. |
|---|
| 1237 | 1262 | kfree(tbuf); |
|---|
| 1238 | 1263 | usbfs_decrease_memory_usage(len1 + sizeof(struct urb)); |
|---|
| 1239 | 1264 | return ret; |
|---|
| 1265 | +} |
|---|
| 1266 | + |
|---|
| 1267 | +static int proc_bulk(struct usb_dev_state *ps, void __user *arg) |
|---|
| 1268 | +{ |
|---|
| 1269 | + struct usbdevfs_bulktransfer bulk; |
|---|
| 1270 | + |
|---|
| 1271 | + if (copy_from_user(&bulk, arg, sizeof(bulk))) |
|---|
| 1272 | + return -EFAULT; |
|---|
| 1273 | + return do_proc_bulk(ps, &bulk); |
|---|
| 1240 | 1274 | } |
|---|
| 1241 | 1275 | |
|---|
| 1242 | 1276 | static void check_reset_of_active_ep(struct usb_device *udev, |
|---|
| .. | .. |
|---|
| 1323 | 1357 | |
|---|
| 1324 | 1358 | if (copy_to_user(arg, &ci, sizeof(ci))) |
|---|
| 1325 | 1359 | return -EFAULT; |
|---|
| 1360 | + return 0; |
|---|
| 1361 | +} |
|---|
| 1362 | + |
|---|
| 1363 | +static int proc_conninfo_ex(struct usb_dev_state *ps, |
|---|
| 1364 | + void __user *arg, size_t size) |
|---|
| 1365 | +{ |
|---|
| 1366 | + struct usbdevfs_conninfo_ex ci; |
|---|
| 1367 | + struct usb_device *udev = ps->dev; |
|---|
| 1368 | + |
|---|
| 1369 | + if (size < sizeof(ci.size)) |
|---|
| 1370 | + return -EINVAL; |
|---|
| 1371 | + |
|---|
| 1372 | + memset(&ci, 0, sizeof(ci)); |
|---|
| 1373 | + ci.size = sizeof(ci); |
|---|
| 1374 | + ci.busnum = udev->bus->busnum; |
|---|
| 1375 | + ci.devnum = udev->devnum; |
|---|
| 1376 | + ci.speed = udev->speed; |
|---|
| 1377 | + |
|---|
| 1378 | + while (udev && udev->portnum != 0) { |
|---|
| 1379 | + if (++ci.num_ports <= ARRAY_SIZE(ci.ports)) |
|---|
| 1380 | + ci.ports[ARRAY_SIZE(ci.ports) - ci.num_ports] = |
|---|
| 1381 | + udev->portnum; |
|---|
| 1382 | + udev = udev->parent; |
|---|
| 1383 | + } |
|---|
| 1384 | + |
|---|
| 1385 | + if (ci.num_ports < ARRAY_SIZE(ci.ports)) |
|---|
| 1386 | + memmove(&ci.ports[0], |
|---|
| 1387 | + &ci.ports[ARRAY_SIZE(ci.ports) - ci.num_ports], |
|---|
| 1388 | + ci.num_ports); |
|---|
| 1389 | + |
|---|
| 1390 | + if (copy_to_user(arg, &ci, min(sizeof(ci), size))) |
|---|
| 1391 | + return -EFAULT; |
|---|
| 1392 | + |
|---|
| 1326 | 1393 | return 0; |
|---|
| 1327 | 1394 | } |
|---|
| 1328 | 1395 | |
|---|
| .. | .. |
|---|
| 1445 | 1512 | |
|---|
| 1446 | 1513 | static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb, |
|---|
| 1447 | 1514 | struct usbdevfs_iso_packet_desc __user *iso_frame_desc, |
|---|
| 1448 | | - void __user *arg) |
|---|
| 1515 | + void __user *arg, sigval_t userurb_sigval) |
|---|
| 1449 | 1516 | { |
|---|
| 1450 | 1517 | struct usbdevfs_iso_packet_desc *isopkt = NULL; |
|---|
| 1451 | 1518 | struct usb_host_endpoint *ep; |
|---|
| .. | .. |
|---|
| 1504 | 1571 | ret = -EFAULT; |
|---|
| 1505 | 1572 | goto error; |
|---|
| 1506 | 1573 | } |
|---|
| 1507 | | - if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) { |
|---|
| 1574 | + if (uurb->buffer_length < (le16_to_cpu(dr->wLength) + 8)) { |
|---|
| 1508 | 1575 | ret = -EINVAL; |
|---|
| 1509 | 1576 | goto error; |
|---|
| 1510 | 1577 | } |
|---|
| 1511 | 1578 | ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest, |
|---|
| 1512 | | - le16_to_cpup(&dr->wIndex)); |
|---|
| 1579 | + le16_to_cpu(dr->wIndex)); |
|---|
| 1513 | 1580 | if (ret) |
|---|
| 1514 | 1581 | goto error; |
|---|
| 1515 | | - uurb->buffer_length = le16_to_cpup(&dr->wLength); |
|---|
| 1582 | + uurb->buffer_length = le16_to_cpu(dr->wLength); |
|---|
| 1516 | 1583 | uurb->buffer += 8; |
|---|
| 1517 | 1584 | if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) { |
|---|
| 1518 | | - is_in = 1; |
|---|
| 1585 | + is_in = true; |
|---|
| 1519 | 1586 | uurb->endpoint |= USB_DIR_IN; |
|---|
| 1520 | 1587 | } else { |
|---|
| 1521 | | - is_in = 0; |
|---|
| 1588 | + is_in = false; |
|---|
| 1522 | 1589 | uurb->endpoint &= ~USB_DIR_IN; |
|---|
| 1523 | 1590 | } |
|---|
| 1524 | 1591 | if (is_in) |
|---|
| .. | .. |
|---|
| 1527 | 1594 | "bRequest=%02x wValue=%04x " |
|---|
| 1528 | 1595 | "wIndex=%04x wLength=%04x\n", |
|---|
| 1529 | 1596 | dr->bRequestType, dr->bRequest, |
|---|
| 1530 | | - __le16_to_cpup(&dr->wValue), |
|---|
| 1531 | | - __le16_to_cpup(&dr->wIndex), |
|---|
| 1532 | | - __le16_to_cpup(&dr->wLength)); |
|---|
| 1597 | + __le16_to_cpu(dr->wValue), |
|---|
| 1598 | + __le16_to_cpu(dr->wIndex), |
|---|
| 1599 | + __le16_to_cpu(dr->wLength)); |
|---|
| 1533 | 1600 | u = sizeof(struct usb_ctrlrequest); |
|---|
| 1534 | 1601 | break; |
|---|
| 1535 | 1602 | |
|---|
| .. | .. |
|---|
| 1582 | 1649 | } |
|---|
| 1583 | 1650 | for (totlen = u = 0; u < number_of_packets; u++) { |
|---|
| 1584 | 1651 | /* |
|---|
| 1585 | | - * arbitrary limit need for USB 3.0 |
|---|
| 1586 | | - * bMaxBurst (0~15 allowed, 1~16 packets) |
|---|
| 1587 | | - * bmAttributes (bit 1:0, mult 0~2, 1~3 packets) |
|---|
| 1588 | | - * sizemax: 1024 * 16 * 3 = 49152 |
|---|
| 1652 | + * arbitrary limit need for USB 3.1 Gen2 |
|---|
| 1653 | + * sizemax: 96 DPs at SSP, 96 * 1024 = 98304 |
|---|
| 1589 | 1654 | */ |
|---|
| 1590 | | - if (isopkt[u].length > 49152) { |
|---|
| 1655 | + if (isopkt[u].length > 98304) { |
|---|
| 1591 | 1656 | ret = -EINVAL; |
|---|
| 1592 | 1657 | goto error; |
|---|
| 1593 | 1658 | } |
|---|
| .. | .. |
|---|
| 1602 | 1667 | } |
|---|
| 1603 | 1668 | |
|---|
| 1604 | 1669 | if (uurb->buffer_length > 0 && |
|---|
| 1605 | | - !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, |
|---|
| 1606 | | - uurb->buffer, uurb->buffer_length)) { |
|---|
| 1670 | + !access_ok(uurb->buffer, uurb->buffer_length)) { |
|---|
| 1607 | 1671 | ret = -EFAULT; |
|---|
| 1608 | 1672 | goto error; |
|---|
| 1609 | 1673 | } |
|---|
| .. | .. |
|---|
| 1626 | 1690 | if (as->usbm) |
|---|
| 1627 | 1691 | num_sgs = 0; |
|---|
| 1628 | 1692 | |
|---|
| 1629 | | - u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length + |
|---|
| 1693 | + u += sizeof(struct async) + sizeof(struct urb) + |
|---|
| 1694 | + (as->usbm ? 0 : uurb->buffer_length) + |
|---|
| 1630 | 1695 | num_sgs * sizeof(struct scatterlist); |
|---|
| 1631 | 1696 | ret = usbfs_increase_memory_usage(u); |
|---|
| 1632 | 1697 | if (ret) |
|---|
| .. | .. |
|---|
| 1748 | 1813 | isopkt = NULL; |
|---|
| 1749 | 1814 | as->ps = ps; |
|---|
| 1750 | 1815 | as->userurb = arg; |
|---|
| 1816 | + as->userurb_sigval = userurb_sigval; |
|---|
| 1751 | 1817 | if (as->usbm) { |
|---|
| 1752 | 1818 | unsigned long uurb_start = (unsigned long)uurb->buffer; |
|---|
| 1753 | 1819 | |
|---|
| .. | .. |
|---|
| 1820 | 1886 | static int proc_submiturb(struct usb_dev_state *ps, void __user *arg) |
|---|
| 1821 | 1887 | { |
|---|
| 1822 | 1888 | struct usbdevfs_urb uurb; |
|---|
| 1889 | + sigval_t userurb_sigval; |
|---|
| 1823 | 1890 | |
|---|
| 1824 | 1891 | if (copy_from_user(&uurb, arg, sizeof(uurb))) |
|---|
| 1825 | 1892 | return -EFAULT; |
|---|
| 1826 | 1893 | |
|---|
| 1894 | + memset(&userurb_sigval, 0, sizeof(userurb_sigval)); |
|---|
| 1895 | + userurb_sigval.sival_ptr = arg; |
|---|
| 1896 | + |
|---|
| 1827 | 1897 | return proc_do_submiturb(ps, &uurb, |
|---|
| 1828 | 1898 | (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), |
|---|
| 1829 | | - arg); |
|---|
| 1899 | + arg, userurb_sigval); |
|---|
| 1830 | 1900 | } |
|---|
| 1831 | 1901 | |
|---|
| 1832 | 1902 | static int proc_unlinkurb(struct usb_dev_state *ps, void __user *arg) |
|---|
| .. | .. |
|---|
| 1962 | 2032 | static int proc_control_compat(struct usb_dev_state *ps, |
|---|
| 1963 | 2033 | struct usbdevfs_ctrltransfer32 __user *p32) |
|---|
| 1964 | 2034 | { |
|---|
| 1965 | | - struct usbdevfs_ctrltransfer __user *p; |
|---|
| 1966 | | - __u32 udata; |
|---|
| 1967 | | - p = compat_alloc_user_space(sizeof(*p)); |
|---|
| 1968 | | - if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) || |
|---|
| 1969 | | - get_user(udata, &p32->data) || |
|---|
| 1970 | | - put_user(compat_ptr(udata), &p->data)) |
|---|
| 2035 | + struct usbdevfs_ctrltransfer ctrl; |
|---|
| 2036 | + u32 udata; |
|---|
| 2037 | + |
|---|
| 2038 | + if (copy_from_user(&ctrl, p32, sizeof(*p32) - sizeof(compat_caddr_t)) || |
|---|
| 2039 | + get_user(udata, &p32->data)) |
|---|
| 1971 | 2040 | return -EFAULT; |
|---|
| 1972 | | - return proc_control(ps, p); |
|---|
| 2041 | + ctrl.data = compat_ptr(udata); |
|---|
| 2042 | + return do_proc_control(ps, &ctrl); |
|---|
| 1973 | 2043 | } |
|---|
| 1974 | 2044 | |
|---|
| 1975 | 2045 | static int proc_bulk_compat(struct usb_dev_state *ps, |
|---|
| 1976 | 2046 | struct usbdevfs_bulktransfer32 __user *p32) |
|---|
| 1977 | 2047 | { |
|---|
| 1978 | | - struct usbdevfs_bulktransfer __user *p; |
|---|
| 1979 | | - compat_uint_t n; |
|---|
| 2048 | + struct usbdevfs_bulktransfer bulk; |
|---|
| 1980 | 2049 | compat_caddr_t addr; |
|---|
| 1981 | 2050 | |
|---|
| 1982 | | - p = compat_alloc_user_space(sizeof(*p)); |
|---|
| 1983 | | - |
|---|
| 1984 | | - if (get_user(n, &p32->ep) || put_user(n, &p->ep) || |
|---|
| 1985 | | - get_user(n, &p32->len) || put_user(n, &p->len) || |
|---|
| 1986 | | - get_user(n, &p32->timeout) || put_user(n, &p->timeout) || |
|---|
| 1987 | | - get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data)) |
|---|
| 2051 | + if (get_user(bulk.ep, &p32->ep) || |
|---|
| 2052 | + get_user(bulk.len, &p32->len) || |
|---|
| 2053 | + get_user(bulk.timeout, &p32->timeout) || |
|---|
| 2054 | + get_user(addr, &p32->data)) |
|---|
| 1988 | 2055 | return -EFAULT; |
|---|
| 1989 | | - |
|---|
| 1990 | | - return proc_bulk(ps, p); |
|---|
| 2056 | + bulk.data = compat_ptr(addr); |
|---|
| 2057 | + return do_proc_bulk(ps, &bulk); |
|---|
| 1991 | 2058 | } |
|---|
| 2059 | + |
|---|
| 1992 | 2060 | static int proc_disconnectsignal_compat(struct usb_dev_state *ps, void __user *arg) |
|---|
| 1993 | 2061 | { |
|---|
| 1994 | 2062 | struct usbdevfs_disconnectsignal32 ds; |
|---|
| .. | .. |
|---|
| 1996 | 2064 | if (copy_from_user(&ds, arg, sizeof(ds))) |
|---|
| 1997 | 2065 | return -EFAULT; |
|---|
| 1998 | 2066 | ps->discsignr = ds.signr; |
|---|
| 1999 | | - ps->disccontext = compat_ptr(ds.context); |
|---|
| 2067 | + ps->disccontext.sival_int = ds.context; |
|---|
| 2000 | 2068 | return 0; |
|---|
| 2001 | 2069 | } |
|---|
| 2002 | 2070 | |
|---|
| .. | .. |
|---|
| 2024 | 2092 | static int proc_submiturb_compat(struct usb_dev_state *ps, void __user *arg) |
|---|
| 2025 | 2093 | { |
|---|
| 2026 | 2094 | struct usbdevfs_urb uurb; |
|---|
| 2095 | + sigval_t userurb_sigval; |
|---|
| 2027 | 2096 | |
|---|
| 2028 | 2097 | if (get_urb32(&uurb, (struct usbdevfs_urb32 __user *)arg)) |
|---|
| 2029 | 2098 | return -EFAULT; |
|---|
| 2030 | 2099 | |
|---|
| 2100 | + memset(&userurb_sigval, 0, sizeof(userurb_sigval)); |
|---|
| 2101 | + userurb_sigval.sival_int = ptr_to_compat(arg); |
|---|
| 2102 | + |
|---|
| 2031 | 2103 | return proc_do_submiturb(ps, &uurb, |
|---|
| 2032 | 2104 | ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, |
|---|
| 2033 | | - arg); |
|---|
| 2105 | + arg, userurb_sigval); |
|---|
| 2034 | 2106 | } |
|---|
| 2035 | 2107 | |
|---|
| 2036 | 2108 | static int processcompl_compat(struct async *as, void __user * __user *arg) |
|---|
| .. | .. |
|---|
| 2111 | 2183 | if (copy_from_user(&ds, arg, sizeof(ds))) |
|---|
| 2112 | 2184 | return -EFAULT; |
|---|
| 2113 | 2185 | ps->discsignr = ds.signr; |
|---|
| 2114 | | - ps->disccontext = ds.context; |
|---|
| 2186 | + ps->disccontext.sival_ptr = ds.context; |
|---|
| 2115 | 2187 | return 0; |
|---|
| 2116 | 2188 | } |
|---|
| 2117 | 2189 | |
|---|
| .. | .. |
|---|
| 2149 | 2221 | if (ps->privileges_dropped) |
|---|
| 2150 | 2222 | return -EACCES; |
|---|
| 2151 | 2223 | |
|---|
| 2224 | + if (!connected(ps)) |
|---|
| 2225 | + return -ENODEV; |
|---|
| 2226 | + |
|---|
| 2152 | 2227 | /* alloc buffer */ |
|---|
| 2153 | 2228 | size = _IOC_SIZE(ctl->ioctl_code); |
|---|
| 2154 | 2229 | if (size > 0) { |
|---|
| .. | .. |
|---|
| 2163 | 2238 | } else { |
|---|
| 2164 | 2239 | memset(buf, 0, size); |
|---|
| 2165 | 2240 | } |
|---|
| 2166 | | - } |
|---|
| 2167 | | - |
|---|
| 2168 | | - if (!connected(ps)) { |
|---|
| 2169 | | - kfree(buf); |
|---|
| 2170 | | - return -ENODEV; |
|---|
| 2171 | 2241 | } |
|---|
| 2172 | 2242 | |
|---|
| 2173 | 2243 | if (ps->dev->state != USB_STATE_CONFIGURED) |
|---|
| .. | .. |
|---|
| 2271 | 2341 | |
|---|
| 2272 | 2342 | caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM | |
|---|
| 2273 | 2343 | USBDEVFS_CAP_REAP_AFTER_DISCONNECT | USBDEVFS_CAP_MMAP | |
|---|
| 2274 | | - USBDEVFS_CAP_DROP_PRIVILEGES; |
|---|
| 2344 | + USBDEVFS_CAP_DROP_PRIVILEGES | |
|---|
| 2345 | + USBDEVFS_CAP_CONNINFO_EX | MAYBE_CAP_SUSPEND; |
|---|
| 2275 | 2346 | if (!ps->dev->bus->no_stop_on_short) |
|---|
| 2276 | 2347 | caps |= USBDEVFS_CAP_BULK_CONTINUATION; |
|---|
| 2277 | 2348 | if (ps->dev->bus->sg_tablesize) |
|---|
| .. | .. |
|---|
| 2372 | 2443 | ps->privileges_dropped = true; |
|---|
| 2373 | 2444 | |
|---|
| 2374 | 2445 | return 0; |
|---|
| 2446 | +} |
|---|
| 2447 | + |
|---|
| 2448 | +static int proc_forbid_suspend(struct usb_dev_state *ps) |
|---|
| 2449 | +{ |
|---|
| 2450 | + int ret = 0; |
|---|
| 2451 | + |
|---|
| 2452 | + if (ps->suspend_allowed) { |
|---|
| 2453 | + ret = usb_autoresume_device(ps->dev); |
|---|
| 2454 | + if (ret == 0) |
|---|
| 2455 | + ps->suspend_allowed = false; |
|---|
| 2456 | + else if (ret != -ENODEV) |
|---|
| 2457 | + ret = -EIO; |
|---|
| 2458 | + } |
|---|
| 2459 | + return ret; |
|---|
| 2460 | +} |
|---|
| 2461 | + |
|---|
| 2462 | +static int proc_allow_suspend(struct usb_dev_state *ps) |
|---|
| 2463 | +{ |
|---|
| 2464 | + if (!connected(ps)) |
|---|
| 2465 | + return -ENODEV; |
|---|
| 2466 | + |
|---|
| 2467 | + WRITE_ONCE(ps->not_yet_resumed, 1); |
|---|
| 2468 | + if (!ps->suspend_allowed) { |
|---|
| 2469 | + usb_autosuspend_device(ps->dev); |
|---|
| 2470 | + ps->suspend_allowed = true; |
|---|
| 2471 | + } |
|---|
| 2472 | + return 0; |
|---|
| 2473 | +} |
|---|
| 2474 | + |
|---|
| 2475 | +static int proc_wait_for_resume(struct usb_dev_state *ps) |
|---|
| 2476 | +{ |
|---|
| 2477 | + int ret; |
|---|
| 2478 | + |
|---|
| 2479 | + usb_unlock_device(ps->dev); |
|---|
| 2480 | + ret = wait_event_interruptible(ps->wait_for_resume, |
|---|
| 2481 | + READ_ONCE(ps->not_yet_resumed) == 0); |
|---|
| 2482 | + usb_lock_device(ps->dev); |
|---|
| 2483 | + |
|---|
| 2484 | + if (ret != 0) |
|---|
| 2485 | + return -EINTR; |
|---|
| 2486 | + return proc_forbid_suspend(ps); |
|---|
| 2375 | 2487 | } |
|---|
| 2376 | 2488 | |
|---|
| 2377 | 2489 | /* |
|---|
| .. | .. |
|---|
| 2568 | 2680 | case USBDEVFS_GET_SPEED: |
|---|
| 2569 | 2681 | ret = ps->dev->speed; |
|---|
| 2570 | 2682 | break; |
|---|
| 2683 | + case USBDEVFS_FORBID_SUSPEND: |
|---|
| 2684 | + ret = proc_forbid_suspend(ps); |
|---|
| 2685 | + break; |
|---|
| 2686 | + case USBDEVFS_ALLOW_SUSPEND: |
|---|
| 2687 | + ret = proc_allow_suspend(ps); |
|---|
| 2688 | + break; |
|---|
| 2689 | + case USBDEVFS_WAIT_FOR_RESUME: |
|---|
| 2690 | + ret = proc_wait_for_resume(ps); |
|---|
| 2691 | + break; |
|---|
| 2692 | + } |
|---|
| 2693 | + |
|---|
| 2694 | + /* Handle variable-length commands */ |
|---|
| 2695 | + switch (cmd & ~IOCSIZE_MASK) { |
|---|
| 2696 | + case USBDEVFS_CONNINFO_EX(0): |
|---|
| 2697 | + ret = proc_conninfo_ex(ps, p, _IOC_SIZE(cmd)); |
|---|
| 2698 | + break; |
|---|
| 2571 | 2699 | } |
|---|
| 2572 | 2700 | |
|---|
| 2573 | 2701 | done: |
|---|
| .. | .. |
|---|
| 2586 | 2714 | |
|---|
| 2587 | 2715 | return ret; |
|---|
| 2588 | 2716 | } |
|---|
| 2589 | | - |
|---|
| 2590 | | -#ifdef CONFIG_COMPAT |
|---|
| 2591 | | -static long usbdev_compat_ioctl(struct file *file, unsigned int cmd, |
|---|
| 2592 | | - unsigned long arg) |
|---|
| 2593 | | -{ |
|---|
| 2594 | | - int ret; |
|---|
| 2595 | | - |
|---|
| 2596 | | - ret = usbdev_do_ioctl(file, cmd, compat_ptr(arg)); |
|---|
| 2597 | | - |
|---|
| 2598 | | - return ret; |
|---|
| 2599 | | -} |
|---|
| 2600 | | -#endif |
|---|
| 2601 | 2717 | |
|---|
| 2602 | 2718 | /* No kernel lock - fine */ |
|---|
| 2603 | 2719 | static __poll_t usbdev_poll(struct file *file, |
|---|
| .. | .. |
|---|
| 2622 | 2738 | .read = usbdev_read, |
|---|
| 2623 | 2739 | .poll = usbdev_poll, |
|---|
| 2624 | 2740 | .unlocked_ioctl = usbdev_ioctl, |
|---|
| 2625 | | -#ifdef CONFIG_COMPAT |
|---|
| 2626 | | - .compat_ioctl = usbdev_compat_ioctl, |
|---|
| 2627 | | -#endif |
|---|
| 2741 | + .compat_ioctl = compat_ptr_ioctl, |
|---|
| 2628 | 2742 | .mmap = usbdev_mmap, |
|---|
| 2629 | 2743 | .open = usbdev_open, |
|---|
| 2630 | 2744 | .release = usbdev_release, |
|---|
| .. | .. |
|---|
| 2633 | 2747 | static void usbdev_remove(struct usb_device *udev) |
|---|
| 2634 | 2748 | { |
|---|
| 2635 | 2749 | struct usb_dev_state *ps; |
|---|
| 2636 | | - struct siginfo sinfo; |
|---|
| 2637 | 2750 | |
|---|
| 2751 | + /* Protect against simultaneous resume */ |
|---|
| 2752 | + mutex_lock(&usbfs_mutex); |
|---|
| 2638 | 2753 | while (!list_empty(&udev->filelist)) { |
|---|
| 2639 | 2754 | ps = list_entry(udev->filelist.next, struct usb_dev_state, list); |
|---|
| 2640 | 2755 | destroy_all_async(ps); |
|---|
| 2641 | 2756 | wake_up_all(&ps->wait); |
|---|
| 2757 | + WRITE_ONCE(ps->not_yet_resumed, 0); |
|---|
| 2758 | + wake_up_all(&ps->wait_for_resume); |
|---|
| 2642 | 2759 | list_del_init(&ps->list); |
|---|
| 2643 | | - if (ps->discsignr) { |
|---|
| 2644 | | - clear_siginfo(&sinfo); |
|---|
| 2645 | | - sinfo.si_signo = ps->discsignr; |
|---|
| 2646 | | - sinfo.si_errno = EPIPE; |
|---|
| 2647 | | - sinfo.si_code = SI_ASYNCIO; |
|---|
| 2648 | | - sinfo.si_addr = ps->disccontext; |
|---|
| 2649 | | - kill_pid_info_as_cred(ps->discsignr, &sinfo, |
|---|
| 2650 | | - ps->disc_pid, ps->cred); |
|---|
| 2651 | | - } |
|---|
| 2760 | + if (ps->discsignr) |
|---|
| 2761 | + kill_pid_usb_asyncio(ps->discsignr, EPIPE, ps->disccontext, |
|---|
| 2762 | + ps->disc_pid, ps->cred); |
|---|
| 2652 | 2763 | } |
|---|
| 2764 | + mutex_unlock(&usbfs_mutex); |
|---|
| 2653 | 2765 | } |
|---|
| 2654 | 2766 | |
|---|
| 2655 | 2767 | static int usbdev_notify(struct notifier_block *self, |
|---|