# 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