diff options
Diffstat (limited to 'drivers/usb/core/devio.c')
-rw-r--r-- | drivers/usb/core/devio.c | 247 |
1 files changed, 176 insertions, 71 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 4247eccf858c..181f78c84105 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c | |||
@@ -52,6 +52,7 @@ | |||
52 | 52 | ||
53 | #include "hcd.h" /* for usbcore internals */ | 53 | #include "hcd.h" /* for usbcore internals */ |
54 | #include "usb.h" | 54 | #include "usb.h" |
55 | #include "hub.h" | ||
55 | 56 | ||
56 | #define USB_MAXBUS 64 | 57 | #define USB_MAXBUS 64 |
57 | #define USB_DEVICE_MAX USB_MAXBUS * 128 | 58 | #define USB_DEVICE_MAX USB_MAXBUS * 128 |
@@ -73,6 +74,7 @@ struct dev_state { | |||
73 | void __user *disccontext; | 74 | void __user *disccontext; |
74 | unsigned long ifclaimed; | 75 | unsigned long ifclaimed; |
75 | u32 secid; | 76 | u32 secid; |
77 | u32 disabled_bulk_eps; | ||
76 | }; | 78 | }; |
77 | 79 | ||
78 | struct async { | 80 | struct async { |
@@ -87,6 +89,8 @@ struct async { | |||
87 | struct urb *urb; | 89 | struct urb *urb; |
88 | int status; | 90 | int status; |
89 | u32 secid; | 91 | u32 secid; |
92 | u8 bulk_addr; | ||
93 | u8 bulk_status; | ||
90 | }; | 94 | }; |
91 | 95 | ||
92 | static int usbfs_snoop; | 96 | static int usbfs_snoop; |
@@ -99,11 +103,15 @@ MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic"); | |||
99 | dev_info(dev , format , ## arg); \ | 103 | dev_info(dev , format , ## arg); \ |
100 | } while (0) | 104 | } while (0) |
101 | 105 | ||
102 | #define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) | 106 | enum snoop_when { |
107 | SUBMIT, COMPLETE | ||
108 | }; | ||
103 | 109 | ||
110 | #define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) | ||
104 | 111 | ||
105 | #define MAX_USBFS_BUFFER_SIZE 16384 | 112 | #define MAX_USBFS_BUFFER_SIZE 16384 |
106 | 113 | ||
114 | |||
107 | static int connected(struct dev_state *ps) | 115 | static int connected(struct dev_state *ps) |
108 | { | 116 | { |
109 | return (!list_empty(&ps->list) && | 117 | return (!list_empty(&ps->list) && |
@@ -300,24 +308,79 @@ static struct async *async_getpending(struct dev_state *ps, | |||
300 | return NULL; | 308 | return NULL; |
301 | } | 309 | } |
302 | 310 | ||
303 | static void snoop_urb(struct urb *urb, void __user *userurb) | 311 | static void snoop_urb(struct usb_device *udev, |
312 | void __user *userurb, int pipe, unsigned length, | ||
313 | int timeout_or_status, enum snoop_when when) | ||
304 | { | 314 | { |
305 | unsigned j; | 315 | static const char *types[] = {"isoc", "int", "ctrl", "bulk"}; |
306 | unsigned char *data = urb->transfer_buffer; | 316 | static const char *dirs[] = {"out", "in"}; |
317 | int ep; | ||
318 | const char *t, *d; | ||
307 | 319 | ||
308 | if (!usbfs_snoop) | 320 | if (!usbfs_snoop) |
309 | return; | 321 | return; |
310 | 322 | ||
311 | dev_info(&urb->dev->dev, "direction=%s\n", | 323 | ep = usb_pipeendpoint(pipe); |
312 | usb_urb_dir_in(urb) ? "IN" : "OUT"); | 324 | t = types[usb_pipetype(pipe)]; |
313 | dev_info(&urb->dev->dev, "userurb=%p\n", userurb); | 325 | d = dirs[!!usb_pipein(pipe)]; |
314 | dev_info(&urb->dev->dev, "transfer_buffer_length=%u\n", | 326 | |
315 | urb->transfer_buffer_length); | 327 | if (userurb) { /* Async */ |
316 | dev_info(&urb->dev->dev, "actual_length=%u\n", urb->actual_length); | 328 | if (when == SUBMIT) |
317 | dev_info(&urb->dev->dev, "data: "); | 329 | dev_info(&udev->dev, "userurb %p, ep%d %s-%s, " |
318 | for (j = 0; j < urb->transfer_buffer_length; ++j) | 330 | "length %u\n", |
319 | printk("%02x ", data[j]); | 331 | userurb, ep, t, d, length); |
320 | printk("\n"); | 332 | else |
333 | dev_info(&udev->dev, "userurb %p, ep%d %s-%s, " | ||
334 | "actual_length %u status %d\n", | ||
335 | userurb, ep, t, d, length, | ||
336 | timeout_or_status); | ||
337 | } else { | ||
338 | if (when == SUBMIT) | ||
339 | dev_info(&udev->dev, "ep%d %s-%s, length %u, " | ||
340 | "timeout %d\n", | ||
341 | ep, t, d, length, timeout_or_status); | ||
342 | else | ||
343 | dev_info(&udev->dev, "ep%d %s-%s, actual_length %u, " | ||
344 | "status %d\n", | ||
345 | ep, t, d, length, timeout_or_status); | ||
346 | } | ||
347 | } | ||
348 | |||
349 | #define AS_CONTINUATION 1 | ||
350 | #define AS_UNLINK 2 | ||
351 | |||
352 | static void cancel_bulk_urbs(struct dev_state *ps, unsigned bulk_addr) | ||
353 | __releases(ps->lock) | ||
354 | __acquires(ps->lock) | ||
355 | { | ||
356 | struct async *as; | ||
357 | |||
358 | /* Mark all the pending URBs that match bulk_addr, up to but not | ||
359 | * including the first one without AS_CONTINUATION. If such an | ||
360 | * URB is encountered then a new transfer has already started so | ||
361 | * the endpoint doesn't need to be disabled; otherwise it does. | ||
362 | */ | ||
363 | list_for_each_entry(as, &ps->async_pending, asynclist) { | ||
364 | if (as->bulk_addr == bulk_addr) { | ||
365 | if (as->bulk_status != AS_CONTINUATION) | ||
366 | goto rescan; | ||
367 | as->bulk_status = AS_UNLINK; | ||
368 | as->bulk_addr = 0; | ||
369 | } | ||
370 | } | ||
371 | ps->disabled_bulk_eps |= (1 << bulk_addr); | ||
372 | |||
373 | /* Now carefully unlink all the marked pending URBs */ | ||
374 | rescan: | ||
375 | list_for_each_entry(as, &ps->async_pending, asynclist) { | ||
376 | if (as->bulk_status == AS_UNLINK) { | ||
377 | as->bulk_status = 0; /* Only once */ | ||
378 | spin_unlock(&ps->lock); /* Allow completions */ | ||
379 | usb_unlink_urb(as->urb); | ||
380 | spin_lock(&ps->lock); | ||
381 | goto rescan; | ||
382 | } | ||
383 | } | ||
321 | } | 384 | } |
322 | 385 | ||
323 | static void async_completed(struct urb *urb) | 386 | static void async_completed(struct urb *urb) |
@@ -346,7 +409,11 @@ static void async_completed(struct urb *urb) | |||
346 | secid = as->secid; | 409 | secid = as->secid; |
347 | } | 410 | } |
348 | snoop(&urb->dev->dev, "urb complete\n"); | 411 | snoop(&urb->dev->dev, "urb complete\n"); |
349 | snoop_urb(urb, as->userurb); | 412 | snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length, |
413 | as->status, COMPLETE); | ||
414 | if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET && | ||
415 | as->status != -ENOENT) | ||
416 | cancel_bulk_urbs(ps, as->bulk_addr); | ||
350 | spin_unlock(&ps->lock); | 417 | spin_unlock(&ps->lock); |
351 | 418 | ||
352 | if (signr) | 419 | if (signr) |
@@ -655,6 +722,7 @@ static int usbdev_release(struct inode *inode, struct file *file) | |||
655 | struct async *as; | 722 | struct async *as; |
656 | 723 | ||
657 | usb_lock_device(dev); | 724 | usb_lock_device(dev); |
725 | usb_hub_release_all_ports(dev, ps); | ||
658 | 726 | ||
659 | /* Protect against simultaneous open */ | 727 | /* Protect against simultaneous open */ |
660 | mutex_lock(&usbfs_mutex); | 728 | mutex_lock(&usbfs_mutex); |
@@ -688,7 +756,7 @@ static int proc_control(struct dev_state *ps, void __user *arg) | |||
688 | unsigned int tmo; | 756 | unsigned int tmo; |
689 | unsigned char *tbuf; | 757 | unsigned char *tbuf; |
690 | unsigned wLength; | 758 | unsigned wLength; |
691 | int i, j, ret; | 759 | int i, pipe, ret; |
692 | 760 | ||
693 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | 761 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) |
694 | return -EFAULT; | 762 | return -EFAULT; |
@@ -708,24 +776,17 @@ static int proc_control(struct dev_state *ps, void __user *arg) | |||
708 | free_page((unsigned long)tbuf); | 776 | free_page((unsigned long)tbuf); |
709 | return -EINVAL; | 777 | return -EINVAL; |
710 | } | 778 | } |
711 | snoop(&dev->dev, "control read: bRequest=%02x " | 779 | pipe = usb_rcvctrlpipe(dev, 0); |
712 | "bRrequestType=%02x wValue=%04x " | 780 | snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT); |
713 | "wIndex=%04x wLength=%04x\n", | ||
714 | ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, | ||
715 | ctrl.wIndex, ctrl.wLength); | ||
716 | 781 | ||
717 | usb_unlock_device(dev); | 782 | usb_unlock_device(dev); |
718 | i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, | 783 | i = usb_control_msg(dev, pipe, ctrl.bRequest, |
719 | ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, | 784 | ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, |
720 | tbuf, ctrl.wLength, tmo); | 785 | tbuf, ctrl.wLength, tmo); |
721 | usb_lock_device(dev); | 786 | usb_lock_device(dev); |
787 | snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE); | ||
788 | |||
722 | if ((i > 0) && ctrl.wLength) { | 789 | if ((i > 0) && ctrl.wLength) { |
723 | if (usbfs_snoop) { | ||
724 | dev_info(&dev->dev, "control read: data "); | ||
725 | for (j = 0; j < i; ++j) | ||
726 | printk("%02x ", (u8)(tbuf)[j]); | ||
727 | printk("\n"); | ||
728 | } | ||
729 | if (copy_to_user(ctrl.data, tbuf, i)) { | 790 | if (copy_to_user(ctrl.data, tbuf, i)) { |
730 | free_page((unsigned long)tbuf); | 791 | free_page((unsigned long)tbuf); |
731 | return -EFAULT; | 792 | return -EFAULT; |
@@ -738,22 +799,15 @@ static int proc_control(struct dev_state *ps, void __user *arg) | |||
738 | return -EFAULT; | 799 | return -EFAULT; |
739 | } | 800 | } |
740 | } | 801 | } |
741 | snoop(&dev->dev, "control write: bRequest=%02x " | 802 | pipe = usb_sndctrlpipe(dev, 0); |
742 | "bRrequestType=%02x wValue=%04x " | 803 | snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT); |
743 | "wIndex=%04x wLength=%04x\n", | 804 | |
744 | ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, | ||
745 | ctrl.wIndex, ctrl.wLength); | ||
746 | if (usbfs_snoop) { | ||
747 | dev_info(&dev->dev, "control write: data: "); | ||
748 | for (j = 0; j < ctrl.wLength; ++j) | ||
749 | printk("%02x ", (unsigned char)(tbuf)[j]); | ||
750 | printk("\n"); | ||
751 | } | ||
752 | usb_unlock_device(dev); | 805 | usb_unlock_device(dev); |
753 | i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, | 806 | i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, |
754 | ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, | 807 | ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, |
755 | tbuf, ctrl.wLength, tmo); | 808 | tbuf, ctrl.wLength, tmo); |
756 | usb_lock_device(dev); | 809 | usb_lock_device(dev); |
810 | snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE); | ||
757 | } | 811 | } |
758 | free_page((unsigned long)tbuf); | 812 | free_page((unsigned long)tbuf); |
759 | if (i < 0 && i != -EPIPE) { | 813 | if (i < 0 && i != -EPIPE) { |
@@ -772,7 +826,7 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) | |||
772 | unsigned int tmo, len1, pipe; | 826 | unsigned int tmo, len1, pipe; |
773 | int len2; | 827 | int len2; |
774 | unsigned char *tbuf; | 828 | unsigned char *tbuf; |
775 | int i, j, ret; | 829 | int i, ret; |
776 | 830 | ||
777 | if (copy_from_user(&bulk, arg, sizeof(bulk))) | 831 | if (copy_from_user(&bulk, arg, sizeof(bulk))) |
778 | return -EFAULT; | 832 | return -EFAULT; |
@@ -799,18 +853,14 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) | |||
799 | kfree(tbuf); | 853 | kfree(tbuf); |
800 | return -EINVAL; | 854 | return -EINVAL; |
801 | } | 855 | } |
802 | snoop(&dev->dev, "bulk read: len=0x%02x timeout=%04d\n", | 856 | snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT); |
803 | bulk.len, bulk.timeout); | 857 | |
804 | usb_unlock_device(dev); | 858 | usb_unlock_device(dev); |
805 | i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); | 859 | i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); |
806 | usb_lock_device(dev); | 860 | usb_lock_device(dev); |
861 | snoop_urb(dev, NULL, pipe, len2, i, COMPLETE); | ||
862 | |||
807 | if (!i && len2) { | 863 | if (!i && len2) { |
808 | if (usbfs_snoop) { | ||
809 | dev_info(&dev->dev, "bulk read: data "); | ||
810 | for (j = 0; j < len2; ++j) | ||
811 | printk("%02x ", (u8)(tbuf)[j]); | ||
812 | printk("\n"); | ||
813 | } | ||
814 | if (copy_to_user(bulk.data, tbuf, len2)) { | 864 | if (copy_to_user(bulk.data, tbuf, len2)) { |
815 | kfree(tbuf); | 865 | kfree(tbuf); |
816 | return -EFAULT; | 866 | return -EFAULT; |
@@ -823,17 +873,12 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) | |||
823 | return -EFAULT; | 873 | return -EFAULT; |
824 | } | 874 | } |
825 | } | 875 | } |
826 | snoop(&dev->dev, "bulk write: len=0x%02x timeout=%04d\n", | 876 | snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT); |
827 | bulk.len, bulk.timeout); | 877 | |
828 | if (usbfs_snoop) { | ||
829 | dev_info(&dev->dev, "bulk write: data: "); | ||
830 | for (j = 0; j < len1; ++j) | ||
831 | printk("%02x ", (unsigned char)(tbuf)[j]); | ||
832 | printk("\n"); | ||
833 | } | ||
834 | usb_unlock_device(dev); | 878 | usb_unlock_device(dev); |
835 | i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); | 879 | i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); |
836 | usb_lock_device(dev); | 880 | usb_lock_device(dev); |
881 | snoop_urb(dev, NULL, pipe, len2, i, COMPLETE); | ||
837 | } | 882 | } |
838 | kfree(tbuf); | 883 | kfree(tbuf); |
839 | if (i < 0) | 884 | if (i < 0) |
@@ -991,6 +1036,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
991 | 1036 | ||
992 | if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP | | 1037 | if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP | |
993 | USBDEVFS_URB_SHORT_NOT_OK | | 1038 | USBDEVFS_URB_SHORT_NOT_OK | |
1039 | USBDEVFS_URB_BULK_CONTINUATION | | ||
994 | USBDEVFS_URB_NO_FSBR | | 1040 | USBDEVFS_URB_NO_FSBR | |
995 | USBDEVFS_URB_ZERO_PACKET | | 1041 | USBDEVFS_URB_ZERO_PACKET | |
996 | USBDEVFS_URB_NO_INTERRUPT)) | 1042 | USBDEVFS_URB_NO_INTERRUPT)) |
@@ -1051,13 +1097,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
1051 | is_in = 0; | 1097 | is_in = 0; |
1052 | uurb->endpoint &= ~USB_DIR_IN; | 1098 | uurb->endpoint &= ~USB_DIR_IN; |
1053 | } | 1099 | } |
1054 | snoop(&ps->dev->dev, "control urb: bRequest=%02x " | ||
1055 | "bRrequestType=%02x wValue=%04x " | ||
1056 | "wIndex=%04x wLength=%04x\n", | ||
1057 | dr->bRequest, dr->bRequestType, | ||
1058 | __le16_to_cpup(&dr->wValue), | ||
1059 | __le16_to_cpup(&dr->wIndex), | ||
1060 | __le16_to_cpup(&dr->wLength)); | ||
1061 | break; | 1100 | break; |
1062 | 1101 | ||
1063 | case USBDEVFS_URB_TYPE_BULK: | 1102 | case USBDEVFS_URB_TYPE_BULK: |
@@ -1070,7 +1109,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
1070 | uurb->number_of_packets = 0; | 1109 | uurb->number_of_packets = 0; |
1071 | if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) | 1110 | if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) |
1072 | return -EINVAL; | 1111 | return -EINVAL; |
1073 | snoop(&ps->dev->dev, "bulk urb\n"); | ||
1074 | break; | 1112 | break; |
1075 | 1113 | ||
1076 | case USBDEVFS_URB_TYPE_ISO: | 1114 | case USBDEVFS_URB_TYPE_ISO: |
@@ -1097,12 +1135,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
1097 | } | 1135 | } |
1098 | totlen += isopkt[u].length; | 1136 | totlen += isopkt[u].length; |
1099 | } | 1137 | } |
1100 | if (totlen > 32768) { | 1138 | /* 3072 * 64 microframes */ |
1139 | if (totlen > 196608) { | ||
1101 | kfree(isopkt); | 1140 | kfree(isopkt); |
1102 | return -EINVAL; | 1141 | return -EINVAL; |
1103 | } | 1142 | } |
1104 | uurb->buffer_length = totlen; | 1143 | uurb->buffer_length = totlen; |
1105 | snoop(&ps->dev->dev, "iso urb\n"); | ||
1106 | break; | 1144 | break; |
1107 | 1145 | ||
1108 | case USBDEVFS_URB_TYPE_INTERRUPT: | 1146 | case USBDEVFS_URB_TYPE_INTERRUPT: |
@@ -1111,7 +1149,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
1111 | return -EINVAL; | 1149 | return -EINVAL; |
1112 | if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) | 1150 | if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) |
1113 | return -EINVAL; | 1151 | return -EINVAL; |
1114 | snoop(&ps->dev->dev, "interrupt urb\n"); | ||
1115 | break; | 1152 | break; |
1116 | 1153 | ||
1117 | default: | 1154 | default: |
@@ -1198,11 +1235,46 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
1198 | return -EFAULT; | 1235 | return -EFAULT; |
1199 | } | 1236 | } |
1200 | } | 1237 | } |
1201 | snoop_urb(as->urb, as->userurb); | 1238 | snoop_urb(ps->dev, as->userurb, as->urb->pipe, |
1239 | as->urb->transfer_buffer_length, 0, SUBMIT); | ||
1202 | async_newpending(as); | 1240 | async_newpending(as); |
1203 | if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { | 1241 | |
1242 | if (usb_endpoint_xfer_bulk(&ep->desc)) { | ||
1243 | spin_lock_irq(&ps->lock); | ||
1244 | |||
1245 | /* Not exactly the endpoint address; the direction bit is | ||
1246 | * shifted to the 0x10 position so that the value will be | ||
1247 | * between 0 and 31. | ||
1248 | */ | ||
1249 | as->bulk_addr = usb_endpoint_num(&ep->desc) | | ||
1250 | ((ep->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) | ||
1251 | >> 3); | ||
1252 | |||
1253 | /* If this bulk URB is the start of a new transfer, re-enable | ||
1254 | * the endpoint. Otherwise mark it as a continuation URB. | ||
1255 | */ | ||
1256 | if (uurb->flags & USBDEVFS_URB_BULK_CONTINUATION) | ||
1257 | as->bulk_status = AS_CONTINUATION; | ||
1258 | else | ||
1259 | ps->disabled_bulk_eps &= ~(1 << as->bulk_addr); | ||
1260 | |||
1261 | /* Don't accept continuation URBs if the endpoint is | ||
1262 | * disabled because of an earlier error. | ||
1263 | */ | ||
1264 | if (ps->disabled_bulk_eps & (1 << as->bulk_addr)) | ||
1265 | ret = -EREMOTEIO; | ||
1266 | else | ||
1267 | ret = usb_submit_urb(as->urb, GFP_ATOMIC); | ||
1268 | spin_unlock_irq(&ps->lock); | ||
1269 | } else { | ||
1270 | ret = usb_submit_urb(as->urb, GFP_KERNEL); | ||
1271 | } | ||
1272 | |||
1273 | if (ret) { | ||
1204 | dev_printk(KERN_DEBUG, &ps->dev->dev, | 1274 | dev_printk(KERN_DEBUG, &ps->dev->dev, |
1205 | "usbfs: usb_submit_urb returned %d\n", ret); | 1275 | "usbfs: usb_submit_urb returned %d\n", ret); |
1276 | snoop_urb(ps->dev, as->userurb, as->urb->pipe, | ||
1277 | 0, ret, COMPLETE); | ||
1206 | async_removepending(as); | 1278 | async_removepending(as); |
1207 | free_async(as); | 1279 | free_async(as); |
1208 | return ret; | 1280 | return ret; |
@@ -1548,6 +1620,29 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg) | |||
1548 | } | 1620 | } |
1549 | #endif | 1621 | #endif |
1550 | 1622 | ||
1623 | static int proc_claim_port(struct dev_state *ps, void __user *arg) | ||
1624 | { | ||
1625 | unsigned portnum; | ||
1626 | int rc; | ||
1627 | |||
1628 | if (get_user(portnum, (unsigned __user *) arg)) | ||
1629 | return -EFAULT; | ||
1630 | rc = usb_hub_claim_port(ps->dev, portnum, ps); | ||
1631 | if (rc == 0) | ||
1632 | snoop(&ps->dev->dev, "port %d claimed by process %d: %s\n", | ||
1633 | portnum, task_pid_nr(current), current->comm); | ||
1634 | return rc; | ||
1635 | } | ||
1636 | |||
1637 | static int proc_release_port(struct dev_state *ps, void __user *arg) | ||
1638 | { | ||
1639 | unsigned portnum; | ||
1640 | |||
1641 | if (get_user(portnum, (unsigned __user *) arg)) | ||
1642 | return -EFAULT; | ||
1643 | return usb_hub_release_port(ps->dev, portnum, ps); | ||
1644 | } | ||
1645 | |||
1551 | /* | 1646 | /* |
1552 | * NOTE: All requests here that have interface numbers as parameters | 1647 | * NOTE: All requests here that have interface numbers as parameters |
1553 | * are assuming that somehow the configuration has been prevented from | 1648 | * are assuming that somehow the configuration has been prevented from |
@@ -1645,7 +1740,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, | |||
1645 | break; | 1740 | break; |
1646 | 1741 | ||
1647 | case USBDEVFS_REAPURBNDELAY32: | 1742 | case USBDEVFS_REAPURBNDELAY32: |
1648 | snoop(&dev->dev, "%s: REAPURBDELAY32\n", __func__); | 1743 | snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__); |
1649 | ret = proc_reapurbnonblock_compat(ps, p); | 1744 | ret = proc_reapurbnonblock_compat(ps, p); |
1650 | break; | 1745 | break; |
1651 | 1746 | ||
@@ -1666,7 +1761,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, | |||
1666 | break; | 1761 | break; |
1667 | 1762 | ||
1668 | case USBDEVFS_REAPURBNDELAY: | 1763 | case USBDEVFS_REAPURBNDELAY: |
1669 | snoop(&dev->dev, "%s: REAPURBDELAY\n", __func__); | 1764 | snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__); |
1670 | ret = proc_reapurbnonblock(ps, p); | 1765 | ret = proc_reapurbnonblock(ps, p); |
1671 | break; | 1766 | break; |
1672 | 1767 | ||
@@ -1689,6 +1784,16 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, | |||
1689 | snoop(&dev->dev, "%s: IOCTL\n", __func__); | 1784 | snoop(&dev->dev, "%s: IOCTL\n", __func__); |
1690 | ret = proc_ioctl_default(ps, p); | 1785 | ret = proc_ioctl_default(ps, p); |
1691 | break; | 1786 | break; |
1787 | |||
1788 | case USBDEVFS_CLAIM_PORT: | ||
1789 | snoop(&dev->dev, "%s: CLAIM_PORT\n", __func__); | ||
1790 | ret = proc_claim_port(ps, p); | ||
1791 | break; | ||
1792 | |||
1793 | case USBDEVFS_RELEASE_PORT: | ||
1794 | snoop(&dev->dev, "%s: RELEASE_PORT\n", __func__); | ||
1795 | ret = proc_release_port(ps, p); | ||
1796 | break; | ||
1692 | } | 1797 | } |
1693 | usb_unlock_device(dev); | 1798 | usb_unlock_device(dev); |
1694 | if (ret >= 0) | 1799 | if (ret >= 0) |