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-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html