You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

multiboot.c 11KB

11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /***************************************************************************
  2. * Copyright (C) 10/2010 by Olaf Rempel *
  3. * razzor@kopf-tisch.de *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; version 2 of the License, *
  8. * *
  9. * This program is distributed in the hope that it will be useful, *
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  12. * GNU General Public License for more details. *
  13. * *
  14. * You should have received a copy of the GNU General Public License *
  15. * along with this program; if not, write to the *
  16. * Free Software Foundation, Inc., *
  17. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  18. ***************************************************************************/
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <unistd.h>
  22. #include <string.h>
  23. #include <getopt.h>
  24. #include "filedata.h"
  25. #include "list.h"
  26. #include "multiboot.h"
  27. #include "optarg.h"
  28. #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
  29. #define ACTION_READ 0x01
  30. #define ACTION_WRITE 0x02
  31. static struct multiboot_ops * prog_ops[] =
  32. {
  33. &twi_ops,
  34. &mpm_ops,
  35. &funk_ops,
  36. &eprog_ops,
  37. &butterfly_ops,
  38. };
  39. struct mboot_action
  40. {
  41. struct list_head list;
  42. char *filename;
  43. int memtype;
  44. int mode;
  45. };
  46. static LIST_HEAD(action_list);
  47. static struct option main_optargs[] =
  48. {
  49. { "help", 0, 0, 'h'}, /* [ -h ] */
  50. { "progress", 1, 0, 'p'}, /* [ -p <0|1|2> ] */
  51. { "read", 1, 0, 'r'}, /* [ -r <flash|eeprom>:<file.hex> ] */
  52. { "write", 1, 0, 'w'}, /* [ -w <flash|eeprom>:<file.hex> ] */
  53. { "no-verify", 0, 0, 'n'}, /* [ -n ] */
  54. { 0, 0, 0, 0}
  55. };
  56. /* *************************************************************************
  57. * progress_mode0_cb
  58. * ************************************************************************* */
  59. static void progress_mode0_cb(const char *msg, int pos, int size)
  60. {
  61. /* unused parameter */
  62. (void)msg;
  63. (void)pos;
  64. (void)size;
  65. /* no progress output */
  66. } /* progress_mode0_cb */
  67. /* *************************************************************************
  68. * progress_mode1_cb
  69. * ************************************************************************* */
  70. static void progress_mode1_cb(const char *msg, int pos, int size)
  71. {
  72. if (pos != -1 && size > 0)
  73. {
  74. char stars[51];
  75. int i;
  76. int count = (pos * 50 / size);
  77. for (i = 0; i < 50; i++)
  78. {
  79. stars[i] = (i < count) ? '*' : ' ';
  80. }
  81. stars[50] = '\0';
  82. printf("%-15s: [%s] (%d)\r", msg, stars, pos);
  83. }
  84. if (pos == size)
  85. {
  86. printf("\n");
  87. }
  88. } /* progress_mode1_cb */
  89. /* *************************************************************************
  90. * progress_mode2_cb
  91. * ************************************************************************* */
  92. static void progress_mode2_cb(const char *msg, int pos, int size)
  93. {
  94. static int old_count;
  95. if (pos != -1 && size > 0)
  96. {
  97. if (pos == 0)
  98. {
  99. old_count = 0;
  100. printf("%-15s: [", msg);
  101. }
  102. else if (pos <=size)
  103. {
  104. int i;
  105. int count = (pos * 50 / size);
  106. for (i = old_count; i < count; i++)
  107. {
  108. printf("*");
  109. }
  110. old_count = count;
  111. if (pos == size)
  112. {
  113. printf("] (%d)\n", pos);
  114. }
  115. }
  116. }
  117. } /* progress_mode2_cb */
  118. /* *************************************************************************
  119. * add_action
  120. * ************************************************************************* */
  121. static int add_action(struct multiboot *mboot, int mode, const char *arg)
  122. {
  123. struct mboot_action *action = malloc(sizeof(struct mboot_action));
  124. if (action == NULL)
  125. {
  126. perror("malloc()");
  127. return -1;
  128. }
  129. char *argcopy = strdup(arg);
  130. if (argcopy == NULL)
  131. {
  132. perror("strdup()");
  133. free(action);
  134. return -1;
  135. }
  136. char *tok = strtok(argcopy, ":");
  137. if (tok == NULL)
  138. {
  139. fprintf(stderr, "invalid argument: '%s'\n", arg);
  140. free(argcopy);
  141. free(action);
  142. return -1;
  143. }
  144. action->memtype = mboot->ops->get_memtype(mboot, tok);
  145. if (action->memtype == -1)
  146. {
  147. fprintf(stderr, "invalid memtype: '%s'\n", tok);
  148. free(argcopy);
  149. free(action);
  150. return -1;
  151. }
  152. tok = strtok(NULL, ":");
  153. if (tok == NULL)
  154. {
  155. fprintf(stderr, "invalid argument: '%s'\n", arg);
  156. free(argcopy);
  157. free(action);
  158. return -1;
  159. }
  160. action->filename = strdup(tok);
  161. if (action->filename == NULL)
  162. {
  163. perror("strdup()");
  164. free(argcopy);
  165. free(action);
  166. return -1;
  167. }
  168. action->mode = mode;
  169. list_add_tail(&action->list, &action_list);
  170. free(argcopy);
  171. return 0;
  172. } /* add_action */
  173. /* *************************************************************************
  174. * main_optarg_cb
  175. * ************************************************************************* */
  176. static int main_optarg_cb(int val, const char *arg, void *privdata)
  177. {
  178. struct multiboot *mboot = (struct multiboot *)privdata;
  179. switch (val)
  180. {
  181. case 'r': /* read */
  182. if ((mboot->ops->read == NULL) ||
  183. (add_action(mboot, ACTION_READ, arg) < 0)
  184. )
  185. {
  186. return -1;
  187. }
  188. break;
  189. case 'w': /* write */
  190. if ((mboot->ops->write == NULL) ||
  191. (add_action(mboot, ACTION_WRITE, arg) < 0)
  192. )
  193. {
  194. return -1;
  195. }
  196. break;
  197. case 'n': /* no verify after write */
  198. mboot->verify = 0;
  199. break;
  200. case 'p':
  201. switch (*arg)
  202. {
  203. case '0':
  204. mboot->progress_cb = progress_mode0_cb;
  205. break;
  206. case '1':
  207. mboot->progress_cb = progress_mode1_cb;
  208. break;
  209. case '2':
  210. mboot->progress_cb = progress_mode2_cb;
  211. break;
  212. default:
  213. fprintf(stderr, "invalid progress bar mode: '%s'\n", arg);
  214. return -1;
  215. }
  216. break;
  217. }
  218. return 0;
  219. }
  220. /* *************************************************************************
  221. * main
  222. * ************************************************************************* */
  223. int main(int argc, char *argv[])
  224. {
  225. struct multiboot *mboot = NULL;
  226. char *progname = strrchr(argv[0], '/');
  227. progname = (progname != NULL) ? (progname +1) : argv[0];
  228. unsigned int i;
  229. for (i = 0; i < ARRAY_SIZE(prog_ops); i++)
  230. {
  231. struct multiboot_ops * ops = prog_ops[i];
  232. if (strcmp(progname, ops->exec_name) == 0)
  233. {
  234. mboot = ops->alloc();
  235. if (mboot == NULL)
  236. {
  237. fprintf(stderr, "failed to allocate '%s'\n",
  238. progname);
  239. return -1;
  240. }
  241. }
  242. }
  243. if (mboot == NULL)
  244. {
  245. fprintf(stderr, "invalid progname\n");
  246. return -1;
  247. }
  248. mboot->verify = 1;
  249. mboot->progress_cb = progress_mode1_cb;
  250. optarg_register(main_optargs, ARRAY_SIZE(main_optargs),
  251. main_optarg_cb, (void *)mboot);
  252. int abort = optarg_parse(argc, argv);
  253. if ((abort == -1) ||
  254. (mboot->ops->open(mboot) != 0)
  255. )
  256. {
  257. return -1;
  258. }
  259. setbuf(stdout, NULL);
  260. struct mboot_action *action, *tmp;
  261. list_for_each_entry(action, &action_list, list)
  262. {
  263. abort = 1;
  264. if (action->mode == ACTION_READ)
  265. {
  266. int memsize = mboot->ops->get_memsize(mboot, action->memtype);
  267. if (memsize == 0)
  268. {
  269. break;
  270. }
  271. struct databuf *dbuf = dbuf_alloc(memsize);
  272. if (dbuf == NULL)
  273. {
  274. break;
  275. }
  276. int result = mboot->ops->read(mboot, dbuf, action->memtype);
  277. if (result != 0)
  278. {
  279. fprintf(stderr, "failed to read from device\n");
  280. dbuf_free(dbuf);
  281. break;
  282. }
  283. result = file_write(action->filename, dbuf);
  284. if (result != 0)
  285. {
  286. fprintf(stderr, "failed to write file '%s'\n", action->filename);
  287. dbuf_free(dbuf);
  288. break;
  289. }
  290. dbuf_free(dbuf);
  291. abort = 0;
  292. }
  293. else if (action->mode == ACTION_WRITE)
  294. {
  295. unsigned int size;
  296. int result;
  297. result = file_getsize(action->filename, &size);
  298. if (result != 0)
  299. {
  300. break;
  301. }
  302. struct databuf *dbuf = dbuf_alloc(size);
  303. if (dbuf == NULL)
  304. {
  305. break;
  306. }
  307. result = file_read(action->filename, dbuf);
  308. if (result != 0)
  309. {
  310. fprintf(stderr, "failed to read file '%s'\n", action->filename);
  311. dbuf_free(dbuf);
  312. break;
  313. }
  314. int memsize = mboot->ops->get_memsize(mboot, action->memtype);
  315. if (memsize == 0)
  316. {
  317. fprintf(stderr, "invalid memsize: 0x%04x > 0x%04x\n", dbuf->length, memsize);
  318. dbuf_free(dbuf);
  319. break;
  320. }
  321. result = mboot->ops->write(mboot, dbuf, action->memtype);
  322. if (result != 0)
  323. {
  324. fprintf(stderr, "failed to write to device\n");
  325. dbuf_free(dbuf);
  326. break;
  327. }
  328. if (mboot->verify &&
  329. (mboot->ops->verify != NULL)
  330. )
  331. {
  332. result = mboot->ops->verify(mboot, dbuf, action->memtype);
  333. if (result != 0)
  334. {
  335. fprintf(stderr, "failed to verify\n");
  336. dbuf_free(dbuf);
  337. break;
  338. }
  339. }
  340. dbuf_free(dbuf);
  341. abort = 0;
  342. }
  343. }
  344. list_for_each_entry_safe(action, tmp, &action_list, list)
  345. {
  346. free(action->filename);
  347. free(action);
  348. }
  349. mboot->ops->close(mboot);
  350. mboot->ops->free(mboot);
  351. optarg_free();
  352. return abort;
  353. } /* main */