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.
248 lines
4.4 KiB
248 lines
4.4 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;
|
|
|
|
static void parse_hex(struct console *con, char *buf, size_t len)
|
|
{
|
|
size_t i;
|
|
char s[3];
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
memset(s, '\0', 3);
|
|
|
|
while (console_getc(s + 0, con) && !isxdigit(s[0]));
|
|
while (console_getc(s + 1, con) && !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;
|
|
}
|
|
}
|
|
|
|
int shell_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;
|
|
}
|
|
|
|
int shell_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;
|
|
}
|
|
|
|
int shell_flash_info(struct console *con, size_t argc, const char **argv)
|
|
{
|
|
char jedec_id[3] = { 0, 0, 0 };
|
|
size_t size, capacity;
|
|
|
|
(void)argv;
|
|
(void)argc;
|
|
|
|
if (!flash) {
|
|
fprintf(con->fp, "error: no flash device probed.\n");
|
|
return -1;
|
|
}
|
|
|
|
if (flash_get_jedec_id(flash, jedec_id, 3)) {
|
|
fprintf(con->fp, " JEDEC ID: %02x%02x%02x\n",
|
|
jedec_id[0], jedec_id[1], jedec_id[2]);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
int shell_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, 0);
|
|
|
|
if (errno == EINVAL || errno == ERANGE) {
|
|
fprintf(con->fp, "error: expected integer value for addr\n");
|
|
return -1;
|
|
}
|
|
|
|
len = strtoull(argv[1], NULL, 0);
|
|
|
|
if (errno == EINVAL || errno == ERANGE) {
|
|
fprintf(con->fp, "error: expected integer 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;
|
|
}
|
|
|
|
int shell_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, 0);
|
|
|
|
if (errno == EINVAL || errno == ERANGE) {
|
|
fprintf(con->fp, "error: expected integer value for addr\n");
|
|
return -1;
|
|
}
|
|
|
|
len = strtoull(argv[1], NULL, 0);
|
|
|
|
if (errno == EINVAL || errno == ERANGE) {
|
|
fprintf(con->fp, "error: expected integer value for len\n");
|
|
return -1;
|
|
}
|
|
|
|
if (!len)
|
|
return 0;
|
|
|
|
while (len) {
|
|
nbytes = min(len, 256);
|
|
parse_hex(con, 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;
|
|
}
|
|
|
|
int shell_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, 0);
|
|
|
|
if (errno == EINVAL || errno == ERANGE) {
|
|
fprintf(con->fp, "error: expected integer value for addr\n");
|
|
return -1;
|
|
}
|
|
|
|
len = strtoull(argv[1], NULL, 0);
|
|
|
|
if (errno == EINVAL || errno == ERANGE) {
|
|
fprintf(con->fp, "error: expected integer value for len\n");
|
|
return -1;
|
|
}
|
|
|
|
if (!len)
|
|
return 0;
|
|
|
|
flash_erase(flash, addr, len);
|
|
|
|
return 0;
|
|
}
|
|
|