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 ( | ep_matches ( | ||||||
| 	struct usb_gadget		*gadget, | 	struct usb_gadget		*gadget, | ||||||
| 	struct usb_ep			*ep, | 	struct usb_ep			*ep, | ||||||
| 	struct usb_endpoint_descriptor	*desc | 	struct usb_endpoint_descriptor	*desc, | ||||||
|  | 	struct usb_ss_ep_comp_descriptor *ep_comp | ||||||
| ) | ) | ||||||
| { | { | ||||||
| 	u8		type; | 	u8		type; | ||||||
| 	const char	*tmp; | 	const char	*tmp; | ||||||
| 	u16		max; | 	u16		max; | ||||||
| 
 | 
 | ||||||
|  | 	int		num_req_streams = 0; | ||||||
|  | 
 | ||||||
| 	/* endpoint already claimed? */ | 	/* endpoint already claimed? */ | ||||||
| 	if (NULL != ep->driver_data) | 	if (NULL != ep->driver_data) | ||||||
| 		return 0; | 		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 | 	 * If the protocol driver hasn't yet decided on wMaxPacketSize | ||||||
| 	 * and wants to know the maximum possible, provide the info. | 	 * 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. |  * @gadget: The device to which the endpoint must belong. | ||||||
|  * @desc: Endpoint descriptor, with endpoint direction and transfer mode |  * @desc: Endpoint descriptor, with endpoint direction and transfer mode | ||||||
|  *	initialized.  For periodic transfers, the maximum packet |  *	initialized.  For periodic transfers, the maximum packet | ||||||
|  | @ -242,66 +374,9 @@ struct usb_ep *usb_ep_autoconfig ( | ||||||
| 	struct usb_endpoint_descriptor	*desc | 	struct usb_endpoint_descriptor	*desc | ||||||
| ) | ) | ||||||
| { | { | ||||||
| 	struct usb_ep	*ep; | 	return usb_ep_autoconfig_ss(gadget, desc, NULL); | ||||||
| 	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; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * usb_ep_autoconfig_reset - reset endpoint autoconfig state |  * usb_ep_autoconfig_reset - reset endpoint autoconfig state | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ struct usb_ep; | ||||||
|  *	field, and the usb controller needs one, it is responsible |  *	field, and the usb controller needs one, it is responsible | ||||||
|  *	for mapping and unmapping the buffer. |  *	for mapping and unmapping the buffer. | ||||||
|  * @length: Length of that data |  * @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. |  * @no_interrupt: If true, hints that no completion irq is needed. | ||||||
|  *	Helpful sometimes with deep request queues that are handled |  *	Helpful sometimes with deep request queues that are handled | ||||||
|  *	directly by DMA controllers. |  *	directly by DMA controllers. | ||||||
|  | @ -82,6 +83,7 @@ struct usb_request { | ||||||
| 	unsigned		length; | 	unsigned		length; | ||||||
| 	dma_addr_t		dma; | 	dma_addr_t		dma; | ||||||
| 
 | 
 | ||||||
|  | 	unsigned		stream_id:16; | ||||||
| 	unsigned		no_interrupt:1; | 	unsigned		no_interrupt:1; | ||||||
| 	unsigned		zero:1; | 	unsigned		zero:1; | ||||||
| 	unsigned		short_not_ok: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 |  * @maxpacket:The maximum packet size used on this endpoint.  The initial | ||||||
|  *	value can sometimes be reduced (hardware allowing), according to |  *	value can sometimes be reduced (hardware allowing), according to | ||||||
|  *      the endpoint descriptor used to configure the endpoint. |  *      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. |  * @driver_data:for use by the gadget driver. | ||||||
|  * @address: used to identify the endpoint when finding descriptor that |  * @address: used to identify the endpoint when finding descriptor that | ||||||
|  *	matches connection speed |  *	matches connection speed | ||||||
|  * @desc: endpoint descriptor.  This pointer is set before the endpoint is |  * @desc: endpoint descriptor.  This pointer is set before the endpoint is | ||||||
|  *	enabled and remains valid until the endpoint is disabled. |  *	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 |  * the bus controller driver lists all the general purpose endpoints in | ||||||
|  * gadget->ep_list.  the control endpoint (gadget->ep0) is not in that list, |  * 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; | 	const struct usb_ep_ops	*ops; | ||||||
| 	struct list_head	ep_list; | 	struct list_head	ep_list; | ||||||
| 	unsigned		maxpacket:16; | 	unsigned		maxpacket:16; | ||||||
|  | 	unsigned		max_streams:16; | ||||||
| 	u8			address; | 	u8			address; | ||||||
| 	const struct usb_endpoint_descriptor	*desc; | 	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 *, | extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *, | ||||||
| 			struct usb_endpoint_descriptor *); | 			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 *); | extern void usb_ep_autoconfig_reset(struct usb_gadget *); | ||||||
| 
 | 
 | ||||||
| #endif /* __LINUX_USB_GADGET_H */ | #endif /* __LINUX_USB_GADGET_H */ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Tatyana Brokhman
						Tatyana Brokhman