altos: Make cmd number parsing functions return value
[fw/altos] / src / kernel / ao_storage.c
1 /*
2  * Copyright © 2011 Keith Packard <keithp@keithp.com>
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, 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.
13  *
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.
17  */
18
19 #include <ao.h>
20 #include <ao_storage.h>
21
22 uint8_t
23 ao_storage_read(ao_pos_t pos, void *buf, uint16_t len) 
24 {
25 #ifdef CC1111
26         return ao_storage_device_read(pos, buf, len);
27 #else
28         uint16_t this_len;
29         uint16_t this_off;
30
31         ao_storage_setup();
32         if (pos >= ao_storage_total || pos + len > ao_storage_total)
33                 return 0;
34         while (len) {
35
36                 /* Compute portion of transfer within
37                  * a single block
38                  */
39                 this_off = (uint16_t) pos & (ao_storage_unit - 1);
40                 this_len = ao_storage_unit - this_off;
41                 if (this_len > len)
42                         this_len = len;
43
44                 if (!ao_storage_device_read(pos, buf, this_len))
45                         return 0;
46
47                 /* See how much is left */
48                 buf += this_len;
49                 len -= this_len;
50                 pos += this_len;
51         }
52         return 1;
53 #endif
54 }
55
56 uint8_t
57 ao_storage_write(ao_pos_t pos, void *buf, uint16_t len) 
58 {
59 #ifdef CC1111
60         return ao_storage_device_write(pos, buf, len);
61 #else
62         uint16_t this_len;
63         uint16_t this_off;
64
65         ao_storage_setup();
66         if (pos >= ao_storage_total || pos + len > ao_storage_total)
67                 return 0;
68         while (len) {
69
70                 /* Compute portion of transfer within
71                  * a single block
72                  */
73                 this_off = (uint16_t) pos & (ao_storage_unit - 1);
74                 this_len = ao_storage_unit - this_off;
75                 if (this_len > len)
76                         this_len = len;
77
78                 if (!ao_storage_device_write(pos, buf, this_len))
79                         return 0;
80
81                 /* See how much is left */
82                 buf += this_len;
83                 len -= this_len;
84                 pos += this_len;
85         }
86         return 1;
87 #endif
88 }
89
90 static uint8_t storage_data[128];
91
92 static void
93 ao_storage_dump(void) 
94 {
95         uint32_t block;
96         uint8_t i, j;
97
98         block = ao_cmd_hex();
99         if (ao_cmd_status != ao_cmd_success)
100                 return;
101         for (i = 0; ; i += 8) {
102                 if (ao_storage_read((block << 8) + i,
103                                     storage_data,
104                                     8)) {
105                         ao_cmd_put16((uint16_t) i);
106                         for (j = 0; j < 8; j++) {
107                                 putchar(' ');
108                                 ao_cmd_put8(storage_data[j]);
109                         }
110                         putchar ('\n');
111                 }
112                 if (i == 248)
113                         break;
114         }
115 }
116
117 #if HAS_STORAGE_DEBUG
118
119 /* not enough space for this today
120  */
121 static void
122 ao_storage_store(void) 
123 {
124         uint16_t block;
125         uint8_t i;
126         uint16_t len;
127         uint8_t b;
128         uint32_t addr;
129
130         block = ao_cmd_hex();
131         i = ao_cmd_hex();
132         addr = ((uint32_t) block << 8) | i;
133         len = ao_cmd_hex();
134         if (ao_cmd_status != ao_cmd_success)
135                 return;
136         while (len--) {
137                 b = ao_cmd_hexbyte();
138                 if (ao_cmd_status != ao_cmd_success)
139                         return;
140                 ao_storage_write(addr, &b, 1);
141                 addr++;
142         }
143 }
144 #endif
145
146 void
147 ao_storage_zap(void) 
148 {
149         uint32_t v = ao_cmd_hex();
150         if (ao_cmd_status != ao_cmd_success)
151                 return;
152         ao_storage_erase((uint32_t) v << 8);
153 }
154
155 void
156 ao_storage_zapall(void) 
157 {
158         uint32_t        pos;
159
160         ao_cmd_white();
161         if (!ao_match_word("DoIt"))
162                 return;
163         for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block)
164                 ao_storage_erase(pos);
165 }
166
167 #if AO_STORAGE_TEST
168
169 static void
170 ao_storage_failure(uint32_t pos, char *format, ...)
171 {
172         va_list a;
173         printf("TEST FAILURE AT %08x: ", pos);
174         va_start(a, format);
175         vprintf(format, a);
176         va_end(a);
177 }
178
179 static uint8_t
180 ao_storage_check_block(uint32_t pos, uint8_t value)
181 {
182         uint32_t        offset;
183         uint32_t        byte;
184
185         for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_data)) {
186                 if (!ao_storage_read(pos + offset, storage_data, sizeof (storage_data))) {
187                         ao_storage_failure(pos + offset, "read failed\n");
188                         return 0;
189                 }
190                 for (byte = 0; byte < sizeof (storage_data); byte++)
191                         if (storage_data[byte] != value) {
192                                 ao_storage_failure(pos + offset + byte,
193                                                    "want %02x got %02x\n",
194                                                    value, storage_data[byte]);
195                                 return 0;
196                         }
197         }
198         return 1;
199 }
200
201 static uint8_t
202 ao_storage_fill_block(uint32_t pos, uint8_t value)
203 {
204         uint32_t        offset;
205         uint32_t        byte;
206
207         for (byte = 0; byte < sizeof (storage_data); byte++)
208                 storage_data[byte] = value;
209         for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_data)) {
210                 if (!ao_storage_write(pos + offset, storage_data, sizeof (storage_data))) {
211                         ao_storage_failure(pos + offset, "write failed\n");
212                         return 0;
213                 }
214         }
215         return 1;
216 }
217
218 static uint8_t
219 ao_storage_check_incr_block(uint32_t pos)
220 {
221         uint32_t        offset;
222         uint32_t        byte;
223
224         for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_data)) {
225                 if (!ao_storage_read(pos + offset, storage_data, sizeof (storage_data))) {
226                         ao_storage_failure(pos + offset, "read failed\n");
227                         return 0;
228                 }
229                 for (byte = 0; byte < sizeof (storage_data); byte++) {
230                         uint8_t value = offset + byte;
231                         if (storage_data[byte] != value) {
232                                 ao_storage_failure(pos + offset + byte,
233                                                    "want %02x got %02x\n",
234                                                    value, storage_data[byte]);
235                                 return 0;
236                         }
237                 }
238         }
239         return 1;
240 }
241
242 static uint8_t
243 ao_storage_fill_incr_block(uint32_t pos)
244 {
245         uint32_t        offset;
246         uint32_t        byte;
247
248         for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_data)) {
249                 for (byte = 0; byte < sizeof (storage_data); byte++)
250                         storage_data[byte] = offset + byte;
251                 if (!ao_storage_write(pos + offset, storage_data, sizeof (storage_data))) {
252                         ao_storage_failure(pos + offset, "write failed\n");
253                         return 0;
254                 }
255         }
256         return 1;
257 }
258
259 static uint8_t
260 ao_storage_fill_check_block(uint32_t pos, uint8_t value)
261 {
262         return ao_storage_fill_block(pos, value) && ao_storage_check_block(pos, value);
263 }
264
265 static uint8_t
266 ao_storage_incr_check_block(uint32_t pos)
267 {
268         return ao_storage_fill_incr_block(pos) && ao_storage_check_incr_block(pos);
269 }
270
271 static uint8_t
272 ao_storage_test_block(uint32_t pos) 
273 {
274         ao_storage_erase(pos);
275         printf(" erase"); flush();
276         if (!ao_storage_check_block(pos, 0xff))
277                 return 0;
278         printf(" zero"); flush();
279         if (!ao_storage_fill_check_block(pos, 0x00))
280                 return 0;
281         ao_storage_erase(pos);
282         printf(" 0xaa"); flush();
283         if (!ao_storage_fill_check_block(pos, 0xaa))
284                 return 0;
285         ao_storage_erase(pos);
286         printf(" 0x55"); flush();
287         if (!ao_storage_fill_check_block(pos, 0x55))
288                 return 0;
289         ao_storage_erase(pos);
290         printf(" increment"); flush();
291         if (!ao_storage_incr_check_block(pos))
292                 return 0;
293         ao_storage_erase(pos);
294         printf(" pass\n"); flush();
295         return 1;
296 }
297
298 static void
299 ao_storage_test(void) 
300 {
301         uint32_t        pos;
302
303         ao_cmd_white();
304         if (!ao_match_word("DoIt"))
305                 return;
306         for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block) {
307                 printf("Testing block 0x%08x:", pos); flush();
308                 if (!ao_storage_test_block(pos))
309                         break;
310         }
311         printf("Test complete\n");
312 }
313 #endif /* AO_STORAGE_TEST */
314
315 void
316 ao_storage_info(void) 
317 {
318         ao_storage_setup();
319         printf("Storage size: %ld\n", (long) ao_storage_total);
320         printf("Storage erase unit: %ld\n", (long) ao_storage_block);
321         ao_storage_device_info();
322 }
323
324 const struct ao_cmds ao_storage_cmds[] = {
325         { ao_storage_info, "f\0Show storage" },
326         { ao_storage_dump, "e <block>\0Dump flash" },
327 #if HAS_STORAGE_DEBUG
328         { ao_storage_store, "w <block> <start> <len> <data> ...\0Write data to flash" },
329 #endif
330         { ao_storage_zap, "z <block>\0Erase <block>" },
331         { ao_storage_zapall,"Z <key>\0Erase all. <key> is doit with D&I" },
332 #if AO_STORAGE_TEST
333         { ao_storage_test, "V <key>\0Validate flash (destructive). <key> is doit with D&I" },
334 #endif
335         { 0, NULL },
336 };
337
338 void
339 ao_storage_init(void)
340 {
341         ao_storage_device_init();
342         ao_cmd_register(&ao_storage_cmds[0]);
343 }