usb: gadget: storage: add superspeed support
this patch adds superspeed descriptors for the storage gadgets. Acked-by: Michal Nazarewicz <mina86@mina86.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
parent
089b837a39
commit
4bb99b7c82
4 changed files with 190 additions and 13 deletions
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue