forked from mirrors/linux
		
	usb: gadget: add streams support to the gadget framework
This patch defines necessary fields to support streaming for USB3.0. It implements a new function, called usb_ep_autoconfig_ss(), to be used instead of the existing usb_ep_autoconfig() when working in SuperSpeed mode and there is a need to search for an endpoint according to the number of required streams. [ balbi@ti.com : slight changes to commit log ] Signed-off-by: Maya Erez <merez@codeaurora.org> Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org> Signed-off-by: Felipe Balbi <balbi@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
		
							parent
							
								
									7c884fe4d7
								
							
						
					
					
						commit
						a59d6b91cb
					
				
					 2 changed files with 150 additions and 62 deletions
				
			
		|  | @ -63,13 +63,16 @@ static int | |||
| ep_matches ( | ||||
| 	struct usb_gadget		*gadget, | ||||
| 	struct usb_ep			*ep, | ||||
| 	struct usb_endpoint_descriptor	*desc | ||||
| 	struct usb_endpoint_descriptor	*desc, | ||||
| 	struct usb_ss_ep_comp_descriptor *ep_comp | ||||
| ) | ||||
| { | ||||
| 	u8		type; | ||||
| 	const char	*tmp; | ||||
| 	u16		max; | ||||
| 
 | ||||
| 	int		num_req_streams = 0; | ||||
| 
 | ||||
| 	/* endpoint already claimed? */ | ||||
| 	if (NULL != ep->driver_data) | ||||
| 		return 0; | ||||
|  | @ -128,6 +131,22 @@ ep_matches ( | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Get the number of required streams from the EP companion | ||||
| 	 * descriptor and see if the EP matches it | ||||
| 	 */ | ||||
| 	if (usb_endpoint_xfer_bulk(desc)) { | ||||
| 		if (ep_comp) { | ||||
| 			num_req_streams = ep_comp->bmAttributes & 0x1f; | ||||
| 			if (num_req_streams > ep->max_streams) | ||||
| 				return 0; | ||||
| 			/* Update the ep_comp descriptor if needed */ | ||||
| 			if (num_req_streams != ep->max_streams) | ||||
| 				ep_comp->bmAttributes = ep->max_streams; | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If the protocol driver hasn't yet decided on wMaxPacketSize | ||||
| 	 * and wants to know the maximum possible, provide the info. | ||||
|  | @ -208,7 +227,120 @@ find_ep (struct usb_gadget *gadget, const char *name) | |||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * usb_ep_autoconfig - choose an endpoint matching the descriptor | ||||
|  * usb_ep_autoconfig_ss() - choose an endpoint matching the ep | ||||
|  * descriptor and ep companion descriptor | ||||
|  * @gadget: The device to which the endpoint must belong. | ||||
|  * @desc: Endpoint descriptor, with endpoint direction and transfer mode | ||||
|  *    initialized.  For periodic transfers, the maximum packet | ||||
|  *    size must also be initialized.  This is modified on | ||||
|  *    success. | ||||
|  * @ep_comp: Endpoint companion descriptor, with the required | ||||
|  *    number of streams. Will be modified when the chosen EP | ||||
|  *    supports a different number of streams. | ||||
|  * | ||||
|  * This routine replaces the usb_ep_autoconfig when needed | ||||
|  * superspeed enhancments. If such enhancemnets are required, | ||||
|  * the FD should call usb_ep_autoconfig_ss directly and provide | ||||
|  * the additional ep_comp parameter. | ||||
|  * | ||||
|  * By choosing an endpoint to use with the specified descriptor, | ||||
|  * this routine simplifies writing gadget drivers that work with | ||||
|  * multiple USB device controllers.  The endpoint would be | ||||
|  * passed later to usb_ep_enable(), along with some descriptor. | ||||
|  * | ||||
|  * That second descriptor won't always be the same as the first one. | ||||
|  * For example, isochronous endpoints can be autoconfigured for high | ||||
|  * bandwidth, and then used in several lower bandwidth altsettings. | ||||
|  * Also, high and full speed descriptors will be different. | ||||
|  * | ||||
|  * Be sure to examine and test the results of autoconfiguration | ||||
|  * on your hardware.  This code may not make the best choices | ||||
|  * about how to use the USB controller, and it can't know all | ||||
|  * the restrictions that may apply. Some combinations of driver | ||||
|  * and hardware won't be able to autoconfigure. | ||||
|  * | ||||
|  * On success, this returns an un-claimed usb_ep, and modifies the endpoint | ||||
|  * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value | ||||
|  * is initialized as if the endpoint were used at full speed and | ||||
|  * the bmAttribute field in the ep companion descriptor is | ||||
|  * updated with the assigned number of streams if it is | ||||
|  * different from the original value. To prevent the endpoint | ||||
|  * from being returned by a later autoconfig call, claim it by | ||||
|  * assigning ep->driver_data to some non-null value. | ||||
|  * | ||||
|  * On failure, this returns a null endpoint descriptor. | ||||
|  */ | ||||
| struct usb_ep *usb_ep_autoconfig_ss( | ||||
| 	struct usb_gadget		*gadget, | ||||
| 	struct usb_endpoint_descriptor	*desc, | ||||
| 	struct usb_ss_ep_comp_descriptor *ep_comp | ||||
| ) | ||||
| { | ||||
| 	struct usb_ep	*ep; | ||||
| 	u8		type; | ||||
| 
 | ||||
| 	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; | ||||
| 
 | ||||
| 	/* First, apply chip-specific "best usage" knowledge.
 | ||||
| 	 * This might make a good usb_gadget_ops hook ... | ||||
| 	 */ | ||||
| 	if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) { | ||||
| 		/* ep-e, ep-f are PIO with only 64 byte fifos */ | ||||
| 		ep = find_ep (gadget, "ep-e"); | ||||
| 		if (ep && ep_matches(gadget, ep, desc, ep_comp)) | ||||
| 			return ep; | ||||
| 		ep = find_ep (gadget, "ep-f"); | ||||
| 		if (ep && ep_matches(gadget, ep, desc, ep_comp)) | ||||
| 			return ep; | ||||
| 
 | ||||
| 	} else if (gadget_is_goku (gadget)) { | ||||
| 		if (USB_ENDPOINT_XFER_INT == type) { | ||||
| 			/* single buffering is enough */ | ||||
| 			ep = find_ep(gadget, "ep3-bulk"); | ||||
| 			if (ep && ep_matches(gadget, ep, desc, ep_comp)) | ||||
| 				return ep; | ||||
| 		} else if (USB_ENDPOINT_XFER_BULK == type | ||||
| 				&& (USB_DIR_IN & desc->bEndpointAddress)) { | ||||
| 			/* DMA may be available */ | ||||
| 			ep = find_ep(gadget, "ep2-bulk"); | ||||
| 			if (ep && ep_matches(gadget, ep, desc, | ||||
| 					      ep_comp)) | ||||
| 				return ep; | ||||
| 		} | ||||
| 
 | ||||
| #ifdef CONFIG_BLACKFIN | ||||
| 	} else if (gadget_is_musbhdrc(gadget)) { | ||||
| 		if ((USB_ENDPOINT_XFER_BULK == type) || | ||||
| 		    (USB_ENDPOINT_XFER_ISOC == type)) { | ||||
| 			if (USB_DIR_IN & desc->bEndpointAddress) | ||||
| 				ep = find_ep (gadget, "ep5in"); | ||||
| 			else | ||||
| 				ep = find_ep (gadget, "ep6out"); | ||||
| 		} else if (USB_ENDPOINT_XFER_INT == type) { | ||||
| 			if (USB_DIR_IN & desc->bEndpointAddress) | ||||
| 				ep = find_ep(gadget, "ep1in"); | ||||
| 			else | ||||
| 				ep = find_ep(gadget, "ep2out"); | ||||
| 		} else | ||||
| 			ep = NULL; | ||||
| 		if (ep && ep_matches(gadget, ep, desc, ep_comp)) | ||||
| 			return ep; | ||||
| #endif | ||||
| 	} | ||||
| 
 | ||||
| 	/* Second, look at endpoints until an unclaimed one looks usable */ | ||||
| 	list_for_each_entry (ep, &gadget->ep_list, ep_list) { | ||||
| 		if (ep_matches(gadget, ep, desc, ep_comp)) | ||||
| 			return ep; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Fail */ | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * usb_ep_autoconfig() - choose an endpoint matching the | ||||
|  * descriptor | ||||
|  * @gadget: The device to which the endpoint must belong. | ||||
|  * @desc: Endpoint descriptor, with endpoint direction and transfer mode | ||||
|  *	initialized.  For periodic transfers, the maximum packet | ||||
|  | @ -237,72 +369,15 @@ find_ep (struct usb_gadget *gadget, const char *name) | |||
|  * | ||||
|  * On failure, this returns a null endpoint descriptor. | ||||
|  */ | ||||
| struct usb_ep *usb_ep_autoconfig ( | ||||
| struct usb_ep *usb_ep_autoconfig( | ||||
| 	struct usb_gadget		*gadget, | ||||
| 	struct usb_endpoint_descriptor	*desc | ||||
| ) | ||||
| { | ||||
| 	struct usb_ep	*ep; | ||||
| 	u8		type; | ||||
| 
 | ||||
| 	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; | ||||
| 
 | ||||
| 	/* First, apply chip-specific "best usage" knowledge.
 | ||||
| 	 * This might make a good usb_gadget_ops hook ... | ||||
| 	 */ | ||||
| 	if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) { | ||||
| 		/* ep-e, ep-f are PIO with only 64 byte fifos */ | ||||
| 		ep = find_ep (gadget, "ep-e"); | ||||
| 		if (ep && ep_matches (gadget, ep, desc)) | ||||
| 			return ep; | ||||
| 		ep = find_ep (gadget, "ep-f"); | ||||
| 		if (ep && ep_matches (gadget, ep, desc)) | ||||
| 			return ep; | ||||
| 
 | ||||
| 	} else if (gadget_is_goku (gadget)) { | ||||
| 		if (USB_ENDPOINT_XFER_INT == type) { | ||||
| 			/* single buffering is enough */ | ||||
| 			ep = find_ep (gadget, "ep3-bulk"); | ||||
| 			if (ep && ep_matches (gadget, ep, desc)) | ||||
| 				return ep; | ||||
| 		} else if (USB_ENDPOINT_XFER_BULK == type | ||||
| 				&& (USB_DIR_IN & desc->bEndpointAddress)) { | ||||
| 			/* DMA may be available */ | ||||
| 			ep = find_ep (gadget, "ep2-bulk"); | ||||
| 			if (ep && ep_matches (gadget, ep, desc)) | ||||
| 				return ep; | ||||
| 		} | ||||
| 
 | ||||
| #ifdef CONFIG_BLACKFIN | ||||
| 	} else if (gadget_is_musbhdrc(gadget)) { | ||||
| 		if ((USB_ENDPOINT_XFER_BULK == type) || | ||||
| 		    (USB_ENDPOINT_XFER_ISOC == type)) { | ||||
| 			if (USB_DIR_IN & desc->bEndpointAddress) | ||||
| 				ep = find_ep (gadget, "ep5in"); | ||||
| 			else | ||||
| 				ep = find_ep (gadget, "ep6out"); | ||||
| 		} else if (USB_ENDPOINT_XFER_INT == type) { | ||||
| 			if (USB_DIR_IN & desc->bEndpointAddress) | ||||
| 				ep = find_ep(gadget, "ep1in"); | ||||
| 			else | ||||
| 				ep = find_ep(gadget, "ep2out"); | ||||
| 		} else | ||||
| 			ep = NULL; | ||||
| 		if (ep && ep_matches (gadget, ep, desc)) | ||||
| 			return ep; | ||||
| #endif | ||||
| 	} | ||||
| 
 | ||||
| 	/* Second, look at endpoints until an unclaimed one looks usable */ | ||||
| 	list_for_each_entry (ep, &gadget->ep_list, ep_list) { | ||||
| 		if (ep_matches (gadget, ep, desc)) | ||||
| 			return ep; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Fail */ | ||||
| 	return NULL; | ||||
| 	return usb_ep_autoconfig_ss(gadget, desc, NULL); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
|  * usb_ep_autoconfig_reset - reset endpoint autoconfig state | ||||
|  * @gadget: device for which autoconfig state will be reset | ||||
|  |  | |||
|  | @ -28,6 +28,7 @@ struct usb_ep; | |||
|  *	field, and the usb controller needs one, it is responsible | ||||
|  *	for mapping and unmapping the buffer. | ||||
|  * @length: Length of that data | ||||
|  * @stream_id: The stream id, when USB3.0 bulk streams are being used | ||||
|  * @no_interrupt: If true, hints that no completion irq is needed. | ||||
|  *	Helpful sometimes with deep request queues that are handled | ||||
|  *	directly by DMA controllers. | ||||
|  | @ -82,6 +83,7 @@ struct usb_request { | |||
| 	unsigned		length; | ||||
| 	dma_addr_t		dma; | ||||
| 
 | ||||
| 	unsigned		stream_id:16; | ||||
| 	unsigned		no_interrupt:1; | ||||
| 	unsigned		zero:1; | ||||
| 	unsigned		short_not_ok:1; | ||||
|  | @ -132,11 +134,15 @@ struct usb_ep_ops { | |||
|  * @maxpacket:The maximum packet size used on this endpoint.  The initial | ||||
|  *	value can sometimes be reduced (hardware allowing), according to | ||||
|  *      the endpoint descriptor used to configure the endpoint. | ||||
|  * @max_streams: The maximum number of streams supported | ||||
|  *	by this EP (0 - 16, actual number is 2^n) | ||||
|  * @driver_data:for use by the gadget driver. | ||||
|  * @address: used to identify the endpoint when finding descriptor that | ||||
|  *	matches connection speed | ||||
|  * @desc: endpoint descriptor.  This pointer is set before the endpoint is | ||||
|  *	enabled and remains valid until the endpoint is disabled. | ||||
|  * @comp_desc: In case of SuperSpeed support, this is the endpoint companion | ||||
|  *	descriptor that is used to configure the endpoint | ||||
|  * | ||||
|  * the bus controller driver lists all the general purpose endpoints in | ||||
|  * gadget->ep_list.  the control endpoint (gadget->ep0) is not in that list, | ||||
|  | @ -149,8 +155,10 @@ struct usb_ep { | |||
| 	const struct usb_ep_ops	*ops; | ||||
| 	struct list_head	ep_list; | ||||
| 	unsigned		maxpacket:16; | ||||
| 	unsigned		max_streams:16; | ||||
| 	u8			address; | ||||
| 	const struct usb_endpoint_descriptor	*desc; | ||||
| 	const struct usb_ss_ep_comp_descriptor	*comp_desc; | ||||
| }; | ||||
| 
 | ||||
| /*-------------------------------------------------------------------------*/ | ||||
|  | @ -895,6 +903,11 @@ static inline void usb_free_descriptors(struct usb_descriptor_header **v) | |||
| extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *, | ||||
| 			struct usb_endpoint_descriptor *); | ||||
| 
 | ||||
| 
 | ||||
| extern struct usb_ep *usb_ep_autoconfig_ss(struct usb_gadget *, | ||||
| 			struct usb_endpoint_descriptor *, | ||||
| 			struct usb_ss_ep_comp_descriptor *); | ||||
| 
 | ||||
| extern void usb_ep_autoconfig_reset(struct usb_gadget *); | ||||
| 
 | ||||
| #endif /* __LINUX_USB_GADGET_H */ | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Tatyana Brokhman
						Tatyana Brokhman