altos: Move common storage code to ao_storage.c. Add M25P80 driver
[fw/altos] / src / 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; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include "ao.h"
19
20 uint8_t
21 ao_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
22 {
23         uint16_t this_len;
24         uint16_t this_off;
25
26         ao_storage_setup();
27         if (pos >= ao_storage_total || pos + len > ao_storage_total)
28                 return 0;
29         while (len) {
30
31                 /* Compute portion of transfer within
32                  * a single block
33                  */
34                 this_off = (uint16_t) pos & (ao_storage_unit - 1);
35                 this_len = ao_storage_unit - this_off;
36                 if (this_len > len)
37                         this_len = len;
38
39                 if (!ao_storage_device_read(pos, buf, this_len))
40                         return 0;
41
42                 /* See how much is left */
43                 buf += this_len;
44                 len -= this_len;
45                 pos += this_len;
46         }
47         return 1;
48 }
49
50 uint8_t
51 ao_storage_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
52 {
53         uint16_t this_len;
54         uint16_t this_off;
55
56         ao_storage_setup();
57         if (pos >= ao_storage_total || pos + len > ao_storage_total)
58                 return 0;
59         while (len) {
60
61                 /* Compute portion of transfer within
62                  * a single block
63                  */
64                 this_off = (uint16_t) pos & (ao_storage_unit - 1);
65                 this_len = ao_storage_unit - this_off;
66                 if (this_len > len)
67                         this_len = len;
68
69                 if (!ao_storage_device_write(pos, buf, this_len))
70                         return 0;
71
72                 /* See how much is left */
73                 buf += this_len;
74                 len -= this_len;
75                 pos += this_len;
76         }
77         return 1;
78 }
79
80 static __xdata uint8_t storage_data[8];
81
82 static void
83 ao_storage_dump(void) __reentrant
84 {
85         uint8_t i, j;
86
87         ao_cmd_hex();
88         if (ao_cmd_status != ao_cmd_success)
89                 return;
90         for (i = 0; ; i += 8) {
91                 if (ao_storage_read(((uint32_t) (ao_cmd_lex_i) << 8) + i,
92                                   storage_data,
93                                   8)) {
94                         ao_cmd_put16((uint16_t) i);
95                         for (j = 0; j < 7; j++) {
96                                 putchar(' ');
97                                 ao_cmd_put8(storage_data[j]);
98                         }
99                         putchar ('\n');
100                 }
101                 if (i == 248)
102                         break;
103         }
104 }
105
106 static void
107 ao_storage_store(void) __reentrant
108 {
109         uint16_t block;
110         uint8_t i;
111         uint16_t len;
112         static __xdata uint8_t b;
113         uint32_t addr;
114
115         ao_cmd_hex();
116         block = ao_cmd_lex_i;
117         ao_cmd_hex();
118         i = ao_cmd_lex_i;
119         addr = ((uint32_t) block << 8) | i;
120         ao_cmd_hex();
121         len = ao_cmd_lex_i;
122         if (ao_cmd_status != ao_cmd_success)
123                 return;
124         while (len--) {
125                 ao_cmd_hex();
126                 if (ao_cmd_status != ao_cmd_success)
127                         return;
128                 b = ao_cmd_lex_i;
129                 ao_storage_write(addr, &b, 1);
130                 addr++;
131         }
132 }
133
134 void
135 ao_storage_zap(void) __reentrant
136 {
137         ao_cmd_hex();
138         if (ao_cmd_status != ao_cmd_success)
139                 return;
140         ao_storage_erase((uint32_t) ao_cmd_lex_i << 8);
141 }
142
143 void
144 ao_storage_info(void) __reentrant
145 {
146         printf("Storage size: %ld\n", ao_storage_total);
147         printf("Storage erase unit: %ld\n", ao_storage_block);
148         ao_storage_device_info();
149 }
150
151 __code struct ao_cmds ao_storage_cmds[] = {
152         { 'f', ao_storage_info, "f                                  Show storage info" },
153         { 'e', ao_storage_dump, "e <block>                          Dump a block of flash data" },
154         { 'w', ao_storage_store,"w <block> <start> <len> <data> ... Write data to flash" },
155         { 'z', ao_storage_zap,  "z <block>                          Erase flash containing <block>" },
156         { 0,   ao_storage_zap, NULL },
157 };
158
159 void
160 ao_storage_init(void)
161 {
162         ao_storage_device_init();
163         ao_cmd_register(&ao_storage_cmds[0]);
164 }