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

6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 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 */