Replace drivers/usb/gadget/epautoconf.c with the one from the Linux
kernel. Fixes will come later.

Signed-off-by: Jerome Forissier <[email protected]>
---

 drivers/usb/gadget/epautoconf.c | 291 +++++++++++++++-----------------
 1 file changed, 132 insertions(+), 159 deletions(-)

diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 495460473e9a..30016b805bfd 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -3,170 +3,120 @@
  * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers
  *
  * Copyright (C) 2004 David Brownell
- *
- * Ported to U-Boot by: Thomas Smits <[email protected]> and
- *                      Remy Bohmer <[email protected]>
  */
 
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/device.h>
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+
 #include <linux/usb/ch9.h>
-#include <linux/errno.h>
 #include <linux/usb/gadget.h>
-#include <asm/unaligned.h>
 
-#define isdigit(c)      ('0' <= (c) && (c) <= '9')
-
-/* we must assign addresses for configurable endpoints (like net2280) */
-static unsigned epnum;
-
-/* #define MANY_ENDPOINTS */
-#ifdef MANY_ENDPOINTS
-/* more than 15 configurable endpoints */
-static unsigned in_epnum;
-#endif
-
-/*
- * This should work with endpoints from controller drivers sharing the
- * same endpoint naming convention.  By example:
+/**
+ * usb_ep_autoconfig_ss() - choose an endpoint matching the ep
+ * descriptor and ep companion descriptor
+ * @gadget: The device to which the endpoint must belong.
+ * @desc: Endpoint descriptor, with endpoint direction and transfer mode
+ *    initialized.  For periodic transfers, the maximum packet
+ *    size must also be initialized.  This is modified on
+ *    success.
+ * @ep_comp: Endpoint companion descriptor, with the required
+ *    number of streams. Will be modified when the chosen EP
+ *    supports a different number of streams.
+ *
+ * This routine replaces the usb_ep_autoconfig when needed
+ * superspeed enhancments. If such enhancemnets are required,
+ * the FD should call usb_ep_autoconfig_ss directly and provide
+ * the additional ep_comp parameter.
+ *
+ * By choosing an endpoint to use with the specified descriptor,
+ * this routine simplifies writing gadget drivers that work with
+ * multiple USB device controllers.  The endpoint would be
+ * passed later to usb_ep_enable(), along with some descriptor.
+ *
+ * That second descriptor won't always be the same as the first one.
+ * For example, isochronous endpoints can be autoconfigured for high
+ * bandwidth, and then used in several lower bandwidth altsettings.
+ * Also, high and full speed descriptors will be different.
  *
- *     - ep1, ep2, ... address is fixed, not direction or type
- *     - ep1in, ep2out, ... address and direction are fixed, not type
- *     - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction
- *     - ep1in-bulk, ep2out-iso, ... all three are fixed
- *     - ep-* ... no functionality restrictions
+ * Be sure to examine and test the results of autoconfiguration
+ * on your hardware.  This code may not make the best choices
+ * about how to use the USB controller, and it can't know all
+ * the restrictions that may apply. Some combinations of driver
+ * and hardware won't be able to autoconfigure.
  *
- * Type suffixes are "-bulk", "-iso", or "-int".  Numbers are decimal.
- * Less common restrictions are implied by gadget_is_*().
+ * On success, this returns an claimed usb_ep, and modifies the endpoint
+ * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
+ * is initialized as if the endpoint were used at full speed and
+ * the bmAttribute field in the ep companion descriptor is
+ * updated with the assigned number of streams if it is
+ * different from the original value. To prevent the endpoint
+ * from being returned by a later autoconfig call, claims it by
+ * assigning ep->claimed to true.
  *
- * NOTE:  each endpoint is unidirectional, as specified by its USB
- * descriptor; and isn't specific to a configuration or altsetting.
+ * On failure, this returns a null endpoint descriptor.
  */
-static int ep_matches(
+struct usb_ep *usb_ep_autoconfig_ss(
        struct usb_gadget               *gadget,
-       struct usb_ep                   *ep,
-       struct usb_endpoint_descriptor  *desc
+       struct usb_endpoint_descriptor  *desc,
+       struct usb_ss_ep_comp_descriptor *ep_comp
 )
 {
-       u8              type;
-       const char      *tmp;
-       u16             max;
+       struct usb_ep   *ep;
 
-       /* endpoint already claimed? */
-       if (NULL != ep->driver_data)
-               return 0;
-
-       /* only support ep0 for portable CONTROL traffic */
-       type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
-       if (USB_ENDPOINT_XFER_CONTROL == type)
-               return 0;
-
-       /* some other naming convention */
-       if ('e' != ep->name[0])
-               return 0;
-
-       /* type-restriction:  "-iso", "-bulk", or "-int".
-        * direction-restriction:  "in", "out".
-        */
-       if ('-' != ep->name[2]) {
-               tmp = strrchr(ep->name, '-');
-               if (tmp) {
-                       switch (type) {
-                       case USB_ENDPOINT_XFER_INT:
-                               /* bulk endpoints handle interrupt transfers,
-                                * except the toggle-quirky iso-synch kind
-                                */
-                               if ('s' == tmp[2])      /* == "-iso" */
-                                       return 0;
-                               break;
-                       case USB_ENDPOINT_XFER_BULK:
-                               if ('b' != tmp[1])      /* != "-bulk" */
-                                       return 0;
-                               break;
-                       case USB_ENDPOINT_XFER_ISOC:
-                               if ('s' != tmp[2])      /* != "-iso" */
-                                       return 0;
-                       }
-               } else {
-                       tmp = ep->name + strlen(ep->name);
-               }
-
-               /* direction-restriction:  "..in-..", "out-.." */
-               tmp--;
-               if (!isdigit(*tmp)) {
-                       if (desc->bEndpointAddress & USB_DIR_IN) {
-                               if ('n' != *tmp)
-                                       return 0;
-                       } else {
-                               if ('t' != *tmp)
-                                       return 0;
-                       }
-               }
+       if (gadget->ops->match_ep) {
+               ep = gadget->ops->match_ep(gadget, desc, ep_comp);
+               if (ep)
+                       goto found_ep;
        }
 
-       /* endpoint maxpacket size is an input parameter, except for bulk
-        * where it's an output parameter representing the full speed limit.
-        * the usb spec fixes high speed bulk maxpacket at 512 bytes.
-        */
-       max = 0x7ff & le16_to_cpu(get_unaligned(&desc->wMaxPacketSize));
-       switch (type) {
-       case USB_ENDPOINT_XFER_INT:
-               /* INT:  limit 64 bytes full speed, 1024 high speed */
-               if (!gadget->is_dualspeed && max > 64)
-                       return 0;
-               /* FALLTHROUGH */
-
-       case USB_ENDPOINT_XFER_ISOC:
-               /* ISO:  limit 1023 bytes full speed, 1024 high speed */
-               if (ep->maxpacket < max)
-                       return 0;
-               if (!gadget->is_dualspeed && max > 1023)
-                       return 0;
-
-               /* BOTH:  "high bandwidth" works only at high speed */
-               if ((get_unaligned(&desc->wMaxPacketSize) &
-                                       __constant_cpu_to_le16(3<<11))) {
-                       if (!gadget->is_dualspeed)
-                               return 0;
-                       /* configure your hardware with enough buffering!! */
-               }
-               break;
+       /* Second, look at endpoints until an unclaimed one looks usable */
+       list_for_each_entry (ep, &gadget->ep_list, ep_list) {
+               if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp))
+                       goto found_ep;
        }
 
-       /* MATCH!! */
+       /* Fail */
+       return NULL;
+found_ep:
+
+       /*
+        * If the protocol driver hasn't yet decided on wMaxPacketSize
+        * and wants to know the maximum possible, provide the info.
+        */
+       if (desc->wMaxPacketSize == 0)
+               desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket_limit);
 
        /* report address */
+       desc->bEndpointAddress &= USB_DIR_IN;
        if (isdigit(ep->name[2])) {
-               u8      num = dectoul(&ep->name[2], NULL);
+               u8 num = simple_strtoul(&ep->name[2], NULL, 10);
                desc->bEndpointAddress |= num;
-#ifdef MANY_ENDPOINTS
        } else if (desc->bEndpointAddress & USB_DIR_IN) {
-               if (++in_epnum > 15)
-                       return 0;
-               desc->bEndpointAddress = USB_DIR_IN | in_epnum;
-#endif
+               if (++gadget->in_epnum > 15)
+                       return NULL;
+               desc->bEndpointAddress = USB_DIR_IN | gadget->in_epnum;
        } else {
-               if (++epnum > 15)
-                       return 0;
-               desc->bEndpointAddress |= epnum;
+               if (++gadget->out_epnum > 15)
+                       return NULL;
+               desc->bEndpointAddress |= gadget->out_epnum;
        }
 
-       /* report (variable) full speed bulk maxpacket */
-       if (USB_ENDPOINT_XFER_BULK == type) {
-               int size = ep->maxpacket;
-
-               /* min() doesn't work on bitfields with gcc-3.5 */
-               if (size > 64)
-                       size = 64;
-               put_unaligned(cpu_to_le16(size), &desc->wMaxPacketSize);
-       }
-
-       if (gadget->ops->ep_conf)
-               return gadget->ops->ep_conf(gadget, ep, desc);
-
-       return 1;
+       ep->address = desc->bEndpointAddress;
+       ep->desc = NULL;
+       ep->comp_desc = NULL;
+       ep->claimed = true;
+       return ep;
 }
+EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss);
 
 /**
- * usb_ep_autoconfig - choose an endpoint matching the descriptor
+ * usb_ep_autoconfig() - choose an endpoint matching the
+ * descriptor
  * @gadget: The device to which the endpoint must belong.
  * @desc: Endpoint descriptor, with endpoint direction and transfer mode
  *     initialized.  For periodic transfers, the maximum packet
@@ -187,11 +137,12 @@ static int ep_matches(
  * USB controller, and it can't know all the restrictions that may apply.
  * Some combinations of driver and hardware won't be able to autoconfigure.
  *
- * On success, this returns an un-claimed usb_ep, and modifies the endpoint
+ * On success, this returns an claimed usb_ep, and modifies the endpoint
  * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
- * is initialized as if the endpoint were used at full speed.  To prevent
- * the endpoint from being returned by a later autoconfig call, claim it
- * by assigning ep->driver_data to some non-null value.
+ * is initialized as if the endpoint were used at full speed. Because of
+ * that the users must consider adjusting the autoconfigured descriptor.
+ * To prevent the endpoint from being returned by a later autoconfig call,
+ * claims it by assigning ep->claimed to true.
  *
  * On failure, this returns a null endpoint descriptor.
  */
@@ -200,23 +151,45 @@ struct usb_ep *usb_ep_autoconfig(
        struct usb_endpoint_descriptor  *desc
 )
 {
-       struct usb_ep *ep;
+       struct usb_ep   *ep;
+       u8              type;
 
-       if (gadget->ops->match_ep) {
-               ep = gadget->ops->match_ep(gadget, desc, NULL);
-               if (ep && ep_matches(gadget, ep, desc))
-                       return ep;
-       }
+       ep = usb_ep_autoconfig_ss(gadget, desc, NULL);
+       if (!ep)
+               return NULL;
+
+       type = usb_endpoint_type(desc);
+
+       /* report (variable) full speed bulk maxpacket */
+       if (type == USB_ENDPOINT_XFER_BULK) {
+               int size = ep->maxpacket_limit;
 
-       /* Second, look at endpoints until an unclaimed one looks usable */
-       list_for_each_entry(ep, &gadget->ep_list, ep_list) {
-               if (ep_matches(gadget, ep, desc))
-                       return ep;
+               /* min() doesn't work on bitfields with gcc-3.5 */
+               if (size > 64)
+                       size = 64;
+               desc->wMaxPacketSize = cpu_to_le16(size);
        }
 
-       /* Fail */
-       return NULL;
+       return ep;
+}
+EXPORT_SYMBOL_GPL(usb_ep_autoconfig);
+
+/**
+ * usb_ep_autoconfig_release - releases endpoint and set it to initial state
+ * @ep: endpoint which should be released
+ *
+ * This function can be used during function bind for endpoints obtained
+ * from usb_ep_autoconfig(). It unclaims endpoint claimed by
+ * usb_ep_autoconfig() to make it available for other functions. Endpoint
+ * which was released is no longer valid and shouldn't be used in
+ * context of function which released it.
+ */
+void usb_ep_autoconfig_release(struct usb_ep *ep)
+{
+       ep->claimed = false;
+       ep->driver_data = NULL;
 }
+EXPORT_SYMBOL_GPL(usb_ep_autoconfig_release);
 
 /**
  * usb_ep_autoconfig_reset - reset endpoint autoconfig state
@@ -224,18 +197,18 @@ struct usb_ep *usb_ep_autoconfig(
  *
  * Use this for devices where one configuration may need to assign
  * endpoint resources very differently from the next one.  It clears
- * state such as ep->driver_data and the record of assigned endpoints
+ * state such as ep->claimed and the record of assigned endpoints
  * used by usb_ep_autoconfig().
  */
-void usb_ep_autoconfig_reset(struct usb_gadget *gadget)
+void usb_ep_autoconfig_reset (struct usb_gadget *gadget)
 {
        struct usb_ep   *ep;
 
-       list_for_each_entry(ep, &gadget->ep_list, ep_list) {
+       list_for_each_entry (ep, &gadget->ep_list, ep_list) {
+               ep->claimed = false;
                ep->driver_data = NULL;
        }
-#ifdef MANY_ENDPOINTS
-       in_epnum = 0;
-#endif
-       epnum = 0;
+       gadget->in_epnum = 0;
+       gadget->out_epnum = 0;
 }
+EXPORT_SYMBOL_GPL(usb_ep_autoconfig_reset);
-- 
2.48.1

Reply via email to