Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Mon, 26 Mar 2007 21:34:11 +0000 (14:34 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Mon, 26 Mar 2007 21:34:11 +0000 (14:34 -0700)
* 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

drivers/usb/core/quirks.c
drivers/usb/gadget/omap_udc.c
drivers/usb/host/uhci-debug.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-q.c
drivers/usb/serial/airprime.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/generic.c

index 0e5c646..f08ec85 100644 (file)
@@ -30,7 +30,8 @@
 static const struct usb_device_id usb_quirk_list[] = {
        /* HP 5300/5370C scanner */
        { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
-
+       /* Seiko Epson Corp - Perfection 1670 */
+       { USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
        /* Elsa MicroLink 56k (V.250) */
        { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
 
index 8f9a2b6..b394e63 100644 (file)
@@ -296,6 +296,15 @@ omap_free_request(struct usb_ep *ep, struct usb_request *_req)
 
 /*-------------------------------------------------------------------------*/
 
+/*
+ * dma-coherent memory allocation (for dma-capable endpoints)
+ *
+ * NOTE: the dma_*_coherent() API calls suck.  Most implementations are
+ * (a) page-oriented, so small buffers lose big; and (b) asymmetric with
+ * respect to calls with irqs disabled:  alloc is safe, free is not.
+ * We currently work around (b), but not (a).
+ */
+
 static void *
 omap_alloc_buffer(
        struct usb_ep   *_ep,
@@ -307,6 +316,9 @@ omap_alloc_buffer(
        void            *retval;
        struct omap_ep  *ep;
 
+       if (!_ep)
+               return NULL;
+
        ep = container_of(_ep, struct omap_ep, ep);
        if (use_dma && ep->has_dma) {
                static int      warned;
@@ -326,6 +338,35 @@ omap_alloc_buffer(
        return retval;
 }
 
+static DEFINE_SPINLOCK(buflock);
+static LIST_HEAD(buffers);
+
+struct free_record {
+       struct list_head        list;
+       struct device           *dev;
+       unsigned                bytes;
+       dma_addr_t              dma;
+};
+
+static void do_free(unsigned long ignored)
+{
+       spin_lock_irq(&buflock);
+       while (!list_empty(&buffers)) {
+               struct free_record      *buf;
+
+               buf = list_entry(buffers.next, struct free_record, list);
+               list_del(&buf->list);
+               spin_unlock_irq(&buflock);
+
+               dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
+
+               spin_lock_irq(&buflock);
+       }
+       spin_unlock_irq(&buflock);
+}
+
+static DECLARE_TASKLET(deferred_free, do_free, 0);
+
 static void omap_free_buffer(
        struct usb_ep   *_ep,
        void            *buf,
@@ -333,13 +374,29 @@ static void omap_free_buffer(
        unsigned        bytes
 )
 {
-       struct omap_ep  *ep;
+       if (!_ep) {
+               WARN_ON(1);
+               return;
+       }
 
-       ep = container_of(_ep, struct omap_ep, ep);
-       if (use_dma && _ep && ep->has_dma)
-               dma_free_coherent(ep->udc->gadget.dev.parent, bytes, buf, dma);
-       else
-               kfree (buf);
+       /* free memory into the right allocator */
+       if (dma != DMA_ADDR_INVALID) {
+               struct omap_ep          *ep;
+               struct free_record      *rec = buf;
+               unsigned long           flags;
+
+               ep = container_of(_ep, struct omap_ep, ep);
+
+               rec->dev = ep->udc->gadget.dev.parent;
+               rec->bytes = bytes;
+               rec->dma = dma;
+
+               spin_lock_irqsave(&buflock, flags);
+               list_add_tail(&rec->list, &buffers);
+               tasklet_schedule(&deferred_free);
+               spin_unlock_irqrestore(&buflock, flags);
+       } else
+               kfree(buf);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1691,12 +1748,38 @@ ep0out_status_stage:
                        udc->ep0_pending = 0;
                        break;
                case USB_REQ_GET_STATUS:
+                       /* USB_ENDPOINT_HALT status? */
+                       if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT))
+                               goto intf_status;
+
+                       /* ep0 never stalls */
+                       if (!(w_index & 0xf))
+                               goto zero_status;
+
+                       /* only active endpoints count */
+                       ep = &udc->ep[w_index & 0xf];
+                       if (w_index & USB_DIR_IN)
+                               ep += 16;
+                       if (!ep->desc)
+                               goto do_stall;
+
+                       /* iso never stalls */
+                       if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC)
+                               goto zero_status;
+
+                       /* FIXME don't assume non-halted endpoints!! */
+                       ERR("%s status, can't report\n", ep->ep.name);
+                       goto do_stall;
+
+intf_status:
                        /* return interface status.  if we were pedantic,
                         * we'd detect non-existent interfaces, and stall.
                         */
                        if (u.r.bRequestType
                                        != (USB_DIR_IN|USB_RECIP_INTERFACE))
                                goto delegate;
+
+zero_status:
                        /* return two zero bytes */
                        UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR;
                        UDC_DATA_REG = 0;
@@ -2068,7 +2151,7 @@ static irqreturn_t omap_udc_iso_irq(int irq, void *_dev)
 
 /*-------------------------------------------------------------------------*/
 
-static inline int machine_needs_vbus_session(void)
+static inline int machine_without_vbus_sense(void)
 {
        return (machine_is_omap_innovator()
                || machine_is_omap_osk()
@@ -2156,7 +2239,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
        /* boards that don't have VBUS sensing can't autogate 48MHz;
         * can't enter deep sleep while a gadget driver is active.
         */
-       if (machine_needs_vbus_session())
+       if (machine_without_vbus_sense())
                omap_vbus_session(&udc->gadget, 1);
 
 done:
@@ -2179,7 +2262,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
        if (udc->dc_clk != NULL)
                omap_udc_enable_clock(1);
 
-       if (machine_needs_vbus_session())
+       if (machine_without_vbus_sense())
                omap_vbus_session(&udc->gadget, 0);
 
        if (udc->transceiver)
@@ -2822,7 +2905,7 @@ static int __init omap_udc_probe(struct platform_device *pdev)
                hmc = HMC_1510;
                type = "(unknown)";
 
-               if (machine_is_omap_innovator() || machine_is_sx1()) {
+               if (machine_without_vbus_sense()) {
                        /* just set up software VBUS detect, and then
                         * later rig it so we always report VBUS.
                         * FIXME without really sensing VBUS, we can't
index 8d24d3d..1497371 100644 (file)
@@ -145,7 +145,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
        return out - buf;
 }
 
-static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
+static int uhci_show_qh(struct uhci_hcd *uhci,
+               struct uhci_qh *qh, char *buf, int len, int space)
 {
        char *out = buf;
        int i, nurbs;
@@ -190,6 +191,9 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
 
        if (list_empty(&qh->queue)) {
                out += sprintf(out, "%*s  queue is empty\n", space, "");
+               if (qh == uhci->skel_async_qh)
+                       out += uhci_show_td(uhci->term_td, out,
+                                       len - (out - buf), 0);
        } else {
                struct urb_priv *urbp = list_entry(qh->queue.next,
                                struct urb_priv, node);
@@ -343,6 +347,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
        struct list_head *tmp, *head;
        int nframes, nerrs;
        __le32 link;
+       __le32 fsbr_link;
 
        static const char * const qh_names[] = {
                "unlink", "iso", "int128", "int64", "int32", "int16",
@@ -424,21 +429,22 @@ check_link:
 
        out += sprintf(out, "Skeleton QHs\n");
 
+       fsbr_link = 0;
        for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
                int cnt = 0;
-               __le32 fsbr_link = 0;
 
                qh = uhci->skelqh[i];
                out += sprintf(out, "- skel_%s_qh\n", qh_names[i]); \
-               out += uhci_show_qh(qh, out, len - (out - buf), 4);
+               out += uhci_show_qh(uhci, qh, out, len - (out - buf), 4);
 
                /* Last QH is the Terminating QH, it's different */
                if (i == SKEL_TERM) {
                        if (qh_element(qh) != LINK_TO_TD(uhci->term_td))
                                out += sprintf(out, "    skel_term_qh element is not set to term_td!\n");
-                       if (link == LINK_TO_QH(uhci->skel_term_qh))
-                               goto check_qh_link;
-                       continue;
+                       link = fsbr_link;
+                       if (!link)
+                               link = LINK_TO_QH(uhci->skel_term_qh);
+                       goto check_qh_link;
                }
 
                head = &qh->node;
@@ -448,7 +454,7 @@ check_link:
                        qh = list_entry(tmp, struct uhci_qh, node);
                        tmp = tmp->next;
                        if (++cnt <= 10)
-                               out += uhci_show_qh(qh, out,
+                               out += uhci_show_qh(uhci, qh, out,
                                                len - (out - buf), 4);
                        if (!fsbr_link && qh->skel >= SKEL_FSBR)
                                fsbr_link = LINK_TO_QH(qh);
@@ -463,8 +469,6 @@ check_link:
                        link = LINK_TO_QH(uhci->skel_async_qh);
                else if (!uhci->fsbr_is_on)
                        ;
-               else if (fsbr_link)
-                       link = fsbr_link;
                else
                        link = LINK_TO_QH(uhci->skel_term_qh);
 check_qh_link:
@@ -573,8 +577,8 @@ static const struct file_operations uhci_debug_operations = {
 static inline void lprintk(char *buf)
 {}
 
-static inline int uhci_show_qh(struct uhci_qh *qh, char *buf,
-               int len, int space)
+static inline int uhci_show_qh(struct uhci_hcd *uhci,
+               struct uhci_qh *qh, char *buf, int len, int space)
 {
        return 0;
 }
index 44da433..d22da26 100644 (file)
@@ -632,7 +632,8 @@ static int uhci_start(struct usb_hcd *hcd)
         */
        for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i)
                uhci->skelqh[i]->link = LINK_TO_QH(uhci->skel_async_qh);
-       uhci->skel_async_qh->link = uhci->skel_term_qh->link = UHCI_PTR_TERM;
+       uhci->skel_async_qh->link = UHCI_PTR_TERM;
+       uhci->skel_term_qh->link = LINK_TO_QH(uhci->skel_term_qh);
 
        /* This dummy TD is to work around a bug in Intel PIIX controllers */
        uhci_fill_td(uhci->term_td, 0, uhci_explen(0) |
index f4ebdb3..19a0cc0 100644 (file)
@@ -45,43 +45,27 @@ static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
  */
 static void uhci_fsbr_on(struct uhci_hcd *uhci)
 {
-       struct uhci_qh *fsbr_qh, *lqh, *tqh;
+       struct uhci_qh *lqh;
 
+       /* The terminating skeleton QH always points back to the first
+        * FSBR QH.  Make the last async QH point to the terminating
+        * skeleton QH. */
        uhci->fsbr_is_on = 1;
        lqh = list_entry(uhci->skel_async_qh->node.prev,
                        struct uhci_qh, node);
-
-       /* Find the first FSBR QH.  Linear search through the list is
-        * acceptable because normally FSBR gets turned on as soon as
-        * one QH needs it. */
-       fsbr_qh = NULL;
-       list_for_each_entry_reverse(tqh, &uhci->skel_async_qh->node, node) {
-               if (tqh->skel < SKEL_FSBR)
-                       break;
-               fsbr_qh = tqh;
-       }
-
-       /* No FSBR QH means we must insert the terminating skeleton QH */
-       if (!fsbr_qh) {
-               uhci->skel_term_qh->link = LINK_TO_QH(uhci->skel_term_qh);
-               wmb();
-               lqh->link = uhci->skel_term_qh->link;
-
-       /* Otherwise loop the last QH to the first FSBR QH */
-       } else
-               lqh->link = LINK_TO_QH(fsbr_qh);
+       lqh->link = LINK_TO_QH(uhci->skel_term_qh);
 }
 
 static void uhci_fsbr_off(struct uhci_hcd *uhci)
 {
        struct uhci_qh *lqh;
 
+       /* Remove the link from the last async QH to the terminating
+        * skeleton QH. */
        uhci->fsbr_is_on = 0;
        lqh = list_entry(uhci->skel_async_qh->node.prev,
                        struct uhci_qh, node);
-
-       /* End the async list normally and unlink the terminating QH */
-       lqh->link = uhci->skel_term_qh->link = UHCI_PTR_TERM;
+       lqh->link = UHCI_PTR_TERM;
 }
 
 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)
  */
 static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
 {
-       struct uhci_qh *pqh, *lqh;
+       struct uhci_qh *pqh;
        __le32 link_to_new_qh;
-       __le32 *extra_link = &link_to_new_qh;
 
        /* Find the predecessor QH for our new one and insert it in the list.
         * 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)
                        break;
        }
        list_add(&qh->node, &pqh->node);
-       qh->link = pqh->link;
-
-       link_to_new_qh = LINK_TO_QH(qh);
-
-       /* If this is now the first FSBR QH, take special action */
-       if (uhci->fsbr_is_on && pqh->skel < SKEL_FSBR &&
-                       qh->skel >= SKEL_FSBR) {
-               lqh = list_entry(uhci->skel_async_qh->node.prev,
-                               struct uhci_qh, node);
-
-               /* If the new QH is also the last one, we must unlink
-                * the terminating skeleton QH and make the new QH point
-                * back to itself. */
-               if (qh == lqh) {
-                       qh->link = link_to_new_qh;
-                       extra_link = &uhci->skel_term_qh->link;
-
-               /* Otherwise the last QH must point to the new QH */
-               } else
-                       extra_link = &lqh->link;
-       }
 
        /* Link it into the schedule */
+       qh->link = pqh->link;
        wmb();
-       *extra_link = pqh->link = link_to_new_qh;
+       link_to_new_qh = LINK_TO_QH(qh);
+       pqh->link = link_to_new_qh;
+
+       /* If this is now the first FSBR QH, link the terminating skeleton
+        * QH to it. */
+       if (pqh->skel < SKEL_FSBR && qh->skel >= SKEL_FSBR)
+               uhci->skel_term_qh->link = link_to_new_qh;
 }
 
 /*
@@ -561,31 +530,16 @@ static void unlink_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
  */
 static void unlink_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
 {
-       struct uhci_qh *pqh, *lqh;
+       struct uhci_qh *pqh;
        __le32 link_to_next_qh = qh->link;
 
        pqh = list_entry(qh->node.prev, struct uhci_qh, node);
-
-       /* If this is the first FSBQ QH, take special action */
-       if (uhci->fsbr_is_on && pqh->skel < SKEL_FSBR &&
-                       qh->skel >= SKEL_FSBR) {
-               lqh = list_entry(uhci->skel_async_qh->node.prev,
-                               struct uhci_qh, node);
-
-               /* If this QH is also the last one, we must link in
-                * the terminating skeleton QH. */
-               if (qh == lqh) {
-                       link_to_next_qh = LINK_TO_QH(uhci->skel_term_qh);
-                       uhci->skel_term_qh->link = link_to_next_qh;
-                       wmb();
-                       qh->link = link_to_next_qh;
-
-               /* Otherwise the last QH must point to the new first FSBR QH */
-               } else
-                       lqh->link = link_to_next_qh;
-       }
-
        pqh->link = link_to_next_qh;
+
+       /* If this was the old first FSBR QH, link the terminating skeleton
+        * QH to the next (new first FSBR) QH. */
+       if (pqh->skel < SKEL_FSBR && qh->skel >= SKEL_FSBR)
+               uhci->skel_term_qh->link = link_to_next_qh;
        mb();
 }
 
@@ -1217,7 +1171,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
 
                                if (debug > 1 && errbuf) {
                                        /* Print the chain for debugging */
-                                       uhci_show_qh(urbp->qh, errbuf,
+                                       uhci_show_qh(uhci, urbp->qh, errbuf,
                                                        ERRBUF_LEN, 0);
                                        lprintk(errbuf);
                                }
index 7538c64..39a4983 100644 (file)
@@ -18,7 +18,6 @@
 
 static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
-       { USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */
        { USB_DEVICE(0x413c, 0x8115) }, /* Dell Wireless HSDPA 5500 */
        { },
 };
index 1633a0f..8ff9d54 100644 (file)
@@ -879,6 +879,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
                break;
        case FT232BM: /* FT232BM chip */
        case FT2232C: /* FT2232C chip */
+       case FT232RL:
                if (baud <= 3000000) {
                        div_value = ftdi_232bm_baud_to_divisor(baud);
                } else {
@@ -1021,9 +1022,12 @@ static void ftdi_determine_type(struct usb_serial_port *port)
                /* (It might be a BM because of the iSerialNumber bug,
                 * but it will still work as an AM device.) */
                priv->chip_type = FT8U232AM;
-       } else {
+       } else if (version < 0x600) {
                /* Assume its an FT232BM (or FT245BM) */
                priv->chip_type = FT232BM;
+       } else {
+               /* Assume its an FT232R  */
+               priv->chip_type = FT232RL;
        }
        info("Detected %s", ftdi_chip_name[priv->chip_type]);
 }
index 53baeec..4f8282a 100644 (file)
 #include <linux/usb/serial.h>
 #include <asm/uaccess.h>
 
-static int generic_probe(struct usb_interface *interface,
-                        const struct usb_device_id *id);
-
 
 static int debug;
 
 #ifdef CONFIG_USB_SERIAL_GENERIC
+
+static int generic_probe(struct usb_interface *interface,
+                        const struct usb_device_id *id);
+
 static __u16 vendor  = 0x05f9;
 static __u16 product = 0xffff;