| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- /*
- * Copyright (c) 2009, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
- #include <debug.h>
- #include <string.h>
- #include <stdlib.h>
- #include <kernel/thread.h>
- #include <kernel/event.h>
- #include <dev/udc.h>
- #define MAX_RSP_SIZE 64
- #define MAX_USBFS_BULK_SIZE (16 * 1024)
- void boot_linux(void *bootimg, unsigned sz);
- /* todo: give lk strtoul and nuke this */
- static unsigned hex2unsigned(const char *x)
- {
- unsigned n = 0;
- while(*x) {
- switch(*x) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- n = (n << 4) | (*x - '0');
- break;
- case 'a': case 'b': case 'c':
- case 'd': case 'e': case 'f':
- n = (n << 4) | (*x - 'a' + 10);
- break;
- case 'A': case 'B': case 'C':
- case 'D': case 'E': case 'F':
- n = (n << 4) | (*x - 'A' + 10);
- break;
- default:
- return n;
- }
- x++;
- }
- return n;
- }
- struct fastboot_cmd {
- struct fastboot_cmd *next;
- const char *prefix;
- unsigned prefix_len;
- void (*handle)(const char *arg, void *data, unsigned sz);
- };
- struct fastboot_var {
- struct fastboot_var *next;
- const char *name;
- const char *value;
- };
-
- static struct fastboot_cmd *cmdlist;
- void fastboot_register(const char *prefix,
- void (*handle)(const char *arg, void *data, unsigned sz))
- {
- struct fastboot_cmd *cmd;
- cmd = malloc(sizeof(*cmd));
- if (cmd) {
- cmd->prefix = prefix;
- cmd->prefix_len = strlen(prefix);
- cmd->handle = handle;
- cmd->next = cmdlist;
- cmdlist = cmd;
- }
- }
- static struct fastboot_var *varlist;
- void fastboot_publish(const char *name, const char *value)
- {
- struct fastboot_var *var;
- var = malloc(sizeof(*var));
- if (var) {
- var->name = name;
- var->value = value;
- var->next = varlist;
- varlist = var;
- }
- }
- static event_t usb_online;
- static event_t txn_done;
- static unsigned char buffer[4096];
- static struct udc_endpoint *in, *out;
- static struct udc_request *req;
- int txn_status;
- static void *download_base;
- static unsigned download_max;
- static unsigned download_size;
- #define STATE_OFFLINE 0
- #define STATE_COMMAND 1
- #define STATE_COMPLETE 2
- #define STATE_ERROR 3
- static unsigned fastboot_state = STATE_OFFLINE;
- static void req_complete(struct udc_request *req, unsigned actual, int status)
- {
- txn_status = status;
- req->length = actual;
- event_signal(&txn_done, 0);
- }
- static int usb_read(void *_buf, unsigned len)
- {
- int r;
- unsigned xfer;
- unsigned char *buf = _buf;
- int count = 0;
- if (fastboot_state == STATE_ERROR)
- goto oops;
- while (len > 0) {
- xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
- req->buf = buf;
- req->length = xfer;
- req->complete = req_complete;
- r = udc_request_queue(out, req);
- if (r < 0) {
- dprintf(INFO, "usb_read() queue failed\n");
- goto oops;
- }
- event_wait(&txn_done);
- if (txn_status < 0) {
- dprintf(INFO, "usb_read() transaction failed\n");
- goto oops;
- }
- count += req->length;
- buf += req->length;
- len -= req->length;
- /* short transfer? */
- if (req->length != xfer) break;
- }
- return count;
- oops:
- fastboot_state = STATE_ERROR;
- return -1;
- }
- static int usb_write(void *buf, unsigned len)
- {
- int r;
- if (fastboot_state == STATE_ERROR)
- goto oops;
- req->buf = buf;
- req->length = len;
- req->complete = req_complete;
- r = udc_request_queue(in, req);
- if (r < 0) {
- dprintf(INFO, "usb_write() queue failed\n");
- goto oops;
- }
- event_wait(&txn_done);
- if (txn_status < 0) {
- dprintf(INFO, "usb_write() transaction failed\n");
- goto oops;
- }
- return req->length;
- oops:
- fastboot_state = STATE_ERROR;
- return -1;
- }
- void fastboot_ack(const char *code, const char *reason)
- {
- char response[MAX_RSP_SIZE];
- if (fastboot_state != STATE_COMMAND)
- return;
- if (reason == 0)
- reason = "";
- snprintf(response, MAX_RSP_SIZE, "%s%s", code, reason);
- fastboot_state = STATE_COMPLETE;
- usb_write(response, strlen(response));
- }
- void fastboot_info(const char *reason)
- {
- char response[MAX_RSP_SIZE];
- if (fastboot_state != STATE_COMMAND)
- return;
- if (reason == 0)
- return;
- snprintf(response, MAX_RSP_SIZE, "INFO%s", reason);
- usb_write(response, strlen(response));
- }
- void fastboot_fail(const char *reason)
- {
- fastboot_ack("FAIL", reason);
- }
- void fastboot_okay(const char *info)
- {
- fastboot_ack("OKAY", info);
- }
- static void cmd_getvar(const char *arg, void *data, unsigned sz)
- {
- struct fastboot_var *var;
- for (var = varlist; var; var = var->next) {
- if (!strcmp(var->name, arg)) {
- fastboot_okay(var->value);
- return;
- }
- }
- fastboot_okay("");
- }
- static void cmd_download(const char *arg, void *data, unsigned sz)
- {
- char response[MAX_RSP_SIZE];
- unsigned len = hex2unsigned(arg);
- int r;
- download_size = 0;
- if (len > download_max) {
- fastboot_fail("data too large");
- return;
- }
- snprintf(response, MAX_RSP_SIZE, "DATA%08x", len);
- if (usb_write(response, strlen(response)) < 0)
- return;
- r = usb_read(download_base, len);
- if ((r < 0) || ((unsigned) r != len)) {
- fastboot_state = STATE_ERROR;
- return;
- }
- download_size = len;
- fastboot_okay("");
- }
- static void fastboot_command_loop(void)
- {
- struct fastboot_cmd *cmd;
- int r;
- dprintf(INFO,"fastboot: processing commands\n");
- again:
- while (fastboot_state != STATE_ERROR) {
- r = usb_read(buffer, MAX_RSP_SIZE);
- if (r < 0) break;
- buffer[r] = 0;
- dprintf(INFO,"fastboot: %s\n", buffer);
- for (cmd = cmdlist; cmd; cmd = cmd->next) {
- if (memcmp(buffer, cmd->prefix, cmd->prefix_len))
- continue;
- fastboot_state = STATE_COMMAND;
- cmd->handle((const char*) buffer + cmd->prefix_len,
- (void*) download_base, download_size);
- if (fastboot_state == STATE_COMMAND)
- fastboot_fail("unknown reason");
- goto again;
- }
- fastboot_fail("unknown command");
-
- }
- fastboot_state = STATE_OFFLINE;
- dprintf(INFO,"fastboot: oops!\n");
- }
- static int fastboot_handler(void *arg)
- {
- for (;;) {
- event_wait(&usb_online);
- fastboot_command_loop();
- }
- return 0;
- }
- static void fastboot_notify(struct udc_gadget *gadget, unsigned event)
- {
- if (event == UDC_EVENT_ONLINE) {
- event_signal(&usb_online, 0);
- }
- }
- static struct udc_endpoint *fastboot_endpoints[2];
- static struct udc_gadget fastboot_gadget = {
- .notify = fastboot_notify,
- .ifc_class = 0xff,
- .ifc_subclass = 0x42,
- .ifc_protocol = 0x03,
- .ifc_endpoints = 2,
- .ifc_string = "fastboot",
- .ept = fastboot_endpoints,
- };
- int fastboot_init(void *base, unsigned size)
- {
- thread_t *thr;
- dprintf(INFO, "fastboot_init()\n");
- download_base = base;
- download_max = size;
- event_init(&usb_online, 0, EVENT_FLAG_AUTOUNSIGNAL);
- event_init(&txn_done, 0, EVENT_FLAG_AUTOUNSIGNAL);
- #if 0
- in = udc_endpoint_alloc(UDC_TYPE_BULK_IN, 512);
- if (!in)
- goto fail_alloc_in;
- out = udc_endpoint_alloc(UDC_TYPE_BULK_OUT, 512);
- if (!out)
- goto fail_alloc_out;
- fastboot_endpoints[0] = in;
- fastboot_endpoints[1] = out;
- req = udc_request_alloc();
- if (!req)
- goto fail_alloc_req;
- if (udc_register_gadget(&fastboot_gadget))
- goto fail_udc_register;
- #endif
- fastboot_register("getvar:", cmd_getvar);
- fastboot_register("download:", cmd_download);
- fastboot_publish("version", "0.5");
-
- thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, 4096);
- if (!thr)
- {
- goto fail_alloc_in;
- }
- thread_resume(thr);
- return 0;
- fail_udc_register:
- udc_request_free(req);
- fail_alloc_req:
- udc_endpoint_free(out);
- fail_alloc_out:
- udc_endpoint_free(in);
- fail_alloc_in:
- return -1;
- }
|