|
|
|
#include <ctype.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include <flash.h>
|
|
|
|
#include <macros.h>
|
|
|
|
#include <shell.h>
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|