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.

633 lines
17 KiB

  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 <sys/stat.h>
  24. #include <sys/types.h>
  25. #include <dirent.h>
  26. #include <fcntl.h>
  27. #include <errno.h>
  28. #include <sys/ioctl.h>
  29. #include <linux/i2c.h>
  30. #include <linux/i2c-dev.h>
  31. #include "chipinfo_avr.h"
  32. #include "filedata.h"
  33. #include "list.h"
  34. #include "multiboot.h"
  35. #include "optarg.h"
  36. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  37. #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
  38. #define TWI_DEFAULT_DEVICE "/dev/i2c-0"
  39. #define READ_BLOCK_SIZE 128 /* bytes in one flash/eeprom read request */
  40. #define WRITE_BLOCK_SIZE 16 /* bytes in one eeprom write request */
  41. /* SLA+R */
  42. #define CMD_WAIT 0x00
  43. #define CMD_READ_VERSION 0x01
  44. #define CMD_READ_MEMORY 0x02
  45. /* SLA+W */
  46. #define CMD_SWITCH_APPLICATION CMD_READ_VERSION
  47. #define CMD_WRITE_MEMORY CMD_READ_MEMORY
  48. /* CMD_SWITCH_APPLICATION parameter */
  49. #define BOOTTYPE_BOOTLOADER 0x00 /* only in APP */
  50. #define BOOTTYPE_APPLICATION 0x80
  51. /* CMD_{READ|WRITE}_* parameter */
  52. #define MEMTYPE_CHIPINFO 0x00
  53. #define MEMTYPE_FLASH 0x01
  54. #define MEMTYPE_EEPROM 0x02
  55. #define MEMTYPE_PARAMETERS 0x03 /* only in APP */
  56. struct multiboot_ops twi_ops;
  57. struct twi_privdata
  58. {
  59. char *device;
  60. uint8_t address;
  61. int fd;
  62. int connected;
  63. uint8_t pagesize;
  64. uint16_t flashsize;
  65. uint16_t eepromsize;
  66. };
  67. static struct option twi_optargs[] =
  68. {
  69. { "address", 1, 0, 'a'}, /* -a <addr> */
  70. { "device", 1, 0, 'd'}, /* [ -d <device> ] */
  71. };
  72. /* *************************************************************************
  73. * twi_switch_application
  74. * ************************************************************************* */
  75. static int twi_switch_application(struct twi_privdata *twi,
  76. uint8_t application)
  77. {
  78. uint8_t cmd[] = { CMD_SWITCH_APPLICATION, application };
  79. return (write(twi->fd, cmd, sizeof(cmd)) != sizeof(cmd));
  80. } /* twi_switch_application */
  81. /* *************************************************************************
  82. * twi_switch_application
  83. * ************************************************************************* */
  84. static int twi_read_version(struct twi_privdata *twi,
  85. char *version, int length)
  86. {
  87. uint8_t cmd[] = { CMD_READ_VERSION };
  88. if (write(twi->fd, cmd, sizeof(cmd)) != sizeof(cmd))
  89. {
  90. return -1;
  91. }
  92. memset(version, 0, length);
  93. if (read(twi->fd, version, length) != length)
  94. {
  95. return -1;
  96. }
  97. int i;
  98. for (i = 0; i < length; i++)
  99. {
  100. version[i] &= ~0x80;
  101. }
  102. return 0;
  103. } /* twi_read_version */
  104. /* *************************************************************************
  105. * twi_read_memory
  106. * ************************************************************************* */
  107. static int twi_read_memory(struct twi_privdata *twi,
  108. uint8_t *buffer, uint8_t size,
  109. uint8_t memtype, uint16_t address)
  110. {
  111. uint8_t cmd[] = { CMD_READ_MEMORY, memtype, (address >> 8) & 0xFF, (address & 0xFF) };
  112. if (write(twi->fd, cmd, sizeof(cmd)) != sizeof(cmd))
  113. {
  114. return -1;
  115. }
  116. return (read(twi->fd, buffer, size) != size);
  117. } /* twi_read_memory */
  118. /* *************************************************************************
  119. * twi_write_memory
  120. * ************************************************************************* */
  121. static int twi_write_memory(struct twi_privdata *twi,
  122. uint8_t *buffer, uint8_t size,
  123. uint8_t memtype, uint16_t address)
  124. {
  125. int bufsize;
  126. if (memtype == MEMTYPE_FLASH)
  127. {
  128. if ((address & (twi->pagesize -1)) != 0x00)
  129. {
  130. fprintf(stderr, "twi_write_memory(): address 0x%04x not aligned to pagesize 0x%02x\n",
  131. address, twi->pagesize);
  132. return -1;
  133. }
  134. bufsize = 4 + twi->pagesize;
  135. }
  136. else
  137. {
  138. bufsize = 4 + size;
  139. }
  140. uint8_t *cmd = malloc(bufsize);
  141. if (cmd == NULL)
  142. {
  143. return -1;
  144. }
  145. cmd[0] = CMD_WRITE_MEMORY;
  146. cmd[1] = memtype;
  147. cmd[2] = (address >> 8) & 0xFF;
  148. cmd[3] = (address & 0xFF);
  149. memcpy(cmd +4, buffer, size);
  150. if (memtype == MEMTYPE_FLASH)
  151. {
  152. memset(cmd +4 +size, 0xFF, twi->pagesize - size);
  153. }
  154. int result = write(twi->fd, cmd, bufsize);
  155. free(cmd);
  156. return (result != bufsize);
  157. } /* twi_write_memory */
  158. /* *************************************************************************
  159. * twi_close_device
  160. * ************************************************************************* */
  161. static void twi_close_device(struct twi_privdata *twi)
  162. {
  163. if (twi->connected)
  164. {
  165. close(twi->fd);
  166. }
  167. twi->connected = 0;
  168. } /* twi_close_device */
  169. /* *************************************************************************
  170. * twi_open_device
  171. * ************************************************************************* */
  172. static int twi_open_device(struct twi_privdata *twi)
  173. {
  174. twi->fd = open(twi->device, O_RDWR);
  175. if (twi->fd < 0)
  176. {
  177. fprintf(stderr, "failed to open '%s': %s\n",
  178. twi->device, strerror(errno));
  179. return -1;
  180. }
  181. unsigned long funcs;
  182. if (ioctl(twi->fd, I2C_FUNCS, &funcs))
  183. {
  184. perror("ioctl(I2C_FUNCS)");
  185. close(twi->fd);
  186. return -1;
  187. }
  188. if (!(funcs & I2C_FUNC_I2C))
  189. {
  190. fprintf(stderr, "I2C_FUNC_I2C not supported on '%s'!\n",
  191. twi->device);
  192. close(twi->fd);
  193. return -1;
  194. }
  195. if (ioctl(twi->fd, I2C_SLAVE, twi->address) < 0)
  196. {
  197. fprintf(stderr, "failed to select slave address '%d': %s\n",
  198. twi->address, strerror(errno));
  199. close(twi->fd);
  200. return -1;
  201. }
  202. twi->connected = 1;
  203. return 0;
  204. } /* twi_open_device */
  205. /* *************************************************************************
  206. * twi_close
  207. * ************************************************************************* */
  208. static int twi_close(struct multiboot *mboot)
  209. {
  210. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  211. if (twi->connected)
  212. {
  213. twi_switch_application(twi, BOOTTYPE_APPLICATION);
  214. }
  215. twi_close_device(twi);
  216. return 0;
  217. } /* twi_close */
  218. /* *************************************************************************
  219. * twi_open
  220. * ************************************************************************* */
  221. static int twi_open(struct multiboot *mboot)
  222. {
  223. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  224. if (twi->address == 0)
  225. {
  226. fprintf(stderr, "abort: no address given\n");
  227. return -1;
  228. }
  229. if (twi->device == NULL)
  230. {
  231. twi->device = strdup(TWI_DEFAULT_DEVICE);
  232. if (twi->device == NULL)
  233. {
  234. perror("strdup()");
  235. return -1;
  236. }
  237. }
  238. if (twi_open_device(twi) != 0)
  239. {
  240. return -1;
  241. }
  242. if (twi_switch_application(twi, BOOTTYPE_BOOTLOADER))
  243. {
  244. fprintf(stderr, "failed to switch to bootloader (invalid address?): %s\n",
  245. strerror(errno));
  246. twi_close(mboot);
  247. return -1;
  248. }
  249. /* wait for watchdog and startup time */
  250. usleep(100000);
  251. char version[16 +1];
  252. if (twi_read_version(twi, version, sizeof(version) -1))
  253. {
  254. fprintf(stderr, "failed to get bootloader version: %s\n",
  255. strerror(errno));
  256. twi_close(mboot);
  257. return -1;
  258. }
  259. version[16] = '\0';
  260. uint8_t chipinfo[8];
  261. if (twi_read_memory(twi, chipinfo, sizeof(chipinfo), MEMTYPE_CHIPINFO, 0x0000))
  262. {
  263. fprintf(stderr, "failed to get chipinfo: %s\n", strerror(errno));
  264. twi_close(mboot);
  265. return -1;
  266. }
  267. const char *chipname = chipinfo_get_avr_name(chipinfo);
  268. twi->pagesize = chipinfo[3];
  269. twi->flashsize = (chipinfo[4] << 8) + chipinfo[5];
  270. twi->eepromsize = (chipinfo[6] << 8) + chipinfo[7];
  271. printf("device : %-16s (address: 0x%02X)\n",
  272. twi->device, twi->address);
  273. printf("version : %-16s (sig: 0x%02x 0x%02x 0x%02x => %s)\n",
  274. version, chipinfo[0], chipinfo[1], chipinfo[2], chipname);
  275. printf("flash size : 0x%04x / %5d (0x%02x bytes/page)\n",
  276. twi->flashsize, twi->flashsize, twi->pagesize);
  277. printf("eeprom size : 0x%04x / %5d\n",
  278. twi->eepromsize, twi->eepromsize);
  279. return 0;
  280. } /* twi_open */
  281. /* *************************************************************************
  282. * twi_read
  283. * ************************************************************************* */
  284. static int twi_read(struct multiboot *mboot,
  285. struct databuf *dbuf,
  286. int memtype)
  287. {
  288. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  289. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "reading flash" : "reading eeprom";
  290. uint16_t pos = 0;
  291. uint16_t size = (memtype == MEMTYPE_FLASH) ? twi->flashsize : twi->eepromsize;
  292. while (pos < size)
  293. {
  294. mboot->progress_cb(progress_msg, pos, size);
  295. uint8_t len = MIN(READ_BLOCK_SIZE, size - pos);
  296. if (twi_read_memory(twi, dbuf->data + pos, len, memtype, pos))
  297. {
  298. mboot->progress_cb(progress_msg, -1, -1);
  299. return -1;
  300. }
  301. pos += len;
  302. }
  303. dbuf->length = pos;
  304. mboot->progress_cb(progress_msg, pos, size);
  305. return 0;
  306. } /* twi_read */
  307. /* *************************************************************************
  308. * twi_write
  309. * ************************************************************************* */
  310. static int twi_write(struct multiboot *mboot,
  311. struct databuf *dbuf,
  312. int memtype)
  313. {
  314. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  315. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "writing flash" : "writing eeprom";
  316. uint16_t pos = 0;
  317. while (pos < dbuf->length)
  318. {
  319. mboot->progress_cb(progress_msg, pos, dbuf->length);
  320. uint8_t len = (memtype == MEMTYPE_FLASH) ? twi->pagesize : WRITE_BLOCK_SIZE;
  321. len = MIN(len, dbuf->length - pos);
  322. if (twi_write_memory(twi, dbuf->data + pos, len, memtype, pos))
  323. {
  324. mboot->progress_cb(progress_msg, -1, -1);
  325. return -1;
  326. }
  327. pos += len;
  328. }
  329. mboot->progress_cb(progress_msg, pos, dbuf->length);
  330. return 0;
  331. } /* twi_write */
  332. /* *************************************************************************
  333. * twi_verify
  334. * ************************************************************************* */
  335. static int twi_verify(struct multiboot *mboot, struct databuf *dbuf, int memtype)
  336. {
  337. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  338. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "verifing flash" : "verifing eeprom";
  339. uint16_t pos = 0;
  340. uint8_t comp[READ_BLOCK_SIZE];
  341. while (pos < dbuf->length)
  342. {
  343. mboot->progress_cb(progress_msg, pos, dbuf->length);
  344. int len = MIN(READ_BLOCK_SIZE, dbuf->length - pos);
  345. if (twi_read_memory(twi, comp, len, memtype, pos))
  346. {
  347. mboot->progress_cb(progress_msg, -1, -1);
  348. return -1;
  349. }
  350. if (memcmp(comp, dbuf->data + pos, len) != 0x00)
  351. {
  352. mboot->progress_cb(progress_msg, -1, -1);
  353. fprintf(stderr, "verify failed at page 0x%04x!!\n", pos);
  354. return -1;
  355. }
  356. pos += len;
  357. }
  358. dbuf->length = pos;
  359. mboot->progress_cb(progress_msg, pos, dbuf->length);
  360. return 0;
  361. } /* twi_verify */
  362. /* *************************************************************************
  363. * twi_optarg_cb
  364. * ************************************************************************* */
  365. static int twi_optarg_cb(int val, const char *arg, void *privdata)
  366. {
  367. struct twi_privdata *twi = (struct twi_privdata *)privdata;
  368. switch (val)
  369. {
  370. case 'a': /* address */
  371. {
  372. char *endptr;
  373. twi->address = strtol(arg, &endptr, 16);
  374. if (*endptr != '\0' || twi->address < 0x01 || twi->address > 0x7F)
  375. {
  376. fprintf(stderr, "invalid address: '%s'\n", arg);
  377. return -1;
  378. }
  379. }
  380. break;
  381. case 'd': /* device */
  382. if (twi->device != NULL)
  383. {
  384. fprintf(stderr, "invalid device: '%s'\n", optarg);
  385. return -1;
  386. }
  387. twi->device = strdup(optarg);
  388. if (twi->device == NULL)
  389. {
  390. perror("strdup()");
  391. return -1;
  392. }
  393. break;
  394. case 'h':
  395. case '?': /* error */
  396. fprintf(stderr, "Usage: twiboot [options]\n"
  397. " -a <address> - selects i2c address (0x01 - 0x7F)\n"
  398. " -d <device> - selects i2c device (default: /dev/i2c-0)\n"
  399. " -r <flash|eeprom>:<file> - reads flash/eeprom to file (.bin | .hex | -)\n"
  400. " -w <flash|eeprom>:<file> - write flash/eeprom from file (.bin | .hex)\n"
  401. " -n - disable verify after write\n"
  402. " -p <0|1|2> - progress bar mode\n"
  403. "\n"
  404. "Example: twiboot -a 0x22 -w flash:blmc.hex -w flash:blmc_eeprom.hex\n"
  405. "\n");
  406. return -1;
  407. default:
  408. return 1;
  409. }
  410. return 0;
  411. } /* twi_optarg_cb */
  412. /* *************************************************************************
  413. * twi_alloc
  414. * ************************************************************************* */
  415. static struct multiboot * twi_alloc(void)
  416. {
  417. struct multiboot * mboot = malloc(sizeof(struct multiboot));
  418. if (mboot == NULL)
  419. {
  420. return NULL;
  421. }
  422. memset(mboot, 0x00, sizeof(struct multiboot));
  423. mboot->ops = &twi_ops;
  424. struct twi_privdata *twi = malloc(sizeof(struct twi_privdata));
  425. if (twi == NULL)
  426. {
  427. free(mboot);
  428. return NULL;
  429. }
  430. memset(twi, 0x00, sizeof(struct twi_privdata));
  431. twi->device = NULL;
  432. twi->address = 0;
  433. optarg_register(twi_optargs, ARRAY_SIZE(twi_optargs), twi_optarg_cb, (void *)twi);
  434. mboot->privdata = twi;
  435. return mboot;
  436. } /* twi_alloc */
  437. /* *************************************************************************
  438. * twi_free
  439. * ************************************************************************* */
  440. static void twi_free(struct multiboot *mboot)
  441. {
  442. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  443. if (twi->device != NULL)
  444. {
  445. free(twi->device);
  446. }
  447. free(twi);
  448. free(mboot);
  449. } /* twi_free */
  450. /* *************************************************************************
  451. * twi_get_memtype
  452. * ************************************************************************* */
  453. static int twi_get_memtype(struct multiboot *mboot,
  454. const char *memname)
  455. {
  456. /* unused parameter */
  457. (void)mboot;
  458. if (strcmp(memname, "flash") == 0)
  459. {
  460. return MEMTYPE_FLASH;
  461. }
  462. else if (strcmp(memname, "eeprom") == 0)
  463. {
  464. return MEMTYPE_EEPROM;
  465. }
  466. return -1;
  467. } /* twi_get_memtype */
  468. /* *************************************************************************
  469. * twi_get_memsize
  470. * ************************************************************************* */
  471. static int twi_get_memsize(struct multiboot *mboot,
  472. int memtype)
  473. {
  474. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  475. if (!twi->connected)
  476. {
  477. return 0;
  478. }
  479. switch (memtype)
  480. {
  481. case MEMTYPE_FLASH:
  482. return twi->flashsize;
  483. case MEMTYPE_EEPROM:
  484. return twi->eepromsize;
  485. default:
  486. return 0;
  487. }
  488. } /* twi_get_memsize */
  489. struct multiboot_ops twi_ops =
  490. {
  491. .exec_name = "twiboot",
  492. .alloc = twi_alloc,
  493. .free = twi_free,
  494. .get_memtype = twi_get_memtype,
  495. .get_memsize = twi_get_memsize,
  496. .open = twi_open,
  497. .close = twi_close,
  498. .read = twi_read,
  499. .write = twi_write,
  500. .verify = twi_verify,
  501. };