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; | ||||
| 
 | ||||
| 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 @@ 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, | ||||
|  | ||||
| @ -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 New Issue
	
	Block a user