1
2
3
4
5
6
7
8
9
10
11#include <common.h>
12#include <linux/usb/ch9.h>
13#include <linux/errno.h>
14#include <linux/usb/gadget.h>
15#include <asm/unaligned.h>
16#include "gadget_chips.h"
17
18#define isdigit(c) ('0' <= (c) && (c) <= '9')
19
20
21static unsigned epnum;
22
23
24#ifdef MANY_ENDPOINTS
25
26static unsigned in_epnum;
27#endif
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46static int ep_matches(
47 struct usb_gadget *gadget,
48 struct usb_ep *ep,
49 struct usb_endpoint_descriptor *desc
50)
51{
52 u8 type;
53 const char *tmp;
54 u16 max;
55
56
57 if (NULL != ep->driver_data)
58 return 0;
59
60
61 type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
62 if (USB_ENDPOINT_XFER_CONTROL == type)
63 return 0;
64
65
66 if ('e' != ep->name[0])
67 return 0;
68
69
70
71
72 if ('-' != ep->name[2]) {
73 tmp = strrchr(ep->name, '-');
74 if (tmp) {
75 switch (type) {
76 case USB_ENDPOINT_XFER_INT:
77
78
79
80 if ('s' == tmp[2])
81 return 0;
82 break;
83 case USB_ENDPOINT_XFER_BULK:
84 if ('b' != tmp[1])
85 return 0;
86 break;
87 case USB_ENDPOINT_XFER_ISOC:
88 if ('s' != tmp[2])
89 return 0;
90 }
91 } else {
92 tmp = ep->name + strlen(ep->name);
93 }
94
95
96 tmp--;
97 if (!isdigit(*tmp)) {
98 if (desc->bEndpointAddress & USB_DIR_IN) {
99 if ('n' != *tmp)
100 return 0;
101 } else {
102 if ('t' != *tmp)
103 return 0;
104 }
105 }
106 }
107
108
109
110
111
112 max = 0x7ff & le16_to_cpu(get_unaligned(&desc->wMaxPacketSize));
113 switch (type) {
114 case USB_ENDPOINT_XFER_INT:
115
116 if (!gadget->is_dualspeed && max > 64)
117 return 0;
118
119
120 case USB_ENDPOINT_XFER_ISOC:
121
122 if (ep->maxpacket < max)
123 return 0;
124 if (!gadget->is_dualspeed && max > 1023)
125 return 0;
126
127
128 if ((get_unaligned(&desc->wMaxPacketSize) &
129 __constant_cpu_to_le16(3<<11))) {
130 if (!gadget->is_dualspeed)
131 return 0;
132
133 }
134 break;
135 }
136
137
138
139
140 if (isdigit(ep->name[2])) {
141 u8 num = dectoul(&ep->name[2], NULL);
142 desc->bEndpointAddress |= num;
143#ifdef MANY_ENDPOINTS
144 } else if (desc->bEndpointAddress & USB_DIR_IN) {
145 if (++in_epnum > 15)
146 return 0;
147 desc->bEndpointAddress = USB_DIR_IN | in_epnum;
148#endif
149 } else {
150 if (++epnum > 15)
151 return 0;
152 desc->bEndpointAddress |= epnum;
153 }
154
155
156 if (USB_ENDPOINT_XFER_BULK == type) {
157 int size = ep->maxpacket;
158
159
160 if (size > 64)
161 size = 64;
162 put_unaligned(cpu_to_le16(size), &desc->wMaxPacketSize);
163 }
164
165 if (gadget->ops->ep_conf)
166 return gadget->ops->ep_conf(gadget, ep, desc);
167
168 return 1;
169}
170
171static struct usb_ep *
172find_ep(struct usb_gadget *gadget, const char *name)
173{
174 struct usb_ep *ep;
175
176 list_for_each_entry(ep, &gadget->ep_list, ep_list) {
177 if (0 == strcmp(ep->name, name))
178 return ep;
179 }
180 return NULL;
181}
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213struct usb_ep *usb_ep_autoconfig(
214 struct usb_gadget *gadget,
215 struct usb_endpoint_descriptor *desc
216)
217{
218 struct usb_ep *ep = NULL;
219 u8 type;
220
221 type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
222
223
224
225
226 if (gadget_is_net2280(gadget) && type == USB_ENDPOINT_XFER_INT) {
227
228 ep = find_ep(gadget, "ep-e");
229 if (ep && ep_matches(gadget, ep, desc))
230 return ep;
231 ep = find_ep(gadget, "ep-f");
232 if (ep && ep_matches(gadget, ep, desc))
233 return ep;
234
235 } else if (gadget_is_goku(gadget)) {
236 if (USB_ENDPOINT_XFER_INT == type) {
237
238 ep = find_ep(gadget, "ep3-bulk");
239 if (ep && ep_matches(gadget, ep, desc))
240 return ep;
241 } else if (USB_ENDPOINT_XFER_BULK == type
242 && (USB_DIR_IN & desc->bEndpointAddress)) {
243
244 ep = find_ep(gadget, "ep2-bulk");
245 if (ep && ep_matches(gadget, ep, desc))
246 return ep;
247 }
248
249 } else if (gadget_is_sh(gadget) && USB_ENDPOINT_XFER_INT == type) {
250
251 ep = find_ep(gadget, "ep3in-bulk");
252 if (ep && ep_matches(gadget, ep, desc))
253 return ep;
254
255 } else if (gadget_is_mq11xx(gadget) && USB_ENDPOINT_XFER_INT == type) {
256 ep = find_ep(gadget, "ep1-bulk");
257 if (ep && ep_matches(gadget, ep, desc))
258 return ep;
259#ifndef CONFIG_SPL_BUILD
260 } else if (gadget_is_dwc3(gadget)) {
261 const char *name = NULL;
262
263
264
265
266
267
268 if ((desc->bEndpointAddress & USB_DIR_IN) &&
269 type == USB_ENDPOINT_XFER_BULK)
270 name = "ep1in";
271 else if ((desc->bEndpointAddress & USB_DIR_IN) == 0 &&
272 type == USB_ENDPOINT_XFER_BULK)
273 name = "ep2out";
274 else if ((desc->bEndpointAddress & USB_DIR_IN) &&
275 type == USB_ENDPOINT_XFER_INT)
276 name = "ep3in";
277
278 if (name)
279 ep = find_ep(gadget, name);
280 if (ep && ep_matches(gadget, ep, desc))
281 return ep;
282#endif
283 }
284
285 if (gadget->ops->match_ep)
286 ep = gadget->ops->match_ep(gadget, desc, NULL);
287
288
289 list_for_each_entry(ep, &gadget->ep_list, ep_list) {
290 if (ep_matches(gadget, ep, desc))
291 return ep;
292 }
293
294
295 return NULL;
296}
297
298
299
300
301
302
303
304
305
306
307void usb_ep_autoconfig_reset(struct usb_gadget *gadget)
308{
309 struct usb_ep *ep;
310
311 list_for_each_entry(ep, &gadget->ep_list, ep_list) {
312 ep->driver_data = NULL;
313 }
314#ifdef MANY_ENDPOINTS
315 in_epnum = 0;
316#endif
317 epnum = 0;
318}
319