diff options
| author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-03-26 17:34:11 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-03-26 17:34:11 -0400 |
| commit | 8b66a454bf09958b474d12981996287d19aa462d (patch) | |
| tree | e5369b91539c113b6cc66d786ad7aff24a0e512b | |
| parent | 55ab97569f5e64a1febe02485b2d5dd77c208298 (diff) | |
| parent | 3b009c637fee4990265591cc282d0c0f9e3c5384 (diff) | |
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6:
USB: fix usb-serial/ftdi build warning
USB: fix usb-serial/generic build warning
USB: another entry for the quirk list
USB: remove duplicated device id in airprime driver
USB: omap_udc: workaround dma_free_coherent() bogosity
UHCI: Fix problem caused by lack of terminating QH
| -rw-r--r-- | drivers/usb/core/quirks.c | 3 | ||||
| -rw-r--r-- | drivers/usb/gadget/omap_udc.c | 103 | ||||
| -rw-r--r-- | drivers/usb/host/uhci-debug.c | 26 | ||||
| -rw-r--r-- | drivers/usb/host/uhci-hcd.c | 3 | ||||
| -rw-r--r-- | drivers/usb/host/uhci-q.c | 94 | ||||
| -rw-r--r-- | drivers/usb/serial/airprime.c | 1 | ||||
| -rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 6 | ||||
| -rw-r--r-- | drivers/usb/serial/generic.c | 7 |
8 files changed, 145 insertions, 98 deletions
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 0e5c646cb4f6..f08ec85a6d64 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c | |||
| @@ -30,7 +30,8 @@ | |||
| 30 | static const struct usb_device_id usb_quirk_list[] = { | 30 | static const struct usb_device_id usb_quirk_list[] = { |
| 31 | /* HP 5300/5370C scanner */ | 31 | /* HP 5300/5370C scanner */ |
| 32 | { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 }, | 32 | { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 }, |
| 33 | 33 | /* Seiko Epson Corp - Perfection 1670 */ | |
| 34 | { USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, | ||
| 34 | /* Elsa MicroLink 56k (V.250) */ | 35 | /* Elsa MicroLink 56k (V.250) */ |
| 35 | { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, | 36 | { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, |
| 36 | 37 | ||
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 8f9a2b615422..b394e63894d2 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c | |||
| @@ -296,6 +296,15 @@ omap_free_request(struct usb_ep *ep, struct usb_request *_req) | |||
| 296 | 296 | ||
| 297 | /*-------------------------------------------------------------------------*/ | 297 | /*-------------------------------------------------------------------------*/ |
| 298 | 298 | ||
| 299 | /* | ||
| 300 | * dma-coherent memory allocation (for dma-capable endpoints) | ||
| 301 | * | ||
| 302 | * NOTE: the dma_*_coherent() API calls suck. Most implementations are | ||
| 303 | * (a) page-oriented, so small buffers lose big; and (b) asymmetric with | ||
| 304 | * respect to calls with irqs disabled: alloc is safe, free is not. | ||
| 305 | * We currently work around (b), but not (a). | ||
| 306 | */ | ||
| 307 | |||
| 299 | static void * | 308 | static void * |
| 300 | omap_alloc_buffer( | 309 | omap_alloc_buffer( |
| 301 | struct usb_ep *_ep, | 310 | struct usb_ep *_ep, |
| @@ -307,6 +316,9 @@ omap_alloc_buffer( | |||
| 307 | void *retval; | 316 | void *retval; |
| 308 | struct omap_ep *ep; | 317 | struct omap_ep *ep; |
| 309 | 318 | ||
| 319 | if (!_ep) | ||
| 320 | return NULL; | ||
| 321 | |||
| 310 | ep = container_of(_ep, struct omap_ep, ep); | 322 | ep = container_of(_ep, struct omap_ep, ep); |
| 311 | if (use_dma && ep->has_dma) { | 323 | if (use_dma && ep->has_dma) { |
| 312 | static int warned; | 324 | static int warned; |
| @@ -326,6 +338,35 @@ omap_alloc_buffer( | |||
| 326 | return retval; | 338 | return retval; |
| 327 | } | 339 | } |
| 328 | 340 | ||
| 341 | static DEFINE_SPINLOCK(buflock); | ||
| 342 | static LIST_HEAD(buffers); | ||
| 343 | |||
| 344 | struct free_record { | ||
| 345 | struct list_head list; | ||
| 346 | struct device *dev; | ||
| 347 | unsigned bytes; | ||
| 348 | dma_addr_t dma; | ||
| 349 | }; | ||
| 350 | |||
| 351 | static void do_free(unsigned long ignored) | ||
| 352 | { | ||
| 353 | spin_lock_irq(&buflock); | ||
| 354 | while (!list_empty(&buffers)) { | ||
| 355 | struct free_record *buf; | ||
| 356 | |||
| 357 | buf = list_entry(buffers.next, struct free_record, list); | ||
| 358 | list_del(&buf->list); | ||
| 359 | spin_unlock_irq(&buflock); | ||
| 360 | |||
| 361 | dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma); | ||
| 362 | |||
| 363 | spin_lock_irq(&buflock); | ||
| 364 | } | ||
| 365 | spin_unlock_irq(&buflock); | ||
| 366 | } | ||
| 367 | |||
| 368 | static DECLARE_TASKLET(deferred_free, do_free, 0); | ||
| 369 | |||
| 329 | static void omap_free_buffer( | 370 | static void omap_free_buffer( |
| 330 | struct usb_ep *_ep, | 371 | struct usb_ep *_ep, |
| 331 | void *buf, | 372 | void *buf, |
| @@ -333,13 +374,29 @@ static void omap_free_buffer( | |||
| 333 | unsigned bytes | 374 | unsigned bytes |
| 334 | ) | 375 | ) |
| 335 | { | 376 | { |
| 336 | struct omap_ep *ep; | 377 | if (!_ep) { |
| 378 | WARN_ON(1); | ||
| 379 | return; | ||
| 380 | } | ||
| 337 | 381 | ||
| 338 | ep = container_of(_ep, struct omap_ep, ep); | 382 | /* free memory into the right allocator */ |
| 339 | if (use_dma && _ep && ep->has_dma) | 383 | if (dma != DMA_ADDR_INVALID) { |
| 340 | dma_free_coherent(ep->udc->gadget.dev.parent, bytes, buf, dma); | 384 | struct omap_ep *ep; |
| 341 | else | 385 | struct free_record *rec = buf; |
| 342 | kfree (buf); | 386 | unsigned long flags; |
| 387 | |||
| 388 | ep = container_of(_ep, struct omap_ep, ep); | ||
| 389 | |||
| 390 | rec->dev = ep->udc->gadget.dev.parent; | ||
| 391 | rec->bytes = bytes; | ||
| 392 | rec->dma = dma; | ||
| 393 | |||
| 394 | spin_lock_irqsave(&buflock, flags); | ||
| 395 | list_add_tail(&rec->list, &buffers); | ||
| 396 | tasklet_schedule(&deferred_free); | ||
| 397 | spin_unlock_irqrestore(&buflock, flags); | ||
| 398 | } else | ||
| 399 | kfree(buf); | ||
| 343 | } | 400 | } |
| 344 | 401 | ||
| 345 | /*-------------------------------------------------------------------------*/ | 402 | /*-------------------------------------------------------------------------*/ |
| @@ -1691,12 +1748,38 @@ ep0out_status_stage: | |||
| 1691 | udc->ep0_pending = 0; | 1748 | udc->ep0_pending = 0; |
| 1692 | break; | 1749 | break; |
| 1693 | case USB_REQ_GET_STATUS: | 1750 | case USB_REQ_GET_STATUS: |
| 1751 | /* USB_ENDPOINT_HALT status? */ | ||
| 1752 | if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT)) | ||
| 1753 | goto intf_status; | ||
| 1754 | |||
| 1755 | /* ep0 never stalls */ | ||
| 1756 | if (!(w_index & 0xf)) | ||
| 1757 | goto zero_status; | ||
| 1758 | |||
| 1759 | /* only active endpoints count */ | ||
| 1760 | ep = &udc->ep[w_index & 0xf]; | ||
| 1761 | if (w_index & USB_DIR_IN) | ||
| 1762 | ep += 16; | ||
| 1763 | if (!ep->desc) | ||
| 1764 | goto do_stall; | ||
| 1765 | |||
| 1766 | /* iso never stalls */ | ||
| 1767 | if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) | ||
| 1768 | goto zero_status; | ||
| 1769 | |||
| 1770 | /* FIXME don't assume non-halted endpoints!! */ | ||
| 1771 | ERR("%s status, can't report\n", ep->ep.name); | ||
| 1772 | goto do_stall; | ||
| 1773 | |||
| 1774 | intf_status: | ||
| 1694 | /* return interface status. if we were pedantic, | 1775 | /* return interface status. if we were pedantic, |
| 1695 | * we'd detect non-existent interfaces, and stall. | 1776 | * we'd detect non-existent interfaces, and stall. |
| 1696 | */ | 1777 | */ |
| 1697 | if (u.r.bRequestType | 1778 | if (u.r.bRequestType |
| 1698 | != (USB_DIR_IN|USB_RECIP_INTERFACE)) | 1779 | != (USB_DIR_IN|USB_RECIP_INTERFACE)) |
| 1699 | goto delegate; | 1780 | goto delegate; |
| 1781 | |||
| 1782 | zero_status: | ||
| 1700 | /* return two zero bytes */ | 1783 | /* return two zero bytes */ |
| 1701 | UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR; | 1784 | UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR; |
| 1702 | UDC_DATA_REG = 0; | 1785 | UDC_DATA_REG = 0; |
| @@ -2068,7 +2151,7 @@ static irqreturn_t omap_udc_iso_irq(int irq, void *_dev) | |||
| 2068 | 2151 | ||
| 2069 | /*-------------------------------------------------------------------------*/ | 2152 | /*-------------------------------------------------------------------------*/ |
| 2070 | 2153 | ||
| 2071 | static inline int machine_needs_vbus_session(void) | 2154 | static inline int machine_without_vbus_sense(void) |
| 2072 | { | 2155 | { |
| 2073 | return (machine_is_omap_innovator() | 2156 | return (machine_is_omap_innovator() |
| 2074 | || machine_is_omap_osk() | 2157 | || machine_is_omap_osk() |
| @@ -2156,7 +2239,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) | |||
| 2156 | /* boards that don't have VBUS sensing can't autogate 48MHz; | 2239 | /* boards that don't have VBUS sensing can't autogate 48MHz; |
| 2157 | * can't enter deep sleep while a gadget driver is active. | 2240 | * can't enter deep sleep while a gadget driver is active. |
| 2158 | */ | 2241 | */ |
| 2159 | if (machine_needs_vbus_session()) | 2242 | if (machine_without_vbus_sense()) |
| 2160 | omap_vbus_session(&udc->gadget, 1); | 2243 | omap_vbus_session(&udc->gadget, 1); |
| 2161 | 2244 | ||
| 2162 | done: | 2245 | done: |
| @@ -2179,7 +2262,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) | |||
| 2179 | if (udc->dc_clk != NULL) | 2262 | if (udc->dc_clk != NULL) |
| 2180 | omap_udc_enable_clock(1); | 2263 | omap_udc_enable_clock(1); |
| 2181 | 2264 | ||
| 2182 | if (machine_needs_vbus_session()) | 2265 | if (machine_without_vbus_sense()) |
| 2183 | omap_vbus_session(&udc->gadget, 0); | 2266 | omap_vbus_session(&udc->gadget, 0); |
| 2184 | 2267 | ||
| 2185 | if (udc->transceiver) | 2268 | if (udc->transceiver) |
| @@ -2822,7 +2905,7 @@ static int __init omap_udc_probe(struct platform_device *pdev) | |||
| 2822 | hmc = HMC_1510; | 2905 | hmc = HMC_1510; |
| 2823 | type = "(unknown)"; | 2906 | type = "(unknown)"; |
| 2824 | 2907 | ||
| 2825 | if (machine_is_omap_innovator() || machine_is_sx1()) { | 2908 | if (machine_without_vbus_sense()) { |
| 2826 | /* just set up software VBUS detect, and then | 2909 | /* just set up software VBUS detect, and then |
| 2827 | * later rig it so we always report VBUS. | 2910 | * later rig it so we always report VBUS. |
| 2828 | * FIXME without really sensing VBUS, we can't | 2911 | * FIXME without really sensing VBUS, we can't |
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 8d24d3dc0a61..1497371583b9 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c | |||
| @@ -145,7 +145,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) | |||
| 145 | return out - buf; | 145 | return out - buf; |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) | 148 | static int uhci_show_qh(struct uhci_hcd *uhci, |
| 149 | struct uhci_qh *qh, char *buf, int len, int space) | ||
| 149 | { | 150 | { |
| 150 | char *out = buf; | 151 | char *out = buf; |
| 151 | int i, nurbs; | 152 | int i, nurbs; |
| @@ -190,6 +191,9 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) | |||
| 190 | 191 | ||
| 191 | if (list_empty(&qh->queue)) { | 192 | if (list_empty(&qh->queue)) { |
| 192 | out += sprintf(out, "%*s queue is empty\n", space, ""); | 193 | out += sprintf(out, "%*s queue is empty\n", space, ""); |
| 194 | if (qh == uhci->skel_async_qh) | ||
| 195 | out += uhci_show_td(uhci->term_td, out, | ||
| 196 | len - (out - buf), 0); | ||
| 193 | } else { | 197 | } else { |
| 194 | struct urb_priv *urbp = list_entry(qh->queue.next, | 198 | struct urb_priv *urbp = list_entry(qh->queue.next, |
| 195 | struct urb_priv, node); | 199 | struct urb_priv, node); |
| @@ -343,6 +347,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) | |||
| 343 | struct list_head *tmp, *head; | 347 | struct list_head *tmp, *head; |
| 344 | int nframes, nerrs; | 348 | int nframes, nerrs; |
| 345 | __le32 link; | 349 | __le32 link; |
| 350 | __le32 fsbr_link; | ||
| 346 | 351 | ||
| 347 | static const char * const qh_names[] = { | 352 | static const char * const qh_names[] = { |
| 348 | "unlink", "iso", "int128", "int64", "int32", "int16", | 353 | "unlink", "iso", "int128", "int64", "int32", "int16", |
| @@ -424,21 +429,22 @@ check_link: | |||
| 424 | 429 | ||
| 425 | out += sprintf(out, "Skeleton QHs\n"); | 430 | out += sprintf(out, "Skeleton QHs\n"); |
| 426 | 431 | ||
| 432 | fsbr_link = 0; | ||
| 427 | for (i = 0; i < UHCI_NUM_SKELQH; ++i) { | 433 | for (i = 0; i < UHCI_NUM_SKELQH; ++i) { |
| 428 | int cnt = 0; | 434 | int cnt = 0; |
| 429 | __le32 fsbr_link = 0; | ||
| 430 | 435 | ||
| 431 | qh = uhci->skelqh[i]; | 436 | qh = uhci->skelqh[i]; |
| 432 | out += sprintf(out, "- skel_%s_qh\n", qh_names[i]); \ | 437 | out += sprintf(out, "- skel_%s_qh\n", qh_names[i]); \ |
| 433 | out += uhci_show_qh(qh, out, len - (out - buf), 4); | 438 | out += uhci_show_qh(uhci, qh, out, len - (out - buf), 4); |
| 434 | 439 | ||
| 435 | /* Last QH is the Terminating QH, it's different */ | 440 | /* Last QH is the Terminating QH, it's different */ |
| 436 | if (i == SKEL_TERM) { | 441 | if (i == SKEL_TERM) { |
| 437 | if (qh_element(qh) != LINK_TO_TD(uhci->term_td)) | 442 | if (qh_element(qh) != LINK_TO_TD(uhci->term_td)) |
| 438 | out += sprintf(out, " skel_term_qh element is not set to term_td!\n"); | 443 | out += sprintf(out, " skel_term_qh element is not set to term_td!\n"); |
| 439 | if (link == LINK_TO_QH(uhci->skel_term_qh)) | 444 | link = fsbr_link; |
| 440 | goto check_qh_link; | 445 | if (!link) |
| 441 | continue; | 446 | link = LINK_TO_QH(uhci->skel_term_qh); |
| 447 | goto check_qh_link; | ||
| 442 | } | 448 | } |
| 443 | 449 | ||
| 444 | head = &qh->node; | 450 | head = &qh->node; |
| @@ -448,7 +454,7 @@ check_link: | |||
| 448 | qh = list_entry(tmp, struct uhci_qh, node); | 454 | qh = list_entry(tmp, struct uhci_qh, node); |
| 449 | tmp = tmp->next; | 455 | tmp = tmp->next; |
| 450 | if (++cnt <= 10) | 456 | if (++cnt <= 10) |
| 451 | out += uhci_show_qh(qh, out, | 457 | out += uhci_show_qh(uhci, qh, out, |
| 452 | len - (out - buf), 4); | 458 | len - (out - buf), 4); |
| 453 | if (!fsbr_link && qh->skel >= SKEL_FSBR) | 459 | if (!fsbr_link && qh->skel >= SKEL_FSBR) |
| 454 | fsbr_link = LINK_TO_QH(qh); | 460 | fsbr_link = LINK_TO_QH(qh); |
| @@ -463,8 +469,6 @@ check_link: | |||
| 463 | link = LINK_TO_QH(uhci->skel_async_qh); | 469 | link = LINK_TO_QH(uhci->skel_async_qh); |
| 464 | else if (!uhci->fsbr_is_on) | 470 | else if (!uhci->fsbr_is_on) |
| 465 | ; | 471 | ; |
| 466 | else if (fsbr_link) | ||
| 467 | link = fsbr_link; | ||
| 468 | else | 472 | else |
| 469 | link = LINK_TO_QH(uhci->skel_term_qh); | 473 | link = LINK_TO_QH(uhci->skel_term_qh); |
| 470 | check_qh_link: | 474 | check_qh_link: |
| @@ -573,8 +577,8 @@ static const struct file_operations uhci_debug_operations = { | |||
| 573 | static inline void lprintk(char *buf) | 577 | static inline void lprintk(char *buf) |
| 574 | {} | 578 | {} |
| 575 | 579 | ||
| 576 | static inline int uhci_show_qh(struct uhci_qh *qh, char *buf, | 580 | static inline int uhci_show_qh(struct uhci_hcd *uhci, |
| 577 | int len, int space) | 581 | struct uhci_qh *qh, char *buf, int len, int space) |
| 578 | { | 582 | { |
| 579 | return 0; | 583 | return 0; |
| 580 | } | 584 | } |
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 44da4334f1d6..d22da26ff167 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
| @@ -632,7 +632,8 @@ static int uhci_start(struct usb_hcd *hcd) | |||
| 632 | */ | 632 | */ |
| 633 | for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i) | 633 | for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i) |
| 634 | uhci->skelqh[i]->link = LINK_TO_QH(uhci->skel_async_qh); | 634 | uhci->skelqh[i]->link = LINK_TO_QH(uhci->skel_async_qh); |
| 635 | uhci->skel_async_qh->link = uhci->skel_term_qh->link = UHCI_PTR_TERM; | 635 | uhci->skel_async_qh->link = UHCI_PTR_TERM; |
| 636 | uhci->skel_term_qh->link = LINK_TO_QH(uhci->skel_term_qh); | ||
| 636 | 637 | ||
| 637 | /* This dummy TD is to work around a bug in Intel PIIX controllers */ | 638 | /* This dummy TD is to work around a bug in Intel PIIX controllers */ |
| 638 | uhci_fill_td(uhci->term_td, 0, uhci_explen(0) | | 639 | uhci_fill_td(uhci->term_td, 0, uhci_explen(0) | |
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index f4ebdb3e488f..19a0cc02b9a2 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c | |||
| @@ -45,43 +45,27 @@ static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci) | |||
| 45 | */ | 45 | */ |
| 46 | static void uhci_fsbr_on(struct uhci_hcd *uhci) | 46 | static void uhci_fsbr_on(struct uhci_hcd *uhci) |
| 47 | { | 47 | { |
| 48 | struct uhci_qh *fsbr_qh, *lqh, *tqh; | 48 | struct uhci_qh *lqh; |
| 49 | 49 | ||
| 50 | /* The terminating skeleton QH always points back to the first | ||
| 51 | * FSBR QH. Make the last async QH point to the terminating | ||
| 52 | * skeleton QH. */ | ||
| 50 | uhci->fsbr_is_on = 1; | 53 | uhci->fsbr_is_on = 1; |
| 51 | lqh = list_entry(uhci->skel_async_qh->node.prev, | 54 | lqh = list_entry(uhci->skel_async_qh->node.prev, |
| 52 | struct uhci_qh, node); | 55 | struct uhci_qh, node); |
| 53 | 56 | lqh->link = LINK_TO_QH(uhci->skel_term_qh); | |
| 54 | /* Find the first FSBR QH. Linear search through the list is | ||
| 55 | * acceptable because normally FSBR gets turned on as soon as | ||
| 56 | * one QH needs it. */ | ||
| 57 | fsbr_qh = NULL; | ||
| 58 | list_for_each_entry_reverse(tqh, &uhci->skel_async_qh->node, node) { | ||
| 59 | if (tqh->skel < SKEL_FSBR) | ||
| 60 | break; | ||
| 61 | fsbr_qh = tqh; | ||
| 62 | } | ||
| 63 | |||
| 64 | /* No FSBR QH means we must insert the terminating skeleton QH */ | ||
| 65 | if (!fsbr_qh) { | ||
| 66 | uhci->skel_term_qh->link = LINK_TO_QH(uhci->skel_term_qh); | ||
| 67 | wmb(); | ||
| 68 | lqh->link = uhci->skel_term_qh->link; | ||
| 69 | |||
| 70 | /* Otherwise loop the last QH to the first FSBR QH */ | ||
| 71 | } else | ||
| 72 | lqh->link = LINK_TO_QH(fsbr_qh); | ||
| 73 | } | 57 | } |
| 74 | 58 | ||
| 75 | static void uhci_fsbr_off(struct uhci_hcd *uhci) | 59 | static void uhci_fsbr_off(struct uhci_hcd *uhci) |
| 76 | { | 60 | { |
| 77 | struct uhci_qh *lqh; | 61 | struct uhci_qh *lqh; |
| 78 | 62 | ||
| 63 | /* Remove the link from the last async QH to the terminating | ||
| 64 | * skeleton QH. */ | ||
| 79 | uhci->fsbr_is_on = 0; | 65 | uhci->fsbr_is_on = 0; |
| 80 | lqh = list_entry(uhci->skel_async_qh->node.prev, | 66 | lqh = list_entry(uhci->skel_async_qh->node.prev, |
| 81 | struct uhci_qh, node); | 67 | struct uhci_qh, node); |
| 82 | 68 | lqh->link = UHCI_PTR_TERM; | |
| 83 | /* End the async list normally and unlink the terminating QH */ | ||
| 84 | lqh->link = uhci->skel_term_qh->link = UHCI_PTR_TERM; | ||
| 85 | } | 69 | } |
| 86 | 70 | ||
| 87 | static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb) | 71 | static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb) |
| @@ -464,9 +448,8 @@ static void link_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh) | |||
| 464 | */ | 448 | */ |
| 465 | static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh) | 449 | static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh) |
| 466 | { | 450 | { |
| 467 | struct uhci_qh *pqh, *lqh; | 451 | struct uhci_qh *pqh; |
| 468 | __le32 link_to_new_qh; | 452 | __le32 link_to_new_qh; |
| 469 | __le32 *extra_link = &link_to_new_qh; | ||
| 470 | 453 | ||
| 471 | /* Find the predecessor QH for our new one and insert it in the list. | 454 | /* Find the predecessor QH for our new one and insert it in the list. |
| 472 | * The list of QHs is expected to be short, so linear search won't | 455 | * The list of QHs is expected to be short, so linear search won't |
| @@ -476,31 +459,17 @@ static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh) | |||
| 476 | break; | 459 | break; |
| 477 | } | 460 | } |
| 478 | list_add(&qh->node, &pqh->node); | 461 | list_add(&qh->node, &pqh->node); |
| 479 | qh->link = pqh->link; | ||
| 480 | |||
| 481 | link_to_new_qh = LINK_TO_QH(qh); | ||
| 482 | |||
| 483 | /* If this is now the first FSBR QH, take special action */ | ||
| 484 | if (uhci->fsbr_is_on && pqh->skel < SKEL_FSBR && | ||
| 485 | qh->skel >= SKEL_FSBR) { | ||
| 486 | lqh = list_entry(uhci->skel_async_qh->node.prev, | ||
| 487 | struct uhci_qh, node); | ||
| 488 | |||
| 489 | /* If the new QH is also the last one, we must unlink | ||
| 490 | * the terminating skeleton QH and make the new QH point | ||
| 491 | * back to itself. */ | ||
| 492 | if (qh == lqh) { | ||
| 493 | qh->link = link_to_new_qh; | ||
| 494 | extra_link = &uhci->skel_term_qh->link; | ||
| 495 | |||
| 496 | /* Otherwise the last QH must point to the new QH */ | ||
| 497 | } else | ||
| 498 | extra_link = &lqh->link; | ||
| 499 | } | ||
| 500 | 462 | ||
| 501 | /* Link it into the schedule */ | 463 | /* Link it into the schedule */ |
| 464 | qh->link = pqh->link; | ||
| 502 | wmb(); | 465 | wmb(); |
| 503 | *extra_link = pqh->link = link_to_new_qh; | 466 | link_to_new_qh = LINK_TO_QH(qh); |
| 467 | pqh->link = link_to_new_qh; | ||
| 468 | |||
| 469 | /* If this is now the first FSBR QH, link the terminating skeleton | ||
| 470 | * QH to it. */ | ||
| 471 | if (pqh->skel < SKEL_FSBR && qh->skel >= SKEL_FSBR) | ||
| 472 | uhci->skel_term_qh->link = link_to_new_qh; | ||
| 504 | } | 473 | } |
| 505 | 474 | ||
| 506 | /* | 475 | /* |
| @@ -561,31 +530,16 @@ static void unlink_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh) | |||
| 561 | */ | 530 | */ |
| 562 | static void unlink_async(struct uhci_hcd *uhci, struct uhci_qh *qh) | 531 | static void unlink_async(struct uhci_hcd *uhci, struct uhci_qh *qh) |
| 563 | { | 532 | { |
| 564 | struct uhci_qh *pqh, *lqh; | 533 | struct uhci_qh *pqh; |
| 565 | __le32 link_to_next_qh = qh->link; | 534 | __le32 link_to_next_qh = qh->link; |
| 566 | 535 | ||
| 567 | pqh = list_entry(qh->node.prev, struct uhci_qh, node); | 536 | pqh = list_entry(qh->node.prev, struct uhci_qh, node); |
| 568 | |||
| 569 | /* If this is the first FSBQ QH, take special action */ | ||
| 570 | if (uhci->fsbr_is_on && pqh->skel < SKEL_FSBR && | ||
| 571 | qh->skel >= SKEL_FSBR) { | ||
| 572 | lqh = list_entry(uhci->skel_async_qh->node.prev, | ||
| 573 | struct uhci_qh, node); | ||
| 574 | |||
| 575 | /* If this QH is also the last one, we must link in | ||
| 576 | * the terminating skeleton QH. */ | ||
| 577 | if (qh == lqh) { | ||
| 578 | link_to_next_qh = LINK_TO_QH(uhci->skel_term_qh); | ||
| 579 | uhci->skel_term_qh->link = link_to_next_qh; | ||
| 580 | wmb(); | ||
| 581 | qh->link = link_to_next_qh; | ||
| 582 | |||
| 583 | /* Otherwise the last QH must point to the new first FSBR QH */ | ||
| 584 | } else | ||
| 585 | lqh->link = link_to_next_qh; | ||
| 586 | } | ||
| 587 | |||
| 588 | pqh->link = link_to_next_qh; | 537 | pqh->link = link_to_next_qh; |
| 538 | |||
| 539 | /* If this was the old first FSBR QH, link the terminating skeleton | ||
| 540 | * QH to the next (new first FSBR) QH. */ | ||
| 541 | if (pqh->skel < SKEL_FSBR && qh->skel >= SKEL_FSBR) | ||
| 542 | uhci->skel_term_qh->link = link_to_next_qh; | ||
| 589 | mb(); | 543 | mb(); |
| 590 | } | 544 | } |
| 591 | 545 | ||
| @@ -1217,7 +1171,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) | |||
| 1217 | 1171 | ||
| 1218 | if (debug > 1 && errbuf) { | 1172 | if (debug > 1 && errbuf) { |
| 1219 | /* Print the chain for debugging */ | 1173 | /* Print the chain for debugging */ |
| 1220 | uhci_show_qh(urbp->qh, errbuf, | 1174 | uhci_show_qh(uhci, urbp->qh, errbuf, |
| 1221 | ERRBUF_LEN, 0); | 1175 | ERRBUF_LEN, 0); |
| 1222 | lprintk(errbuf); | 1176 | lprintk(errbuf); |
| 1223 | } | 1177 | } |
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 7538c64a5097..39a498362594 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c | |||
| @@ -18,7 +18,6 @@ | |||
| 18 | 18 | ||
| 19 | static struct usb_device_id id_table [] = { | 19 | static struct usb_device_id id_table [] = { |
| 20 | { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */ | 20 | { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */ |
| 21 | { USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */ | ||
| 22 | { USB_DEVICE(0x413c, 0x8115) }, /* Dell Wireless HSDPA 5500 */ | 21 | { USB_DEVICE(0x413c, 0x8115) }, /* Dell Wireless HSDPA 5500 */ |
| 23 | { }, | 22 | { }, |
| 24 | }; | 23 | }; |
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 1633a0fd48e8..8ff9d54b21e6 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
| @@ -879,6 +879,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port) | |||
| 879 | break; | 879 | break; |
| 880 | case FT232BM: /* FT232BM chip */ | 880 | case FT232BM: /* FT232BM chip */ |
| 881 | case FT2232C: /* FT2232C chip */ | 881 | case FT2232C: /* FT2232C chip */ |
| 882 | case FT232RL: | ||
| 882 | if (baud <= 3000000) { | 883 | if (baud <= 3000000) { |
| 883 | div_value = ftdi_232bm_baud_to_divisor(baud); | 884 | div_value = ftdi_232bm_baud_to_divisor(baud); |
| 884 | } else { | 885 | } else { |
| @@ -1021,9 +1022,12 @@ static void ftdi_determine_type(struct usb_serial_port *port) | |||
| 1021 | /* (It might be a BM because of the iSerialNumber bug, | 1022 | /* (It might be a BM because of the iSerialNumber bug, |
| 1022 | * but it will still work as an AM device.) */ | 1023 | * but it will still work as an AM device.) */ |
| 1023 | priv->chip_type = FT8U232AM; | 1024 | priv->chip_type = FT8U232AM; |
| 1024 | } else { | 1025 | } else if (version < 0x600) { |
| 1025 | /* Assume its an FT232BM (or FT245BM) */ | 1026 | /* Assume its an FT232BM (or FT245BM) */ |
| 1026 | priv->chip_type = FT232BM; | 1027 | priv->chip_type = FT232BM; |
| 1028 | } else { | ||
| 1029 | /* Assume its an FT232R */ | ||
| 1030 | priv->chip_type = FT232RL; | ||
| 1027 | } | 1031 | } |
| 1028 | info("Detected %s", ftdi_chip_name[priv->chip_type]); | 1032 | info("Detected %s", ftdi_chip_name[priv->chip_type]); |
| 1029 | } | 1033 | } |
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 53baeec8f265..4f8282ad7720 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c | |||
| @@ -20,13 +20,14 @@ | |||
| 20 | #include <linux/usb/serial.h> | 20 | #include <linux/usb/serial.h> |
| 21 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
| 22 | 22 | ||
| 23 | static int generic_probe(struct usb_interface *interface, | ||
| 24 | const struct usb_device_id *id); | ||
| 25 | |||
| 26 | 23 | ||
| 27 | static int debug; | 24 | static int debug; |
| 28 | 25 | ||
| 29 | #ifdef CONFIG_USB_SERIAL_GENERIC | 26 | #ifdef CONFIG_USB_SERIAL_GENERIC |
| 27 | |||
| 28 | static int generic_probe(struct usb_interface *interface, | ||
| 29 | const struct usb_device_id *id); | ||
| 30 | |||
| 30 | static __u16 vendor = 0x05f9; | 31 | static __u16 vendor = 0x05f9; |
| 31 | static __u16 product = 0xffff; | 32 | static __u16 product = 0xffff; |
| 32 | 33 | ||
