#include #include #include #include #include #include #include #include #include #include #include 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])); while ((s[1] = getc(fp)) && !isxdigit(s[1])); *buf++ = strtoul(s, NULL, 16); } } static void print_hex_ascii(FILE *fp, uint32_t offset, const char *buf, size_t len) { size_t n, i; uint8_t c; for (; len; buf += n, len -= n) { n = min(len, 16); fprintf(fp, "%08" PRIx32 ": ", offset); for (i = 0; i < 16; ++i) { c = (i < n) ? buf[i] : 0; fprintf(fp, "%02x", c); } fprintf(fp, " "); for (i = 0; i < 16; ++i) { c = (i < n) ? buf[i] : 0; fprintf(fp, "%c", isalnum(c) ? c : '.'); } fprintf(fp, "\n"); offset += n; } } static int do_flash_probe(struct console *con, size_t argc, const char **argv) { (void)argv; (void)argc; if (flash) { flash_release(flash); flash = NULL; } if (!(flash = flash_probe())) { fprintf(con->fp, "error: unable to probe the flash device.\n"); return -1; } return 0; } static int do_flash_release(struct console *con, size_t argc, const char **argv) { (void)argv; (void)argc; if (!flash) { fprintf(con->fp, "no flash device currently active.\n"); return -1; } flash_release(flash); flash = NULL; return 0; } static int do_flash_info(struct console *con, size_t argc, const char **argv) { size_t size, capacity; (void)argv; (void)argc; if (!flash) { fprintf(con->fp, "error: no flash device probed.\n"); return -1; } size = flash_get_size(flash); capacity = flash_get_capacity(flash); fprintf(con->fp, " size: %" PRSZu "/%" PRSZu " bytes (%" PRSZu "%% usage)\n", size, capacity, 100 * size / capacity); return 0; } static int do_flash_read(struct console *con, size_t argc, const char **argv) { char buf[256]; size_t addr, len, nbytes; if (argc < 2) { fprintf(con->fp, "usage: flash read \n"); return -1; } if (!flash) { fprintf(con->fp, "error: no flash device probed.\n"); return -1; } addr = strtoull(argv[0], NULL, 16); if (errno == EINVAL || errno == ERANGE) { fprintf(con->fp, "error: expected hexadecimal value for addr\n"); return -1; } len = strtoull(argv[1], NULL, 16); if (errno == EINVAL || errno == ERANGE) { fprintf(con->fp, "error: expected hexadecimal value for len\n"); return -1; } if (!len) return 0; while (len) { nbytes = min(len, 256); flash_read(flash, addr, buf, nbytes); print_hex_ascii(con->fp, addr, buf, nbytes); addr += nbytes; len -= nbytes; } return 0; } static int do_flash_write(struct console *con, size_t argc, const char **argv) { char buf[256]; size_t addr, len, nbytes; if (argc < 2) { fprintf(con->fp, "usage: flash write \n"); return -1; } if (!flash) { fprintf(con->fp, "error: no flash device probed.\n"); return -1; } addr = strtoull(argv[0], NULL, 16); if (errno == EINVAL || errno == ERANGE) { fprintf(con->fp, "error: expected hexadecimal value for addr\n"); return -1; } len = strtoull(argv[1], NULL, 16); if (errno == EINVAL || errno == ERANGE) { fprintf(con->fp, "error: expected hexadecimal value for len\n"); return -1; } if (!len) return 0; while (len) { nbytes = min(len, 256); parse_hex(con->fp, buf, nbytes); printf("\n"); print_hex_ascii(con->fp, addr, buf, nbytes); flash_write(flash, addr, buf, nbytes); addr += nbytes; len -= nbytes; } flash_sync(flash); return 0; } static int do_flash_erase(struct console *con, size_t argc, const char **argv) { size_t addr, len; if (argc < 2) { fprintf(con->fp, "usage: flash erase \n"); return -1; } if (!flash) { fprintf(con->fp, "error: no flash device probed.\n"); return -1; } addr = strtoull(argv[0], NULL, 16); if (errno == EINVAL || errno == ERANGE) { fprintf(con->fp, "error: expected hexadecimal value for addr\n"); return -1; } len = strtoull(argv[1], NULL, 16); if (errno == EINVAL || errno == ERANGE) { fprintf(con->fp, "error: expected hexadecimal value for len\n"); return -1; } if (!len) return 0; flash_erase(flash, addr, len); return 0; } static struct cmd flash_cmds[] = { { "probe", NULL, do_flash_probe }, { "release", NULL, do_flash_release }, { "info", NULL, do_flash_info }, { "read", NULL, do_flash_read }, { "write", NULL, do_flash_write }, { "erase", NULL, do_flash_erase }, { NULL, NULL, NULL }, }; int do_flash_cmd(struct console *con, size_t argc, const char **argv) { if (argc < 1) { fprintf(con->fp, "usage: flash \n"); return -1; } return cmd_exec(flash_cmds, con, argc, argv); }