contrib: add a userspace port of the Broadcom NVRAM kernel api, allows NVRAM manipula...
authorJo-Philipp Wich <jow@openwrt.org>
Tue, 21 Apr 2009 21:59:59 +0000 (21:59 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Tue, 21 Apr 2009 21:59:59 +0000 (21:59 +0000)
contrib/userspace-nvram/Makefile [new file with mode: 0644]
contrib/userspace-nvram/cli.c [new file with mode: 0644]
contrib/userspace-nvram/crc.c [new file with mode: 0644]
contrib/userspace-nvram/nvram.c [new file with mode: 0644]
contrib/userspace-nvram/nvram.h [new file with mode: 0644]
contrib/userspace-nvram/sdinitvals.h [new file with mode: 0644]

diff --git a/contrib/userspace-nvram/Makefile b/contrib/userspace-nvram/Makefile
new file mode 100644 (file)
index 0000000..b0e4471
--- /dev/null
@@ -0,0 +1,39 @@
+CC      = gcc
+LN      = ln
+CFLAGS  = -Wall -g
+LDFLAGS =
+
+LIB_VERMAJOR = 0
+LIB_VERMINOR = 1
+LIB_FILENAME = libnvram.so
+
+LIB_CFLAGS  = $(CFLAGS) -shared -fPIC
+LIB_LDFLAGS = $(LDFLAGS) -Wl,-soname,$(LIB_FILENAME).$(LIB_VERMAJOR).$(LIB_VERMINOR)
+
+CLI_CFLAGS  = $(CFLAGS)
+CLI_LDFLAGS = $(LDFLAGS) -lc -L. -lnvram
+
+CLI_OBJ = cli.o
+LIB_OBJ = crc.o nvram.o
+
+all: cli libnvram
+
+cli: libnvram
+       $(CC) $(CLI_CFLAGS) -c -o cli.o cli.c
+       $(CC) -o nvram $(CLI_OBJ) $(CLI_LDFLAGS)
+
+cli.o: cli.c
+       $(CC) $(CLI_CFLAGS) -c -o $@ $<
+
+libnvram:
+       $(CC) $(LIB_CFLAGS) -c -o crc.o crc.c
+       $(CC) $(LIB_CFLAGS) -c -o nvram.o nvram.c
+       $(CC) $(LIB_CFLAGS) $(LIB_LDFLAGS) \
+               -o $(LIB_FILENAME).$(LIB_VERMAJOR).$(LIB_VERMINOR) $(LIB_OBJ)
+       $(LN) -s $(LIB_FILENAME).$(LIB_VERMAJOR).$(LIB_VERMINOR) \
+               $(LIB_FILENAME).$(LIB_VERMAJOR)
+       $(LN) -s $(LIB_FILENAME).$(LIB_VERMAJOR).$(LIB_VERMINOR) \
+               $(LIB_FILENAME)
+
+clean:
+       rm -f nvram $(LIB_FILENAME)* *.o
diff --git a/contrib/userspace-nvram/cli.c b/contrib/userspace-nvram/cli.c
new file mode 100644 (file)
index 0000000..3a07199
--- /dev/null
@@ -0,0 +1,154 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+#include "nvram.h"
+
+
+static nvram_handle_t * nvram_open_rdonly(void)
+{
+       const char *file = nvram_find_staging();
+
+       if( file == NULL )
+               file = nvram_find_mtd();
+
+       if( file != NULL )
+               return nvram_open(file, NVRAM_RO);
+
+       return NULL;
+}
+
+static nvram_handle_t * nvram_open_staging(void)
+{
+       if( nvram_find_staging() != NULL || nvram_to_staging() == 0 )
+               return nvram_open(NVRAM_STAGING, NVRAM_RW);
+
+       return NULL;
+}
+
+static int do_show(nvram_handle_t *nvram)
+{
+       nvram_tuple_t *t;
+       int stat = 1;
+
+       if( (t = nvram_getall(nvram)) != NULL )
+       {
+               while( t )
+               {
+                       printf("%s=%s\n", t->name, t->value);
+                       t = t->next;
+               }
+
+               stat = 0;
+       }
+
+       return stat;
+}
+
+static int do_get(nvram_handle_t *nvram, const char *var)
+{
+       const char *val;
+       int stat = 1;
+
+       if( (val = nvram_get(nvram, var)) != NULL )
+       {
+               printf("%s\n", val);
+               stat = 0;
+       }
+
+       return stat;
+}
+
+static int do_unset(nvram_handle_t *nvram, const char *var)
+{
+       return nvram_unset(nvram, var);
+}
+
+static int do_set(nvram_handle_t *nvram, const char *pair)
+{
+       char *val = strstr(pair, "=");
+       char var[strlen(pair)];
+       int stat = 1;
+
+       if( val != NULL )
+       {
+               memset(var, 0, sizeof(var));
+               strncpy(var, pair, (int)(val-pair));
+               stat = nvram_set(nvram, var, (char *)(val + 1));
+       }
+
+       return stat;
+}
+
+
+int main( int argc, const char *argv[] )
+{
+       nvram_handle_t *nvram;
+       int commit = 0;
+       int write = 0;
+       int stat = 1;
+       int i;
+
+       /* Ugly... iterate over arguments to see whether we can expect a write */
+       for( i = 1; i < argc; i++ )
+               if( ( !strcmp(argv[i], "set")   && ++i < argc ) ||
+                       ( !strcmp(argv[i], "unset") && ++i < argc ) ||
+                       !strcmp(argv[i], "commit") )
+               {
+                       write = 1;
+                       break;
+               }
+
+
+       if( (nvram = write ? nvram_open_staging() : nvram_open_rdonly()) != NULL )
+       {
+               for( i = 1; i < argc; i++ )
+               {
+                       if( !strcmp(argv[i], "show") )
+                       {
+                               stat = do_show(nvram);
+                       }
+                       else if( !strcmp(argv[i], "get") && ++i < argc )
+                       {
+                               stat = do_get(nvram, argv[i]);
+                       }
+                       else if( !strcmp(argv[i], "unset") && ++i < argc )
+                       {
+                               stat = do_unset(nvram, argv[i]);
+                       }
+                       else if( !strcmp(argv[i], "set") && ++i < argc )
+                       {
+                               stat = do_set(nvram, argv[i]);
+                       }
+                       else if( !strcmp(argv[i], "commit") )
+                       {
+                               commit = 1;
+                       }
+                       else
+                       {
+                               fprintf(stderr,
+                                       "Usage:\n"
+                                       "       nvram show\n"
+                                       "       nvram get variable\n"
+                                       "       nvram set variable=value [set ...]\n"
+                                       "       nvram unset variable [unset ...]\n"
+                                       "       nvram commit\n"
+                               );
+
+                               return 1;
+                       }
+               }
+
+               if( write )
+                       stat = nvram_commit(nvram);
+
+               nvram_close(nvram);
+
+               if( commit )
+                       stat = staging_to_nvram();
+       }
+
+       return stat;
+}
diff --git a/contrib/userspace-nvram/crc.c b/contrib/userspace-nvram/crc.c
new file mode 100644 (file)
index 0000000..22a3665
--- /dev/null
@@ -0,0 +1,69 @@
+#include "nvram.h"
+
+/*******************************************************************************
+ * crc8
+ *
+ * Computes a crc8 over the input data using the polynomial:
+ *
+ *       x^8 + x^7 +x^6 + x^4 + x^2 + 1
+ *
+ * The caller provides the initial value (either CRC8_INIT_VALUE
+ * or the previous returned value) to allow for processing of
+ * discontiguous blocks of data.  When generating the CRC the
+ * caller is responsible for complementing the final return value
+ * and inserting it into the byte stream.  When checking, a final
+ * return value of CRC8_GOOD_VALUE indicates a valid CRC.
+ *
+ * Reference: Dallas Semiconductor Application Note 27
+ *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
+ *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
+ *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
+ *
+ * ****************************************************************************
+ */
+
+static const uint8_t crc8_table[256] = {
+       0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
+       0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
+       0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
+       0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
+       0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
+       0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
+       0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
+       0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
+       0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
+       0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
+       0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
+       0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
+       0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
+       0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
+       0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
+       0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
+       0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
+       0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
+       0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
+       0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
+       0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
+       0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
+       0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
+       0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
+       0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
+       0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
+       0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
+       0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
+       0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
+       0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
+       0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
+       0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
+};
+
+uint8_t hndcrc8 (
+       uint8_t * pdata,  /* pointer to array of data to process */
+       uint32_t nbytes,  /* number of input data bytes to process */
+       uint8_t crc       /* either CRC8_INIT_VALUE or previous return value */
+) {
+       while (nbytes-- > 0)
+               crc = crc8_table[(crc ^ *pdata++) & 0xff];
+
+       return crc;
+}
diff --git a/contrib/userspace-nvram/nvram.c b/contrib/userspace-nvram/nvram.c
new file mode 100644 (file)
index 0000000..a2ded14
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+ * NVRAM variable manipulation (common)
+ *
+ * Copyright 2004, Broadcom Corporation
+ * Copyright 2009, OpenWrt.org
+ * All Rights Reserved.
+ *
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ */
+
+#include "nvram.h"
+
+#define TRACE() \
+       printf("%s(%i) in %s()\n", \
+               __FILE__, __LINE__, __FUNCTION__)
+
+/*
+ * -- Helper functions --
+ */
+
+/* String hash */
+static uint32_t hash(const char *s)
+{
+       uint32_t hash = 0;
+
+       while (*s)
+               hash = 31 * hash + *s++;
+
+       return hash;
+}
+
+/* Free all tuples. */
+static void _nvram_free(nvram_handle_t *h)
+{
+       uint32_t i;
+       nvram_tuple_t *t, *next;
+
+       /* Free hash table */
+       for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) {
+               for (t = h->nvram_hash[i]; t; t = next) {
+                       next = t->next;
+                       free(t);
+               }
+               h->nvram_hash[i] = NULL;
+       }
+
+       /* Free dead table */
+       for (t = h->nvram_dead; t; t = next) {
+               next = t->next;
+               free(t);
+       }
+
+       h->nvram_dead = NULL;
+}
+
+/* (Re)allocate NVRAM tuples. */
+static nvram_tuple_t * _nvram_realloc( nvram_handle_t *h, nvram_tuple_t *t,
+       const char *name, const char *value )
+{
+       if ((strlen(value) + 1) > NVRAM_SPACE)
+               return NULL;
+
+       if (!t) {
+               if (!(t = malloc(sizeof(nvram_tuple_t) + strlen(name) + 1)))
+                       return NULL;
+
+               /* Copy name */
+               t->name = (char *) &t[1];
+               strcpy(t->name, name);
+
+               t->value = NULL;
+       }
+
+       /* Copy value */
+       if (!t->value || strcmp(t->value, value))
+       {
+               if(!(t->value = (char *) realloc(t->value, strlen(value)+1)))
+                       return NULL;
+
+               strcpy(t->value, value);
+               t->value[strlen(value)] = '\0';
+       }
+
+       return t;
+}
+
+/* (Re)initialize the hash table. */
+static int _nvram_rehash(nvram_handle_t *h)
+{
+       nvram_header_t *header = (nvram_header_t *) &h->mmap[NVRAM_SPACE];
+       char buf[] = "0xXXXXXXXX", *name, *value, *end, *eq;
+
+       /* (Re)initialize hash table */
+       _nvram_free(h);
+
+       /* Parse and set "name=value\0 ... \0\0" */
+       name = (char *) &header[1];
+       /*
+       end = (char *) header + NVRAM_SPACE - 2;
+       end[0] = end[1] = '\0';
+       */
+       for (; *name; name = value + strlen(value) + 1) {
+               if (!(eq = strchr(name, '=')))
+                       break;
+               *eq = '\0';
+               value = eq + 1;
+               nvram_set(h, name, value);
+               *eq = '=';
+       }
+
+       /* Set special SDRAM parameters */
+       if (!nvram_get(h, "sdram_init")) {
+               sprintf(buf, "0x%04X", (uint16_t)(header->crc_ver_init >> 16));
+               nvram_set(h, "sdram_init", buf);
+       }
+       if (!nvram_get(h, "sdram_config")) {
+               sprintf(buf, "0x%04X", (uint16_t)(header->config_refresh & 0xffff));
+               nvram_set(h, "sdram_config", buf);
+       }
+       if (!nvram_get(h, "sdram_refresh")) {
+               sprintf(buf, "0x%04X",
+                       (uint16_t)((header->config_refresh >> 16) & 0xffff));
+               nvram_set(h, "sdram_refresh", buf);
+       }
+       if (!nvram_get(h, "sdram_ncdl")) {
+               sprintf(buf, "0x%08X", header->config_ncdl);
+               nvram_set(h, "sdram_ncdl", buf);
+       }
+
+       return 0;
+}
+
+
+/*
+ * -- Public functions --
+ */
+
+/* Get the value of an NVRAM variable. */
+char * nvram_get(nvram_handle_t *h, const char *name)
+{
+       uint32_t i;
+       nvram_tuple_t *t;
+       char *value;
+
+       if (!name)
+               return NULL;
+
+       /* Hash the name */
+       i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash);
+
+       /* Find the associated tuple in the hash table */
+       for (t = h->nvram_hash[i]; t && strcmp(t->name, name); t = t->next);
+
+       value = t ? t->value : NULL;
+
+       return value;
+}
+
+/* Set the value of an NVRAM variable. */
+int nvram_set(nvram_handle_t *h, const char *name, const char *value)
+{
+       uint32_t i;
+       nvram_tuple_t *t, *u, **prev;
+
+       /* Hash the name */
+       i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash);
+
+       /* Find the associated tuple in the hash table */
+       for (prev = &h->nvram_hash[i], t = *prev;
+                t && strcmp(t->name, name); prev = &t->next, t = *prev);
+
+       /* (Re)allocate tuple */
+       if (!(u = _nvram_realloc(h, t, name, value)))
+               return -12; /* -ENOMEM */
+
+       /* Value reallocated */
+       if (t && t == u)
+               return 0;
+
+       /* Move old tuple to the dead table */
+       if (t) {
+               *prev = t->next;
+               t->next = h->nvram_dead;
+               h->nvram_dead = t;
+       }
+
+       /* Add new tuple to the hash table */
+       u->next = h->nvram_hash[i];
+       h->nvram_hash[i] = u;
+
+       return 0;
+}
+
+/* Unset the value of an NVRAM variable. */
+int nvram_unset(nvram_handle_t *h, const char *name)
+{
+       uint32_t i;
+       nvram_tuple_t *t, **prev;
+
+       if (!name)
+               return 0;
+
+       /* Hash the name */
+       i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash);
+
+       /* Find the associated tuple in the hash table */
+       for (prev = &h->nvram_hash[i], t = *prev;
+                t && strcmp(t->name, name); prev = &t->next, t = *prev);
+
+       /* Move it to the dead table */
+       if (t) {
+               *prev = t->next;
+               t->next = h->nvram_dead;
+               h->nvram_dead = t;
+       }
+
+       return 0;
+}
+
+/* Get all NVRAM variables. */
+nvram_tuple_t * nvram_getall(nvram_handle_t *h)
+{
+       int i;
+       nvram_tuple_t *t, *l, *x;
+
+       l = NULL;
+
+       for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) {
+               for (t = h->nvram_hash[i]; t; t = t->next) {
+                       if( (x = (nvram_tuple_t *) malloc(sizeof(nvram_tuple_t))) != NULL )
+                       {
+                               x->name  = t->name;
+                               x->value = t->value;
+                               x->next  = l;
+                               l = x;
+                       }
+                       else
+                       {
+                               break;
+                       }
+               }
+       }
+
+       return l;
+}
+
+/* Regenerate NVRAM. */
+int nvram_commit(nvram_handle_t *h)
+{
+       nvram_header_t *header = (nvram_header_t *) &h->mmap[NVRAM_SPACE];
+       char *init, *config, *refresh, *ncdl;
+       char *ptr, *end;
+       int i;
+       nvram_tuple_t *t;
+       nvram_header_t tmp;
+       uint8_t crc;
+
+       /* Regenerate header */
+       header->magic = NVRAM_MAGIC;
+       header->crc_ver_init = (NVRAM_VERSION << 8);
+       if (!(init = nvram_get(h, "sdram_init")) ||
+               !(config = nvram_get(h, "sdram_config")) ||
+               !(refresh = nvram_get(h, "sdram_refresh")) ||
+               !(ncdl = nvram_get(h, "sdram_ncdl"))) {
+               header->crc_ver_init |= SDRAM_INIT << 16;
+               header->config_refresh = SDRAM_CONFIG;
+               header->config_refresh |= SDRAM_REFRESH << 16;
+               header->config_ncdl = 0;
+       } else {
+               header->crc_ver_init |= (strtoul(init, NULL, 0) & 0xffff) << 16;
+               header->config_refresh = strtoul(config, NULL, 0) & 0xffff;
+               header->config_refresh |= (strtoul(refresh, NULL, 0) & 0xffff) << 16;
+               header->config_ncdl = strtoul(ncdl, NULL, 0);
+       }
+
+       /* Clear data area */
+       ptr = (char *) header + sizeof(nvram_header_t);
+       memset(ptr, 0xFF, NVRAM_SPACE - sizeof(nvram_header_t));
+
+       /* Leave space for a double NUL at the end */
+       end = (char *) header + NVRAM_SPACE - 2;
+
+       /* Write out all tuples */
+       for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) {
+               for (t = h->nvram_hash[i]; t; t = t->next) {
+                       if ((ptr + strlen(t->name) + 1 + strlen(t->value) + 1) > end)
+                               break;
+                       ptr += sprintf(ptr, "%s=%s", t->name, t->value) + 1;
+               }
+       }
+
+       /* End with a double NUL */
+       *ptr = '\0';
+       ptr += 2;
+
+       /* Set new length */
+       header->len = NVRAM_ROUNDUP(ptr - (char *) header, 4);
+
+       /* Little-endian CRC8 over the last 11 bytes of the header */
+       tmp.crc_ver_init = htonl(header->crc_ver_init);
+       tmp.config_refresh = htonl(header->config_refresh);
+       tmp.config_ncdl = htonl(header->config_ncdl);
+       crc = hndcrc8((unsigned char *) &tmp + 9, sizeof(nvram_header_t) - 9, 0xff);
+
+       /* Continue CRC8 over data bytes */
+       crc = hndcrc8((unsigned char *) &header[1],
+               header->len - sizeof(nvram_header_t), crc);
+
+       /* Set new CRC8 */
+       header->crc_ver_init |= crc;
+
+       /* Write out */
+       msync(h->mmap, h->length, MS_SYNC);
+       fsync(h->fd);
+
+       /* Reinitialize hash table */
+       return _nvram_rehash(h);
+}
+
+/* Open NVRAM and obtain a handle. */
+nvram_handle_t * nvram_open(const char *file, int rdonly)
+{
+       int fd;
+       nvram_handle_t *h;
+       nvram_header_t *header;
+
+       if( (fd = open(file, O_RDWR)) > -1 )
+       {
+               char *mmap_area = (char *) mmap(
+                       NULL, 0x10000, PROT_READ | PROT_WRITE,
+                       ( rdonly == NVRAM_RO ) ? MAP_PRIVATE : MAP_SHARED, fd, 0);
+
+               if( mmap_area != MAP_FAILED )
+               {
+                       memset(mmap_area, 0xFF, NVRAM_SPACE);
+
+                       if((h = (nvram_handle_t *) malloc(sizeof(nvram_handle_t))) != NULL)
+                       {
+                               memset(h, 0, sizeof(nvram_handle_t));
+
+                               h->fd     = fd;
+                               h->mmap   = mmap_area;
+                               h->length = 0x10000;
+
+                               header = (nvram_header_t *) &h->mmap[NVRAM_SPACE];
+
+                               if( header->magic == NVRAM_MAGIC )
+                               {
+                                       _nvram_rehash(h);
+                                       return h;
+                               }
+                               else
+                               {
+                                       munmap(h->mmap, h->length);
+                                       free(h);
+                               }
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+/* Close NVRAM and free memory. */
+int nvram_close(nvram_handle_t *h)
+{
+       _nvram_free(h);
+       munmap(h->mmap, h->length);
+       close(h->fd);
+       free(h);
+
+       return 0;
+}
+
+/* Determine NVRAM device node. */
+const char * nvram_find_mtd(void)
+{
+       //return "./samples/nvram.1";
+
+       FILE *fp;
+       int i;
+       char dev[PATH_MAX];
+       char *path;
+
+       // "/dev/mtdblock/" + ( 0 < x < 99 ) + "ro" + \0 = 19
+       if( (path = (char *) malloc(19)) == NULL )
+               return NULL;
+
+       if ((fp = fopen("/proc/mtd", "r"))) {
+               while (fgets(dev, sizeof(dev), fp)) {
+                       if (sscanf(dev, "mtd%d:", &i) && strstr(dev, "nvram")) {
+                               snprintf(path, 19, "/dev/mtdblock/%d", i);
+                       }
+               }
+               fclose(fp);
+       }
+
+       return (const char *) path;
+}
+
+/* Check NVRAM staging file. */
+const char * nvram_find_staging(void)
+{
+       struct stat s;
+
+       if( (stat(NVRAM_STAGING, &s) > -1) && (s.st_mode & S_IFREG) )
+       {
+               return NVRAM_STAGING;
+       }
+
+       return NULL;
+}
+
+/* Copy NVRAM contents to staging file. */
+int nvram_to_staging(void)
+{
+       int fdmtd, fdstg, stat;
+       const char *mtd;
+       char buf[0x10000];
+
+       stat = -1;
+
+       if( (mtd = nvram_find_mtd()) != NULL )
+       {
+               if( (fdmtd = open(mtd, O_RDONLY)) > -1 )
+               {
+                       if( read(fdmtd, buf, sizeof(buf)) == sizeof(buf) )
+                       {
+                               if((fdstg = open(NVRAM_STAGING, O_WRONLY | O_CREAT, 0600)) > -1)
+                               {
+                                       write(fdstg, buf, sizeof(buf));
+                                       fsync(fdstg);
+                                       close(fdstg);
+
+                                       stat = 0;
+                               }
+                       }
+
+                       close(fdmtd);
+               }
+       }
+
+       return stat;
+}
+
+/* Copy staging file to NVRAM device. */
+int staging_to_nvram(void)
+{
+       int fdmtd, fdstg, stat;
+       const char *mtd;
+       char buf[0x10000];
+
+       stat = -1;
+
+       if( (mtd = nvram_find_mtd()) != NULL )
+       {
+               if( (fdstg = open(NVRAM_STAGING, O_RDONLY)) > -1 )
+               {
+                       if( read(fdstg, buf, sizeof(buf)) == sizeof(buf) )
+                       {
+                               if( (fdmtd = open(mtd, O_WRONLY | O_SYNC)) > -1 )
+                               {
+                                       write(fdmtd, buf, sizeof(buf));
+                                       fsync(fdmtd);
+                                       close(fdmtd);
+                                       stat = 0;
+                               }
+                       }
+
+                       close(fdstg);
+
+                       if( !stat )
+                               stat = unlink(NVRAM_STAGING) ? 1 : 0;
+               }
+       }
+
+       return stat;
+}
diff --git a/contrib/userspace-nvram/nvram.h b/contrib/userspace-nvram/nvram.h
new file mode 100644 (file)
index 0000000..4061991
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * NVRAM variable manipulation
+ *
+ * Copyright 2007, Broadcom Corporation
+ * Copyright 2009, OpenWrt.org
+ * All Rights Reserved.
+ *
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ */
+
+#ifndef _nvram_h_
+#define _nvram_h_
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <linux/limits.h>
+
+#include "sdinitvals.h"
+
+
+struct nvram_header {
+       uint32_t magic;
+       uint32_t len;
+       uint32_t crc_ver_init;  /* 0:7 crc, 8:15 ver, 16:31 sdram_init */
+       uint32_t config_refresh;        /* 0:15 sdram_config, 16:31 sdram_refresh */
+       uint32_t config_ncdl;   /* ncdl values for memc */
+};
+
+struct nvram_tuple {
+       char *name;
+       char *value;
+       struct nvram_tuple *next;
+};
+
+struct nvram_handle {
+       int fd;
+       char *mmap;
+       unsigned long length;
+       struct nvram_tuple *nvram_hash[257];
+       struct nvram_tuple *nvram_dead;
+};
+
+typedef struct nvram_handle nvram_handle_t;
+typedef struct nvram_header nvram_header_t;
+typedef struct nvram_tuple  nvram_tuple_t;
+
+
+/* Set the value of an NVRAM variable */
+int nvram_set(nvram_handle_t *h, const char *name, const char *value);
+
+/* Get the value of an NVRAM variable. */
+char * nvram_get(nvram_handle_t *h, const char *name);
+
+/* Unset the value of an NVRAM variable. */
+int nvram_unset(nvram_handle_t *h, const char *name);
+
+/* Get all NVRAM variables. */
+nvram_tuple_t * nvram_getall(nvram_handle_t *h);
+
+/* Regenerate NVRAM. */
+int nvram_commit(nvram_handle_t *h);
+
+/* Open NVRAM and obtain a handle. */
+nvram_handle_t * nvram_open(const char *file, int rdonly);
+
+/* Close NVRAM and free memory. */
+int nvram_close(nvram_handle_t *h);
+
+/* Get the value of an NVRAM variable in a safe way, use "" instead of NULL. */
+#define nvram_safe_get(h, name) (nvram_get(h, name) ? : "")
+
+/* Computes a crc8 over the input data. */
+uint8_t hndcrc8 (uint8_t * pdata, uint32_t nbytes, uint8_t crc );
+
+/* Returns the crc value of the nvram. */
+uint8_t nvram_calc_crc(nvram_header_t * nvh);
+
+/* Determine NVRAM device node. */
+const char * nvram_find_mtd(void);
+
+/* Copy NVRAM contents to staging file. */
+int nvram_to_staging(void);
+
+/* Copy staging file to NVRAM device. */
+int staging_to_nvram(void);
+
+/* Check NVRAM staging file. */
+const char * nvram_find_staging(void);
+
+
+/* Staging file for NVRAM */
+#define NVRAM_STAGING  "/tmp/.nvram"
+#define NVRAM_RO       1
+#define NVRAM_RW       0
+
+/* Helper macros */
+#define NVRAM_ARRAYSIZE(a) sizeof(a)/sizeof(a[0])
+#define        NVRAM_ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
+
+/* The NVRAM version number stored as an NVRAM variable */
+#define NVRAM_SOFTWARE_VERSION "1"
+
+/* NVRAM constants */
+#define NVRAM_MAGIC                    0x48534C46      /* 'FLSH' */
+#define NVRAM_CLEAR_MAGIC      0x0
+#define NVRAM_INVALID_MAGIC    0xFFFFFFFF
+#define NVRAM_VERSION          1
+#define NVRAM_HEADER_SIZE      20
+#define NVRAM_SPACE                    0x8000
+
+#define NVRAM_MAX_VALUE_LEN 255
+#define NVRAM_MAX_PARAM_LEN 64
+
+#define NVRAM_CRC_START_POSITION       9 /* magic, len, crc8 to be skipped */
+#define NVRAM_CRC_VER_MASK                     0xffffff00 /* for crc_ver_init */
+
+
+#endif /* _nvram_h_ */
diff --git a/contrib/userspace-nvram/sdinitvals.h b/contrib/userspace-nvram/sdinitvals.h
new file mode 100644 (file)
index 0000000..5a289ad
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * SDRAM init values
+ *
+ * Copyright 2007, Broadcom Corporation
+ * Copyright 2009, OpenWrt.org
+ * All Rights Reserved.
+ *
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ */
+
+#ifndef _sdinitvals_h_
+#define _sdinitvals_h_
+
+/* SDRAM refresh control (refresh) register bits */
+#define SDRAM_REF(p)    (((p)&0xff) | SDRAM_REF_EN)     /* Refresh period */
+#define SDRAM_REF_EN    0x8000          /* Writing 1 enables periodic refresh */
+
+/* SDRAM Core default Init values (OCP ID 0x803) */
+#define MEM4MX16X2      0x419   /* 16 MB */
+
+#define SDRAM_INIT     MEM4MX16X2
+#define SDRAM_BURSTFULL 0x0000  /* Use full page bursts */
+#define SDRAM_CONFIG    SDRAM_BURSTFULL
+#define SDRAM_REFRESH   SDRAM_REF(0x40)
+
+#endif /* _sdinitvals_h_ */