Commit 4bb99b7c authored by Felipe Balbi's avatar Felipe Balbi

usb: gadget: storage: add superspeed support

this patch adds superspeed descriptors for the
storage gadgets.
Acked-by: default avatarMichal Nazarewicz <mina86@mina86.com>
Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 089b837a
......@@ -3023,6 +3023,28 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
}
}
if (gadget_is_superspeed(gadget)) {
unsigned max_burst;
/* Calculate bMaxBurst, we know packet size is 1024 */
max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15);
fsg_ss_bulk_in_desc.bEndpointAddress =
fsg_fs_bulk_in_desc.bEndpointAddress;
fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
fsg_ss_bulk_out_desc.bEndpointAddress =
fsg_fs_bulk_out_desc.bEndpointAddress;
fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
f->ss_descriptors = usb_copy_descriptors(fsg_ss_function);
if (unlikely(!f->ss_descriptors)) {
usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->descriptors);
return -ENOMEM;
}
}
return 0;
autoconf_fail:
......
......@@ -586,7 +586,19 @@ dev_qualifier = {
.bNumConfigurations = 1,
};
static int populate_bos(struct fsg_dev *fsg, u8 *buf)
{
memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE);
buf += USB_DT_BOS_SIZE;
memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE);
buf += USB_DT_USB_EXT_CAP_SIZE;
memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE);
return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE
+ USB_DT_USB_EXT_CAP_SIZE;
}
/*
* Config descriptors must agree with the code that sets configurations
......@@ -935,7 +947,8 @@ static int standard_setup_req(struct fsg_dev *fsg,
break;
case USB_DT_DEVICE_QUALIFIER:
VDBG(fsg, "get device qualifier\n");
if (!gadget_is_dualspeed(fsg->gadget))
if (!gadget_is_dualspeed(fsg->gadget) ||
fsg->gadget->speed == USB_SPEED_SUPER)
break;
/*
* Assume ep0 uses the same maxpacket value for both
......@@ -948,7 +961,8 @@ static int standard_setup_req(struct fsg_dev *fsg,
case USB_DT_OTHER_SPEED_CONFIG:
VDBG(fsg, "get other-speed config descriptor\n");
if (!gadget_is_dualspeed(fsg->gadget))
if (!gadget_is_dualspeed(fsg->gadget) ||
fsg->gadget->speed == USB_SPEED_SUPER)
break;
goto get_config;
case USB_DT_CONFIG:
......@@ -967,7 +981,15 @@ static int standard_setup_req(struct fsg_dev *fsg,
value = usb_gadget_get_string(&fsg_stringtab,
w_value & 0xff, req->buf);
break;
case USB_DT_BOS:
VDBG(fsg, "get bos descriptor\n");
if (gadget_is_superspeed(fsg->gadget))
value = populate_bos(fsg, req->buf);
break;
}
break;
/* One config, two speeds */
......@@ -2777,13 +2799,15 @@ static int do_set_interface(struct fsg_dev *fsg, int altsetting)
/* Enable the endpoints */
d = fsg_ep_desc(fsg->gadget,
&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc,
&fsg_ss_bulk_in_desc);
if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
goto reset;
fsg->bulk_in_enabled = 1;
d = fsg_ep_desc(fsg->gadget,
&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc,
&fsg_ss_bulk_out_desc);
if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
goto reset;
fsg->bulk_out_enabled = 1;
......@@ -2792,7 +2816,8 @@ static int do_set_interface(struct fsg_dev *fsg, int altsetting)
if (transport_is_cbi()) {
d = fsg_ep_desc(fsg->gadget,
&fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc);
&fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc,
&fsg_ss_intr_in_desc);
if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0)
goto reset;
fsg->intr_in_enabled = 1;
......@@ -3424,6 +3449,24 @@ static int __init fsg_bind(struct usb_gadget *gadget)
fsg_fs_intr_in_desc.bEndpointAddress;
}
if (gadget_is_superspeed(gadget)) {
unsigned max_burst;
fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL;
/* Calculate bMaxBurst, we know packet size is 1024 */
max_burst = min_t(unsigned, mod_data.buflen / 1024, 15);
/* Assume endpoint addresses are the same for both speeds */
fsg_ss_bulk_in_desc.bEndpointAddress =
fsg_fs_bulk_in_desc.bEndpointAddress;
fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
fsg_ss_bulk_out_desc.bEndpointAddress =
fsg_fs_bulk_out_desc.bEndpointAddress;
fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
}
if (gadget_is_otg(gadget))
fsg_otg_desc.bmAttributes |= USB_OTG_HNP;
......@@ -3540,11 +3583,7 @@ static void fsg_resume(struct usb_gadget *gadget)
/*-------------------------------------------------------------------------*/
static struct usb_gadget_driver fsg_driver = {
#ifdef CONFIG_USB_GADGET_DUALSPEED
.speed = USB_SPEED_HIGH,
#else
.speed = USB_SPEED_FULL,
#endif
.speed = USB_SPEED_SUPER,
.function = (char *) fsg_string_product,
.unbind = fsg_unbind,
.disconnect = fsg_disconnect,
......
......@@ -160,7 +160,7 @@ static struct usb_composite_driver msg_driver = {
.name = "g_mass_storage",
.dev = &msg_device_desc,
.iProduct = DRIVER_DESC,
.max_speed = USB_SPEED_HIGH,
.max_speed = USB_SPEED_SUPER,
.needs_serial = 1,
};
......
......@@ -515,12 +515,128 @@ static struct usb_descriptor_header *fsg_hs_function[] = {
NULL,
};
static struct usb_endpoint_descriptor
fsg_ss_bulk_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024),
};
static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = {
.bLength = sizeof(fsg_ss_bulk_in_comp_desc),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
/*.bMaxBurst = DYNAMIC, */
};
static struct usb_endpoint_descriptor
fsg_ss_bulk_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024),
};
static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
.bLength = sizeof(fsg_ss_bulk_in_comp_desc),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
/*.bMaxBurst = DYNAMIC, */
};
#ifndef FSG_NO_INTR_EP
static struct usb_endpoint_descriptor
fsg_ss_intr_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
/* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = cpu_to_le16(2),
.bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */
};
static struct usb_ss_ep_comp_descriptor fsg_ss_intr_in_comp_desc = {
.bLength = sizeof(fsg_ss_bulk_in_comp_desc),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
.wBytesPerInterval = cpu_to_le16(2),
};
#ifndef FSG_NO_OTG
# define FSG_SS_FUNCTION_PRE_EP_ENTRIES 2
#else
# define FSG_SS_FUNCTION_PRE_EP_ENTRIES 1
#endif
#endif
static __maybe_unused struct usb_ext_cap_descriptor fsg_ext_cap_desc = {
.bLength = USB_DT_USB_EXT_CAP_SIZE,
.bDescriptorType = USB_DT_DEVICE_CAPABILITY,
.bDevCapabilityType = USB_CAP_TYPE_EXT,
.bmAttributes = cpu_to_le32(USB_LPM_SUPPORT),
};
static __maybe_unused struct usb_ss_cap_descriptor fsg_ss_cap_desc = {
.bLength = USB_DT_USB_SS_CAP_SIZE,
.bDescriptorType = USB_DT_DEVICE_CAPABILITY,
.bDevCapabilityType = USB_SS_CAP_TYPE,
/* .bmAttributes = LTM is not supported yet */
.wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION
| USB_FULL_SPEED_OPERATION
| USB_HIGH_SPEED_OPERATION
| USB_5GBPS_OPERATION),
.bFunctionalitySupport = USB_LOW_SPEED_OPERATION,
.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT,
.bU2DevExitLat = USB_DEFAULT_U2_DEV_EXIT_LAT,
};
static __maybe_unused struct usb_bos_descriptor fsg_bos_desc = {
.bLength = USB_DT_BOS_SIZE,
.bDescriptorType = USB_DT_BOS,
.wTotalLength = USB_DT_BOS_SIZE
+ USB_DT_USB_EXT_CAP_SIZE
+ USB_DT_USB_SS_CAP_SIZE,
.bNumDeviceCaps = 2,
};
static struct usb_descriptor_header *fsg_ss_function[] = {
#ifndef FSG_NO_OTG
(struct usb_descriptor_header *) &fsg_otg_desc,
#endif
(struct usb_descriptor_header *) &fsg_intf_desc,
(struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
(struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc,
(struct usb_descriptor_header *) &fsg_ss_bulk_out_desc,
(struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc,
#ifndef FSG_NO_INTR_EP
(struct usb_descriptor_header *) &fsg_ss_intr_in_desc,
(struct usb_descriptor_header *) &fsg_ss_intr_in_comp_desc,
#endif
NULL,
};
/* Maxpacket and other transfer characteristics vary by speed. */
static __maybe_unused struct usb_endpoint_descriptor *
fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
struct usb_endpoint_descriptor *hs)
struct usb_endpoint_descriptor *hs,
struct usb_endpoint_descriptor *ss)
{
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
return ss;
else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return hs;
return fs;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment