Fixes warning.
[bertos.git] / bertos / io / kblock.h
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2009 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \author Francesco Sacchi <batt@develer.com>
34  *
35  * \brief KBlock interface
36  */
37
38 #ifndef IO_KBLOCK_H
39 #define IO_KBLOCK_H
40
41 #include <cfg/compiler.h>
42 #include <cfg/debug.h>
43 #include <cfg/macros.h>
44
45 /** Type for addressing blocks in the device. */
46 typedef uint32_t block_idx_t;
47
48 // Fwd Declaration
49 struct KBlock;
50
51 /**
52  * \name Prototypes for KBlock access functions.
53  * 
54  * A KBlock user can choose which function subset to implement,
55  * but has to set to NULL unimplemented features.
56  * 
57  *  \{ 
58  */
59 typedef size_t (* kblock_read_t)    (struct KBlock *b, void *buf, size_t offset, size_t size);
60 typedef size_t (* kblock_write_t)   (struct KBlock *b, const void *buf, size_t offset, size_t size);
61 typedef int    (* kblock_load_t)    (struct KBlock *b, block_idx_t index);
62 typedef int    (* kblock_store_t)   (struct KBlock *b, block_idx_t index);
63 typedef void * (* kblock_map_t)     (struct KBlock *b, size_t offset, size_t size);
64 typedef int    (* kblock_unmap_t)   (struct KBlock *b, size_t offset, size_t size);
65 typedef int    (* kblock_error_t)   (struct KBlock *b);
66 typedef int    (* kblock_clearerr_t)(struct KBlock *b);
67 typedef int    (* kblock_close_t)   (struct KBlock *b);
68 /* \} */
69
70 /**
71  * Table of interface functions for a KBlock device.
72  */
73 typedef struct KBlockVTable
74 {
75     kblock_read_t  readBuf;  ///< \sa kblock_readBuf()
76         kblock_write_t writeBuf; ///< \sa kblock_writeBuf()
77         kblock_load_t  load;     ///< \sa kblock_load()
78         kblock_store_t store;    ///< \sa kblock_store()
79
80         kblock_map_t   map;   ///< \sa kblock_map()
81         kblock_unmap_t unmap; ///< \sa kblock_unmap()
82         
83         kblock_error_t    error;    ///< \sa kblock_error()
84         kblock_clearerr_t clearerr; ///< \sa kblock_clearerr()
85         
86         kblock_close_t  close; ///< \sa kblock_close()
87 } KBlockVTable;
88
89
90 /**
91  * KBlock status and error codes.
92  */
93 typedef enum KBlockStatus
94 {
95         /* Status flags */
96         KBS_MAPPED,  ///< Status: The current loaded block from the device is memory mapped.
97         
98         /* Errors */
99         KBS_ERR_ALREADY_MAPPED,    ///< Error: trying to memory map a block already mapped.
100         KBS_ERR_NOT_MAPPED,        ///< Error: trying to memory unmap a block not yet mapped.
101         KBS_ERR_MAP_NOT_AVAILABLE, ///< Error: mapping methods not implemented.
102
103         #define KBS_STATUS_MASK (BV(KBS_MAPPED) | 0 /* Add status flags here */)
104         
105         #define KBS_ERROR_MASK (BV(KBS_ERR_ALREADY_MAPPED) | BV(KBS_ERR_ALREADY_MAPPED) \
106                 | BV(KBS_ERR_MAP_NOT_AVAILABLE) | 0 /* Add error flags here */)
107 }  KBlockStatus;
108
109
110 /**
111  * KBlock private members.
112  * These are the private members of the KBlock class, please do not
113  * access these directly, use the KBlock API.
114  */ 
115 typedef struct KBlockPriv
116 {
117         DB(id_t type);         ///< Used to keep track, at runtime, of the class type.
118         void *pagebuf;         ///< Pointer to a buffer used as page buffer when memory mapping is active. \sa kblock_map(), kblock_unmap()
119         size_t pagebuf_size;   ///< Size of the page buffer used for memory mapping. \sa kblock_map(), kblock_unmap()
120         KBlockStatus flags;    ///< Status and error flags.
121         block_idx_t blk_start; ///< Start block number when the device is trimmed. \sa kblock_trim()
122         DB(size_t map_off);    ///< When mapping is active, this is the mapped data offset inside the block. \sa kblock_map(), kblock_unmap()
123         DB(size_t map_size);   ///< When mapping is active, this is the mapped data size inside the block. \sa kblock_map(), kblock_unmap()
124 } KBlockPriv;
125
126 /**
127  * KBlock: interface for a generic block device.
128  * 
129  * A block device is a device which can only be read/written
130  * with data blocks of constant size: flash memories,
131  * SD cards, hard disks, etc...
132  * 
133  * This interface is designed to adapt to most block devices and 
134  * use peculiar features in order to save CPU time and memory space.
135  * 
136  * You do not have to use this structure directly, specific implementations
137  * will be supplied in the peripheral drivers.
138  */
139 typedef struct KBlock
140 {
141         KBlockPriv priv;         ///< Interface private data, do not use directly.
142         
143         /* Public access members/methods */
144         size_t blk_size;         ///< Block size.
145         block_idx_t blk_cnt;     ///< Number of blocks available in the device.
146         struct KBlockVTable *vt; ///< Virtual table of interface functions.
147 } KBlock;
148
149
150 /**
151  * Add generic memory mapping functionality to a block device.
152  * 
153  * If the device has an hardware page buffer mechanism, the map/unmap
154  * functions are unimplemented.
155  * If you need to use the mapping functions of such device, this function
156  * will add generic software mapping features wrapping the KBlock methods.
157  * 
158  * \param dev the block device.
159  * \param buf the buffer to be used as page buffer for memory mapping functions.
160  * \param size the size of the buffer. This is the maximum size that can be
161  *        memory mapped. If you want to map a full block, a size of at least
162  *        dev->blk_size have to be supplied.
163  * 
164  * \sa kblock_map(), kblock_unmap(), kblock_readBuf(), kblock_writeBuf()
165  */
166 void kblock_addMapping(struct KBlock *dev, void *buf, size_t size);
167
168 /**
169  * Use a subset of the blocks on the device.
170  * 
171  * This function is useful for partitioning a device and use it for
172  * different purposes at the same time.
173  * 
174  * This function will limit the number of blocks used on the device by setting
175  * a start index and a number of blocks to be used counting from that index.
176  * 
177  * The blocks outside this range are no more accessible.
178  * 
179  * Logical block indexes will be mapped to physical indexes inside this new
180  * range automatically. Even following calls to kblock_trim() will use logical
181  * indexes, so, once trimmed, access can only be limited further and never
182  * expanded back.
183  * 
184  * Example:
185  * \code
186  * //...init KBlock device dev
187  * kblock_trim(dev, 200, 1500); // Restrict access to the 200-1700 physical block range.
188  * kblock_load(dev, 0);  // Load the physical block #200.
189  * kblock_trim(dev, 0, 300); // Restrict access to the 200-500 physical block range.
190  * \endcode
191  * 
192  * \param b KBlock device.
193  * \param start The index of the start block for the limiting window in logical addressing units.
194  * \param count The number of blocks to be used.
195  * 
196  */ 
197 INLINE void kblock_trim(struct KBlock *b, block_idx_t start, block_idx_t count)
198 {
199         ASSERT(start + count <= b->blk_cnt);
200         b->priv.blk_start += start;
201         b->blk_cnt = count;
202 }
203
204 /**
205  * Transfer data from the internal page buffer to user memory.
206  * 
207  * This function accesses the internal page buffer of the block device and copy
208  * the data to \a buf. The content is copied from the current cached block.
209  * 
210  * \param b KBlock device.
211  * \param buf User buffer to copy the data to.
212  * \param offset Address offset within the block, from which to copy data.
213  * \param size Size, in bytes, of the data to be copied.
214  * 
215  * \return The number of bytes copied. Can be less than \a size on errors.
216  * 
217  * \sa kblock_writeBuf()
218  */
219 INLINE size_t kblock_readBuf(struct KBlock *b, void *buf, size_t offset, size_t size)
220 {
221         ASSERT(b->vt);
222         ASSERT(b->vt->readBuf);
223         ASSERT(offset + size <= b->blk_size);
224         
225         return b->vt->readBuf(b, buf, offset, size);
226 }
227
228 /**
229  * Write to the page buffer.
230  * 
231  * Copies data from user memory to the device page buffer. The data is written
232  * in the current cached block buffer.
233  * 
234  * \param b KBlock device.
235  * \param buf User buffer to copy the data from.
236  * \param offset Address offset within the block, from which data has to be written.
237  * \param size Size, in bytes, of the data to be written.
238  * 
239  * \return The number of bytes written. Can be less than \a size on errors.
240  * 
241  * \sa kblock_readBuf()
242  */
243 INLINE size_t kblock_writeBuf(struct KBlock *b, const void *buf, size_t offset, size_t size)
244 {
245         ASSERT(b->vt);
246         ASSERT(b->vt->writeBuf);
247         ASSERT(offset + size <= b->blk_size);
248         return b->vt->writeBuf(b, buf, offset, size);
249 }
250
251 /**
252  * Load a block from the device to the page buffer.
253  * 
254  * The block \a index will be loaded in the internal page buffer.
255  * 
256  * \param b KBlock device.
257  * \param index Logical index of the block to be loaded.
258  * 
259  * \return 0 on success, EOF on errors.
260  */
261 INLINE int kblock_load(struct KBlock *b, block_idx_t index)
262 {
263         ASSERT(b->vt);
264         ASSERT(b->vt->load);
265         ASSERT(index < b->blk_cnt);
266         
267         return b->vt->load(b, b->priv.blk_start + index);
268 }
269
270 /**
271  * Store a block from the page buffer to the device.
272  * 
273  * The current content of the page buffer will be flushed to the block \a index.
274  * 
275  * \param b KBlock device.
276  * \param index Logical index of the block to be stored.
277  * 
278  * \return 0 on success, EOF on errors.
279  */
280 INLINE int kblock_store(struct KBlock *b, block_idx_t index)
281 {
282         ASSERT(b->vt);
283         ASSERT(b->vt->store);
284         ASSERT(index < b->blk_cnt);
285         
286         return b->vt->store(b, b->priv.blk_start + index);
287 }
288
289
290 /**
291  * Memory map the current page buffer.
292  * 
293  * To speed up access, instead of using kblock_readBuf() and kblock_writeBuf(),
294  * you can memory map the page buffer and access it directly through the
295  * returned pointer. You can freely access the pointer in any way you
296  * like. Once done, call kblock_unmap() to release the lock on the page_buffer.
297  * 
298  * \note This function may be not available on all drivers, since the page
299  *       buffer can be in the hardware and not directly accessible through memory.
300  *       For this devices you can still add generic software mapping features
301  *       thanks to kblock_addMapping().
302  * 
303  * \note Only one mapping is available at a time, trying to map the page buffer
304  *       again before releasing it is an error.
305  * 
306  * \param b KBlock device.
307  * \param offset Address offset within the page buffer, from which data has to 
308  *               be memory mapped.
309  * \param size Size of the memory to be mapped.
310  * 
311  * \return A pointer to the mapped region of the page buffer or NULL on errors.
312  * 
313  * \sa kblock_addMapping(), kblock_unmap()
314  */
315 INLINE void * kblock_map(struct KBlock *b, size_t offset, size_t size)
316 {
317         ASSERT(b->vt);
318         ASSERT(b->vt->map);
319         
320         if (b->priv.flags & BV(KBS_MAPPED))
321         {
322                 b->priv.flags |= BV(KBS_ERR_ALREADY_MAPPED);
323                 return NULL;
324         }
325         
326         ASSERT(size < b->priv.pagebuf_size);
327         ASSERT(offset + size <= b->blk_size);
328         DB(b->priv.map_off = offset);
329         DB(b->priv.map_size = size);
330
331         void *ret = b->vt->map(b, offset, size);
332         
333         if (ret)
334                 b->priv.flags |= BV(KBS_MAPPED);
335
336         return ret;
337 }
338
339
340 /**
341  * Release the memory map on the page buffer.
342  * 
343  * This function has to be called when memory mapped access has finished.
344  * This is needed because only one mapping is allowed at a time.
345  * The \a offset and \a size passed should be the same passed to 
346  * kblock_map() when the page buffer has been mapped.
347  * 
348  * \note Trying to unmap the page buffer when there is no mapping ongoing is
349  *       an error.
350  * 
351  * \param b KBlock device.
352  * \param offset Address offset within the page buffer, from which data has been
353  *               memory mapped. Must be the same value passed to kblock_map()
354  *               when the memory was mapped.
355  * \param size Size of the memory mapped. Must be the same value passed to
356  *             kblock_map() when the memory was mapped.
357  * 
358  * \return 0 on success, EOF on errors.
359  * 
360  * \sa kblock_addMapping(), kblock_map()
361  */ 
362 INLINE int kblock_unmap(struct KBlock *b, size_t offset, size_t size)
363 {
364         ASSERT(b->vt);
365         ASSERT(b->vt->unmap);
366         
367         if (!(b->priv.flags & BV(KBS_MAPPED)))
368         {
369                 b->priv.flags |= BV(KBS_ERR_NOT_MAPPED);
370                 return EOF;
371         }
372         
373         ASSERT(b->priv.map_off == offset);
374         ASSERT(b->priv.map_size == size);
375         int ret = b->vt->unmap(b, offset, size);
376         
377         if (ret == 0)
378                 b->priv.flags &= ~BV(KBS_MAPPED);
379         return ret;
380 }
381
382 /**
383  * Get the current errors for the device.
384  * 
385  * \note Calling this function will not clear the errors. 
386  * 
387  * \param b KBlock device.
388  * 
389  * \return 0 if no error is present, a driver specific mask of errors otherwise.
390  * 
391  * \sa kblock_clearerr()
392  */
393 INLINE int kblock_error(struct KBlock *b)
394 {
395         ASSERT(b->vt);
396         ASSERT(b->vt->error);
397         /* Automatically mask status flags */
398         return b->vt->error(b) & ~KBS_STATUS_MASK;
399 }
400
401 /**
402  * Clear the errors of the device.
403  * 
404  * \param b KBlock device.
405  * 
406  * \return 0 on success, EOF on errors.
407  * 
408  * \sa kblock_error()
409  */
410 INLINE int kblock_clearerr(struct KBlock *b)
411 {
412         ASSERT(b->vt);
413         ASSERT(b->vt->clearerr);
414         /* Automatically clear error flags */
415         b->priv.flags &= ~KBS_ERROR_MASK;
416         return b->vt->clearerr(b);
417 }
418
419 /**
420  * Close the device.
421  * 
422  * \param b KBlock device.
423  * 
424  * \return 0 on success, EOF on errors.
425  */
426 INLINE int kblock_close(struct KBlock *b)
427 {
428         ASSERT(b->vt);
429         ASSERT(b->vt->close);
430         return b->vt->close(b);
431 }
432
433 void *kblock_unsupportedMap(struct KBlock *b, UNUSED_ARG(size_t, offset), UNUSED_ARG(size_t, size));
434
435 #endif /* IO_KBLOCK_H */