]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/usb/gadget/epautoconf.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/wfg/writeback
[karo-tx-linux.git] / drivers / usb / gadget / epautoconf.c
index 9b7360ff5aa70c2992256cda8b1533fa76d7f4b9..7a7e6b7e1fd614639f53a8fa9b19fd83648b9d6d 100644 (file)
@@ -63,13 +63,16 @@ 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;
@@ -128,6 +131,22 @@ 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) {
+                       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.
@@ -142,13 +161,13 @@ ep_matches (
        max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
        switch (type) {
        case USB_ENDPOINT_XFER_INT:
-               /* INT:  limit 64 bytes full speed, 1024 high speed */
+               /* INT:  limit 64 bytes full speed, 1024 high/super speed */
                if (!gadget->is_dualspeed && max > 64)
                        return 0;
                /* FALLTHROUGH */
 
        case USB_ENDPOINT_XFER_ISOC:
-               /* ISO:  limit 1023 bytes full speed, 1024 high speed */
+               /* ISO:  limit 1023 bytes full speed, 1024 high/super speed */
                if (ep->maxpacket < max)
                        return 0;
                if (!gadget->is_dualspeed && max > 1023)
@@ -183,7 +202,7 @@ ep_matches (
        }
 
        /* report (variable) full speed bulk maxpacket */
-       if (USB_ENDPOINT_XFER_BULK == type) {
+       if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) {
                int size = ep->maxpacket;
 
                /* min() doesn't work on bitfields with gcc-3.5 */
@@ -191,6 +210,7 @@ ep_matches (
                        size = 64;
                desc->wMaxPacketSize = cpu_to_le16(size);
        }
+       ep->address = desc->bEndpointAddress;
        return 1;
 }
 
@@ -207,38 +227,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 *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;
@@ -252,23 +287,24 @@ struct usb_ep *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))
+               if (ep && ep_matches(gadget, ep, desc, ep_comp))
                        return ep;
                ep = find_ep (gadget, "ep-f");
-               if (ep && ep_matches (gadget, ep, desc))
+               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 = 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 = find_ep(gadget, "ep2-bulk");
+                       if (ep && ep_matches(gadget, ep, desc,
+                                             ep_comp))
                                return ep;
                }
 
@@ -287,14 +323,14 @@ struct usb_ep *usb_ep_autoconfig (
                                ep = find_ep(gadget, "ep2out");
                } else
                        ep = NULL;
-               if (ep && ep_matches (gadget, ep, desc))
+               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))
+               if (ep_matches(gadget, ep, desc, ep_comp))
                        return ep;
        }
 
@@ -302,6 +338,46 @@ struct usb_ep *usb_ep_autoconfig (
        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
+ *     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);
+}
+
+
 /**
  * usb_ep_autoconfig_reset - reset endpoint autoconfig state
  * @gadget: device for which autoconfig state will be reset