USB: add ep->enable

This patch (as944) adds an explicit "enabled" field to the
usb_host_endpoint structure and uses it in place of the current
mechanism.  This is merely a time-space tradeoff; it makes checking
whether URBs may be submitted to an endpoint simpler.  The existing
mechanism is efficient when converting urb->pipe to an endpoint
pointer, but it's not so efficient when urb->ep is used instead.

As a side effect, the procedure for enabling an endpoint is now a
little more complicated.  The ad-hoc inline code in usb.c and hub.c
for enabling ep0 is now replaced with calls to usb_enable_endpoint,
which is no longer static.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index fb82c50..cc5b1d3 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -943,7 +943,6 @@
 {
 	int			status;
 	struct usb_hcd		*hcd = bus_to_hcd(urb->dev->bus);
-	struct usb_host_endpoint *ep;
 	unsigned long		flags;
 
 	if (!hcd)
@@ -960,9 +959,7 @@
 	// FIXME:  verify that quiescing hc works right (RH cleans up)
 
 	spin_lock_irqsave(&hcd_urb_list_lock, flags);
-	ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
-			[usb_pipeendpoint(urb->pipe)];
-	if (unlikely(ep != urb->ep))
+	if (unlikely(!urb->ep->enabled))
 		status = -ENOENT;
 	else if (unlikely (urb->reject))
 		status = -EPERM;
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index f7b337f..c8a01f6 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1999,7 +1999,7 @@
 {
 	usb_disable_endpoint(udev, 0 + USB_DIR_IN);
 	usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
-	udev->ep_in[0] = udev->ep_out[0] = &udev->ep0;
+	usb_enable_endpoint(udev, &udev->ep0);
 }
 
 #define usb_sndaddr0pipe()	(PIPE_CONTROL << 30)
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index d8f7b08..0d61864 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1013,8 +1013,10 @@
 		ep = dev->ep_in[epnum];
 		dev->ep_in[epnum] = NULL;
 	}
-	if (ep && dev->bus)
+	if (ep) {
+		ep->enabled = 0;
 		usb_hcd_endpoint_disable(dev, ep);
+	}
 }
 
 /**
@@ -1096,23 +1098,21 @@
  * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers.
  * For control endpoints, both the input and output sides are handled.
  */
-static void
-usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
+void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
 {
-	unsigned int epaddr = ep->desc.bEndpointAddress;
-	unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
-	int is_control;
+	int epnum = usb_endpoint_num(&ep->desc);
+	int is_out = usb_endpoint_dir_out(&ep->desc);
+	int is_control = usb_endpoint_xfer_control(&ep->desc);
 
-	is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-			== USB_ENDPOINT_XFER_CONTROL);
-	if (usb_endpoint_out(epaddr) || is_control) {
+	if (is_out || is_control) {
 		usb_settoggle(dev, epnum, 1, 0);
 		dev->ep_out[epnum] = ep;
 	}
-	if (!usb_endpoint_out(epaddr) || is_control) {
+	if (!is_out || is_control) {
 		usb_settoggle(dev, epnum, 0, 0);
 		dev->ep_in[epnum] = ep;
 	}
+	ep->enabled = 1;
 }
 
 /*
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 0fee5c6..d3c68d8 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -260,7 +260,7 @@
 	dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
 	dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
 	/* ep0 maxpacket comes later, from device descriptor */
-	dev->ep_in[0] = dev->ep_out[0] = &dev->ep0;
+	usb_enable_endpoint(dev, &dev->ep0);
 
 	/* Save readable and stable topology id, distinguishing devices
 	 * by location for diagnostics, tools, driver model, etc.  The
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index ad5fa03..cde6e52 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -8,6 +8,8 @@
 				struct usb_device *udev);
 extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
 
+extern void usb_enable_endpoint(struct usb_device *dev,
+		struct usb_host_endpoint *ep);
 extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
 extern void usb_disable_interface (struct usb_device *dev,
 		struct usb_interface *intf);