Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -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:
+49 −10
Original line number Diff line number Diff line
@@ -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 @@ get_config:
			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 @@ reset:

	/* 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 @@ reset:

	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,
+1 −1
Original line number Diff line number Diff line
@@ -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,
};

+118 −2
Original line number Diff line number Diff line
@@ -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;
}