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.

470 lines
13KB

  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. char *device;
  59. uint8_t address;
  60. int fd;
  61. int connected;
  62. uint8_t pagesize;
  63. uint16_t flashsize;
  64. uint16_t eepromsize;
  65. };
  66. static struct option twi_optargs[] = {
  67. {"address", 1, 0, 'a'}, /* -a <addr> */
  68. {"device", 1, 0, 'd'}, /* [ -d <device> ] */
  69. };
  70. static int twi_switch_application(struct twi_privdata *twi, uint8_t application)
  71. {
  72. uint8_t cmd[] = { CMD_SWITCH_APPLICATION, application };
  73. return (write(twi->fd, cmd, sizeof(cmd)) != sizeof(cmd));
  74. }
  75. static int twi_read_version(struct twi_privdata *twi, char *version, int length)
  76. {
  77. uint8_t cmd[] = { CMD_READ_VERSION };
  78. if (write(twi->fd, cmd, sizeof(cmd)) != sizeof(cmd))
  79. return -1;
  80. memset(version, 0, length);
  81. if (read(twi->fd, version, length) != length)
  82. return -1;
  83. int i;
  84. for (i = 0; i < length; i++)
  85. version[i] &= ~0x80;
  86. return 0;
  87. }
  88. static int twi_read_memory(struct twi_privdata *twi, uint8_t *buffer, uint8_t size, uint8_t memtype, uint16_t address)
  89. {
  90. uint8_t cmd[] = { CMD_READ_MEMORY, memtype, (address >> 8) & 0xFF, (address & 0xFF) };
  91. if (write(twi->fd, cmd, sizeof(cmd)) != sizeof(cmd))
  92. return -1;
  93. return (read(twi->fd, buffer, size) != size);
  94. }
  95. static int twi_write_memory(struct twi_privdata *twi, uint8_t *buffer, uint8_t size, uint8_t memtype, uint16_t address)
  96. {
  97. int bufsize;
  98. if (memtype == MEMTYPE_FLASH) {
  99. if ((address & (twi->pagesize -1)) != 0x00) {
  100. fprintf(stderr, "twi_write_memory(): address 0x%04x not aligned to pagesize 0x%02x\n", address, twi->pagesize);
  101. return -1;
  102. }
  103. bufsize = 4 + twi->pagesize;
  104. } else {
  105. bufsize = 4 + size;
  106. }
  107. uint8_t *cmd = malloc(bufsize);
  108. if (cmd == NULL)
  109. return -1;
  110. cmd[0] = CMD_WRITE_MEMORY;
  111. cmd[1] = memtype;
  112. cmd[2] = (address >> 8) & 0xFF;
  113. cmd[3] = (address & 0xFF);
  114. memcpy(cmd +4, buffer, size);
  115. if (memtype == MEMTYPE_FLASH) {
  116. memset(cmd +4 +size, 0xFF, twi->pagesize - size);
  117. }
  118. int result = write(twi->fd, cmd, bufsize);
  119. free(cmd);
  120. return (result != bufsize);
  121. }
  122. static void twi_close_device(struct twi_privdata *twi)
  123. {
  124. if (twi->connected)
  125. close(twi->fd);
  126. twi->connected = 0;
  127. }
  128. static int twi_open_device(struct twi_privdata *twi)
  129. {
  130. twi->fd = open(twi->device, O_RDWR);
  131. if (twi->fd < 0) {
  132. fprintf(stderr, "failed to open '%s': %s\n", twi->device, strerror(errno));
  133. return -1;
  134. }
  135. unsigned long funcs;
  136. if (ioctl(twi->fd, I2C_FUNCS, &funcs)) {
  137. perror("ioctl(I2C_FUNCS)");
  138. close(twi->fd);
  139. return -1;
  140. }
  141. if (!(funcs & I2C_FUNC_I2C)) {
  142. fprintf(stderr, "I2C_FUNC_I2C not supported on '%s'!\n", twi->device);
  143. close(twi->fd);
  144. return -1;
  145. }
  146. if (ioctl(twi->fd, I2C_SLAVE, twi->address) < 0) {
  147. fprintf(stderr, "failed to select slave address '%d': %s\n", twi->address, strerror(errno));
  148. close(twi->fd);
  149. return -1;
  150. }
  151. twi->connected = 1;
  152. return 0;
  153. }
  154. static int twi_close(struct multiboot *mboot)
  155. {
  156. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  157. if (twi->connected)
  158. twi_switch_application(twi, BOOTTYPE_APPLICATION);
  159. twi_close_device(twi);
  160. return 0;
  161. }
  162. static int twi_open(struct multiboot *mboot)
  163. {
  164. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  165. if (twi->address == 0) {
  166. fprintf(stderr, "abort: no address given\n");
  167. return -1;
  168. }
  169. if (twi->device == NULL) {
  170. twi->device = strdup(TWI_DEFAULT_DEVICE);
  171. if (twi->device == NULL) {
  172. perror("strdup()");
  173. return -1;
  174. }
  175. }
  176. if (twi_open_device(twi) != 0)
  177. return -1;
  178. if (twi_switch_application(twi, BOOTTYPE_BOOTLOADER)) {
  179. fprintf(stderr, "failed to switch to bootloader (invalid address?): %s\n", strerror(errno));
  180. twi_close(mboot);
  181. return -1;
  182. }
  183. /* wait for watchdog and startup time */
  184. usleep(100000);
  185. char version[16];
  186. if (twi_read_version(twi, version, sizeof(version))) {
  187. fprintf(stderr, "failed to get bootloader version: %s\n", strerror(errno));
  188. twi_close(mboot);
  189. return -1;
  190. }
  191. uint8_t chipinfo[8];
  192. if (twi_read_memory(twi, chipinfo, sizeof(chipinfo), MEMTYPE_CHIPINFO, 0x0000)) {
  193. fprintf(stderr, "failed to get chipinfo: %s\n", strerror(errno));
  194. twi_close(mboot);
  195. return -1;
  196. }
  197. const char *chipname = chipinfo_get_avr_name(chipinfo);
  198. twi->pagesize = chipinfo[3];
  199. twi->flashsize = (chipinfo[4] << 8) + chipinfo[5];
  200. twi->eepromsize = (chipinfo[6] << 8) + chipinfo[7];
  201. printf("device : %-16s (address: 0x%02X)\n", twi->device, twi->address);
  202. printf("version : %-16s (sig: 0x%02x 0x%02x 0x%02x => %s)\n", version, chipinfo[0], chipinfo[1], chipinfo[2], chipname);
  203. printf("flash size : 0x%04x / %5d (0x%02x bytes/page)\n", twi->flashsize, twi->flashsize, twi->pagesize);
  204. printf("eeprom size : 0x%04x / %5d\n", twi->eepromsize, twi->eepromsize);
  205. return 0;
  206. }
  207. static int twi_read(struct multiboot *mboot, struct databuf *dbuf, int memtype)
  208. {
  209. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  210. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "reading flash" : "reading eeprom";
  211. int pos = 0;
  212. int size = (memtype == MEMTYPE_FLASH) ? twi->flashsize : twi->eepromsize;
  213. while (pos < size) {
  214. mboot->progress_cb(progress_msg, pos, size);
  215. int len = MIN(READ_BLOCK_SIZE, size - pos);
  216. if (twi_read_memory(twi, dbuf->data + pos, len, memtype, pos)) {
  217. mboot->progress_cb(progress_msg, -1, -1);
  218. return -1;
  219. }
  220. pos += len;
  221. }
  222. dbuf->length = pos;
  223. mboot->progress_cb(progress_msg, pos, size);
  224. return 0;
  225. }
  226. static int twi_write(struct multiboot *mboot, struct databuf *dbuf, int memtype)
  227. {
  228. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  229. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "writing flash" : "writing eeprom";
  230. int pos = 0;
  231. while (pos < dbuf->length) {
  232. mboot->progress_cb(progress_msg, pos, dbuf->length);
  233. int len = (memtype == MEMTYPE_FLASH) ? twi->pagesize : WRITE_BLOCK_SIZE;
  234. len = MIN(len, dbuf->length - pos);
  235. if (twi_write_memory(twi, dbuf->data + pos, len, memtype, pos)) {
  236. mboot->progress_cb(progress_msg, -1, -1);
  237. return -1;
  238. }
  239. pos += len;
  240. }
  241. mboot->progress_cb(progress_msg, pos, dbuf->length);
  242. return 0;
  243. }
  244. static int twi_verify(struct multiboot *mboot, struct databuf *dbuf, int memtype)
  245. {
  246. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  247. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "verifing flash" : "verifing eeprom";
  248. int pos = 0;
  249. uint8_t comp[READ_BLOCK_SIZE];
  250. while (pos < dbuf->length) {
  251. mboot->progress_cb(progress_msg, pos, dbuf->length);
  252. int len = MIN(READ_BLOCK_SIZE, dbuf->length - pos);
  253. if (twi_read_memory(twi, comp, len, memtype, pos)) {
  254. mboot->progress_cb(progress_msg, -1, -1);
  255. return -1;
  256. }
  257. if (memcmp(comp, dbuf->data + pos, len) != 0x00) {
  258. mboot->progress_cb(progress_msg, -1, -1);
  259. fprintf(stderr, "verify failed at page 0x%04x!!\n", pos);
  260. return -1;
  261. }
  262. pos += len;
  263. }
  264. dbuf->length = pos;
  265. mboot->progress_cb(progress_msg, pos, dbuf->length);
  266. return 0;
  267. }
  268. static int twi_optarg_cb(int val, const char *arg, void *privdata)
  269. {
  270. struct twi_privdata *twi = (struct twi_privdata *)privdata;
  271. switch (val) {
  272. case 'a': /* address */
  273. {
  274. char *endptr;
  275. twi->address = strtol(arg, &endptr, 16);
  276. if (*endptr != '\0' || twi->address < 0x01 || twi->address > 0x7F) {
  277. fprintf(stderr, "invalid address: '%s'\n", arg);
  278. return -1;
  279. }
  280. }
  281. break;
  282. case 'd': /* device */
  283. {
  284. if (twi->device != NULL) {
  285. fprintf(stderr, "invalid device: '%s'\n", optarg);
  286. return -1;
  287. }
  288. twi->device = strdup(optarg);
  289. if (twi->device == NULL) {
  290. perror("strdup()");
  291. return -1;
  292. }
  293. }
  294. break;
  295. case 'h':
  296. case '?': /* error */
  297. fprintf(stderr, "Usage: twiboot [options]\n"
  298. " -a <address> - selects i2c address (0x01 - 0x7F)\n"
  299. " -d <device> - selects i2c device (default: /dev/i2c-0)\n"
  300. " -r <flash|eeprom>:<file> - reads flash/eeprom to file (.bin | .hex | -)\n"
  301. " -w <flash|eeprom>:<file> - write flash/eeprom from file (.bin | .hex)\n"
  302. " -n - disable verify after write\n"
  303. " -p <0|1|2> - progress bar mode\n"
  304. "\n"
  305. "Example: twiboot -a 0x22 -w flash:blmc.hex -w flash:blmc_eeprom.hex\n"
  306. "\n");
  307. return -1;
  308. default:
  309. return 1;
  310. }
  311. return 0;
  312. }
  313. static struct multiboot * twi_alloc(void)
  314. {
  315. struct multiboot * mboot = malloc(sizeof(struct multiboot));
  316. if (mboot == NULL)
  317. return NULL;
  318. memset(mboot, 0x00, sizeof(struct multiboot));
  319. mboot->ops = &twi_ops;
  320. struct twi_privdata *twi = malloc(sizeof(struct twi_privdata));
  321. if (twi == NULL) {
  322. free(mboot);
  323. return NULL;
  324. }
  325. memset(twi, 0x00, sizeof(struct twi_privdata));
  326. twi->device = NULL;
  327. twi->address = 0;
  328. optarg_register(twi_optargs, ARRAY_SIZE(twi_optargs), twi_optarg_cb, (void *)twi);
  329. mboot->privdata = twi;
  330. return mboot;
  331. }
  332. static void twi_free(struct multiboot *mboot)
  333. {
  334. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  335. if (twi->device != NULL)
  336. free(twi->device);
  337. free(twi);
  338. free(mboot);
  339. }
  340. static int twi_get_memtype(struct multiboot *mboot, const char *memname)
  341. {
  342. if (strcmp(memname, "flash") == 0)
  343. return MEMTYPE_FLASH;
  344. else if (strcmp(memname, "eeprom") == 0)
  345. return MEMTYPE_EEPROM;
  346. return -1;
  347. }
  348. static int twi_get_memsize(struct multiboot *mboot, int memtype)
  349. {
  350. struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
  351. if (!twi->connected)
  352. return 0;
  353. switch (memtype) {
  354. case MEMTYPE_FLASH:
  355. return twi->flashsize;
  356. case MEMTYPE_EEPROM:
  357. return twi->eepromsize;
  358. default:
  359. return 0;
  360. }
  361. }
  362. struct multiboot_ops twi_ops = {
  363. .alloc = twi_alloc,
  364. .free = twi_free,
  365. .get_memtype = twi_get_memtype,
  366. .get_memsize = twi_get_memsize,
  367. .open = twi_open,
  368. .close = twi_close,
  369. .read = twi_read,
  370. .write = twi_write,
  371. .verify = twi_verify,
  372. };