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.

412 lines
11KB

  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. struct prog_mode {
  32. char *progname;
  33. struct multiboot_ops *ops;
  34. };
  35. static struct prog_mode prog_modes[] =
  36. {
  37. { "twiboot", &twi_ops },
  38. { "mpmboot", &mpm_ops },
  39. { "funkboot", &funk_ops },
  40. };
  41. struct mboot_action
  42. {
  43. struct list_head list;
  44. char *filename;
  45. int memtype;
  46. int mode;
  47. };
  48. static LIST_HEAD(action_list);
  49. static struct option main_optargs[] =
  50. {
  51. { "help", 0, 0, 'h'}, /* [ -h ] */
  52. { "progress", 1, 0, 'p'}, /* [ -p <0|1|2> ] */
  53. { "read", 1, 0, 'r'}, /* [ -r <flash|eeprom>:<file.hex> ] */
  54. { "write", 1, 0, 'w'}, /* [ -w <flash|eeprom>:<file.hex> ] */
  55. { "no-verify", 0, 0, 'n'}, /* [ -n ] */
  56. { 0, 0, 0, 0}
  57. };
  58. /* *************************************************************************
  59. * progress_mode0_cb
  60. * ************************************************************************* */
  61. static void progress_mode0_cb(const char *msg, int pos, int size)
  62. {
  63. /* no progress output */
  64. } /* progress_mode0_cb */
  65. /* *************************************************************************
  66. * progress_mode1_cb
  67. * ************************************************************************* */
  68. static void progress_mode1_cb(const char *msg, int pos, int size)
  69. {
  70. if (pos != -1 && size != -1)
  71. {
  72. char stars[50];
  73. int i;
  74. int count = (pos * sizeof(stars) / size);
  75. for (i = 0; i < sizeof(stars); i++)
  76. {
  77. stars[i] = (i < count) ? '*' : ' ';
  78. }
  79. printf("%-15s: [%s] (%d)\r", msg, stars, pos);
  80. }
  81. if (pos == size)
  82. {
  83. printf("\n");
  84. }
  85. } /* progress_mode1_cb */
  86. /* *************************************************************************
  87. * progress_mode2_cb
  88. * ************************************************************************* */
  89. static void progress_mode2_cb(const char *msg, int pos, int size)
  90. {
  91. static int old_count;
  92. if (pos != -1 && size != -1)
  93. {
  94. if (pos == 0)
  95. {
  96. old_count = 0;
  97. printf("%-15s: [", msg);
  98. }
  99. else if (pos <=size)
  100. {
  101. int i;
  102. int count = (pos * 50 / size);
  103. for (i = old_count; i < count; i++)
  104. {
  105. printf("*");
  106. }
  107. old_count = count;
  108. if (pos == size)
  109. {
  110. printf("] (%d)\n", pos);
  111. }
  112. }
  113. }
  114. } /* progress_mode2_cb */
  115. /* *************************************************************************
  116. * add_action
  117. * ************************************************************************* */
  118. static int add_action(struct multiboot *mboot, int mode, const char *arg)
  119. {
  120. struct mboot_action *action = malloc(sizeof(struct mboot_action));
  121. if (action == NULL)
  122. {
  123. perror("malloc()");
  124. return -1;
  125. }
  126. char *argcopy = strdup(arg);
  127. if (argcopy == NULL)
  128. {
  129. perror("strdup()");
  130. free(action);
  131. return -1;
  132. }
  133. char *tok = strtok(argcopy, ":");
  134. if (tok == NULL)
  135. {
  136. fprintf(stderr, "invalid argument: '%s'\n", arg);
  137. free(argcopy);
  138. free(action);
  139. return -1;
  140. }
  141. action->memtype = mboot->ops->get_memtype(mboot, tok);
  142. if (action->memtype == -1)
  143. {
  144. fprintf(stderr, "invalid memtype: '%s'\n", tok);
  145. free(argcopy);
  146. free(action);
  147. return -1;
  148. }
  149. tok = strtok(NULL, ":");
  150. if (tok == NULL)
  151. {
  152. fprintf(stderr, "invalid argument: '%s'\n", arg);
  153. free(argcopy);
  154. free(action);
  155. return -1;
  156. }
  157. action->filename = strdup(tok);
  158. if (action->filename == NULL)
  159. {
  160. perror("strdup()");
  161. free(argcopy);
  162. free(action);
  163. return -1;
  164. }
  165. action->mode = mode;
  166. list_add_tail(&action->list, &action_list);
  167. free(argcopy);
  168. return 0;
  169. } /* add_action */
  170. /* *************************************************************************
  171. * main_optarg_cb
  172. * ************************************************************************* */
  173. static int main_optarg_cb(int val, const char *arg, void *privdata)
  174. {
  175. struct multiboot *mboot = (struct multiboot *)privdata;
  176. switch (val)
  177. {
  178. case 'r': /* read */
  179. if (add_action(mboot, ACTION_READ, arg) < 0)
  180. {
  181. return -1;
  182. }
  183. break;
  184. case 'w': /* write */
  185. if (add_action(mboot, ACTION_WRITE, arg) < 0)
  186. {
  187. return -1;
  188. }
  189. break;
  190. case 'n': /* no verify after write */
  191. mboot->verify = 0;
  192. break;
  193. case 'p':
  194. switch (*arg)
  195. {
  196. case '0':
  197. mboot->progress_cb = progress_mode0_cb;
  198. break;
  199. case '1':
  200. mboot->progress_cb = progress_mode1_cb;
  201. break;
  202. case '2':
  203. mboot->progress_cb = progress_mode2_cb;
  204. break;
  205. default:
  206. fprintf(stderr, "invalid progress bar mode: '%s'\n", arg);
  207. return -1;
  208. }
  209. break;
  210. }
  211. return 0;
  212. }
  213. /* *************************************************************************
  214. * main
  215. * ************************************************************************* */
  216. int main(int argc, char *argv[])
  217. {
  218. struct multiboot *mboot = NULL;
  219. char *progname = strrchr(argv[0], '/');
  220. progname = (progname != NULL) ? (progname +1) : argv[0];
  221. int i;
  222. for (i = 0; i < ARRAY_SIZE(prog_modes); i++)
  223. {
  224. struct prog_mode *mode = &prog_modes[i];
  225. if (strcmp(progname, mode->progname) == 0)
  226. {
  227. mboot = mode->ops->alloc();
  228. if (mboot == NULL)
  229. {
  230. fprintf(stderr, "failed to allocate '%s'\n", progname);
  231. return -1;
  232. }
  233. }
  234. }
  235. if (mboot == NULL)
  236. {
  237. fprintf(stderr, "invalid progname\n");
  238. return -1;
  239. }
  240. mboot->verify = 1;
  241. mboot->progress_cb = progress_mode1_cb;
  242. optarg_register(main_optargs, ARRAY_SIZE(main_optargs),
  243. main_optarg_cb, (void *)mboot);
  244. int abort = optarg_parse(argc, argv);
  245. if ((abort == -1) ||
  246. (mboot->ops->open(mboot) != 0)
  247. )
  248. {
  249. return -1;
  250. }
  251. setbuf(stdout, NULL);
  252. struct mboot_action *action, *tmp;
  253. list_for_each_entry(action, &action_list, list)
  254. {
  255. abort = 1;
  256. if (action->mode == ACTION_READ)
  257. {
  258. int memsize = mboot->ops->get_memsize(mboot, action->memtype);
  259. if (memsize == 0)
  260. {
  261. break;
  262. }
  263. struct databuf *dbuf = dbuf_alloc(memsize);
  264. if (dbuf == NULL)
  265. {
  266. break;
  267. }
  268. int result = mboot->ops->read(mboot, dbuf, action->memtype);
  269. if (result != 0)
  270. {
  271. fprintf(stderr, "failed to read from device\n");
  272. dbuf_free(dbuf);
  273. break;
  274. }
  275. result = file_write(action->filename, dbuf);
  276. if (result != 0)
  277. {
  278. fprintf(stderr, "failed to write file '%s'\n", action->filename);
  279. dbuf_free(dbuf);
  280. break;
  281. }
  282. dbuf_free(dbuf);
  283. abort = 0;
  284. }
  285. else if (action->mode == ACTION_WRITE)
  286. {
  287. unsigned int size;
  288. int result;
  289. result = file_getsize(action->filename, &size);
  290. if (result != 0)
  291. {
  292. break;
  293. }
  294. struct databuf *dbuf = dbuf_alloc(size);
  295. if (dbuf == NULL)
  296. {
  297. break;
  298. }
  299. result = file_read(action->filename, dbuf);
  300. if (result != 0)
  301. {
  302. fprintf(stderr, "failed to read file '%s'\n", action->filename);
  303. dbuf_free(dbuf);
  304. break;
  305. }
  306. int memsize = mboot->ops->get_memsize(mboot, action->memtype);
  307. if (memsize == 0)
  308. {
  309. fprintf(stderr, "invalid memsize: 0x%04x > 0x%04x\n", dbuf->length, memsize);
  310. dbuf_free(dbuf);
  311. break;
  312. }
  313. result = mboot->ops->write(mboot, dbuf, action->memtype);
  314. if (result != 0)
  315. {
  316. fprintf(stderr, "failed to write to device\n");
  317. dbuf_free(dbuf);
  318. break;
  319. }
  320. if (mboot->verify)
  321. {
  322. result = mboot->ops->verify(mboot, dbuf, action->memtype);
  323. if (result != 0)
  324. {
  325. fprintf(stderr, "failed to verify\n");
  326. dbuf_free(dbuf);
  327. break;
  328. }
  329. }
  330. dbuf_free(dbuf);
  331. abort = 0;
  332. }
  333. }
  334. list_for_each_entry_safe(action, tmp, &action_list, list)
  335. {
  336. free(action->filename);
  337. free(action);
  338. }
  339. mboot->ops->close(mboot);
  340. mboot->ops->free(mboot);
  341. optarg_free();
  342. return abort;
  343. } /* main */