Adding David Vrabel to review from a WUSB point of view.

> From: Tatyana Linder <[email protected]>
>
> This patch adds the SuperSpeed functionality to the gadget framework.
> In order not to force all the FDs to supply SuperSpeed descriptors when
> operating in SuperSpeed mode the following approach was taken:
> If we're operating in SuperSpeed mode and the FD didn't supply SuperSpeed
> descriptors, the composite layer will automatically create SuperSpeed
> descriptors with default values.
> Support for new SuperSpeed BOS descriptor was added.
> Support for SET_FEATURE and GET_STATUS requests in SuperSpeed mode was
> added.
>
> Signed-off-by: Tatyana Linder <[email protected]>
> ---
> This patch was verified by USBCV 3.0 and 2.0.
>
>  drivers/usb/gadget/Kconfig     |   20 ++-
>  drivers/usb/gadget/composite.c |  319
> +++++++++++++++++++++++++++++++++++++---
>  include/linux/usb/ch9.h        |   54 +++++++-
>  include/linux/usb/composite.h  |   24 +++
>  include/linux/usb/gadget.h     |   19 +++
>  5 files changed, 407 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
> index cd27f9b..9afdd08 100644
> --- a/drivers/usb/gadget/Kconfig
> +++ b/drivers/usb/gadget/Kconfig
> @@ -520,11 +520,11 @@ config USB_GADGET_DUMMY_HCD
>         side is the master; the gadget side is the slave.  Gadget drivers
>         can be high, full, or low speed; and they have access to endpoints
>         like those from NET2280, PXA2xx, or SA1100 hardware.
> -
> +
>         This may help in some stages of creating a driver to embed in a
>         Linux device, since it lets you debug several parts of the gadget
>         driver without its hardware or drivers being involved.
> -
> +
>         Since such a gadget side driver needs to interoperate with a host
>         side Linux-USB device driver, this may help to debug both sides
>         of a USB protocol stack.
> @@ -552,6 +552,18 @@ config USB_GADGET_DUALSPEED
>         Means that gadget drivers should include extra descriptors
>         and code to handle dual-speed controllers.
>
> +config USB_GADGET_SUPERSPEED
> +     boolean "Gadget opperating in Super Speed"
> +     depends on USB_GADGET
> +     depends on USB_GADGET_DUALSPEED
> +     default n
> +     help
> +       Enabling this feature enables Super Speed support in the Gadget
> +       driver. It means that gadget drivers should include extra (SuperSpeed)
> +       descriptors.
> +       For composite devices: if SupeSpeed descriptors weren't supplied by
> +       the FD, they will be automatically generated with default values.
> +
>  #
>  # USB Gadget Drivers
>  #
> @@ -633,7 +645,7 @@ config USB_ETH
>       help
>         This driver implements Ethernet style communication, in one of
>         several ways:
> -
> +
>          - The "Communication Device Class" (CDC) Ethernet Control Model.
>            That protocol is often avoided with pure Ethernet adapters, in
>            favor of simpler vendor-specific hardware, but is widely
> @@ -673,7 +685,7 @@ config USB_ETH_RNDIS
>          If you say "y" here, the Ethernet gadget driver will try to provide
>          a second device configuration, supporting RNDIS to talk to such
>          Microsoft USB hosts.
> -
> +
>          To make MS-Windows work with this, use Documentation/usb/linux.inf
>          as the "driver info file".  For versions of MS-Windows older than
>          XP, you'll need to download drivers from Microsoft's website; a URL
> diff --git a/drivers/usb/gadget/composite.c
> b/drivers/usb/gadget/composite.c
> index c619c80..a5dcfe1 100644
> --- a/drivers/usb/gadget/composite.c
> +++ b/drivers/usb/gadget/composite.c
> @@ -70,6 +70,102 @@ static char *iSerialNumber;
>  module_param(iSerialNumber, charp, 0);
>  MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
>
> +/** Default endpoint companion descriptor */
> +static struct usb_ss_ep_comp_descriptor ep_comp_desc = {
> +             .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
> +             .bLength = 0x06,
> +             .bMaxBurst = 0, /*the default is we don't support bursting*/
> +             .bmAttributes = 0, /*2^0 streams supported*/
> +             .wBytesPerInterval = 0,
> +};
> +
> +/**This function receives a pointer to usb_function and adds
> + * missing super speed descriptors in the ss_descriptor field
> + * according to its hs_descriptors field.
> + *
> + * In more details: this function copies f->hs_descriptors while
> + * updating the endpoint descriptor and adding endpoint
> + * companion descriptor
> + */
> +static void create_ss_descriptors(struct usb_function *f)
> +{
> +     unsigned bytes; /*number of bytes to allocate*/
> +     unsigned n_desc;    /* number of descriptors*/
> +     void *mem; /*allocated memory to copy to*/
> +     struct usb_descriptor_header **tmp;
> +     struct usb_endpoint_descriptor  *ep_desc ;
> +     struct usb_descriptor_header **src = f->hs_descriptors;
> +
> +     if (!f->hs_descriptors)
> +             return;
> +
> +     /* Count number of EPs (in order to know how many SS_EP_COMPANION
> +        descriptors to add), the total number of descriptors and the sum of
> +        each descriptor bLength field in order to know how much memory to
> +        allocate*/
> +     for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++) {
> +             if ((*tmp)->bDescriptorType == USB_DT_ENDPOINT) {
> +                     bytes += ep_comp_desc.bLength;
> +                     n_desc++;
> +             }
> +             bytes += (*tmp)->bLength;
> +     }
> +
> +     bytes += (n_desc + 1) * sizeof(*tmp);
> +     mem = kmalloc(bytes, GFP_KERNEL);
> +     if (!mem)
> +             return;
> +
> +     /* fill in pointers starting at "tmp",
> +      * to descriptors copied starting at "mem";
> +      * and return "ret"
> +      */
> +     tmp = mem;
> +     f->ss_descriptors  = mem;
> +     mem += (n_desc + 1) * sizeof(*tmp);
> +     while (*src) {
> +             /*Copy the original descriptor*/
> +             memcpy(mem, *src, (*src)->bLength);
> +             switch ((*src)->bDescriptorType) {
> +             case USB_DT_ENDPOINT:
> +                     /*update ep descriptor*/
> +                     ep_desc = (struct usb_endpoint_descriptor *)mem;
> +                     switch (ep_desc->bmAttributes &
> +                             USB_ENDPOINT_XFERTYPE_MASK) {
> +                     case USB_ENDPOINT_XFER_CONTROL:
> +                             ep_desc->wMaxPacketSize = 512;
> +                             ep_desc->bInterval = 0;
> +                             break;
> +                     case USB_ENDPOINT_XFER_BULK:
> +                             ep_desc->wMaxPacketSize = 1024;
> +                             ep_desc->bInterval = 0;
> +                             break;
> +                     case USB_ENDPOINT_XFER_INT:
> +                     case USB_ENDPOINT_XFER_ISOC:
> +                             break;
> +                     }
> +                     *tmp = mem;
> +                     tmp++;
> +                     mem += (*src)->bLength;
> +                     /*add ep companion descriptor*/
> +                     memcpy(mem, &ep_comp_desc, ep_comp_desc.bLength);
> +                     *tmp = mem;
> +                     tmp++;
> +                     mem += ep_comp_desc.bLength;
> +                     break;
> +             default:
> +                     *tmp = mem;
> +                     tmp++;
> +                     mem += (*src)->bLength;
> +                     break;
> +             }
> +             src++;
> +     }
> +     *tmp = NULL; /*The last (struct usb_descriptor_header *) in the
> +                     descriptors vector is NULL*/
> +     f->ss_desc_allocated = true;
> +}
> +
>  /*-------------------------------------------------------------------------*/
>  /**
>   * next_ep_desc - advance to the next EP descriptor
> @@ -110,6 +206,9 @@ int ep_choose(struct usb_gadget *g, struct
> usb_function *f, struct usb_ep *_ep)
>       struct usb_endpoint_descriptor *chosen_desc = NULL;
>       struct usb_descriptor_header **speed_desc = NULL;
>
> +     struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
> +     int want_comp_desc = 0;
> +
>       struct usb_descriptor_header **d_spd; /* cursor for speed desc */
>
>       if (!g || !f || !_ep)
> @@ -117,6 +216,13 @@ int ep_choose(struct usb_gadget *g, struct
> usb_function *f, struct usb_ep *_ep)
>
>       /* select desired speed */
>       switch (g->speed) {
> +     case USB_SPEED_SUPER:
> +             if (gadget_is_superspeed(g)) {
> +                     speed_desc = f->ss_descriptors;
> +                     want_comp_desc = 1;
> +                     break;
> +             }
> +             /*else: Fall trough*/
>       case USB_SPEED_HIGH:
>               if (gadget_is_dualspeed(g)) {
>                       speed_desc = f->hs_descriptors;
> @@ -143,7 +249,18 @@ ep_found:
>       /* commit results */
>       _ep->maxpacket = chosen_desc->wMaxPacketSize;
>       _ep->desc = chosen_desc;
> -
> +     _ep->comp_desc = NULL;
> +     if (want_comp_desc) {
> +             /**
> +              * Companion descriptor should follow EP descriptor
> +              * USB 3.0 spec, #9.6.7
> +              */
> +             comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd);
> +             if (!comp_desc ||
> +                 (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP))
> +                     return -EIO;
> +             _ep->comp_desc = comp_desc;
> +     }
>       return 0;
>  }
>
> @@ -185,6 +302,12 @@ int usb_add_function(struct usb_configuration
> *config,
>                       list_del(&function->list);
>                       function->config = NULL;
>               }
> +             /*Add SS descriptors if there are any. This has to be done
> +               after the bind since we need the hs_descriptors to be set in
> +               usb_function and some of the FDs does it in the bind. */
> +             if ((gadget_is_superspeed(config->cdev->gadget)) &&
> +                 (!function->ss_not_capable) && (!function->ss_descriptors))
> +                     create_ss_descriptors(function);
>       } else
>               value = 0;
>
> @@ -197,6 +320,8 @@ int usb_add_function(struct usb_configuration *config,
>               config->fullspeed = true;
>       if (!config->highspeed && function->hs_descriptors)
>               config->highspeed = true;
> +     if (!config->superspeed && function->ss_descriptors)
> +             config->superspeed = true;
>
>  done:
>       if (value)
> @@ -340,7 +465,9 @@ static int config_buf(struct usb_configuration
> *config,
>       list_for_each_entry(f, &config->functions, list) {
>               struct usb_descriptor_header **descriptors;
>
> -             if (speed == USB_SPEED_HIGH)
> +             if (speed == USB_SPEED_SUPER)
> +                     descriptors = f->ss_descriptors;
> +             else if (speed == USB_SPEED_HIGH)
>                       descriptors = f->hs_descriptors;
>               else
>                       descriptors = f->descriptors;
> @@ -366,23 +493,26 @@ static int config_desc(struct usb_composite_dev
> *cdev, unsigned w_value)
>       u8                              type = w_value >> 8;
>       enum usb_device_speed           speed = USB_SPEED_UNKNOWN;
>
> -     if (gadget_is_dualspeed(gadget)) {
> -             int                     hs = 0;
> -
> +     if (gadget->speed == USB_SPEED_SUPER)
> +             speed = gadget->speed;
> +     else if (gadget_is_dualspeed(gadget)) {
> +             int     hs = 0;
>               if (gadget->speed == USB_SPEED_HIGH)
>                       hs = 1;
>               if (type == USB_DT_OTHER_SPEED_CONFIG)
>                       hs = !hs;
>               if (hs)
>                       speed = USB_SPEED_HIGH;
> -
>       }
>
>       /* This is a lookup by config *INDEX* */
>       w_value &= 0xff;
>       list_for_each_entry(c, &cdev->configs, list) {
>               /* ignore configs that won't work at this speed */
> -             if (speed == USB_SPEED_HIGH) {
> +             if (speed == USB_SPEED_SUPER) {
> +                     if (!c->superspeed)
> +                             continue;
> +             } else if (speed == USB_SPEED_HIGH) {
>                       if (!c->highspeed)
>                               continue;
>               } else {
> @@ -402,16 +532,22 @@ static int count_configs(struct usb_composite_dev
> *cdev, unsigned type)
>       struct usb_configuration        *c;
>       unsigned                        count = 0;
>       int                             hs = 0;
> +     int                             ss = 0;
>
>       if (gadget_is_dualspeed(gadget)) {
>               if (gadget->speed == USB_SPEED_HIGH)
>                       hs = 1;
> +             if (gadget->speed == USB_SPEED_SUPER)
> +                     ss = 1;
>               if (type == USB_DT_DEVICE_QUALIFIER)
>                       hs = !hs;
>       }
>       list_for_each_entry(c, &cdev->configs, list) {
>               /* ignore configs that won't work at this speed */
> -             if (hs) {
> +             if (ss) {
> +                     if (!c->superspeed)
> +                             continue;
> +             } else if (hs) {
>                       if (!c->highspeed)
>                               continue;
>               } else {
> @@ -423,6 +559,55 @@ static int count_configs(struct usb_composite_dev
> *cdev, unsigned type)
>       return count;
>  }
>
> +/**
> + * bos() - prepares the BOS (Binary Device Object) descriptor
> + * and its device capabilities descriptors. The bos descriptor
> + * should be supported by a Superspeed device.
> + */
> +static int bos(struct usb_composite_dev *cdev)
> +{
> +     struct usb_bos_descriptor       *bos = cdev->req->buf;
> +     struct usb_ext_cap_descriptor   *usb_ext = NULL;
> +     struct ss_usb_cap_descriptor    *ss_cap = NULL;
> +
> +     bos->bLength = USB_DT_BOS_SIZE;
> +     bos->bDescriptorType = USB_DT_BOS;
> +
> +     bos->wTotalLength = USB_DT_BOS_SIZE;
> +     bos->bNumDeviceCaps = 0;
> +
> +     /* A SuperSpeed device shall include the USB2.0 extension descriptor and
> +        shall support LPM when operating in USB2.0 HS mode.*/
> +     usb_ext = (struct usb_ext_cap_descriptor *)
> +                     (cdev->req->buf+bos->wTotalLength);
> +     bos->bNumDeviceCaps++;
> +     bos->wTotalLength += USB_DT_USB_EXT_CAP_SIZE;
> +     usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
> +     usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
> +     usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
> +     usb_ext->bmAttributes = USB_LPM_SUPPORT;
> +
> +     /* The Superspeed USB Capability descriptor shall be implemented by all
> +        Superspeed devices. */
> +     ss_cap = (struct ss_usb_cap_descriptor *)
> +             (cdev->req->buf+bos->wTotalLength);
> +     bos->bNumDeviceCaps++;
> +     bos->wTotalLength += USB_DT_SS_USB_CAP_SIZE;
> +     ss_cap->bLength = USB_DT_SS_USB_CAP_SIZE;
> +     ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
> +     ss_cap->bDevCapabilityType = SS_USB_CAP_TYPE;
> +     ss_cap->bmAttributes = 0; /*LTM is not supported yet*/
> +     ss_cap->wSpeedSupported = USB_LOW_SPEED_OPERATION |
> +                             USB_FULL_SPEED_OPERATION |
> +                             USB_HIGH_SPEED_OPERATION |
> +                             USB_5GBPS_OPERATION;
> +     ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
> +     ss_cap->bU1devExitLat = 0;
> +     ss_cap->bU2DevExitLat = 0;
> +
> +     return bos->wTotalLength;
> +}
> +
>  static void device_qual(struct usb_composite_dev *cdev)
>  {
>       struct usb_qualifier_descriptor *qual = cdev->req->buf;
> @@ -466,27 +651,40 @@ static int set_config(struct usb_composite_dev
> *cdev,
>       unsigned                power = gadget_is_otg(gadget) ? 8 : 100;
>       int                     tmp;
>
> -     if (cdev->config)
> -             reset_config(cdev);
> -
>       if (number) {
>               list_for_each_entry(c, &cdev->configs, list) {
>                       if (c->bConfigurationValue == number) {
> +                             /* Need to disable the FDs of the previous
> +                                configuration */
> +                             if (cdev->config)
> +                                     reset_config(cdev);
>                               result = 0;
>                               break;
>                       }
>               }
>               if (result < 0)
>                       goto done;
> -     } else
> +     } else { /* Zero configuration value - need to reset the config */
> +             if (cdev->config)
> +                     reset_config(cdev);
>               result = 0;
> +     }
>
>       INFO(cdev, "%s speed config #%d: %s\n",
>               ({ char *speed;
>               switch (gadget->speed) {
> -             case USB_SPEED_LOW:     speed = "low"; break;
> -             case USB_SPEED_FULL:    speed = "full"; break;
> -             case USB_SPEED_HIGH:    speed = "high"; break;
> +             case USB_SPEED_LOW:
> +                     speed = "low";
> +                     break;
> +             case USB_SPEED_FULL:
> +                     speed = "full";
> +                     break;
> +             case USB_SPEED_HIGH:
> +                     speed = "high";
> +                     break;
> +             case USB_SPEED_SUPER:
> +                     speed = "super";
> +                     break;
>               default:                speed = "?"; break;
>               } ; speed; }), number, c ? c->label : "unconfigured");
>
> @@ -509,7 +707,9 @@ static int set_config(struct usb_composite_dev *cdev,
>                * function's setup callback instead of the current
>                * configuration's setup callback.
>                */
> -             if (gadget->speed == USB_SPEED_HIGH)
> +             if (gadget->speed == USB_SPEED_SUPER)
> +                     descriptors = f->ss_descriptors;
> +             else if (gadget->speed == USB_SPEED_HIGH)
>                       descriptors = f->hs_descriptors;
>               else
>                       descriptors = f->descriptors;
> @@ -592,14 +792,14 @@ int usb_add_config(struct usb_composite_dev *cdev,
>       } else {
>               unsigned        i;
>
> -             DBG(cdev, "cfg %d/%p speeds:%s%s\n",
> +             DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",
>                       config->bConfigurationValue, config,
> +                     config->superspeed ? " super" : "",
>                       config->highspeed ? " high" : "",
>                       config->fullspeed
>                               ? (gadget_is_dualspeed(cdev->gadget)
>                                       ? " full"
> -                                     : " full/low")
> -                             : "");
> +                                     : " full/low") : "");
>
>               for (i = 0; i < MAX_CONFIG_INTERFACES; i++) {
>                       struct usb_function     *f = config->interface[i];
> @@ -851,6 +1051,7 @@ composite_setup(struct usb_gadget *gadget, const
> struct usb_ctrlrequest *ctrl)
>       struct usb_composite_dev        *cdev = get_gadget_data(gadget);
>       struct usb_request              *req = cdev->req;
>       int                             value = -EOPNOTSUPP;
> +     int                             status = 0;
>       u16                             w_index = le16_to_cpu(ctrl->wIndex);
>       u8                              intf = w_index & 0xFF;
>       u16                             w_value = le16_to_cpu(ctrl->wValue);
> @@ -878,18 +1079,30 @@ composite_setup(struct usb_gadget *gadget, const
> struct usb_ctrlrequest *ctrl)
>               case USB_DT_DEVICE:
>                       cdev->desc.bNumConfigurations =
>                               count_configs(cdev, USB_DT_DEVICE);
> +                     cdev->desc.bMaxPacketSize0 =
> +                             cdev->gadget->ep0->maxpacket;
> +                     if (gadget->speed >= USB_SPEED_SUPER)
> +                             cdev->desc.bcdUSB = cpu_to_le16(0x0300);
> +                     else if ((gadget_is_superspeed(gadget)) &&
> +                              (gadget->speed <= USB_SPEED_HIGH))
> +                             cdev->desc.bcdUSB = cpu_to_le16(0x0210);
> +
>                       value = min(w_length, (u16) sizeof cdev->desc);
>                       memcpy(req->buf, &cdev->desc, value);
>                       break;
> +
>               case USB_DT_DEVICE_QUALIFIER:
> -                     if (!gadget_is_dualspeed(gadget))
> +                     if (!gadget_is_dualspeed(gadget) ||
> +                         gadget->speed >= USB_SPEED_SUPER)
>                               break;
> +
>                       device_qual(cdev);
>                       value = min_t(int, w_length,
>                               sizeof(struct usb_qualifier_descriptor));
>                       break;
>               case USB_DT_OTHER_SPEED_CONFIG:
> -                     if (!gadget_is_dualspeed(gadget))
> +                     if (!gadget_is_dualspeed(gadget) ||
> +                         gadget->speed >= USB_SPEED_SUPER)
>                               break;
>                       /* FALLTHROUGH */
>               case USB_DT_CONFIG:
> @@ -903,6 +1116,12 @@ composite_setup(struct usb_gadget *gadget, const
> struct usb_ctrlrequest *ctrl)
>                       if (value >= 0)
>                               value = min(w_length, (u16) value);
>                       break;
> +             case USB_DT_BOS:
> +                     if (gadget_is_superspeed(gadget)) {
> +                             value = bos(cdev);
> +                             value = min(w_length, (u16) value);
> +                     }
> +                     break;
>               }
>               break;
>
> @@ -962,6 +1181,55 @@ composite_setup(struct usb_gadget *gadget, const
> struct usb_ctrlrequest *ctrl)
>               *((u8 *)req->buf) = value;
>               value = min(w_length, (u16) 1);
>               break;
> +
> +             /*USB 3.0 additions*/
> +     /* Function driver should handle get_status request. If such cb
> +       wasn't supplied we respond with default value = 0
> +       Note: FD should supply such cb only for the first interface
> +       of the function*/
> +     case USB_REQ_GET_STATUS:
> +             if (!gadget_is_superspeed(gadget))
> +                     goto unknown;
> +             if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
> +                     goto unknown;
> +             value = 2;      /*This is the length of the get_status reply*/
> +             *((u16 *)req->buf) = 0;
> +             if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
> +                     break;
> +             f = cdev->config->interface[intf];
> +             if (!f)
> +                     break;
> +             status = f->get_status ? f->get_status(f) : 0;
> +             if (status < 0)
> +                     break;
> +             *((u16 *)req->buf) = status & 0x0000ffff;
> +             break;
> +     /*Function drivers should handle SetFeature(FUNCTION_SUSPEND) request.
> +       function_suspend cb should be supplied only for the first interface
> +       of the function*/
> +     case USB_REQ_SET_FEATURE:
> +             if (!gadget_is_superspeed(gadget))
> +                     goto unknown;
> +             if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
> +                     goto unknown;
> +             switch (w_value) {
> +             case USB_INTRF_FUNC_SUSPEND:
> +                     if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
> +                             break;
> +                     f = cdev->config->interface[intf];
> +                     if (!f)
> +                             break;
> +                     value = f->func_suspend ? f->func_suspend(f) : 0;
> +                     if (value < 0) {
> +                             ERROR(cdev, "func_suspend() returned "
> +                                         "error %d\n", value);
> +                             value = 0;
> +                     }
> +                     break;
> +             default:
> +                     break;
> +             }
> +             break;
>       default:
>  unknown:
>               VDBG(cdev,
> @@ -1080,8 +1348,11 @@ composite_unbind(struct usb_gadget *gadget)
>                               DBG(cdev, "unbind function '%s'/%p\n",
>                                               f->name, f);
>                               f->unbind(c, f);
> -                             /* may free memory for "f" */
>                       }
> +                     /*Free memory allocated for ss descriptors*/
> +                     if (f->ss_desc_allocated && f->ss_descriptors)
> +                             usb_free_descriptors(f->ss_descriptors);
> +                     /* may free memory for "f" */
>               }
>               list_del(&c->list);
>               if (c->unbind) {
> @@ -1254,7 +1525,6 @@ composite_resume(struct usb_gadget *gadget)
>
>  static struct usb_gadget_driver composite_driver = {
>       .speed          = USB_SPEED_HIGH,
> -
>       .bind           = composite_bind,
>       .unbind         = composite_unbind,
>
> @@ -1293,6 +1563,9 @@ int usb_composite_register(struct
> usb_composite_driver *driver)
>               driver->name = "composite";
>       composite_driver.function =  (char *) driver->name;
>       composite_driver.driver.name = driver->name;
> +#ifdef CONFIG_USB_GADGET_SUPERSPEED
> +     composite_driver.speed = USB_SPEED_SUPER;
> +#endif /*CONFIG_USB_GADGET_SUPERSPEED*/
>       composite = driver;
>
>       return usb_gadget_register_driver(&composite_driver);
> diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
> index da2ed77..69e528a 100644
> --- a/include/linux/usb/ch9.h
> +++ b/include/linux/usb/ch9.h
> @@ -125,6 +125,20 @@
>
>  #define USB_ENDPOINT_HALT            0       /* IN/OUT will STALL */
>
> +/**
> + * New Feature Selectors as added by USB 3.0
> + * See USB 3.0 spec Table 9-6
> + */
> +#define USB_DEVICE_U1_ENABLE         48      /*enables the upstream port to
> +                                             initiate requests for transition
> +                                             into U1 state*/
> +#define USB_DEVICE_U2_ENABLE         49      /*enables the upstream port to
> +                                             initiate requests for transition
> +                                             into U2 state*/
> +#define USB_DEVICE_LTM_ENABLE                50      /*enables the devise to 
> send
> +                                             Latency tolerance messages.*/
> +#define USB_INTRF_FUNC_SUSPEND               0       /*function suspend*/
> +
>
>  /**
>   * struct usb_ctrlrequest - SETUP data for a USB device control request
> @@ -675,6 +689,7 @@ struct usb_bos_descriptor {
>       __u8  bNumDeviceCaps;
>  } __attribute__((packed));
>
> +#define USB_DT_BOS_SIZE              5
>  /*-------------------------------------------------------------------------*/
>
>  /* USB_DT_DEVICE_CAPABILITY:  grouped with BOS */
> @@ -712,16 +727,51 @@ struct usb_wireless_cap_descriptor {    /* Ultra Wide
> Band */
>       __u8  bReserved;
>  } __attribute__((packed));
>
> +/*USB 2.0 Extension descriptor*/
>  #define      USB_CAP_TYPE_EXT                2
> -
>  struct usb_ext_cap_descriptor {              /* Link Power Management */
>       __u8  bLength;
>       __u8  bDescriptorType;
>       __u8  bDevCapabilityType;
> -     __u8  bmAttributes;
> +     __u32 bmAttributes;
>  #define USB_LPM_SUPPORT                      (1 << 1)        /* supports LPM 
> */
>  } __attribute__((packed));
>
> +#define USB_DT_USB_EXT_CAP_SIZE      7
> +
> +/*SuperSpeed USB Capability descriptor: Defines the set of SuperSpeed USB
> +  specific device level capabilities*/
> +#define      SS_USB_CAP_TYPE         3
> +struct ss_usb_cap_descriptor {               /* Link Power Management */
> +     __u8  bLength;
> +     __u8  bDescriptorType;
> +     __u8  bDevCapabilityType;
> +     __u8  bmAttributes;
> +#define USB_LTM_SUPPORT                      (1 << 1) /* supports LTM */
> +     __u16 wSpeedSupported;
> +#define USB_LOW_SPEED_OPERATION              (1)      /* Low speed operation 
> */
> +#define USB_FULL_SPEED_OPERATION     (1 << 1) /* Full speed operation */
> +#define USB_HIGH_SPEED_OPERATION     (1 << 2) /* High speed operation */
> +#define USB_5GBPS_OPERATION          (1 << 3) /* Operation at 5Gbps */
> +     __u8  bFunctionalitySupport;
> +     __u8  bU1devExitLat;
> +     __u16 bU2DevExitLat;
> +} __attribute__((packed));
> +
> +#define USB_DT_SS_USB_CAP_SIZE       10
> +
> +/*Container ID Capability descriptor: Defines the instance unique ID used
> to
> +  identify the instance across all operating modes*/
> +#define      CONTAINER_ID_TYPE       4
> +struct ss_usb_container_id_descriptor {
> +     __u8  bLength;
> +     __u8  bDescriptorType;
> +     __u8  bDevCapabilityType;
> +     __u8  bReserved;
> +     __u8  ContainerID[16]; /*128-bit number*/
> +} __attribute__((packed));
> +
> +#define USB_DT_SS_CONTN_ID_SIZE      20
>  /*-------------------------------------------------------------------------*/
>
>  /* USB_DT_WIRELESS_ENDPOINT_COMP:  companion descriptor associated with
> diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
> index c623bed..36ab1d0 100644
> --- a/include/linux/usb/composite.h
> +++ b/include/linux/usb/composite.h
> @@ -52,6 +52,18 @@ struct usb_configuration;
>   * @hs_descriptors: Table of high speed descriptors, using interface and
>   *   string identifiers assigned during @bind().  If this pointer is null,
>   *   the function will not be available at high speed.
> + * @ss_descriptors: Table of super speed descriptors. If
> + *   wasnt supplied by the FD during @bind() and
> + *   !ss_not_capble, will be generated automaticly with
> + *   default values while working in superspeed mode. If this
> + *   pointer is null after initiation, the function will not
> + *   be available at super speed.
> + * @ss_not_capable: This flag is used by the FD to indicate if
> + *   this function is SS capble. Meaning: if SS descriptors
> + *   weren't supplied by the FD, and the flag is set ss
> + *   descriptors will NOT be automatically generated
> + * @ss_desc_allocated: This flag indicates whether the ss descriptors
> were
> + *   dynamically allocated (and needs to be released).
>   * @config: assigned when @usb_add_function() is called; this is the
>   *   configuration with which this function is associated.
>   * @bind: Before the gadget can register, all of its functions bind() to
> the
> @@ -70,6 +82,10 @@ struct usb_configuration;
>   * @setup: Used for interface-specific control requests.
>   * @suspend: Notifies functions when the host stops sending USB traffic.
>   * @resume: Notifies functions when the host restarts USB traffic.
> + * @get_status: Returns function status as a reply to
> + *   GetStatus() request when the recepient is Interface.
> + * @func_suspend: callback to be called when
> + *   SetFeature(FUNCTION_SUSPEND) is reseived
>   *
>   * A single USB function uses one or more interfaces, and should in most
>   * cases support operation at both full and high speeds.  Each function
> is
> @@ -99,6 +115,10 @@ struct usb_function {
>       struct usb_gadget_strings       **strings;
>       struct usb_descriptor_header    **descriptors;
>       struct usb_descriptor_header    **hs_descriptors;
> +     struct usb_descriptor_header    **ss_descriptors;
> +
> +     unsigned                        ss_desc_allocated:1;
> +     unsigned                        ss_not_capable:1;
>
>       struct usb_configuration        *config;
>
> @@ -125,6 +145,9 @@ struct usb_function {
>       void                    (*suspend)(struct usb_function *);
>       void                    (*resume)(struct usb_function *);
>
> +     /* USB 3.0 additions */
> +     int                     (*get_status)(struct usb_function *);
> +     int                     (*func_suspend)(struct usb_function *);
>       /* private: */
>       /* internals */
>       struct list_head                list;
> @@ -229,6 +252,7 @@ struct usb_configuration {
>       struct list_head        list;
>       struct list_head        functions;
>       u8                      next_interface_id;
> +     unsigned                superspeed:1;
>       unsigned                highspeed:1;
>       unsigned                fullspeed:1;
>       struct usb_function     *interface[MAX_CONFIG_INTERFACES];
> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> index bf7dc0b..40329b0 100644
> --- a/include/linux/usb/gadget.h
> +++ b/include/linux/usb/gadget.h
> @@ -139,6 +139,8 @@ struct usb_ep_ops {
>   * @desc:endpoint descriptor.  this pointer set before endpoint is
> enabled and
>   *   remains valid until the endpoint is disabled; the data byte order
>   *   is little-endian (usb-standard).
> + * @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,
> @@ -153,6 +155,7 @@ struct usb_ep {
>       unsigned                        maxpacket:16;
>       u8                              bEndpointAddress;
>       struct usb_endpoint_descriptor  *desc;
> +     struct usb_ss_ep_comp_descriptor        *comp_desc;
>  };
>
>  /*-------------------------------------------------------------------------*/
> @@ -525,6 +528,22 @@ static inline int gadget_is_dualspeed(struct
> usb_gadget *g)
>  }
>
>  /**
> + * gadget_is_superspeed - return true if the hardware handles
> + * supperspeed
> + */
> +static inline int gadget_is_superspeed(struct usb_gadget *g)
> +{
> +#ifdef CONFIG_USB_GADGET_SUPERSPEED
> +     /* runtime test would check "g->is_superspeed" ... that might be
> +      * useful to work around hardware bugs, but is mostly pointless
> +      */
> +     return 1;
> +#else
> +     return 0;
> +#endif
> +}
> +
> +/**
>   * gadget_is_otg - return true iff the hardware is OTG-ready
>   * @g: controller that might have a Mini-AB connector
>   *
> --
> 1.6.3.3
>
> --
> Sent by an  consultant of the Qualcomm Innovation Center, Inc.
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
>
>


--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to