2 * NVRAM variable manipulation (common)
4 * Copyright 2004, Broadcom Corporation
5 * Copyright 2009, OpenWrt.org
8 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
9 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
10 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
11 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
18 printf("%s(%i) in %s()\n", \
19 __FILE__, __LINE__, __FUNCTION__)
22 * -- Helper functions --
26 static uint32_t hash(const char *s)
31 hash = 31 * hash + *s++;
36 /* Free all tuples. */
37 static void _nvram_free(nvram_handle_t *h)
40 nvram_tuple_t *t, *next;
43 for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) {
44 for (t = h->nvram_hash[i]; t; t = next) {
48 h->nvram_hash[i] = NULL;
52 for (t = h->nvram_dead; t; t = next) {
60 /* (Re)allocate NVRAM tuples. */
61 static nvram_tuple_t * _nvram_realloc( nvram_handle_t *h, nvram_tuple_t *t,
62 const char *name, const char *value )
64 if ((strlen(value) + 1) > NVRAM_SPACE)
68 if (!(t = malloc(sizeof(nvram_tuple_t) + strlen(name) + 1)))
72 t->name = (char *) &t[1];
73 strcpy(t->name, name);
79 if (!t->value || strcmp(t->value, value))
81 if(!(t->value = (char *) realloc(t->value, strlen(value)+1)))
84 strcpy(t->value, value);
85 t->value[strlen(value)] = '\0';
91 /* (Re)initialize the hash table. */
92 static int _nvram_rehash(nvram_handle_t *h)
94 nvram_header_t *header = (nvram_header_t *) &h->mmap[NVRAM_SPACE];
95 char buf[] = "0xXXXXXXXX", *name, *value, *end, *eq;
97 /* (Re)initialize hash table */
100 /* Parse and set "name=value\0 ... \0\0" */
101 name = (char *) &header[1];
103 end = (char *) header + NVRAM_SPACE - 2;
104 end[0] = end[1] = '\0';
106 for (; *name; name = value + strlen(value) + 1) {
107 if (!(eq = strchr(name, '=')))
111 nvram_set(h, name, value);
115 /* Set special SDRAM parameters */
116 if (!nvram_get(h, "sdram_init")) {
117 sprintf(buf, "0x%04X", (uint16_t)(header->crc_ver_init >> 16));
118 nvram_set(h, "sdram_init", buf);
120 if (!nvram_get(h, "sdram_config")) {
121 sprintf(buf, "0x%04X", (uint16_t)(header->config_refresh & 0xffff));
122 nvram_set(h, "sdram_config", buf);
124 if (!nvram_get(h, "sdram_refresh")) {
125 sprintf(buf, "0x%04X",
126 (uint16_t)((header->config_refresh >> 16) & 0xffff));
127 nvram_set(h, "sdram_refresh", buf);
129 if (!nvram_get(h, "sdram_ncdl")) {
130 sprintf(buf, "0x%08X", header->config_ncdl);
131 nvram_set(h, "sdram_ncdl", buf);
139 * -- Public functions --
142 /* Get the value of an NVRAM variable. */
143 char * nvram_get(nvram_handle_t *h, const char *name)
153 i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash);
155 /* Find the associated tuple in the hash table */
156 for (t = h->nvram_hash[i]; t && strcmp(t->name, name); t = t->next);
158 value = t ? t->value : NULL;
163 /* Set the value of an NVRAM variable. */
164 int nvram_set(nvram_handle_t *h, const char *name, const char *value)
167 nvram_tuple_t *t, *u, **prev;
170 i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash);
172 /* Find the associated tuple in the hash table */
173 for (prev = &h->nvram_hash[i], t = *prev;
174 t && strcmp(t->name, name); prev = &t->next, t = *prev);
176 /* (Re)allocate tuple */
177 if (!(u = _nvram_realloc(h, t, name, value)))
178 return -12; /* -ENOMEM */
180 /* Value reallocated */
184 /* Move old tuple to the dead table */
187 t->next = h->nvram_dead;
191 /* Add new tuple to the hash table */
192 u->next = h->nvram_hash[i];
193 h->nvram_hash[i] = u;
198 /* Unset the value of an NVRAM variable. */
199 int nvram_unset(nvram_handle_t *h, const char *name)
202 nvram_tuple_t *t, **prev;
208 i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash);
210 /* Find the associated tuple in the hash table */
211 for (prev = &h->nvram_hash[i], t = *prev;
212 t && strcmp(t->name, name); prev = &t->next, t = *prev);
214 /* Move it to the dead table */
217 t->next = h->nvram_dead;
224 /* Get all NVRAM variables. */
225 nvram_tuple_t * nvram_getall(nvram_handle_t *h)
228 nvram_tuple_t *t, *l, *x;
232 for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) {
233 for (t = h->nvram_hash[i]; t; t = t->next) {
234 if( (x = (nvram_tuple_t *) malloc(sizeof(nvram_tuple_t))) != NULL )
251 /* Regenerate NVRAM. */
252 int nvram_commit(nvram_handle_t *h)
254 nvram_header_t *header = (nvram_header_t *) &h->mmap[NVRAM_SPACE];
255 char *init, *config, *refresh, *ncdl;
262 /* Regenerate header */
263 header->magic = NVRAM_MAGIC;
264 header->crc_ver_init = (NVRAM_VERSION << 8);
265 if (!(init = nvram_get(h, "sdram_init")) ||
266 !(config = nvram_get(h, "sdram_config")) ||
267 !(refresh = nvram_get(h, "sdram_refresh")) ||
268 !(ncdl = nvram_get(h, "sdram_ncdl"))) {
269 header->crc_ver_init |= SDRAM_INIT << 16;
270 header->config_refresh = SDRAM_CONFIG;
271 header->config_refresh |= SDRAM_REFRESH << 16;
272 header->config_ncdl = 0;
274 header->crc_ver_init |= (strtoul(init, NULL, 0) & 0xffff) << 16;
275 header->config_refresh = strtoul(config, NULL, 0) & 0xffff;
276 header->config_refresh |= (strtoul(refresh, NULL, 0) & 0xffff) << 16;
277 header->config_ncdl = strtoul(ncdl, NULL, 0);
280 /* Clear data area */
281 ptr = (char *) header + sizeof(nvram_header_t);
282 memset(ptr, 0xFF, NVRAM_SPACE - sizeof(nvram_header_t));
284 /* Leave space for a double NUL at the end */
285 end = (char *) header + NVRAM_SPACE - 2;
287 /* Write out all tuples */
288 for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) {
289 for (t = h->nvram_hash[i]; t; t = t->next) {
290 if ((ptr + strlen(t->name) + 1 + strlen(t->value) + 1) > end)
292 ptr += sprintf(ptr, "%s=%s", t->name, t->value) + 1;
296 /* End with a double NUL */
301 header->len = NVRAM_ROUNDUP(ptr - (char *) header, 4);
303 /* Little-endian CRC8 over the last 11 bytes of the header */
304 tmp.crc_ver_init = htonl(header->crc_ver_init);
305 tmp.config_refresh = htonl(header->config_refresh);
306 tmp.config_ncdl = htonl(header->config_ncdl);
307 crc = hndcrc8((unsigned char *) &tmp + 9, sizeof(nvram_header_t) - 9, 0xff);
309 /* Continue CRC8 over data bytes */
310 crc = hndcrc8((unsigned char *) &header[1],
311 header->len - sizeof(nvram_header_t), crc);
314 header->crc_ver_init |= crc;
317 msync(h->mmap, h->length, MS_SYNC);
320 /* Reinitialize hash table */
321 return _nvram_rehash(h);
324 /* Open NVRAM and obtain a handle. */
325 nvram_handle_t * nvram_open(const char *file, int rdonly)
329 nvram_header_t *header;
331 if( (fd = open(file, O_RDWR)) > -1 )
333 char *mmap_area = (char *) mmap(
334 NULL, 0x10000, PROT_READ | PROT_WRITE,
335 ( rdonly == NVRAM_RO ) ? MAP_PRIVATE : MAP_SHARED, fd, 0);
337 if( mmap_area != MAP_FAILED )
339 memset(mmap_area, 0xFF, NVRAM_SPACE);
341 if((h = (nvram_handle_t *) malloc(sizeof(nvram_handle_t))) != NULL)
343 memset(h, 0, sizeof(nvram_handle_t));
349 header = (nvram_header_t *) &h->mmap[NVRAM_SPACE];
351 if( header->magic == NVRAM_MAGIC )
358 munmap(h->mmap, h->length);
368 /* Close NVRAM and free memory. */
369 int nvram_close(nvram_handle_t *h)
372 munmap(h->mmap, h->length);
379 /* Determine NVRAM device node. */
380 const char * nvram_find_mtd(void)
382 //return "./samples/nvram.1";
389 // "/dev/mtdblock/" + ( 0 < x < 99 ) + "ro" + \0 = 19
390 if( (path = (char *) malloc(19)) == NULL )
393 if ((fp = fopen("/proc/mtd", "r"))) {
394 while (fgets(dev, sizeof(dev), fp)) {
395 if (sscanf(dev, "mtd%d:", &i) && strstr(dev, "nvram")) {
396 snprintf(path, 19, "/dev/mtdblock/%d", i);
402 return (const char *) path;
405 /* Check NVRAM staging file. */
406 const char * nvram_find_staging(void)
410 if( (stat(NVRAM_STAGING, &s) > -1) && (s.st_mode & S_IFREG) )
412 return NVRAM_STAGING;
418 /* Copy NVRAM contents to staging file. */
419 int nvram_to_staging(void)
421 int fdmtd, fdstg, stat;
427 if( (mtd = nvram_find_mtd()) != NULL )
429 if( (fdmtd = open(mtd, O_RDONLY)) > -1 )
431 if( read(fdmtd, buf, sizeof(buf)) == sizeof(buf) )
433 if((fdstg = open(NVRAM_STAGING, O_WRONLY | O_CREAT, 0600)) > -1)
435 write(fdstg, buf, sizeof(buf));
450 /* Copy staging file to NVRAM device. */
451 int staging_to_nvram(void)
453 int fdmtd, fdstg, stat;
459 if( (mtd = nvram_find_mtd()) != NULL )
461 if( (fdstg = open(NVRAM_STAGING, O_RDONLY)) > -1 )
463 if( read(fdstg, buf, sizeof(buf)) == sizeof(buf) )
465 if( (fdmtd = open(mtd, O_WRONLY | O_SYNC)) > -1 )
467 write(fdmtd, buf, sizeof(buf));
477 stat = unlink(NVRAM_STAGING) ? 1 : 0;