3 * Copyright (C) 2015 Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <libpayload.h>
30 #include <arch/cache.h>
42 #define debug(x...) printf(x)
44 #define debug(x...) do {} while (0)
47 #define min(a, b) (((a) < (b)) ? (a) : (b))
49 static unsigned short strings_lang_id
= 0;
50 static unsigned char strings_count
= 0;
51 static const char **strings
;
53 void udc_add_strings(unsigned short lang_id
, unsigned char count
,
56 strings_lang_id
= lang_id
;
57 strings_count
= count
;
61 /* determine if an additional zero length packet is necessary for
63 static unsigned int zlp(struct usbdev_ctrl
*this, const int epnum
,
64 const int len
, const int explen
)
66 const unsigned int mps
= this->ep_mps
[epnum
][1];
68 /* zero length transfers are handled explicitly */
71 /* host expects exactly the right amount, so no zlp necessary */
74 /* last packet will be short -> host knows that transfer is over */
78 /* otherwise we need an extra zero length packet */
82 static struct usbdev_configuration
*fetch_config(struct usbdev_ctrl
*this,
85 struct usbdev_configuration
*config
;
86 SLIST_FOREACH(config
, &this->configs
, list
) {
87 debug("checking descriptor %d\n",
88 config
->descriptor
.bConfigurationValue
);
89 if (config
->descriptor
.bConfigurationValue
== id
)
95 static void cease_operation(struct usbdev_ctrl
*this)
98 for (i
= 1; i
< 16; i
++) {
99 /* disable endpoints */
100 this->halt_ep(this, i
, 0);
101 this->halt_ep(this, i
, 1);
106 static void enable_interface(struct usbdev_ctrl
*this, int iface_num
)
108 struct usbdev_configuration
*config
= this->current_config
;
109 struct usbdev_interface
*iface
= &config
->interfaces
[iface_num
];
111 /* first: shut down all endpoints except EP0 */
112 cease_operation(this);
114 /* now enable all configured endpoints */
115 int epcount
= iface
->descriptor
.bNumEndpoints
;
117 for (i
= 0; i
< epcount
; i
++) {
118 int ep
= iface
->eps
[i
].bEndpointAddress
;
119 int mps
= iface
->eps
[i
].wMaxPacketSize
;
125 int ep_type
= iface
->eps
[i
].bmAttributes
& 0x3;
126 this->start_ep(this, ep
, in_dir
, ep_type
, mps
);
129 this->current_iface
= iface
;
131 // gadget specific configuration
137 * handle default control transfers on EP 0
139 * returns 1 if transfer was handled
141 static int setup_ep0(struct usbdev_ctrl
*this, dev_req_t
*dr
)
143 if ((dr
->bmRequestType
== 0x00) &&
144 (dr
->bRequest
== SET_ADDRESS
)) {
145 this->set_address(this, dr
->wValue
& 0x7f);
147 /* status phase IN */
148 this->enqueue_packet(this, 0, 1, NULL
, 0, 0, 0);
151 if ((dr
->bmRequestType
== 0x00) &&
152 (dr
->bRequest
== SET_CONFIGURATION
)) {
153 struct usbdev_configuration
*config
=
154 fetch_config(this, dr
->wValue
);
157 cease_operation(this);
159 if (config
== NULL
) {
160 this->stall(this, 0, 0, 1);
161 this->stall(this, 0, 1, 1);
165 /* status phase IN */
166 this->enqueue_packet(this, 0, 1, NULL
, 0, 0, 0);
168 this->current_config
= config
;
169 this->current_config_id
= dr
->wValue
;
171 /* activate first interface */
172 enable_interface(this, 0);
173 this->initialized
= 1;
176 if ((dr
->bmRequestType
== 0x80) &&
177 (dr
->bRequest
== GET_CONFIGURATION
)) {
178 unsigned char *res
= dma_malloc(1);
179 res
[0] = this->current_config_id
;
182 this->enqueue_packet(this, 0, 1, res
, min(1, dr
->wLength
),
185 /* status phase OUT */
186 this->enqueue_packet(this, 0, 0, NULL
, 0, 0, 0);
190 if ((dr
->bmRequestType
== 0x02) && // endpoint
191 (dr
->bRequest
== CLEAR_FEATURE
) &&
195 this->stall(this, ep
& 0xf, ep
& 0x80, 0);
197 /* status phase IN */
198 this->enqueue_packet(this, 0, 1, NULL
, 0, 0, 0);
202 if ((dr
->bmRequestType
== 0x02) && // endpoint
203 (dr
->bRequest
== SET_FEATURE
) &&
207 this->stall(this, ep
& 0xf, ep
& 0x80, 1);
209 /* status phase IN */
210 this->enqueue_packet(this, 0, 1, NULL
, 0, 0, 0);
213 // DEVICE_REMOTE_WAKEUP
214 if ((dr
->bmRequestType
== 0x00) &&
215 (dr
->bRequest
== CLEAR_FEATURE
) &&
217 this->remote_wakeup
= 0;
219 /* status phase IN */
220 this->enqueue_packet(this, 0, 1, NULL
, 0, 0, 0);
223 // DEVICE_REMOTE_WAKEUP
224 if ((dr
->bmRequestType
== 0x00) &&
225 (dr
->bRequest
== SET_FEATURE
) &&
227 this->remote_wakeup
= 1;
229 /* status phase IN */
230 this->enqueue_packet(this, 0, 1, NULL
, 0, 0, 0);
233 if ((dr
->bmRequestType
== 0x82) && // endpoint
234 (dr
->bRequest
== GET_STATUS
)) {
235 unsigned char *res
= dma_malloc(2);
238 res
[0] = this->ep_halted
[ep
& 0xf][(ep
& 0x80) ? 1 : 0];
242 this->enqueue_packet(this, 0, 1, res
,
243 min(2, dr
->wLength
), 0, 1);
246 this->enqueue_packet(this, 0, 0, NULL
, 0, 0, 0);
249 if ((dr
->bmRequestType
== 0x80) &&
250 (dr
->bRequest
== GET_STATUS
)) {
251 unsigned char *res
= dma_malloc(2);
252 res
[0] = 1; // self powered
253 if (this->remote_wakeup
)
259 this->enqueue_packet(this, 0, 1, res
,
260 min(2, dr
->wLength
), 0, 1);
263 this->enqueue_packet(this, 0, 0, NULL
, 0, 0, 0);
266 if ((dr
->bmRequestType
== 0x80) &&
267 (dr
->bRequest
== GET_DESCRIPTOR
) &&
268 ((dr
->wValue
& 0xff00) == 0x0200)) {
270 /* config descriptor #id
271 * since config = 0 is undefined, but descriptors
272 * should start at 0, add 1 to have them match up.
274 int id
= (dr
->wValue
& 0xff) + 1;
275 struct usbdev_configuration
*config
= fetch_config(this, id
);
276 if (config
== NULL
) {
277 this->stall(this, 0, 0, 1);
278 this->stall(this, 0, 1, 1);
281 debug("descriptor found, should be %d bytes\n",
282 config
->descriptor
.wTotalLength
);
284 uint8_t *data
= dma_malloc(config
->descriptor
.wTotalLength
);
285 uint8_t *head
= data
;
287 memcpy(head
, &config
->descriptor
,
288 sizeof(configuration_descriptor_t
));
289 head
+= sizeof(configuration_descriptor_t
);
291 for (i
= 0; i
< config
->descriptor
.bNumInterfaces
; i
++) {
292 memcpy(head
, &config
->interfaces
[i
].descriptor
,
293 sizeof(interface_descriptor_t
));
294 head
+= sizeof(interface_descriptor_t
);
296 j
< config
->interfaces
[i
].descriptor
.bNumEndpoints
;
298 memcpy(head
, &config
->interfaces
[i
].eps
[j
],
299 sizeof(endpoint_descriptor_t
));
300 head
+= sizeof(endpoint_descriptor_t
);
303 int size
= config
->descriptor
.wTotalLength
;
304 assert((head
- data
) == config
->descriptor
.wTotalLength
);
307 this->enqueue_packet(this, 0, 1, data
,
308 min(size
, dr
->wLength
),
309 zlp(this, 0, size
, dr
->wLength
), 1);
311 /* status phase OUT */
312 this->enqueue_packet(this, 0, 0, NULL
, 0, 0, 0);
315 if ((dr
->bmRequestType
== 0x80) &&
316 (dr
->bRequest
== GET_DESCRIPTOR
) &&
317 ((dr
->wValue
& 0xff00) == 0x0300)) {
318 int id
= (dr
->wValue
& 0xff);
320 if (strings_lang_id
== 0)
323 uint8_t *data
= dma_malloc(4);
324 data
[0] = 0x04; // length
325 data
[1] = 0x03; // string descriptor
326 data
[2] = strings_lang_id
& 0xff;
327 data
[3] = strings_lang_id
>> 8;
329 this->enqueue_packet(this, 0, 1,
331 min(data
[0], dr
->wLength
),
332 zlp(this, 0, data
[0], dr
->wLength
),
335 /* status phase OUT */
336 this->enqueue_packet(this, 0, 0, NULL
, 0, 0, 0);
338 if (strings_lang_id
== 0)
341 int lang
= dr
->wIndex
;
342 if (lang
!= strings_lang_id
)
345 if (id
> strings_count
)
348 int s_len
= strlen(strings
[id
]);
349 int d_len
= s_len
* 2;
351 uint8_t *data
= dma_malloc(d_len
+ 2);
352 memset(data
, 0, d_len
+ 2);
353 data
[0] = d_len
+ 2; // length
354 data
[1] = 0x03; // string descriptor
356 for (i
= 0; i
< s_len
; i
++)
357 data
[i
* 2 + 2] = strings
[id
][i
];
360 this->enqueue_packet(this, 0, 1,
362 min(d_len
+ 2, dr
->wLength
),
363 zlp(this, 0, d_len
+ 2, dr
->wLength
),
366 /* status phase OUT */
367 this->enqueue_packet(this, 0, 0, NULL
, 0, 0, 0);
371 if ((dr
->bmRequestType
== 0x80) &&
372 (dr
->bRequest
== GET_DESCRIPTOR
) &&
373 ((dr
->wValue
& 0xff00) == 0x0100)) {
374 device_descriptor_t
*dd
= dma_malloc(sizeof(*dd
));
375 memcpy(dd
, &this->device_descriptor
, sizeof(*dd
));
376 dd
->bNumConfigurations
= this->config_count
;
379 this->enqueue_packet(this, 0, 1, (void *)dd
,
380 min(sizeof(*dd
), dr
->wLength
),
381 zlp(this, 0, sizeof(*dd
), dr
->wLength
), 1);
383 /* status phase OUT */
384 this->enqueue_packet(this, 0, 0, NULL
, 0, 0, 0);
390 void udc_add_gadget(struct usbdev_ctrl
*this,
391 struct usbdev_configuration
*config
)
394 SLIST_INSERT_HEAD(&this->configs
, config
, list
);
396 size
= sizeof(configuration_descriptor_t
);
398 for (i
= 0; i
< config
->descriptor
.bNumInterfaces
; i
++) {
399 size
+= sizeof(config
->interfaces
[i
].descriptor
);
400 size
+= config
->interfaces
[i
].descriptor
.bNumEndpoints
*
401 sizeof(endpoint_descriptor_t
);
403 config
->descriptor
.wTotalLength
= size
;
404 config
->descriptor
.bConfigurationValue
= ++this->config_count
;
407 void udc_handle_setup(struct usbdev_ctrl
*this, int ep
, dev_req_t
*dr
)
409 if ((ep
== 0) && setup_ep0(this, dr
))
412 if (this->current_config
&&
413 this->current_config
->interfaces
[0].handle_setup
&&
414 this->current_config
->interfaces
[0].handle_setup(this, ep
, dr
))
417 /* no successful SETUP transfer should end up here, report error */
418 this->halt_ep(this, ep
, 0);
419 this->halt_ep(this, ep
, 1);