a566cdfde1480ab0ea551c34cc664a30138710b8
[people/mcb30/gpxe.git] / src / drivers / nvs / nvs.c
1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or 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
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <stdint.h>
20 #include <assert.h>
21 #include <gpxe/nvs.h>
22
23 /** @file
24  *
25  * Non-volatile storage
26  *
27  */
28
29 /**
30  * Read from non-volatile storage device
31  *
32  * @v nvs               NVS device
33  * @v address           Address from which to read
34  * @v data              Data buffer
35  * @v len               Length of data buffer
36  * @ret rc              Return status code
37  */
38 int nvs_read ( struct nvs_device *nvs, unsigned int address,
39                void *data, size_t len ) {
40         size_t frag_len;
41         int rc;
42
43         /* We don't even attempt to handle buffer lengths that aren't
44          * an integral number of words.
45          */
46         assert ( ( len & ( ( 1 << nvs->word_len_log2 ) - 1 ) ) == 0 );
47
48         while ( len ) {
49
50                 /* Calculate space remaining up to next block boundary */
51                 frag_len = ( ( nvs->block_size -
52                                ( address & ( nvs->block_size - 1 ) ) )
53                              << nvs->word_len_log2 );
54
55                 /* Limit to space remaining in buffer */
56                 if ( frag_len > len )
57                         frag_len = len;
58
59                 /* Read this portion of the buffer from the device */
60                 if ( ( rc = nvs->read ( nvs, address, data, frag_len ) ) != 0 )
61                         return rc;
62
63                 /* Update parameters */
64                 data += frag_len;
65                 address += ( frag_len >> nvs->word_len_log2 );
66                 len -= frag_len;
67         }
68
69         return 0;
70 }
71
72 /**
73  * Write to non-volatile storage device
74  *
75  * @v nvs               NVS device
76  * @v address           Address to which to write
77  * @v data              Data buffer
78  * @v len               Length of data buffer
79  * @ret rc              Return status code
80  */
81 int nvs_write ( struct nvs_device *nvs, unsigned int address,
82                 const void *data, size_t len ) {
83         size_t frag_len;
84         int rc;
85
86         /* We don't even attempt to handle buffer lengths that aren't
87          * an integral number of words.
88          */
89         assert ( ( len & ( ( 1 << nvs->word_len_log2 ) - 1 ) ) == 0 );
90
91         while ( len ) {
92
93                 /* Calculate space remaining up to next block boundary */
94                 frag_len = ( ( nvs->block_size -
95                                ( address & ( nvs->block_size - 1 ) ) )
96                              << nvs->word_len_log2 );
97
98                 /* Limit to space remaining in buffer */
99                 if ( frag_len > len )
100                         frag_len = len;
101
102                 /* Read this portion of the buffer from the device */
103                 if ( ( rc = nvs->write ( nvs, address, data, frag_len ) ) != 0)
104                         return rc;
105
106                 /* Update parameters */
107                 data += frag_len;
108                 address += ( frag_len >> nvs->word_len_log2 );
109                 len -= frag_len;
110         }
111
112         return 0;
113 }