Attached is a patch leveraging some of the new generic dma stuff:
- Replaces dma mapping calls in usbcore with generic equivalents.
This is a minor code shrink (which we'd hoped could happen).
- Pass dma mask along, so net drivers can notice it'd be good to
set NETIF_F_HIGHDMA; or scsi ones can set highmem_io. (Some
Intel EHCI setups are able to support this kind of DMA.)
- Updates one net driver (usbnet) to set NETIF_F_HIGHDMA when
appropriate, mostly as an example (since I can't test this).
- Provides Documentation/usb/dma.txt, describing current APIs.
(Unchanged by this patch, except dma mask visibility.)
- Converted another info() to dev_info(), and likewise a couple
dbg() to dev_dbg() conversions in the modified routine.
The number of FIXMEs was conserved: the generic API doesn't yet
fix the error reporting bugs in the PCI-specific mapping API.
- Dave
--- ./include/linux-dist/usb.h Tue Dec 24 09:59:08 2002
+++ ./include/linux/usb.h Tue Dec 24 13:41:22 2002
@@ -28,14 +28,6 @@
mdelay(ms);
}
-/*
- * USB device number allocation bitmap. There's one bitmap
- * per USB tree.
- */
-struct usb_devmap {
- unsigned long devicemap[128 / (8*sizeof(unsigned long))];
-};
-
struct usb_device;
/*-------------------------------------------------------------------------*/
@@ -159,10 +151,16 @@
struct usb_operations;
+/* USB device number allocation bitmap */
+struct usb_devmap {
+ unsigned long devicemap[128 / (8*sizeof(unsigned long))];
+};
+
/*
- * Allocated per bus we have
+ * Allocated per bus (tree of devices) we have:
*/
struct usb_bus {
+ struct device *controller; /* host/master side hardware */
int busnum; /* Bus number (in order of reg) */
char *bus_name; /* stable id (PCI slot_name etc) */
--- ./drivers/usb-dist/core/hcd.h Tue Dec 24 10:01:01 2002
+++ ./drivers/usb/core/hcd.h Tue Dec 24 13:41:22 2002
@@ -145,26 +145,6 @@
dma_addr_t *dma);
void (*buffer_free)(struct usb_bus *bus, size_t size,
void *addr, dma_addr_t dma);
-
- int (*buffer_map) (struct usb_bus *bus,
- void *addr, dma_addr_t *dma,
- size_t size, int direction);
- void (*buffer_dmasync) (struct usb_bus *bus,
- dma_addr_t dma,
- size_t size, int direction);
- void (*buffer_unmap) (struct usb_bus *bus,
- dma_addr_t dma,
- size_t size, int direction);
-
- int (*buffer_map_sg) (struct usb_bus *bus,
- struct scatterlist *sg, int *n_hw_ents,
- int nents, int direction);
- void (*buffer_dmasync_sg) (struct usb_bus *bus,
- struct scatterlist *sg,
- int n_hw_ents, int direction);
- void (*buffer_unmap_sg) (struct usb_bus *bus,
- struct scatterlist *sg,
- int n_hw_ents, int direction);
};
/* each driver provides one of these, and hardware init support */
@@ -248,23 +228,6 @@
void hcd_buffer_free (struct usb_bus *bus, size_t size,
void *addr, dma_addr_t dma);
-int hcd_buffer_map (struct usb_bus *bus,
- void *addr, dma_addr_t *dma,
- size_t size, int direction);
-void hcd_buffer_dmasync (struct usb_bus *bus,
- dma_addr_t dma,
- size_t size, int direction);
-void hcd_buffer_unmap (struct usb_bus *bus,
- dma_addr_t dma,
- size_t size, int direction);
-int hcd_buffer_map_sg (struct usb_bus *bus, struct scatterlist *sg,
- int *n_hw_ents, int nents, int direction);
-void hcd_buffer_sync_sg (struct usb_bus *bus, struct scatterlist *sg,
- int n_hw_ents, int direction);
-
-void hcd_buffer_unmap_sg (struct usb_bus *bus, struct scatterlist *sg,
- int n_hw_ents, int direction);
-
/* generic bus glue, needed for host controllers that don't use PCI */
extern struct usb_operations usb_hcd_operations;
extern void usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r);
--- ./drivers/usb-dist/core/hcd-pci.c Tue Dec 24 10:01:01 2002
+++ ./drivers/usb/core/hcd-pci.c Tue Dec 24 13:41:22 2002
@@ -138,7 +138,8 @@
hcd->pdev = dev;
hcd->self.bus_name = dev->slot_name;
hcd->product_desc = dev->dev.name;
- hcd->controller = &dev->dev;
+ hcd->self.controller = &dev->dev;
+ hcd->controller = hcd->self.controller;
if ((retval = hcd_buffer_create (hcd)) != 0) {
clean_3:
--- ./drivers/usb-dist/core/usb.c Tue Dec 24 10:01:01 2002
+++ ./drivers/usb/core/usb.c Tue Dec 24 13:41:22 2002
@@ -41,6 +41,11 @@
#endif
#include <linux/usb.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+
#include "hcd.h"
#include "usb.h"
@@ -803,7 +808,7 @@
*pdev = NULL;
- info("USB disconnect on device %d", dev->devnum);
+ dev_info (dev->dev, "USB disconnect, address %d\n", dev->devnum);
/* Free up all the children before we remove this device */
for (i = 0; i < USB_MAXCHILDREN; i++) {
@@ -812,7 +817,7 @@
usb_disconnect(child);
}
- dbg ("unregistering interfaces on device %d", dev->devnum);
+ dev_dbg (dev->dev, "unregistering interfaces\n");
if (dev->actconfig) {
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *interface =
&dev->actconfig->interface[i];
@@ -822,7 +827,7 @@
}
}
- dbg ("unregistering the device %d", dev->devnum);
+ dev_dbg (dev->dev, "unregistering device\n");
/* Free the device number and remove the /proc/bus/usb entry */
if (dev->devnum > 0) {
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
@@ -980,6 +985,9 @@
sprintf (&dev->dev.bus_id[0], "%d-%s",
dev->bus->busnum, dev->devpath);
+ /* dma masks come from the controller; readonly, except to hcd */
+ dev->dev.dma_mask = parent->dma_mask;
+
/* USB device state == default ... it's not usable yet */
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
@@ -1104,6 +1112,7 @@
interface->dev.parent = &dev->dev;
interface->dev.driver = NULL;
interface->dev.bus = &usb_bus_type;
+ interface->dev.dma_mask = parent->dma_mask;
sprintf (&interface->dev.bus_id[0], "%d-%s:%d",
dev->bus->busnum, dev->devpath,
desc->bInterfaceNumber);
@@ -1206,24 +1215,21 @@
struct urb *usb_buffer_map (struct urb *urb)
{
struct usb_bus *bus;
- struct usb_operations *op;
+ struct device *controller;
if (!urb
|| usb_pipecontrol (urb->pipe)
|| !urb->dev
|| !(bus = urb->dev->bus)
- || !(op = bus->op)
- || !op->buffer_map)
+ || !(controller = bus->controller))
return 0;
- if (op->buffer_map (bus,
- urb->transfer_buffer,
- &urb->transfer_dma,
- urb->transfer_buffer_length,
+ urb->transfer_dma = dma_map_single (controller,
+ urb->transfer_buffer, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
- ? USB_DIR_IN
- : USB_DIR_OUT))
- return 0;
+ ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ // FIXME generic api broken like pci, can't report errors
+ // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
urb->transfer_flags |= URB_NO_DMA_MAP;
return urb;
}
@@ -1235,22 +1241,19 @@
void usb_buffer_dmasync (struct urb *urb)
{
struct usb_bus *bus;
- struct usb_operations *op;
+ struct device *controller;
if (!urb
|| !(urb->transfer_flags & URB_NO_DMA_MAP)
|| !urb->dev
|| !(bus = urb->dev->bus)
- || !(op = bus->op)
- || !op->buffer_dmasync)
+ || !(controller = bus->controller))
return;
- op->buffer_dmasync (bus,
- urb->transfer_dma,
- urb->transfer_buffer_length,
+ dma_sync_single (controller,
+ urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
- ? USB_DIR_IN
- : USB_DIR_OUT);
+ ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/**
@@ -1262,23 +1265,21 @@
void usb_buffer_unmap (struct urb *urb)
{
struct usb_bus *bus;
- struct usb_operations *op;
+ struct device *controller;
if (!urb
|| !(urb->transfer_flags & URB_NO_DMA_MAP)
|| !urb->dev
|| !(bus = urb->dev->bus)
- || !(op = bus->op)
- || !op->buffer_unmap)
+ || !(controller = bus->controller))
return;
- op->buffer_unmap (bus,
- urb->transfer_dma,
- urb->transfer_buffer_length,
+ dma_unmap_single (controller,
+ urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
- ? USB_DIR_IN
- : USB_DIR_OUT);
+ ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
+
/**
* usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
* @dev: device to which the scatterlist will be mapped
@@ -1297,6 +1298,7 @@
* to complete before starting the next I/O. This is particularly easy
* to do with scatterlists. Just allocate and submit one URB for each DMA
* mapping entry returned, stopping on the first error or when all succeed.
+ * Better yet, use the usb_sg_*() calls, which do that (and more) for you.
*
* This call would normally be used when translating scatterlist requests,
* rather than usb_buffer_map(), since on some hardware (with IOMMUs) it
@@ -1308,26 +1310,17 @@
struct scatterlist *sg, int nents)
{
struct usb_bus *bus;
- struct usb_operations *op;
- int n_hw_ents;
+ struct device *controller;
if (!dev
|| usb_pipecontrol (pipe)
|| !(bus = dev->bus)
- || !(op = bus->op)
- || !op->buffer_map_sg)
- return -1;
-
- if (op->buffer_map_sg (bus,
- sg,
- &n_hw_ents,
- nents,
- usb_pipein (pipe)
- ? USB_DIR_IN
- : USB_DIR_OUT))
+ || !(controller = bus->controller))
return -1;
- return n_hw_ents;
+ // FIXME generic api broken like pci, can't report errors
+ return dma_map_sg (controller, sg, nents,
+ usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/**
@@ -1344,20 +1337,15 @@
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
- struct usb_operations *op;
+ struct device *controller;
if (!dev
|| !(bus = dev->bus)
- || !(op = bus->op)
- || !op->buffer_dmasync_sg)
+ || !(controller = bus->controller))
return;
- op->buffer_dmasync_sg (bus,
- sg,
- n_hw_ents,
- usb_pipein (pipe)
- ? USB_DIR_IN
- : USB_DIR_OUT);
+ dma_sync_sg (controller, sg, n_hw_ents,
+ usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/**
@@ -1373,20 +1361,15 @@
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
- struct usb_operations *op;
+ struct device *controller;
if (!dev
|| !(bus = dev->bus)
- || !(op = bus->op)
- || !op->buffer_unmap_sg)
+ || !(controller = bus->controller))
return;
- op->buffer_unmap_sg (bus,
- sg,
- n_hw_ents,
- usb_pipein (pipe)
- ? USB_DIR_IN
- : USB_DIR_OUT);
+ dma_unmap_sg (controller, sg, n_hw_ents,
+ usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
--- ./drivers/usb-dist/core/buffer.c Tue Dec 24 10:01:02 2002
+++ ./drivers/usb/core/buffer.c Tue Dec 24 13:41:22 2002
@@ -24,11 +24,14 @@
/*
- * DMA-Consistent Buffers
+ * DMA-Coherent Buffers
*/
/* FIXME tune these based on pool statistics ... */
static const size_t pool_max [HCD_BUFFER_POOLS] = {
+ /* platforms without dma-friendly caches might need to
+ * prevent cacheline sharing...
+ */
32,
128,
512,
@@ -133,98 +136,3 @@
}
pci_free_consistent (hcd->pdev, size, addr, dma);
}
-
-
-/*
- * DMA-Mappings for arbitrary memory buffers
- */
-
-int hcd_buffer_map (
- struct usb_bus *bus,
- void *addr,
- dma_addr_t *dma,
- size_t size,
- int direction
-) {
- struct usb_hcd *hcd = bus->hcpriv;
-
- // FIXME pci_map_single() has no standard failure mode!
- *dma = pci_map_single (hcd->pdev, addr, size,
- (direction == USB_DIR_IN)
- ? PCI_DMA_FROMDEVICE
- : PCI_DMA_TODEVICE);
- return 0;
-}
-
-void hcd_buffer_dmasync (
- struct usb_bus *bus,
- dma_addr_t dma,
- size_t size,
- int direction
-) {
- struct usb_hcd *hcd = bus->hcpriv;
-
- pci_dma_sync_single (hcd->pdev, dma, size,
- (direction == USB_DIR_IN)
- ? PCI_DMA_FROMDEVICE
- : PCI_DMA_TODEVICE);
-}
-
-void hcd_buffer_unmap (
- struct usb_bus *bus,
- dma_addr_t dma,
- size_t size,
- int direction
-) {
- struct usb_hcd *hcd = bus->hcpriv;
-
- pci_unmap_single (hcd->pdev, dma, size,
- (direction == USB_DIR_IN)
- ? PCI_DMA_FROMDEVICE
- : PCI_DMA_TODEVICE);
-}
-
-int hcd_buffer_map_sg (
- struct usb_bus *bus,
- struct scatterlist *sg,
- int *n_hw_ents,
- int nents,
- int direction
-) {
- struct usb_hcd *hcd = bus->hcpriv;
-
- // FIXME pci_map_sg() has no standard failure mode!
- *n_hw_ents = pci_map_sg(hcd->pdev, sg, nents,
- (direction == USB_DIR_IN)
- ? PCI_DMA_FROMDEVICE
- : PCI_DMA_TODEVICE);
- return 0;
-}
-
-void hcd_buffer_sync_sg (
- struct usb_bus *bus,
- struct scatterlist *sg,
- int n_hw_ents,
- int direction
-) {
- struct usb_hcd *hcd = bus->hcpriv;
-
- pci_dma_sync_sg(hcd->pdev, sg, n_hw_ents,
- (direction == USB_DIR_IN)
- ? PCI_DMA_FROMDEVICE
- : PCI_DMA_TODEVICE);
-}
-
-void hcd_buffer_unmap_sg (
- struct usb_bus *bus,
- struct scatterlist *sg,
- int n_hw_ents,
- int direction
-) {
- struct usb_hcd *hcd = bus->hcpriv;
-
- pci_unmap_sg(hcd->pdev, sg, n_hw_ents,
- (direction == USB_DIR_IN)
- ? PCI_DMA_FROMDEVICE
- : PCI_DMA_TODEVICE);
-}
--- ./drivers/usb-dist/core/hcd.c Tue Dec 24 10:01:01 2002
+++ ./drivers/usb/core/hcd.c Tue Dec 24 13:41:22 2002
@@ -1031,19 +1031,19 @@
/* lower level hcd code should use *_dma exclusively */
if (!(urb->transfer_flags & URB_NO_DMA_MAP)) {
if (usb_pipecontrol (urb->pipe))
- urb->setup_dma = pci_map_single (
- hcd->pdev,
+ urb->setup_dma = dma_map_single (
+ hcd->controller,
urb->setup_packet,
sizeof (struct usb_ctrlrequest),
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
if (urb->transfer_buffer_length != 0)
- urb->transfer_dma = pci_map_single (
- hcd->pdev,
+ urb->transfer_dma = dma_map_single (
+ hcd->controller,
urb->transfer_buffer,
urb->transfer_buffer_length,
usb_pipein (urb->pipe)
- ? PCI_DMA_FROMDEVICE
- : PCI_DMA_TODEVICE);
+ ? DMA_FROM_DEVICE
+ : DMA_TO_DEVICE);
}
status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
@@ -1265,12 +1265,6 @@
.deallocate = hcd_free_dev,
.buffer_alloc = hcd_buffer_alloc,
.buffer_free = hcd_buffer_free,
- .buffer_map = hcd_buffer_map,
- .buffer_dmasync = hcd_buffer_dmasync,
- .buffer_unmap = hcd_buffer_unmap,
- .buffer_map_sg = hcd_buffer_map_sg,
- .buffer_dmasync_sg = hcd_buffer_sync_sg,
- .buffer_unmap_sg = hcd_buffer_unmap_sg,
};
EXPORT_SYMBOL (usb_hcd_operations);
--- ./drivers/usb-dist/host/ohci-sa1111.c Tue Dec 24 10:01:02 2002
+++ ./drivers/usb/host/ohci-sa1111.c Tue Dec 24 13:41:22 2002
@@ -176,7 +176,8 @@
hcd->irq = dev->irq[1];
hcd->regs = dev->mapbase;
hcd->pdev = SA1111_FAKE_PCIDEV;
- hcd->controller = &dev->dev;
+ hcd->self.controller = &dev->dev;
+ hcd->controller = hcd->self.controller;
retval = hcd_buffer_create (hcd);
if (retval != 0) {
--- ./drivers/usb-dist/host/ehci-hcd.c Tue Dec 24 10:01:02 2002
+++ ./drivers/usb/host/ehci-hcd.c Tue Dec 24 13:41:22 2002
@@ -405,9 +405,10 @@
* streaming mappings for I/O buffers, like pci_map_single(),
* can return segments above 4GB, if the device allows.
*
- * NOTE: layered drivers can't yet tell when we enable that,
- * so they can't pass this info along (like NETIF_F_HIGHDMA)
- * (or like Scsi_Host.highmem_io) ... usb_bus.flags?
+ * NOTE: the dma mask is visible through dma_supported(), so
+ * drivers can pass this info along ... like NETIF_F_HIGHDMA,
+ * Scsi_Host.highmem_io, and so forth. It's readonly to all
+ * host side drivers though.
*/
if (HCC_64BIT_ADDR (hcc_params)) {
writel (0, &ehci->regs->segment);
--- ./drivers/usb-dist/net/usbnet.c Tue Dec 24 10:00:59 2002
+++ ./drivers/usb/net/usbnet.c Tue Dec 24 13:41:22 2002
@@ -146,6 +146,11 @@
#endif
#include <linux/usb.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+
/* minidrivers _could_ be individually configured */
#define CONFIG_USB_AN2720
@@ -2169,9 +2174,13 @@
memcpy (net->dev_addr, node_id, sizeof node_id);
// point-to-point link ... we always use Ethernet headers
- // supports win32 interop and the bridge driver.
+ // supports win32 interop (some devices) and the bridge driver.
ether_setup (net);
+ // possible with some EHCI controllers
+ if (dma_supported (&udev->dev, 0xffffffffffffffffULL))
+ net->features |= NETIF_F_HIGHDMA;
+
net->change_mtu = usbnet_change_mtu;
net->get_stats = usbnet_get_stats;
net->hard_start_xmit = usbnet_start_xmit;
--- ./Documentation-dist/usb/dma.txt Wed Dec 31 16:00:00 1969
+++ ./Documentation/usb/dma.txt Tue Dec 24 13:41:22 2002
@@ -0,0 +1,104 @@
+In Linux 2.5 kernels (and later), USB device drivers have additional control
+over how DMA may be used to perform I/O operations. The APIs are detailed
+in the kernel usb programming guide (kerneldoc, from the source code).
+
+
+API OVERVIEW
+
+The big picture is that USB drivers can continue to ignore most DMA issues,
+though they still must provide DMA-ready buffers (see DMA-mapping.txt).
+That's how they've worked through the 2.4 (and earlier) kernels.
+
+OR: they can now be DMA-aware.
+
+- New calls enable DMA-aware drivers, letting them allocate dma buffers and
+ manage dma mappings for existing dma-ready buffers (see below).
+
+- URBs have an additional "transfer_dma" field, as well as a transfer_flags
+ bit saying if it's valid. (Control requests also needed "setup_dma".)
+
+- "usbcore" will map those DMA addresses, if a DMA-aware driver didn't do it
+ first and set URB_NO_DMA_MAP. HCDs don't manage dma mappings for urbs.
+
+- There's a new "generic DMA API", parts of which are usable by USB device
+ drivers. Never use dma_set_mask() on any USB interface or device; that
+ would potentially break all devices sharing that bus.
+
+
+ELIMINATING COPIES
+
+It's good to avoid making CPUs copy data needlessly. The costs can add up,
+and effects like cache-trashing can impose subtle penalties.
+
+- When you're allocating a buffer for DMA purposes anyway, use the buffer
+ primitives. Think of them as kmalloc and kfree that give you the right
+ kind of addresses to store in urb->transfer_buffer and urb->transfer_dma,
+ while guaranteeing that hidden copies through DMA "bounce" buffers won't
+ slow things down. You'd also set URB_NO_DMA_MAP in urb->transfer_flags:
+
+ void *usb_buffer_alloc (struct usb_device *dev, size_t size,
+ int mem_flags, dma_addr_t *dma);
+
+ void usb_buffer_free (struct usb_device *dev, size_t size,
+ void *addr, dma_addr_t dma);
+
+ The memory buffer returned is "dma-coherent"; sometimes you might need to
+ force a consistent memory access ordering by using memory barriers. It's
+ not using a streaming DMA mapping, so it's good for small transfers on
+ systems where the I/O would otherwise tie up an IOMMU mapping.
+
+ Asking for 1/Nth of a page (as well as asking for N pages) is reasonably
+ space-efficient.
+
+- Devices on some EHCI controllers could handle DMA to/from high memory.
+ Driver probe() routines can notice this using a generic DMA call, then
+ tell higher level code (network, scsi, etc) about it like this:
+
+ if (dma_supported (&intf->dev, 0xffffffffffffffffULL))
+ net->features |= NETIF_F_HIGHDMA;
+
+ That can eliminate dma bounce buffering of requests that originate (or
+ terminate) in high memory, in cases where the buffers aren't allocated
+ with usb_buffer_alloc() but instead are dma-mapped.
+
+
+WORKING WITH EXISTING BUFFERS
+
+Existing buffers aren't usable for DMA without first being mapped into the
+DMA address space of the device.
+
+- When you're using scatterlists, you can map everything at once. On some
+ systems, this kicks in an IOMMU and turns the scatterlists into single
+ DMA transactions:
+
+ int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
+ struct scatterlist *sg, int nents);
+
+ void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
+ struct scatterlist *sg, int n_hw_ents);
+
+ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
+ struct scatterlist *sg, int n_hw_ents);
+
+ It's probably easier to use the new usb_sg_*() calls, which do the DMA
+ mapping and apply other tweaks to make scatterlist i/o be fast.
+
+- Some drivers may prefer to work with the model that they're mapping large
+ buffers, synchronizing their safe re-use. (If there's no re-use, then let
+ usbcore do the map/unmap.) Large periodic transfers make good examples
+ here, since it's cheaper to just synchronize the buffer than to unmap it
+ each time an urb completes and then re-map it on during resubmission.
+
+ These calls all work with initialized urbs: urb->dev, urb->pipe,
+ urb->transfer_buffer, and urb->transfer_buffer_length must all be
+ valid when these calls are used:
+
+ struct urb *usb_buffer_map (struct urb *urb);
+
+ void usb_buffer_dmasync (struct urb *urb);
+
+ void usb_buffer_unmap (struct urb *urb);
+
+ The calls manage urb->transfer_dma for you, and set URB_NO_DMA_MAP so that
+ usbcore won't map or unmap the buffer.
+