Abstracted out part of the concept of an SPI device to a generalised NVS
[people/xl0/gpxe.git] / src / core / nvo.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 <string.h>
21 #include <gpxe/dhcp.h>
22 #include <gpxe/nvs.h>
23 #include <gpxe/nvo.h>
24
25 /** @file
26  *
27  * Non-volatile stored options
28  *
29  */
30
31 static size_t nvo_options_len ( struct nvs_options *nvo ) {
32         struct dhcp_option *option;
33         uint8_t sum;
34         unsigned int i;
35         size_t len;
36
37         for ( sum = 0, i = 0 ; i < nvo->nvs->size ; i++ ) {
38                 sum += * ( ( uint8_t * ) ( nvo->options->data + i ) );
39         }
40         if ( sum != 0 ) {
41                 DBG ( "NVO %p has bad checksum %02x; assuming empty\n",
42                       nvo, sum );
43                 return 0;
44         }
45
46         option = nvo->options->data;
47         if ( option->tag == DHCP_PAD ) {
48                 DBG ( "NVO %p has bad start; assuming empty\n", nvo );
49                 return 0;
50         }
51         
52         option = find_dhcp_option ( nvo->options, DHCP_END );
53         if ( ! option ) {
54                 DBG ( "NVO %p has no end tag; assuming empty\n", nvo );
55                 return 0;
56         }
57
58         len = ( ( void * ) option - nvo->options->data + 1 );
59         DBG ( "NVO %p contains %zd bytes of options (maximum %zd)\n",
60               nvo, len, nvo->nvs->size );
61
62         return len;
63 }
64
65 int nvo_register ( struct nvs_options *nvo ) {
66         struct dhcp_option *option;
67         int rc;
68
69         nvo->options = alloc_dhcp_options ( nvo->nvs->size );
70         if ( ! nvo->options ) {
71                 DBG ( "NVO %p could not allocate %zd bytes\n",
72                       nvo, nvo->nvs->size );
73                 rc = -ENOMEM;
74                 goto err;
75         }
76
77         if ( ( rc = nvo->nvs->read ( nvo->nvs, 0, nvo->options->data,
78                                      nvo->nvs->size ) ) != 0 ) {
79                 DBG ( "NVO %p could not read [0,%zd)\n",
80                       nvo, nvo->nvs->size );
81                 goto err;
82         }
83
84         nvo->options->len = nvo->options->max_len;
85         nvo->options->len = nvo_options_len ( nvo );
86         if ( ! nvo->options->len ) {
87                 option = nvo->options->data;
88                 option->tag = DHCP_END;
89                 nvo->options->len = 1;
90         }
91
92         register_dhcp_options ( nvo->options );
93
94         return 0;
95         
96  err:
97         
98         free_dhcp_options ( nvo->options );
99         nvo->options = NULL;
100         return rc;
101 }
102
103 void nvo_unregister ( struct nvs_options *nvo ) {
104         if ( nvo->options ) {
105                 unregister_dhcp_options ( nvo->options );
106                 free_dhcp_options ( nvo->options );
107                 nvo->options = NULL;
108         }
109 }