diff options
author | Robert Morell <rmorell@nvidia.com> | 2011-01-26 22:06:48 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-02-04 14:48:55 -0500 |
commit | 2694a48d9007a8bdf1731c1b97d4942c9cc49296 (patch) | |
tree | 9f5394c7aca54d6ee0565428e91c12f240be89bd | |
parent | c8cf203a1d228fa001b95534f639ffb7a23d5386 (diff) |
USB: HCD: Add driver hooks for (un)?map_urb_for_dma
Provide optional hooks for the host controller driver to override the
default DMA mapping and unmapping routines. In general, these shouldn't
be necessary unless the host controller has special DMA requirements,
such as alignment contraints. If these are not specified, the
general usb_hcd_(un)?map_urb_for_dma functions will be used instead.
Also, pass the status to unmap_urb_for_dma so it can know whether the
DMA buffer has been overwritten.
Finally, add a flag to be used by these implementations if they
allocated a temporary buffer so it can be freed properly when unmapping.
Signed-off-by: Robert Morell <rmorell@nvidia.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/core/hcd.c | 22 | ||||
-rw-r--r-- | include/linux/usb.h | 1 | ||||
-rw-r--r-- | include/linux/usb/hcd.h | 15 |
3 files changed, 36 insertions, 2 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 335c1ddb260d..d0b782c4523a 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -1281,6 +1281,14 @@ void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *hcd, struct urb *urb) | |||
1281 | } | 1281 | } |
1282 | EXPORT_SYMBOL_GPL(usb_hcd_unmap_urb_setup_for_dma); | 1282 | EXPORT_SYMBOL_GPL(usb_hcd_unmap_urb_setup_for_dma); |
1283 | 1283 | ||
1284 | static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) | ||
1285 | { | ||
1286 | if (hcd->driver->unmap_urb_for_dma) | ||
1287 | hcd->driver->unmap_urb_for_dma(hcd, urb); | ||
1288 | else | ||
1289 | usb_hcd_unmap_urb_for_dma(hcd, urb); | ||
1290 | } | ||
1291 | |||
1284 | void usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) | 1292 | void usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) |
1285 | { | 1293 | { |
1286 | enum dma_data_direction dir; | 1294 | enum dma_data_direction dir; |
@@ -1319,6 +1327,15 @@ EXPORT_SYMBOL_GPL(usb_hcd_unmap_urb_for_dma); | |||
1319 | static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, | 1327 | static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, |
1320 | gfp_t mem_flags) | 1328 | gfp_t mem_flags) |
1321 | { | 1329 | { |
1330 | if (hcd->driver->map_urb_for_dma) | ||
1331 | return hcd->driver->map_urb_for_dma(hcd, urb, mem_flags); | ||
1332 | else | ||
1333 | return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); | ||
1334 | } | ||
1335 | |||
1336 | int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, | ||
1337 | gfp_t mem_flags) | ||
1338 | { | ||
1322 | enum dma_data_direction dir; | 1339 | enum dma_data_direction dir; |
1323 | int ret = 0; | 1340 | int ret = 0; |
1324 | 1341 | ||
@@ -1414,6 +1431,7 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, | |||
1414 | } | 1431 | } |
1415 | return ret; | 1432 | return ret; |
1416 | } | 1433 | } |
1434 | EXPORT_SYMBOL_GPL(usb_hcd_map_urb_for_dma); | ||
1417 | 1435 | ||
1418 | /*-------------------------------------------------------------------------*/ | 1436 | /*-------------------------------------------------------------------------*/ |
1419 | 1437 | ||
@@ -1451,7 +1469,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) | |||
1451 | if (likely(status == 0)) { | 1469 | if (likely(status == 0)) { |
1452 | status = hcd->driver->urb_enqueue(hcd, urb, mem_flags); | 1470 | status = hcd->driver->urb_enqueue(hcd, urb, mem_flags); |
1453 | if (unlikely(status)) | 1471 | if (unlikely(status)) |
1454 | usb_hcd_unmap_urb_for_dma(hcd, urb); | 1472 | unmap_urb_for_dma(hcd, urb); |
1455 | } | 1473 | } |
1456 | } | 1474 | } |
1457 | 1475 | ||
@@ -1557,7 +1575,7 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) | |||
1557 | !status)) | 1575 | !status)) |
1558 | status = -EREMOTEIO; | 1576 | status = -EREMOTEIO; |
1559 | 1577 | ||
1560 | usb_hcd_unmap_urb_for_dma(hcd, urb); | 1578 | unmap_urb_for_dma(hcd, urb); |
1561 | usbmon_urb_complete(&hcd->self, urb, status); | 1579 | usbmon_urb_complete(&hcd->self, urb, status); |
1562 | usb_unanchor_urb(urb); | 1580 | usb_unanchor_urb(urb); |
1563 | 1581 | ||
diff --git a/include/linux/usb.h b/include/linux/usb.h index bd69b65f3356..e63efeb378e3 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h | |||
@@ -976,6 +976,7 @@ extern int usb_disabled(void); | |||
976 | #define URB_SETUP_MAP_SINGLE 0x00100000 /* Setup packet DMA mapped */ | 976 | #define URB_SETUP_MAP_SINGLE 0x00100000 /* Setup packet DMA mapped */ |
977 | #define URB_SETUP_MAP_LOCAL 0x00200000 /* HCD-local setup packet */ | 977 | #define URB_SETUP_MAP_LOCAL 0x00200000 /* HCD-local setup packet */ |
978 | #define URB_DMA_SG_COMBINED 0x00400000 /* S-G entries were combined */ | 978 | #define URB_DMA_SG_COMBINED 0x00400000 /* S-G entries were combined */ |
979 | #define URB_ALIGNED_TEMP_BUFFER 0x00800000 /* Temp buffer was alloc'd */ | ||
979 | 980 | ||
980 | struct usb_iso_packet_descriptor { | 981 | struct usb_iso_packet_descriptor { |
981 | unsigned int offset; | 982 | unsigned int offset; |
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 395704bdf5cc..92b96fe39307 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h | |||
@@ -233,6 +233,19 @@ struct hc_driver { | |||
233 | int (*urb_dequeue)(struct usb_hcd *hcd, | 233 | int (*urb_dequeue)(struct usb_hcd *hcd, |
234 | struct urb *urb, int status); | 234 | struct urb *urb, int status); |
235 | 235 | ||
236 | /* | ||
237 | * (optional) these hooks allow an HCD to override the default DMA | ||
238 | * mapping and unmapping routines. In general, they shouldn't be | ||
239 | * necessary unless the host controller has special DMA requirements, | ||
240 | * such as alignment contraints. If these are not specified, the | ||
241 | * general usb_hcd_(un)?map_urb_for_dma functions will be used instead | ||
242 | * (and it may be a good idea to call these functions in your HCD | ||
243 | * implementation) | ||
244 | */ | ||
245 | int (*map_urb_for_dma)(struct usb_hcd *hcd, struct urb *urb, | ||
246 | gfp_t mem_flags); | ||
247 | void (*unmap_urb_for_dma)(struct usb_hcd *hcd, struct urb *urb); | ||
248 | |||
236 | /* hw synch, freeing endpoint resources that urb_dequeue can't */ | 249 | /* hw synch, freeing endpoint resources that urb_dequeue can't */ |
237 | void (*endpoint_disable)(struct usb_hcd *hcd, | 250 | void (*endpoint_disable)(struct usb_hcd *hcd, |
238 | struct usb_host_endpoint *ep); | 251 | struct usb_host_endpoint *ep); |
@@ -329,6 +342,8 @@ extern int usb_hcd_submit_urb(struct urb *urb, gfp_t mem_flags); | |||
329 | extern int usb_hcd_unlink_urb(struct urb *urb, int status); | 342 | extern int usb_hcd_unlink_urb(struct urb *urb, int status); |
330 | extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, | 343 | extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, |
331 | int status); | 344 | int status); |
345 | extern int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, | ||
346 | gfp_t mem_flags); | ||
332 | extern void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *, struct urb *); | 347 | extern void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *, struct urb *); |
333 | extern void usb_hcd_unmap_urb_for_dma(struct usb_hcd *, struct urb *); | 348 | extern void usb_hcd_unmap_urb_for_dma(struct usb_hcd *, struct urb *); |
334 | extern void usb_hcd_flush_endpoint(struct usb_device *udev, | 349 | extern void usb_hcd_flush_endpoint(struct usb_device *udev, |