cli: Add new `config' CLI for status/config registers
TBD
For instance, the quad-enable bit can then be queried like this:
$ flashprog config -p ch341a_spi --get quad-enable
TODO: Write a manpage once the syntax is agreed upon.
Change-Id: I6b9d26c67e6ad65be5df367d2db7942bb98f27ac
Signed-off-by: Nico Huber <nico.h@gmx.de>
diff --git a/Makefile b/Makefile
index a75c280..6341935 100644
--- a/Makefile
+++ b/Makefile
@@ -401,7 +401,7 @@
###############################################################################
# Frontend related stuff.
-CLI_OBJS = cli.o cli_classic.o cli_output.o cli_common.o print.o
+CLI_OBJS = cli.o cli_config.o cli_classic.o cli_output.o cli_common.o print.o
# By default version information will be fetched from Git if available.
# Otherwise, versioninfo.inc stores the metadata required to build a
diff --git a/cli.c b/cli.c
index 82723fd..6a0cbe1 100644
--- a/cli.c
+++ b/cli.c
@@ -27,6 +27,8 @@
} commands[] = {
{ "mem", flashprog_classic_main },
{ "memory", flashprog_classic_main },
+ { "cfg", flashprog_config_main },
+ { "config", flashprog_config_main },
};
static void usage(const char *const name)
@@ -35,6 +37,7 @@
fprintf(stderr, "\nWhere <command> can be\n\n"
" mem[ory] Standard memory operations\n"
" (read/erase/write/verify)\n"
+ " cfg|config Status/config register operations\n"
"\n"
"The default is 'memory'. See `%s <command> --help`\n"
"for further instructions.\n\n", name);
diff --git a/cli_config.c b/cli_config.c
new file mode 100644
index 0000000..55f98cf
--- /dev/null
+++ b/cli_config.c
@@ -0,0 +1,253 @@
+/*
+ * This file is part of the flashprog project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <limits.h>
+
+#include "libflashprog.h"
+#include "chipdrivers.h"
+#include "flash.h"
+#include "cli.h"
+
+enum settings {
+ QUAD_ENABLE,
+};
+
+static const struct reg_bit_info *get_bit_info(
+ const struct flashctx *flash, enum settings setting)
+{
+ switch (setting) {
+ case QUAD_ENABLE:
+ return &flash->chip->reg_bits.qe;
+ default:
+ return NULL;
+ }
+}
+
+static int config_get(const struct flashctx *flash, enum settings setting)
+{
+ const struct reg_bit_info *const bit = get_bit_info(flash, setting);
+ uint8_t reg_val;
+
+ if (!bit)
+ return 1;
+
+ const int ret = spi_read_register(flash, bit->reg, ®_val);
+ if (ret)
+ return 1;
+
+ printf("%u\n", reg_val >> bit->bit_index & 1);
+ return 0;
+}
+
+static int config_set(const struct flashctx *flash, enum settings setting, unsigned int value)
+{
+ const struct reg_bit_info *const bit = get_bit_info(flash, setting);
+ uint8_t reg_val;
+ int ret;
+
+ if (!bit)
+ return 1;
+
+ ret = spi_read_register(flash, bit->reg, ®_val);
+ if (ret)
+ return 1;
+
+ reg_val &= ~(1 << bit->bit_index);
+ reg_val |= (value & 1) << bit->bit_index;
+
+ ret = spi_write_register(flash, bit->reg, reg_val, default_wrsr_target(flash));
+ if (ret)
+ return 1;
+
+ return 0;
+}
+
+static void usage(const char *const name, const char *const msg)
+{
+ if (msg)
+ fprintf(stderr, "\nError: %s\n", msg);
+
+ fprintf(stderr, "\nUsage: %s -p <programmername>[:<parameters] [-c <chipname>]\n"
+ "\t\t\t\t[-V[V[V]]] [-o <logfile>]\n"
+ "\t\t\t\t([--get] <setting>|--set [--volatile] <setting> <value>)\n",
+ name);
+ fprintf(stderr, "\nWhere <setting> can be\n\n"
+ " qe|quad-enable Quad-Enable (QE) bit\n"
+ "\nand <value> can be `true', `false', or a number.\n"
+ "\nBy default, the setting is queried (--get).\n"
+ "\n");
+ exit(1);
+}
+
+static int parse_setting(const char *const setting)
+{
+ if (!strcmp(setting, "qe") ||
+ !strcmp(setting, "quad-enable"))
+ return QUAD_ENABLE;
+ return -1;
+}
+
+static int parse_value(const char *const value)
+{
+ if (!strcmp(value, "true"))
+ return 1;
+ if (!strcmp(value, "false"))
+ return 0;
+
+ char *endptr;
+ const unsigned long i = strtoul(value, &endptr, 0);
+ if (value[0] && !endptr[0] && i <= INT_MAX)
+ return i;
+
+ return -1;
+}
+
+int flashprog_config_main(int argc, char *argv[])
+{
+ static const char optstring[] = "+p:c:Vo:h";
+ static const struct option long_options[] = {
+ {"programmer", 1, NULL, 'p'},
+ {"chip", 1, NULL, 'c'},
+ {"verbose", 0, NULL, 'V'},
+ {"output", 1, NULL, 'o'},
+ {"help", 0, NULL, 'h'},
+ {"get", 0, NULL, OPTION_CONFIG_GET},
+ {"set", 0, NULL, OPTION_CONFIG_SET},
+ {"volatile", 0, NULL, OPTION_CONFIG_VOLATILE},
+ {NULL, 0, NULL, 0},
+ };
+
+ unsigned int ops = 0;
+ int ret, opt, option_index;
+ struct log_args log_args = { FLASHPROG_MSG_INFO, FLASHPROG_MSG_DEBUG2, NULL };
+ struct flash_args flash_args = { 0 };
+ bool get = false, set = false, volat1le = false;
+
+ while ((opt = getopt_long(argc, argv, optstring,
+ long_options, &option_index)) != EOF) {
+ switch (opt) {
+ case 'V':
+ case 'o':
+ ret = cli_parse_log_args(&log_args, opt, optarg);
+ if (ret == 1)
+ usage(argv[0], NULL);
+ else if (ret)
+ goto free_ret;
+ break;
+ case 'p':
+ case 'c':
+ ret = cli_parse_flash_args(&flash_args, opt, optarg);
+ if (ret == 1)
+ usage(argv[0], NULL);
+ else if (ret)
+ goto free_ret;
+ break;
+ case OPTION_CONFIG_GET:
+ get = true;
+ ++ops;
+ break;
+ case OPTION_CONFIG_SET:
+ set = true;
+ ++ops;
+ break;
+ case OPTION_CONFIG_VOLATILE:
+ volat1le = true;
+ break;
+ case '?':
+ case 'h':
+ usage(argv[0], NULL);
+ break;
+ }
+ }
+
+ if (!ops) {
+ get = true;
+ ++ops;
+ }
+ if (ops > 1)
+ usage(argv[0], "Only one operation may be specified.");
+
+ if (!flash_args.prog_name)
+ usage(argv[0], "No programmer specified.");
+
+ if (get && volat1le)
+ usage(argv[0], "`--volatile' may only be specified for `--set'.");
+ if (get && optind != argc - 1)
+ usage(argv[0], "`--get' requires exactly one argument.");
+ if (set && optind != argc - 2)
+ usage(argv[0], "`--set' requires exactly two arguments.");
+
+ const int setting = parse_setting(argv[optind]);
+ if (setting < 0) {
+ fprintf(stderr, "\nError: Unknown <setting> argument `%s'.\n", argv[optind]);
+ usage(argv[0], NULL);
+ }
+ int value = 0;
+ if (set) {
+ value = parse_value(argv[optind + 1]);
+ if (value < 0) {
+ fprintf(stderr, "\nError: Cannot parse value `%s'.\n", argv[optind + 1]);
+ usage(argv[0], NULL);
+ }
+ }
+
+ struct flashprog_programmer *prog;
+ struct flashprog_flashctx *flash;
+ ret = 1;
+
+ if (cli_init())
+ goto free_ret;
+
+ if (log_args.logfile && open_logfile(log_args.logfile))
+ goto free_ret;
+ verbose_screen = log_args.screen_level;
+ verbose_logfile = log_args.logfile_level;
+ start_logging();
+
+ if (flashprog_programmer_init(&prog, flash_args.prog_name, flash_args.prog_args))
+ goto free_ret;
+ if (flashprog_flash_probe(&flash, prog, flash_args.chip)) {
+ fprintf(stderr, "No EEPROM/flash device found.\n");
+ goto shutdown_ret;
+ }
+
+ if (flash->chip->bustype != BUS_SPI || flash->chip->spi_cmd_set != SPI25) {
+ fprintf(stderr, "Only SPI25 flash chips are supported.\n");
+ goto shutdown_ret;
+ }
+
+ flashprog_flag_set(flash, FLASHPROG_FLAG_NON_VOLATILE_WRSR, set && !volat1le);
+
+ if (get)
+ ret = config_get(flash, setting);
+
+ if (set)
+ ret = config_set(flash, setting, value);
+
+ flashprog_flash_release(flash);
+shutdown_ret:
+ flashprog_programmer_shutdown(prog);
+free_ret:
+ free(flash_args.chip);
+ free(flash_args.prog_args);
+ free(flash_args.prog_name);
+ free(log_args.logfile);
+ close_logfile();
+ return ret;
+}
diff --git a/include/cli.h b/include/cli.h
index e9e512c..a96bbfb 100644
--- a/include/cli.h
+++ b/include/cli.h
@@ -32,6 +32,9 @@
OPTION_FLASH_NAME,
OPTION_FLASH_SIZE,
OPTION_PROGRESS,
+ OPTION_CONFIG_GET,
+ OPTION_CONFIG_SET,
+ OPTION_CONFIG_VOLATILE,
};
struct log_args {
@@ -63,6 +66,7 @@
int cli_init(void);
int flashprog_classic_main(int argc, char *argv[]);
+int flashprog_config_main(int argc, char *argv[]);
extern enum flashprog_log_level verbose_screen;
extern enum flashprog_log_level verbose_logfile;
diff --git a/meson.build b/meson.build
index e8dd525..c871ad9 100644
--- a/meson.build
+++ b/meson.build
@@ -606,6 +606,7 @@
'flashprog',
files(
'cli.c',
+ 'cli_config.c',
'cli_classic.c',
'cli_common.c',
'cli_output.c',