This is a slightly updated version of the patch I sent before.
Please merge to Marcelo's latest.
Thanks in advance,
- Dave
David Brownell wrote:
> Here's the first of those two patches, to usbcore's "hcd" glue:
>
> - removes something I left in pre7 to simplify these patches.
> - does pci map/unmap for the hardware-aware layer
> - knows that none fault mode is no longer allowed
>
> It'll break the 2.4.20-pre7 ehci-hcd, so use it with [2 of 2].
>
> - Dave
>
>
--- ./drivers/usb-pre7/hcd.h Thu Sep 12 22:17:09 2002
+++ ./drivers/usb/hcd.h Fri Sep 13 11:04:25 2002
@@ -36,7 +36,6 @@
struct usb_bus *bus; /* hcd is-a bus */
struct list_head hcd_list;
- const char *bus_name;
const char *product_desc;
const char *description; /* "ehci-hcd" etc */
--- ./drivers/usb-pre7/hcd.c Thu Sep 12 22:17:09 2002
+++ ./drivers/usb/hcd.c Sat Sep 14 17:04:09 2002
@@ -296,7 +296,7 @@
// serial number
} else if (id == 1) {
- strcpy (buf, hcd->bus_name);
+ strcpy (buf, hcd->bus->bus_name);
// product description
} else if (id == 2) {
@@ -392,7 +392,7 @@
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
// wValue == urb->dev->devaddr
dbg ("%s root hub device address %d",
- hcd->bus_name, wValue);
+ hcd->bus->bus_name, wValue);
break;
/* INTERFACE REQUESTS (no defined feature/status flags) */
@@ -506,7 +506,7 @@
&& rh_status_urb (hcd, urb) != 0) {
/* another driver snuck in? */
dbg ("%s, can't resubmit roothub status urb?",
- hcd->bus_name);
+ hcd->bus->bus_name);
spin_unlock_irqrestore (&hcd_data_lock, flags);
BUG ();
}
@@ -687,6 +687,7 @@
base);
// FIXME simpler: make "bus" be that data, not pointer to it.
+// (fixed in 2.5)
bus = usb_alloc_bus (&hcd_operations);
if (bus == NULL) {
dbg ("usb_alloc_bus fail");
@@ -695,7 +696,6 @@
goto clean_3;
}
hcd->bus = bus;
- hcd->bus_name = dev->slot_name; /* prefer bus->bus_name */
bus->bus_name = dev->slot_name;
hcd->product_desc = dev->name;
bus->hcpriv = (void *) hcd;
@@ -739,14 +739,14 @@
hcd = pci_get_drvdata(dev);
if (!hcd)
return;
- info ("remove: %s, state %x", hcd->bus_name, hcd->state);
+ info ("remove: %s, state %x", hcd->bus->bus_name, hcd->state);
if (in_interrupt ()) BUG ();
hub = hcd->bus->root_hub;
hcd->state = USB_STATE_QUIESCING;
- dbg ("%s: roothub graceful disconnect", hcd->bus_name);
+ dbg ("%s: roothub graceful disconnect", hcd->bus->bus_name);
usb_disconnect (&hub);
// usb_disconnect (&hcd->bus->root_hub);
@@ -817,7 +817,7 @@
int retval;
hcd = pci_get_drvdata(dev);
- info ("suspend %s to state %d", hcd->bus_name, state);
+ info ("suspend %s to state %d", hcd->bus->bus_name, state);
pci_save_state (dev, hcd->pci_state);
@@ -846,12 +846,12 @@
int retval;
hcd = pci_get_drvdata(dev);
- info ("resume %s", hcd->bus_name);
+ info ("resume %s", hcd->bus->bus_name);
/* guard against multiple resumes (APM bug?) */
atomic_inc (&hcd->resume_count);
if (atomic_read (&hcd->resume_count) != 1) {
- err ("concurrent PCI resumes for %s", hcd->bus_name);
+ err ("concurrent PCI resumes for %s", hcd->bus->bus_name);
retval = 0;
goto done;
}
@@ -868,7 +868,8 @@
retval = hcd->driver->resume (hcd);
if (!HCD_IS_RUNNING (hcd->state)) {
- dbg ("resume %s failure, retval %d", hcd->bus_name, retval);
+ dbg ("resume %s failure, retval %d",
+ hcd->bus->bus_name, retval);
hc_died (hcd);
// FIXME: recover, reset etc.
} else {
@@ -943,7 +944,8 @@
list_for_each (urblist, &dev->urb_list) {
urb = list_entry (urblist, struct urb, urb_list);
dbg ("shutdown %s urb %p pipe %x, current status %d",
- hcd->bus_name, urb, urb->pipe, urb->status);
+ hcd->bus->bus_name,
+ urb, urb->pipe, urb->status);
if (urb->status == -EINPROGRESS)
urb->status = -ESHUTDOWN;
}
@@ -1067,8 +1069,6 @@
if (urb->transfer_buffer_length < 0)
return -EINVAL;
- // FIXME set urb->transfer_dma and/or setup_dma
-
if (urb->next) {
warn ("use explicit queuing not urb->next");
return -EINVAL;
@@ -1186,16 +1186,26 @@
if (status)
return status;
+ // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag
+ if (usb_pipecontrol (urb->pipe))
+ urb->setup_dma = pci_map_single (
+ hcd->pdev,
+ urb->setup_packet,
+ sizeof (struct usb_ctrlrequest),
+ PCI_DMA_TODEVICE);
+ if (urb->transfer_buffer_length != 0)
+ urb->transfer_dma = pci_map_single (
+ hcd->pdev,
+ urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ usb_pipein (urb->pipe)
+ ? PCI_DMA_FROMDEVICE
+ : PCI_DMA_TODEVICE);
+
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;
}
@@ -1282,25 +1292,25 @@
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.
+ /* Any status except -EINPROGRESS means the HCD has already started
+ * to return this URB to the driver. In that case, there's no
+ * more work for us 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.
+ * There's much magic because of "automagic resubmit" of interrupt
+ * transfers, stopped only by explicit unlinking. We won't issue
+ * an "it's unlinked" callback more than once, but device drivers
+ * can need to retry (SMP, -EAGAIN) an unlink request as well as
+ * fake out the "not yet completed" state (set -EINPROGRESS) if
+ * unlinking from complete(). Automagic eventually vanishes.
*
* 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) {
+ if (urb->status != -EINPROGRESS) {
+ if (usb_pipetype (urb->pipe) == PIPE_INTERRUPT)
+ retval = -EAGAIN;
+ else
retval = -EINVAL;
- goto done;
- }
+ goto done;
}
/* maybe set up to block on completion notification */
@@ -1340,7 +1350,7 @@
&& HCD_IS_RUNNING (hcd->state)
&& !retval) {
dbg ("%s: wait for giveback urb %p",
- hcd->bus_name, urb);
+ hcd->bus->bus_name, urb);
wait_for_completion (&splice.done);
} else if ((urb->transfer_flags & USB_ASYNC_UNLINK) && retval == 0) {
return -EINPROGRESS;
@@ -1352,7 +1362,7 @@
bye:
if (retval)
dbg ("%s: hcd_unlink_urb fail %d",
- hcd ? hcd->bus_name : "(no bus?)",
+ hcd ? hcd->bus->bus_name : "(no bus?)",
retval);
return retval;
}
@@ -1385,7 +1395,7 @@
/* device driver problem with refcounts? */
if (!list_empty (&dev->urb_list)) {
dbg ("free busy dev, %s devnum %d (bug!)",
- hcd->bus_name, udev->devnum);
+ hcd->bus->bus_name, udev->devnum);
return -EINVAL;
}
@@ -1460,7 +1470,17 @@
dbg ("giveback urb %p status %d len %d",
urb, urb->status, urb->actual_length);
- // FIXME unmap urb->transfer_dma and/or setup_dma
+ // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag
+ if (usb_pipecontrol (urb->pipe))
+ pci_unmap_single (hcd->pdev, urb->setup_dma,
+ sizeof (struct usb_ctrlrequest),
+ PCI_DMA_TODEVICE);
+ if (urb->transfer_buffer_length != 0)
+ pci_unmap_single (hcd->pdev, urb->transfer_dma,
+ urb->transfer_buffer_length,
+ usb_pipein (urb->pipe)
+ ? PCI_DMA_FROMDEVICE
+ : PCI_DMA_TODEVICE);
/* pass ownership to the completion handler */
urb->complete (urb);