9dd4eeeb314fb117638ee9266087ea9f3a35415a
[openwrt.git] / target / linux / brcm-2.4 / files / arch / mips / bcm947xx / cfe_env.c
1 /*
2  * NVRAM variable manipulation (Linux kernel half)
3  *
4  * Copyright 2001-2003, Broadcom Corporation
5  * All Rights Reserved.
6  * 
7  * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8  * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9  * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10  * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11  *
12  * $Id$
13  */
14
15 #include <linux/config.h>
16 #include <linux/init.h>
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/string.h>
20 #include <asm/io.h>
21 #include <asm/uaccess.h>
22
23 #include <typedefs.h>
24 #include <osl.h>
25 #include <bcmendian.h>
26
27 #define NVRAM_SIZE       (0x1ff0)
28 static char _nvdata[NVRAM_SIZE] __initdata;
29 static char _valuestr[256] __initdata;
30
31 /*
32  * TLV types.  These codes are used in the "type-length-value"
33  * encoding of the items stored in the NVRAM device (flash or EEPROM)
34  *
35  * The layout of the flash/nvram is as follows:
36  *
37  * <type> <length> <data ...> <type> <length> <data ...> <type_end>
38  *
39  * The type code of "ENV_TLV_TYPE_END" marks the end of the list.
40  * The "length" field marks the length of the data section, not
41  * including the type and length fields.
42  *
43  * Environment variables are stored as follows:
44  *
45  * <type_env> <length> <flags> <name> = <value>
46  *
47  * If bit 0 (low bit) is set, the length is an 8-bit value.
48  * If bit 0 (low bit) is clear, the length is a 16-bit value
49  * 
50  * Bit 7 set indicates "user" TLVs.  In this case, bit 0 still
51  * indicates the size of the length field.  
52  *
53  * Flags are from the constants below:
54  *
55  */
56 #define ENV_LENGTH_16BITS       0x00    /* for low bit */
57 #define ENV_LENGTH_8BITS        0x01
58
59 #define ENV_TYPE_USER           0x80
60
61 #define ENV_CODE_SYS(n,l) (((n)<<1)|(l))
62 #define ENV_CODE_USER(n,l) ((((n)<<1)|(l)) | ENV_TYPE_USER)
63
64 /*
65  * The actual TLV types we support
66  */
67
68 #define ENV_TLV_TYPE_END        0x00    
69 #define ENV_TLV_TYPE_ENV        ENV_CODE_SYS(0,ENV_LENGTH_8BITS)
70
71 /*
72  * Environment variable flags 
73  */
74
75 #define ENV_FLG_NORMAL          0x00    /* normal read/write */
76 #define ENV_FLG_BUILTIN         0x01    /* builtin - not stored in flash */
77 #define ENV_FLG_READONLY        0x02    /* read-only - cannot be changed */
78
79 #define ENV_FLG_MASK            0xFF    /* mask of attributes we keep */
80 #define ENV_FLG_ADMIN           0x100   /* lets us internally override permissions */
81
82
83 /*  *********************************************************************
84     *  _nvram_read(buffer,offset,length)
85     *  
86     *  Read data from the NVRAM device
87     *  
88     *  Input parameters: 
89     *      buffer - destination buffer
90     *      offset - offset of data to read
91     *      length - number of bytes to read
92     *      
93     *  Return value:
94     *      number of bytes read, or <0 if error occured
95     ********************************************************************* */
96 static int
97 _nvram_read(unsigned char *nv_buf, unsigned char *buffer, int offset, int length)
98 {
99     int i;
100     if (offset > NVRAM_SIZE)
101         return -1; 
102
103     for ( i = 0; i < length; i++) {
104         buffer[i] = ((volatile unsigned char*)nv_buf)[offset + i];
105     }
106     return length;
107 }
108
109
110 static char*
111 _strnchr(const char *dest,int c,size_t cnt)
112 {
113         while (*dest && (cnt > 0)) {
114         if (*dest == c) return (char *) dest;
115         dest++;
116         cnt--;
117         }
118         return NULL;
119 }
120
121
122
123 /*
124  * Core support API: Externally visible.
125  */
126
127 /*
128  * Get the value of an NVRAM variable
129  * @param       name    name of variable to get
130  * @return      value of variable or NULL if undefined
131  */
132
133 char* 
134 cfe_env_get(unsigned char *nv_buf, char* name)
135 {
136     int size;
137     unsigned char *buffer;
138     unsigned char *ptr;
139     unsigned char *envval;
140     unsigned int reclen;
141     unsigned int rectype;
142     int offset;
143     int flg;
144     
145     size = NVRAM_SIZE;
146     buffer = &_nvdata[0];
147
148     ptr = buffer;
149     offset = 0;
150
151     /* Read the record type and length */
152     if (_nvram_read(nv_buf, ptr,offset,1) != 1) {
153         goto error;
154     }
155     
156     while ((*ptr != ENV_TLV_TYPE_END)  && (size > 1)) {
157
158         /* Adjust pointer for TLV type */
159         rectype = *(ptr);
160         offset++;
161         size--;
162
163         /* 
164          * Read the length.  It can be either 1 or 2 bytes
165          * depending on the code 
166          */
167         if (rectype & ENV_LENGTH_8BITS) {
168             /* Read the record type and length - 8 bits */
169             if (_nvram_read(nv_buf, ptr,offset,1) != 1) {
170                 goto error;
171             }
172             reclen = *(ptr);
173             size--;
174             offset++;
175         }
176         else {
177             /* Read the record type and length - 16 bits, MSB first */
178             if (_nvram_read(nv_buf, ptr,offset,2) != 2) {
179                 goto error;
180             }
181             reclen = (((unsigned int) *(ptr)) << 8) + (unsigned int) *(ptr+1);
182             size -= 2;
183             offset += 2;
184         }
185
186         if (reclen > size)
187             break;      /* should not happen, bad NVRAM */
188
189         switch (rectype) {
190             case ENV_TLV_TYPE_ENV:
191                 /* Read the TLV data */
192                 if (_nvram_read(nv_buf, ptr,offset,reclen) != reclen)
193                     goto error;
194                 flg = *ptr++;
195                 envval = (unsigned char *) _strnchr(ptr,'=',(reclen-1));
196                 if (envval) {
197                     *envval++ = '\0';
198                     memcpy(_valuestr,envval,(reclen-1)-(envval-ptr));
199                     _valuestr[(reclen-1)-(envval-ptr)] = '\0';
200 #if 0                   
201                     printk(KERN_INFO "NVRAM:%s=%s\n", ptr, _valuestr);
202 #endif
203                     if(!strcmp(ptr, name)){
204                         return _valuestr;
205                     }
206                     if((strlen(ptr) > 1) && !strcmp(&ptr[1], name))
207                         return _valuestr;
208                 }
209                 break;
210                 
211             default: 
212                 /* Unknown TLV type, skip it. */
213                 break;
214             }
215
216         /*
217          * Advance to next TLV 
218          */
219                 
220         size -= (int)reclen;
221         offset += reclen;
222
223         /* Read the next record type */
224         ptr = buffer;
225         if (_nvram_read(nv_buf, ptr,offset,1) != 1)
226             goto error;
227         }
228
229 error:
230     return NULL;
231
232 }
233