Re: [RFC/PATCH 2/2] usb:gadget: Add SuperSpeed support to the Gadget Framework

From: tlinder
Date: Wed Oct 06 2010 - 15:29:20 EST


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

> From: Tatyana Linder <tlinder@xxxxxxxxxxxxxx>
>
> 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 <tlinder@xxxxxxxxxxxxxx>
> ---
> 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-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/