| .. | .. |
|---|
| 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; |
|---|
| .. | .. |
|---|
| 163 | 173 | static void dec_usb_memory_use_count(struct usb_memory *usbm, int *count) |
|---|
| 164 | 174 | { |
|---|
| 165 | 175 | struct usb_dev_state *ps = usbm->ps; |
|---|
| 176 | + struct usb_hcd *hcd = bus_to_hcd(ps->dev->bus); |
|---|
| 166 | 177 | unsigned long flags; |
|---|
| 167 | 178 | |
|---|
| 168 | 179 | spin_lock_irqsave(&ps->lock, flags); |
|---|
| .. | .. |
|---|
| 171 | 182 | list_del(&usbm->memlist); |
|---|
| 172 | 183 | spin_unlock_irqrestore(&ps->lock, flags); |
|---|
| 173 | 184 | |
|---|
| 174 | | - usb_free_coherent(ps->dev, usbm->size, usbm->mem, |
|---|
| 175 | | - usbm->dma_handle); |
|---|
| 185 | + hcd_buffer_free_pages(hcd, usbm->size, |
|---|
| 186 | + usbm->mem, usbm->dma_handle); |
|---|
| 176 | 187 | usbfs_decrease_memory_usage( |
|---|
| 177 | 188 | usbm->size + sizeof(struct usb_memory)); |
|---|
| 178 | 189 | kfree(usbm); |
|---|
| .. | .. |
|---|
| 207 | 218 | { |
|---|
| 208 | 219 | struct usb_memory *usbm = NULL; |
|---|
| 209 | 220 | struct usb_dev_state *ps = file->private_data; |
|---|
| 221 | + struct usb_hcd *hcd = bus_to_hcd(ps->dev->bus); |
|---|
| 210 | 222 | size_t size = vma->vm_end - vma->vm_start; |
|---|
| 211 | 223 | void *mem; |
|---|
| 212 | 224 | unsigned long flags; |
|---|
| 213 | | - dma_addr_t dma_handle; |
|---|
| 225 | + dma_addr_t dma_handle = DMA_MAPPING_ERROR; |
|---|
| 214 | 226 | int ret; |
|---|
| 215 | 227 | |
|---|
| 216 | 228 | ret = usbfs_increase_memory_usage(size + sizeof(struct usb_memory)); |
|---|
| .. | .. |
|---|
| 223 | 235 | goto error_decrease_mem; |
|---|
| 224 | 236 | } |
|---|
| 225 | 237 | |
|---|
| 226 | | - mem = usb_alloc_coherent(ps->dev, size, GFP_USER | __GFP_NOWARN, |
|---|
| 227 | | - &dma_handle); |
|---|
| 238 | + mem = hcd_buffer_alloc_pages(hcd, |
|---|
| 239 | + size, GFP_USER | __GFP_NOWARN, &dma_handle); |
|---|
| 228 | 240 | if (!mem) { |
|---|
| 229 | 241 | ret = -ENOMEM; |
|---|
| 230 | 242 | goto error_free_usbm; |
|---|
| .. | .. |
|---|
| 240 | 252 | usbm->vma_use_count = 1; |
|---|
| 241 | 253 | INIT_LIST_HEAD(&usbm->memlist); |
|---|
| 242 | 254 | |
|---|
| 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; |
|---|
| 255 | + /* |
|---|
| 256 | + * In DMA-unavailable cases, hcd_buffer_alloc_pages allocates |
|---|
| 257 | + * normal pages and assigns DMA_MAPPING_ERROR to dma_handle. Check |
|---|
| 258 | + * whether we are in such cases, and then use remap_pfn_range (or |
|---|
| 259 | + * dma_mmap_coherent) to map normal (or DMA) pages into the user |
|---|
| 260 | + * space, respectively. |
|---|
| 261 | + */ |
|---|
| 262 | + if (dma_handle == DMA_MAPPING_ERROR) { |
|---|
| 263 | + if (remap_pfn_range(vma, vma->vm_start, |
|---|
| 264 | + virt_to_phys(usbm->mem) >> PAGE_SHIFT, |
|---|
| 265 | + size, vma->vm_page_prot) < 0) { |
|---|
| 266 | + dec_usb_memory_use_count(usbm, &usbm->vma_use_count); |
|---|
| 267 | + return -EAGAIN; |
|---|
| 268 | + } |
|---|
| 269 | + } else { |
|---|
| 270 | + if (dma_mmap_coherent(hcd->self.sysdev, vma, mem, dma_handle, |
|---|
| 271 | + size)) { |
|---|
| 272 | + dec_usb_memory_use_count(usbm, &usbm->vma_use_count); |
|---|
| 273 | + return -EAGAIN; |
|---|
| 274 | + } |
|---|
| 248 | 275 | } |
|---|
| 249 | 276 | |
|---|
| 250 | 277 | vma->vm_flags |= VM_IO; |
|---|
| .. | .. |
|---|
| 564 | 591 | |
|---|
| 565 | 592 | /* Now carefully unlink all the marked pending URBs */ |
|---|
| 566 | 593 | rescan: |
|---|
| 567 | | - list_for_each_entry(as, &ps->async_pending, asynclist) { |
|---|
| 594 | + list_for_each_entry_reverse(as, &ps->async_pending, asynclist) { |
|---|
| 568 | 595 | if (as->bulk_status == AS_UNLINK) { |
|---|
| 569 | 596 | as->bulk_status = 0; /* Only once */ |
|---|
| 570 | 597 | urb = as->urb; |
|---|
| .. | .. |
|---|
| 582 | 609 | { |
|---|
| 583 | 610 | struct async *as = urb->context; |
|---|
| 584 | 611 | struct usb_dev_state *ps = as->ps; |
|---|
| 585 | | - struct siginfo sinfo; |
|---|
| 586 | 612 | struct pid *pid = NULL; |
|---|
| 587 | 613 | const struct cred *cred = NULL; |
|---|
| 588 | 614 | unsigned long flags; |
|---|
| 589 | | - int signr; |
|---|
| 615 | + sigval_t addr; |
|---|
| 616 | + int signr, errno; |
|---|
| 590 | 617 | |
|---|
| 591 | 618 | spin_lock_irqsave(&ps->lock, flags); |
|---|
| 592 | 619 | list_move_tail(&as->asynclist, &ps->async_completed); |
|---|
| 593 | 620 | as->status = urb->status; |
|---|
| 594 | 621 | signr = as->signr; |
|---|
| 595 | 622 | 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; |
|---|
| 623 | + errno = as->status; |
|---|
| 624 | + addr = as->userurb_sigval; |
|---|
| 601 | 625 | pid = get_pid(as->pid); |
|---|
| 602 | 626 | cred = get_cred(as->cred); |
|---|
| 603 | 627 | } |
|---|
| 604 | 628 | snoop(&urb->dev->dev, "urb complete\n"); |
|---|
| 605 | 629 | snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length, |
|---|
| 606 | 630 | as->status, COMPLETE, NULL, 0); |
|---|
| 607 | | - if ((urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN) |
|---|
| 631 | + if (usb_urb_dir_in(urb)) |
|---|
| 608 | 632 | snoop_urb_data(urb, urb->actual_length); |
|---|
| 609 | 633 | |
|---|
| 610 | 634 | if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET && |
|---|
| .. | .. |
|---|
| 615 | 639 | spin_unlock_irqrestore(&ps->lock, flags); |
|---|
| 616 | 640 | |
|---|
| 617 | 641 | if (signr) { |
|---|
| 618 | | - kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred); |
|---|
| 642 | + kill_pid_usb_asyncio(signr, errno, addr, pid, cred); |
|---|
| 619 | 643 | put_pid(pid); |
|---|
| 620 | 644 | put_cred(cred); |
|---|
| 621 | 645 | } |
|---|
| .. | .. |
|---|
| 629 | 653 | |
|---|
| 630 | 654 | spin_lock_irqsave(&ps->lock, flags); |
|---|
| 631 | 655 | while (!list_empty(list)) { |
|---|
| 632 | | - as = list_entry(list->next, struct async, asynclist); |
|---|
| 656 | + as = list_last_entry(list, struct async, asynclist); |
|---|
| 633 | 657 | list_del_init(&as->asynclist); |
|---|
| 634 | 658 | urb = as->urb; |
|---|
| 635 | 659 | usb_get_urb(urb); |
|---|
| .. | .. |
|---|
| 699 | 723 | destroy_async_on_interface(ps, ifnum); |
|---|
| 700 | 724 | } |
|---|
| 701 | 725 | |
|---|
| 702 | | -/* The following routines are merely placeholders. There is no way |
|---|
| 703 | | - * to inform a user task about suspend or resumes. |
|---|
| 704 | | - */ |
|---|
| 726 | +/* We don't care about suspend/resume of claimed interfaces */ |
|---|
| 705 | 727 | static int driver_suspend(struct usb_interface *intf, pm_message_t msg) |
|---|
| 706 | 728 | { |
|---|
| 707 | 729 | return 0; |
|---|
| .. | .. |
|---|
| 712 | 734 | return 0; |
|---|
| 713 | 735 | } |
|---|
| 714 | 736 | |
|---|
| 737 | +#ifdef CONFIG_PM |
|---|
| 738 | +/* The following routines apply to the entire device, not interfaces */ |
|---|
| 739 | +void usbfs_notify_suspend(struct usb_device *udev) |
|---|
| 740 | +{ |
|---|
| 741 | + /* We don't need to handle this */ |
|---|
| 742 | +} |
|---|
| 743 | + |
|---|
| 744 | +void usbfs_notify_resume(struct usb_device *udev) |
|---|
| 745 | +{ |
|---|
| 746 | + struct usb_dev_state *ps; |
|---|
| 747 | + |
|---|
| 748 | + /* Protect against simultaneous remove or release */ |
|---|
| 749 | + mutex_lock(&usbfs_mutex); |
|---|
| 750 | + list_for_each_entry(ps, &udev->filelist, list) { |
|---|
| 751 | + WRITE_ONCE(ps->not_yet_resumed, 0); |
|---|
| 752 | + wake_up_all(&ps->wait_for_resume); |
|---|
| 753 | + } |
|---|
| 754 | + mutex_unlock(&usbfs_mutex); |
|---|
| 755 | +} |
|---|
| 756 | +#endif |
|---|
| 757 | + |
|---|
| 715 | 758 | struct usb_driver usbfs_driver = { |
|---|
| 716 | 759 | .name = "usbfs", |
|---|
| 717 | 760 | .probe = driver_probe, |
|---|
| 718 | 761 | .disconnect = driver_disconnect, |
|---|
| 719 | 762 | .suspend = driver_suspend, |
|---|
| 720 | 763 | .resume = driver_resume, |
|---|
| 764 | + .supports_autosuspend = 1, |
|---|
| 721 | 765 | }; |
|---|
| 722 | 766 | |
|---|
| 723 | 767 | static int claimintf(struct usb_dev_state *ps, unsigned int ifnum) |
|---|
| .. | .. |
|---|
| 960 | 1004 | return ret; |
|---|
| 961 | 1005 | } |
|---|
| 962 | 1006 | |
|---|
| 963 | | -static int match_devt(struct device *dev, void *data) |
|---|
| 964 | | -{ |
|---|
| 965 | | - return dev->devt == (dev_t) (unsigned long) data; |
|---|
| 966 | | -} |
|---|
| 967 | | - |
|---|
| 968 | 1007 | static struct usb_device *usbdev_lookup_by_devt(dev_t devt) |
|---|
| 969 | 1008 | { |
|---|
| 970 | 1009 | struct device *dev; |
|---|
| 971 | 1010 | |
|---|
| 972 | | - dev = bus_find_device(&usb_bus_type, NULL, |
|---|
| 973 | | - (void *) (unsigned long) devt, match_devt); |
|---|
| 1011 | + dev = bus_find_device_by_devt(&usb_bus_type, devt); |
|---|
| 974 | 1012 | if (!dev) |
|---|
| 975 | 1013 | return NULL; |
|---|
| 976 | 1014 | return to_usb_device(dev); |
|---|
| .. | .. |
|---|
| 992 | 1030 | |
|---|
| 993 | 1031 | ret = -ENODEV; |
|---|
| 994 | 1032 | |
|---|
| 995 | | - /* Protect against simultaneous removal or release */ |
|---|
| 996 | | - mutex_lock(&usbfs_mutex); |
|---|
| 997 | | - |
|---|
| 998 | 1033 | /* usbdev device-node */ |
|---|
| 999 | 1034 | if (imajor(inode) == USB_DEVICE_MAJOR) |
|---|
| 1000 | 1035 | dev = usbdev_lookup_by_devt(inode->i_rdev); |
|---|
| 1001 | | - |
|---|
| 1002 | | - mutex_unlock(&usbfs_mutex); |
|---|
| 1003 | | - |
|---|
| 1004 | 1036 | if (!dev) |
|---|
| 1005 | 1037 | goto out_free_ps; |
|---|
| 1006 | 1038 | |
|---|
| .. | .. |
|---|
| 1021 | 1053 | INIT_LIST_HEAD(&ps->async_completed); |
|---|
| 1022 | 1054 | INIT_LIST_HEAD(&ps->memory_list); |
|---|
| 1023 | 1055 | init_waitqueue_head(&ps->wait); |
|---|
| 1056 | + init_waitqueue_head(&ps->wait_for_resume); |
|---|
| 1024 | 1057 | ps->disc_pid = get_pid(task_pid(current)); |
|---|
| 1025 | 1058 | ps->cred = get_current_cred(); |
|---|
| 1026 | 1059 | smp_wmb(); |
|---|
| 1060 | + |
|---|
| 1061 | + /* Can't race with resume; the device is already active */ |
|---|
| 1027 | 1062 | list_add_tail(&ps->list, &dev->filelist); |
|---|
| 1028 | 1063 | file->private_data = ps; |
|---|
| 1029 | 1064 | usb_unlock_device(dev); |
|---|
| .. | .. |
|---|
| 1049 | 1084 | usb_lock_device(dev); |
|---|
| 1050 | 1085 | usb_hub_release_all_ports(dev, ps); |
|---|
| 1051 | 1086 | |
|---|
| 1087 | + /* Protect against simultaneous resume */ |
|---|
| 1088 | + mutex_lock(&usbfs_mutex); |
|---|
| 1052 | 1089 | list_del_init(&ps->list); |
|---|
| 1090 | + mutex_unlock(&usbfs_mutex); |
|---|
| 1053 | 1091 | |
|---|
| 1054 | 1092 | for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed); |
|---|
| 1055 | 1093 | ifnum++) { |
|---|
| .. | .. |
|---|
| 1057 | 1095 | releaseintf(ps, ifnum); |
|---|
| 1058 | 1096 | } |
|---|
| 1059 | 1097 | destroy_all_async(ps); |
|---|
| 1060 | | - usb_autosuspend_device(dev); |
|---|
| 1098 | + if (!ps->suspend_allowed) |
|---|
| 1099 | + usb_autosuspend_device(dev); |
|---|
| 1061 | 1100 | usb_unlock_device(dev); |
|---|
| 1062 | 1101 | usb_put_dev(dev); |
|---|
| 1063 | 1102 | put_pid(ps->disc_pid); |
|---|
| .. | .. |
|---|
| 1073 | 1112 | return 0; |
|---|
| 1074 | 1113 | } |
|---|
| 1075 | 1114 | |
|---|
| 1076 | | -static int proc_control(struct usb_dev_state *ps, void __user *arg) |
|---|
| 1115 | +static int do_proc_control(struct usb_dev_state *ps, |
|---|
| 1116 | + struct usbdevfs_ctrltransfer *ctrl) |
|---|
| 1077 | 1117 | { |
|---|
| 1078 | 1118 | struct usb_device *dev = ps->dev; |
|---|
| 1079 | | - struct usbdevfs_ctrltransfer ctrl; |
|---|
| 1080 | 1119 | unsigned int tmo; |
|---|
| 1081 | 1120 | unsigned char *tbuf; |
|---|
| 1082 | 1121 | unsigned wLength; |
|---|
| 1083 | 1122 | int i, pipe, ret; |
|---|
| 1084 | 1123 | |
|---|
| 1085 | | - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) |
|---|
| 1086 | | - return -EFAULT; |
|---|
| 1087 | | - ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.bRequest, |
|---|
| 1088 | | - ctrl.wIndex); |
|---|
| 1124 | + ret = check_ctrlrecip(ps, ctrl->bRequestType, ctrl->bRequest, |
|---|
| 1125 | + ctrl->wIndex); |
|---|
| 1089 | 1126 | if (ret) |
|---|
| 1090 | 1127 | return ret; |
|---|
| 1091 | | - wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */ |
|---|
| 1128 | + wLength = ctrl->wLength; /* To suppress 64k PAGE_SIZE warning */ |
|---|
| 1092 | 1129 | if (wLength > PAGE_SIZE) |
|---|
| 1093 | 1130 | return -EINVAL; |
|---|
| 1094 | 1131 | ret = usbfs_increase_memory_usage(PAGE_SIZE + sizeof(struct urb) + |
|---|
| .. | .. |
|---|
| 1100 | 1137 | ret = -ENOMEM; |
|---|
| 1101 | 1138 | goto done; |
|---|
| 1102 | 1139 | } |
|---|
| 1103 | | - tmo = ctrl.timeout; |
|---|
| 1140 | + tmo = ctrl->timeout; |
|---|
| 1104 | 1141 | snoop(&dev->dev, "control urb: bRequestType=%02x " |
|---|
| 1105 | 1142 | "bRequest=%02x wValue=%04x " |
|---|
| 1106 | 1143 | "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 | | - } |
|---|
| 1144 | + ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, |
|---|
| 1145 | + ctrl->wIndex, ctrl->wLength); |
|---|
| 1146 | + if ((ctrl->bRequestType & USB_DIR_IN) && ctrl->wLength) { |
|---|
| 1115 | 1147 | pipe = usb_rcvctrlpipe(dev, 0); |
|---|
| 1116 | | - snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0); |
|---|
| 1148 | + snoop_urb(dev, NULL, pipe, ctrl->wLength, tmo, SUBMIT, NULL, 0); |
|---|
| 1117 | 1149 | |
|---|
| 1118 | 1150 | 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); |
|---|
| 1151 | + i = usb_control_msg(dev, pipe, ctrl->bRequest, |
|---|
| 1152 | + ctrl->bRequestType, ctrl->wValue, ctrl->wIndex, |
|---|
| 1153 | + tbuf, ctrl->wLength, tmo); |
|---|
| 1122 | 1154 | usb_lock_device(dev); |
|---|
| 1123 | 1155 | snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, |
|---|
| 1124 | 1156 | tbuf, max(i, 0)); |
|---|
| 1125 | | - if ((i > 0) && ctrl.wLength) { |
|---|
| 1126 | | - if (copy_to_user(ctrl.data, tbuf, i)) { |
|---|
| 1157 | + if ((i > 0) && ctrl->wLength) { |
|---|
| 1158 | + if (copy_to_user(ctrl->data, tbuf, i)) { |
|---|
| 1127 | 1159 | ret = -EFAULT; |
|---|
| 1128 | 1160 | goto done; |
|---|
| 1129 | 1161 | } |
|---|
| 1130 | 1162 | } |
|---|
| 1131 | 1163 | } else { |
|---|
| 1132 | | - if (ctrl.wLength) { |
|---|
| 1133 | | - if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) { |
|---|
| 1164 | + if (ctrl->wLength) { |
|---|
| 1165 | + if (copy_from_user(tbuf, ctrl->data, ctrl->wLength)) { |
|---|
| 1134 | 1166 | ret = -EFAULT; |
|---|
| 1135 | 1167 | goto done; |
|---|
| 1136 | 1168 | } |
|---|
| 1137 | 1169 | } |
|---|
| 1138 | 1170 | pipe = usb_sndctrlpipe(dev, 0); |
|---|
| 1139 | | - snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, |
|---|
| 1140 | | - tbuf, ctrl.wLength); |
|---|
| 1171 | + snoop_urb(dev, NULL, pipe, ctrl->wLength, tmo, SUBMIT, |
|---|
| 1172 | + tbuf, ctrl->wLength); |
|---|
| 1141 | 1173 | |
|---|
| 1142 | 1174 | 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); |
|---|
| 1175 | + i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl->bRequest, |
|---|
| 1176 | + ctrl->bRequestType, ctrl->wValue, ctrl->wIndex, |
|---|
| 1177 | + tbuf, ctrl->wLength, tmo); |
|---|
| 1146 | 1178 | usb_lock_device(dev); |
|---|
| 1147 | 1179 | snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0); |
|---|
| 1148 | 1180 | } |
|---|
| 1149 | 1181 | if (i < 0 && i != -EPIPE) { |
|---|
| 1150 | 1182 | dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL " |
|---|
| 1151 | 1183 | "failed cmd %s rqt %u rq %u len %u ret %d\n", |
|---|
| 1152 | | - current->comm, ctrl.bRequestType, ctrl.bRequest, |
|---|
| 1153 | | - ctrl.wLength, i); |
|---|
| 1184 | + current->comm, ctrl->bRequestType, ctrl->bRequest, |
|---|
| 1185 | + ctrl->wLength, i); |
|---|
| 1154 | 1186 | } |
|---|
| 1155 | 1187 | ret = i; |
|---|
| 1156 | 1188 | done: |
|---|
| .. | .. |
|---|
| 1160 | 1192 | return ret; |
|---|
| 1161 | 1193 | } |
|---|
| 1162 | 1194 | |
|---|
| 1163 | | -static int proc_bulk(struct usb_dev_state *ps, void __user *arg) |
|---|
| 1195 | +static int proc_control(struct usb_dev_state *ps, void __user *arg) |
|---|
| 1196 | +{ |
|---|
| 1197 | + struct usbdevfs_ctrltransfer ctrl; |
|---|
| 1198 | + |
|---|
| 1199 | + if (copy_from_user(&ctrl, arg, sizeof(ctrl))) |
|---|
| 1200 | + return -EFAULT; |
|---|
| 1201 | + return do_proc_control(ps, &ctrl); |
|---|
| 1202 | +} |
|---|
| 1203 | + |
|---|
| 1204 | +static int do_proc_bulk(struct usb_dev_state *ps, |
|---|
| 1205 | + struct usbdevfs_bulktransfer *bulk) |
|---|
| 1164 | 1206 | { |
|---|
| 1165 | 1207 | struct usb_device *dev = ps->dev; |
|---|
| 1166 | | - struct usbdevfs_bulktransfer bulk; |
|---|
| 1167 | 1208 | unsigned int tmo, len1, pipe; |
|---|
| 1168 | 1209 | int len2; |
|---|
| 1169 | 1210 | unsigned char *tbuf; |
|---|
| 1170 | 1211 | int i, ret; |
|---|
| 1171 | 1212 | |
|---|
| 1172 | | - if (copy_from_user(&bulk, arg, sizeof(bulk))) |
|---|
| 1173 | | - return -EFAULT; |
|---|
| 1174 | | - ret = findintfep(ps->dev, bulk.ep); |
|---|
| 1213 | + ret = findintfep(ps->dev, bulk->ep); |
|---|
| 1175 | 1214 | if (ret < 0) |
|---|
| 1176 | 1215 | return ret; |
|---|
| 1177 | 1216 | ret = checkintf(ps, ret); |
|---|
| 1178 | 1217 | if (ret) |
|---|
| 1179 | 1218 | return ret; |
|---|
| 1180 | | - if (bulk.ep & USB_DIR_IN) |
|---|
| 1181 | | - pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f); |
|---|
| 1219 | + if (bulk->ep & USB_DIR_IN) |
|---|
| 1220 | + pipe = usb_rcvbulkpipe(dev, bulk->ep & 0x7f); |
|---|
| 1182 | 1221 | else |
|---|
| 1183 | | - pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f); |
|---|
| 1184 | | - if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) |
|---|
| 1222 | + pipe = usb_sndbulkpipe(dev, bulk->ep & 0x7f); |
|---|
| 1223 | + if (!usb_maxpacket(dev, pipe, !(bulk->ep & USB_DIR_IN))) |
|---|
| 1185 | 1224 | return -EINVAL; |
|---|
| 1186 | | - len1 = bulk.len; |
|---|
| 1225 | + len1 = bulk->len; |
|---|
| 1187 | 1226 | if (len1 >= (INT_MAX - sizeof(struct urb))) |
|---|
| 1188 | 1227 | return -EINVAL; |
|---|
| 1189 | 1228 | ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); |
|---|
| .. | .. |
|---|
| 1199 | 1238 | ret = -ENOMEM; |
|---|
| 1200 | 1239 | goto done; |
|---|
| 1201 | 1240 | } |
|---|
| 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 | | - } |
|---|
| 1241 | + tmo = bulk->timeout; |
|---|
| 1242 | + if (bulk->ep & 0x80) { |
|---|
| 1208 | 1243 | snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0); |
|---|
| 1209 | 1244 | |
|---|
| 1210 | 1245 | usb_unlock_device(dev); |
|---|
| .. | .. |
|---|
| 1213 | 1248 | snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, tbuf, len2); |
|---|
| 1214 | 1249 | |
|---|
| 1215 | 1250 | if (!i && len2) { |
|---|
| 1216 | | - if (copy_to_user(bulk.data, tbuf, len2)) { |
|---|
| 1251 | + if (copy_to_user(bulk->data, tbuf, len2)) { |
|---|
| 1217 | 1252 | ret = -EFAULT; |
|---|
| 1218 | 1253 | goto done; |
|---|
| 1219 | 1254 | } |
|---|
| 1220 | 1255 | } |
|---|
| 1221 | 1256 | } else { |
|---|
| 1222 | 1257 | if (len1) { |
|---|
| 1223 | | - if (copy_from_user(tbuf, bulk.data, len1)) { |
|---|
| 1258 | + if (copy_from_user(tbuf, bulk->data, len1)) { |
|---|
| 1224 | 1259 | ret = -EFAULT; |
|---|
| 1225 | 1260 | goto done; |
|---|
| 1226 | 1261 | } |
|---|
| .. | .. |
|---|
| 1237 | 1272 | kfree(tbuf); |
|---|
| 1238 | 1273 | usbfs_decrease_memory_usage(len1 + sizeof(struct urb)); |
|---|
| 1239 | 1274 | return ret; |
|---|
| 1275 | +} |
|---|
| 1276 | + |
|---|
| 1277 | +static int proc_bulk(struct usb_dev_state *ps, void __user *arg) |
|---|
| 1278 | +{ |
|---|
| 1279 | + struct usbdevfs_bulktransfer bulk; |
|---|
| 1280 | + |
|---|
| 1281 | + if (copy_from_user(&bulk, arg, sizeof(bulk))) |
|---|
| 1282 | + return -EFAULT; |
|---|
| 1283 | + return do_proc_bulk(ps, &bulk); |
|---|
| 1240 | 1284 | } |
|---|
| 1241 | 1285 | |
|---|
| 1242 | 1286 | static void check_reset_of_active_ep(struct usb_device *udev, |
|---|
| .. | .. |
|---|
| 1323 | 1367 | |
|---|
| 1324 | 1368 | if (copy_to_user(arg, &ci, sizeof(ci))) |
|---|
| 1325 | 1369 | return -EFAULT; |
|---|
| 1370 | + return 0; |
|---|
| 1371 | +} |
|---|
| 1372 | + |
|---|
| 1373 | +static int proc_conninfo_ex(struct usb_dev_state *ps, |
|---|
| 1374 | + void __user *arg, size_t size) |
|---|
| 1375 | +{ |
|---|
| 1376 | + struct usbdevfs_conninfo_ex ci; |
|---|
| 1377 | + struct usb_device *udev = ps->dev; |
|---|
| 1378 | + |
|---|
| 1379 | + if (size < sizeof(ci.size)) |
|---|
| 1380 | + return -EINVAL; |
|---|
| 1381 | + |
|---|
| 1382 | + memset(&ci, 0, sizeof(ci)); |
|---|
| 1383 | + ci.size = sizeof(ci); |
|---|
| 1384 | + ci.busnum = udev->bus->busnum; |
|---|
| 1385 | + ci.devnum = udev->devnum; |
|---|
| 1386 | + ci.speed = udev->speed; |
|---|
| 1387 | + |
|---|
| 1388 | + while (udev && udev->portnum != 0) { |
|---|
| 1389 | + if (++ci.num_ports <= ARRAY_SIZE(ci.ports)) |
|---|
| 1390 | + ci.ports[ARRAY_SIZE(ci.ports) - ci.num_ports] = |
|---|
| 1391 | + udev->portnum; |
|---|
| 1392 | + udev = udev->parent; |
|---|
| 1393 | + } |
|---|
| 1394 | + |
|---|
| 1395 | + if (ci.num_ports < ARRAY_SIZE(ci.ports)) |
|---|
| 1396 | + memmove(&ci.ports[0], |
|---|
| 1397 | + &ci.ports[ARRAY_SIZE(ci.ports) - ci.num_ports], |
|---|
| 1398 | + ci.num_ports); |
|---|
| 1399 | + |
|---|
| 1400 | + if (copy_to_user(arg, &ci, min(sizeof(ci), size))) |
|---|
| 1401 | + return -EFAULT; |
|---|
| 1402 | + |
|---|
| 1326 | 1403 | return 0; |
|---|
| 1327 | 1404 | } |
|---|
| 1328 | 1405 | |
|---|
| .. | .. |
|---|
| 1445 | 1522 | |
|---|
| 1446 | 1523 | static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb, |
|---|
| 1447 | 1524 | struct usbdevfs_iso_packet_desc __user *iso_frame_desc, |
|---|
| 1448 | | - void __user *arg) |
|---|
| 1525 | + void __user *arg, sigval_t userurb_sigval) |
|---|
| 1449 | 1526 | { |
|---|
| 1450 | 1527 | struct usbdevfs_iso_packet_desc *isopkt = NULL; |
|---|
| 1451 | 1528 | struct usb_host_endpoint *ep; |
|---|
| .. | .. |
|---|
| 1504 | 1581 | ret = -EFAULT; |
|---|
| 1505 | 1582 | goto error; |
|---|
| 1506 | 1583 | } |
|---|
| 1507 | | - if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) { |
|---|
| 1584 | + if (uurb->buffer_length < (le16_to_cpu(dr->wLength) + 8)) { |
|---|
| 1508 | 1585 | ret = -EINVAL; |
|---|
| 1509 | 1586 | goto error; |
|---|
| 1510 | 1587 | } |
|---|
| 1511 | 1588 | ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest, |
|---|
| 1512 | | - le16_to_cpup(&dr->wIndex)); |
|---|
| 1589 | + le16_to_cpu(dr->wIndex)); |
|---|
| 1513 | 1590 | if (ret) |
|---|
| 1514 | 1591 | goto error; |
|---|
| 1515 | | - uurb->buffer_length = le16_to_cpup(&dr->wLength); |
|---|
| 1592 | + uurb->buffer_length = le16_to_cpu(dr->wLength); |
|---|
| 1516 | 1593 | uurb->buffer += 8; |
|---|
| 1517 | 1594 | if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) { |
|---|
| 1518 | | - is_in = 1; |
|---|
| 1595 | + is_in = true; |
|---|
| 1519 | 1596 | uurb->endpoint |= USB_DIR_IN; |
|---|
| 1520 | 1597 | } else { |
|---|
| 1521 | | - is_in = 0; |
|---|
| 1598 | + is_in = false; |
|---|
| 1522 | 1599 | uurb->endpoint &= ~USB_DIR_IN; |
|---|
| 1523 | 1600 | } |
|---|
| 1524 | 1601 | if (is_in) |
|---|
| .. | .. |
|---|
| 1527 | 1604 | "bRequest=%02x wValue=%04x " |
|---|
| 1528 | 1605 | "wIndex=%04x wLength=%04x\n", |
|---|
| 1529 | 1606 | dr->bRequestType, dr->bRequest, |
|---|
| 1530 | | - __le16_to_cpup(&dr->wValue), |
|---|
| 1531 | | - __le16_to_cpup(&dr->wIndex), |
|---|
| 1532 | | - __le16_to_cpup(&dr->wLength)); |
|---|
| 1607 | + __le16_to_cpu(dr->wValue), |
|---|
| 1608 | + __le16_to_cpu(dr->wIndex), |
|---|
| 1609 | + __le16_to_cpu(dr->wLength)); |
|---|
| 1533 | 1610 | u = sizeof(struct usb_ctrlrequest); |
|---|
| 1534 | 1611 | break; |
|---|
| 1535 | 1612 | |
|---|
| .. | .. |
|---|
| 1582 | 1659 | } |
|---|
| 1583 | 1660 | for (totlen = u = 0; u < number_of_packets; u++) { |
|---|
| 1584 | 1661 | /* |
|---|
| 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 |
|---|
| 1662 | + * arbitrary limit need for USB 3.1 Gen2 |
|---|
| 1663 | + * sizemax: 96 DPs at SSP, 96 * 1024 = 98304 |
|---|
| 1589 | 1664 | */ |
|---|
| 1590 | | - if (isopkt[u].length > 49152) { |
|---|
| 1665 | + if (isopkt[u].length > 98304) { |
|---|
| 1591 | 1666 | ret = -EINVAL; |
|---|
| 1592 | 1667 | goto error; |
|---|
| 1593 | 1668 | } |
|---|
| .. | .. |
|---|
| 1602 | 1677 | } |
|---|
| 1603 | 1678 | |
|---|
| 1604 | 1679 | if (uurb->buffer_length > 0 && |
|---|
| 1605 | | - !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, |
|---|
| 1606 | | - uurb->buffer, uurb->buffer_length)) { |
|---|
| 1680 | + !access_ok(uurb->buffer, uurb->buffer_length)) { |
|---|
| 1607 | 1681 | ret = -EFAULT; |
|---|
| 1608 | 1682 | goto error; |
|---|
| 1609 | 1683 | } |
|---|
| .. | .. |
|---|
| 1626 | 1700 | if (as->usbm) |
|---|
| 1627 | 1701 | num_sgs = 0; |
|---|
| 1628 | 1702 | |
|---|
| 1629 | | - u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length + |
|---|
| 1703 | + u += sizeof(struct async) + sizeof(struct urb) + |
|---|
| 1704 | + (as->usbm ? 0 : uurb->buffer_length) + |
|---|
| 1630 | 1705 | num_sgs * sizeof(struct scatterlist); |
|---|
| 1631 | 1706 | ret = usbfs_increase_memory_usage(u); |
|---|
| 1632 | 1707 | if (ret) |
|---|
| .. | .. |
|---|
| 1748 | 1823 | isopkt = NULL; |
|---|
| 1749 | 1824 | as->ps = ps; |
|---|
| 1750 | 1825 | as->userurb = arg; |
|---|
| 1826 | + as->userurb_sigval = userurb_sigval; |
|---|
| 1751 | 1827 | if (as->usbm) { |
|---|
| 1752 | 1828 | unsigned long uurb_start = (unsigned long)uurb->buffer; |
|---|
| 1753 | 1829 | |
|---|
| .. | .. |
|---|
| 1820 | 1896 | static int proc_submiturb(struct usb_dev_state *ps, void __user *arg) |
|---|
| 1821 | 1897 | { |
|---|
| 1822 | 1898 | struct usbdevfs_urb uurb; |
|---|
| 1899 | + sigval_t userurb_sigval; |
|---|
| 1823 | 1900 | |
|---|
| 1824 | 1901 | if (copy_from_user(&uurb, arg, sizeof(uurb))) |
|---|
| 1825 | 1902 | return -EFAULT; |
|---|
| 1826 | 1903 | |
|---|
| 1904 | + memset(&userurb_sigval, 0, sizeof(userurb_sigval)); |
|---|
| 1905 | + userurb_sigval.sival_ptr = arg; |
|---|
| 1906 | + |
|---|
| 1827 | 1907 | return proc_do_submiturb(ps, &uurb, |
|---|
| 1828 | 1908 | (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), |
|---|
| 1829 | | - arg); |
|---|
| 1909 | + arg, userurb_sigval); |
|---|
| 1830 | 1910 | } |
|---|
| 1831 | 1911 | |
|---|
| 1832 | 1912 | static int proc_unlinkurb(struct usb_dev_state *ps, void __user *arg) |
|---|
| .. | .. |
|---|
| 1962 | 2042 | static int proc_control_compat(struct usb_dev_state *ps, |
|---|
| 1963 | 2043 | struct usbdevfs_ctrltransfer32 __user *p32) |
|---|
| 1964 | 2044 | { |
|---|
| 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)) |
|---|
| 2045 | + struct usbdevfs_ctrltransfer ctrl; |
|---|
| 2046 | + u32 udata; |
|---|
| 2047 | + |
|---|
| 2048 | + if (copy_from_user(&ctrl, p32, sizeof(*p32) - sizeof(compat_caddr_t)) || |
|---|
| 2049 | + get_user(udata, &p32->data)) |
|---|
| 1971 | 2050 | return -EFAULT; |
|---|
| 1972 | | - return proc_control(ps, p); |
|---|
| 2051 | + ctrl.data = compat_ptr(udata); |
|---|
| 2052 | + return do_proc_control(ps, &ctrl); |
|---|
| 1973 | 2053 | } |
|---|
| 1974 | 2054 | |
|---|
| 1975 | 2055 | static int proc_bulk_compat(struct usb_dev_state *ps, |
|---|
| 1976 | 2056 | struct usbdevfs_bulktransfer32 __user *p32) |
|---|
| 1977 | 2057 | { |
|---|
| 1978 | | - struct usbdevfs_bulktransfer __user *p; |
|---|
| 1979 | | - compat_uint_t n; |
|---|
| 2058 | + struct usbdevfs_bulktransfer bulk; |
|---|
| 1980 | 2059 | compat_caddr_t addr; |
|---|
| 1981 | 2060 | |
|---|
| 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)) |
|---|
| 2061 | + if (get_user(bulk.ep, &p32->ep) || |
|---|
| 2062 | + get_user(bulk.len, &p32->len) || |
|---|
| 2063 | + get_user(bulk.timeout, &p32->timeout) || |
|---|
| 2064 | + get_user(addr, &p32->data)) |
|---|
| 1988 | 2065 | return -EFAULT; |
|---|
| 1989 | | - |
|---|
| 1990 | | - return proc_bulk(ps, p); |
|---|
| 2066 | + bulk.data = compat_ptr(addr); |
|---|
| 2067 | + return do_proc_bulk(ps, &bulk); |
|---|
| 1991 | 2068 | } |
|---|
| 2069 | + |
|---|
| 1992 | 2070 | static int proc_disconnectsignal_compat(struct usb_dev_state *ps, void __user *arg) |
|---|
| 1993 | 2071 | { |
|---|
| 1994 | 2072 | struct usbdevfs_disconnectsignal32 ds; |
|---|
| .. | .. |
|---|
| 1996 | 2074 | if (copy_from_user(&ds, arg, sizeof(ds))) |
|---|
| 1997 | 2075 | return -EFAULT; |
|---|
| 1998 | 2076 | ps->discsignr = ds.signr; |
|---|
| 1999 | | - ps->disccontext = compat_ptr(ds.context); |
|---|
| 2077 | + ps->disccontext.sival_int = ds.context; |
|---|
| 2000 | 2078 | return 0; |
|---|
| 2001 | 2079 | } |
|---|
| 2002 | 2080 | |
|---|
| .. | .. |
|---|
| 2024 | 2102 | static int proc_submiturb_compat(struct usb_dev_state *ps, void __user *arg) |
|---|
| 2025 | 2103 | { |
|---|
| 2026 | 2104 | struct usbdevfs_urb uurb; |
|---|
| 2105 | + sigval_t userurb_sigval; |
|---|
| 2027 | 2106 | |
|---|
| 2028 | 2107 | if (get_urb32(&uurb, (struct usbdevfs_urb32 __user *)arg)) |
|---|
| 2029 | 2108 | return -EFAULT; |
|---|
| 2030 | 2109 | |
|---|
| 2110 | + memset(&userurb_sigval, 0, sizeof(userurb_sigval)); |
|---|
| 2111 | + userurb_sigval.sival_int = ptr_to_compat(arg); |
|---|
| 2112 | + |
|---|
| 2031 | 2113 | return proc_do_submiturb(ps, &uurb, |
|---|
| 2032 | 2114 | ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, |
|---|
| 2033 | | - arg); |
|---|
| 2115 | + arg, userurb_sigval); |
|---|
| 2034 | 2116 | } |
|---|
| 2035 | 2117 | |
|---|
| 2036 | 2118 | static int processcompl_compat(struct async *as, void __user * __user *arg) |
|---|
| .. | .. |
|---|
| 2111 | 2193 | if (copy_from_user(&ds, arg, sizeof(ds))) |
|---|
| 2112 | 2194 | return -EFAULT; |
|---|
| 2113 | 2195 | ps->discsignr = ds.signr; |
|---|
| 2114 | | - ps->disccontext = ds.context; |
|---|
| 2196 | + ps->disccontext.sival_ptr = ds.context; |
|---|
| 2115 | 2197 | return 0; |
|---|
| 2116 | 2198 | } |
|---|
| 2117 | 2199 | |
|---|
| .. | .. |
|---|
| 2149 | 2231 | if (ps->privileges_dropped) |
|---|
| 2150 | 2232 | return -EACCES; |
|---|
| 2151 | 2233 | |
|---|
| 2234 | + if (!connected(ps)) |
|---|
| 2235 | + return -ENODEV; |
|---|
| 2236 | + |
|---|
| 2152 | 2237 | /* alloc buffer */ |
|---|
| 2153 | 2238 | size = _IOC_SIZE(ctl->ioctl_code); |
|---|
| 2154 | 2239 | if (size > 0) { |
|---|
| .. | .. |
|---|
| 2163 | 2248 | } else { |
|---|
| 2164 | 2249 | memset(buf, 0, size); |
|---|
| 2165 | 2250 | } |
|---|
| 2166 | | - } |
|---|
| 2167 | | - |
|---|
| 2168 | | - if (!connected(ps)) { |
|---|
| 2169 | | - kfree(buf); |
|---|
| 2170 | | - return -ENODEV; |
|---|
| 2171 | 2251 | } |
|---|
| 2172 | 2252 | |
|---|
| 2173 | 2253 | if (ps->dev->state != USB_STATE_CONFIGURED) |
|---|
| .. | .. |
|---|
| 2271 | 2351 | |
|---|
| 2272 | 2352 | caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM | |
|---|
| 2273 | 2353 | USBDEVFS_CAP_REAP_AFTER_DISCONNECT | USBDEVFS_CAP_MMAP | |
|---|
| 2274 | | - USBDEVFS_CAP_DROP_PRIVILEGES; |
|---|
| 2354 | + USBDEVFS_CAP_DROP_PRIVILEGES | |
|---|
| 2355 | + USBDEVFS_CAP_CONNINFO_EX | MAYBE_CAP_SUSPEND; |
|---|
| 2275 | 2356 | if (!ps->dev->bus->no_stop_on_short) |
|---|
| 2276 | 2357 | caps |= USBDEVFS_CAP_BULK_CONTINUATION; |
|---|
| 2277 | 2358 | if (ps->dev->bus->sg_tablesize) |
|---|
| .. | .. |
|---|
| 2372 | 2453 | ps->privileges_dropped = true; |
|---|
| 2373 | 2454 | |
|---|
| 2374 | 2455 | return 0; |
|---|
| 2456 | +} |
|---|
| 2457 | + |
|---|
| 2458 | +static int proc_forbid_suspend(struct usb_dev_state *ps) |
|---|
| 2459 | +{ |
|---|
| 2460 | + int ret = 0; |
|---|
| 2461 | + |
|---|
| 2462 | + if (ps->suspend_allowed) { |
|---|
| 2463 | + ret = usb_autoresume_device(ps->dev); |
|---|
| 2464 | + if (ret == 0) |
|---|
| 2465 | + ps->suspend_allowed = false; |
|---|
| 2466 | + else if (ret != -ENODEV) |
|---|
| 2467 | + ret = -EIO; |
|---|
| 2468 | + } |
|---|
| 2469 | + return ret; |
|---|
| 2470 | +} |
|---|
| 2471 | + |
|---|
| 2472 | +static int proc_allow_suspend(struct usb_dev_state *ps) |
|---|
| 2473 | +{ |
|---|
| 2474 | + if (!connected(ps)) |
|---|
| 2475 | + return -ENODEV; |
|---|
| 2476 | + |
|---|
| 2477 | + WRITE_ONCE(ps->not_yet_resumed, 1); |
|---|
| 2478 | + if (!ps->suspend_allowed) { |
|---|
| 2479 | + usb_autosuspend_device(ps->dev); |
|---|
| 2480 | + ps->suspend_allowed = true; |
|---|
| 2481 | + } |
|---|
| 2482 | + return 0; |
|---|
| 2483 | +} |
|---|
| 2484 | + |
|---|
| 2485 | +static int proc_wait_for_resume(struct usb_dev_state *ps) |
|---|
| 2486 | +{ |
|---|
| 2487 | + int ret; |
|---|
| 2488 | + |
|---|
| 2489 | + usb_unlock_device(ps->dev); |
|---|
| 2490 | + ret = wait_event_interruptible(ps->wait_for_resume, |
|---|
| 2491 | + READ_ONCE(ps->not_yet_resumed) == 0); |
|---|
| 2492 | + usb_lock_device(ps->dev); |
|---|
| 2493 | + |
|---|
| 2494 | + if (ret != 0) |
|---|
| 2495 | + return -EINTR; |
|---|
| 2496 | + return proc_forbid_suspend(ps); |
|---|
| 2375 | 2497 | } |
|---|
| 2376 | 2498 | |
|---|
| 2377 | 2499 | /* |
|---|
| .. | .. |
|---|
| 2568 | 2690 | case USBDEVFS_GET_SPEED: |
|---|
| 2569 | 2691 | ret = ps->dev->speed; |
|---|
| 2570 | 2692 | break; |
|---|
| 2693 | + case USBDEVFS_FORBID_SUSPEND: |
|---|
| 2694 | + ret = proc_forbid_suspend(ps); |
|---|
| 2695 | + break; |
|---|
| 2696 | + case USBDEVFS_ALLOW_SUSPEND: |
|---|
| 2697 | + ret = proc_allow_suspend(ps); |
|---|
| 2698 | + break; |
|---|
| 2699 | + case USBDEVFS_WAIT_FOR_RESUME: |
|---|
| 2700 | + ret = proc_wait_for_resume(ps); |
|---|
| 2701 | + break; |
|---|
| 2702 | + } |
|---|
| 2703 | + |
|---|
| 2704 | + /* Handle variable-length commands */ |
|---|
| 2705 | + switch (cmd & ~IOCSIZE_MASK) { |
|---|
| 2706 | + case USBDEVFS_CONNINFO_EX(0): |
|---|
| 2707 | + ret = proc_conninfo_ex(ps, p, _IOC_SIZE(cmd)); |
|---|
| 2708 | + break; |
|---|
| 2571 | 2709 | } |
|---|
| 2572 | 2710 | |
|---|
| 2573 | 2711 | done: |
|---|
| .. | .. |
|---|
| 2586 | 2724 | |
|---|
| 2587 | 2725 | return ret; |
|---|
| 2588 | 2726 | } |
|---|
| 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 | 2727 | |
|---|
| 2602 | 2728 | /* No kernel lock - fine */ |
|---|
| 2603 | 2729 | static __poll_t usbdev_poll(struct file *file, |
|---|
| .. | .. |
|---|
| 2622 | 2748 | .read = usbdev_read, |
|---|
| 2623 | 2749 | .poll = usbdev_poll, |
|---|
| 2624 | 2750 | .unlocked_ioctl = usbdev_ioctl, |
|---|
| 2625 | | -#ifdef CONFIG_COMPAT |
|---|
| 2626 | | - .compat_ioctl = usbdev_compat_ioctl, |
|---|
| 2627 | | -#endif |
|---|
| 2751 | + .compat_ioctl = compat_ptr_ioctl, |
|---|
| 2628 | 2752 | .mmap = usbdev_mmap, |
|---|
| 2629 | 2753 | .open = usbdev_open, |
|---|
| 2630 | 2754 | .release = usbdev_release, |
|---|
| .. | .. |
|---|
| 2633 | 2757 | static void usbdev_remove(struct usb_device *udev) |
|---|
| 2634 | 2758 | { |
|---|
| 2635 | 2759 | struct usb_dev_state *ps; |
|---|
| 2636 | | - struct siginfo sinfo; |
|---|
| 2637 | 2760 | |
|---|
| 2761 | + /* Protect against simultaneous resume */ |
|---|
| 2762 | + mutex_lock(&usbfs_mutex); |
|---|
| 2638 | 2763 | while (!list_empty(&udev->filelist)) { |
|---|
| 2639 | 2764 | ps = list_entry(udev->filelist.next, struct usb_dev_state, list); |
|---|
| 2640 | 2765 | destroy_all_async(ps); |
|---|
| 2641 | 2766 | wake_up_all(&ps->wait); |
|---|
| 2767 | + WRITE_ONCE(ps->not_yet_resumed, 0); |
|---|
| 2768 | + wake_up_all(&ps->wait_for_resume); |
|---|
| 2642 | 2769 | 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 | | - } |
|---|
| 2770 | + if (ps->discsignr) |
|---|
| 2771 | + kill_pid_usb_asyncio(ps->discsignr, EPIPE, ps->disccontext, |
|---|
| 2772 | + ps->disc_pid, ps->cred); |
|---|
| 2652 | 2773 | } |
|---|
| 2774 | + mutex_unlock(&usbfs_mutex); |
|---|
| 2653 | 2775 | } |
|---|
| 2654 | 2776 | |
|---|
| 2655 | 2777 | static int usbdev_notify(struct notifier_block *self, |
|---|