usb: gadget: add streams support to the gadget framework
This patch defines necessary fields to support
streaming for USB3.0.
It implements a new function, called
usb_ep_autoconfig_ss(), to be used instead of the
existing usb_ep_autoconfig() when working in
SuperSpeed mode and there is a need to search for
an endpoint according to the number of required
streams.
[ balbi@ti.com : slight changes to commit log ]
Signed-off-by: Maya Erez <merez@codeaurora.org>
Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 0022d44..91c032f 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -63,13 +63,16 @@
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;
@@ -129,6 +132,22 @@
}
/*
+ * 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) {
+ num_req_streams = ep_comp->bmAttributes & 0x1f;
+ if (num_req_streams > ep->max_streams)
+ return 0;
+ /* Update the ep_comp descriptor if needed */
+ if (num_req_streams != ep->max_streams)
+ ep_comp->bmAttributes = ep->max_streams;
+ }
+
+ }
+
+ /*
* If the protocol driver hasn't yet decided on wMaxPacketSize
* and wants to know the maximum possible, provide the info.
*/
@@ -208,7 +227,120 @@
}
/**
- * 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.
+ * @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.
+ *
+ * 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 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 *usb_ep_autoconfig_ss(
+ struct usb_gadget *gadget,
+ struct usb_endpoint_descriptor *desc,
+ struct usb_ss_ep_comp_descriptor *ep_comp
+)
+{
+ struct usb_ep *ep;
+ u8 type;
+
+ type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+ /* First, apply chip-specific "best usage" knowledge.
+ * This might make a good usb_gadget_ops hook ...
+ */
+ 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, ep_comp))
+ return ep;
+ ep = find_ep (gadget, "ep-f");
+ if (ep && ep_matches(gadget, ep, desc, ep_comp))
+ return 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, ep_comp))
+ return 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,
+ ep_comp))
+ 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))
+ return 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, ep_comp))
+ return ep;
+ }
+
+ /* Fail */
+ return NULL;
+}
+
+/**
+ * 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
@@ -237,72 +369,15 @@
*
* On failure, this returns a null endpoint descriptor.
*/
-struct usb_ep *usb_ep_autoconfig (
+struct usb_ep *usb_ep_autoconfig(
struct usb_gadget *gadget,
struct usb_endpoint_descriptor *desc
)
{
- struct usb_ep *ep;
- u8 type;
-
- type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
-
- /* First, apply chip-specific "best usage" knowledge.
- * This might make a good usb_gadget_ops hook ...
- */
- 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;
- ep = find_ep (gadget, "ep-f");
- if (ep && ep_matches (gadget, ep, desc))
- return 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;
- } 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;
- }
-
-#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))
- return 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;
- }
-
- /* Fail */
- return NULL;
+ return usb_ep_autoconfig_ss(gadget, desc, NULL);
}
+
/**
* usb_ep_autoconfig_reset - reset endpoint autoconfig state
* @gadget: device for which autoconfig state will be reset
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index d22b4a4..6259712 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -28,6 +28,7 @@
* field, and the usb controller needs one, it is responsible
* for mapping and unmapping the buffer.
* @length: Length of that data
+ * @stream_id: The stream id, when USB3.0 bulk streams are being used
* @no_interrupt: If true, hints that no completion irq is needed.
* Helpful sometimes with deep request queues that are handled
* directly by DMA controllers.
@@ -82,6 +83,7 @@
unsigned length;
dma_addr_t dma;
+ unsigned stream_id:16;
unsigned no_interrupt:1;
unsigned zero:1;
unsigned short_not_ok:1;
@@ -132,11 +134,15 @@
* @maxpacket:The maximum packet size used on this endpoint. The initial
* value can sometimes be reduced (hardware allowing), according to
* the endpoint descriptor used to configure the endpoint.
+ * @max_streams: The maximum number of streams supported
+ * by this EP (0 - 16, actual number is 2^n)
* @driver_data:for use by the gadget driver.
* @address: used to identify the endpoint when finding descriptor that
* matches connection speed
* @desc: endpoint descriptor. This pointer is set before the endpoint is
* enabled and remains valid until the endpoint is disabled.
+ * @comp_desc: In case of SuperSpeed support, this is the endpoint companion
+ * descriptor that is used to configure the endpoint
*
* the bus controller driver lists all the general purpose endpoints in
* gadget->ep_list. the control endpoint (gadget->ep0) is not in that list,
@@ -149,8 +155,10 @@
const struct usb_ep_ops *ops;
struct list_head ep_list;
unsigned maxpacket:16;
+ unsigned max_streams:16;
u8 address;
const struct usb_endpoint_descriptor *desc;
+ const struct usb_ss_ep_comp_descriptor *comp_desc;
};
/*-------------------------------------------------------------------------*/
@@ -895,6 +903,11 @@
extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *,
struct usb_endpoint_descriptor *);
+
+extern struct usb_ep *usb_ep_autoconfig_ss(struct usb_gadget *,
+ struct usb_endpoint_descriptor *,
+ struct usb_ss_ep_comp_descriptor *);
+
extern void usb_ep_autoconfig_reset(struct usb_gadget *);
#endif /* __LINUX_USB_GADGET_H */