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