#include #include #include #include #include #include #include #include #include #include static void do_flash_probe(const char *s); static void do_flash_info(const char *s); static void do_flash_read(const char *s); static void do_flash_write(const char *s); static void do_flash_erase(const char *s); static struct cmd flash_cmds[] = { { "probe", do_flash_probe }, { "info", do_flash_info }, { "read", do_flash_read }, { "write", do_flash_write }, { "erase", do_flash_erase }, { NULL, NULL }, }; struct flash_dev *flash = NULL; /* TODO: implement a parser for hex arrays that is more user-friendly. * Also implement dry runs for programmers. */ static void parse_hex(FILE *fp, char *buf, size_t len) { size_t i; char s[3]; for (i = 0; i < len; ++i) { memset(s, '\0', 3); while ((s[0] = getc(fp)) && !isxdigit(s[0])) putchar(s[0]); putchar(s[0]); while ((s[1] = getc(fp)) && !isxdigit(s[1])) putchar(s[1]); putchar(s[1]); *buf++ = strtoul(s, NULL, 16); } } static void print_hex_ascii(const char *buf, size_t len) { size_t n, i; uint8_t c; for (; len; buf += n, len -= n) { n = min(len, 16); for (i = 0; i < 16; ++i) { c = (i < n) ? buf[i] : 0; printf("%x", c); } printf(" "); for (i = 0; i < 16; ++i) { c = (i < n) ? buf[i] : 0; printf("%c", isalnum(c) ? c : '.'); } printf("\n"); } } static void print_size(size_t size) { if (size == 0) { printf("0"); #if defined(TIB) } else if (size % TIB == 0) { printf("%" PRSZu " TiB", size / TIB); #endif } else if (size % GIB == 0) { printf("%" PRSZu " GiB", size / GIB); } else if (size % MIB == 0) { printf("%" PRSZu " MiB", size / MIB); } else if (size % KIB == 0) { printf("%" PRSZu " KiB", size / KIB); } else { printf("%" PRSZu " B", size); } } static void do_flash_probe(const char *s) { (void)s; if (flash) { flash_release(flash); flash = NULL; } if (!(flash = flash_probe())) { fprintf(stderr, "error: unable to probe flash device.\n"); } } static void do_flash_info(const char *s) { size_t size; (void)s; if (!flash) { fprintf(stderr, "error: no flash device probed.\n"); return; } size = flash_get_size(flash); printf("Capacity: %" PRSZu " blocks (", size / (4 * KIB)); print_size(size); printf(")\n"); } static void do_flash_read(const char *s) { char buf[256], *end = NULL; size_t addr, len, nbytes; if (!flash) { fprintf(stderr, "error: no flash device probed.\n"); return; } if (strncmp(s, "0x", 2) == 0) s += 2; addr = strtoull(s, &end, 16); s = end; if (errno == EINVAL || errno == ERANGE) return; s += strspn(s, " \n"); if (strncmp(s, "0x", 2) == 0) s += 2; len = strtoull(s, &end, 16); s = end; if (errno == EINVAL || errno == ERANGE) return; if (!len) return; while (len) { nbytes = min(len, 256); flash_read(flash, addr, buf, nbytes); print_hex_ascii(buf, nbytes); addr += nbytes; len -= nbytes; } } static void do_flash_write(const char *s) { char buf[256], *end = NULL; size_t addr, len, nbytes; if (!flash) { fprintf(stderr, "error: no flash device probed.\n"); return; } if (strncmp(s, "0x", 2) == 0) s += 2; addr = strtoull(s, &end, 16); s = end; if (errno == EINVAL || errno == ERANGE) return; s += strspn(s, " \n"); if (strncmp(s, "0x", 2) == 0) s += 2; len = strtoull(s, &end, 16); s = end; if (errno == EINVAL || errno == ERANGE) return; if (!len) return; while (len) { nbytes = min(len, 256); parse_hex(stdin, buf, nbytes); printf("\n"); print_hex_ascii(buf, nbytes); flash_write(flash, addr, buf, nbytes); addr += nbytes; len -= nbytes; } } static void do_flash_erase(const char *s) { char *end = NULL; size_t addr, len; if (!flash) { fprintf(stderr, "error: no flash device probed.\n"); return; } if (strncmp(s, "0x", 2) == 0) s += 2; addr = strtoull(s, &end, 16); s = end; if (errno == EINVAL || errno == ERANGE) return; s += strspn(s, " \n"); if (strncmp(s, "0x", 2) == 0) s += 2; len = strtoull(s, &end, 16); s = end; if (errno == EINVAL || errno == ERANGE) return; if (!len) return; flash_erase(flash, addr, len); } void do_flash_cmd(const char *line) { cmd_exec(flash_cmds, line); }