fastboot.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /*
  2. * Copyright (c) 2009, Google Inc.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in
  12. * the documentation and/or other materials provided with the
  13. * distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  16. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  17. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  18. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  19. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  20. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  21. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  22. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  23. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  24. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  25. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  26. * SUCH DAMAGE.
  27. */
  28. #include <debug.h>
  29. #include <string.h>
  30. #include <stdlib.h>
  31. #include <kernel/thread.h>
  32. #include <kernel/event.h>
  33. #include <dev/udc.h>
  34. #define MAX_RSP_SIZE 64
  35. #define MAX_USBFS_BULK_SIZE (16 * 1024)
  36. void boot_linux(void *bootimg, unsigned sz);
  37. /* todo: give lk strtoul and nuke this */
  38. static unsigned hex2unsigned(const char *x)
  39. {
  40. unsigned n = 0;
  41. while(*x) {
  42. switch(*x) {
  43. case '0': case '1': case '2': case '3': case '4':
  44. case '5': case '6': case '7': case '8': case '9':
  45. n = (n << 4) | (*x - '0');
  46. break;
  47. case 'a': case 'b': case 'c':
  48. case 'd': case 'e': case 'f':
  49. n = (n << 4) | (*x - 'a' + 10);
  50. break;
  51. case 'A': case 'B': case 'C':
  52. case 'D': case 'E': case 'F':
  53. n = (n << 4) | (*x - 'A' + 10);
  54. break;
  55. default:
  56. return n;
  57. }
  58. x++;
  59. }
  60. return n;
  61. }
  62. struct fastboot_cmd {
  63. struct fastboot_cmd *next;
  64. const char *prefix;
  65. unsigned prefix_len;
  66. void (*handle)(const char *arg, void *data, unsigned sz);
  67. };
  68. struct fastboot_var {
  69. struct fastboot_var *next;
  70. const char *name;
  71. const char *value;
  72. };
  73. static struct fastboot_cmd *cmdlist;
  74. void fastboot_register(const char *prefix,
  75. void (*handle)(const char *arg, void *data, unsigned sz))
  76. {
  77. struct fastboot_cmd *cmd;
  78. cmd = malloc(sizeof(*cmd));
  79. if (cmd) {
  80. cmd->prefix = prefix;
  81. cmd->prefix_len = strlen(prefix);
  82. cmd->handle = handle;
  83. cmd->next = cmdlist;
  84. cmdlist = cmd;
  85. }
  86. }
  87. static struct fastboot_var *varlist;
  88. void fastboot_publish(const char *name, const char *value)
  89. {
  90. struct fastboot_var *var;
  91. var = malloc(sizeof(*var));
  92. if (var) {
  93. var->name = name;
  94. var->value = value;
  95. var->next = varlist;
  96. varlist = var;
  97. }
  98. }
  99. static event_t usb_online;
  100. static event_t txn_done;
  101. static unsigned char buffer[4096];
  102. static struct udc_endpoint *in, *out;
  103. static struct udc_request *req;
  104. int txn_status;
  105. static void *download_base;
  106. static unsigned download_max;
  107. static unsigned download_size;
  108. #define STATE_OFFLINE 0
  109. #define STATE_COMMAND 1
  110. #define STATE_COMPLETE 2
  111. #define STATE_ERROR 3
  112. static unsigned fastboot_state = STATE_OFFLINE;
  113. static void req_complete(struct udc_request *req, unsigned actual, int status)
  114. {
  115. txn_status = status;
  116. req->length = actual;
  117. event_signal(&txn_done, 0);
  118. }
  119. static int usb_read(void *_buf, unsigned len)
  120. {
  121. int r;
  122. unsigned xfer;
  123. unsigned char *buf = _buf;
  124. int count = 0;
  125. if (fastboot_state == STATE_ERROR)
  126. goto oops;
  127. while (len > 0) {
  128. xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
  129. req->buf = buf;
  130. req->length = xfer;
  131. req->complete = req_complete;
  132. r = udc_request_queue(out, req);
  133. if (r < 0) {
  134. dprintf(INFO, "usb_read() queue failed\n");
  135. goto oops;
  136. }
  137. event_wait(&txn_done);
  138. if (txn_status < 0) {
  139. dprintf(INFO, "usb_read() transaction failed\n");
  140. goto oops;
  141. }
  142. count += req->length;
  143. buf += req->length;
  144. len -= req->length;
  145. /* short transfer? */
  146. if (req->length != xfer) break;
  147. }
  148. return count;
  149. oops:
  150. fastboot_state = STATE_ERROR;
  151. return -1;
  152. }
  153. static int usb_write(void *buf, unsigned len)
  154. {
  155. int r;
  156. if (fastboot_state == STATE_ERROR)
  157. goto oops;
  158. req->buf = buf;
  159. req->length = len;
  160. req->complete = req_complete;
  161. r = udc_request_queue(in, req);
  162. if (r < 0) {
  163. dprintf(INFO, "usb_write() queue failed\n");
  164. goto oops;
  165. }
  166. event_wait(&txn_done);
  167. if (txn_status < 0) {
  168. dprintf(INFO, "usb_write() transaction failed\n");
  169. goto oops;
  170. }
  171. return req->length;
  172. oops:
  173. fastboot_state = STATE_ERROR;
  174. return -1;
  175. }
  176. void fastboot_ack(const char *code, const char *reason)
  177. {
  178. char response[MAX_RSP_SIZE];
  179. if (fastboot_state != STATE_COMMAND)
  180. return;
  181. if (reason == 0)
  182. reason = "";
  183. snprintf(response, MAX_RSP_SIZE, "%s%s", code, reason);
  184. fastboot_state = STATE_COMPLETE;
  185. usb_write(response, strlen(response));
  186. }
  187. void fastboot_info(const char *reason)
  188. {
  189. char response[MAX_RSP_SIZE];
  190. if (fastboot_state != STATE_COMMAND)
  191. return;
  192. if (reason == 0)
  193. return;
  194. snprintf(response, MAX_RSP_SIZE, "INFO%s", reason);
  195. usb_write(response, strlen(response));
  196. }
  197. void fastboot_fail(const char *reason)
  198. {
  199. fastboot_ack("FAIL", reason);
  200. }
  201. void fastboot_okay(const char *info)
  202. {
  203. fastboot_ack("OKAY", info);
  204. }
  205. static void cmd_getvar(const char *arg, void *data, unsigned sz)
  206. {
  207. struct fastboot_var *var;
  208. for (var = varlist; var; var = var->next) {
  209. if (!strcmp(var->name, arg)) {
  210. fastboot_okay(var->value);
  211. return;
  212. }
  213. }
  214. fastboot_okay("");
  215. }
  216. static void cmd_download(const char *arg, void *data, unsigned sz)
  217. {
  218. char response[MAX_RSP_SIZE];
  219. unsigned len = hex2unsigned(arg);
  220. int r;
  221. download_size = 0;
  222. if (len > download_max) {
  223. fastboot_fail("data too large");
  224. return;
  225. }
  226. snprintf(response, MAX_RSP_SIZE, "DATA%08x", len);
  227. if (usb_write(response, strlen(response)) < 0)
  228. return;
  229. r = usb_read(download_base, len);
  230. if ((r < 0) || ((unsigned) r != len)) {
  231. fastboot_state = STATE_ERROR;
  232. return;
  233. }
  234. download_size = len;
  235. fastboot_okay("");
  236. }
  237. static void fastboot_command_loop(void)
  238. {
  239. struct fastboot_cmd *cmd;
  240. int r;
  241. dprintf(INFO,"fastboot: processing commands\n");
  242. again:
  243. while (fastboot_state != STATE_ERROR) {
  244. r = usb_read(buffer, MAX_RSP_SIZE);
  245. if (r < 0) break;
  246. buffer[r] = 0;
  247. dprintf(INFO,"fastboot: %s\n", buffer);
  248. for (cmd = cmdlist; cmd; cmd = cmd->next) {
  249. if (memcmp(buffer, cmd->prefix, cmd->prefix_len))
  250. continue;
  251. fastboot_state = STATE_COMMAND;
  252. cmd->handle((const char*) buffer + cmd->prefix_len,
  253. (void*) download_base, download_size);
  254. if (fastboot_state == STATE_COMMAND)
  255. fastboot_fail("unknown reason");
  256. goto again;
  257. }
  258. fastboot_fail("unknown command");
  259. }
  260. fastboot_state = STATE_OFFLINE;
  261. dprintf(INFO,"fastboot: oops!\n");
  262. }
  263. static int fastboot_handler(void *arg)
  264. {
  265. for (;;) {
  266. event_wait(&usb_online);
  267. fastboot_command_loop();
  268. }
  269. return 0;
  270. }
  271. static void fastboot_notify(struct udc_gadget *gadget, unsigned event)
  272. {
  273. if (event == UDC_EVENT_ONLINE) {
  274. event_signal(&usb_online, 0);
  275. }
  276. }
  277. static struct udc_endpoint *fastboot_endpoints[2];
  278. static struct udc_gadget fastboot_gadget = {
  279. .notify = fastboot_notify,
  280. .ifc_class = 0xff,
  281. .ifc_subclass = 0x42,
  282. .ifc_protocol = 0x03,
  283. .ifc_endpoints = 2,
  284. .ifc_string = "fastboot",
  285. .ept = fastboot_endpoints,
  286. };
  287. int fastboot_init(void *base, unsigned size)
  288. {
  289. thread_t *thr;
  290. dprintf(INFO, "fastboot_init()\n");
  291. download_base = base;
  292. download_max = size;
  293. event_init(&usb_online, 0, EVENT_FLAG_AUTOUNSIGNAL);
  294. event_init(&txn_done, 0, EVENT_FLAG_AUTOUNSIGNAL);
  295. #if 0
  296. in = udc_endpoint_alloc(UDC_TYPE_BULK_IN, 512);
  297. if (!in)
  298. goto fail_alloc_in;
  299. out = udc_endpoint_alloc(UDC_TYPE_BULK_OUT, 512);
  300. if (!out)
  301. goto fail_alloc_out;
  302. fastboot_endpoints[0] = in;
  303. fastboot_endpoints[1] = out;
  304. req = udc_request_alloc();
  305. if (!req)
  306. goto fail_alloc_req;
  307. if (udc_register_gadget(&fastboot_gadget))
  308. goto fail_udc_register;
  309. #endif
  310. fastboot_register("getvar:", cmd_getvar);
  311. fastboot_register("download:", cmd_download);
  312. fastboot_publish("version", "0.5");
  313. thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, 4096);
  314. if (!thr)
  315. {
  316. goto fail_alloc_in;
  317. }
  318. thread_resume(thr);
  319. return 0;
  320. fail_udc_register:
  321. udc_request_free(req);
  322. fail_alloc_req:
  323. udc_endpoint_free(out);
  324. fail_alloc_out:
  325. udc_endpoint_free(in);
  326. fail_alloc_in:
  327. return -1;
  328. }