# 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.686 -> 1.687 # drivers/usb/hcd.h 1.3 -> 1.4 # drivers/usb/hcd.c 1.5 -> 1.6 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/09/26 david-b@pacbell.net 1.687 # [PATCH] Re: [PATCH 2.4.20-pre7 1 of 2] usbcore/hcd updates # # 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 # -------------------------------------------- # diff -Nru a/drivers/usb/hcd.c b/drivers/usb/hcd.c --- a/drivers/usb/hcd.c Mon Sep 30 10:47:15 2002 +++ b/drivers/usb/hcd.c Mon Sep 30 10:47:15 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); diff -Nru a/drivers/usb/hcd.h b/drivers/usb/hcd.h --- a/drivers/usb/hcd.h Mon Sep 30 10:47:15 2002 +++ b/drivers/usb/hcd.h Mon Sep 30 10:47:15 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 */