# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#                  ChangeSet    1.537   -> 1.538  
#       drivers/usb/core/hub.h  1.9     -> 1.10   
#        include/linux/usb.h    1.30    -> 1.31   
#       drivers/usb/core/hub.c  1.25    -> 1.26   
#       drivers/usb/core/usb.c  1.50    -> 1.51   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/05/11      [EMAIL PROTECTED]     1.538
# [PATCH] -- hub/tt error recovery
# 
# This patch adds missing functionality to the transaction translator
# support for USB 2.0 hubs:
# 
#     - moves the 'struct usb_tt' definition to "hub.h" from <linux/usb.h>
#     - adds state to it as neeed for some control/bulk error recovery
#     - teaches the hub driver how to use that state (via keventd)
#     - adds a call letting HCDs trigger that recovery
# --------------------------------------------
#
diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c    Sat May 11 22:29:25 2002
+++ b/drivers/usb/core/hub.c    Sat May 11 22:29:25 2002
@@ -149,6 +149,98 @@
        spin_unlock_irqrestore(&hub_event_lock, flags);
 }
 
+/* USB 2.0 spec Section 11.24.2.3 */
+static inline int
+hub_clear_tt_buffer (struct usb_device *hub, u16 devinfo, u16 tt)
+{
+       return usb_control_msg (hub, usb_rcvctrlpipe (hub, 0),
+               HUB_CLEAR_TT_BUFFER, USB_DIR_IN | USB_RECIP_OTHER,
+               devinfo, tt, 0, 0, HZ);
+}
+
+/*
+ * enumeration blocks khubd for a long time. we use keventd instead, since
+ * long blocking there is the exception, not the rule.  accordingly, HCDs
+ * talking to TTs must queue control transfers (not just bulk and iso), so
+ * both can talk to the same hub concurrently.
+ */
+static void hub_tt_kevent (void *arg)
+{
+       struct usb_hub          *hub = arg;
+       unsigned long           flags;
+
+       spin_lock_irqsave (&hub->tt.lock, flags);
+       while (!list_empty (&hub->tt.clear_list)) {
+               struct list_head        *temp;
+               struct usb_tt_clear     *clear;
+               int                     status;
+
+               temp = hub->tt.clear_list.next;
+               clear = list_entry (temp, struct usb_tt_clear, clear_list);
+               list_del (&clear->clear_list);
+
+               /* drop lock so HCD can concurrently report other TT errors */
+               spin_unlock_irqrestore (&hub->tt.lock, flags);
+               status = hub_clear_tt_buffer (hub->dev,
+                               clear->devinfo, clear->tt);
+               spin_lock_irqsave (&hub->tt.lock, flags);
+
+               if (status)
+                       err ("usb-%s-%s clear tt %d (%04x) error %d",
+                               hub->dev->bus->bus_name, hub->dev->devpath,
+                               clear->tt, clear->devinfo, status);
+               kfree (clear);
+       }
+       spin_unlock_irqrestore (&hub->tt.lock, flags);
+}
+
+/**
+ * usb_hub_tt_clear_buffer - clear control/bulk TT state in high speed hub
+ * @dev: the device whose split transaction failed
+ * @pipe: identifies the endpoint of the failed transaction
+ *
+ * High speed HCDs use this to tell the hub driver that some split control or
+ * bulk transaction failed in a way that requires clearing internal state of
+ * a transaction translator.  This is normally detected (and reported) from
+ * interrupt context.
+ *
+ * It may not be possible for that hub to handle additional full (or low)
+ * speed transactions until that state is fully cleared out.
+ */
+void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe)
+{
+       struct usb_tt           *tt = dev->tt;
+       unsigned long           flags;
+       struct usb_tt_clear     *clear;
+
+       /* we've got to cope with an arbitrary number of pending TT clears,
+        * since each TT has "at least two" buffers that can need it (and
+        * there can be many TTs per hub).  even if they're uncommon.
+        */
+       if ((clear = kmalloc (sizeof *clear, SLAB_ATOMIC)) == 0) {
+               err ("can't save CLEAR_TT_BUFFER state for hub at usb-%s-%s",
+                       dev->bus->bus_name, tt->hub->devpath);
+               /* FIXME recover somehow ... RESET_TT? */
+               return;
+       }
+
+       /* info that CLEAR_TT_BUFFER needs */
+       clear->tt = tt->multi ? dev->ttport : 1;
+       clear->devinfo = usb_pipeendpoint (pipe);
+       clear->devinfo |= dev->devnum << 4;
+       clear->devinfo |= usb_pipecontrol (pipe)
+                       ? (USB_ENDPOINT_XFER_CONTROL << 11)
+                       : (USB_ENDPOINT_XFER_BULK << 11);
+       if (usb_pipein (pipe))
+               clear->devinfo |= 1 << 15;
+       
+       /* tell keventd to clear state for this TT */
+       spin_lock_irqsave (&tt->lock, flags);
+       list_add_tail (&clear->clear_list, &tt->clear_list);
+       schedule_task (&tt->kevent);
+       spin_unlock_irqrestore (&tt->lock, flags);
+}
+
 static void usb_hub_power_on(struct usb_hub *hub)
 {
        int i;
@@ -231,6 +323,9 @@
                         break;
        }
 
+       spin_lock_init (&hub->tt.lock);
+       INIT_LIST_HEAD (&hub->tt.clear_list);
+       INIT_TQUEUE (&hub->tt.kevent, hub_tt_kevent, hub);
        switch (dev->descriptor.bDeviceProtocol) {
                case 0:
                        break;
@@ -431,6 +526,10 @@
 
        down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */
        up(&hub->khubd_sem);
+
+       /* assuming we used keventd, it must quiesce too */
+       if (hub->tt.hub)
+               flush_scheduled_tasks ();
 
        if (hub->urb) {
                usb_unlink_urb(hub->urb);
diff -Nru a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
--- a/drivers/usb/core/hub.h    Sat May 11 22:29:25 2002
+++ b/drivers/usb/core/hub.h    Sat May 11 22:29:25 2002
@@ -136,6 +136,34 @@
 
 struct usb_device;
 
+/*
+ * As of USB 2.0, full/low speed devices are segregated into trees.
+ * One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
+ * The other type grows from high speed hubs when they connect to
+ * full/low speed devices using "Transaction Translators" (TTs).
+ *
+ * TTs should only be known to the hub driver, and high speed bus
+ * drivers (only EHCI for now).  They affect periodic scheduling and
+ * sometimes control/bulk error recovery.
+ */
+struct usb_tt {
+       struct usb_device       *hub;   /* upstream highspeed hub */
+       int                     multi;  /* true means one TT per port */
+
+       /* for control/bulk error recovery (CLEAR_TT_BUFFER) */
+       spinlock_t              lock;
+       struct list_head        clear_list;     /* of usb_tt_clear */
+       struct tq_struct        kevent;
+};
+
+struct usb_tt_clear {
+       struct list_head        clear_list;
+       unsigned                tt;
+       u16                     devinfo;
+};
+
+extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe);
+
 struct usb_hub {
        struct usb_device       *dev;           /* the "real" device */
        struct urb              *urb;           /* for interrupt polling pipe */
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c    Sat May 11 22:29:25 2002
+++ b/drivers/usb/core/usb.c    Sat May 11 22:29:25 2002
@@ -2743,9 +2743,8 @@
 
 /*
  * USB may be built into the kernel or be built as modules.
- * If the USB core [and maybe a host controller driver] is built
- * into the kernel, and other device drivers are built as modules,
- * then these symbols need to be exported for the modules to use.
+ * These symbols are exported for device (or host controller)
+ * driver modules to use.
  */
 EXPORT_SYMBOL(usb_ifnum_to_ifpos);
 EXPORT_SYMBOL(usb_ifnum_to_if);
@@ -2762,6 +2761,7 @@
 
 EXPORT_SYMBOL(usb_alloc_dev);
 EXPORT_SYMBOL(usb_free_dev);
+EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
 
 EXPORT_SYMBOL(usb_find_interface_driver_for_ifnum);
 EXPORT_SYMBOL(usb_driver_claim_interface);
@@ -2799,6 +2799,5 @@
 EXPORT_SYMBOL(usb_set_configuration);
 EXPORT_SYMBOL(usb_set_interface);
 
-EXPORT_SYMBOL(usb_make_path);
 EXPORT_SYMBOL(usb_devfs_handle);
 MODULE_LICENSE("GPL");
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h       Sat May 11 22:29:25 2002
+++ b/include/linux/usb.h       Sat May 11 22:29:25 2002
@@ -363,22 +363,6 @@
 extern int usb_root_hub_string(int id, int serial,
                char *type, __u8 *data, int len);
 
-/*
- * As of USB 2.0, full/low speed devices are segregated into trees.
- * One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
- * The other type grows from high speed hubs when they connect to
- * full/low speed devices using "Transaction Translators" (TTs).
- *
- * TTs should only be known to the hub driver, and high speed bus
- * drivers (only EHCI for now).  They affect periodic scheduling and
- * sometimes control/bulk error recovery.
- */
-struct usb_tt {
-       struct usb_device       *hub;   /* upstream highspeed hub */
-       int                     multi;  /* true means one TT per port */
-};
-
-
 /* -------------------------------------------------------------------------- */
 
 /* This is arbitrary.
@@ -387,6 +371,8 @@
  */
 #define USB_MAXCHILDREN                (16)
 
+struct usb_tt;
+
 struct usb_device {
        int             devnum;         /* Address on USB bus */
        char            devpath [16];   /* Use in messages: /port/port/... */
@@ -1176,6 +1162,7 @@
  * appropriately.
  */
 
+/* NOTE:  these are not the standard USB_ENDPOINT_XFER_* values!! */
 #define PIPE_ISOCHRONOUS               0
 #define PIPE_INTERRUPT                 1
 #define PIPE_CONTROL                   2

_______________________________________________________________

Have big pipes? SourceForge.net is looking for download mirrors. We supply
the hardware. You get the recognition. Email Us: [EMAIL PROTECTED]
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to