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.

627 lines
17KB

  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];
  252. if (twi_read_version(twi, version, sizeof(version)))
  253. {
  254. fprintf(stderr, "failed to get bootloader version: %s\n",
  255. strerror(errno));
  256. twi_close(mboot);
  257. return -1;
  258. }
  259. uint8_t chipinfo[8];
  260. if (twi_read_memory(twi, chipinfo, sizeof(chipinfo), MEMTYPE_CHIPINFO, 0x0000))
  261. {
  262. fprintf(stderr, "failed to get chipinfo: %s\n", strerror(errno));
  263. twi_close(mboot);
  264. return -1;
  265. }
  266. const char *chipname = chipinfo_get_avr_name(chipinfo);
  267. twi->pagesize = chipinfo[3];
  268. twi->flashsize = (chipinfo[4] << 8) + chipinfo[5];
  269. twi->eepromsize = (chipinfo[6] << 8) + chipinfo[7];
  270. printf("device : %-16s (address: 0x%02X)\n",
  271. twi->device, twi->address);
  272. printf("version : %-16s (sig: 0x%02x 0x%02x 0x%02x => %s)\n",
  273. version, chipinfo[0], chipinfo[1], chipinfo[2], chipname);
  274. printf("flash size : 0x%04x / %5d (0x%02x bytes/page)\n",
  275. twi->flashsize, twi->flashsize, twi->pagesize);
  276. printf("eeprom size : 0x%04x / %5d\n",
  277. twi->eepromsize, twi->eepromsize);
  278. return 0;
  279. } /* twi_open */
  280. /* *************************************************************************
  281. * twi_read
  282. * ************************************************************************* */
  283. static int twi_read(struct multiboot *mboot,
  284. struct databuf *dbuf,
  285. int memtype)
  286. {
  287. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  288. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "reading flash" : "reading eeprom";
  289. int pos = 0;
  290. int size = (memtype == MEMTYPE_FLASH) ? twi->flashsize : twi->eepromsize;
  291. while (pos < size)
  292. {
  293. mboot->progress_cb(progress_msg, pos, size);
  294. int len = MIN(READ_BLOCK_SIZE, size - pos);
  295. if (twi_read_memory(twi, dbuf->data + pos, len, memtype, pos))
  296. {
  297. mboot->progress_cb(progress_msg, -1, -1);
  298. return -1;
  299. }
  300. pos += len;
  301. }
  302. dbuf->length = pos;
  303. mboot->progress_cb(progress_msg, pos, size);
  304. return 0;
  305. } /* twi_read */
  306. /* *************************************************************************
  307. * twi_write
  308. * ************************************************************************* */
  309. static int twi_write(struct multiboot *mboot,
  310. struct databuf *dbuf,
  311. int memtype)
  312. {
  313. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  314. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "writing flash" : "writing eeprom";
  315. int pos = 0;
  316. while (pos < dbuf->length)
  317. {
  318. mboot->progress_cb(progress_msg, pos, dbuf->length);
  319. int len = (memtype == MEMTYPE_FLASH) ? twi->pagesize : WRITE_BLOCK_SIZE;
  320. len = MIN(len, dbuf->length - pos);
  321. if (twi_write_memory(twi, dbuf->data + pos, len, memtype, pos))
  322. {
  323. mboot->progress_cb(progress_msg, -1, -1);
  324. return -1;
  325. }
  326. pos += len;
  327. }
  328. mboot->progress_cb(progress_msg, pos, dbuf->length);
  329. return 0;
  330. } /* twi_write */
  331. /* *************************************************************************
  332. * twi_verify
  333. * ************************************************************************* */
  334. static int twi_verify(struct multiboot *mboot, struct databuf *dbuf, int memtype)
  335. {
  336. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  337. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "verifing flash" : "verifing eeprom";
  338. int pos = 0;
  339. uint8_t comp[READ_BLOCK_SIZE];
  340. while (pos < dbuf->length)
  341. {
  342. mboot->progress_cb(progress_msg, pos, dbuf->length);
  343. int len = MIN(READ_BLOCK_SIZE, dbuf->length - pos);
  344. if (twi_read_memory(twi, comp, len, memtype, pos))
  345. {
  346. mboot->progress_cb(progress_msg, -1, -1);
  347. return -1;
  348. }
  349. if (memcmp(comp, dbuf->data + pos, len) != 0x00)
  350. {
  351. mboot->progress_cb(progress_msg, -1, -1);
  352. fprintf(stderr, "verify failed at page 0x%04x!!\n", pos);
  353. return -1;
  354. }
  355. pos += len;
  356. }
  357. dbuf->length = pos;
  358. mboot->progress_cb(progress_msg, pos, dbuf->length);
  359. return 0;
  360. } /* twi_verify */
  361. /* *************************************************************************
  362. * twi_optarg_cb
  363. * ************************************************************************* */
  364. static int twi_optarg_cb(int val, const char *arg, void *privdata)
  365. {
  366. struct twi_privdata *twi = (struct twi_privdata *)privdata;
  367. switch (val)
  368. {
  369. case 'a': /* address */
  370. {
  371. char *endptr;
  372. twi->address = strtol(arg, &endptr, 16);
  373. if (*endptr != '\0' || twi->address < 0x01 || twi->address > 0x7F)
  374. {
  375. fprintf(stderr, "invalid address: '%s'\n", arg);
  376. return -1;
  377. }
  378. }
  379. break;
  380. case 'd': /* device */
  381. if (twi->device != NULL)
  382. {
  383. fprintf(stderr, "invalid device: '%s'\n", optarg);
  384. return -1;
  385. }
  386. twi->device = strdup(optarg);
  387. if (twi->device == NULL)
  388. {
  389. perror("strdup()");
  390. return -1;
  391. }
  392. break;
  393. case 'h':
  394. case '?': /* error */
  395. fprintf(stderr, "Usage: twiboot [options]\n"
  396. " -a <address> - selects i2c address (0x01 - 0x7F)\n"
  397. " -d <device> - selects i2c device (default: /dev/i2c-0)\n"
  398. " -r <flash|eeprom>:<file> - reads flash/eeprom to file (.bin | .hex | -)\n"
  399. " -w <flash|eeprom>:<file> - write flash/eeprom from file (.bin | .hex)\n"
  400. " -n - disable verify after write\n"
  401. " -p <0|1|2> - progress bar mode\n"
  402. "\n"
  403. "Example: twiboot -a 0x22 -w flash:blmc.hex -w flash:blmc_eeprom.hex\n"
  404. "\n");
  405. return -1;
  406. default:
  407. return 1;
  408. }
  409. return 0;
  410. } /* twi_optarg_cb */
  411. /* *************************************************************************
  412. * twi_alloc
  413. * ************************************************************************* */
  414. static struct multiboot * twi_alloc(void)
  415. {
  416. struct multiboot * mboot = malloc(sizeof(struct multiboot));
  417. if (mboot == NULL)
  418. {
  419. return NULL;
  420. }
  421. memset(mboot, 0x00, sizeof(struct multiboot));
  422. mboot->ops = &twi_ops;
  423. struct twi_privdata *twi = malloc(sizeof(struct twi_privdata));
  424. if (twi == NULL)
  425. {
  426. free(mboot);
  427. return NULL;
  428. }
  429. memset(twi, 0x00, sizeof(struct twi_privdata));
  430. twi->device = NULL;
  431. twi->address = 0;
  432. optarg_register(twi_optargs, ARRAY_SIZE(twi_optargs), twi_optarg_cb, (void *)twi);
  433. mboot->privdata = twi;
  434. return mboot;
  435. } /* twi_alloc */
  436. /* *************************************************************************
  437. * twi_free
  438. * ************************************************************************* */
  439. static void twi_free(struct multiboot *mboot)
  440. {
  441. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  442. if (twi->device != NULL)
  443. {
  444. free(twi->device);
  445. }
  446. free(twi);
  447. free(mboot);
  448. } /* twi_free */
  449. /* *************************************************************************
  450. * twi_get_memtype
  451. * ************************************************************************* */
  452. static int twi_get_memtype(struct multiboot *mboot,
  453. const char *memname)
  454. {
  455. if (strcmp(memname, "flash") == 0)
  456. {
  457. return MEMTYPE_FLASH;
  458. }
  459. else if (strcmp(memname, "eeprom") == 0)
  460. {
  461. return MEMTYPE_EEPROM;
  462. }
  463. return -1;
  464. } /* twi_get_memtype */
  465. /* *************************************************************************
  466. * twi_get_memsize
  467. * ************************************************************************* */
  468. static int twi_get_memsize(struct multiboot *mboot,
  469. int memtype)
  470. {
  471. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  472. if (!twi->connected)
  473. {
  474. return 0;
  475. }
  476. switch (memtype)
  477. {
  478. case MEMTYPE_FLASH:
  479. return twi->flashsize;
  480. case MEMTYPE_EEPROM:
  481. return twi->eepromsize;
  482. default:
  483. return 0;
  484. }
  485. } /* twi_get_memsize */
  486. struct multiboot_ops twi_ops =
  487. {
  488. .alloc = twi_alloc,
  489. .free = twi_free,
  490. .get_memtype = twi_get_memtype,
  491. .get_memsize = twi_get_memsize,
  492. .open = twi_open,
  493. .close = twi_close,
  494. .read = twi_read,
  495. .write = twi_write,
  496. .verify = twi_verify,
  497. };