@@ -729,45 +729,73 @@ static int bos_desc(struct usb_composite_dev *cdev)
/* The SuperSpeedPlus USB Device Capability descriptor */
if (gadget_is_superspeed_plus(cdev->gadget)) {
struct usb_ssp_cap_descriptor *ssp_cap;
+ unsigned int ssac = 1;
+ unsigned int ssic = 0;
+ unsigned int min_ssid = 0;
+ int i;
+
+ if (cdev->gadget->ssac) {
+ ssac = cdev->gadget->ssac;
+
+ /*
+ * Paired RX and TX sublink speed attributes share
+ * the same SSID.
+ */
+ ssic = (ssac + 1) / 2 - 1;
+ min_ssid = cdev->gadget->min_speed_ssid;
+ }
ssp_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
bos->bNumDeviceCaps++;
- /*
- * Report typical values.
- */
-
- le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SSP_CAP_SIZE(1));
- ssp_cap->bLength = USB_DT_USB_SSP_CAP_SIZE(1);
+ le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SSP_CAP_SIZE(ssac));
+ ssp_cap->bLength = USB_DT_USB_SSP_CAP_SIZE(ssac);
ssp_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
ssp_cap->bDevCapabilityType = USB_SSP_CAP_TYPE;
ssp_cap->bReserved = 0;
ssp_cap->wReserved = 0;
ssp_cap->bmAttributes =
- cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_ATTRIBS, 1) |
- FIELD_PREP(USB_SSP_SUBLINK_SPEED_IDS, 0));
+ cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_ATTRIBS, ssac) |
+ FIELD_PREP(USB_SSP_SUBLINK_SPEED_IDS, ssic));
ssp_cap->wFunctionalitySupport =
- cpu_to_le16(FIELD_PREP(USB_SSP_MIN_SUBLINK_SPEED_ATTRIBUTE_ID, 0) |
+ cpu_to_le16(FIELD_PREP(USB_SSP_MIN_SUBLINK_SPEED_ATTRIBUTE_ID, min_ssid) |
FIELD_PREP(USB_SSP_MIN_RX_LANE_COUNT, 1) |
FIELD_PREP(USB_SSP_MIN_TX_LANE_COUNT, 1));
- ssp_cap->bmSublinkSpeedAttr[0] =
- cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_SSID, 0) |
- FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSE, USB_LSE_GBPS) |
- FIELD_PREP(USB_SSP_SUBLINK_SPEED_ST,
- USB_ST_SYMMETRIC_RX) |
- FIELD_PREP(USB_SSP_SUBLINK_SPEED_LP, USB_LP_SSP) |
- FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSM, 10));
-
- ssp_cap->bmSublinkSpeedAttr[1] =
- cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_SSID, 0) |
- FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSE, USB_LSE_GBPS) |
- FIELD_PREP(USB_SSP_SUBLINK_SPEED_ST,
- USB_ST_SYMMETRIC_TX) |
- FIELD_PREP(USB_SSP_SUBLINK_SPEED_LP, USB_LP_SSP) |
- FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSM, 10));
+ /*
+ * If the sublink speed attributes are not specified, then the
+ * default will be a pair symmetric RX/TX sublink speed
+ * attributes of 10 Gbps.
+ */
+ for (i = 0; i < ssac + 1; i++) {
+ struct usb_sublink_speed default_ssa;
+ struct usb_sublink_speed *ptr;
+
+ if (cdev->gadget->ssac) {
+ ptr = &cdev->gadget->sublink_speed[i];
+ } else {
+ default_ssa.id = i / 2;
+ default_ssa.protocol = USB_LP_SSP;
+ default_ssa.exponent = USB_LSE_GBPS;
+ default_ssa.mantissa = 10;
+
+ if (i % 2)
+ default_ssa.type = USB_ST_SYMMETRIC_TX;
+ else
+ default_ssa.type = USB_ST_SYMMETRIC_RX;
+
+ ptr = &default_ssa;
+ }
+
+ ssp_cap->bmSublinkSpeedAttr[i] =
+ cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_SSID, ptr->id) |
+ FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSE, ptr->exponent) |
+ FIELD_PREP(USB_SSP_SUBLINK_SPEED_ST, ptr->type) |
+ FIELD_PREP(USB_SSP_SUBLINK_SPEED_LP, ptr->protocol) |
+ FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSM, ptr->mantissa));
+ }
}
return le16_to_cpu(bos->wTotalLength);
Use the max sublink speed attributes reported in the gadget structure to write to the super-speed-plus BOS descriptor if available. Signed-off-by: Thinh Nguyen <thinhn@synopsys.com> --- drivers/usb/gadget/composite.c | 76 +++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 24 deletions(-)