usb: gadget: add super speed support
This patch is to add usb gadget super speed support in common driver, including BOS descriptor and select the super speed descriptor from function driver. Reviewed-by: Ye Li <ye.li@nxp.com> Reviewed-by: Peter Chen <peter.chen@nxp.com> Tested-by: faqiang.zhu <faqiang.zhu@nxp.com> Signed-off-by: Li Jun <jun.li@nxp.com> Signed-off-by: Peng Fan <peng.fan@nxp.com>
This commit is contained in:
		
							parent
							
								
									42a594de14
								
							
						
					
					
						commit
						8745b9ebcc
					
				|  | @ -88,6 +88,8 @@ int usb_add_function(struct usb_configuration *config, | |||
| 		config->fullspeed = 1; | ||||
| 	if (!config->highspeed && function->hs_descriptors) | ||||
| 		config->highspeed = 1; | ||||
| 	if (!config->superspeed && function->ss_descriptors) | ||||
| 		config->superspeed = 1; | ||||
| 
 | ||||
| done: | ||||
| 	if (value) | ||||
|  | @ -223,7 +225,9 @@ static int config_buf(struct usb_configuration *config, | |||
| 
 | ||||
| 	/* add each function's descriptors */ | ||||
| 	list_for_each_entry(f, &config->functions, list) { | ||||
| 		if (speed == USB_SPEED_HIGH) | ||||
| 		if (speed == USB_SPEED_SUPER) | ||||
| 			descriptors = f->ss_descriptors; | ||||
| 		else if (speed == USB_SPEED_HIGH) | ||||
| 			descriptors = f->hs_descriptors; | ||||
| 		else | ||||
| 			descriptors = f->descriptors; | ||||
|  | @ -251,7 +255,9 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) | |||
| 	struct usb_configuration	*c; | ||||
| 	struct list_head		*pos; | ||||
| 
 | ||||
| 	if (gadget_is_dualspeed(gadget)) { | ||||
| 	if (gadget_is_superspeed(gadget)) { | ||||
| 		speed = gadget->speed; | ||||
| 	} else if (gadget_is_dualspeed(gadget)) { | ||||
| 		if (gadget->speed == USB_SPEED_HIGH) | ||||
| 			hs = 1; | ||||
| 		if (type == USB_DT_OTHER_SPEED_CONFIG) | ||||
|  | @ -275,7 +281,10 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) | |||
| 			continue; | ||||
| 
 | ||||
| check_config: | ||||
| 		if (speed == USB_SPEED_HIGH) { | ||||
| 		if (speed == USB_SPEED_SUPER) { | ||||
| 			if (!c->superspeed) | ||||
| 				continue; | ||||
| 		} else if (speed == USB_SPEED_HIGH) { | ||||
| 			if (!c->highspeed) | ||||
| 				continue; | ||||
| 		} else { | ||||
|  | @ -294,8 +303,12 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type) | |||
| 	struct usb_gadget		*gadget = cdev->gadget; | ||||
| 	unsigned			count = 0; | ||||
| 	int				hs = 0; | ||||
| 	int				ss = 0; | ||||
| 	struct usb_configuration	*c; | ||||
| 
 | ||||
| 	if (gadget->speed == USB_SPEED_SUPER) | ||||
| 		ss = 1; | ||||
| 
 | ||||
| 	if (gadget_is_dualspeed(gadget)) { | ||||
| 		if (gadget->speed == USB_SPEED_HIGH) | ||||
| 			hs = 1; | ||||
|  | @ -304,7 +317,10 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type) | |||
| 	} | ||||
| 	list_for_each_entry(c, &cdev->configs, list) { | ||||
| 		/* ignore configs that won't work at this speed */ | ||||
| 		if (hs) { | ||||
| 		if (ss) { | ||||
| 			if (!c->superspeed) | ||||
| 				continue; | ||||
| 		} else if (hs) { | ||||
| 			if (!c->highspeed) | ||||
| 				continue; | ||||
| 		} else { | ||||
|  | @ -388,6 +404,9 @@ static int set_config(struct usb_composite_dev *cdev, | |||
| 		     case USB_SPEED_HIGH: | ||||
| 			     speed = "high"; | ||||
| 			     break; | ||||
| 		     case USB_SPEED_SUPER: | ||||
| 			     speed = "super"; | ||||
| 			     break; | ||||
| 		     default: | ||||
| 			     speed = "?"; | ||||
| 			     break; | ||||
|  | @ -412,7 +431,9 @@ static int set_config(struct usb_composite_dev *cdev, | |||
| 		 * function's setup callback instead of the current | ||||
| 		 * configuration's setup callback. | ||||
| 		 */ | ||||
| 		if (gadget->speed == USB_SPEED_HIGH) | ||||
| 		if (gadget->speed == USB_SPEED_SUPER) | ||||
| 			descriptors = f->ss_descriptors; | ||||
| 		else if (gadget->speed == USB_SPEED_HIGH) | ||||
| 			descriptors = f->hs_descriptors; | ||||
| 		else | ||||
| 			descriptors = f->descriptors; | ||||
|  | @ -492,8 +513,9 @@ int usb_add_config(struct usb_composite_dev *cdev, | |||
| 		list_del(&config->list); | ||||
| 		config->cdev = NULL; | ||||
| 	} else { | ||||
| 		debug("cfg %d/%p speeds:%s%s\n", | ||||
| 		debug("cfg %d/%p speeds:%s%s%s\n", | ||||
| 			config->bConfigurationValue, config, | ||||
| 			config->superspeed ? " super" : "", | ||||
| 			config->highspeed ? " high" : "", | ||||
| 			config->fullspeed | ||||
| 				? (gadget_is_dualspeed(cdev->gadget) | ||||
|  | @ -751,6 +773,7 @@ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req) | |||
| static int bos_desc(struct usb_composite_dev *cdev) | ||||
| { | ||||
| 	struct usb_ext_cap_descriptor   *usb_ext; | ||||
| 	struct usb_dcd_config_params	dcd_config_params; | ||||
| 	struct usb_bos_descriptor       *bos = cdev->req->buf; | ||||
| 
 | ||||
| 	bos->bLength = USB_DT_BOS_SIZE; | ||||
|  | @ -794,9 +817,19 @@ static int bos_desc(struct usb_composite_dev *cdev) | |||
| 				    USB_HIGH_SPEED_OPERATION | | ||||
| 				    USB_5GBPS_OPERATION); | ||||
| 		ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION; | ||||
| 		ss_cap->bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT; | ||||
| 		ss_cap->bU2DevExitLat = | ||||
| 			cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT); | ||||
| 
 | ||||
| 		/* Get Controller configuration */ | ||||
| 		if (cdev->gadget->ops->get_config_params) { | ||||
| 			cdev->gadget->ops->get_config_params( | ||||
| 				&dcd_config_params); | ||||
| 		} else { | ||||
| 			dcd_config_params.bU1devExitLat = | ||||
| 				USB_DEFAULT_U1_DEV_EXIT_LAT; | ||||
| 			dcd_config_params.bU2DevExitLat = | ||||
| 				cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT); | ||||
| 		} | ||||
| 		ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat; | ||||
| 		ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat; | ||||
| 	} | ||||
| 	return le16_to_cpu(bos->wTotalLength); | ||||
| } | ||||
|  | @ -999,32 +1032,28 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) | |||
| 			cdev->desc.bNumConfigurations = | ||||
| 				count_configs(cdev, USB_DT_DEVICE); | ||||
| 
 | ||||
| 			/*
 | ||||
| 			 * If the speed is Super speed, then the supported | ||||
| 			 * max packet size is 512 and it should be sent as | ||||
| 			 * exponent of 2. So, 9(2^9=512) should be filled in | ||||
| 			 * bMaxPacketSize0. Also fill USB version as 3.0 | ||||
| 			 * if speed is Super speed. | ||||
| 			 */ | ||||
| 			if (cdev->gadget->speed == USB_SPEED_SUPER) { | ||||
| 			cdev->desc.bMaxPacketSize0 = | ||||
| 				cdev->gadget->ep0->maxpacket; | ||||
| 			if (gadget->speed >= USB_SPEED_SUPER) { | ||||
| 				cdev->desc.bcdUSB = cpu_to_le16(0x0310); | ||||
| 				cdev->desc.bMaxPacketSize0 = 9; | ||||
| 				cdev->desc.bcdUSB = cpu_to_le16(0x0300); | ||||
| 			} else { | ||||
| 				cdev->desc.bMaxPacketSize0 = | ||||
| 					cdev->gadget->ep0->maxpacket; | ||||
| 				cdev->desc.bcdUSB = cpu_to_le16(0x0200); | ||||
| 			} | ||||
| 			value = min(w_length, (u16) sizeof cdev->desc); | ||||
| 			memcpy(req->buf, &cdev->desc, value); | ||||
| 			break; | ||||
| 		case USB_DT_DEVICE_QUALIFIER: | ||||
| 			if (!gadget_is_dualspeed(gadget)) | ||||
| 			if (!gadget_is_dualspeed(gadget) || | ||||
| 			    gadget->speed >= USB_SPEED_SUPER) | ||||
| 				break; | ||||
| 			device_qual(cdev); | ||||
| 			value = min_t(int, w_length, | ||||
| 				      sizeof(struct usb_qualifier_descriptor)); | ||||
| 			break; | ||||
| 		case USB_DT_OTHER_SPEED_CONFIG: | ||||
| 			if (!gadget_is_dualspeed(gadget)) | ||||
| 			if (!gadget_is_dualspeed(gadget) || | ||||
| 			    gadget->speed >= USB_SPEED_SUPER) | ||||
| 				break; | ||||
| 
 | ||||
| 		case USB_DT_CONFIG: | ||||
|  | @ -1039,10 +1068,16 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) | |||
| 				value = min(w_length, (u16) value); | ||||
| 			break; | ||||
| 		case USB_DT_BOS: | ||||
| 			if (gadget_is_superspeed(cdev->gadget)) | ||||
| 			/*
 | ||||
| 			 * Super speed connection should support BOS, and | ||||
| 			 * USB compliance test (USB 2.0 Command Verifier) | ||||
| 			 * also issues this request, return for now for | ||||
| 			 * USB 2.0 connection. | ||||
| 			 */ | ||||
| 			if (gadget->speed >= USB_SPEED_SUPER) { | ||||
| 				value = bos_desc(cdev); | ||||
| 			if (value >= 0) | ||||
| 				value = min(w_length, (u16)value); | ||||
| 			} | ||||
| 			break; | ||||
| 		default: | ||||
| 			goto unknown; | ||||
|  | @ -1421,7 +1456,7 @@ composite_resume(struct usb_gadget *gadget) | |||
| } | ||||
| 
 | ||||
| static struct usb_gadget_driver composite_driver = { | ||||
| 	.speed		= USB_SPEED_HIGH, | ||||
| 	.speed		= USB_SPEED_SUPER, | ||||
| 
 | ||||
| 	.bind		= composite_bind, | ||||
| 	.unbind         = composite_unbind, | ||||
|  |  | |||
|  | @ -146,6 +146,7 @@ struct usb_function { | |||
| 	struct usb_gadget_strings	**strings; | ||||
| 	struct usb_descriptor_header	**descriptors; | ||||
| 	struct usb_descriptor_header	**hs_descriptors; | ||||
| 	struct usb_descriptor_header    **ss_descriptors; | ||||
| 
 | ||||
| 	struct usb_configuration	*config; | ||||
| 
 | ||||
|  | @ -279,6 +280,7 @@ struct usb_configuration { | |||
| 	u8			next_interface_id; | ||||
| 	unsigned		highspeed:1; | ||||
| 	unsigned		fullspeed:1; | ||||
| 	unsigned		superspeed:1; | ||||
| 	struct usb_function	*interface[MAX_CONFIG_INTERFACES]; | ||||
| }; | ||||
| 
 | ||||
|  | @ -292,6 +294,7 @@ int usb_add_config(struct usb_composite_dev *, | |||
|  *	identifiers. | ||||
|  * @strings: tables of strings, keyed by identifiers assigned during bind() | ||||
|  *	and language IDs provided in control requests | ||||
|  * @max_speed: Highest speed the driver supports. | ||||
|  * @bind: (REQUIRED) Used to allocate resources that are shared across the | ||||
|  *	whole device, such as string IDs, and add its configurations using | ||||
|  *	@usb_add_config().  This may fail by returning a negative errno | ||||
|  | @ -319,6 +322,7 @@ struct usb_composite_driver { | |||
| 	const char				*name; | ||||
| 	const struct usb_device_descriptor	*dev; | ||||
| 	struct usb_gadget_strings		**strings; | ||||
| 	enum usb_device_speed			max_speed; | ||||
| 
 | ||||
| 	/* REVISIT:  bind() functions can be marked __init, which
 | ||||
| 	 * makes trouble for section mismatch analysis.  See if | ||||
|  |  | |||
|  | @ -449,6 +449,11 @@ static inline void usb_ep_fifo_flush(struct usb_ep *ep) | |||
| 
 | ||||
| /*-------------------------------------------------------------------------*/ | ||||
| 
 | ||||
| struct usb_dcd_config_params { | ||||
| 	__u8  bU1devExitLat;	/* U1 Device exit Latency */ | ||||
| 	__le16 bU2DevExitLat;	/* U2 Device exit Latency */ | ||||
| }; | ||||
| 
 | ||||
| struct usb_gadget; | ||||
| struct usb_gadget_driver; | ||||
| 
 | ||||
|  | @ -464,6 +469,7 @@ struct usb_gadget_ops { | |||
| 	int	(*pullup) (struct usb_gadget *, int is_on); | ||||
| 	int	(*ioctl)(struct usb_gadget *, | ||||
| 				unsigned code, unsigned long param); | ||||
| 	void	(*get_config_params)(struct usb_dcd_config_params *); | ||||
| 	int	(*udc_start)(struct usb_gadget *, | ||||
| 			     struct usb_gadget_driver *); | ||||
| 	int	(*udc_stop)(struct usb_gadget *); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue