diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2007-07-30 17:06:16 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-10-12 17:55:00 -0400 |
commit | fea3409112a93581db18da4c4332c8bf8d68af6b (patch) | |
tree | c89b9fd9f8a64d2419d7888a6ab135851f4fee38 | |
parent | bdd016ba64d909329cb4bacacc8443901c00e112 (diff) |
USB: add direction bit to urb->transfer_flags
This patch (as945) adds a bit to urb->transfer_flags for recording the
direction of the URB. The bit is set/cleared automatically in
usb_submit_urb() so drivers don't have to worry about it (although as
a result, it isn't valid until the URB has been submitted). Inline
routines are added for easily checking an URB's direction. They
replace calls to usb_pipein in the DMA-mapping parts of hcd.c.
For non-control endpoints, the direction is determined directly from
the endpoint descriptor. However control endpoints are
bi-directional; for them the direction is determined from the
bRequestType byte and the wLength value in the setup packet.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/core/hcd.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/urb.c | 18 | ||||
-rw-r--r-- | include/linux/usb.h | 30 |
3 files changed, 48 insertions, 4 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index cc5b1d3c3680..bcbaedc897d5 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -928,7 +928,7 @@ static void urb_unlink(struct usb_hcd *hcd, struct urb *urb) | |||
928 | dma_unmap_single (hcd->self.controller, | 928 | dma_unmap_single (hcd->self.controller, |
929 | urb->transfer_dma, | 929 | urb->transfer_dma, |
930 | urb->transfer_buffer_length, | 930 | urb->transfer_buffer_length, |
931 | usb_pipein (urb->pipe) | 931 | usb_urb_dir_in(urb) |
932 | ? DMA_FROM_DEVICE | 932 | ? DMA_FROM_DEVICE |
933 | : DMA_TO_DEVICE); | 933 | : DMA_TO_DEVICE); |
934 | } | 934 | } |
@@ -1014,7 +1014,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) | |||
1014 | hcd->self.controller, | 1014 | hcd->self.controller, |
1015 | urb->transfer_buffer, | 1015 | urb->transfer_buffer, |
1016 | urb->transfer_buffer_length, | 1016 | urb->transfer_buffer_length, |
1017 | usb_pipein (urb->pipe) | 1017 | usb_urb_dir_in(urb) |
1018 | ? DMA_FROM_DEVICE | 1018 | ? DMA_FROM_DEVICE |
1019 | : DMA_TO_DEVICE); | 1019 | : DMA_TO_DEVICE); |
1020 | } | 1020 | } |
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index ff53acb4fab2..1a64a6a850f3 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c | |||
@@ -309,7 +309,21 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) | |||
309 | * and don't need to duplicate tests | 309 | * and don't need to duplicate tests |
310 | */ | 310 | */ |
311 | xfertype = usb_endpoint_type(&ep->desc); | 311 | xfertype = usb_endpoint_type(&ep->desc); |
312 | is_out = usb_pipeout(urb->pipe); | 312 | if (xfertype == USB_ENDPOINT_XFER_CONTROL) { |
313 | struct usb_ctrlrequest *setup = | ||
314 | (struct usb_ctrlrequest *) urb->setup_packet; | ||
315 | |||
316 | if (!setup) | ||
317 | return -ENOEXEC; | ||
318 | is_out = !(setup->bRequestType & USB_DIR_IN) || | ||
319 | !setup->wLength; | ||
320 | } else { | ||
321 | is_out = usb_endpoint_dir_out(&ep->desc); | ||
322 | } | ||
323 | |||
324 | /* Cache the direction for later use */ | ||
325 | urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) | | ||
326 | (is_out ? URB_DIR_OUT : URB_DIR_IN); | ||
313 | 327 | ||
314 | if (xfertype != USB_ENDPOINT_XFER_CONTROL && | 328 | if (xfertype != USB_ENDPOINT_XFER_CONTROL && |
315 | dev->state < USB_STATE_CONFIGURED) | 329 | dev->state < USB_STATE_CONFIGURED) |
@@ -363,7 +377,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) | |||
363 | 377 | ||
364 | /* enforce simple/standard policy */ | 378 | /* enforce simple/standard policy */ |
365 | allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | | 379 | allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | |
366 | URB_NO_INTERRUPT); | 380 | URB_NO_INTERRUPT | URB_DIR_MASK); |
367 | switch (xfertype) { | 381 | switch (xfertype) { |
368 | case USB_ENDPOINT_XFER_BULK: | 382 | case USB_ENDPOINT_XFER_BULK: |
369 | if (is_out) | 383 | if (is_out) |
diff --git a/include/linux/usb.h b/include/linux/usb.h index 818a1b4f737a..9d08f5a5ba76 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h | |||
@@ -1021,6 +1021,8 @@ extern int usb_disabled(void); | |||
1021 | 1021 | ||
1022 | /* | 1022 | /* |
1023 | * urb->transfer_flags: | 1023 | * urb->transfer_flags: |
1024 | * | ||
1025 | * Note: URB_DIR_IN/OUT is automatically set in usb_submit_urb(). | ||
1024 | */ | 1026 | */ |
1025 | #define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */ | 1027 | #define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */ |
1026 | #define URB_ISO_ASAP 0x0002 /* iso-only, urb->start_frame | 1028 | #define URB_ISO_ASAP 0x0002 /* iso-only, urb->start_frame |
@@ -1033,6 +1035,10 @@ extern int usb_disabled(void); | |||
1033 | * needed */ | 1035 | * needed */ |
1034 | #define URB_FREE_BUFFER 0x0100 /* Free transfer buffer with the URB */ | 1036 | #define URB_FREE_BUFFER 0x0100 /* Free transfer buffer with the URB */ |
1035 | 1037 | ||
1038 | #define URB_DIR_IN 0x0200 /* Transfer from device to host */ | ||
1039 | #define URB_DIR_OUT 0 | ||
1040 | #define URB_DIR_MASK URB_DIR_IN | ||
1041 | |||
1036 | struct usb_iso_packet_descriptor { | 1042 | struct usb_iso_packet_descriptor { |
1037 | unsigned int offset; | 1043 | unsigned int offset; |
1038 | unsigned int length; /* expected length */ | 1044 | unsigned int length; /* expected length */ |
@@ -1380,6 +1386,30 @@ extern void usb_unanchor_urb(struct urb *urb); | |||
1380 | extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, | 1386 | extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, |
1381 | unsigned int timeout); | 1387 | unsigned int timeout); |
1382 | 1388 | ||
1389 | /** | ||
1390 | * usb_urb_dir_in - check if an URB describes an IN transfer | ||
1391 | * @urb: URB to be checked | ||
1392 | * | ||
1393 | * Returns 1 if @urb describes an IN transfer (device-to-host), | ||
1394 | * otherwise 0. | ||
1395 | */ | ||
1396 | static inline int usb_urb_dir_in(struct urb *urb) | ||
1397 | { | ||
1398 | return (urb->transfer_flags & URB_DIR_MASK) != URB_DIR_OUT; | ||
1399 | } | ||
1400 | |||
1401 | /** | ||
1402 | * usb_urb_dir_out - check if an URB describes an OUT transfer | ||
1403 | * @urb: URB to be checked | ||
1404 | * | ||
1405 | * Returns 1 if @urb describes an OUT transfer (host-to-device), | ||
1406 | * otherwise 0. | ||
1407 | */ | ||
1408 | static inline int usb_urb_dir_out(struct urb *urb) | ||
1409 | { | ||
1410 | return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT; | ||
1411 | } | ||
1412 | |||
1383 | void *usb_buffer_alloc (struct usb_device *dev, size_t size, | 1413 | void *usb_buffer_alloc (struct usb_device *dev, size_t size, |
1384 | gfp_t mem_flags, dma_addr_t *dma); | 1414 | gfp_t mem_flags, dma_addr_t *dma); |
1385 | void usb_buffer_free (struct usb_device *dev, size_t size, | 1415 | void usb_buffer_free (struct usb_device *dev, size_t size, |