blob: 3ffa04872714d6014879c095424df5cf6f9c6db7 [file] [log] [blame]
Nico Huber1f693db2023-02-11 18:28:33 +01001/*
2 * This file is part of the flashprog project.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <stdio.h>
16#include <stdint.h>
17#include <stdlib.h>
18#include <string.h>
19#include <getopt.h>
20#include <limits.h>
21#include <unistd.h>
22
23#include "libflashprog.h"
24#include "chipdrivers.h"
25#include "flash.h"
26#include "cli.h"
27
28enum settings {
29 QUAD_ENABLE,
30};
31
32static const struct reg_bit_info *get_bit_info(
33 const struct flashctx *flash, enum settings setting)
34{
35 switch (setting) {
36 case QUAD_ENABLE:
37 return &flash->chip->reg_bits.qe;
38 default:
39 return NULL;
40 }
41}
42
43static int config_get(const struct flashctx *flash, enum settings setting)
44{
45 const struct reg_bit_info *const bit = get_bit_info(flash, setting);
46 uint8_t reg_val;
47
48 if (!bit)
49 return 1;
50
51 const int ret = spi_read_register(flash, bit->reg, &reg_val);
52 if (ret)
53 return 1;
54
55 printf("%u\n", reg_val >> bit->bit_index & 1);
56 return 0;
57}
58
59static int config_set(const struct flashctx *flash, enum settings setting, unsigned int value)
60{
61 const struct reg_bit_info *const bit = get_bit_info(flash, setting);
62 uint8_t reg_val;
63 int ret;
64
65 if (!bit)
66 return 1;
67
68 ret = spi_read_register(flash, bit->reg, &reg_val);
69 if (ret)
70 return 1;
71
72 reg_val &= ~(1 << bit->bit_index);
73 reg_val |= (value & 1) << bit->bit_index;
74
75 ret = spi_write_register(flash, bit->reg, reg_val, default_wrsr_target(flash));
76 if (ret)
77 return 1;
78
79 return 0;
80}
81
82static void usage(const char *const name, const char *const msg)
83{
84 if (msg)
85 fprintf(stderr, "\nError: %s\n", msg);
86
87 fprintf(stderr, "\nUsage:"
88 "\t%s [get] <options> <setting>\n"
89 "\t%s set <options> [--temporary] <setting> <value>\n",
90 name, name);
91 print_generic_options();
92 fprintf(stderr, "\n<setting> can be\n"
93 " qe | quad-enable Quad-Enable (QE) bit\n"
94 "\nand <value> can be `true', `false', or a number.\n"
95 "\nBy default, the setting is queried (`get').\n"
96 "\n");
97 exit(1);
98}
99
100static int parse_setting(const char *const setting)
101{
102 if (!strcmp(setting, "qe") ||
103 !strcmp(setting, "quad-enable"))
104 return QUAD_ENABLE;
105 return -1;
106}
107
108static int parse_value(const char *const value)
109{
110 if (!strcmp(value, "true"))
111 return 1;
112 if (!strcmp(value, "false"))
113 return 0;
114
115 char *endptr;
116 const unsigned long i = strtoul(value, &endptr, 0);
117 if (value[0] && !endptr[0] && i <= INT_MAX)
118 return i;
119
120 return -1;
121}
122
123int flashprog_config_main(int argc, char *argv[])
124{
125 static const char optstring[] = "+p:c:Vo:h";
126 static const struct option long_options[] = {
127 {"programmer", 1, NULL, 'p'},
128 {"chip", 1, NULL, 'c'},
129 {"verbose", 0, NULL, 'V'},
130 {"output", 1, NULL, 'o'},
131 {"help", 0, NULL, 'h'},
132 {"get", 0, NULL, OPTION_CONFIG_GET},
133 {"set", 0, NULL, OPTION_CONFIG_SET},
134 {"temporary", 0, NULL, OPTION_CONFIG_VOLATILE},
135 {NULL, 0, NULL, 0},
136 };
137 static const struct opt_command cmd_options[] = {
138 {"get", OPTION_CONFIG_GET},
139 {"set", OPTION_CONFIG_SET},
140 {NULL, 0},
141 };
142
143 unsigned int ops = 0;
144 int ret = 1, opt;
145 struct log_args log_args = { FLASHPROG_MSG_INFO, FLASHPROG_MSG_DEBUG2, NULL };
146 struct flash_args flash_args = { 0 };
147 bool get = false, set = false, volat1le = false;
148
149 if (cli_init()) /* TODO: Can be moved below argument parsing once usage() uses `stderr` directly. */
150 goto free_ret;
151
152 if (argc < 2)
153 usage(argv[0], NULL);
154
155 while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1 ||
156 (opt = getopt_command(argc, argv, cmd_options)) != -1) {
157 switch (opt) {
158 case 'V':
159 case 'o':
160 ret = cli_parse_log_args(&log_args, opt, optarg);
161 if (ret == 1)
162 usage(argv[0], NULL);
163 else if (ret)
164 goto free_ret;
165 break;
166 case 'p':
167 case 'c':
168 ret = cli_parse_flash_args(&flash_args, opt, optarg);
169 if (ret == 1)
170 usage(argv[0], NULL);
171 else if (ret)
172 goto free_ret;
173 break;
174 case OPTION_CONFIG_GET:
175 get = true;
176 ++ops;
177 break;
178 case OPTION_CONFIG_SET:
179 set = true;
180 ++ops;
181 break;
182 case OPTION_CONFIG_VOLATILE:
183 volat1le = true;
184 break;
185 case '?':
186 case 'h':
187 usage(argv[0], NULL);
188 break;
189 }
190 }
191
192 if (!ops) {
193 get = true;
194 ++ops;
195 }
196
197 if (ops > 1)
198 usage(argv[0], "Only one operation may be specified.");
199
200 if (!set && volat1le)
201 usage(argv[0], "`--temporary' may only be specified for `set'.");
202 if (get && optind != argc - 1)
203 usage(argv[0], "`get' requires exactly one argument.");
204 if (set && optind != argc - 2)
205 usage(argv[0], "`set' requires exactly two arguments.");
206
207 if (!flash_args.prog_name)
208 usage(argv[0], "No programmer specified.");
209
210 const int setting = parse_setting(argv[optind]);
211 if (setting < 0) {
212 fprintf(stderr, "\nError: Unknown <setting> argument `%s'.\n", argv[optind]);
213 usage(argv[0], NULL);
214 }
215 int value = 0;
216 if (set) {
217 value = parse_value(argv[optind + 1]);
218 if (value < 0) {
219 fprintf(stderr, "\nError: Cannot parse value `%s'.\n", argv[optind + 1]);
220 usage(argv[0], NULL);
221 }
222 }
223
224 struct flashprog_programmer *prog;
225 struct flashprog_flashctx *flash;
226 ret = 1;
227
228 if (log_args.logfile && open_logfile(log_args.logfile))
229 goto free_ret;
230 verbose_screen = log_args.screen_level;
231 verbose_logfile = log_args.logfile_level;
232 start_logging();
233
234 if (flashprog_programmer_init(&prog, flash_args.prog_name, flash_args.prog_args))
235 goto free_ret;
236 if (flashprog_flash_probe(&flash, prog, flash_args.chip)) {
237 fprintf(stderr, "No EEPROM/flash device found.\n");
238 goto shutdown_ret;
239 }
240
241 if (flash->chip->bustype != BUS_SPI || flash->chip->spi_cmd_set != SPI25) {
242 fprintf(stderr, "Only SPI25 flash chips are supported.\n");
243 goto shutdown_ret;
244 }
245
246 flashprog_flag_set(flash, FLASHPROG_FLAG_NON_VOLATILE_WRSR, set && !volat1le);
247
248 if (get)
249 ret = config_get(flash, setting);
250
251 if (set)
252 ret = config_set(flash, setting, value);
253
254 flashprog_flash_release(flash);
255shutdown_ret:
256 flashprog_programmer_shutdown(prog);
257free_ret:
258 free(flash_args.chip);
259 free(flash_args.prog_args);
260 free(flash_args.prog_name);
261 free(log_args.logfile);
262 close_logfile();
263 return ret;
264}