2 * Copyright © 2011 Keith Packard <keithp@keithp.com>
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.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 #include <ao_storage.h>
22 #define AO_STORAGE_DATA_SIZE 128
24 static uint8_t storage_data[AO_STORAGE_DATA_SIZE];
25 static uint8_t storage_mutex;
28 ao_storage_read(ao_pos_t pos, void *v_buf, uint16_t len)
35 if (pos >= ao_storage_total || pos + len > ao_storage_total)
39 /* Compute portion of transfer within
42 this_off = (uint16_t) pos & (ao_storage_unit - 1);
43 this_len = ao_storage_unit - this_off;
47 if (!ao_storage_device_read(pos, buf, this_len))
50 /* See how much is left */
59 ao_storage_write(ao_pos_t pos, void *v_buf, uint16_t len)
66 if (pos >= ao_storage_total || pos + len > ao_storage_total)
70 /* Compute portion of transfer within
73 this_off = (uint16_t) pos & (ao_storage_unit - 1);
74 this_len = ao_storage_unit - this_off;
78 if (!ao_storage_device_write(pos, buf, this_len))
81 /* See how much is left */
89 #ifndef AO_STORAGE_ERASED_BYTE
90 #define AO_STORAGE_ERASED_BYTE 0xff
94 ao_storage_is_erased(uint32_t pos)
102 ao_mutex_get(&storage_mutex);
104 read_len = ao_storage_block;
106 uint32_t this_time = AO_STORAGE_DATA_SIZE;
107 if (this_time > read_len)
108 this_time = read_len;
109 if (!ao_storage_read(read_pos, storage_data, this_time)) {
113 for (i = 0; i < this_time; i++)
114 if (storage_data[i] != AO_STORAGE_ERASED_BYTE) {
118 read_pos += this_time;
119 read_len -= this_time;
122 ao_mutex_put(&storage_mutex);
127 ao_storage_erase(uint32_t start_pos, uint32_t len)
129 /* Round 'len' up to ao_storage_block units */
130 len = ((len + ao_storage_block - 1) / ao_storage_block) * ao_storage_block;
133 * Start at the end of the area to erase so that the
134 * last block cleared is the first block; this will ensure
135 * that partially erased flight logs still appear in the list
136 * and can be re-erased.
138 uint32_t pos = start_pos + len - ao_storage_block;
142 #define MAX_TRIES 4 /* needs to be at least 2 */
143 for (tries = 0; tries < MAX_TRIES; tries++) {
144 if (ao_storage_is_erased(pos))
146 if (!ao_storage_device_erase(pos))
149 if (tries == MAX_TRIES)
151 pos -= ao_storage_block;
152 len -= ao_storage_block;
158 ao_storage_dump(void)
163 block = ao_cmd_hex();
164 if (ao_cmd_status != ao_cmd_success)
166 ao_mutex_get(&storage_mutex);
167 for (i = 0; ; i += AO_STORAGE_DATA_SIZE) {
168 if (ao_storage_read((block << 8) + i,
170 AO_STORAGE_DATA_SIZE)) {
171 for (k = 0; k < AO_STORAGE_DATA_SIZE; k += 8) {
172 ao_cmd_put16((uint16_t) i + k);
173 for (j = 0; j < 8; j++) {
175 ao_cmd_put8(storage_data[k + j]);
180 if (i == 256 - AO_STORAGE_DATA_SIZE)
183 ao_mutex_put(&storage_mutex);
186 #if HAS_STORAGE_DEBUG
188 /* not enough space for this today
191 ao_storage_store(void)
199 block = ao_cmd_hex();
201 addr = ((uint32_t) block << 8) | i;
203 if (ao_cmd_status != ao_cmd_success)
206 b = ao_cmd_hexbyte();
207 if (ao_cmd_status != ao_cmd_success)
209 ao_storage_write(addr, &b, 1);
218 uint32_t v = ao_cmd_hex();
219 if (ao_cmd_status != ao_cmd_success)
221 ao_storage_erase((uint32_t) v << 8, ao_storage_block);
225 ao_storage_zapall(void)
228 if (!ao_match_word("DoIt"))
230 ao_storage_erase(0, ao_storage_log_max);
235 #define AO_STORAGE_TEST_SIZE 256
236 static uint8_t storage_test[AO_STORAGE_TEST_SIZE];
239 ao_storage_failure(uint32_t pos, char *format, ...)
242 printf("TEST FAILURE AT %08x: ", pos);
249 ao_storage_check_block(uint32_t pos, uint8_t value)
254 for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_test)) {
255 if (!ao_storage_read(pos + offset, storage_test, sizeof (storage_test))) {
256 ao_storage_failure(pos + offset, "read failed\n");
259 for (byte = 0; byte < sizeof (storage_test); byte++)
260 if (storage_test[byte] != value) {
261 ao_storage_failure(pos + offset + byte,
262 "want %02x got %02x\n",
263 value, storage_test[byte]);
271 ao_storage_fill_block(uint32_t pos, uint8_t value)
276 for (byte = 0; byte < sizeof (storage_test); byte++)
277 storage_test[byte] = value;
278 for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_test)) {
279 if (!ao_storage_write(pos + offset, storage_test, sizeof (storage_test))) {
280 ao_storage_failure(pos + offset, "write failed\n");
288 ao_storage_check_incr_block(uint32_t pos)
293 for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_test)) {
294 if (!ao_storage_read(pos + offset, storage_test, sizeof (storage_test))) {
295 ao_storage_failure(pos + offset, "read failed\n");
298 for (byte = 0; byte < sizeof (storage_test); byte++) {
299 uint8_t value = offset + byte;
300 if (storage_test[byte] != value) {
301 ao_storage_failure(pos + offset + byte,
302 "want %02x got %02x\n",
303 value, storage_test[byte]);
312 ao_storage_fill_incr_block(uint32_t pos)
317 for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_test)) {
318 for (byte = 0; byte < sizeof (storage_test); byte++)
319 storage_test[byte] = offset + byte;
320 if (!ao_storage_write(pos + offset, storage_test, sizeof (storage_test))) {
321 ao_storage_failure(pos + offset, "write failed\n");
329 ao_storage_fill_check_block(uint32_t pos, uint8_t value)
331 return ao_storage_fill_block(pos, value) && ao_storage_check_block(pos, value);
335 ao_storage_incr_check_block(uint32_t pos)
337 return ao_storage_fill_incr_block(pos) && ao_storage_check_incr_block(pos);
341 ao_storage_test_block(uint32_t pos)
343 ao_storage_erase(pos, ao_storage_block);
344 printf(" erase"); flush();
345 if (!ao_storage_check_block(pos, 0xff))
347 printf(" zero"); flush();
348 if (!ao_storage_fill_check_block(pos, 0x00))
350 ao_storage_erase(pos, ao_storage_block);
351 printf(" 0xaa"); flush();
352 if (!ao_storage_fill_check_block(pos, 0xaa))
354 ao_storage_erase(pos, ao_storage_block);
355 printf(" 0x55"); flush();
356 if (!ao_storage_fill_check_block(pos, 0x55))
358 ao_storage_erase(pos, ao_storage_block);
359 printf(" increment"); flush();
360 if (!ao_storage_incr_check_block(pos))
362 ao_storage_erase(pos, ao_storage_block);
363 printf(" pass\n"); flush();
368 ao_storage_test(void)
373 if (!ao_match_word("DoIt"))
375 for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block) {
376 printf("Testing block 0x%08x:", pos); flush();
377 if (!ao_storage_test_block(pos))
380 printf("Test complete\n");
384 ao_storage_fill(void)
389 if (!ao_match_word("DoIt"))
391 printf("erase "); flush();
392 ao_storage_erase(0, ao_storage_log_max);
393 for (pos = 0; pos < sizeof (storage_test); pos++)
394 storage_test[pos] = (uint8_t) pos;
395 for (pos = 0; pos < ao_storage_log_max; pos += sizeof (storage_test)) {
396 if ((pos & 0xffff) == 0) {
397 printf("Fill 0x%x\n", pos); flush();
399 ao_storage_write(pos, storage_test, sizeof (storage_test));
401 printf("Fill complete\n");
403 #endif /* AO_STORAGE_TEST */
406 ao_storage_info(void)
409 printf("Storage size: %ld\n", (long) ao_storage_total);
410 printf("Storage erase unit: %ld\n", (long) ao_storage_block);
411 ao_storage_device_info();
414 const struct ao_cmds ao_storage_cmds[] = {
415 { ao_storage_info, "f\0Show storage" },
416 { ao_storage_dump, "e <block>\0Dump flash" },
417 #if HAS_STORAGE_DEBUG
418 { ao_storage_store, "w <block> <start> <len> <data> ...\0Write data to flash" },
420 { ao_storage_zap, "z <block>\0Erase <block>" },
421 { ao_storage_zapall,"Z <key>\0Erase all. <key> is doit with D&I" },
423 { ao_storage_test, "V <key>\0Validate flash (destructive). <key> is doit with D&I" },
424 { ao_storage_fill, "F <key>\0Fill flash with data. <key> is doit with D&I" },
430 ao_storage_init(void)
432 ao_storage_device_init();
433 ao_cmd_register(&ao_storage_cmds[0]);