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

Commit a59d6b91 authored by Tatyana Brokhman's avatar Tatyana Brokhman Committed by Greg Kroah-Hartman
Browse files

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: default avatarMaya Erez <merez@codeaurora.org>
Signed-off-by: default avatarTatyana Brokhman <tlinder@codeaurora.org>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 7c884fe4
Loading
Loading
Loading
Loading
+100 −25
Original line number Original line Diff line number Diff line
@@ -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,38 +227,53 @@ 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.
 * @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
 *	size must also be initialized.  This is modified on success.
 *    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.
 *
 *
 * By choosing an endpoint to use with the specified descriptor, this
 * This routine replaces the usb_ep_autoconfig when needed
 * routine simplifies writing gadget drivers that work with multiple
 * superspeed enhancments. If such enhancemnets are required,
 * USB device controllers.  The endpoint would be passed later to
 * the FD should call usb_ep_autoconfig_ss directly and provide
 * usb_ep_enable(), along with some descriptor.
 * 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.
 * That second descriptor won't always be the same as the first one.
 * For example, isochronous endpoints can be autoconfigured for high
 * For example, isochronous endpoints can be autoconfigured for high
 * bandwidth, and then used in several lower bandwidth altsettings.
 * bandwidth, and then used in several lower bandwidth altsettings.
 * Also, high and full speed descriptors will be different.
 * Also, high and full speed descriptors will be different.
 *
 *
 * Be sure to examine and test the results of autoconfiguration on your
 * Be sure to examine and test the results of autoconfiguration
 * hardware.  This code may not make the best choices about how to use the
 * on your hardware.  This code may not make the best choices
 * USB controller, and it can't know all the restrictions that may apply.
 * about how to use the USB controller, and it can't know all
 * Some combinations of driver and hardware won't be able to autoconfigure.
 * 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
 * On success, this returns an un-claimed usb_ep, and modifies the endpoint
 * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
 * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
 * is initialized as if the endpoint were used at full speed.  To prevent
 * is initialized as if the endpoint were used at full speed and
 * the endpoint from being returned by a later autoconfig call, claim it
 * the bmAttribute field in the ep companion descriptor is
 * by assigning ep->driver_data to some non-null value.
 * 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.
 * On failure, this returns a null endpoint descriptor.
 */
 */
struct usb_ep *usb_ep_autoconfig (
struct usb_ep *usb_ep_autoconfig_ss(
	struct usb_gadget		*gadget,
	struct usb_gadget		*gadget,
	struct usb_endpoint_descriptor	*desc
	struct usb_endpoint_descriptor	*desc,
	struct usb_ss_ep_comp_descriptor *ep_comp
)
)
{
{
	struct usb_ep	*ep;
	struct usb_ep	*ep;
@@ -253,23 +287,24 @@ struct usb_ep *usb_ep_autoconfig (
	if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
	if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
		/* ep-e, ep-f are PIO with only 64 byte fifos */
		/* ep-e, ep-f are PIO with only 64 byte fifos */
		ep = find_ep (gadget, "ep-e");
		ep = find_ep (gadget, "ep-e");
		if (ep && ep_matches (gadget, ep, desc))
		if (ep && ep_matches(gadget, ep, desc, ep_comp))
			return ep;
			return ep;
		ep = find_ep (gadget, "ep-f");
		ep = find_ep (gadget, "ep-f");
		if (ep && ep_matches (gadget, ep, desc))
		if (ep && ep_matches(gadget, ep, desc, ep_comp))
			return ep;
			return ep;


	} else if (gadget_is_goku (gadget)) {
	} else if (gadget_is_goku (gadget)) {
		if (USB_ENDPOINT_XFER_INT == type) {
		if (USB_ENDPOINT_XFER_INT == type) {
			/* single buffering is enough */
			/* single buffering is enough */
			ep = find_ep(gadget, "ep3-bulk");
			ep = find_ep(gadget, "ep3-bulk");
			if (ep && ep_matches (gadget, ep, desc))
			if (ep && ep_matches(gadget, ep, desc, ep_comp))
				return ep;
				return ep;
		} else if (USB_ENDPOINT_XFER_BULK == type
		} else if (USB_ENDPOINT_XFER_BULK == type
				&& (USB_DIR_IN & desc->bEndpointAddress)) {
				&& (USB_DIR_IN & desc->bEndpointAddress)) {
			/* DMA may be available */
			/* DMA may be available */
			ep = find_ep(gadget, "ep2-bulk");
			ep = find_ep(gadget, "ep2-bulk");
			if (ep && ep_matches (gadget, ep, desc))
			if (ep && ep_matches(gadget, ep, desc,
					      ep_comp))
				return ep;
				return ep;
		}
		}


@@ -288,14 +323,14 @@ struct usb_ep *usb_ep_autoconfig (
				ep = find_ep(gadget, "ep2out");
				ep = find_ep(gadget, "ep2out");
		} else
		} else
			ep = NULL;
			ep = NULL;
		if (ep && ep_matches (gadget, ep, desc))
		if (ep && ep_matches(gadget, ep, desc, ep_comp))
			return ep;
			return ep;
#endif
#endif
	}
	}


	/* Second, look at endpoints until an unclaimed one looks usable */
	/* Second, look at endpoints until an unclaimed one looks usable */
	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
		if (ep_matches (gadget, ep, desc))
		if (ep_matches(gadget, ep, desc, ep_comp))
			return ep;
			return ep;
	}
	}


@@ -303,6 +338,46 @@ struct usb_ep *usb_ep_autoconfig (
	return NULL;
	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
 *	size must also be initialized.  This is modified on success.
 *
 * 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.  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(
	struct usb_gadget		*gadget,
	struct usb_endpoint_descriptor	*desc
)
{
	return usb_ep_autoconfig_ss(gadget, desc, NULL);
}


/**
/**
 * usb_ep_autoconfig_reset - reset endpoint autoconfig state
 * usb_ep_autoconfig_reset - reset endpoint autoconfig state
 * @gadget: device for which autoconfig state will be reset
 * @gadget: device for which autoconfig state will be reset
+13 −0
Original line number Original line Diff line number Diff line
@@ -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 */