diff options
| author | jow <jow@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2009-04-27 12:58:54 +0000 | 
|---|---|---|
| committer | jow <jow@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2009-04-27 12:58:54 +0000 | 
| commit | fad131f967cbb1ba415fca80e90361e5e9ed7a48 (patch) | |
| tree | 47667c9459ee869346f1ea6322dcac1aa75eb350 /package/nvram/src | |
| parent | 32fce976bd2e1bf710d5486f7168b8a73b2aaf5d (diff) | |
[package] rename unvram to nvram
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@15437 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/nvram/src')
| -rw-r--r-- | package/nvram/src/Makefile | 33 | ||||
| -rw-r--r-- | package/nvram/src/cli.c | 233 | ||||
| -rw-r--r-- | package/nvram/src/crc.c | 69 | ||||
| -rw-r--r-- | package/nvram/src/nvram.c | 531 | ||||
| -rw-r--r-- | package/nvram/src/nvram.h | 123 | ||||
| -rw-r--r-- | package/nvram/src/sdinitvals.h | 30 | 
6 files changed, 1019 insertions, 0 deletions
diff --git a/package/nvram/src/Makefile b/package/nvram/src/Makefile new file mode 100644 index 000000000..4872728ba --- /dev/null +++ b/package/nvram/src/Makefile @@ -0,0 +1,33 @@ +CLI_FILENAME = nvram + +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) + +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 $(CLI_FILENAME) $(CLI_LDFLAGS) $(CLI_OBJ) \ +		$(LIB_FILENAME).$(LIB_VERMAJOR).$(LIB_VERMINOR) + +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) + +clean: +	rm -f $(CLI_FILENAME) $(LIB_FILENAME)* *.o diff --git a/package/nvram/src/cli.c b/package/nvram/src/cli.c new file mode 100644 index 000000000..953910cd6 --- /dev/null +++ b/package/nvram/src/cli.c @@ -0,0 +1,233 @@ +/* + * 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("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_SPACE - hdr->len, +		(100.00 / (double)NVRAM_SPACE) * (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") && ++i < argc ) +			{ +				stat = do_get(nvram, argv[i]); +				done++; +			} +			else if( !strcmp(argv[i], "unset") && ++i < argc ) +			{ +				stat = do_unset(nvram, argv[i]); +				done++; +			} +			else if( !strcmp(argv[i], "set") && ++i < argc ) +			{ +				stat = do_set(nvram, argv[i]); +				done++; +			} +			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/nvram/src/crc.c b/package/nvram/src/crc.c new file mode 100644 index 000000000..22a36652a --- /dev/null +++ b/package/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/nvram/src/nvram.c b/package/nvram/src/nvram.c new file mode 100644 index 000000000..78baa9431 --- /dev/null +++ b/package/nvram/src/nvram.c @@ -0,0 +1,531 @@ +/* + * 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(msg) \ +	printf("%s(%i) in %s(): %s\n", \ +		__FILE__, __LINE__, __FUNCTION__, msg ? msg : "?") + +size_t nvram_erase_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) > 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(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[NVRAM_START(nvram_erase_size)]; +} + +/* 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_SPACE - sizeof(nvram_header_t)); +	memset(&tmp, 0, 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 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 fd; +	char *mtd = NULL; +	nvram_handle_t *h; +	nvram_header_t *header; + +	/* If erase size or file are undefined then try to define them */ +	if( (nvram_erase_size == 0) || (file == NULL) ) +	{ +		/* Finding the mtd will set the appropriate erase size */ +		if( (mtd = nvram_find_mtd()) == NULL || nvram_erase_size == 0 ) +		{ +			free(mtd); +			return NULL; +		} +	} + +	if( (fd = open(file ? file : mtd, O_RDWR)) > -1 ) +	{ +		char *mmap_area = (char *) mmap( +			NULL, nvram_erase_size, PROT_READ | PROT_WRITE, +			( rdonly == NVRAM_RO ) ? MAP_PRIVATE : MAP_SHARED, fd, 0); + +		if( mmap_area != MAP_FAILED ) +		{ +			memset(mmap_area, 0xFF, NVRAM_START(nvram_erase_size)); + +			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 = nvram_erase_size; + +				header = nvram_header(h); + +				if( header->magic == NVRAM_MAGIC ) +				{ +					_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, esz; +	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, &esz) ) +			{ +				nvram_erase_size = esz; + +				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; +					} +				} +				else +				{ +					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_erase_size]; + +	stat = -1; + +	if( (mtd != NULL) && (nvram_erase_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_erase_size]; + +	stat = -1; + +	if( (mtd != NULL) && (nvram_erase_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/nvram/src/nvram.h b/package/nvram/src/nvram.h new file mode 100644 index 000000000..e3d64613d --- /dev/null +++ b/package/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 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; + + +/* 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_SPACE			0x8000 +#define NVRAM_START(x)		x - NVRAM_SPACE +#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/nvram/src/sdinitvals.h b/package/nvram/src/sdinitvals.h new file mode 100644 index 000000000..5a289adec --- /dev/null +++ b/package/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_ */  | 
