aboutsummaryrefslogtreecommitdiffstats
path: root/package/utils/nvram
diff options
context:
space:
mode:
Diffstat (limited to 'package/utils/nvram')
-rw-r--r--package/utils/nvram/Makefile52
-rwxr-xr-xpackage/utils/nvram/files/nvram.init98
-rw-r--r--package/utils/nvram/src/Makefile7
-rw-r--r--package/utils/nvram/src/cli.c246
-rw-r--r--package/utils/nvram/src/crc.c69
-rw-r--r--package/utils/nvram/src/nvram.c540
-rw-r--r--package/utils/nvram/src/nvram.h123
-rw-r--r--package/utils/nvram/src/sdinitvals.h30
8 files changed, 1165 insertions, 0 deletions
diff --git a/package/utils/nvram/Makefile b/package/utils/nvram/Makefile
new file mode 100644
index 0000000..992f336
--- /dev/null
+++ b/package/utils/nvram/Makefile
@@ -0,0 +1,52 @@
+#
+# Copyright (C) 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=nvram
+PKG_RELEASE:=9
+
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/nvram
+ SECTION:=utils
+ CATEGORY:=Base system
+ TITLE:=Userspace port of the Broadcom NVRAM manipulation tool
+ MAINTAINER:=Jo-Philipp Wich <xm@subsignal.org>
+ DEPENDS:=@TARGET_brcm47xx||@TARGET_bcm53xx||@TARGET_ar71xx
+endef
+
+define Package/nvram/description
+ This package contains an utility to manipulate NVRAM on Broadcom based devices.
+ It works on bcm47xx (Linux 2.6) without using the kernel api.
+endef
+
+define Build/Prepare
+ mkdir -p $(PKG_BUILD_DIR)
+ $(CP) ./src/* $(PKG_BUILD_DIR)/
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+ $(MAKE) -C $(PKG_BUILD_DIR) \
+ CC="$(TARGET_CC)" \
+ CFLAGS="$(TARGET_CFLAGS) -Wall" \
+ LDFLAGS="$(TARGET_LDFLAGS)"
+endef
+
+define Package/nvram/install
+ $(INSTALL_DIR) $(1)/etc/init.d
+ $(INSTALL_BIN) ./files/nvram.init $(1)/etc/init.d/nvram
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/nvram $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,nvram))
diff --git a/package/utils/nvram/files/nvram.init b/package/utils/nvram/files/nvram.init
new file mode 100755
index 0000000..467ab28
--- /dev/null
+++ b/package/utils/nvram/files/nvram.init
@@ -0,0 +1,98 @@
+#!/bin/sh /etc/rc.common
+# NVRAM setup
+#
+# This file handles the NVRAM quirks of various hardware.
+
+START=02
+alias debug=${DEBUG:-:}
+
+nvram_default() {
+ [ -z "$(nvram get $1)" ] && nvram set "$1=$2"
+}
+
+nvram_set() { # for the linksys fixup part
+ [ "$(nvram get "$1")" = "$2" -a "$2" != "" ] || {
+ COMMIT=1
+ /usr/sbin/nvram set "$1=$2"
+ }
+}
+
+fixup_linksys() {
+ # work around braindead CFE defaults in linksys routers
+ boardtype=$(nvram get boardtype)
+ boardnum=$(nvram get boardnum)
+ boardflags=$(($(nvram get boardflags)))
+ adm_switch="$(( ($boardflags & 0x80) >> 7 ))"
+
+ [ -n "$(nvram get vxkilled)" ] && boardtype=0 # don't mess with the ram settings on the hacked cfe
+ case "$(( $boardtype ))" in
+ "1800") #0x708
+ if [ "$adm_switch" = 0 ]; then
+ nvram_set sdram_init "$(printf 0x%04x $(( $(/usr/sbin/nvram get sdram_init) | 0x0100 )))"
+ [ "$COMMIT" = 1 ] && {
+ nvram_set clkfreq 216
+ nvram_set sdram_ncdl 0x0
+ nvram_set pa0itssit 62
+ nvram_set pa0b0 0x15eb
+ nvram_set pa0b1 0xfa82
+ nvram_set pa0b2 0xfe66
+ nvram_set pa0maxpwr 0x4e
+ }
+ fi
+ ;;
+ "1127") #0x467
+ nvram_set sdram_init "$(printf 0x%04x $(( $(/usr/sbin/nvram get sdram_init) | 0x0100 )))"
+ [ "$COMMIT" = 1 ] && {
+ nvram_set sdram_ncdl 0x0
+ nvram_set pa0itssit 62
+ nvram_set pa0b0 0x168b
+ nvram_set pa0b1 0xfabf
+ nvram_set pa0b2 0xfeaf
+ nvram_set pa0maxpwr 0x4e
+ }
+ ;;
+ "1071") #0x042f
+ # do sanity check first! max 0x0011 = 128mb
+ SDRAM_INIT=$(printf %d $(/usr/sbin/nvram get sdram_init))
+ [ "$SDRAM_INIT" -lt "9" -o "$SDRAM_INIT" -gt "17" ] && {
+ # set this to default: 0x09 only if value is invaild like 16MB on Asus WL-500GP
+ echo "sdram_init is invaild: $(printf 0x%04x $SDRAM_INIT), force to default!"
+ nvram_set sdram_init 0x0009
+ }
+ # on WRT54G3GV2 set flag, so checksum errors of firmware image 2 don't stop the boot process
+ noset_try_flag=$(nvram get noset_try_flag)
+ [ "$noset_try_flag" = 0 ] && {
+ echo "setting noset_try_flag to 1."
+ nvram_set noset_try_flag 1
+ }
+ [ "$COMMIT" = 1 ] && {
+ nvram_set sdram_ncdl 0x0
+ }
+ esac
+}
+
+start() {
+ # Don't do any fixups on the WGT634U
+ [ "$(cat /proc/diag/model)" = "Netgear WGT634U" ] && return
+
+ fixup_linksys
+
+ # OFDM Power Offset is set incorrectly on many boards.
+ # Setting it to 0 will increase the tx power to normal levels.
+ nvram_set opo 0x0
+
+ [ "$(nvram get il0macaddr)" = "00:90:4c:5f:00:2a" ] && {
+ # if default wifi mac, set two higher than the lan mac
+ nvram set il0macaddr=$(nvram get et0macaddr|
+ awk '{OFS=FS=":";for(x=7,y=2;--x;){$x=sprintf("%02x",(y+="0x"$x)%256);y/=256}print}')
+ }
+
+ [ "$(nvram get et0macaddr)" = "00:90:4c:c0:00:08" ] && {
+ # OvisLink WL-1600GL mac workaround
+ nvram set et0macaddr=$(hexdump -n 6 -s 130976 -e '5/1 "%02x:" "%02x" ' /dev/mtd/0)
+ nvram set il0macaddr=$(nvram get et0macaddr|
+ awk '{OFS=FS=":";for(x=7,y=2;--x;){$x=sprintf("%02x",(y+="0x"$x)%256);y/=256}print}')
+ }
+
+ [ "$COMMIT" = "1" ] && nvram commit
+}
diff --git a/package/utils/nvram/src/Makefile b/package/utils/nvram/src/Makefile
new file mode 100644
index 0000000..68a6354
--- /dev/null
+++ b/package/utils/nvram/src/Makefile
@@ -0,0 +1,7 @@
+all: nvram
+
+nvram:
+ $(CC) $(CFLAGS) -o $@ cli.c crc.c nvram.c $(LDFLAGS)
+
+clean:
+ rm -f nvram
diff --git a/package/utils/nvram/src/cli.c b/package/utils/nvram/src/cli.c
new file mode 100644
index 0000000..488d641
--- /dev/null
+++ b/package/utils/nvram/src/cli.c
@@ -0,0 +1,246 @@
+/*
+ * Command line interface for libnvram
+ *
+ * Copyright 2009, Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * The libnvram code is based on Broadcom code for Linux 2.4.x .
+ *
+ */
+
+#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;
+}
+
+static int do_info(nvram_handle_t *nvram)
+{
+ nvram_header_t *hdr = nvram_header(nvram);
+
+ /* CRC8 over the last 11 bytes of the header and data bytes */
+ uint8_t crc = hndcrc8((unsigned char *) &hdr[0] + NVRAM_CRC_START_POSITION,
+ hdr->len - NVRAM_CRC_START_POSITION, 0xff);
+
+ /* Show info */
+ printf("Magic: 0x%08X\n", hdr->magic);
+ printf("Length: 0x%08X\n", hdr->len);
+ printf("Offset: 0x%08X\n", nvram->offset);
+
+ printf("CRC8: 0x%02X (calculated: 0x%02X)\n",
+ hdr->crc_ver_init & 0xFF, crc);
+
+ printf("Version: 0x%02X\n", (hdr->crc_ver_init >> 8) & 0xFF);
+ printf("SDRAM init: 0x%04X\n", (hdr->crc_ver_init >> 16) & 0xFFFF);
+ printf("SDRAM config: 0x%04X\n", hdr->config_refresh & 0xFFFF);
+ printf("SDRAM refresh: 0x%04X\n", (hdr->config_refresh >> 16) & 0xFFFF);
+ printf("NCDL values: 0x%08X\n\n", hdr->config_ncdl);
+
+ printf("%i bytes used / %i bytes available (%.2f%%)\n",
+ hdr->len, nvram->length - nvram->offset - hdr->len,
+ (100.00 / (double)(nvram->length - nvram->offset)) * (double)hdr->len);
+
+ return 0;
+}
+
+
+int main( int argc, const char *argv[] )
+{
+ nvram_handle_t *nvram;
+ int commit = 0;
+ int write = 0;
+ int stat = 1;
+ int done = 0;
+ 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;
+ }
+
+
+ nvram = write ? nvram_open_staging() : nvram_open_rdonly();
+
+ if( nvram != NULL && argc > 1 )
+ {
+ for( i = 1; i < argc; i++ )
+ {
+ if( !strcmp(argv[i], "show") )
+ {
+ stat = do_show(nvram);
+ done++;
+ }
+ else if( !strcmp(argv[i], "info") )
+ {
+ stat = do_info(nvram);
+ done++;
+ }
+ else if( !strcmp(argv[i], "get") || !strcmp(argv[i], "unset") || !strcmp(argv[i], "set") )
+ {
+ if( (i+1) < argc )
+ {
+ switch(argv[i++][0])
+ {
+ case 'g':
+ stat = do_get(nvram, argv[i]);
+ break;
+
+ case 'u':
+ stat = do_unset(nvram, argv[i]);
+ break;
+
+ case 's':
+ stat = do_set(nvram, argv[i]);
+ break;
+ }
+ done++;
+ }
+ else
+ {
+ fprintf(stderr, "Command '%s' requires an argument!\n", argv[i]);
+ done = 0;
+ break;
+ }
+ }
+ else if( !strcmp(argv[i], "commit") )
+ {
+ commit = 1;
+ done++;
+ }
+ else
+ {
+ fprintf(stderr, "Unknown option '%s' !\n", argv[i]);
+ done = 0;
+ break;
+ }
+ }
+
+ if( write )
+ stat = nvram_commit(nvram);
+
+ nvram_close(nvram);
+
+ if( commit )
+ stat = staging_to_nvram();
+ }
+
+ if( !nvram )
+ {
+ fprintf(stderr,
+ "Could not open nvram! Possible reasons are:\n"
+ " - No device found (/proc not mounted or no nvram present)\n"
+ " - Insufficient permissions to open mtd device\n"
+ " - Insufficient memory to complete operation\n"
+ " - Memory mapping failed or not supported\n"
+ );
+
+ stat = 1;
+ }
+ else if( !done )
+ {
+ fprintf(stderr,
+ "Usage:\n"
+ " nvram show\n"
+ " nvram info\n"
+ " nvram get variable\n"
+ " nvram set variable=value [set ...]\n"
+ " nvram unset variable [unset ...]\n"
+ " nvram commit\n"
+ );
+
+ stat = 1;
+ }
+
+ return stat;
+}
diff --git a/package/utils/nvram/src/crc.c b/package/utils/nvram/src/crc.c
new file mode 100644
index 0000000..22a3665
--- /dev/null
+++ b/package/utils/nvram/src/crc.c
@@ -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/package/utils/nvram/src/nvram.c b/package/utils/nvram/src/nvram.c
new file mode 100644
index 0000000..0e42943
--- /dev/null
+++ b/package/utils/nvram/src/nvram.c
@@ -0,0 +1,540 @@
+/*
+ * NVRAM variable manipulation (common)
+ *
+ * Copyright 2004, Broadcom Corporation
+ * Copyright 2009-2010, 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(msg) \
+ printf("%s(%i) in %s(): %s\n", \
+ __FILE__, __LINE__, __FUNCTION__, msg ? msg : "?")
+
+/* Size of "nvram" MTD partition */
+size_t nvram_part_size = 0;
+
+
+/*
+ * -- 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) > h->length - h->offset)
+ 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(h);
+ char buf[] = "0xXXXXXXXX", *name, *value, *eq;
+
+ /* (Re)initialize hash table */
+ _nvram_free(h);
+
+ /* Parse and set "name=value\0 ... \0\0" */
+ name = (char *) &header[1];
+
+ 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 nvram header. */
+nvram_header_t * nvram_header(nvram_handle_t *h)
+{
+ return (nvram_header_t *) &h->mmap[h->offset];
+}
+
+/* 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(h);
+ 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_part_size - h->offset - sizeof(nvram_header_t));
+ memset(&tmp, 0, sizeof(nvram_header_t));
+
+ /* Leave space for a double NUL at the end */
+ end = (char *) header + nvram_part_size - h->offset - 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 NULL and pad to 4 bytes */
+ *ptr = '\0';
+ ptr++;
+
+ if( (int)ptr % 4 )
+ memset(ptr, 0, 4 - ((int)ptr % 4));
+
+ ptr++;
+
+ /* 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 = header->crc_ver_init;
+ tmp.config_refresh = header->config_refresh;
+ tmp.config_ncdl = header->config_ncdl;
+ crc = hndcrc8((unsigned char *) &tmp + NVRAM_CRC_START_POSITION,
+ sizeof(nvram_header_t) - NVRAM_CRC_START_POSITION, 0xff);
+
+ /* Continue CRC8 over data bytes */
+ crc = hndcrc8((unsigned char *) &header[0] + sizeof(nvram_header_t),
+ 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 i;
+ int fd;
+ char *mtd = NULL;
+ nvram_handle_t *h;
+ nvram_header_t *header;
+ int offset = -1;
+
+ /* If erase size or file are undefined then try to define them */
+ if( (nvram_part_size == 0) || (file == NULL) )
+ {
+ /* Finding the mtd will set the appropriate erase size */
+ if( (mtd = nvram_find_mtd()) == NULL || nvram_part_size == 0 )
+ {
+ free(mtd);
+ return NULL;
+ }
+ }
+
+ if( (fd = open(file ? file : mtd, O_RDWR)) > -1 )
+ {
+ char *mmap_area = (char *) mmap(
+ NULL, nvram_part_size, PROT_READ | PROT_WRITE,
+ (( rdonly == NVRAM_RO ) ? MAP_PRIVATE : MAP_SHARED) | MAP_LOCKED, fd, 0);
+
+ if( mmap_area != MAP_FAILED )
+ {
+ /*
+ * Start looking for NVRAM_MAGIC at beginning of MTD
+ * partition. Stop if there is less than NVRAM_MIN_SPACE
+ * to check, that was the lowest used size.
+ */
+ for( i = 0; i <= ((nvram_part_size - NVRAM_MIN_SPACE) / sizeof(uint32_t)); i++ )
+ {
+ if( ((uint32_t *)mmap_area)[i] == NVRAM_MAGIC )
+ {
+ offset = i * sizeof(uint32_t);
+ break;
+ }
+ }
+
+ if( offset < 0 )
+ {
+ free(mtd);
+ return NULL;
+ }
+ else if( (h = malloc(sizeof(nvram_handle_t))) != NULL )
+ {
+ memset(h, 0, sizeof(nvram_handle_t));
+
+ h->fd = fd;
+ h->mmap = mmap_area;
+ h->length = nvram_part_size;
+ h->offset = offset;
+
+ header = nvram_header(h);
+
+ if (header->magic == NVRAM_MAGIC &&
+ (rdonly || header->len < h->length - h->offset)) {
+ _nvram_rehash(h);
+ free(mtd);
+ return h;
+ }
+ else
+ {
+ munmap(h->mmap, h->length);
+ free(h);
+ }
+ }
+ }
+ }
+
+ free(mtd);
+ 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. */
+char * nvram_find_mtd(void)
+{
+ FILE *fp;
+ int i, part_size;
+ char dev[PATH_MAX];
+ char *path = NULL;
+ struct stat s;
+
+ if ((fp = fopen("/proc/mtd", "r")))
+ {
+ while( fgets(dev, sizeof(dev), fp) )
+ {
+ if( strstr(dev, "nvram") && sscanf(dev, "mtd%d: %08x", &i, &part_size) )
+ {
+ nvram_part_size = part_size;
+
+ sprintf(dev, "/dev/mtdblock%d", i);
+ if( stat(dev, &s) > -1 && (s.st_mode & S_IFBLK) )
+ {
+ if( (path = (char *) malloc(strlen(dev)+1)) != NULL )
+ {
+ strncpy(path, dev, strlen(dev)+1);
+ break;
+ }
+ }
+ }
+ }
+ fclose(fp);
+ }
+
+ return path;
+}
+
+/* Check NVRAM staging file. */
+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;
+ char *mtd = nvram_find_mtd();
+ char buf[nvram_part_size];
+
+ stat = -1;
+
+ if( (mtd != NULL) && (nvram_part_size > 0) )
+ {
+ 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);
+ }
+ }
+
+ free(mtd);
+ return stat;
+}
+
+/* Copy staging file to NVRAM device. */
+int staging_to_nvram(void)
+{
+ int fdmtd, fdstg, stat;
+ char *mtd = nvram_find_mtd();
+ char buf[nvram_part_size];
+
+ stat = -1;
+
+ if( (mtd != NULL) && (nvram_part_size > 0) )
+ {
+ 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;
+ }
+ }
+
+ free(mtd);
+ return stat;
+}
diff --git a/package/utils/nvram/src/nvram.h b/package/utils/nvram/src/nvram.h
new file mode 100644
index 0000000..724f33b
--- /dev/null
+++ b/package/utils/nvram/src/nvram.h
@@ -0,0 +1,123 @@
+/*
+ * 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 <errno.h>
+#include <sys/mman.h>
+#include <sys/stat.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 */
+} __attribute__((__packed__));
+
+struct nvram_tuple {
+ char *name;
+ char *value;
+ struct nvram_tuple *next;
+};
+
+struct nvram_handle {
+ int fd;
+ char *mmap;
+ unsigned int length;
+ unsigned int offset;
+ 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;
+
+
+/* Get nvram header. */
+nvram_header_t * nvram_header(nvram_handle_t *h);
+
+/* 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. */
+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. */
+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))
+
+/* NVRAM constants */
+#define NVRAM_MIN_SPACE 0x8000
+#define NVRAM_MAGIC 0x48534C46 /* 'FLSH' */
+#define NVRAM_VERSION 1
+
+#define NVRAM_CRC_START_POSITION 9 /* magic, len, crc8 to be skipped */
+
+
+#endif /* _nvram_h_ */
diff --git a/package/utils/nvram/src/sdinitvals.h b/package/utils/nvram/src/sdinitvals.h
new file mode 100644
index 0000000..5a289ad
--- /dev/null
+++ b/package/utils/nvram/src/sdinitvals.h
@@ -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_ */