diff options
Diffstat (limited to 'drivers/usb/core/devio.c')
-rw-r--r-- | drivers/usb/core/devio.c | 174 |
1 files changed, 159 insertions, 15 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 2a8afe6754b8..257876ea03a1 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c | |||
@@ -769,6 +769,88 @@ static int check_ctrlrecip(struct usb_dev_state *ps, unsigned int requesttype, | |||
769 | return ret; | 769 | return ret; |
770 | } | 770 | } |
771 | 771 | ||
772 | static struct usb_host_endpoint *ep_to_host_endpoint(struct usb_device *dev, | ||
773 | unsigned char ep) | ||
774 | { | ||
775 | if (ep & USB_ENDPOINT_DIR_MASK) | ||
776 | return dev->ep_in[ep & USB_ENDPOINT_NUMBER_MASK]; | ||
777 | else | ||
778 | return dev->ep_out[ep & USB_ENDPOINT_NUMBER_MASK]; | ||
779 | } | ||
780 | |||
781 | static int parse_usbdevfs_streams(struct usb_dev_state *ps, | ||
782 | struct usbdevfs_streams __user *streams, | ||
783 | unsigned int *num_streams_ret, | ||
784 | unsigned int *num_eps_ret, | ||
785 | struct usb_host_endpoint ***eps_ret, | ||
786 | struct usb_interface **intf_ret) | ||
787 | { | ||
788 | unsigned int i, num_streams, num_eps; | ||
789 | struct usb_host_endpoint **eps; | ||
790 | struct usb_interface *intf = NULL; | ||
791 | unsigned char ep; | ||
792 | int ifnum, ret; | ||
793 | |||
794 | if (get_user(num_streams, &streams->num_streams) || | ||
795 | get_user(num_eps, &streams->num_eps)) | ||
796 | return -EFAULT; | ||
797 | |||
798 | if (num_eps < 1 || num_eps > USB_MAXENDPOINTS) | ||
799 | return -EINVAL; | ||
800 | |||
801 | /* The XHCI controller allows max 2 ^ 16 streams */ | ||
802 | if (num_streams_ret && (num_streams < 2 || num_streams > 65536)) | ||
803 | return -EINVAL; | ||
804 | |||
805 | eps = kmalloc(num_eps * sizeof(*eps), GFP_KERNEL); | ||
806 | if (!eps) | ||
807 | return -ENOMEM; | ||
808 | |||
809 | for (i = 0; i < num_eps; i++) { | ||
810 | if (get_user(ep, &streams->eps[i])) { | ||
811 | ret = -EFAULT; | ||
812 | goto error; | ||
813 | } | ||
814 | eps[i] = ep_to_host_endpoint(ps->dev, ep); | ||
815 | if (!eps[i]) { | ||
816 | ret = -EINVAL; | ||
817 | goto error; | ||
818 | } | ||
819 | |||
820 | /* usb_alloc/free_streams operate on an usb_interface */ | ||
821 | ifnum = findintfep(ps->dev, ep); | ||
822 | if (ifnum < 0) { | ||
823 | ret = ifnum; | ||
824 | goto error; | ||
825 | } | ||
826 | |||
827 | if (i == 0) { | ||
828 | ret = checkintf(ps, ifnum); | ||
829 | if (ret < 0) | ||
830 | goto error; | ||
831 | intf = usb_ifnum_to_if(ps->dev, ifnum); | ||
832 | } else { | ||
833 | /* Verify all eps belong to the same interface */ | ||
834 | if (ifnum != intf->altsetting->desc.bInterfaceNumber) { | ||
835 | ret = -EINVAL; | ||
836 | goto error; | ||
837 | } | ||
838 | } | ||
839 | } | ||
840 | |||
841 | if (num_streams_ret) | ||
842 | *num_streams_ret = num_streams; | ||
843 | *num_eps_ret = num_eps; | ||
844 | *eps_ret = eps; | ||
845 | *intf_ret = intf; | ||
846 | |||
847 | return 0; | ||
848 | |||
849 | error: | ||
850 | kfree(eps); | ||
851 | return ret; | ||
852 | } | ||
853 | |||
772 | static int match_devt(struct device *dev, void *data) | 854 | static int match_devt(struct device *dev, void *data) |
773 | { | 855 | { |
774 | return dev->devt == (dev_t) (unsigned long) data; | 856 | return dev->devt == (dev_t) (unsigned long) data; |
@@ -1043,6 +1125,20 @@ static int proc_bulk(struct usb_dev_state *ps, void __user *arg) | |||
1043 | return ret; | 1125 | return ret; |
1044 | } | 1126 | } |
1045 | 1127 | ||
1128 | static void check_reset_of_active_ep(struct usb_device *udev, | ||
1129 | unsigned int epnum, char *ioctl_name) | ||
1130 | { | ||
1131 | struct usb_host_endpoint **eps; | ||
1132 | struct usb_host_endpoint *ep; | ||
1133 | |||
1134 | eps = (epnum & USB_DIR_IN) ? udev->ep_in : udev->ep_out; | ||
1135 | ep = eps[epnum & 0x0f]; | ||
1136 | if (ep && !list_empty(&ep->urb_list)) | ||
1137 | dev_warn(&udev->dev, "Process %d (%s) called USBDEVFS_%s for active endpoint 0x%02x\n", | ||
1138 | task_pid_nr(current), current->comm, | ||
1139 | ioctl_name, epnum); | ||
1140 | } | ||
1141 | |||
1046 | static int proc_resetep(struct usb_dev_state *ps, void __user *arg) | 1142 | static int proc_resetep(struct usb_dev_state *ps, void __user *arg) |
1047 | { | 1143 | { |
1048 | unsigned int ep; | 1144 | unsigned int ep; |
@@ -1056,6 +1152,7 @@ static int proc_resetep(struct usb_dev_state *ps, void __user *arg) | |||
1056 | ret = checkintf(ps, ret); | 1152 | ret = checkintf(ps, ret); |
1057 | if (ret) | 1153 | if (ret) |
1058 | return ret; | 1154 | return ret; |
1155 | check_reset_of_active_ep(ps->dev, ep, "RESETEP"); | ||
1059 | usb_reset_endpoint(ps->dev, ep); | 1156 | usb_reset_endpoint(ps->dev, ep); |
1060 | return 0; | 1157 | return 0; |
1061 | } | 1158 | } |
@@ -1074,6 +1171,7 @@ static int proc_clearhalt(struct usb_dev_state *ps, void __user *arg) | |||
1074 | ret = checkintf(ps, ret); | 1171 | ret = checkintf(ps, ret); |
1075 | if (ret) | 1172 | if (ret) |
1076 | return ret; | 1173 | return ret; |
1174 | check_reset_of_active_ep(ps->dev, ep, "CLEAR_HALT"); | ||
1077 | if (ep & USB_DIR_IN) | 1175 | if (ep & USB_DIR_IN) |
1078 | pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f); | 1176 | pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f); |
1079 | else | 1177 | else |
@@ -1127,6 +1225,9 @@ static int proc_setintf(struct usb_dev_state *ps, void __user *arg) | |||
1127 | return -EFAULT; | 1225 | return -EFAULT; |
1128 | if ((ret = checkintf(ps, setintf.interface))) | 1226 | if ((ret = checkintf(ps, setintf.interface))) |
1129 | return ret; | 1227 | return ret; |
1228 | |||
1229 | destroy_async_on_interface(ps, setintf.interface); | ||
1230 | |||
1130 | return usb_set_interface(ps->dev, setintf.interface, | 1231 | return usb_set_interface(ps->dev, setintf.interface, |
1131 | setintf.altsetting); | 1232 | setintf.altsetting); |
1132 | } | 1233 | } |
@@ -1189,6 +1290,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb | |||
1189 | struct usb_ctrlrequest *dr = NULL; | 1290 | struct usb_ctrlrequest *dr = NULL; |
1190 | unsigned int u, totlen, isofrmlen; | 1291 | unsigned int u, totlen, isofrmlen; |
1191 | int i, ret, is_in, num_sgs = 0, ifnum = -1; | 1292 | int i, ret, is_in, num_sgs = 0, ifnum = -1; |
1293 | int number_of_packets = 0; | ||
1294 | unsigned int stream_id = 0; | ||
1192 | void *buf; | 1295 | void *buf; |
1193 | 1296 | ||
1194 | if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP | | 1297 | if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP | |
@@ -1209,15 +1312,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb | |||
1209 | if (ret) | 1312 | if (ret) |
1210 | return ret; | 1313 | return ret; |
1211 | } | 1314 | } |
1212 | if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) { | 1315 | ep = ep_to_host_endpoint(ps->dev, uurb->endpoint); |
1213 | is_in = 1; | ||
1214 | ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; | ||
1215 | } else { | ||
1216 | is_in = 0; | ||
1217 | ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; | ||
1218 | } | ||
1219 | if (!ep) | 1316 | if (!ep) |
1220 | return -ENOENT; | 1317 | return -ENOENT; |
1318 | is_in = (uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0; | ||
1221 | 1319 | ||
1222 | u = 0; | 1320 | u = 0; |
1223 | switch(uurb->type) { | 1321 | switch(uurb->type) { |
@@ -1242,7 +1340,6 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb | |||
1242 | le16_to_cpup(&dr->wIndex)); | 1340 | le16_to_cpup(&dr->wIndex)); |
1243 | if (ret) | 1341 | if (ret) |
1244 | goto error; | 1342 | goto error; |
1245 | uurb->number_of_packets = 0; | ||
1246 | uurb->buffer_length = le16_to_cpup(&dr->wLength); | 1343 | uurb->buffer_length = le16_to_cpup(&dr->wLength); |
1247 | uurb->buffer += 8; | 1344 | uurb->buffer += 8; |
1248 | if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) { | 1345 | if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) { |
@@ -1272,17 +1369,17 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb | |||
1272 | uurb->type = USBDEVFS_URB_TYPE_INTERRUPT; | 1369 | uurb->type = USBDEVFS_URB_TYPE_INTERRUPT; |
1273 | goto interrupt_urb; | 1370 | goto interrupt_urb; |
1274 | } | 1371 | } |
1275 | uurb->number_of_packets = 0; | ||
1276 | num_sgs = DIV_ROUND_UP(uurb->buffer_length, USB_SG_SIZE); | 1372 | num_sgs = DIV_ROUND_UP(uurb->buffer_length, USB_SG_SIZE); |
1277 | if (num_sgs == 1 || num_sgs > ps->dev->bus->sg_tablesize) | 1373 | if (num_sgs == 1 || num_sgs > ps->dev->bus->sg_tablesize) |
1278 | num_sgs = 0; | 1374 | num_sgs = 0; |
1375 | if (ep->streams) | ||
1376 | stream_id = uurb->stream_id; | ||
1279 | break; | 1377 | break; |
1280 | 1378 | ||
1281 | case USBDEVFS_URB_TYPE_INTERRUPT: | 1379 | case USBDEVFS_URB_TYPE_INTERRUPT: |
1282 | if (!usb_endpoint_xfer_int(&ep->desc)) | 1380 | if (!usb_endpoint_xfer_int(&ep->desc)) |
1283 | return -EINVAL; | 1381 | return -EINVAL; |
1284 | interrupt_urb: | 1382 | interrupt_urb: |
1285 | uurb->number_of_packets = 0; | ||
1286 | break; | 1383 | break; |
1287 | 1384 | ||
1288 | case USBDEVFS_URB_TYPE_ISO: | 1385 | case USBDEVFS_URB_TYPE_ISO: |
@@ -1292,15 +1389,16 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb | |||
1292 | return -EINVAL; | 1389 | return -EINVAL; |
1293 | if (!usb_endpoint_xfer_isoc(&ep->desc)) | 1390 | if (!usb_endpoint_xfer_isoc(&ep->desc)) |
1294 | return -EINVAL; | 1391 | return -EINVAL; |
1392 | number_of_packets = uurb->number_of_packets; | ||
1295 | isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * | 1393 | isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * |
1296 | uurb->number_of_packets; | 1394 | number_of_packets; |
1297 | if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) | 1395 | if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) |
1298 | return -ENOMEM; | 1396 | return -ENOMEM; |
1299 | if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { | 1397 | if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { |
1300 | ret = -EFAULT; | 1398 | ret = -EFAULT; |
1301 | goto error; | 1399 | goto error; |
1302 | } | 1400 | } |
1303 | for (totlen = u = 0; u < uurb->number_of_packets; u++) { | 1401 | for (totlen = u = 0; u < number_of_packets; u++) { |
1304 | /* | 1402 | /* |
1305 | * arbitrary limit need for USB 3.0 | 1403 | * arbitrary limit need for USB 3.0 |
1306 | * bMaxBurst (0~15 allowed, 1~16 packets) | 1404 | * bMaxBurst (0~15 allowed, 1~16 packets) |
@@ -1331,7 +1429,7 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb | |||
1331 | ret = -EFAULT; | 1429 | ret = -EFAULT; |
1332 | goto error; | 1430 | goto error; |
1333 | } | 1431 | } |
1334 | as = alloc_async(uurb->number_of_packets); | 1432 | as = alloc_async(number_of_packets); |
1335 | if (!as) { | 1433 | if (!as) { |
1336 | ret = -ENOMEM; | 1434 | ret = -ENOMEM; |
1337 | goto error; | 1435 | goto error; |
@@ -1425,7 +1523,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb | |||
1425 | as->urb->setup_packet = (unsigned char *)dr; | 1523 | as->urb->setup_packet = (unsigned char *)dr; |
1426 | dr = NULL; | 1524 | dr = NULL; |
1427 | as->urb->start_frame = uurb->start_frame; | 1525 | as->urb->start_frame = uurb->start_frame; |
1428 | as->urb->number_of_packets = uurb->number_of_packets; | 1526 | as->urb->number_of_packets = number_of_packets; |
1527 | as->urb->stream_id = stream_id; | ||
1429 | if (uurb->type == USBDEVFS_URB_TYPE_ISO || | 1528 | if (uurb->type == USBDEVFS_URB_TYPE_ISO || |
1430 | ps->dev->speed == USB_SPEED_HIGH) | 1529 | ps->dev->speed == USB_SPEED_HIGH) |
1431 | as->urb->interval = 1 << min(15, ep->desc.bInterval - 1); | 1530 | as->urb->interval = 1 << min(15, ep->desc.bInterval - 1); |
@@ -1433,7 +1532,7 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb | |||
1433 | as->urb->interval = ep->desc.bInterval; | 1532 | as->urb->interval = ep->desc.bInterval; |
1434 | as->urb->context = as; | 1533 | as->urb->context = as; |
1435 | as->urb->complete = async_completed; | 1534 | as->urb->complete = async_completed; |
1436 | for (totlen = u = 0; u < uurb->number_of_packets; u++) { | 1535 | for (totlen = u = 0; u < number_of_packets; u++) { |
1437 | as->urb->iso_frame_desc[u].offset = totlen; | 1536 | as->urb->iso_frame_desc[u].offset = totlen; |
1438 | as->urb->iso_frame_desc[u].length = isopkt[u].length; | 1537 | as->urb->iso_frame_desc[u].length = isopkt[u].length; |
1439 | totlen += isopkt[u].length; | 1538 | totlen += isopkt[u].length; |
@@ -1983,6 +2082,45 @@ static int proc_disconnect_claim(struct usb_dev_state *ps, void __user *arg) | |||
1983 | return claimintf(ps, dc.interface); | 2082 | return claimintf(ps, dc.interface); |
1984 | } | 2083 | } |
1985 | 2084 | ||
2085 | static int proc_alloc_streams(struct usb_dev_state *ps, void __user *arg) | ||
2086 | { | ||
2087 | unsigned num_streams, num_eps; | ||
2088 | struct usb_host_endpoint **eps; | ||
2089 | struct usb_interface *intf; | ||
2090 | int r; | ||
2091 | |||
2092 | r = parse_usbdevfs_streams(ps, arg, &num_streams, &num_eps, | ||
2093 | &eps, &intf); | ||
2094 | if (r) | ||
2095 | return r; | ||
2096 | |||
2097 | destroy_async_on_interface(ps, | ||
2098 | intf->altsetting[0].desc.bInterfaceNumber); | ||
2099 | |||
2100 | r = usb_alloc_streams(intf, eps, num_eps, num_streams, GFP_KERNEL); | ||
2101 | kfree(eps); | ||
2102 | return r; | ||
2103 | } | ||
2104 | |||
2105 | static int proc_free_streams(struct usb_dev_state *ps, void __user *arg) | ||
2106 | { | ||
2107 | unsigned num_eps; | ||
2108 | struct usb_host_endpoint **eps; | ||
2109 | struct usb_interface *intf; | ||
2110 | int r; | ||
2111 | |||
2112 | r = parse_usbdevfs_streams(ps, arg, NULL, &num_eps, &eps, &intf); | ||
2113 | if (r) | ||
2114 | return r; | ||
2115 | |||
2116 | destroy_async_on_interface(ps, | ||
2117 | intf->altsetting[0].desc.bInterfaceNumber); | ||
2118 | |||
2119 | r = usb_free_streams(intf, eps, num_eps, GFP_KERNEL); | ||
2120 | kfree(eps); | ||
2121 | return r; | ||
2122 | } | ||
2123 | |||
1986 | /* | 2124 | /* |
1987 | * NOTE: All requests here that have interface numbers as parameters | 2125 | * NOTE: All requests here that have interface numbers as parameters |
1988 | * are assuming that somehow the configuration has been prevented from | 2126 | * are assuming that somehow the configuration has been prevented from |
@@ -2159,6 +2297,12 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd, | |||
2159 | case USBDEVFS_DISCONNECT_CLAIM: | 2297 | case USBDEVFS_DISCONNECT_CLAIM: |
2160 | ret = proc_disconnect_claim(ps, p); | 2298 | ret = proc_disconnect_claim(ps, p); |
2161 | break; | 2299 | break; |
2300 | case USBDEVFS_ALLOC_STREAMS: | ||
2301 | ret = proc_alloc_streams(ps, p); | ||
2302 | break; | ||
2303 | case USBDEVFS_FREE_STREAMS: | ||
2304 | ret = proc_free_streams(ps, p); | ||
2305 | break; | ||
2162 | } | 2306 | } |
2163 | usb_unlock_device(dev); | 2307 | usb_unlock_device(dev); |
2164 | if (ret >= 0) | 2308 | if (ret >= 0) |