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.

mpm.c 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <sys/socket.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <fcntl.h>
  9. #include <termios.h>
  10. #include <sys/time.h>
  11. #include "chipinfo_avr.h"
  12. #include "multiboot.h"
  13. #include "optarg.h"
  14. #define READ_BLOCK_SIZE 256 /* bytes in one flash/eeprom read request */
  15. #define WRITE_BLOCK_SIZE 16 /* bytes in one eeprom write request */
  16. #define CMD_SWITCH_APPLICATION 0x01
  17. #define CMD_GET_BOOTLOADER_VERSION 0x02
  18. #define CMD_GET_CHIP_INFO 0x03
  19. #define CMD_READ_MEMORY 0x11
  20. #define CMD_WRITE_MEMORY 0x12
  21. #define CAUSE_SUCCESS 0x00
  22. #define CAUSE_COMMAND_NOT_SUPPORTED 0xF0
  23. #define CAUSE_INVALID_PARAMETER 0xF1
  24. #define CAUSE_UNSPECIFIED_ERROR 0xFF
  25. /* CMD_SWITCH_APPLICATION parameter */
  26. #define BOOTTYPE_BOOTLOADER 0x00
  27. #define BOOTTYPE_APPLICATION 0x80
  28. #define MEMTYPE_FLASH 0x01
  29. #define MEMTYPE_EEPROM 0x02
  30. #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
  31. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  32. struct multiboot_ops mpm_ops;
  33. struct mpm_privdata
  34. {
  35. char *device;
  36. int fd;
  37. int connected;
  38. int address;
  39. int flashsize;
  40. int flashpage;
  41. int eepromsize;
  42. struct termios oldtio;
  43. };
  44. static struct option mpm_optargs[] =
  45. {
  46. { "address", 1, 0, 'a'}, /* -a <addr> */
  47. { "device", 1, 0, 'd'}, /* [ -d <device> ] */
  48. };
  49. /* *************************************************************************
  50. * mpm_optarg_cb
  51. * ************************************************************************* */
  52. static int mpm_optarg_cb(int val, const char *arg, void *privdata)
  53. {
  54. struct mpm_privdata *mpm = (struct mpm_privdata *)privdata;
  55. switch (val)
  56. {
  57. case 'a': /* address */
  58. {
  59. char *endptr;
  60. mpm->address = strtol(arg, &endptr, 16);
  61. if (*endptr != '\0' || mpm->address < 0x01 || mpm->address > 0x7F)
  62. {
  63. fprintf(stderr, "invalid address: '%s'\n", arg);
  64. return -1;
  65. }
  66. }
  67. break;
  68. case 'd': /* device */
  69. if (mpm->device != NULL)
  70. {
  71. fprintf(stderr, "invalid device: '%s'\n", optarg);
  72. return -1;
  73. }
  74. mpm->device = strdup(optarg);
  75. if (mpm->device == NULL)
  76. {
  77. perror("strdup()");
  78. return -1;
  79. }
  80. break;
  81. case 'h':
  82. case '?': /* error */
  83. fprintf(stderr, "Usage: mpmboot [options]\n"
  84. " -a <address> - selects mpm address (0x01 - 0xFF)\n"
  85. " -d <device> - selects mpm device\n"
  86. " -r <flash|eeprom>:<file> - reads flash/eeprom to file (.bin | .hex | -)\n"
  87. " -w <flash|eeprom>:<file> - write flash/eeprom from file (.bin | .hex)\n"
  88. " -n - disable verify after write\n"
  89. " -p <0|1|2> - progress bar mode\n"
  90. "\n"
  91. "Example: mpmboot -d /dev/ttyUSB0 -a 0x22 -w flash:blmc.hex -w flash:blmc_eeprom.hex\n"
  92. "\n");
  93. return -1;
  94. default:
  95. return 1;
  96. }
  97. return 0;
  98. } /* mpm_optarg_cb */
  99. /* *************************************************************************
  100. * mpm_alloc
  101. * ************************************************************************* */
  102. static struct multiboot * mpm_alloc(void)
  103. {
  104. struct multiboot * mboot = malloc(sizeof(struct multiboot));
  105. if (mboot == NULL)
  106. {
  107. return NULL;
  108. }
  109. memset(mboot, 0x00, sizeof(struct multiboot));
  110. mboot->ops = &mpm_ops;
  111. struct mpm_privdata *mpm = malloc(sizeof(struct mpm_privdata));
  112. if (mpm == NULL)
  113. {
  114. free(mboot);
  115. return NULL;
  116. }
  117. memset(mpm, 0x00, sizeof(struct mpm_privdata));
  118. mpm->device = NULL;
  119. mpm->address = 0;
  120. optarg_register(mpm_optargs, ARRAY_SIZE(mpm_optargs),
  121. mpm_optarg_cb, (void *)mpm);
  122. mboot->privdata = mpm;
  123. return mboot;
  124. } /* mpm_alloc */
  125. /* *************************************************************************
  126. * mpm_free
  127. * ************************************************************************* */
  128. static void mpm_free(struct multiboot *mboot)
  129. {
  130. struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
  131. if (mpm->device != NULL)
  132. {
  133. free(mpm->device);
  134. }
  135. free(mpm);
  136. free(mboot);
  137. } /* mpm_free */
  138. /* *************************************************************************
  139. * mpm_get_memtype
  140. * ************************************************************************* */
  141. static int mpm_get_memtype(struct multiboot *mboot,
  142. const char *memname)
  143. {
  144. if (strcmp(memname, "flash") == 0)
  145. {
  146. return MEMTYPE_FLASH;
  147. }
  148. else if (strcmp(memname, "eeprom") == 0)
  149. {
  150. return MEMTYPE_EEPROM;
  151. }
  152. return -1;
  153. } /* mpm_get_memtype */
  154. /* *************************************************************************
  155. * mpm_get_memsize
  156. * ************************************************************************* */
  157. static int mpm_get_memsize(struct multiboot *mboot, int memtype)
  158. {
  159. struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
  160. if (!mpm->connected)
  161. {
  162. return 0;
  163. }
  164. switch (memtype)
  165. {
  166. case MEMTYPE_FLASH:
  167. return mpm->flashsize;
  168. case MEMTYPE_EEPROM:
  169. return mpm->eepromsize;
  170. default:
  171. return 0;
  172. }
  173. } /* mpm_get_memsize */
  174. /* *************************************************************************
  175. * mpm_send
  176. * ************************************************************************* */
  177. static int mpm_send(struct mpm_privdata *mpm, uint8_t command,
  178. uint8_t *data, int length)
  179. {
  180. struct termios tio;
  181. if (tcgetattr(mpm->fd, &tio) < 0)
  182. {
  183. perror("tcgetattr(tio)");
  184. return -1;
  185. }
  186. tio.c_cflag |= PARODD;
  187. if (tcsetattr(mpm->fd, TCSAFLUSH, &tio) < 0)
  188. {
  189. perror("tcsetattr(tio)");
  190. return -1;
  191. }
  192. // usleep(5000);
  193. uint8_t address = mpm->address;
  194. if (write(mpm->fd, &address, sizeof(address)) != sizeof(address))
  195. {
  196. perror("write(address)");
  197. return -1;
  198. }
  199. usleep(500);
  200. tio.c_cflag &= ~(PARODD);
  201. if (tcsetattr(mpm->fd, TCSAFLUSH, &tio) < 0)
  202. {
  203. perror("tcsetattr(tio)");
  204. return -1;
  205. }
  206. uint8_t header[3];
  207. header[0] = command;
  208. header[1] = (length >> 8) & 0xFF;
  209. header[2] = length & 0xFF;
  210. if (write(mpm->fd, header, sizeof(header)) != sizeof(header))
  211. {
  212. perror("write(header)");
  213. return -1;
  214. }
  215. if (data != NULL && length != 0)
  216. {
  217. if (write(mpm->fd, data, length) != length)
  218. {
  219. perror("write(data)");
  220. return -1;
  221. }
  222. }
  223. return 0;
  224. } /* mpm_send */
  225. /* *************************************************************************
  226. * myread
  227. * ************************************************************************* */
  228. static int myread(int fd, void *data, int size)
  229. {
  230. int pos = 0;
  231. while (1)
  232. {
  233. fd_set fdset;
  234. struct timeval timeout = { .tv_sec = 1, .tv_usec = 0 };
  235. FD_ZERO(&fdset);
  236. FD_SET(fd, &fdset);
  237. int ret = select(fd +1, &fdset, NULL, NULL, &timeout);
  238. if (ret == -1)
  239. {
  240. perror("select");
  241. return -1;
  242. }
  243. else if (ret == 0)
  244. {
  245. break;
  246. }
  247. else if (FD_ISSET(fd, &fdset))
  248. {
  249. int len = read(fd, data + pos, size - pos);
  250. if (len < 0)
  251. {
  252. return -1;
  253. }
  254. else
  255. {
  256. pos += len;
  257. if (pos == size)
  258. {
  259. break;
  260. }
  261. }
  262. }
  263. }
  264. return pos;
  265. } /* myread */
  266. /* *************************************************************************
  267. * mpm_recv
  268. * ************************************************************************* */
  269. static int mpm_recv(struct mpm_privdata *mpm,
  270. uint8_t command,
  271. uint8_t *cause,
  272. uint8_t *buffer,
  273. uint16_t buffersize)
  274. {
  275. int len;
  276. uint8_t header[4];
  277. len = myread(mpm->fd, header, sizeof(header));
  278. if (len != sizeof(header))
  279. {
  280. fprintf(stderr, "short read() from device (not addressed?)\n");
  281. return -1;
  282. }
  283. if (header[0] != command)
  284. {
  285. fprintf(stderr, "invalid command response (0x%02x != 0x%02x)\n", header[0], command);
  286. return -1;
  287. }
  288. *cause = header[1];
  289. uint16_t length = (header[2] << 8) | header[3];
  290. // printf("mpm_recv() cmd=0x%02x cause=0x%02x length=0x%04x\n", command, *cause, length);
  291. uint16_t bufferpos = 0;
  292. while (length > 0)
  293. {
  294. /* free space in output buffer? */
  295. if ((bufferpos < buffersize) && (buffer != NULL))
  296. {
  297. uint16_t size = MIN(buffersize - bufferpos, length);
  298. len = myread(mpm->fd, buffer + bufferpos, size);
  299. if (len <= 0)
  300. {
  301. fprintf(stderr, "short read() from device (%d != %d)\n", len, size);
  302. return -1;
  303. }
  304. bufferpos += len;
  305. length -= len;
  306. }
  307. else
  308. {
  309. uint8_t dummy[256];
  310. /* no space in output buffer, but device still sends data -> do dummy read */
  311. uint16_t size = MIN(sizeof(dummy), length);
  312. len = myread(mpm->fd, dummy, size);
  313. if (len <= 0)
  314. {
  315. fprintf(stderr, "short read() from device (%d != %d)\n", len, size);
  316. return -1;
  317. }
  318. length -= len;
  319. }
  320. }
  321. return bufferpos;
  322. } /* mpm_recv */
  323. /* *************************************************************************
  324. * mpm_close_device
  325. * ************************************************************************* */
  326. static void mpm_close_device(struct mpm_privdata *mpm)
  327. {
  328. /* delay close() / tcsetattr() */
  329. usleep(100000);
  330. tcsetattr(mpm->fd, TCSANOW, &mpm->oldtio);
  331. close(mpm->fd);
  332. } /* mpm_close_device */
  333. /* *************************************************************************
  334. * mpm_open_device
  335. * ************************************************************************* */
  336. static int mpm_open_device(struct mpm_privdata *mpm)
  337. {
  338. mpm->fd = open(mpm->device, O_RDWR | O_NOCTTY | O_CLOEXEC);
  339. if (mpm->fd < 0)
  340. {
  341. perror("open()");
  342. return -1;
  343. }
  344. if (tcgetattr(mpm->fd, &mpm->oldtio) < 0)
  345. {
  346. perror("tcgetattr(oldtio)");
  347. close(mpm->fd);
  348. return -1;
  349. }
  350. struct termios newtio;
  351. memset(&newtio, 0, sizeof(newtio));
  352. newtio.c_iflag |= IGNBRK;
  353. newtio.c_cflag |= B115200 | CS8 | CLOCAL | CREAD | PARENB | CMSPAR;
  354. newtio.c_cc[VMIN] = 1;
  355. newtio.c_cc[VTIME] = 0;
  356. int err = tcsetattr(mpm->fd, TCSANOW, &newtio);
  357. if (err < 0)
  358. {
  359. perror("tcsetattr(newtio)");
  360. close(mpm->fd);
  361. return -1;
  362. }
  363. mpm->connected = 1;
  364. return 0;
  365. } /* mpm_open_device */
  366. /* *************************************************************************
  367. * mpm_switch_application
  368. * ************************************************************************* */
  369. static int mpm_switch_application(struct mpm_privdata *mpm,
  370. uint8_t application)
  371. {
  372. uint8_t data[] = { application };
  373. int ret = mpm_send(mpm, CMD_SWITCH_APPLICATION, data, sizeof(data));
  374. if (ret < 0)
  375. {
  376. return ret;
  377. }
  378. uint8_t cause = CAUSE_SUCCESS;
  379. ret = mpm_recv(mpm, CMD_SWITCH_APPLICATION, &cause, NULL, 0);
  380. if (ret < 0)
  381. {
  382. return ret;
  383. }
  384. return (cause != CAUSE_SUCCESS);
  385. } /* mpm_switch_application */
  386. /* *************************************************************************
  387. * mpm_read_version
  388. * ************************************************************************* */
  389. static int mpm_read_version(struct mpm_privdata *mpm,
  390. uint8_t *version, uint16_t length)
  391. {
  392. memset(version, 0, length);
  393. int ret = mpm_send(mpm, CMD_GET_BOOTLOADER_VERSION, NULL, 0);
  394. if (ret < 0)
  395. {
  396. return ret;
  397. }
  398. uint8_t cause = CAUSE_SUCCESS;
  399. ret = mpm_recv(mpm, CMD_GET_BOOTLOADER_VERSION, &cause, version, length);
  400. if (ret < 0)
  401. {
  402. return ret;
  403. }
  404. int i;
  405. for (i = 0; i < length; i++)
  406. {
  407. version[i] &= ~0x80;
  408. }
  409. return (cause != CAUSE_SUCCESS);
  410. }
  411. /* *************************************************************************
  412. * mpm_read_chipinfo
  413. * ************************************************************************* */
  414. static int mpm_read_chipinfo(struct mpm_privdata *mpm,
  415. uint8_t *chipinfo, uint16_t length)
  416. {
  417. int ret = mpm_send(mpm, CMD_GET_CHIP_INFO, NULL, 0);
  418. if (ret < 0)
  419. {
  420. return ret;
  421. }
  422. uint8_t cause = CAUSE_SUCCESS;
  423. ret = mpm_recv(mpm, CMD_GET_CHIP_INFO, &cause, chipinfo, length);
  424. if (ret < 0)
  425. {
  426. return ret;
  427. }
  428. return (cause != CAUSE_SUCCESS);
  429. } /* mpm_read_chipinfo */
  430. /* *************************************************************************
  431. * mpm_read_memory
  432. * ************************************************************************* */
  433. static int mpm_read_memory(struct mpm_privdata *mpm,
  434. uint8_t *buffer, uint16_t size,
  435. uint8_t memtype, uint16_t address)
  436. {
  437. uint8_t param[5] = {
  438. memtype,
  439. (address >> 8) & 0xFF,
  440. (address & 0xFF),
  441. (size >> 8) & 0xFF,
  442. (size & 0xFF)
  443. };
  444. int ret = mpm_send(mpm, CMD_READ_MEMORY, param, sizeof(param));
  445. if (ret < 0)
  446. {
  447. return ret;
  448. }
  449. uint8_t cause = CAUSE_SUCCESS;
  450. ret = mpm_recv(mpm, CMD_READ_MEMORY, &cause, buffer, size);
  451. if (ret < 0)
  452. {
  453. return ret;
  454. }
  455. return (cause != CAUSE_SUCCESS);
  456. } /* mpm_read_memory */
  457. /* *************************************************************************
  458. * mpm_write_memory
  459. * ************************************************************************* */
  460. static int mpm_write_memory(struct mpm_privdata *mpm,
  461. uint8_t *buffer, uint16_t size,
  462. uint8_t memtype, uint16_t address)
  463. {
  464. int bufsize;
  465. if (memtype == MEMTYPE_FLASH)
  466. {
  467. if ((address & (mpm->flashpage -1)) != 0x00)
  468. {
  469. fprintf(stderr, "mpm_write_memory(): address 0x%04x not aligned to pagesize 0x%02x\n", address, mpm->flashpage);
  470. return -1;
  471. }
  472. bufsize = 5 + mpm->flashpage;
  473. }
  474. else
  475. {
  476. bufsize = 5 + size;
  477. }
  478. uint8_t *cmd = malloc(bufsize);
  479. if (cmd == NULL)
  480. {
  481. return -1;
  482. }
  483. cmd[0] = memtype;
  484. cmd[1] = (address >> 8) & 0xFF;
  485. cmd[2] = (address & 0xFF);
  486. cmd[3] = ((bufsize -5) >> 8) & 0xFF;
  487. cmd[4] = ((bufsize -5) & 0xFF);
  488. memcpy(cmd +5, buffer, size);
  489. if (memtype == MEMTYPE_FLASH)
  490. {
  491. memset(cmd +5 +size, 0xFF, mpm->flashpage - size);
  492. }
  493. int ret = mpm_send(mpm, CMD_WRITE_MEMORY, cmd, bufsize);
  494. if (ret < 0)
  495. {
  496. return ret;
  497. }
  498. free(cmd);
  499. uint8_t cause = CAUSE_SUCCESS;
  500. ret = mpm_recv(mpm, CMD_WRITE_MEMORY, &cause, NULL, 0);
  501. if (ret < 0)
  502. {
  503. return ret;
  504. }
  505. return (cause != CAUSE_SUCCESS);
  506. } /* mpm_write_memory */
  507. /* *************************************************************************
  508. * mpm_close
  509. * ************************************************************************* */
  510. static int mpm_close(struct multiboot *mboot)
  511. {
  512. struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
  513. if (mpm->connected)
  514. {
  515. mpm_switch_application(mpm, BOOTTYPE_APPLICATION);
  516. }
  517. mpm_close_device(mpm);
  518. return 0;
  519. } /* mpm_close */
  520. /* *************************************************************************
  521. * mpm_open
  522. * ************************************************************************* */
  523. static int mpm_open(struct multiboot *mboot)
  524. {
  525. struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
  526. if (mpm->address == 0)
  527. {
  528. fprintf(stderr, "abort: no address given\n");
  529. return -1;
  530. }
  531. if (mpm->device == NULL)
  532. {
  533. fprintf(stderr, "abort: no device given\n");
  534. return -1;
  535. }
  536. if (mpm_open_device(mpm) < 0)
  537. {
  538. return -1;
  539. }
  540. if (mpm_switch_application(mpm, BOOTTYPE_BOOTLOADER))
  541. {
  542. fprintf(stderr, "failed to switch to bootloader (invalid address?)\n");
  543. mpm_close(mboot);
  544. return -1;
  545. }
  546. /* wait for watchdog and startup time */
  547. usleep(100000);
  548. char version[16];
  549. if (mpm_read_version(mpm, (uint8_t *)version, sizeof(version)))
  550. {
  551. fprintf(stderr, "failed to get bootloader version\n");
  552. mpm_close(mboot);
  553. return -1;
  554. }
  555. uint8_t chipinfo[8];
  556. if (mpm_read_chipinfo(mpm, chipinfo, sizeof(chipinfo)))
  557. {
  558. fprintf(stderr, "failed to get bootloader version\n");
  559. mpm_close(mboot);
  560. return -1;
  561. }
  562. const char *chipname = chipinfo_get_avr_name(chipinfo);
  563. mpm->flashpage = chipinfo[3];
  564. mpm->flashsize = (chipinfo[4] << 8) + chipinfo[5];
  565. mpm->eepromsize = (chipinfo[6] << 8) + chipinfo[7];
  566. printf("device : %-16s (address: 0x%02X)\n",
  567. mpm->device, mpm->address);
  568. printf("version : %-16s (sig: 0x%02x 0x%02x 0x%02x => %s)\n",
  569. version, chipinfo[0], chipinfo[1], chipinfo[2], chipname);
  570. printf("flash size : 0x%04x / %5d (0x%02x bytes/page)\n",
  571. mpm->flashsize, mpm->flashsize, mpm->flashpage);
  572. printf("eeprom size : 0x%04x / %5d\n",
  573. mpm->eepromsize, mpm->eepromsize);
  574. return 0;
  575. } /* mpm_open */
  576. /* *************************************************************************
  577. * mpm_read
  578. * ************************************************************************* */
  579. static int mpm_read(struct multiboot *mboot,
  580. struct databuf *dbuf, int memtype)
  581. {
  582. struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
  583. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "reading flash" : "reading eeprom";
  584. int pos = 0;
  585. int size = (memtype == MEMTYPE_FLASH) ? mpm->flashsize : mpm->eepromsize;
  586. while (pos < size)
  587. {
  588. mboot->progress_cb(progress_msg, pos, size);
  589. int len = MIN(READ_BLOCK_SIZE, size - pos);
  590. if (mpm_read_memory(mpm, dbuf->data + pos, len, memtype, pos))
  591. {
  592. mboot->progress_cb(progress_msg, -1, -1);
  593. return -1;
  594. }
  595. pos += len;
  596. }
  597. dbuf->length = pos;
  598. mboot->progress_cb(progress_msg, pos, size);
  599. return 0;
  600. } /* mpm_read */
  601. /* *************************************************************************
  602. * mpm_write
  603. * ************************************************************************* */
  604. static int mpm_write(struct multiboot *mboot,
  605. struct databuf *dbuf, int memtype)
  606. {
  607. struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
  608. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "writing flash" : "writing eeprom";
  609. int pos = 0;
  610. while (pos < dbuf->length)
  611. {
  612. mboot->progress_cb(progress_msg, pos, dbuf->length);
  613. int len = (memtype == MEMTYPE_FLASH) ? mpm->flashpage : WRITE_BLOCK_SIZE;
  614. len = MIN(len, dbuf->length - pos);
  615. if (mpm_write_memory(mpm, dbuf->data + pos, len, memtype, pos))
  616. {
  617. mboot->progress_cb(progress_msg, -1, -1);
  618. return -1;
  619. }
  620. pos += len;
  621. }
  622. mboot->progress_cb(progress_msg, pos, dbuf->length);
  623. return 0;
  624. } /* mpm_write */
  625. /* *************************************************************************
  626. * mpm_verify
  627. * ************************************************************************* */
  628. static int mpm_verify(struct multiboot *mboot,
  629. struct databuf *dbuf, int memtype)
  630. {
  631. struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
  632. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "verifing flash" : "verifing eeprom";
  633. int pos = 0;
  634. uint8_t comp[READ_BLOCK_SIZE];
  635. while (pos < dbuf->length)
  636. {
  637. mboot->progress_cb(progress_msg, pos, dbuf->length);
  638. int len = MIN(READ_BLOCK_SIZE, dbuf->length - pos);
  639. if (mpm_read_memory(mpm, comp, len, memtype, pos))
  640. {
  641. mboot->progress_cb(progress_msg, -1, -1);
  642. return -1;
  643. }
  644. if (memcmp(comp, dbuf->data + pos, len) != 0x00)
  645. {
  646. mboot->progress_cb(progress_msg, -1, -1);
  647. fprintf(stderr, "verify failed at page 0x%04x!!\n", pos);
  648. return -1;
  649. }
  650. pos += len;
  651. }
  652. dbuf->length = pos;
  653. mboot->progress_cb(progress_msg, pos, dbuf->length);
  654. return 0;
  655. } /* mpm_verify */
  656. struct multiboot_ops mpm_ops =
  657. {
  658. .alloc = mpm_alloc,
  659. .free = mpm_free,
  660. .get_memtype = mpm_get_memtype,
  661. .get_memsize = mpm_get_memsize,
  662. .open = mpm_open,
  663. .close = mpm_close,
  664. .read = mpm_read,
  665. .write = mpm_write,
  666. .verify = mpm_verify,
  667. };