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
83
84
85 if (gadget_is_pxa(gadget)
86 && 'i' == tmp[1])
87 return 0;
88 break;
89 case USB_ENDPOINT_XFER_BULK:
90 if ('b' != tmp[1])
91 return 0;
92 break;
93 case USB_ENDPOINT_XFER_ISOC:
94 if ('s' != tmp[2])
95 return 0;
96 }
97 } else {
98 tmp = ep->name + strlen(ep->name);
99 }
100
101
102 tmp--;
103 if (!isdigit(*tmp)) {
104 if (desc->bEndpointAddress & USB_DIR_IN) {
105 if ('n' != *tmp)
106 return 0;
107 } else {
108 if ('t' != *tmp)
109 return 0;
110 }
111 }
112 }
113
114
115
116
117
118 max = 0x7ff & le16_to_cpu(get_unaligned(&desc->wMaxPacketSize));
119 switch (type) {
120 case USB_ENDPOINT_XFER_INT:
121
122 if (!gadget->is_dualspeed && max > 64)
123 return 0;
124
125
126 case USB_ENDPOINT_XFER_ISOC:
127
128 if (ep->maxpacket < max)
129 return 0;
130 if (!gadget->is_dualspeed && max > 1023)
131 return 0;
132
133
134 if ((get_unaligned(&desc->wMaxPacketSize) &
135 __constant_cpu_to_le16(3<<11))) {
136 if (!gadget->is_dualspeed)
137 return 0;
138
139 }
140 break;
141 }
142
143
144
145
146 if (isdigit(ep->name[2])) {
147 u8 num = simple_strtoul(&ep->name[2], NULL, 10);
148 desc->bEndpointAddress |= num;
149#ifdef MANY_ENDPOINTS
150 } else if (desc->bEndpointAddress & USB_DIR_IN) {
151 if (++in_epnum > 15)
152 return 0;
153 desc->bEndpointAddress = USB_DIR_IN | in_epnum;
154#endif
155 } else {
156 if (++epnum > 15)
157 return 0;
158 desc->bEndpointAddress |= epnum;
159 }
160
161
162 if (USB_ENDPOINT_XFER_BULK == type) {
163 int size = ep->maxpacket;
164
165
166 if (size > 64)
167 size = 64;
168 put_unaligned(cpu_to_le16(size), &desc->wMaxPacketSize);
169 }
170 return 1;
171}
172
173static struct usb_ep *
174find_ep(struct usb_gadget *gadget, const char *name)
175{
176 struct usb_ep *ep;
177
178 list_for_each_entry(ep, &gadget->ep_list, ep_list) {
179 if (0 == strcmp(ep->name, name))
180 return ep;
181 }
182 return NULL;
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
213
214
215struct usb_ep *usb_ep_autoconfig(
216 struct usb_gadget *gadget,
217 struct usb_endpoint_descriptor *desc
218)
219{
220 struct usb_ep *ep = NULL;
221 u8 type;
222
223 type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
224
225
226
227
228 if (gadget_is_net2280(gadget) && type == USB_ENDPOINT_XFER_INT) {
229
230 ep = find_ep(gadget, "ep-e");
231 if (ep && ep_matches(gadget, ep, desc))
232 return ep;
233 ep = find_ep(gadget, "ep-f");
234 if (ep && ep_matches(gadget, ep, desc))
235 return ep;
236
237 } else if (gadget_is_goku(gadget)) {
238 if (USB_ENDPOINT_XFER_INT == type) {
239
240 ep = find_ep(gadget, "ep3-bulk");
241 if (ep && ep_matches(gadget, ep, desc))
242 return ep;
243 } else if (USB_ENDPOINT_XFER_BULK == type
244 && (USB_DIR_IN & desc->bEndpointAddress)) {
245
246 ep = find_ep(gadget, "ep2-bulk");
247 if (ep && ep_matches(gadget, ep, desc))
248 return ep;
249 }
250
251 } else if (gadget_is_sh(gadget) && USB_ENDPOINT_XFER_INT == type) {
252
253 ep = find_ep(gadget, "ep3in-bulk");
254 if (ep && ep_matches(gadget, ep, desc))
255 return ep;
256
257 } else if (gadget_is_mq11xx(gadget) && USB_ENDPOINT_XFER_INT == type) {
258 ep = find_ep(gadget, "ep1-bulk");
259 if (ep && ep_matches(gadget, ep, desc))
260 return ep;
261 } else if (gadget_is_dwc3(gadget)) {
262 const char *name = NULL;
263
264
265
266
267
268
269 if ((desc->bEndpointAddress & USB_DIR_IN) &&
270 type == USB_ENDPOINT_XFER_BULK)
271 name = "ep1in";
272 else if ((desc->bEndpointAddress & USB_DIR_IN) == 0 &&
273 type == USB_ENDPOINT_XFER_BULK)
274 name = "ep2out";
275 else if ((desc->bEndpointAddress & USB_DIR_IN) &&
276 type == USB_ENDPOINT_XFER_INT)
277 name = "ep3in";
278
279 if (name)
280 ep = find_ep(gadget, name);
281 if (ep && ep_matches(gadget, ep, desc))
282 return ep;
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