xref: /openbmc/u-boot/drivers/usb/gadget/epautoconf.c (revision 9d86f0c3)
1 /*
2  * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers
3  *
4  * Copyright (C) 2004 David Brownell
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and
21  *                      Remy Bohmer <linux@bohmer.net>
22  */
23 
24 #include <common.h>
25 #include <linux/usb/ch9.h>
26 #include <asm/errno.h>
27 #include <linux/usb/gadget.h>
28 #include <asm/unaligned.h>
29 #include "gadget_chips.h"
30 
31 #define isdigit(c)      ('0' <= (c) && (c) <= '9')
32 
33 /* we must assign addresses for configurable endpoints (like net2280) */
34 static unsigned epnum;
35 
36 /* #define MANY_ENDPOINTS */
37 #ifdef MANY_ENDPOINTS
38 /* more than 15 configurable endpoints */
39 static unsigned in_epnum;
40 #endif
41 
42 
43 /*
44  * This should work with endpoints from controller drivers sharing the
45  * same endpoint naming convention.  By example:
46  *
47  *	- ep1, ep2, ... address is fixed, not direction or type
48  *	- ep1in, ep2out, ... address and direction are fixed, not type
49  *	- ep1-bulk, ep2-bulk, ... address and type are fixed, not direction
50  *	- ep1in-bulk, ep2out-iso, ... all three are fixed
51  *	- ep-* ... no functionality restrictions
52  *
53  * Type suffixes are "-bulk", "-iso", or "-int".  Numbers are decimal.
54  * Less common restrictions are implied by gadget_is_*().
55  *
56  * NOTE:  each endpoint is unidirectional, as specified by its USB
57  * descriptor; and isn't specific to a configuration or altsetting.
58  */
59 static int ep_matches(
60 	struct usb_gadget		*gadget,
61 	struct usb_ep			*ep,
62 	struct usb_endpoint_descriptor	*desc
63 )
64 {
65 	u8		type;
66 	const char	*tmp;
67 	u16		max;
68 
69 	/* endpoint already claimed? */
70 	if (NULL != ep->driver_data)
71 		return 0;
72 
73 	/* only support ep0 for portable CONTROL traffic */
74 	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
75 	if (USB_ENDPOINT_XFER_CONTROL == type)
76 		return 0;
77 
78 	/* some other naming convention */
79 	if ('e' != ep->name[0])
80 		return 0;
81 
82 	/* type-restriction:  "-iso", "-bulk", or "-int".
83 	 * direction-restriction:  "in", "out".
84 	 */
85 	if ('-' != ep->name[2]) {
86 		tmp = strrchr(ep->name, '-');
87 		if (tmp) {
88 			switch (type) {
89 			case USB_ENDPOINT_XFER_INT:
90 				/* bulk endpoints handle interrupt transfers,
91 				 * except the toggle-quirky iso-synch kind
92 				 */
93 				if ('s' == tmp[2])	/* == "-iso" */
94 					return 0;
95 				/* for now, avoid PXA "interrupt-in";
96 				 * it's documented as never using DATA1.
97 				 */
98 				if (gadget_is_pxa(gadget)
99 						&& 'i' == tmp[1])
100 					return 0;
101 				break;
102 			case USB_ENDPOINT_XFER_BULK:
103 				if ('b' != tmp[1])	/* != "-bulk" */
104 					return 0;
105 				break;
106 			case USB_ENDPOINT_XFER_ISOC:
107 				if ('s' != tmp[2])	/* != "-iso" */
108 					return 0;
109 			}
110 		} else {
111 			tmp = ep->name + strlen(ep->name);
112 		}
113 
114 		/* direction-restriction:  "..in-..", "out-.." */
115 		tmp--;
116 		if (!isdigit(*tmp)) {
117 			if (desc->bEndpointAddress & USB_DIR_IN) {
118 				if ('n' != *tmp)
119 					return 0;
120 			} else {
121 				if ('t' != *tmp)
122 					return 0;
123 			}
124 		}
125 	}
126 
127 	/* endpoint maxpacket size is an input parameter, except for bulk
128 	 * where it's an output parameter representing the full speed limit.
129 	 * the usb spec fixes high speed bulk maxpacket at 512 bytes.
130 	 */
131 	max = 0x7ff & le16_to_cpu(get_unaligned(&desc->wMaxPacketSize));
132 	switch (type) {
133 	case USB_ENDPOINT_XFER_INT:
134 		/* INT:  limit 64 bytes full speed, 1024 high speed */
135 		if (!gadget->is_dualspeed && max > 64)
136 			return 0;
137 		/* FALLTHROUGH */
138 
139 	case USB_ENDPOINT_XFER_ISOC:
140 		/* ISO:  limit 1023 bytes full speed, 1024 high speed */
141 		if (ep->maxpacket < max)
142 			return 0;
143 		if (!gadget->is_dualspeed && max > 1023)
144 			return 0;
145 
146 		/* BOTH:  "high bandwidth" works only at high speed */
147 		if ((get_unaligned(&desc->wMaxPacketSize) &
148 					__constant_cpu_to_le16(3<<11))) {
149 			if (!gadget->is_dualspeed)
150 				return 0;
151 			/* configure your hardware with enough buffering!! */
152 		}
153 		break;
154 	}
155 
156 	/* MATCH!! */
157 
158 	/* report address */
159 	if (isdigit(ep->name[2])) {
160 		u8	num = simple_strtoul(&ep->name[2], NULL, 10);
161 		desc->bEndpointAddress |= num;
162 #ifdef	MANY_ENDPOINTS
163 	} else if (desc->bEndpointAddress & USB_DIR_IN) {
164 		if (++in_epnum > 15)
165 			return 0;
166 		desc->bEndpointAddress = USB_DIR_IN | in_epnum;
167 #endif
168 	} else {
169 		if (++epnum > 15)
170 			return 0;
171 		desc->bEndpointAddress |= epnum;
172 	}
173 
174 	/* report (variable) full speed bulk maxpacket */
175 	if (USB_ENDPOINT_XFER_BULK == type) {
176 		int size = ep->maxpacket;
177 
178 		/* min() doesn't work on bitfields with gcc-3.5 */
179 		if (size > 64)
180 			size = 64;
181 		put_unaligned(cpu_to_le16(size), &desc->wMaxPacketSize);
182 	}
183 	return 1;
184 }
185 
186 static struct usb_ep *
187 find_ep(struct usb_gadget *gadget, const char *name)
188 {
189 	struct usb_ep	*ep;
190 
191 	list_for_each_entry(ep, &gadget->ep_list, ep_list) {
192 		if (0 == strcmp(ep->name, name))
193 			return ep;
194 	}
195 	return NULL;
196 }
197 
198 /**
199  * usb_ep_autoconfig - choose an endpoint matching the descriptor
200  * @gadget: The device to which the endpoint must belong.
201  * @desc: Endpoint descriptor, with endpoint direction and transfer mode
202  *	initialized.  For periodic transfers, the maximum packet
203  *	size must also be initialized.  This is modified on success.
204  *
205  * By choosing an endpoint to use with the specified descriptor, this
206  * routine simplifies writing gadget drivers that work with multiple
207  * USB device controllers.  The endpoint would be passed later to
208  * usb_ep_enable(), along with some descriptor.
209  *
210  * That second descriptor won't always be the same as the first one.
211  * For example, isochronous endpoints can be autoconfigured for high
212  * bandwidth, and then used in several lower bandwidth altsettings.
213  * Also, high and full speed descriptors will be different.
214  *
215  * Be sure to examine and test the results of autoconfiguration on your
216  * hardware.  This code may not make the best choices about how to use the
217  * USB controller, and it can't know all the restrictions that may apply.
218  * Some combinations of driver and hardware won't be able to autoconfigure.
219  *
220  * On success, this returns an un-claimed usb_ep, and modifies the endpoint
221  * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
222  * is initialized as if the endpoint were used at full speed.  To prevent
223  * the endpoint from being returned by a later autoconfig call, claim it
224  * by assigning ep->driver_data to some non-null value.
225  *
226  * On failure, this returns a null endpoint descriptor.
227  */
228 struct usb_ep *usb_ep_autoconfig(
229 	struct usb_gadget		*gadget,
230 	struct usb_endpoint_descriptor	*desc
231 )
232 {
233 	struct usb_ep	*ep;
234 	u8		type;
235 
236 	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
237 
238 	/* First, apply chip-specific "best usage" knowledge.
239 	 * This might make a good usb_gadget_ops hook ...
240 	 */
241 	if (gadget_is_net2280(gadget) && type == USB_ENDPOINT_XFER_INT) {
242 		/* ep-e, ep-f are PIO with only 64 byte fifos */
243 		ep = find_ep(gadget, "ep-e");
244 		if (ep && ep_matches(gadget, ep, desc))
245 			return ep;
246 		ep = find_ep(gadget, "ep-f");
247 		if (ep && ep_matches(gadget, ep, desc))
248 			return ep;
249 
250 	} else if (gadget_is_goku(gadget)) {
251 		if (USB_ENDPOINT_XFER_INT == type) {
252 			/* single buffering is enough */
253 			ep = find_ep(gadget, "ep3-bulk");
254 			if (ep && ep_matches(gadget, ep, desc))
255 				return ep;
256 		} else if (USB_ENDPOINT_XFER_BULK == type
257 				&& (USB_DIR_IN & desc->bEndpointAddress)) {
258 			/* DMA may be available */
259 			ep = find_ep(gadget, "ep2-bulk");
260 			if (ep && ep_matches(gadget, ep, desc))
261 				return ep;
262 		}
263 
264 	} else if (gadget_is_sh(gadget) && USB_ENDPOINT_XFER_INT == type) {
265 		/* single buffering is enough; maybe 8 byte fifo is too */
266 		ep = find_ep(gadget, "ep3in-bulk");
267 		if (ep && ep_matches(gadget, ep, desc))
268 			return ep;
269 
270 	} else if (gadget_is_mq11xx(gadget) && USB_ENDPOINT_XFER_INT == type) {
271 		ep = find_ep(gadget, "ep1-bulk");
272 		if (ep && ep_matches(gadget, ep, desc))
273 			return ep;
274 	}
275 
276 	/* Second, look at endpoints until an unclaimed one looks usable */
277 	list_for_each_entry(ep, &gadget->ep_list, ep_list) {
278 		if (ep_matches(gadget, ep, desc))
279 			return ep;
280 	}
281 
282 	/* Fail */
283 	return NULL;
284 }
285 
286 /**
287  * usb_ep_autoconfig_reset - reset endpoint autoconfig state
288  * @gadget: device for which autoconfig state will be reset
289  *
290  * Use this for devices where one configuration may need to assign
291  * endpoint resources very differently from the next one.  It clears
292  * state such as ep->driver_data and the record of assigned endpoints
293  * used by usb_ep_autoconfig().
294  */
295 void usb_ep_autoconfig_reset(struct usb_gadget *gadget)
296 {
297 	struct usb_ep	*ep;
298 
299 	list_for_each_entry(ep, &gadget->ep_list, ep_list) {
300 		ep->driver_data = NULL;
301 	}
302 #ifdef	MANY_ENDPOINTS
303 	in_epnum = 0;
304 #endif
305 	epnum = 0;
306 }
307