2 * Copyright © 2013 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.
23 /* Include bufio commands */
25 #define BUFIO_COMMANDS 0
28 #include "ao_sdcard.h"
41 static struct ao_bufio ao_bufio[AO_NUM_BUF];
42 static uint8_t ao_buffer[AO_NUM_BUF][AO_BUFSIZ];
43 static int16_t ao_seqno;
44 static uint8_t ao_bufio_mutex;
47 #define DBG(...) printf(__VA_ARGS__)
49 #define DBG(...) (void) 0
55 ao_mutex_get(&ao_bufio_mutex);
61 ao_mutex_put(&ao_bufio_mutex);
65 ao_seqno_age(int16_t s)
77 ao_seqno_older(int16_t a, int16_t b)
79 return ao_seqno_age(a) > ao_seqno_age(b);
83 ao_validate_bufno(int b)
85 if (b < 0 || AO_NUM_BUF <= b)
86 ao_panic(AO_PANIC_BUFIO);
90 ao_buf_to_num(uint8_t *buf)
92 int b = (buf - &ao_buffer[0][0]) / AO_BUFSIZ;
99 ao_bufio_to_num(struct ao_bufio *bufio)
101 int b = (bufio - ao_bufio);
103 ao_validate_bufno(b);
107 static inline struct ao_bufio *
108 ao_buf_to_bufio(uint8_t *buf)
110 int b = ao_buf_to_num(buf);
111 struct ao_bufio *bufio;
113 bufio = &ao_bufio[b];
114 DBG ("buf %08x is %d bufio %08x\n", buf, b, bufio);
118 static inline uint8_t *
119 ao_bufio_to_buf(struct ao_bufio *bufio)
121 int b = ao_bufio_to_num(bufio);
124 buf = &ao_buffer[b][0];
125 DBG ("bufio %08x is %d buf %08x\n", bufio, b, buf);
130 * Write a buffer to storage if it is dirty
133 ao_bufio_write(struct ao_bufio *bufio)
136 ao_sdcard_write_block(bufio->block, ao_bufio_to_buf(bufio));
142 * Read a buffer from storage
145 ao_bufio_read(struct ao_bufio *bufio)
147 uint8_t *buf = ao_bufio_to_buf(bufio);
149 return ao_sdcard_read_block(bufio->block, buf);
153 * Find a buffer containing the specified block
155 static struct ao_bufio *
156 ao_bufio_find_block(uint32_t block)
160 for (b = 0; b < AO_NUM_BUF; b++) {
161 struct ao_bufio *bufio = &ao_bufio[b];
162 if (bufio->block == block) {
163 DBG ("Found existing buffer %d (seqno %d)\n",
164 ao_bufio_to_num(bufio), bufio->seqno);
172 * Find the least recently used idle buffer
174 static struct ao_bufio *
175 ao_bufio_find_idle(void)
178 struct ao_bufio *oldest = NULL;
180 for (b = 0; b < AO_NUM_BUF; b++) {
181 struct ao_bufio *bufio = &ao_bufio[b];
183 if (!oldest || ao_seqno_older(bufio->seqno, oldest->seqno))
187 DBG ("Using idle buffer %d (seqno %d)\n",
188 ao_bufio_to_num(oldest), oldest->seqno);
193 * Return a pointer to a buffer containing
194 * the contents of the specified block
197 ao_bufio_get(uint32_t block)
199 struct ao_bufio *bufio;
203 bufio = ao_bufio_find_block(block);
205 bufio = ao_bufio_find_idle();
207 ao_bufio_write(bufio);
208 bufio->block = block;
209 DBG ("read buffer\n");
210 if (!ao_bufio_read(bufio)) {
211 bufio->block = 0xffffffff;
215 ao_panic(AO_PANIC_BUFIO);
220 ao_panic(AO_PANIC_BUFIO);
221 buf = ao_bufio_to_buf(bufio);
228 * Release a buffer, marking it dirty
229 * if it has been written to
232 ao_bufio_put(uint8_t *buf, uint8_t write)
234 struct ao_bufio *bufio;
237 bufio = ao_buf_to_bufio(buf);
240 ao_panic(AO_PANIC_BUFIO);
242 DBG ("idle buffer %d write %d\n", ao_bufio_to_num(bufio), write);
243 bufio->dirty |= write;
244 if (!--bufio->busy) {
245 bufio->seqno = ao_seqno_next();
246 DBG ("not busy, seqno %d\n", bufio->seqno);
252 * Flush a single buffer immediately. Useful
253 * if write order is important
256 ao_bufio_flush_one(uint8_t *buf)
259 ao_bufio_write(ao_buf_to_bufio(buf));
264 * Flush all buffers to storage
272 for (b = 0; b < AO_NUM_BUF; b++)
273 ao_bufio_write(&ao_bufio[b]);
279 ao_bufio_test_read(void)
283 if (ao_cmd_status != ao_cmd_success)
285 if ((buf = ao_bufio_get(ao_cmd_lex_u32))) {
287 for (i = 0; i < 512; i++) {
288 printf (" %02x", buf[i]);
289 if ((i & 0xf) == 0xf)
292 ao_bufio_put(buf, 0);
296 static const struct ao_cmds ao_bufio_cmds[] = {
297 { ao_bufio_test_read, "q\0Test bufio read" },
307 for (b = 0; b < AO_NUM_BUF; b++) {
308 ao_bufio[b].dirty = 0;
309 ao_bufio[b].busy = 0;
310 ao_bufio[b].block = 0xffffffff;
320 ao_cmd_register(&ao_bufio_cmds[0]);