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.
264 lines
4.9 KiB
264 lines
4.9 KiB
#include <ctype.h>
|
|
#include <inttypes.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <console.h>
|
|
#include <flash.h>
|
|
#include <macros.h>
|
|
#include <shell.h>
|
|
|
|
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 <addr> <len>\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 <addr> <len>\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 <addr> <len>\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 <command>\n");
|
|
return -1;
|
|
}
|
|
|
|
return cmd_exec(flash_cmds, con, argc, argv);
|
|
}
|
|
|