Commit 5b653c79 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

USB: add urb->ep

This patch (as943) prepares the way for eliminating urb->pipe by
introducing an endpoint pointer into struct urb.  For now urb->ep
is set by usb_submit_urb() from the pipe value; eventually drivers
will set it themselves and we will remove urb->pipe completely.

The patch also adds new inline routines to retrieve an endpoint
descriptor's number and transfer type, essentially as replacements for
usb_pipeendpoint and usb_pipetype.

usb_submit_urb(), usb_hcd_submit_urb(), and usb_hcd_unlink_urb() are
converted to use the new field and new routines.  Other parts of
usbcore will be converted in later patches.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent a96173af
...@@ -962,14 +962,14 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) ...@@ -962,14 +962,14 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
spin_lock_irqsave(&hcd_urb_list_lock, flags); spin_lock_irqsave(&hcd_urb_list_lock, flags);
ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
[usb_pipeendpoint(urb->pipe)]; [usb_pipeendpoint(urb->pipe)];
if (unlikely (!ep)) if (unlikely(ep != urb->ep))
status = -ENOENT; status = -ENOENT;
else if (unlikely (urb->reject)) else if (unlikely (urb->reject))
status = -EPERM; status = -EPERM;
else switch (hcd->state) { else switch (hcd->state) {
case HC_STATE_RUNNING: case HC_STATE_RUNNING:
case HC_STATE_RESUMING: case HC_STATE_RESUMING:
list_add_tail (&urb->urb_list, &ep->urb_list); list_add_tail (&urb->urb_list, &urb->ep->urb_list);
status = 0; status = 0;
break; break;
default: default:
...@@ -1022,7 +1022,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) ...@@ -1022,7 +1022,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
: DMA_TO_DEVICE); : DMA_TO_DEVICE);
} }
status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags); status = hcd->driver->urb_enqueue (hcd, urb->ep, urb, mem_flags);
done: done:
if (unlikely (status)) { if (unlikely (status)) {
urb_unlink(hcd, urb); urb_unlink(hcd, urb);
...@@ -1071,7 +1071,6 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb) ...@@ -1071,7 +1071,6 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
*/ */
int usb_hcd_unlink_urb (struct urb *urb, int status) int usb_hcd_unlink_urb (struct urb *urb, int status)
{ {
struct usb_host_endpoint *ep;
struct usb_hcd *hcd = NULL; struct usb_hcd *hcd = NULL;
struct device *sys = NULL; struct device *sys = NULL;
unsigned long flags; unsigned long flags;
...@@ -1082,10 +1081,6 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) ...@@ -1082,10 +1081,6 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
return -EINVAL; return -EINVAL;
if (!urb->dev || !urb->dev->bus) if (!urb->dev || !urb->dev->bus)
return -ENODEV; return -ENODEV;
ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
[usb_pipeendpoint(urb->pipe)];
if (!ep)
return -ENODEV;
/* /*
* we contend for urb->status with the hcd core, * we contend for urb->status with the hcd core,
...@@ -1109,7 +1104,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) ...@@ -1109,7 +1104,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
} }
/* insist the urb is still queued */ /* insist the urb is still queued */
list_for_each(tmp, &ep->urb_list) { list_for_each(tmp, &urb->ep->urb_list) {
if (tmp == &urb->urb_list) if (tmp == &urb->urb_list)
break; break;
} }
......
...@@ -277,8 +277,9 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); ...@@ -277,8 +277,9 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
*/ */
int usb_submit_urb(struct urb *urb, gfp_t mem_flags) int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{ {
int pipe, temp, max; int xfertype, max;
struct usb_device *dev; struct usb_device *dev;
struct usb_host_endpoint *ep;
int is_out; int is_out;
if (!urb || urb->hcpriv || !urb->complete) if (!urb || urb->hcpriv || !urb->complete)
...@@ -291,30 +292,34 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) ...@@ -291,30 +292,34 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|| dev->state == USB_STATE_SUSPENDED) || dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH; return -EHOSTUNREACH;
/* For now, get the endpoint from the pipe. Eventually drivers
* will be required to set urb->ep directly and we will eliminate
* urb->pipe.
*/
ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
[usb_pipeendpoint(urb->pipe)];
if (!ep)
return -ENOENT;
urb->ep = ep;
urb->status = -EINPROGRESS; urb->status = -EINPROGRESS;
urb->actual_length = 0; urb->actual_length = 0;
/* Lots of sanity checks, so HCDs can rely on clean data /* Lots of sanity checks, so HCDs can rely on clean data
* and don't need to duplicate tests * and don't need to duplicate tests
*/ */
pipe = urb->pipe; xfertype = usb_endpoint_type(&ep->desc);
temp = usb_pipetype(pipe); is_out = usb_pipeout(urb->pipe);
is_out = usb_pipeout(pipe);
if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED) if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
dev->state < USB_STATE_CONFIGURED)
return -ENODEV; return -ENODEV;
/* FIXME there should be a sharable lock protecting us against max = le16_to_cpu(ep->desc.wMaxPacketSize);
* config/altsetting changes and disconnects, kicking in here.
* (here == before maxpacket, and eventually endpoint type,
* checks get made.)
*/
max = usb_maxpacket(dev, pipe, is_out);
if (max <= 0) { if (max <= 0) {
dev_dbg(&dev->dev, dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
usb_pipeendpoint(pipe), is_out ? "out" : "in", usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
__FUNCTION__, max); __FUNCTION__, max);
return -EMSGSIZE; return -EMSGSIZE;
} }
...@@ -323,7 +328,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) ...@@ -323,7 +328,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* but drivers only control those sizes for ISO. * but drivers only control those sizes for ISO.
* while we're checking, initialize return status. * while we're checking, initialize return status.
*/ */
if (temp == PIPE_ISOCHRONOUS) { if (xfertype == USB_ENDPOINT_XFER_ISOC) {
int n, len; int n, len;
/* "high bandwidth" mode, 1-3 packets/uframe? */ /* "high bandwidth" mode, 1-3 packets/uframe? */
...@@ -359,19 +364,19 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) ...@@ -359,19 +364,19 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
/* enforce simple/standard policy */ /* enforce simple/standard policy */
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
URB_NO_INTERRUPT); URB_NO_INTERRUPT);
switch (temp) { switch (xfertype) {
case PIPE_BULK: case USB_ENDPOINT_XFER_BULK:
if (is_out) if (is_out)
allowed |= URB_ZERO_PACKET; allowed |= URB_ZERO_PACKET;
/* FALLTHROUGH */ /* FALLTHROUGH */
case PIPE_CONTROL: case USB_ENDPOINT_XFER_CONTROL:
allowed |= URB_NO_FSBR; /* only affects UHCI */ allowed |= URB_NO_FSBR; /* only affects UHCI */
/* FALLTHROUGH */ /* FALLTHROUGH */
default: /* all non-iso endpoints */ default: /* all non-iso endpoints */
if (!is_out) if (!is_out)
allowed |= URB_SHORT_NOT_OK; allowed |= URB_SHORT_NOT_OK;
break; break;
case PIPE_ISOCHRONOUS: case USB_ENDPOINT_XFER_ISOC:
allowed |= URB_ISO_ASAP; allowed |= URB_ISO_ASAP;
break; break;
} }
...@@ -393,9 +398,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) ...@@ -393,9 +398,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* supports different values... this uses EHCI/UHCI defaults (and * supports different values... this uses EHCI/UHCI defaults (and
* EHCI can use smaller non-default values). * EHCI can use smaller non-default values).
*/ */
switch (temp) { switch (xfertype) {
case PIPE_ISOCHRONOUS: case USB_ENDPOINT_XFER_ISOC:
case PIPE_INTERRUPT: case USB_ENDPOINT_XFER_INT:
/* too small? */ /* too small? */
if (urb->interval <= 0) if (urb->interval <= 0)
return -EINVAL; return -EINVAL;
...@@ -405,29 +410,29 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) ...@@ -405,29 +410,29 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
// NOTE usb handles 2^15 // NOTE usb handles 2^15
if (urb->interval > (1024 * 8)) if (urb->interval > (1024 * 8))
urb->interval = 1024 * 8; urb->interval = 1024 * 8;
temp = 1024 * 8; max = 1024 * 8;
break; break;
case USB_SPEED_FULL: /* units are frames/msec */ case USB_SPEED_FULL: /* units are frames/msec */
case USB_SPEED_LOW: case USB_SPEED_LOW:
if (temp == PIPE_INTERRUPT) { if (xfertype == USB_ENDPOINT_XFER_INT) {
if (urb->interval > 255) if (urb->interval > 255)
return -EINVAL; return -EINVAL;
// NOTE ohci only handles up to 32 // NOTE ohci only handles up to 32
temp = 128; max = 128;
} else { } else {
if (urb->interval > 1024) if (urb->interval > 1024)
urb->interval = 1024; urb->interval = 1024;
// NOTE usb and ohci handle up to 2^15 // NOTE usb and ohci handle up to 2^15
temp = 1024; max = 1024;
} }
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
/* power of two? */ /* power of two? */
while (temp > urb->interval) while (max > urb->interval)
temp >>= 1; max >>= 1;
urb->interval = temp; urb->interval = max;
} }
return usb_hcd_submit_urb(urb, mem_flags); return usb_hcd_submit_urb(urb, mem_flags);
......
...@@ -554,6 +554,29 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, ...@@ -554,6 +554,29 @@ static inline int usb_make_path (struct usb_device *dev, char *buf,
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/**
* usb_endpoint_num - get the endpoint's number
* @epd: endpoint to be checked
*
* Returns @epd's number: 0 to 15.
*/
static inline int usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
{
return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
}
/**
* usb_endpoint_type - get the endpoint's transfer type
* @epd: endpoint to be checked
*
* Returns one of USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT} according
* to @epd's transfer type.
*/
static inline int usb_endpoint_type(const struct usb_endpoint_descriptor *epd)
{
return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
}
/** /**
* usb_endpoint_dir_in - check if the endpoint has IN direction * usb_endpoint_dir_in - check if the endpoint has IN direction
* @epd: endpoint to be checked * @epd: endpoint to be checked
...@@ -1037,6 +1060,8 @@ typedef void (*usb_complete_t)(struct urb *); ...@@ -1037,6 +1060,8 @@ typedef void (*usb_complete_t)(struct urb *);
* @urb_list: For use by current owner of the URB. * @urb_list: For use by current owner of the URB.
* @anchor_list: membership in the list of an anchor * @anchor_list: membership in the list of an anchor
* @anchor: to anchor URBs to a common mooring * @anchor: to anchor URBs to a common mooring
* @ep: Points to the endpoint's data structure. Will eventually
* replace @pipe.
* @pipe: Holds endpoint number, direction, type, and more. * @pipe: Holds endpoint number, direction, type, and more.
* Create these values with the eight macros available; * Create these values with the eight macros available;
* usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl" * usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl"
...@@ -1212,6 +1237,7 @@ struct urb ...@@ -1212,6 +1237,7 @@ struct urb
struct list_head anchor_list; /* the URB may be anchored by the driver */ struct list_head anchor_list; /* the URB may be anchored by the driver */
struct usb_anchor *anchor; struct usb_anchor *anchor;
struct usb_device *dev; /* (in) pointer to associated device */ struct usb_device *dev; /* (in) pointer to associated device */
struct usb_host_endpoint *ep; /* (internal) pointer to endpoint struct */
unsigned int pipe; /* (in) pipe information */ unsigned int pipe; /* (in) pipe information */
int status; /* (return) non-ISO status */ int status; /* (return) non-ISO status */
unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/ unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment