diff options
| author | Ingo Molnar <mingo@elte.hu> | 2009-07-18 06:19:57 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-07-18 06:20:01 -0400 |
| commit | 45bceffc3013bda7d2ebc7802e9b153b674e2d44 (patch) | |
| tree | 222d7dd8fd300925cbf12cdc0fba5bee2528997e /drivers/usb/core | |
| parent | 6f2f3cf00ee32f75ba007a46bab88a54d68a5deb (diff) | |
| parent | 78af08d90b8f745044b1274430bc4bc6b2b27aca (diff) | |
Merge branch 'linus' into tracing/core
Merge reason: tracing/core was on an older, pre-rc1 base.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'drivers/usb/core')
| -rw-r--r-- | drivers/usb/core/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/usb/core/devices.c | 10 | ||||
| -rw-r--r-- | drivers/usb/core/devio.c | 78 | ||||
| -rw-r--r-- | drivers/usb/core/hcd.c | 2 | ||||
| -rw-r--r-- | drivers/usb/core/hcd.h | 4 | ||||
| -rw-r--r-- | drivers/usb/core/hub.c | 40 | ||||
| -rw-r--r-- | drivers/usb/core/hub.h | 6 | ||||
| -rw-r--r-- | drivers/usb/core/message.c | 63 |
8 files changed, 134 insertions, 71 deletions
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 69280c35b5cb..ad925946f869 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig | |||
| @@ -28,7 +28,7 @@ comment "Miscellaneous USB options" | |||
| 28 | depends on USB | 28 | depends on USB |
| 29 | 29 | ||
| 30 | config USB_DEVICEFS | 30 | config USB_DEVICEFS |
| 31 | bool "USB device filesystem (DEPRECATED)" if EMBEDDED | 31 | bool "USB device filesystem (DEPRECATED)" |
| 32 | depends on USB | 32 | depends on USB |
| 33 | ---help--- | 33 | ---help--- |
| 34 | If you say Y here (and to "/proc file system support" in the "File | 34 | If you say Y here (and to "/proc file system support" in the "File |
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 73c108d117b4..96f11715cd26 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c | |||
| @@ -136,17 +136,19 @@ static const struct class_info clas_info[] = | |||
| 136 | {USB_CLASS_AUDIO, "audio"}, | 136 | {USB_CLASS_AUDIO, "audio"}, |
| 137 | {USB_CLASS_COMM, "comm."}, | 137 | {USB_CLASS_COMM, "comm."}, |
| 138 | {USB_CLASS_HID, "HID"}, | 138 | {USB_CLASS_HID, "HID"}, |
| 139 | {USB_CLASS_HUB, "hub"}, | ||
| 140 | {USB_CLASS_PHYSICAL, "PID"}, | 139 | {USB_CLASS_PHYSICAL, "PID"}, |
| 140 | {USB_CLASS_STILL_IMAGE, "still"}, | ||
| 141 | {USB_CLASS_PRINTER, "print"}, | 141 | {USB_CLASS_PRINTER, "print"}, |
| 142 | {USB_CLASS_MASS_STORAGE, "stor."}, | 142 | {USB_CLASS_MASS_STORAGE, "stor."}, |
| 143 | {USB_CLASS_HUB, "hub"}, | ||
| 143 | {USB_CLASS_CDC_DATA, "data"}, | 144 | {USB_CLASS_CDC_DATA, "data"}, |
| 144 | {USB_CLASS_APP_SPEC, "app."}, | ||
| 145 | {USB_CLASS_VENDOR_SPEC, "vend."}, | ||
| 146 | {USB_CLASS_STILL_IMAGE, "still"}, | ||
| 147 | {USB_CLASS_CSCID, "scard"}, | 145 | {USB_CLASS_CSCID, "scard"}, |
| 148 | {USB_CLASS_CONTENT_SEC, "c-sec"}, | 146 | {USB_CLASS_CONTENT_SEC, "c-sec"}, |
| 149 | {USB_CLASS_VIDEO, "video"}, | 147 | {USB_CLASS_VIDEO, "video"}, |
| 148 | {USB_CLASS_WIRELESS_CONTROLLER, "wlcon"}, | ||
| 149 | {USB_CLASS_MISC, "misc"}, | ||
| 150 | {USB_CLASS_APP_SPEC, "app."}, | ||
| 151 | {USB_CLASS_VENDOR_SPEC, "vend."}, | ||
| 150 | {-1, "unk."} /* leave as last */ | 152 | {-1, "unk."} /* leave as last */ |
| 151 | }; | 153 | }; |
| 152 | 154 | ||
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 308609039c73..38b8bce782d6 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c | |||
| @@ -325,21 +325,34 @@ static void async_completed(struct urb *urb) | |||
| 325 | struct async *as = urb->context; | 325 | struct async *as = urb->context; |
| 326 | struct dev_state *ps = as->ps; | 326 | struct dev_state *ps = as->ps; |
| 327 | struct siginfo sinfo; | 327 | struct siginfo sinfo; |
| 328 | struct pid *pid = NULL; | ||
| 329 | uid_t uid = 0; | ||
| 330 | uid_t euid = 0; | ||
| 331 | u32 secid = 0; | ||
| 332 | int signr; | ||
| 328 | 333 | ||
| 329 | spin_lock(&ps->lock); | 334 | spin_lock(&ps->lock); |
| 330 | list_move_tail(&as->asynclist, &ps->async_completed); | 335 | list_move_tail(&as->asynclist, &ps->async_completed); |
| 331 | spin_unlock(&ps->lock); | ||
| 332 | as->status = urb->status; | 336 | as->status = urb->status; |
| 333 | if (as->signr) { | 337 | signr = as->signr; |
| 338 | if (signr) { | ||
| 334 | sinfo.si_signo = as->signr; | 339 | sinfo.si_signo = as->signr; |
| 335 | sinfo.si_errno = as->status; | 340 | sinfo.si_errno = as->status; |
| 336 | sinfo.si_code = SI_ASYNCIO; | 341 | sinfo.si_code = SI_ASYNCIO; |
| 337 | sinfo.si_addr = as->userurb; | 342 | sinfo.si_addr = as->userurb; |
| 338 | kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid, | 343 | pid = as->pid; |
| 339 | as->euid, as->secid); | 344 | uid = as->uid; |
| 345 | euid = as->euid; | ||
| 346 | secid = as->secid; | ||
| 340 | } | 347 | } |
| 341 | snoop(&urb->dev->dev, "urb complete\n"); | 348 | snoop(&urb->dev->dev, "urb complete\n"); |
| 342 | snoop_urb(urb, as->userurb); | 349 | snoop_urb(urb, as->userurb); |
| 350 | spin_unlock(&ps->lock); | ||
| 351 | |||
| 352 | if (signr) | ||
| 353 | kill_pid_info_as_uid(sinfo.si_signo, &sinfo, pid, uid, | ||
| 354 | euid, secid); | ||
| 355 | |||
| 343 | wake_up(&ps->wait); | 356 | wake_up(&ps->wait); |
| 344 | } | 357 | } |
| 345 | 358 | ||
| @@ -982,7 +995,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
| 982 | USBDEVFS_URB_ZERO_PACKET | | 995 | USBDEVFS_URB_ZERO_PACKET | |
| 983 | USBDEVFS_URB_NO_INTERRUPT)) | 996 | USBDEVFS_URB_NO_INTERRUPT)) |
| 984 | return -EINVAL; | 997 | return -EINVAL; |
| 985 | if (!uurb->buffer) | 998 | if (uurb->buffer_length > 0 && !uurb->buffer) |
| 986 | return -EINVAL; | 999 | return -EINVAL; |
| 987 | if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && | 1000 | if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && |
| 988 | (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { | 1001 | (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { |
| @@ -1038,11 +1051,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
| 1038 | is_in = 0; | 1051 | is_in = 0; |
| 1039 | uurb->endpoint &= ~USB_DIR_IN; | 1052 | uurb->endpoint &= ~USB_DIR_IN; |
| 1040 | } | 1053 | } |
| 1041 | if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, | ||
| 1042 | uurb->buffer, uurb->buffer_length)) { | ||
| 1043 | kfree(dr); | ||
| 1044 | return -EFAULT; | ||
| 1045 | } | ||
| 1046 | snoop(&ps->dev->dev, "control urb: bRequest=%02x " | 1054 | snoop(&ps->dev->dev, "control urb: bRequest=%02x " |
| 1047 | "bRrequestType=%02x wValue=%04x " | 1055 | "bRrequestType=%02x wValue=%04x " |
| 1048 | "wIndex=%04x wLength=%04x\n", | 1056 | "wIndex=%04x wLength=%04x\n", |
| @@ -1062,9 +1070,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
| 1062 | uurb->number_of_packets = 0; | 1070 | uurb->number_of_packets = 0; |
| 1063 | if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) | 1071 | if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) |
| 1064 | return -EINVAL; | 1072 | return -EINVAL; |
| 1065 | if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, | ||
| 1066 | uurb->buffer, uurb->buffer_length)) | ||
| 1067 | return -EFAULT; | ||
| 1068 | snoop(&ps->dev->dev, "bulk urb\n"); | 1073 | snoop(&ps->dev->dev, "bulk urb\n"); |
| 1069 | break; | 1074 | break; |
| 1070 | 1075 | ||
| @@ -1106,28 +1111,35 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
| 1106 | return -EINVAL; | 1111 | return -EINVAL; |
| 1107 | if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) | 1112 | if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) |
| 1108 | return -EINVAL; | 1113 | return -EINVAL; |
| 1109 | if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, | ||
| 1110 | uurb->buffer, uurb->buffer_length)) | ||
| 1111 | return -EFAULT; | ||
| 1112 | snoop(&ps->dev->dev, "interrupt urb\n"); | 1114 | snoop(&ps->dev->dev, "interrupt urb\n"); |
| 1113 | break; | 1115 | break; |
| 1114 | 1116 | ||
| 1115 | default: | 1117 | default: |
| 1116 | return -EINVAL; | 1118 | return -EINVAL; |
| 1117 | } | 1119 | } |
| 1118 | as = alloc_async(uurb->number_of_packets); | 1120 | if (uurb->buffer_length > 0 && |
| 1119 | if (!as) { | 1121 | !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, |
| 1122 | uurb->buffer, uurb->buffer_length)) { | ||
| 1120 | kfree(isopkt); | 1123 | kfree(isopkt); |
| 1121 | kfree(dr); | 1124 | kfree(dr); |
| 1122 | return -ENOMEM; | 1125 | return -EFAULT; |
| 1123 | } | 1126 | } |
| 1124 | as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL); | 1127 | as = alloc_async(uurb->number_of_packets); |
| 1125 | if (!as->urb->transfer_buffer) { | 1128 | if (!as) { |
| 1126 | kfree(isopkt); | 1129 | kfree(isopkt); |
| 1127 | kfree(dr); | 1130 | kfree(dr); |
| 1128 | free_async(as); | ||
| 1129 | return -ENOMEM; | 1131 | return -ENOMEM; |
| 1130 | } | 1132 | } |
| 1133 | if (uurb->buffer_length > 0) { | ||
| 1134 | as->urb->transfer_buffer = kmalloc(uurb->buffer_length, | ||
| 1135 | GFP_KERNEL); | ||
| 1136 | if (!as->urb->transfer_buffer) { | ||
| 1137 | kfree(isopkt); | ||
| 1138 | kfree(dr); | ||
| 1139 | free_async(as); | ||
| 1140 | return -ENOMEM; | ||
| 1141 | } | ||
| 1142 | } | ||
| 1131 | as->urb->dev = ps->dev; | 1143 | as->urb->dev = ps->dev; |
| 1132 | as->urb->pipe = (uurb->type << 30) | | 1144 | as->urb->pipe = (uurb->type << 30) | |
| 1133 | __create_pipe(ps->dev, uurb->endpoint & 0xf) | | 1145 | __create_pipe(ps->dev, uurb->endpoint & 0xf) | |
| @@ -1169,7 +1181,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
| 1169 | kfree(isopkt); | 1181 | kfree(isopkt); |
| 1170 | as->ps = ps; | 1182 | as->ps = ps; |
| 1171 | as->userurb = arg; | 1183 | as->userurb = arg; |
| 1172 | if (uurb->endpoint & USB_DIR_IN) | 1184 | if (is_in && uurb->buffer_length > 0) |
| 1173 | as->userbuffer = uurb->buffer; | 1185 | as->userbuffer = uurb->buffer; |
| 1174 | else | 1186 | else |
| 1175 | as->userbuffer = NULL; | 1187 | as->userbuffer = NULL; |
| @@ -1179,9 +1191,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
| 1179 | as->uid = cred->uid; | 1191 | as->uid = cred->uid; |
| 1180 | as->euid = cred->euid; | 1192 | as->euid = cred->euid; |
| 1181 | security_task_getsecid(current, &as->secid); | 1193 | security_task_getsecid(current, &as->secid); |
| 1182 | if (!is_in) { | 1194 | if (!is_in && uurb->buffer_length > 0) { |
| 1183 | if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, | 1195 | if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, |
| 1184 | as->urb->transfer_buffer_length)) { | 1196 | uurb->buffer_length)) { |
| 1185 | free_async(as); | 1197 | free_async(as); |
| 1186 | return -EFAULT; | 1198 | return -EFAULT; |
| 1187 | } | 1199 | } |
| @@ -1231,22 +1243,22 @@ static int processcompl(struct async *as, void __user * __user *arg) | |||
| 1231 | if (as->userbuffer) | 1243 | if (as->userbuffer) |
| 1232 | if (copy_to_user(as->userbuffer, urb->transfer_buffer, | 1244 | if (copy_to_user(as->userbuffer, urb->transfer_buffer, |
| 1233 | urb->transfer_buffer_length)) | 1245 | urb->transfer_buffer_length)) |
| 1234 | return -EFAULT; | 1246 | goto err_out; |
| 1235 | if (put_user(as->status, &userurb->status)) | 1247 | if (put_user(as->status, &userurb->status)) |
| 1236 | return -EFAULT; | 1248 | goto err_out; |
| 1237 | if (put_user(urb->actual_length, &userurb->actual_length)) | 1249 | if (put_user(urb->actual_length, &userurb->actual_length)) |
| 1238 | return -EFAULT; | 1250 | goto err_out; |
| 1239 | if (put_user(urb->error_count, &userurb->error_count)) | 1251 | if (put_user(urb->error_count, &userurb->error_count)) |
| 1240 | return -EFAULT; | 1252 | goto err_out; |
| 1241 | 1253 | ||
| 1242 | if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { | 1254 | if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { |
| 1243 | for (i = 0; i < urb->number_of_packets; i++) { | 1255 | for (i = 0; i < urb->number_of_packets; i++) { |
| 1244 | if (put_user(urb->iso_frame_desc[i].actual_length, | 1256 | if (put_user(urb->iso_frame_desc[i].actual_length, |
| 1245 | &userurb->iso_frame_desc[i].actual_length)) | 1257 | &userurb->iso_frame_desc[i].actual_length)) |
| 1246 | return -EFAULT; | 1258 | goto err_out; |
| 1247 | if (put_user(urb->iso_frame_desc[i].status, | 1259 | if (put_user(urb->iso_frame_desc[i].status, |
| 1248 | &userurb->iso_frame_desc[i].status)) | 1260 | &userurb->iso_frame_desc[i].status)) |
| 1249 | return -EFAULT; | 1261 | goto err_out; |
| 1250 | } | 1262 | } |
| 1251 | } | 1263 | } |
| 1252 | 1264 | ||
| @@ -1255,6 +1267,10 @@ static int processcompl(struct async *as, void __user * __user *arg) | |||
| 1255 | if (put_user(addr, (void __user * __user *)arg)) | 1267 | if (put_user(addr, (void __user * __user *)arg)) |
| 1256 | return -EFAULT; | 1268 | return -EFAULT; |
| 1257 | return 0; | 1269 | return 0; |
| 1270 | |||
| 1271 | err_out: | ||
| 1272 | free_async(as); | ||
| 1273 | return -EFAULT; | ||
| 1258 | } | 1274 | } |
| 1259 | 1275 | ||
| 1260 | static struct async *reap_as(struct dev_state *ps) | 1276 | static struct async *reap_as(struct dev_state *ps) |
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index ce3f453f02ef..95ccfa0b9fc5 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
| @@ -648,7 +648,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) | |||
| 648 | struct urb *urb; | 648 | struct urb *urb; |
| 649 | int length; | 649 | int length; |
| 650 | unsigned long flags; | 650 | unsigned long flags; |
| 651 | char buffer[4]; /* Any root hubs with > 31 ports? */ | 651 | char buffer[6]; /* Any root hubs with > 31 ports? */ |
| 652 | 652 | ||
| 653 | if (unlikely(!hcd->rh_registered)) | 653 | if (unlikely(!hcd->rh_registered)) |
| 654 | return; | 654 | return; |
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index d397ecfd5b17..ec5c67ea07b7 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h | |||
| @@ -227,6 +227,10 @@ struct hc_driver { | |||
| 227 | /* has a port been handed over to a companion? */ | 227 | /* has a port been handed over to a companion? */ |
| 228 | int (*port_handed_over)(struct usb_hcd *, int); | 228 | int (*port_handed_over)(struct usb_hcd *, int); |
| 229 | 229 | ||
| 230 | /* CLEAR_TT_BUFFER completion callback */ | ||
| 231 | void (*clear_tt_buffer_complete)(struct usb_hcd *, | ||
| 232 | struct usb_host_endpoint *); | ||
| 233 | |||
| 230 | /* xHCI specific functions */ | 234 | /* xHCI specific functions */ |
| 231 | /* Called by usb_alloc_dev to alloc HC device structures */ | 235 | /* Called by usb_alloc_dev to alloc HC device structures */ |
| 232 | int (*alloc_dev)(struct usb_hcd *, struct usb_device *); | 236 | int (*alloc_dev)(struct usb_hcd *, struct usb_device *); |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 2af3b4f06054..71f86c60d83c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
| @@ -450,10 +450,10 @@ hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt) | |||
| 450 | * talking to TTs must queue control transfers (not just bulk and iso), so | 450 | * talking to TTs must queue control transfers (not just bulk and iso), so |
| 451 | * both can talk to the same hub concurrently. | 451 | * both can talk to the same hub concurrently. |
| 452 | */ | 452 | */ |
| 453 | static void hub_tt_kevent (struct work_struct *work) | 453 | static void hub_tt_work(struct work_struct *work) |
| 454 | { | 454 | { |
| 455 | struct usb_hub *hub = | 455 | struct usb_hub *hub = |
| 456 | container_of(work, struct usb_hub, tt.kevent); | 456 | container_of(work, struct usb_hub, tt.clear_work); |
| 457 | unsigned long flags; | 457 | unsigned long flags; |
| 458 | int limit = 100; | 458 | int limit = 100; |
| 459 | 459 | ||
| @@ -462,6 +462,7 @@ static void hub_tt_kevent (struct work_struct *work) | |||
| 462 | struct list_head *next; | 462 | struct list_head *next; |
| 463 | struct usb_tt_clear *clear; | 463 | struct usb_tt_clear *clear; |
| 464 | struct usb_device *hdev = hub->hdev; | 464 | struct usb_device *hdev = hub->hdev; |
| 465 | const struct hc_driver *drv; | ||
| 465 | int status; | 466 | int status; |
| 466 | 467 | ||
| 467 | next = hub->tt.clear_list.next; | 468 | next = hub->tt.clear_list.next; |
| @@ -471,21 +472,25 @@ static void hub_tt_kevent (struct work_struct *work) | |||
| 471 | /* drop lock so HCD can concurrently report other TT errors */ | 472 | /* drop lock so HCD can concurrently report other TT errors */ |
| 472 | spin_unlock_irqrestore (&hub->tt.lock, flags); | 473 | spin_unlock_irqrestore (&hub->tt.lock, flags); |
| 473 | status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt); | 474 | status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt); |
| 474 | spin_lock_irqsave (&hub->tt.lock, flags); | ||
| 475 | |||
| 476 | if (status) | 475 | if (status) |
| 477 | dev_err (&hdev->dev, | 476 | dev_err (&hdev->dev, |
| 478 | "clear tt %d (%04x) error %d\n", | 477 | "clear tt %d (%04x) error %d\n", |
| 479 | clear->tt, clear->devinfo, status); | 478 | clear->tt, clear->devinfo, status); |
| 479 | |||
| 480 | /* Tell the HCD, even if the operation failed */ | ||
| 481 | drv = clear->hcd->driver; | ||
| 482 | if (drv->clear_tt_buffer_complete) | ||
| 483 | (drv->clear_tt_buffer_complete)(clear->hcd, clear->ep); | ||
| 484 | |||
| 480 | kfree(clear); | 485 | kfree(clear); |
| 486 | spin_lock_irqsave(&hub->tt.lock, flags); | ||
| 481 | } | 487 | } |
| 482 | spin_unlock_irqrestore (&hub->tt.lock, flags); | 488 | spin_unlock_irqrestore (&hub->tt.lock, flags); |
| 483 | } | 489 | } |
| 484 | 490 | ||
| 485 | /** | 491 | /** |
| 486 | * usb_hub_tt_clear_buffer - clear control/bulk TT state in high speed hub | 492 | * usb_hub_clear_tt_buffer - clear control/bulk TT state in high speed hub |
| 487 | * @udev: the device whose split transaction failed | 493 | * @urb: an URB associated with the failed or incomplete split transaction |
| 488 | * @pipe: identifies the endpoint of the failed transaction | ||
| 489 | * | 494 | * |
| 490 | * High speed HCDs use this to tell the hub driver that some split control or | 495 | * High speed HCDs use this to tell the hub driver that some split control or |
| 491 | * bulk transaction failed in a way that requires clearing internal state of | 496 | * bulk transaction failed in a way that requires clearing internal state of |
| @@ -495,8 +500,10 @@ static void hub_tt_kevent (struct work_struct *work) | |||
| 495 | * It may not be possible for that hub to handle additional full (or low) | 500 | * It may not be possible for that hub to handle additional full (or low) |
| 496 | * speed transactions until that state is fully cleared out. | 501 | * speed transactions until that state is fully cleared out. |
| 497 | */ | 502 | */ |
| 498 | void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe) | 503 | int usb_hub_clear_tt_buffer(struct urb *urb) |
| 499 | { | 504 | { |
| 505 | struct usb_device *udev = urb->dev; | ||
| 506 | int pipe = urb->pipe; | ||
| 500 | struct usb_tt *tt = udev->tt; | 507 | struct usb_tt *tt = udev->tt; |
| 501 | unsigned long flags; | 508 | unsigned long flags; |
| 502 | struct usb_tt_clear *clear; | 509 | struct usb_tt_clear *clear; |
| @@ -508,7 +515,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe) | |||
| 508 | if ((clear = kmalloc (sizeof *clear, GFP_ATOMIC)) == NULL) { | 515 | if ((clear = kmalloc (sizeof *clear, GFP_ATOMIC)) == NULL) { |
| 509 | dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n"); | 516 | dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n"); |
| 510 | /* FIXME recover somehow ... RESET_TT? */ | 517 | /* FIXME recover somehow ... RESET_TT? */ |
| 511 | return; | 518 | return -ENOMEM; |
| 512 | } | 519 | } |
| 513 | 520 | ||
| 514 | /* info that CLEAR_TT_BUFFER needs */ | 521 | /* info that CLEAR_TT_BUFFER needs */ |
| @@ -520,14 +527,19 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe) | |||
| 520 | : (USB_ENDPOINT_XFER_BULK << 11); | 527 | : (USB_ENDPOINT_XFER_BULK << 11); |
| 521 | if (usb_pipein (pipe)) | 528 | if (usb_pipein (pipe)) |
| 522 | clear->devinfo |= 1 << 15; | 529 | clear->devinfo |= 1 << 15; |
| 523 | 530 | ||
| 531 | /* info for completion callback */ | ||
| 532 | clear->hcd = bus_to_hcd(udev->bus); | ||
| 533 | clear->ep = urb->ep; | ||
| 534 | |||
| 524 | /* tell keventd to clear state for this TT */ | 535 | /* tell keventd to clear state for this TT */ |
| 525 | spin_lock_irqsave (&tt->lock, flags); | 536 | spin_lock_irqsave (&tt->lock, flags); |
| 526 | list_add_tail (&clear->clear_list, &tt->clear_list); | 537 | list_add_tail (&clear->clear_list, &tt->clear_list); |
| 527 | schedule_work (&tt->kevent); | 538 | schedule_work(&tt->clear_work); |
| 528 | spin_unlock_irqrestore (&tt->lock, flags); | 539 | spin_unlock_irqrestore (&tt->lock, flags); |
| 540 | return 0; | ||
| 529 | } | 541 | } |
| 530 | EXPORT_SYMBOL_GPL(usb_hub_tt_clear_buffer); | 542 | EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer); |
| 531 | 543 | ||
| 532 | /* If do_delay is false, return the number of milliseconds the caller | 544 | /* If do_delay is false, return the number of milliseconds the caller |
| 533 | * needs to delay. | 545 | * needs to delay. |
| @@ -818,7 +830,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) | |||
| 818 | if (hub->has_indicators) | 830 | if (hub->has_indicators) |
| 819 | cancel_delayed_work_sync(&hub->leds); | 831 | cancel_delayed_work_sync(&hub->leds); |
| 820 | if (hub->tt.hub) | 832 | if (hub->tt.hub) |
| 821 | cancel_work_sync(&hub->tt.kevent); | 833 | cancel_work_sync(&hub->tt.clear_work); |
| 822 | } | 834 | } |
| 823 | 835 | ||
| 824 | /* caller has locked the hub device */ | 836 | /* caller has locked the hub device */ |
| @@ -935,7 +947,7 @@ static int hub_configure(struct usb_hub *hub, | |||
| 935 | 947 | ||
| 936 | spin_lock_init (&hub->tt.lock); | 948 | spin_lock_init (&hub->tt.lock); |
| 937 | INIT_LIST_HEAD (&hub->tt.clear_list); | 949 | INIT_LIST_HEAD (&hub->tt.clear_list); |
| 938 | INIT_WORK (&hub->tt.kevent, hub_tt_kevent); | 950 | INIT_WORK(&hub->tt.clear_work, hub_tt_work); |
| 939 | switch (hdev->descriptor.bDeviceProtocol) { | 951 | switch (hdev->descriptor.bDeviceProtocol) { |
| 940 | case 0: | 952 | case 0: |
| 941 | break; | 953 | break; |
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 889c0f32a40b..de8081f065ed 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h | |||
| @@ -188,16 +188,18 @@ struct usb_tt { | |||
| 188 | /* for control/bulk error recovery (CLEAR_TT_BUFFER) */ | 188 | /* for control/bulk error recovery (CLEAR_TT_BUFFER) */ |
| 189 | spinlock_t lock; | 189 | spinlock_t lock; |
| 190 | struct list_head clear_list; /* of usb_tt_clear */ | 190 | struct list_head clear_list; /* of usb_tt_clear */ |
| 191 | struct work_struct kevent; | 191 | struct work_struct clear_work; |
| 192 | }; | 192 | }; |
| 193 | 193 | ||
| 194 | struct usb_tt_clear { | 194 | struct usb_tt_clear { |
| 195 | struct list_head clear_list; | 195 | struct list_head clear_list; |
| 196 | unsigned tt; | 196 | unsigned tt; |
| 197 | u16 devinfo; | 197 | u16 devinfo; |
| 198 | struct usb_hcd *hcd; | ||
| 199 | struct usb_host_endpoint *ep; | ||
| 198 | }; | 200 | }; |
| 199 | 201 | ||
| 200 | extern void usb_hub_tt_clear_buffer(struct usb_device *dev, int pipe); | 202 | extern int usb_hub_clear_tt_buffer(struct urb *urb); |
| 201 | extern void usb_ep0_reinit(struct usb_device *); | 203 | extern void usb_ep0_reinit(struct usb_device *); |
| 202 | 204 | ||
| 203 | #endif /* __LINUX_HUB_H */ | 205 | #endif /* __LINUX_HUB_H */ |
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 2bed83caacb1..9720e699f472 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c | |||
| @@ -806,6 +806,48 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid, | |||
| 806 | return rc; | 806 | return rc; |
| 807 | } | 807 | } |
| 808 | 808 | ||
| 809 | static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf) | ||
| 810 | { | ||
| 811 | int err; | ||
| 812 | |||
| 813 | if (dev->have_langid) | ||
| 814 | return 0; | ||
| 815 | |||
| 816 | if (dev->string_langid < 0) | ||
| 817 | return -EPIPE; | ||
| 818 | |||
| 819 | err = usb_string_sub(dev, 0, 0, tbuf); | ||
| 820 | |||
| 821 | /* If the string was reported but is malformed, default to english | ||
| 822 | * (0x0409) */ | ||
| 823 | if (err == -ENODATA || (err > 0 && err < 4)) { | ||
| 824 | dev->string_langid = 0x0409; | ||
| 825 | dev->have_langid = 1; | ||
| 826 | dev_err(&dev->dev, | ||
| 827 | "string descriptor 0 malformed (err = %d), " | ||
| 828 | "defaulting to 0x%04x\n", | ||
| 829 | err, dev->string_langid); | ||
| 830 | return 0; | ||
| 831 | } | ||
| 832 | |||
| 833 | /* In case of all other errors, we assume the device is not able to | ||
| 834 | * deal with strings at all. Set string_langid to -1 in order to | ||
| 835 | * prevent any string to be retrieved from the device */ | ||
| 836 | if (err < 0) { | ||
| 837 | dev_err(&dev->dev, "string descriptor 0 read error: %d\n", | ||
| 838 | err); | ||
| 839 | dev->string_langid = -1; | ||
| 840 | return -EPIPE; | ||
| 841 | } | ||
| 842 | |||
| 843 | /* always use the first langid listed */ | ||
| 844 | dev->string_langid = tbuf[2] | (tbuf[3] << 8); | ||
| 845 | dev->have_langid = 1; | ||
| 846 | dev_dbg(&dev->dev, "default language 0x%04x\n", | ||
| 847 | dev->string_langid); | ||
| 848 | return 0; | ||
| 849 | } | ||
| 850 | |||
| 809 | /** | 851 | /** |
| 810 | * usb_string - returns UTF-8 version of a string descriptor | 852 | * usb_string - returns UTF-8 version of a string descriptor |
| 811 | * @dev: the device whose string descriptor is being retrieved | 853 | * @dev: the device whose string descriptor is being retrieved |
| @@ -837,24 +879,9 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) | |||
| 837 | if (!tbuf) | 879 | if (!tbuf) |
| 838 | return -ENOMEM; | 880 | return -ENOMEM; |
| 839 | 881 | ||
| 840 | /* get langid for strings if it's not yet known */ | 882 | err = usb_get_langid(dev, tbuf); |
| 841 | if (!dev->have_langid) { | 883 | if (err < 0) |
| 842 | err = usb_string_sub(dev, 0, 0, tbuf); | 884 | goto errout; |
| 843 | if (err < 0) { | ||
| 844 | dev_err(&dev->dev, | ||
| 845 | "string descriptor 0 read error: %d\n", | ||
| 846 | err); | ||
| 847 | } else if (err < 4) { | ||
| 848 | dev_err(&dev->dev, "string descriptor 0 too short\n"); | ||
| 849 | } else { | ||
| 850 | dev->string_langid = tbuf[2] | (tbuf[3] << 8); | ||
| 851 | /* always use the first langid listed */ | ||
| 852 | dev_dbg(&dev->dev, "default language 0x%04x\n", | ||
| 853 | dev->string_langid); | ||
| 854 | } | ||
| 855 | |||
| 856 | dev->have_langid = 1; | ||
| 857 | } | ||
| 858 | 885 | ||
| 859 | err = usb_string_sub(dev, dev->string_langid, index, tbuf); | 886 | err = usb_string_sub(dev, dev->string_langid, index, tbuf); |
| 860 | if (err < 0) | 887 | if (err < 0) |
