blob: f8b726271b8d73742838b93d220858f3bc8537bc [file] [log] [blame]
Brian Swetland9c4c0752009-01-25 16:23:50 -08001/*
2 * Copyright (c) 2009, Google Inc.
3 * All rights reserved.
4 *
Deepa Dinamani26bc2d32013-03-15 13:17:16 -07005 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
6 *
Brian Swetland9c4c0752009-01-25 16:23:50 -08007 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
Deepa Dinamani26bc2d32013-03-15 13:17:16 -070010 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
Brian Swetland9c4c0752009-01-25 16:23:50 -080013 * notice, this list of conditions and the following disclaimer in
Deepa Dinamani26bc2d32013-03-15 13:17:16 -070014 * the documentation and/or other materials provided with the
Brian Swetland9c4c0752009-01-25 16:23:50 -080015 * distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
Deepa Dinamani26bc2d32013-03-15 13:17:16 -070024 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
Brian Swetland9c4c0752009-01-25 16:23:50 -080025 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <debug.h>
32#include <string.h>
33#include <stdlib.h>
Deepa Dinamani0bf2f442012-10-19 11:41:06 -070034#include <platform.h>
Amol Jadi5edf3552013-07-23 14:15:34 -070035#include <target.h>
Brian Swetland9c4c0752009-01-25 16:23:50 -080036#include <kernel/thread.h>
37#include <kernel/event.h>
38#include <dev/udc.h>
Channagoud Kadabia0930b92013-04-16 15:14:37 -070039#include "fastboot.h"
Brian Swetland9c4c0752009-01-25 16:23:50 -080040
Amol Jadi7c4316c2013-10-07 14:19:26 -070041#ifdef USB30_SUPPORT
42#include <usb30_udc.h>
43#endif
44
45typedef struct
46{
47 int (*udc_init)(struct udc_device *devinfo);
48 int (*udc_register_gadget)(struct udc_gadget *gadget);
49 int (*udc_start)(void);
50 int (*udc_stop)(void);
51
52 struct udc_endpoint *(*udc_endpoint_alloc)(unsigned type, unsigned maxpkt);
53 void (*udc_endpoint_free)(struct udc_endpoint *ept);
54 struct udc_request *(*udc_request_alloc)(void);
55 void (*udc_request_free)(struct udc_request *req);
56
57 int (*usb_read)(void *buf, unsigned len);
58 int (*usb_write)(void *buf, unsigned len);
59} usb_controller_interface_t;
60
61usb_controller_interface_t usb_if;
62
Hanumant Singh108cdc62012-12-11 16:48:49 -080063#define MAX_USBFS_BULK_SIZE (32 * 1024)
Shashank Mittal6a5609f2011-08-04 15:51:59 -070064
Brian Swetland9c4c0752009-01-25 16:23:50 -080065void boot_linux(void *bootimg, unsigned sz);
Amol Jadi5edf3552013-07-23 14:15:34 -070066static void fastboot_notify(struct udc_gadget *gadget, unsigned event);
67static struct udc_endpoint *fastboot_endpoints[2];
68
69static struct udc_device surf_udc_device = {
70 .vendor_id = 0x18d1,
71 .product_id = 0xD00D,
72 .version_id = 0x0100,
73 .manufacturer = "Google",
74 .product = "Android",
75};
76
77static struct udc_gadget fastboot_gadget = {
78 .notify = fastboot_notify,
79 .ifc_class = 0xff,
80 .ifc_subclass = 0x42,
81 .ifc_protocol = 0x03,
82 .ifc_endpoints = 2,
83 .ifc_string = "fastboot",
84 .ept = fastboot_endpoints,
85};
Brian Swetland9c4c0752009-01-25 16:23:50 -080086
87/* todo: give lk strtoul and nuke this */
88static unsigned hex2unsigned(const char *x)
89{
90 unsigned n = 0;
91
92 while(*x) {
93 switch(*x) {
94 case '0': case '1': case '2': case '3': case '4':
95 case '5': case '6': case '7': case '8': case '9':
96 n = (n << 4) | (*x - '0');
97 break;
98 case 'a': case 'b': case 'c':
99 case 'd': case 'e': case 'f':
100 n = (n << 4) | (*x - 'a' + 10);
101 break;
102 case 'A': case 'B': case 'C':
103 case 'D': case 'E': case 'F':
104 n = (n << 4) | (*x - 'A' + 10);
105 break;
106 default:
107 return n;
108 }
109 x++;
110 }
111
112 return n;
113}
114
115struct fastboot_cmd {
116 struct fastboot_cmd *next;
117 const char *prefix;
118 unsigned prefix_len;
119 void (*handle)(const char *arg, void *data, unsigned sz);
120};
121
122struct fastboot_var {
123 struct fastboot_var *next;
124 const char *name;
125 const char *value;
126};
Amol Jadi5edf3552013-07-23 14:15:34 -0700127
Brian Swetland9c4c0752009-01-25 16:23:50 -0800128static struct fastboot_cmd *cmdlist;
129
130void fastboot_register(const char *prefix,
131 void (*handle)(const char *arg, void *data, unsigned sz))
132{
133 struct fastboot_cmd *cmd;
134 cmd = malloc(sizeof(*cmd));
135 if (cmd) {
136 cmd->prefix = prefix;
137 cmd->prefix_len = strlen(prefix);
138 cmd->handle = handle;
139 cmd->next = cmdlist;
140 cmdlist = cmd;
141 }
142}
143
144static struct fastboot_var *varlist;
145
146void fastboot_publish(const char *name, const char *value)
147{
148 struct fastboot_var *var;
149 var = malloc(sizeof(*var));
150 if (var) {
151 var->name = name;
152 var->value = value;
153 var->next = varlist;
154 varlist = var;
155 }
156}
157
158
159static event_t usb_online;
160static event_t txn_done;
Brian Swetland9c4c0752009-01-25 16:23:50 -0800161static struct udc_endpoint *in, *out;
162static struct udc_request *req;
163int txn_status;
164
165static void *download_base;
166static unsigned download_max;
167static unsigned download_size;
168
169#define STATE_OFFLINE 0
170#define STATE_COMMAND 1
171#define STATE_COMPLETE 2
172#define STATE_ERROR 3
173
174static unsigned fastboot_state = STATE_OFFLINE;
175
176static void req_complete(struct udc_request *req, unsigned actual, int status)
177{
178 txn_status = status;
179 req->length = actual;
Hanumant Singh108cdc62012-12-11 16:48:49 -0800180
Brian Swetland9c4c0752009-01-25 16:23:50 -0800181 event_signal(&txn_done, 0);
182}
183
Amol Jadi5e52d722013-08-19 17:10:33 -0700184#ifdef USB30_SUPPORT
Amol Jadi7c4316c2013-10-07 14:19:26 -0700185static int usb30_usb_read(void *buf, unsigned len)
Amol Jadi5e52d722013-08-19 17:10:33 -0700186{
187 int r;
188 struct udc_request req;
189
190 ASSERT(buf);
191 ASSERT(len);
192
193 if (fastboot_state == STATE_ERROR)
194 goto oops;
195
196 dprintf(SPEW, "usb_read(): len = %d\n", len);
197
198 req.buf = (void*) PA((addr_t)buf);
199 req.length = len;
200 req.complete = req_complete;
201
Amol Jadi7c4316c2013-10-07 14:19:26 -0700202 r = usb30_udc_request_queue(out, &req);
Amol Jadi5e52d722013-08-19 17:10:33 -0700203 if (r < 0)
204 {
205 dprintf(CRITICAL, "usb_read() queue failed. r = %d\n", r);
206 goto oops;
207 }
208 event_wait(&txn_done);
209
210 if (txn_status < 0)
211 {
212 dprintf(CRITICAL, "usb_read() transaction failed. txn_status = %d\n",
213 txn_status);
214 goto oops;
215 }
216
217 /* note: req->length is update by callback to reflect the amount of data
218 * actually read.
219 */
220 dprintf(SPEW, "usb_read(): DONE. req.length = %d\n", req.length);
221
222 /* invalidate any cached buf data (controller updates main memory) */
223 arch_invalidate_cache_range((addr_t) buf, len);
224
225 return req.length;
226
227oops:
228 fastboot_state = STATE_ERROR;
229 dprintf(CRITICAL, "usb_read(): DONE: ERROR: len = %d\n", len);
230 return -1;
231}
232
Amol Jadi7c4316c2013-10-07 14:19:26 -0700233static int usb30_usb_write(void *buf, unsigned len)
Amol Jadi5e52d722013-08-19 17:10:33 -0700234{
235 int r;
236 struct udc_request req;
237
238 ASSERT(buf);
239 ASSERT(len);
240
241 if (fastboot_state == STATE_ERROR)
242 goto oops;
243
244 dprintf(SPEW, "usb_write(): len = %d str = %s\n", len, (char *) buf);
245
246 /* flush buffer to main memory before giving to udc */
247 arch_clean_invalidate_cache_range((addr_t) buf, len);
248
249 req.buf = (void*) PA((addr_t)buf);
250 req.length = len;
251 req.complete = req_complete;
252
Amol Jadi7c4316c2013-10-07 14:19:26 -0700253 r = usb30_udc_request_queue(in, &req);
Amol Jadi5e52d722013-08-19 17:10:33 -0700254 if (r < 0) {
255 dprintf(CRITICAL, "usb_write() queue failed. r = %d\n", r);
256 goto oops;
257 }
258 event_wait(&txn_done);
259
260 dprintf(SPEW, "usb_write(): DONE: len = %d req->length = %d str = %s\n",
261 len, req.length, (char *) buf);
262
263 if (txn_status < 0) {
264 dprintf(CRITICAL, "usb_write() transaction failed. txn_status = %d\n",
265 txn_status);
266 goto oops;
267 }
268
269 return req.length;
270
271oops:
272 fastboot_state = STATE_ERROR;
273 dprintf(CRITICAL, "usb_write(): DONE: ERROR: len = %d\n", len);
274 return -1;
275}
Amol Jadi7c4316c2013-10-07 14:19:26 -0700276#endif
Amol Jadi5e52d722013-08-19 17:10:33 -0700277
Amol Jadi7c4316c2013-10-07 14:19:26 -0700278static int hsusb_usb_read(void *_buf, unsigned len)
Brian Swetland9c4c0752009-01-25 16:23:50 -0800279{
280 int r;
281 unsigned xfer;
282 unsigned char *buf = _buf;
283 int count = 0;
284
285 if (fastboot_state == STATE_ERROR)
286 goto oops;
287
288 while (len > 0) {
Shashank Mittal1cc65b02011-12-20 15:30:17 -0800289 xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
Deepa Dinamani0bf2f442012-10-19 11:41:06 -0700290 req->buf = PA((addr_t)buf);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800291 req->length = xfer;
292 req->complete = req_complete;
293 r = udc_request_queue(out, req);
294 if (r < 0) {
295 dprintf(INFO, "usb_read() queue failed\n");
296 goto oops;
297 }
298 event_wait(&txn_done);
299
300 if (txn_status < 0) {
301 dprintf(INFO, "usb_read() transaction failed\n");
302 goto oops;
303 }
304
305 count += req->length;
306 buf += req->length;
307 len -= req->length;
308
309 /* short transfer? */
310 if (req->length != xfer) break;
311 }
Hanumant Singh108cdc62012-12-11 16:48:49 -0800312 /*
313 * Force reload of buffer from memory
314 * since transaction is complete now.
315 */
316 arch_invalidate_cache_range(_buf, count);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800317 return count;
318
319oops:
320 fastboot_state = STATE_ERROR;
321 return -1;
322}
323
Amol Jadi7c4316c2013-10-07 14:19:26 -0700324static int hsusb_usb_write(void *buf, unsigned len)
Brian Swetland9c4c0752009-01-25 16:23:50 -0800325{
326 int r;
327
328 if (fastboot_state == STATE_ERROR)
329 goto oops;
330
Deepa Dinamani0bf2f442012-10-19 11:41:06 -0700331 req->buf = PA((addr_t)buf);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800332 req->length = len;
333 req->complete = req_complete;
334 r = udc_request_queue(in, req);
335 if (r < 0) {
336 dprintf(INFO, "usb_write() queue failed\n");
337 goto oops;
338 }
339 event_wait(&txn_done);
340 if (txn_status < 0) {
341 dprintf(INFO, "usb_write() transaction failed\n");
342 goto oops;
343 }
344 return req->length;
345
346oops:
347 fastboot_state = STATE_ERROR;
348 return -1;
349}
350
351void fastboot_ack(const char *code, const char *reason)
352{
Deepa Dinamani26bc2d32013-03-15 13:17:16 -0700353 STACKBUF_DMA_ALIGN(response, MAX_RSP_SIZE);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800354
355 if (fastboot_state != STATE_COMMAND)
356 return;
357
358 if (reason == 0)
359 reason = "";
360
Shashank Mittal6a5609f2011-08-04 15:51:59 -0700361 snprintf(response, MAX_RSP_SIZE, "%s%s", code, reason);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800362 fastboot_state = STATE_COMPLETE;
363
Amol Jadi7c4316c2013-10-07 14:19:26 -0700364 usb_if.usb_write(response, strlen(response));
Brian Swetland9c4c0752009-01-25 16:23:50 -0800365
366}
367
Shashank Mittal6a5609f2011-08-04 15:51:59 -0700368void fastboot_info(const char *reason)
369{
Deepa Dinamani26bc2d32013-03-15 13:17:16 -0700370 STACKBUF_DMA_ALIGN(response, MAX_RSP_SIZE);
Shashank Mittal6a5609f2011-08-04 15:51:59 -0700371
372 if (fastboot_state != STATE_COMMAND)
373 return;
374
375 if (reason == 0)
376 return;
377
378 snprintf(response, MAX_RSP_SIZE, "INFO%s", reason);
379
Amol Jadi7c4316c2013-10-07 14:19:26 -0700380 usb_if.usb_write(response, strlen(response));
Shashank Mittal6a5609f2011-08-04 15:51:59 -0700381}
382
Brian Swetland9c4c0752009-01-25 16:23:50 -0800383void fastboot_fail(const char *reason)
384{
385 fastboot_ack("FAIL", reason);
386}
387
388void fastboot_okay(const char *info)
389{
390 fastboot_ack("OKAY", info);
391}
392
393static void cmd_getvar(const char *arg, void *data, unsigned sz)
394{
395 struct fastboot_var *var;
396
397 for (var = varlist; var; var = var->next) {
398 if (!strcmp(var->name, arg)) {
399 fastboot_okay(var->value);
400 return;
401 }
402 }
403 fastboot_okay("");
404}
405
406static void cmd_download(const char *arg, void *data, unsigned sz)
407{
Deepa Dinamani26bc2d32013-03-15 13:17:16 -0700408 STACKBUF_DMA_ALIGN(response, MAX_RSP_SIZE);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800409 unsigned len = hex2unsigned(arg);
410 int r;
411
412 download_size = 0;
413 if (len > download_max) {
414 fastboot_fail("data too large");
415 return;
416 }
417
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700418 snprintf(response, MAX_RSP_SIZE, "DATA%08x", len);
Amol Jadi7c4316c2013-10-07 14:19:26 -0700419 if (usb_if.usb_write(response, strlen(response)) < 0)
Brian Swetland9c4c0752009-01-25 16:23:50 -0800420 return;
421
Amol Jadi7c4316c2013-10-07 14:19:26 -0700422 r = usb_if.usb_read(download_base, len);
Greg Griscod6250552011-06-29 14:40:23 -0700423 if ((r < 0) || ((unsigned) r != len)) {
Brian Swetland9c4c0752009-01-25 16:23:50 -0800424 fastboot_state = STATE_ERROR;
425 return;
426 }
427 download_size = len;
428 fastboot_okay("");
429}
430
431static void fastboot_command_loop(void)
432{
433 struct fastboot_cmd *cmd;
434 int r;
435 dprintf(INFO,"fastboot: processing commands\n");
436
Deepa Dinamani26bc2d32013-03-15 13:17:16 -0700437 uint8_t *buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(4096, CACHE_LINE));
438 if (!buffer)
439 {
440 dprintf(CRITICAL, "Could not allocate memory for fastboot buffer\n.");
441 ASSERT(0);
442 }
Brian Swetland9c4c0752009-01-25 16:23:50 -0800443again:
444 while (fastboot_state != STATE_ERROR) {
Amol Jadi5edf3552013-07-23 14:15:34 -0700445
446 /* Read buffer must be cleared first. If buffer is not cleared,
447 * the original data in buf trailing the received command is
448 * interpreted as part of the command.
449 */
450 memset(buffer, 0, MAX_RSP_SIZE);
451 arch_clean_invalidate_cache_range((addr_t) buffer, MAX_RSP_SIZE);
452
Amol Jadi7c4316c2013-10-07 14:19:26 -0700453 r = usb_if.usb_read(buffer, MAX_RSP_SIZE);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800454 if (r < 0) break;
455 buffer[r] = 0;
456 dprintf(INFO,"fastboot: %s\n", buffer);
457
Channagoud Kadabi69c16732013-12-05 17:29:18 -0800458 fastboot_state = STATE_COMMAND;
459
Brian Swetland9c4c0752009-01-25 16:23:50 -0800460 for (cmd = cmdlist; cmd; cmd = cmd->next) {
461 if (memcmp(buffer, cmd->prefix, cmd->prefix_len))
462 continue;
Brian Swetland9c4c0752009-01-25 16:23:50 -0800463 cmd->handle((const char*) buffer + cmd->prefix_len,
464 (void*) download_base, download_size);
465 if (fastboot_state == STATE_COMMAND)
466 fastboot_fail("unknown reason");
467 goto again;
468 }
469
470 fastboot_fail("unknown command");
Amol Jadi5edf3552013-07-23 14:15:34 -0700471
Brian Swetland9c4c0752009-01-25 16:23:50 -0800472 }
473 fastboot_state = STATE_OFFLINE;
474 dprintf(INFO,"fastboot: oops!\n");
Deepa Dinamani26bc2d32013-03-15 13:17:16 -0700475 free(buffer);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800476}
477
478static int fastboot_handler(void *arg)
479{
480 for (;;) {
481 event_wait(&usb_online);
482 fastboot_command_loop();
483 }
484 return 0;
485}
486
487static void fastboot_notify(struct udc_gadget *gadget, unsigned event)
488{
489 if (event == UDC_EVENT_ONLINE) {
490 event_signal(&usb_online, 0);
491 }
492}
493
Brian Swetland9c4c0752009-01-25 16:23:50 -0800494int fastboot_init(void *base, unsigned size)
495{
Amol Jadi5edf3552013-07-23 14:15:34 -0700496 char sn_buf[13];
Brian Swetland9c4c0752009-01-25 16:23:50 -0800497 thread_t *thr;
498 dprintf(INFO, "fastboot_init()\n");
499
500 download_base = base;
501 download_max = size;
502
Amol Jadi5edf3552013-07-23 14:15:34 -0700503 /* target specific initialization before going into fastboot. */
504 target_fastboot_init();
505
506 /* setup serialno */
507 target_serialno((unsigned char *) sn_buf);
508 dprintf(SPEW,"serial number: %s\n",sn_buf);
509 surf_udc_device.serialno = sn_buf;
510
Amol Jadi7c4316c2013-10-07 14:19:26 -0700511 if(!strcmp(target_usb_controller(), "dwc"))
512 {
513#ifdef USB30_SUPPORT
514 /* initialize udc functions to use dwc controller */
515 usb_if.udc_init = usb30_udc_init;
516 usb_if.udc_register_gadget = usb30_udc_register_gadget;
517 usb_if.udc_start = usb30_udc_start;
518 usb_if.udc_stop = usb30_udc_stop;
519
520 usb_if.udc_endpoint_alloc = usb30_udc_endpoint_alloc;
521 usb_if.udc_request_alloc = usb30_udc_request_alloc;
522 usb_if.udc_request_free = usb30_udc_request_free;
523
524 usb_if.usb_read = usb30_usb_read;
525 usb_if.usb_write = usb30_usb_write;
526#else
527 dprintf(CRITICAL, "USB30 needs to be enabled for this target.\n");
528 ASSERT(0);
529#endif
530 }
531 else
532 {
533 /* initialize udc functions to use the default chipidea controller */
534 usb_if.udc_init = udc_init;
535 usb_if.udc_register_gadget = udc_register_gadget;
536 usb_if.udc_start = udc_start;
537 usb_if.udc_stop = udc_stop;
538
539 usb_if.udc_endpoint_alloc = udc_endpoint_alloc;
540 usb_if.udc_request_alloc = udc_request_alloc;
541 usb_if.udc_request_free = udc_request_free;
542
543 usb_if.usb_read = hsusb_usb_read;
544 usb_if.usb_write = hsusb_usb_write;
545 }
546
Amol Jadi5edf3552013-07-23 14:15:34 -0700547 /* register udc device */
Amol Jadi7c4316c2013-10-07 14:19:26 -0700548 usb_if.udc_init(&surf_udc_device);
Amol Jadi5edf3552013-07-23 14:15:34 -0700549
Brian Swetland9c4c0752009-01-25 16:23:50 -0800550 event_init(&usb_online, 0, EVENT_FLAG_AUTOUNSIGNAL);
551 event_init(&txn_done, 0, EVENT_FLAG_AUTOUNSIGNAL);
552
Amol Jadi7c4316c2013-10-07 14:19:26 -0700553 in = usb_if.udc_endpoint_alloc(UDC_TYPE_BULK_IN, 512);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800554 if (!in)
555 goto fail_alloc_in;
Amol Jadi7c4316c2013-10-07 14:19:26 -0700556 out = usb_if.udc_endpoint_alloc(UDC_TYPE_BULK_OUT, 512);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800557 if (!out)
558 goto fail_alloc_out;
559
560 fastboot_endpoints[0] = in;
561 fastboot_endpoints[1] = out;
562
Amol Jadi7c4316c2013-10-07 14:19:26 -0700563 req = usb_if.udc_request_alloc();
Brian Swetland9c4c0752009-01-25 16:23:50 -0800564 if (!req)
565 goto fail_alloc_req;
566
Amol Jadi5edf3552013-07-23 14:15:34 -0700567 /* register gadget */
Amol Jadi7c4316c2013-10-07 14:19:26 -0700568 if (usb_if.udc_register_gadget(&fastboot_gadget))
Brian Swetland9c4c0752009-01-25 16:23:50 -0800569 goto fail_udc_register;
570
571 fastboot_register("getvar:", cmd_getvar);
572 fastboot_register("download:", cmd_download);
573 fastboot_publish("version", "0.5");
574
575 thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, 4096);
neetid32ba8472011-12-07 16:34:06 -0800576 if (!thr)
577 {
578 goto fail_alloc_in;
579 }
Brian Swetland9c4c0752009-01-25 16:23:50 -0800580 thread_resume(thr);
Amol Jadi5edf3552013-07-23 14:15:34 -0700581
Amol Jadi7c4316c2013-10-07 14:19:26 -0700582 usb_if.udc_start();
Amol Jadi5edf3552013-07-23 14:15:34 -0700583
Brian Swetland9c4c0752009-01-25 16:23:50 -0800584 return 0;
585
586fail_udc_register:
Amol Jadi7c4316c2013-10-07 14:19:26 -0700587 usb_if.udc_request_free(req);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800588fail_alloc_req:
Amol Jadi7c4316c2013-10-07 14:19:26 -0700589 usb_if.udc_endpoint_free(out);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800590fail_alloc_out:
Amol Jadi7c4316c2013-10-07 14:19:26 -0700591 usb_if.udc_endpoint_free(in);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800592fail_alloc_in:
593 return -1;
594}
Amol Jadi7c4316c2013-10-07 14:19:26 -0700595
596void fastboot_stop(void)
597{
598 usb_if.udc_stop();
599}