summaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/epautoconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/epautoconf.c')
-rw-r--r--drivers/usb/gadget/epautoconf.c233
1 files changed, 153 insertions, 80 deletions
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 13ad4792cc..f0f576d708 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -7,17 +7,11 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
*/
#include <init.h>
#include <common.h>
+
#include <linux/ctype.h>
#include <asm/byteorder.h>
@@ -26,15 +20,6 @@
#include "gadget_chips.h"
-/* we must assign addresses for configurable endpoints (like net2280) */
-static __initdata unsigned epnum;
-
-// #define MANY_ENDPOINTS
-#ifdef MANY_ENDPOINTS
-/* more than 15 configurable endpoints */
-static __initdata unsigned in_epnum;
-#endif
-
/*
* This should work with endpoints from controller drivers sharing the
* same endpoint naming convention. By example:
@@ -51,23 +36,26 @@ static __initdata unsigned in_epnum;
* NOTE: each endpoint is unidirectional, as specified by its USB
* descriptor; and isn't specific to a configuration or altsetting.
*/
-static int __init
+static int
ep_matches (
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;
+ int num_req_streams = 0;
+
/* endpoint already claimed? */
if (NULL != ep->driver_data)
return 0;
/* only support ep0 for portable CONTROL traffic */
- type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ type = usb_endpoint_type(desc);
if (USB_ENDPOINT_XFER_CONTROL == type)
return 0;
@@ -120,28 +108,48 @@ ep_matches (
}
}
+ /*
+ * Get the number of required streams from the EP companion
+ * descriptor and see if the EP matches it
+ */
+ if (usb_endpoint_xfer_bulk(desc)) {
+ if (ep_comp && gadget->max_speed >= USB_SPEED_SUPER) {
+ num_req_streams = ep_comp->bmAttributes & 0x1f;
+ if (num_req_streams > ep->max_streams)
+ return 0;
+ }
+
+ }
+
+ /*
+ * 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);
+
/* 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(desc->wMaxPacketSize);
+ max = 0x7ff & usb_endpoint_maxp(desc);
switch (type) {
case USB_ENDPOINT_XFER_INT:
- /* INT: limit 64 bytes full speed, 1024 high speed */
- if (!gadget->is_dualspeed && max > 64)
+ /* INT: limit 64 bytes full speed, 1024 high/super speed */
+ if (!gadget_is_dualspeed(gadget) && max > 64)
return 0;
/* FALLTHROUGH */
case USB_ENDPOINT_XFER_ISOC:
- /* ISO: limit 1023 bytes full speed, 1024 high speed */
- if (ep->maxpacket < max)
+ /* ISO: limit 1023 bytes full speed, 1024 high/super speed */
+ if (ep->maxpacket_limit < max)
return 0;
- if (!gadget->is_dualspeed && max > 1023)
+ if (!gadget_is_dualspeed(gadget) && max > 1023)
return 0;
/* BOTH: "high bandwidth" works only at high speed */
if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) {
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
return 0;
/* configure your hardware with enough buffering!! */
}
@@ -155,31 +163,30 @@ ep_matches (
if (isdigit (ep->name [2])) {
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)
+ if (++gadget->in_epnum > 15)
return 0;
- desc->bEndpointAddress = USB_DIR_IN | in_epnum;
-#endif
+ desc->bEndpointAddress = USB_DIR_IN | gadget->in_epnum;
} else {
- if (++epnum > 15)
+ if (++gadget->out_epnum > 15)
return 0;
- desc->bEndpointAddress |= epnum;
+ desc->bEndpointAddress |= gadget->out_epnum;
}
/* report (variable) full speed bulk maxpacket */
- if (USB_ENDPOINT_XFER_BULK == type) {
- int size = ep->maxpacket;
+ if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) {
+ int size = ep->maxpacket_limit;
/* min() doesn't work on bitfields with gcc-3.5 */
if (size > 64)
size = 64;
desc->wMaxPacketSize = cpu_to_le16(size);
}
+ ep->address = desc->bEndpointAddress;
return 1;
}
-static struct usb_ep * __init
+static struct usb_ep *
find_ep (struct usb_gadget *gadget, const char *name)
{
struct usb_ep *ep;
@@ -192,38 +199,53 @@ find_ep (struct usb_gadget *gadget, const char *name)
}
/**
- * usb_ep_autoconfig - choose an endpoint matching the descriptor
+ * 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.
+ * 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.
*
- * 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.
+ * 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.
*
- * 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.
+ * 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.
*
* On success, this returns an un-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 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, claim it by
+ * assigning ep->driver_data to some non-null value.
*
* On failure, this returns a null endpoint descriptor.
*/
-struct usb_ep * __init usb_ep_autoconfig (
+struct usb_ep *usb_ep_autoconfig_ss(
struct usb_gadget *gadget,
- struct usb_endpoint_descriptor *desc
+ struct usb_endpoint_descriptor *desc,
+ struct usb_ss_ep_comp_descriptor *ep_comp
)
{
struct usb_ep *ep;
@@ -237,47 +259,101 @@ struct usb_ep * __init usb_ep_autoconfig (
if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
/* ep-e, ep-f are PIO with only 64 byte fifos */
ep = find_ep (gadget, "ep-e");
- if (ep && ep_matches (gadget, ep, desc))
- return ep;
+ if (ep && ep_matches(gadget, ep, desc, ep_comp))
+ goto found_ep;
ep = find_ep (gadget, "ep-f");
- if (ep && ep_matches (gadget, ep, desc))
- return ep;
+ if (ep && ep_matches(gadget, ep, desc, ep_comp))
+ goto found_ep;
} else if (gadget_is_goku (gadget)) {
if (USB_ENDPOINT_XFER_INT == type) {
/* single buffering is enough */
- ep = find_ep (gadget, "ep3-bulk");
- if (ep && ep_matches (gadget, ep, desc))
- return ep;
+ ep = find_ep(gadget, "ep3-bulk");
+ if (ep && ep_matches(gadget, ep, desc, ep_comp))
+ goto found_ep;
} else if (USB_ENDPOINT_XFER_BULK == type
&& (USB_DIR_IN & desc->bEndpointAddress)) {
/* DMA may be available */
- ep = find_ep (gadget, "ep2-bulk");
- if (ep && ep_matches (gadget, ep, desc))
- return ep;
+ ep = find_ep(gadget, "ep2-bulk");
+ if (ep && ep_matches(gadget, ep, desc,
+ ep_comp))
+ goto found_ep;
}
- } else if (gadget_is_sh (gadget) && USB_ENDPOINT_XFER_INT == type) {
- /* single buffering is enough; maybe 8 byte fifo is too */
- ep = find_ep (gadget, "ep3in-bulk");
- if (ep && ep_matches (gadget, ep, desc))
- return ep;
-
- } else if (gadget_is_mq11xx (gadget) && USB_ENDPOINT_XFER_INT == type) {
- ep = find_ep (gadget, "ep1-bulk");
- if (ep && ep_matches (gadget, ep, desc))
- return ep;
+#ifdef CONFIG_BLACKFIN
+ } else if (gadget_is_musbhdrc(gadget)) {
+ if ((USB_ENDPOINT_XFER_BULK == type) ||
+ (USB_ENDPOINT_XFER_ISOC == type)) {
+ if (USB_DIR_IN & desc->bEndpointAddress)
+ ep = find_ep (gadget, "ep5in");
+ else
+ ep = find_ep (gadget, "ep6out");
+ } else if (USB_ENDPOINT_XFER_INT == type) {
+ if (USB_DIR_IN & desc->bEndpointAddress)
+ ep = find_ep(gadget, "ep1in");
+ else
+ ep = find_ep(gadget, "ep2out");
+ } else
+ ep = NULL;
+ if (ep && ep_matches(gadget, ep, desc, ep_comp))
+ goto found_ep;
+#endif
}
/* 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;
+ if (ep_matches(gadget, ep, desc, ep_comp))
+ goto found_ep;
}
/* Fail */
return NULL;
+found_ep:
+ ep->desc = NULL;
+ ep->comp_desc = NULL;
+ return ep;
}
+EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss);
+
+/**
+ * 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
+ * size must also be initialized. This is modified on success.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * On success, this returns an un-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.
+ *
+ * On failure, this returns a null endpoint descriptor.
+ */
+struct usb_ep *usb_ep_autoconfig(
+ struct usb_gadget *gadget,
+ struct usb_endpoint_descriptor *desc
+)
+{
+ return usb_ep_autoconfig_ss(gadget, desc, NULL);
+}
+EXPORT_SYMBOL_GPL(usb_ep_autoconfig);
/**
* usb_ep_autoconfig_reset - reset endpoint autoconfig state
@@ -288,17 +364,14 @@ struct usb_ep * __init usb_ep_autoconfig (
* state such as ep->driver_data and the record of assigned endpoints
* used by usb_ep_autoconfig().
*/
-void __init 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) {
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);