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