mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-25 16:50:53 +07:00
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
@ -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;
|
return 0;
|
||||||
|
|
||||||
autoconf_fail:
|
autoconf_fail:
|
||||||
|
@ -586,7 +586,19 @@ dev_qualifier = {
|
|||||||
.bNumConfigurations = 1,
|
.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
|
* Config descriptors must agree with the code that sets configurations
|
||||||
@ -935,7 +947,8 @@ static int standard_setup_req(struct fsg_dev *fsg,
|
|||||||
break;
|
break;
|
||||||
case USB_DT_DEVICE_QUALIFIER:
|
case USB_DT_DEVICE_QUALIFIER:
|
||||||
VDBG(fsg, "get device qualifier\n");
|
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;
|
break;
|
||||||
/*
|
/*
|
||||||
* Assume ep0 uses the same maxpacket value for both
|
* 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:
|
case USB_DT_OTHER_SPEED_CONFIG:
|
||||||
VDBG(fsg, "get other-speed config descriptor\n");
|
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;
|
break;
|
||||||
goto get_config;
|
goto get_config;
|
||||||
case USB_DT_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,
|
value = usb_gadget_get_string(&fsg_stringtab,
|
||||||
w_value & 0xff, req->buf);
|
w_value & 0xff, req->buf);
|
||||||
break;
|
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;
|
break;
|
||||||
|
|
||||||
/* One config, two speeds */
|
/* One config, two speeds */
|
||||||
@ -2777,13 +2799,15 @@ static int do_set_interface(struct fsg_dev *fsg, int altsetting)
|
|||||||
|
|
||||||
/* Enable the endpoints */
|
/* Enable the endpoints */
|
||||||
d = fsg_ep_desc(fsg->gadget,
|
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)
|
if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
|
||||||
goto reset;
|
goto reset;
|
||||||
fsg->bulk_in_enabled = 1;
|
fsg->bulk_in_enabled = 1;
|
||||||
|
|
||||||
d = fsg_ep_desc(fsg->gadget,
|
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)
|
if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
|
||||||
goto reset;
|
goto reset;
|
||||||
fsg->bulk_out_enabled = 1;
|
fsg->bulk_out_enabled = 1;
|
||||||
@ -2792,7 +2816,8 @@ static int do_set_interface(struct fsg_dev *fsg, int altsetting)
|
|||||||
|
|
||||||
if (transport_is_cbi()) {
|
if (transport_is_cbi()) {
|
||||||
d = fsg_ep_desc(fsg->gadget,
|
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)
|
if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0)
|
||||||
goto reset;
|
goto reset;
|
||||||
fsg->intr_in_enabled = 1;
|
fsg->intr_in_enabled = 1;
|
||||||
@ -3424,6 +3449,24 @@ static int __init fsg_bind(struct usb_gadget *gadget)
|
|||||||
fsg_fs_intr_in_desc.bEndpointAddress;
|
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))
|
if (gadget_is_otg(gadget))
|
||||||
fsg_otg_desc.bmAttributes |= USB_OTG_HNP;
|
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 = {
|
static struct usb_gadget_driver fsg_driver = {
|
||||||
#ifdef CONFIG_USB_GADGET_DUALSPEED
|
.speed = USB_SPEED_SUPER,
|
||||||
.speed = USB_SPEED_HIGH,
|
|
||||||
#else
|
|
||||||
.speed = USB_SPEED_FULL,
|
|
||||||
#endif
|
|
||||||
.function = (char *) fsg_string_product,
|
.function = (char *) fsg_string_product,
|
||||||
.unbind = fsg_unbind,
|
.unbind = fsg_unbind,
|
||||||
.disconnect = fsg_disconnect,
|
.disconnect = fsg_disconnect,
|
||||||
|
@ -160,7 +160,7 @@ static struct usb_composite_driver msg_driver = {
|
|||||||
.name = "g_mass_storage",
|
.name = "g_mass_storage",
|
||||||
.dev = &msg_device_desc,
|
.dev = &msg_device_desc,
|
||||||
.iProduct = DRIVER_DESC,
|
.iProduct = DRIVER_DESC,
|
||||||
.max_speed = USB_SPEED_HIGH,
|
.max_speed = USB_SPEED_SUPER,
|
||||||
.needs_serial = 1,
|
.needs_serial = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -515,12 +515,128 @@ static struct usb_descriptor_header *fsg_hs_function[] = {
|
|||||||
NULL,
|
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. */
|
/* Maxpacket and other transfer characteristics vary by speed. */
|
||||||
static __maybe_unused struct usb_endpoint_descriptor *
|
static __maybe_unused struct usb_endpoint_descriptor *
|
||||||
fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
|
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 hs;
|
||||||
return fs;
|
return fs;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user