On Wed, Apr 03, 2002 at 10:45:09AM -0800, Greg KH wrote:
> [EMAIL PROTECTED], 2002-04-02 16:55:38-08:00, [EMAIL PROTECTED]
> USB hcd core
>
> update with the 2.5 version of hcd
>
> drivers/usb/hcd.c | 394 ++++++++++++++++++++++++++++++++++++++----------------
> drivers/usb/hcd.h | 2
> 2 files changed, 279 insertions(+), 117 deletions(-)
# 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.304 -> 1.305
# drivers/usb/hcd.h 1.1 -> 1.2
# drivers/usb/hcd.c 1.2 -> 1.3
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/04/02 [EMAIL PROTECTED] 1.305
# USB hcd core
#
# update with the 2.5 version of hcd
# --------------------------------------------
#
diff -Nru a/drivers/usb/hcd.c b/drivers/usb/hcd.c
--- a/drivers/usb/hcd.c Wed Apr 3 10:47:53 2002
+++ b/drivers/usb/hcd.c Wed Apr 3 10:47:53 2002
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001 by David Brownell
+ * Copyright (c) 2001-2002 by David Brownell
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -31,11 +31,9 @@
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
+#include <linux/completion.h>
#include <linux/uts.h> /* for UTS_SYSNAME */
-#ifndef CONFIG_USB_DEBUG
- #define CONFIG_USB_DEBUG /* this is experimental! */
-#endif
#ifdef CONFIG_USB_DEBUG
#define DEBUG
@@ -104,6 +102,9 @@
/*-------------------------------------------------------------------------*/
+#define KERNEL_REL ((LINUX_VERSION_CODE >> 16) & 0x0ff)
+#define KERNEL_VER ((LINUX_VERSION_CODE >> 8) & 0x0ff)
+
/* usb 2.0 root hub device descriptor */
static const u8 usb2_rh_dev_descriptor [18] = {
0x12, /* __u8 bLength; */
@@ -117,7 +118,7 @@
0x00, 0x00, /* __u16 idVendor; */
0x00, 0x00, /* __u16 idProduct; */
- 0x40, 0x02, /* __u16 bcdDevice; (v2.4) */
+ KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */
0x03, /* __u8 iManufacturer; */
0x02, /* __u8 iProduct; */
@@ -140,7 +141,7 @@
0x00, 0x00, /* __u16 idVendor; */
0x00, 0x00, /* __u16 idProduct; */
- 0x40, 0x02, /* __u16 bcdDevice; (v2.4) */
+ KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */
0x03, /* __u8 iManufacturer; */
0x02, /* __u8 iProduct; */
@@ -151,9 +152,56 @@
/*-------------------------------------------------------------------------*/
-/* Configuration descriptor for all our root hubs */
+/* Configuration descriptors for our root hubs */
+
+static const u8 fs_rh_config_descriptor [] = {
+
+ /* one configuration */
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, 0x00, /* __u16 wTotalLength; */
+ 0x01, /* __u8 bNumInterfaces; (1) */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes;
+ Bit 7: Bus-powered,
+ 6: Self-powered,
+ 5 Remote-wakwup,
+ 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* USB 1.1:
+ * USB 2.0, single TT organization (mandatory):
+ * one interface, protocol 0
+ *
+ * USB 2.0, multiple TT organization (optional):
+ * two interfaces, protocols 1 (like single TT)
+ * and 2 (multiple TT mode) ... config is
+ * sometimes settable
+ * NOT IMPLEMENTED
+ */
+
+ /* one interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* one endpoint (status change endpoint) */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
+ 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */
+};
-static const u8 rh_config_descriptor [] = {
+static const u8 hs_rh_config_descriptor [] = {
/* one configuration */
0x09, /* __u8 bLength; */
@@ -197,7 +245,7 @@
0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
0x03, /* __u8 ep_bmAttributes; Interrupt */
0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
- 0x0c /* __u8 ep_bInterval; (12ms -- usb 2.0 spec) */
+ 0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */
};
/*-------------------------------------------------------------------------*/
@@ -206,12 +254,12 @@
* helper routine for returning string descriptors in UTF-16LE
* input can actually be ISO-8859-1; ASCII is its 7-bit subset
*/
-static int ascii2utf (char *ascii, u8 *utf, int utfmax)
+static int ascii2utf (char *s, u8 *utf, int utfmax)
{
int retval;
- for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
- *utf++ = *ascii++ & 0x7f;
+ for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
+ *utf++ = *s++;
*utf++ = 0;
}
return retval;
@@ -230,8 +278,7 @@
*/
static int rh_string (
int id,
- struct pci_dev *pci_desc,
- char *type,
+ struct usb_hcd *hcd,
u8 *data,
int len
) {
@@ -245,15 +292,16 @@
// serial number
} else if (id == 1) {
- strcpy (buf, pci_desc->slot_name);
+ strcpy (buf, hcd->bus_name);
// product description
} else if (id == 2) {
- strcpy (buf, pci_desc->name);
+ strcpy (buf, hcd->product_desc);
// id 3 == vendor description
} else if (id == 3) {
- sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE, type);
+ sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE,
+ hcd->description);
// unsupported IDs --> "protocol stall"
} else
@@ -315,14 +363,17 @@
len = 18;
break;
case USB_DT_CONFIG << 8:
- bufp = rh_config_descriptor;
- len = sizeof rh_config_descriptor;
+ if (hcd->driver->flags & HCD_USB2) {
+ bufp = hs_rh_config_descriptor;
+ len = sizeof hs_rh_config_descriptor;
+ } else {
+ bufp = fs_rh_config_descriptor;
+ len = sizeof fs_rh_config_descriptor;
+ }
break;
case USB_DT_STRING << 8:
urb->actual_length = rh_string (
- wValue & 0xff,
- hcd->pdev,
- (char *) hcd->description,
+ wValue & 0xff, hcd,
ubuf, wLength);
break;
default:
@@ -412,10 +463,8 @@
init_timer (&hcd->rh_timer);
hcd->rh_timer.function = rh_report_status;
hcd->rh_timer.data = (unsigned long) urb;
- hcd->rh_timer.expires = jiffies
- + (HZ * (urb->interval < 30
- ? 30
- : urb->interval)) / 1000;
+ /* USB 2.0 spec says 256msec; this is close enough */
+ hcd->rh_timer.expires = jiffies + HZ/4;
add_timer (&hcd->rh_timer);
return 0;
}
@@ -521,6 +570,7 @@
* usb_hcd_pci_probe - initialize PCI-based HCDs
* @dev: USB Host Controller being probed
* @id: pci hotplug id connecting controller to HCD framework
+ * Context: !in_interrupt()
*
* Allocates basic PCI resources for this USB host controller, and
* then invokes the start() method for the HCD associated with it
@@ -606,7 +656,7 @@
return retval;
}
}
- dev->driver_data = hcd;
+ pci_set_drvdata(dev, hcd);
hcd->driver = driver;
hcd->description = driver->description;
hcd->pdev = dev;
@@ -652,6 +702,7 @@
}
hcd->bus = bus;
hcd->bus_name = dev->slot_name;
+ hcd->product_desc = dev->name;
bus->hcpriv = (void *) hcd;
INIT_LIST_HEAD (&hcd->dev_list);
@@ -677,6 +728,7 @@
/**
* usb_hcd_pci_remove - shutdown processing for PCI-based HCDs
* @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
*
* Reverses the effect of usb_hcd_pci_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
@@ -689,7 +741,7 @@
struct usb_hcd *hcd;
struct usb_device *hub;
- hcd = (struct usb_hcd *) dev->driver_data;
+ hcd = pci_get_drvdata(dev);
if (!hcd)
return;
info ("remove: %s, state %x", hcd->bus_name, hcd->state);
@@ -769,7 +821,7 @@
struct usb_hcd *hcd;
int retval;
- hcd = (struct usb_hcd *) dev->driver_data;
+ hcd = pci_get_drvdata(dev);
info ("suspend %s to state %d", hcd->bus_name, state);
pci_save_state (dev, hcd->pci_state);
@@ -798,7 +850,7 @@
struct usb_hcd *hcd;
int retval;
- hcd = (struct usb_hcd *) dev->driver_data;
+ hcd = pci_get_drvdata(dev);
info ("resume %s", hcd->bus_name);
/* guard against multiple resumes (APM bug?) */
@@ -913,8 +965,29 @@
/*-------------------------------------------------------------------------*/
+static void urb_unlink (struct urb *urb)
+{
+ unsigned long flags;
+ struct usb_device *dev;
+
+ /* Release any periodic transfer bandwidth */
+ if (urb->bandwidth)
+ usb_release_bandwidth (urb->dev, urb,
+ usb_pipeisoc (urb->pipe));
+
+ /* clear all state linking urb to this dev (and hcd) */
+
+ spin_lock_irqsave (&hcd_data_lock, flags);
+ list_del_init (&urb->urb_list);
+ dev = urb->dev;
+ urb->dev = NULL;
+ usb_dec_dev_use (dev);
+ spin_unlock_irqrestore (&hcd_data_lock, flags);
+}
+
+
/* may be called in any context with a valid urb->dev usecount */
-/* caller surrenders "ownership" of urb (and chain at urb->next). */
+/* caller surrenders "ownership" of urb */
static int hcd_submit_urb (struct urb *urb)
{
@@ -922,7 +995,7 @@
struct usb_hcd *hcd;
struct hcd_dev *dev;
unsigned long flags;
- int pipe;
+ int pipe, temp, max;
int mem_flags;
if (!urb || urb->hcpriv || !urb->complete)
@@ -930,6 +1003,7 @@
urb->status = -EINPROGRESS;
urb->actual_length = 0;
+ urb->bandwidth = 0;
INIT_LIST_HEAD (&urb->urb_list);
if (!urb->dev || !urb->dev->bus || urb->dev->devnum <= 0)
@@ -943,16 +1017,70 @@
if (hcd->state == USB_STATE_QUIESCING || !HCD_IS_RUNNING (hcd->state))
return -ESHUTDOWN;
pipe = urb->pipe;
+ temp = usb_pipetype (urb->pipe);
if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe),
usb_pipeout (pipe)))
return -EPIPE;
- // FIXME paging/swapping requests over USB should not use GFP_KERNEL
- // and might even need to use GFP_NOIO ... that flag actually needs
- // to be passed from the higher level.
+ /* NOTE: 2.5 passes this value explicitly in submit() */
mem_flags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL;
+ /* FIXME there should be a sharable lock protecting us against
+ * config/altsetting changes and disconnects, kicking in here.
+ */
+
+ /* Sanity check, so HCDs can rely on clean data */
+ max = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
+ if (max <= 0) {
+ err ("bogus endpoint (bad maxpacket)");
+ return -EINVAL;
+ }
+
+ /* "high bandwidth" mode, 1-3 packets/uframe? */
+ if (urb->dev->speed == USB_SPEED_HIGH) {
+ int mult;
+ switch (temp) {
+ case PIPE_ISOCHRONOUS:
+ case PIPE_INTERRUPT:
+ mult = 1 + ((max >> 11) & 0x03);
+ max &= 0x03ff;
+ max *= mult;
+ }
+ }
+
+ /* periodic transfers limit size per frame/uframe */
+ switch (temp) {
+ case PIPE_ISOCHRONOUS: {
+ int n, len;
+
+ if (urb->number_of_packets <= 0)
+ return -EINVAL;
+ for (n = 0; n < urb->number_of_packets; n++) {
+ len = urb->iso_frame_desc [n].length;
+ if (len < 0 || len > max)
+ return -EINVAL;
+ }
+
+ }
+ break;
+ case PIPE_INTERRUPT:
+ if (urb->transfer_buffer_length > max)
+ return -EINVAL;
+ }
+
+ /* the I/O buffer must usually be mapped/unmapped */
+ if (urb->transfer_buffer_length < 0)
+ return -EINVAL;
+
+ if (urb->next) {
+ warn ("use explicit queuing not urb->next");
+ return -EINVAL;
+ }
+
#ifdef DEBUG
+ /* stuff that drivers shouldn't do, but which shouldn't
+ * cause problems in HCDs if they get it wrong.
+ */
{
unsigned int orig_flags = urb->transfer_flags;
unsigned int allowed;
@@ -960,7 +1088,7 @@
/* enforce simple/standard policy */
allowed = USB_ASYNC_UNLINK; // affects later unlinks
allowed |= USB_NO_FSBR; // only affects UHCI
- switch (usb_pipetype (pipe)) {
+ switch (temp) {
case PIPE_CONTROL:
allowed |= USB_DISABLE_SPD;
break;
@@ -977,17 +1105,61 @@
}
urb->transfer_flags &= allowed;
- /* warn if submitter gave bogus flags */
- if (urb->transfer_flags != orig_flags)
- warn ("BOGUS urb flags, %x --> %x",
+ /* fail if submitter gave bogus flags */
+ if (urb->transfer_flags != orig_flags) {
+ err ("BOGUS urb flags, %x --> %x",
orig_flags, urb->transfer_flags);
+ return -EINVAL;
+ }
}
#endif
/*
- * FIXME: alloc periodic bandwidth here, for interrupt and iso?
- * Need to look at the ring submit mechanism for iso tds ... they
- * aren't actually "periodic" in 2.4 kernels.
+ * Force periodic transfer intervals to be legal values that are
+ * a power of two (so HCDs don't need to).
*
+ * FIXME want bus->{intr,iso}_sched_horizon values here. Each HC
+ * supports different values... this uses EHCI/UHCI defaults (and
+ * EHCI can use smaller non-default values).
+ */
+ switch (temp) {
+ case PIPE_ISOCHRONOUS:
+ case PIPE_INTERRUPT:
+ /* too small? */
+ if (urb->interval <= 0)
+ return -EINVAL;
+ /* too big? */
+ switch (urb->dev->speed) {
+ case USB_SPEED_HIGH: /* units are microframes */
+ // NOTE usb handles 2^15
+ if (urb->interval > (1024 * 8))
+ urb->interval = 1024 * 8;
+ temp = 1024 * 8;
+ break;
+ case USB_SPEED_FULL: /* units are frames/msec */
+ case USB_SPEED_LOW:
+ if (temp == PIPE_INTERRUPT) {
+ if (urb->interval > 255)
+ return -EINVAL;
+ // NOTE ohci only handles up to 32
+ temp = 128;
+ } else {
+ if (urb->interval > 1024)
+ urb->interval = 1024;
+ // NOTE usb and ohci handle up to 2^15
+ temp = 1024;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* power of two? */
+ while (temp > urb->interval)
+ temp >>= 1;
+ urb->interval = temp;
+ }
+
+
+ /*
* FIXME: make urb timeouts be generic, keeping the HCD cores
* as simple as possible.
*/
@@ -1014,20 +1186,20 @@
status = -ESHUTDOWN;
}
spin_unlock_irqrestore (&hcd_data_lock, flags);
+ if (status)
+ return status;
- if (!status) {
- if (urb->dev == hcd->bus->root_hub)
- status = rh_urb_enqueue (hcd, urb);
- else
- status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
- }
- if (status) {
- if (urb->dev) {
- urb->status = status;
- usb_hcd_giveback_urb (hcd, urb);
- }
- }
- return 0;
+ if (urb->dev == hcd->bus->root_hub)
+ status = rh_urb_enqueue (hcd, urb);
+ else
+ status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
+ /* urb->dev got nulled if hcd called giveback for us
+ * NOTE: ref to urb->dev is a race without (2.5) refcounting,
+ * unless driver only returns status when it didn't giveback
+ */
+ if (status && urb->dev)
+ urb_unlink (urb);
+ return status;
}
/*-------------------------------------------------------------------------*/
@@ -1043,7 +1215,7 @@
struct completion_splice { // modified urb context:
/* did we complete? */
- int done;
+ struct completion done;
/* original urb data */
void (*complete)(struct urb *);
@@ -1061,7 +1233,8 @@
urb->context = splice->context;
urb->complete (urb);
- splice->done = 1;
+ /* then let the synchronous unlink call complete */
+ complete (&splice->done);
}
/*
@@ -1081,20 +1254,20 @@
if (!urb)
return -EINVAL;
- // FIXME: add some explicit records to flag the
- // state where the URB is "in periodic completion".
- // Workaround is for driver to set the urb status
- // to "-EINPROGRESS", so it can get through here
- // and unlink from the completion handler.
-
/*
* we contend for urb->status with the hcd core,
* which changes it while returning the urb.
+ *
+ * Caller guaranteed that the urb pointer hasn't been freed, and
+ * that it was submitted. But as a rule it can't know whether or
+ * not it's already been unlinked ... so we respect the reversed
+ * lock sequence needed for the usb_hcd_giveback_urb() code paths
+ * (urb lock, then hcd_data_lock) in case some other CPU is now
+ * unlinking it.
*/
spin_lock_irqsave (&urb->lock, flags);
- if (!urb->hcpriv
- || urb->status != -EINPROGRESS
- || urb->transfer_flags & USB_TIMEOUT_KILLED) {
+ spin_lock (&hcd_data_lock);
+ if (!urb->hcpriv || urb->transfer_flags & USB_TIMEOUT_KILLED) {
retval = -EINVAL;
goto done;
}
@@ -1103,6 +1276,8 @@
retval = -ENODEV;
goto done;
}
+
+ /* giveback clears dev; non-null means it's linked at this level */
dev = urb->dev->hcpriv;
hcd = urb->dev->bus->hcpriv;
if (!dev || !hcd) {
@@ -1110,6 +1285,27 @@
goto done;
}
+ /* For non-periodic transfers, any status except -EINPROGRESS means
+ * the HCD has already started to unlink this URB from the hardware.
+ * In that case, there's no more work to do.
+ *
+ * For periodic transfers, this is the only way to trigger unlinking
+ * from the hardware. Since we (currently) overload urb->status to
+ * tell the driver to unlink, error status might get clobbered ...
+ * unless that transfer hasn't yet restarted. One such case is when
+ * the URB gets unlinked from its completion handler.
+ *
+ * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED
+ */
+ switch (usb_pipetype (urb->pipe)) {
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+ if (urb->status != -EINPROGRESS) {
+ retval = -EINVAL;
+ goto done;
+ }
+ }
+
/* maybe set up to block on completion notification */
if ((urb->transfer_flags & USB_TIMEOUT_KILLED))
urb->status = -ETIMEDOUT;
@@ -1120,7 +1316,7 @@
goto done;
}
/* synchronous unlink: block till we see the completion */
- splice.done = 0;
+ init_completion (&splice.done);
splice.complete = urb->complete;
splice.context = urb->context;
urb->complete = unlink_complete;
@@ -1130,6 +1326,7 @@
/* asynchronous unlink */
urb->status = -ECONNRESET;
}
+ spin_unlock (&hcd_data_lock);
spin_unlock_irqrestore (&urb->lock, flags);
if (urb == (struct urb *) hcd->rh_timer.data) {
@@ -1145,17 +1342,15 @@
if (!(urb->transfer_flags & (USB_ASYNC_UNLINK|USB_TIMEOUT_KILLED))
&& HCD_IS_RUNNING (hcd->state)
&& !retval) {
- while (!splice.done) {
- set_current_state (TASK_UNINTERRUPTIBLE);
- schedule_timeout ((2/*msec*/ * HZ) / 1000);
- dbg ("%s: wait for giveback urb %p",
- hcd->bus_name, urb);
- }
+ dbg ("%s: wait for giveback urb %p",
+ hcd->bus_name, urb);
+ wait_for_completion (&splice.done);
} else if ((urb->transfer_flags & USB_ASYNC_UNLINK) && retval == 0) {
return -EINPROGRESS;
}
goto bye;
done:
+ spin_unlock (&hcd_data_lock);
spin_unlock_irqrestore (&urb->lock, flags);
bye:
if (retval)
@@ -1223,6 +1418,9 @@
struct usb_hcd *hcd = __hcd;
int start = hcd->state;
+ if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
+ return;
+
hcd->driver->irq (hcd);
if (hcd->state != start && hcd->state == USB_STATE_HALT)
hc_died (hcd);
@@ -1234,6 +1432,7 @@
* usb_hcd_giveback_urb - return URB from HCD to device driver
* @hcd: host controller returning the URB
* @urb: urb being returned to the USB device driver.
+ * Context: in_interrupt()
*
* This hands the URB from HCD to its USB device driver, using its
* completion function. The HCD has freed all per-urb resources
@@ -1246,34 +1445,13 @@
* and will be reissued. They should just call their completion handlers
* until the urb is returned to the device driver by unlinking.
*
- * In common cases, urb->next will be submitted before the completion
- * function gets called. That's not done if the URB includes error
- * status (including unlinking).
+ * NOTE that no urb->next processing is done, even for isochronous URBs.
+ * ISO streaming functionality can be achieved by having completion handlers
+ * re-queue URBs. Such explicit queuing doesn't discard error reports.
*/
void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
{
- unsigned long flags;
- struct usb_device *dev;
-
- /* Release periodic transfer bandwidth */
- if (urb->bandwidth) {
- switch (usb_pipetype (urb->pipe)) {
- case PIPE_INTERRUPT:
- usb_release_bandwidth (urb->dev, urb, 0);
- break;
- case PIPE_ISOCHRONOUS:
- usb_release_bandwidth (urb->dev, urb, 1);
- break;
- }
- }
-
- /* clear all state linking urb to this dev (and hcd) */
-
- spin_lock_irqsave (&hcd_data_lock, flags);
- list_del_init (&urb->urb_list);
- dev = urb->dev;
- urb->dev = NULL;
- spin_unlock_irqrestore (&hcd_data_lock, flags);
+ urb_unlink (urb);
// NOTE: a generic device/urb monitoring hook would go here.
// hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev)
@@ -1282,26 +1460,10 @@
// hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev)
if (urb->status)
- dbg ("giveback urb %p status %d", urb, urb->status);
-
- /* if no error, make sure urb->next progresses */
- else if (urb->next) {
- int status;
-
- status = usb_submit_urb (urb->next);
- if (status) {
- dbg ("urb %p chain fail, %d", urb->next, status);
- urb->next->status = -ENOTCONN;
- }
-
- /* HCDs never modify the urb->next chain, and only use it here,
- * so that if urb->complete sees an URB there with -ENOTCONN,
- * it knows the driver chained it but it couldn't be submitted.
- */
- }
+ dbg ("giveback urb %p status %d len %d",
+ urb, urb->status, urb->actual_length);
/* pass ownership to the completion handler */
- usb_dec_dev_use (dev);
urb->complete (urb);
}
EXPORT_SYMBOL (usb_hcd_giveback_urb);
diff -Nru a/drivers/usb/hcd.h b/drivers/usb/hcd.h
--- a/drivers/usb/hcd.h Wed Apr 3 10:47:53 2002
+++ b/drivers/usb/hcd.h Wed Apr 3 10:47:53 2002
@@ -37,7 +37,7 @@
struct list_head hcd_list;
const char *bus_name;
-
+ const char *product_desc;
const char *description; /* "ehci-hcd" etc */
struct timer_list rh_timer; /* drives root hub */
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel