[Armadeus-commitlog] armadeus branch, master, updated. release-3.2-202-g1b1c16d
Brought to you by:
sszy
|
From: Julien B a. A. <ar...@us...> - 2010-02-16 21:36:33
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "armadeus".
The branch, master has been updated
via 1b1c16d8a95d2da379c26a736ba9865987a9e3ac (commit)
from 1d779c611fbcc6c3955948eea250e1bee814abb2 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 1b1c16d8a95d2da379c26a736ba9865987a9e3ac
Author: Julien Boibessot <jul...@ar...>
Date: Tue Feb 16 22:35:44 2010 +0100
[U-Boot] Makes fw_setenv command work with NAND Flash
-----------------------------------------------------------------------
Summary of changes:
...v-fix_build_problems_with_old_MTD_VERSION.patch | 34 +
.../u-boot-1.3.4-331-fw_env-add_NAND_support.patch | 1202 ++++++++++++++++++++
2 files changed, 1236 insertions(+), 0 deletions(-)
create mode 100644 buildroot/target/u-boot/u-boot-1.3.4-330-fw_env-fix_build_problems_with_old_MTD_VERSION.patch
create mode 100644 buildroot/target/u-boot/u-boot-1.3.4-331-fw_env-add_NAND_support.patch
diff --git a/buildroot/target/u-boot/u-boot-1.3.4-330-fw_env-fix_build_problems_with_old_MTD_VERSION.patch b/buildroot/target/u-boot/u-boot-1.3.4-330-fw_env-fix_build_problems_with_old_MTD_VERSION.patch
new file mode 100644
index 0000000..4763ff0
--- /dev/null
+++ b/buildroot/target/u-boot/u-boot-1.3.4-330-fw_env-fix_build_problems_with_old_MTD_VERSION.patch
@@ -0,0 +1,34 @@
+From: Wolfgang Denk <wd...@de...>
+Date: Tue, 2 Sep 2008 19:17:36 +0000 (+0200)
+Subject: fw_env.c: fix build problems with MTD_VERSION=old
+X-Git-Tag: v2008.10-rc1~62
+X-Git-Url: http://git.denx.de/?p=u-boot.git;a=commitdiff_plain;h=1711f3bd16d1c5e9d17b4c0198b426d86999781b
+
+fw_env.c: fix build problems with MTD_VERSION=old
+
+(as needed to support old 2.4 Linux kernel based releases)
+
+Signed-off-by: Wolfgang Denk <wd...@de...>
+---
+
+diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
+index b8bca91..e4fc02d 100644
+--- a/tools/env/fw_env.c
++++ b/tools/env/fw_env.c
+@@ -33,6 +33,7 @@
+ #include <unistd.h>
+
+ #ifdef MTD_OLD
++# include <stdint.h>
+ # include <linux/mtd/mtd.h>
+ #else
+ # define __user /* nothing */
+@@ -397,7 +398,7 @@ int fw_setenv (int argc, char *argv[])
+ static int flash_io (int mode)
+ {
+ int fd, fdr, rc, otherdev, len, resid;
+- erase_info_t erase;
++ struct erase_info_user erase;
+ char *data = NULL;
+
+ if ((fd = open (DEVNAME (curdev), mode)) < 0) {
diff --git a/buildroot/target/u-boot/u-boot-1.3.4-331-fw_env-add_NAND_support.patch b/buildroot/target/u-boot/u-boot-1.3.4-331-fw_env-add_NAND_support.patch
new file mode 100644
index 0000000..679c11e
--- /dev/null
+++ b/buildroot/target/u-boot/u-boot-1.3.4-331-fw_env-add_NAND_support.patch
@@ -0,0 +1,1202 @@
+From: Guennadi Liakhovetski <lg...@de...>
+Date: Thu, 4 Sep 2008 11:01:49 +0000 (+0200)
+Subject: fw_env: add NAND support
+X-Git-Tag: v2008.10-rc1~24
+X-Git-Url: http://git.denx.de/?p=u-boot.git;a=commitdiff_plain;h=5608692104efa8d56df803dc79ea41ac3607eee5
+
+fw_env: add NAND support
+
+Add support for environment in NAND with automatic NOR / NAND recognition,
+including unaligned environment, bad-block skipping, redundant environment
+copy.
+
+Signed-off-by: Guennadi Liakhovetski <lg...@de...>
+---
+
+diff --git a/tools/env/README b/tools/env/README
+index f8a644e..91e679a 100644
+--- a/tools/env/README
++++ b/tools/env/README
+@@ -22,9 +22,11 @@ following lines are relevant:
+ #define DEVICE1_OFFSET 0x0000
+ #define ENV1_SIZE 0x4000
+ #define DEVICE1_ESIZE 0x4000
++#define DEVICE1_ENVSECTORS 2
+ #define DEVICE2_OFFSET 0x0000
+ #define ENV2_SIZE 0x4000
+ #define DEVICE2_ESIZE 0x4000
++#define DEVICE2_ENVSECTORS 2
+
+ Current configuration matches the environment layout of the TRAB
+ board.
+@@ -46,3 +48,7 @@ then 1 sector.
+
+ DEVICEx_ESIZE defines the size of the first sector in the flash
+ partition where the environment resides.
++
++DEVICEx_ENVSECTORS defines the number of sectors that may be used for
++this environment instance. On NAND this is used to limit the range
++within which bad blocks are skipped, on NOR it is not used.
+diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
+index e4fc02d..b6036c8 100644
+--- a/tools/env/fw_env.c
++++ b/tools/env/fw_env.c
+@@ -2,6 +2,9 @@
+ * (C) Copyright 2000-2008
+ * Wolfgang Denk, DENX Software Engineering, wd...@de....
+ *
++ * (C) Copyright 2008
++ * Guennadi Liakhovetski, DENX Software Engineering, lg...@de....
++ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+@@ -45,36 +48,75 @@
+ #define CMD_GETENV "fw_printenv"
+ #define CMD_SETENV "fw_setenv"
+
+-typedef struct envdev_s {
++#define min(x, y) ({ \
++ typeof(x) _min1 = (x); \
++ typeof(y) _min2 = (y); \
++ (void) (&_min1 == &_min2); \
++ _min1 < _min2 ? _min1 : _min2; })
++
++struct envdev_s {
+ char devname[16]; /* Device name */
+ ulong devoff; /* Device offset */
+ ulong env_size; /* environment size */
+ ulong erase_size; /* device erase size */
+-} envdev_t;
++ ulong env_sectors; /* number of environment sectors */
++ uint8_t mtd_type; /* type of the MTD device */
++};
+
+-static envdev_t envdevices[2];
+-static int curdev;
++static struct envdev_s envdevices[2] =
++{
++ {
++ .mtd_type = MTD_ABSENT,
++ }, {
++ .mtd_type = MTD_ABSENT,
++ },
++};
++static int dev_current;
+
+ #define DEVNAME(i) envdevices[(i)].devname
+ #define DEVOFFSET(i) envdevices[(i)].devoff
+ #define ENVSIZE(i) envdevices[(i)].env_size
+ #define DEVESIZE(i) envdevices[(i)].erase_size
++#define ENVSECTORS(i) envdevices[(i)].env_sectors
++#define DEVTYPE(i) envdevices[(i)].mtd_type
+
+-#define CFG_ENV_SIZE ENVSIZE(curdev)
++#define CFG_ENV_SIZE ENVSIZE(dev_current)
+
+ #define ENV_SIZE getenvsize()
+
+-typedef struct environment_s {
+- ulong crc; /* CRC32 over data bytes */
+- unsigned char flags; /* active or obsolete */
+- char *data;
+-} env_t;
++struct env_image_single {
++ uint32_t crc; /* CRC32 over data bytes */
++ char data[];
++};
+
+-static env_t environment;
++struct env_image_redundant {
++ uint32_t crc; /* CRC32 over data bytes */
++ unsigned char flags; /* active or obsolete */
++ char data[];
++};
++
++enum flag_scheme {
++ FLAG_NONE,
++ FLAG_BOOLEAN,
++ FLAG_INCREMENTAL,
++};
++
++struct environment {
++ void *image;
++ uint32_t *crc;
++ unsigned char *flags;
++ char *data;
++ enum flag_scheme flag_scheme;
++};
++
++static struct environment environment = {
++ .flag_scheme = FLAG_NONE,
++};
+
+ static int HaveRedundEnv = 0;
+
+ static unsigned char active_flag = 1;
++/* obsolete_flag must be 0 to efficiently set it on NOR flash without erasing */
+ static unsigned char obsolete_flag = 0;
+
+
+@@ -157,7 +199,7 @@ static char default_environment[] = {
+ #ifdef CONFIG_EXTRA_ENV_SETTINGS
+ CONFIG_EXTRA_ENV_SETTINGS
+ #endif
+- "\0" /* Termimate env_t data with 2 NULs */
++ "\0" /* Termimate struct environment data with 2 NULs */
+ };
+
+ static int flash_io (int mode);
+@@ -186,7 +228,7 @@ char *fw_getenv (char *name)
+ char *env, *nxt;
+
+ if (env_init ())
+- return (NULL);
++ return NULL;
+
+ for (env = environment.data; *env; env = nxt + 1) {
+ char *val;
+@@ -195,15 +237,15 @@ char *fw_getenv (char *name)
+ if (nxt >= &environment.data[ENV_SIZE]) {
+ fprintf (stderr, "## Error: "
+ "environment not terminated\n");
+- return (NULL);
++ return NULL;
+ }
+ }
+ val = envmatch (name, env);
+ if (!val)
+ continue;
+- return (val);
++ return val;
+ }
+- return (NULL);
++ return NULL;
+ }
+
+ /*
+@@ -217,7 +259,7 @@ int fw_printenv (int argc, char *argv[])
+ int rc = 0;
+
+ if (env_init ())
+- return (-1);
++ return -1;
+
+ if (argc == 1) { /* Print all env variables */
+ for (env = environment.data; *env; env = nxt + 1) {
+@@ -225,13 +267,13 @@ int fw_printenv (int argc, char *argv[])
+ if (nxt >= &environment.data[ENV_SIZE]) {
+ fprintf (stderr, "## Error: "
+ "environment not terminated\n");
+- return (-1);
++ return -1;
+ }
+ }
+
+ printf ("%s\n", env);
+ }
+- return (0);
++ return 0;
+ }
+
+ if (strcmp (argv[1], "-n") == 0) {
+@@ -241,7 +283,7 @@ int fw_printenv (int argc, char *argv[])
+ if (argc != 2) {
+ fprintf (stderr, "## Error: "
+ "`-n' option requires exactly one argument\n");
+- return (-1);
++ return -1;
+ }
+ } else {
+ n_flag = 0;
+@@ -257,7 +299,7 @@ int fw_printenv (int argc, char *argv[])
+ if (nxt >= &environment.data[ENV_SIZE]) {
+ fprintf (stderr, "## Error: "
+ "environment not terminated\n");
+- return (-1);
++ return -1;
+ }
+ }
+ val = envmatch (name, env);
+@@ -276,11 +318,11 @@ int fw_printenv (int argc, char *argv[])
+ }
+ }
+
+- return (rc);
++ return rc;
+ }
+
+ /*
+- * Deletes or sets environment variables. Returns errno style error codes:
++ * Deletes or sets environment variables. Returns -1 and sets errno error codes:
+ * 0 - OK
+ * EINVAL - need at least 1 argument
+ * EROFS - certain variables ("ethaddr", "serial#") cannot be
+@@ -295,11 +337,12 @@ int fw_setenv (int argc, char *argv[])
+ char *name;
+
+ if (argc < 2) {
+- return (EINVAL);
++ errno = EINVAL;
++ return -1;
+ }
+
+ if (env_init ())
+- return (errno);
++ return -1;
+
+ name = argv[1];
+
+@@ -311,7 +354,8 @@ int fw_setenv (int argc, char *argv[])
+ if (nxt >= &environment.data[ENV_SIZE]) {
+ fprintf (stderr, "## Error: "
+ "environment not terminated\n");
+- return (EINVAL);
++ errno = EINVAL;
++ return -1;
+ }
+ }
+ if ((oldval = envmatch (name, env)) != NULL)
+@@ -328,7 +372,8 @@ int fw_setenv (int argc, char *argv[])
+ if ((strcmp (name, "ethaddr") == 0) ||
+ (strcmp (name, "serial#") == 0)) {
+ fprintf (stderr, "Can't overwrite \"%s\"\n", name);
+- return (EROFS);
++ errno = EROFS;
++ return -1;
+ }
+
+ if (*++nxt == '\0') {
+@@ -367,7 +412,7 @@ int fw_setenv (int argc, char *argv[])
+ fprintf (stderr,
+ "Error: environment overflow, \"%s\" deleted\n",
+ name);
+- return (-1);
++ return -1;
+ }
+ while ((*env = *name++) != '\0')
+ env++;
+@@ -383,195 +428,430 @@ int fw_setenv (int argc, char *argv[])
+
+ WRITE_FLASH:
+
+- /* Update CRC */
+- environment.crc = crc32 (0, (uint8_t*) environment.data, ENV_SIZE);
++ /*
++ * Update CRC
++ */
++ *environment.crc = crc32 (0, (uint8_t *) environment.data, ENV_SIZE);
+
+ /* write environment back to flash */
+ if (flash_io (O_RDWR)) {
+ fprintf (stderr, "Error: can't write fw_env to flash\n");
+- return (-1);
++ return -1;
+ }
+
+- return (0);
++ return 0;
+ }
+
+-static int flash_io (int mode)
++/*
++ * Test for bad block on NAND, just returns 0 on NOR, on NAND:
++ * 0 - block is good
++ * > 0 - block is bad
++ * < 0 - failed to test
++ */
++static int flash_bad_block (int fd, uint8_t mtd_type, loff_t *blockstart)
+ {
+- int fd, fdr, rc, otherdev, len, resid;
+- struct erase_info_user erase;
+- char *data = NULL;
++ if (mtd_type == MTD_NANDFLASH) {
++ int badblock = ioctl (fd, MEMGETBADBLOCK, blockstart);
+
+- if ((fd = open (DEVNAME (curdev), mode)) < 0) {
+- fprintf (stderr,
+- "Can't open %s: %s\n",
+- DEVNAME (curdev), strerror (errno));
+- return (-1);
++ if (badblock < 0) {
++ perror ("Cannot read bad block mark");
++ return badblock;
++ }
++
++ if (badblock) {
++#ifdef DEBUG
++ fprintf (stderr, "Bad block at 0x%llx, "
++ "skipping\n", *blockstart);
++#endif
++ return badblock;
++ }
+ }
+
+- len = sizeof (environment.crc);
+- if (HaveRedundEnv) {
+- len += sizeof (environment.flags);
++ return 0;
++}
++
++/*
++ * Read data from flash at an offset into a provided buffer. On NAND it skips
++ * bad blocks but makes sure it stays within ENVSECTORS (dev) starting from
++ * the DEVOFFSET (dev) block. On NOR the loop is only run once.
++ */
++static int flash_read_buf (int dev, int fd, void *buf, size_t count,
++ off_t offset, uint8_t mtd_type)
++{
++ size_t blocklen; /* erase / write length - one block on NAND,
++ 0 on NOR */
++ size_t processed = 0; /* progress counter */
++ size_t readlen = count; /* current read length */
++ off_t top_of_range; /* end of the last block we may use */
++ off_t block_seek; /* offset inside the current block to the start
++ of the data */
++ loff_t blockstart; /* running start of the current block -
++ MEMGETBADBLOCK needs 64 bits */
++ int rc;
++
++ /*
++ * Start of the first block to be read, relies on the fact, that
++ * erase sector size is always a power of 2
++ */
++ blockstart = offset & ~(DEVESIZE (dev) - 1);
++
++ /* Offset inside a block */
++ block_seek = offset - blockstart;
++
++ if (mtd_type == MTD_NANDFLASH) {
++ /*
++ * NAND: calculate which blocks we are reading. We have
++ * to read one block at a time to skip bad blocks.
++ */
++ blocklen = DEVESIZE (dev);
++
++ /*
++ * To calculate the top of the range, we have to use the
++ * global DEVOFFSET (dev), which can be different from offset
++ */
++ top_of_range = (DEVOFFSET (dev) & ~(blocklen - 1)) +
++ ENVSECTORS (dev) * blocklen;
++
++ /* Limit to one block for the first read */
++ if (readlen > blocklen - block_seek)
++ readlen = blocklen - block_seek;
++ } else {
++ blocklen = 0;
++ top_of_range = offset + count;
+ }
+
+- if (mode == O_RDWR) {
+- if (HaveRedundEnv) {
+- /* switch to next partition for writing */
+- otherdev = !curdev;
+- if ((fdr = open (DEVNAME (otherdev), mode)) < 0) {
+- fprintf (stderr,
+- "Can't open %s: %s\n",
+- DEVNAME (otherdev),
+- strerror (errno));
+- return (-1);
+- }
+- } else {
+- otherdev = curdev;
+- fdr = fd;
+- }
+- printf ("Unlocking flash...\n");
+- erase.length = DEVESIZE (otherdev);
+- erase.start = DEVOFFSET (otherdev);
+- ioctl (fdr, MEMUNLOCK, &erase);
++ /* This only runs once on NOR flash */
++ while (processed < count) {
++ rc = flash_bad_block (fd, mtd_type, &blockstart);
++ if (rc < 0) /* block test failed */
++ return -1;
+
+- if (HaveRedundEnv) {
+- erase.length = DEVESIZE (curdev);
+- erase.start = DEVOFFSET (curdev);
+- ioctl (fd, MEMUNLOCK, &erase);
+- environment.flags = active_flag;
++ if (blockstart + block_seek + readlen > top_of_range) {
++ /* End of range is reached */
++ fprintf (stderr,
++ "Too few good blocks within range\n");
++ return -1;
+ }
+
+- printf ("Done\n");
+- resid = DEVESIZE (otherdev) - CFG_ENV_SIZE;
+- if (resid) {
+- if ((data = malloc (resid)) == NULL) {
+- fprintf (stderr,
+- "Cannot malloc %d bytes: %s\n",
+- resid,
+- strerror (errno));
+- return (-1);
+- }
+- if (lseek (fdr, DEVOFFSET (otherdev) + CFG_ENV_SIZE, SEEK_SET)
+- == -1) {
+- fprintf (stderr, "seek error on %s: %s\n",
+- DEVNAME (otherdev),
+- strerror (errno));
+- return (-1);
+- }
+- if ((rc = read (fdr, data, resid)) != resid) {
+- fprintf (stderr,
+- "read error on %s: %s\n",
+- DEVNAME (otherdev),
+- strerror (errno));
+- return (-1);
+- }
++ if (rc) { /* block is bad */
++ blockstart += blocklen;
++ continue;
+ }
+
+- printf ("Erasing old environment...\n");
++ /*
++ * If a block is bad, we retry in the next block at the same
++ * offset - see common/env_nand.c::writeenv()
++ */
++ lseek (fd, blockstart + block_seek, SEEK_SET);
+
+- erase.length = DEVESIZE (otherdev);
+- erase.start = DEVOFFSET (otherdev);
+- if (ioctl (fdr, MEMERASE, &erase) != 0) {
+- fprintf (stderr, "MTD erase error on %s: %s\n",
+- DEVNAME (otherdev),
+- strerror (errno));
+- return (-1);
++ rc = read (fd, buf + processed, readlen);
++ if (rc != readlen) {
++ fprintf (stderr, "Read error on %s: %s\n",
++ DEVNAME (dev), strerror (errno));
++ return -1;
+ }
++#ifdef DEBUG
++ fprintf (stderr, "Read 0x%x bytes at 0x%llx\n",
++ rc, blockstart + block_seek);
++#endif
++ processed += readlen;
++ readlen = min (blocklen, count - processed);
++ block_seek = 0;
++ blockstart += blocklen;
++ }
++
++ return processed;
++}
++
++/*
++ * Write count bytes at offset, but stay within ENVSETCORS (dev) sectors of
++ * DEVOFFSET (dev). Similar to the read case above, on NOR we erase and write
++ * the whole data at once.
++ */
++static int flash_write_buf (int dev, int fd, void *buf, size_t count,
++ off_t offset, uint8_t mtd_type)
++{
++ void *data;
++ struct erase_info_user erase;
++ size_t blocklen; /* length of NAND block / NOR erase sector */
++ size_t erase_len; /* whole area that can be erased - may include
++ bad blocks */
++ size_t erasesize; /* erase / write length - one block on NAND,
++ whole area on NOR */
++ size_t processed = 0; /* progress counter */
++ size_t write_total; /* total size to actually write - excludinig
++ bad blocks */
++ off_t erase_offset; /* offset to the first erase block (aligned)
++ below offset */
++ off_t block_seek; /* offset inside the erase block to the start
++ of the data */
++ off_t top_of_range; /* end of the last block we may use */
++ loff_t blockstart; /* running start of the current block -
++ MEMGETBADBLOCK needs 64 bits */
++ int rc;
++
++ blocklen = DEVESIZE (dev);
++
++ /* Erase sector size is always a power of 2 */
++ top_of_range = (DEVOFFSET (dev) & ~(blocklen - 1)) +
++ ENVSECTORS (dev) * blocklen;
+
+- printf ("Done\n");
++ erase_offset = offset & ~(blocklen - 1);
+
+- printf ("Writing environment to %s...\n", DEVNAME (otherdev));
+- if (lseek (fdr, DEVOFFSET (otherdev), SEEK_SET) == -1) {
++ /* Maximum area we may use */
++ erase_len = top_of_range - erase_offset;
++
++ blockstart = erase_offset;
++ /* Offset inside a block */
++ block_seek = offset - erase_offset;
++
++ /*
++ * Data size we actually have to write: from the start of the block
++ * to the start of the data, then count bytes of data, and to the
++ * end of the block
++ */
++ write_total = (block_seek + count + blocklen - 1) & ~(blocklen - 1);
++
++ /*
++ * Support data anywhere within erase sectors: read out the complete
++ * area to be erased, replace the environment image, write the whole
++ * block back again.
++ */
++ if (write_total > count) {
++ data = malloc (erase_len);
++ if (!data) {
+ fprintf (stderr,
+- "seek error on %s: %s\n",
+- DEVNAME (otherdev), strerror (errno));
+- return (-1);
++ "Cannot malloc %u bytes: %s\n",
++ erase_len, strerror (errno));
++ return -1;
+ }
+- if (write (fdr, &environment, len) != len) {
+- fprintf (stderr,
+- "CRC write error on %s: %s\n",
+- DEVNAME (otherdev), strerror (errno));
+- return (-1);
++
++ rc = flash_read_buf (dev, fd, data, write_total, erase_offset,
++ mtd_type);
++ if (write_total != rc)
++ return -1;
++
++ /* Overwrite the old environment */
++ memcpy (data + block_seek, buf, count);
++ } else {
++ /*
++ * We get here, iff offset is block-aligned and count is a
++ * multiple of blocklen - see write_total calculation above
++ */
++ data = buf;
++ }
++
++ if (mtd_type == MTD_NANDFLASH) {
++ /*
++ * NAND: calculate which blocks we are writing. We have
++ * to write one block at a time to skip bad blocks.
++ */
++ erasesize = blocklen;
++ } else {
++ erasesize = erase_len;
++ }
++
++ erase.length = erasesize;
++
++ /* This only runs once on NOR flash */
++ while (processed < write_total) {
++ rc = flash_bad_block (fd, mtd_type, &blockstart);
++ if (rc < 0) /* block test failed */
++ return rc;
++
++ if (blockstart + erasesize > top_of_range) {
++ fprintf (stderr, "End of range reached, aborting\n");
++ return -1;
+ }
+- if (write (fdr, environment.data, ENV_SIZE) != ENV_SIZE) {
++
++ if (rc) { /* block is bad */
++ blockstart += blocklen;
++ continue;
++ }
++
++ erase.start = blockstart;
++ ioctl (fd, MEMUNLOCK, &erase);
++
++ if (ioctl (fd, MEMERASE, &erase) != 0) {
++ fprintf (stderr, "MTD erase error on %s: %s\n",
++ DEVNAME (dev),
++ strerror (errno));
++ return -1;
++ }
++
++ if (lseek (fd, blockstart, SEEK_SET) == -1) {
+ fprintf (stderr,
+- "Write error on %s: %s\n",
+- DEVNAME (otherdev), strerror (errno));
+- return (-1);
++ "Seek error on %s: %s\n",
++ DEVNAME (dev), strerror (errno));
++ return -1;
+ }
+- if (resid) {
+- if (write (fdr, data, resid) != resid) {
+- fprintf (stderr,
+- "write error on %s: %s\n",
+- DEVNAME (curdev), strerror (errno));
+- return (-1);
+- }
+- free (data);
++
++#ifdef DEBUG
++ printf ("Write 0x%x bytes at 0x%llx\n", erasesize, blockstart);
++#endif
++ if (write (fd, data + processed, erasesize) != erasesize) {
++ fprintf (stderr, "Write error on %s: %s\n",
++ DEVNAME (dev), strerror (errno));
++ return -1;
+ }
++
++ ioctl (fd, MEMLOCK, &erase);
++
++ processed += blocklen;
++ block_seek = 0;
++ blockstart += blocklen;
++ }
++
++ if (write_total > count)
++ free (data);
++
++ return processed;
++}
++
++/*
++ * Set obsolete flag at offset - NOR flash only
++ */
++static int flash_flag_obsolete (int dev, int fd, off_t offset)
++{
++ int rc;
++
++ /* This relies on the fact, that obsolete_flag == 0 */
++ rc = lseek (fd, offset, SEEK_SET);
++ if (rc < 0) {
++ fprintf (stderr, "Cannot seek to set the flag on %s \n",
++ DEVNAME (dev));
++ return rc;
++ }
++ rc = write (fd, &obsolete_flag, sizeof (obsolete_flag));
++ if (rc < 0)
++ perror ("Could not set obsolete flag");
++
++ return rc;
++}
++
++static int flash_write (int fd_current, int fd_target, int dev_target)
++{
++ int rc;
++
++ switch (environment.flag_scheme) {
++ case FLAG_NONE:
++ break;
++ case FLAG_INCREMENTAL:
++ (*environment.flags)++;
++ break;
++ case FLAG_BOOLEAN:
++ *environment.flags = active_flag;
++ break;
++ default:
++ fprintf (stderr, "Unimplemented flash scheme %u \n",
++ environment.flag_scheme);
++ return -1;
++ }
++
++#ifdef DEBUG
++ printf ("Writing new environment at 0x%lx on %s\n",
++ DEVOFFSET (dev_target), DEVNAME (dev_target));
++#endif
++ rc = flash_write_buf (dev_target, fd_target, environment.image,
++ CFG_ENV_SIZE, DEVOFFSET (dev_target),
++ DEVTYPE(dev_target));
++ if (rc < 0)
++ return rc;
++
++ if (environment.flag_scheme == FLAG_BOOLEAN) {
++ /* Have to set obsolete flag */
++ off_t offset = DEVOFFSET (dev_current) +
++ offsetof (struct env_image_redundant, flags);
++#ifdef DEBUG
++ printf ("Setting obsolete flag in environment at 0x%lx on %s\n",
++ DEVOFFSET (dev_current), DEVNAME (dev_current));
++#endif
++ flash_flag_obsolete (dev_current, fd_current, offset);
++ }
++
++ return 0;
++}
++
++static int flash_read (int fd)
++{
++ struct mtd_info_user mtdinfo;
++ int rc;
++
++ rc = ioctl (fd, MEMGETINFO, &mtdinfo);
++ if (rc < 0) {
++ perror ("Cannot get MTD information");
++ return -1;
++ }
++
++ if (mtdinfo.type != MTD_NORFLASH && mtdinfo.type != MTD_NANDFLASH) {
++ fprintf (stderr, "Unsupported flash type %u\n", mtdinfo.type);
++ return -1;
++ }
++
++ DEVTYPE(dev_current) = mtdinfo.type;
++
++ rc = flash_read_buf (dev_current, fd, environment.image, CFG_ENV_SIZE,
++ DEVOFFSET (dev_current), mtdinfo.type);
++
++ return (rc != CFG_ENV_SIZE) ? -1 : 0;
++}
++
++static int flash_io (int mode)
++{
++ int fd_current, fd_target, rc, dev_target;
++
++ /* dev_current: fd_current, erase_current */
++ fd_current = open (DEVNAME (dev_current), mode);
++ if (fd_current < 0) {
++ fprintf (stderr,
++ "Can't open %s: %s\n",
++ DEVNAME (dev_current), strerror (errno));
++ return -1;
++ }
++
++ if (mode == O_RDWR) {
+ if (HaveRedundEnv) {
+- /* change flag on current active env partition */
+- if (lseek (fd, DEVOFFSET (curdev) + sizeof (ulong), SEEK_SET)
+- == -1) {
+- fprintf (stderr, "seek error on %s: %s\n",
+- DEVNAME (curdev), strerror (errno));
+- return (-1);
+- }
+- if (write (fd, &obsolete_flag, sizeof (obsolete_flag)) !=
+- sizeof (obsolete_flag)) {
++ /* switch to next partition for writing */
++ dev_target = !dev_current;
++ /* dev_target: fd_target, erase_target */
++ fd_target = open (DEVNAME (dev_target), mode);
++ if (fd_target < 0) {
+ fprintf (stderr,
+- "Write error on %s: %s\n",
+- DEVNAME (curdev), strerror (errno));
+- return (-1);
++ "Can't open %s: %s\n",
++ DEVNAME (dev_target),
++ strerror (errno));
++ rc = -1;
++ goto exit;
+ }
++ } else {
++ dev_target = dev_current;
++ fd_target = fd_current;
+ }
+- printf ("Done\n");
+- printf ("Locking ...\n");
+- erase.length = DEVESIZE (otherdev);
+- erase.start = DEVOFFSET (otherdev);
+- ioctl (fdr, MEMLOCK, &erase);
++
++ rc = flash_write (fd_current, fd_target, dev_target);
++
+ if (HaveRedundEnv) {
+- erase.length = DEVESIZE (curdev);
+- erase.start = DEVOFFSET (curdev);
+- ioctl (fd, MEMLOCK, &erase);
+- if (close (fdr)) {
++ if (close (fd_target)) {
+ fprintf (stderr,
+ "I/O error on %s: %s\n",
+- DEVNAME (otherdev),
++ DEVNAME (dev_target),
+ strerror (errno));
+- return (-1);
++ rc = -1;
+ }
+ }
+- printf ("Done\n");
+ } else {
+-
+- if (lseek (fd, DEVOFFSET (curdev), SEEK_SET) == -1) {
+- fprintf (stderr,
+- "seek error on %s: %s\n",
+- DEVNAME (curdev), strerror (errno));
+- return (-1);
+- }
+- if (read (fd, &environment, len) != len) {
+- fprintf (stderr,
+- "CRC read error on %s: %s\n",
+- DEVNAME (curdev), strerror (errno));
+- return (-1);
+- }
+- if ((rc = read (fd, environment.data, ENV_SIZE)) != ENV_SIZE) {
+- fprintf (stderr,
+- "Read error on %s: %s\n",
+- DEVNAME (curdev), strerror (errno));
+- return (-1);
+- }
++ rc = flash_read (fd_current);
+ }
+
+- if (close (fd)) {
++exit:
++ if (close (fd_current)) {
+ fprintf (stderr,
+- "I/O error on %s: %s\n",
+- DEVNAME (curdev), strerror (errno));
+- return (-1);
++ "I/O error on %s: %s\n",
++ DEVNAME (dev_current), strerror (errno));
++ return -1;
+ }
+
+- /* everything ok */
+- return (0);
++ return rc;
+ }
+
+ /*
+@@ -585,10 +865,10 @@ static char *envmatch (char * s1, char * s2)
+
+ while (*s1 == *s2++)
+ if (*s1++ == '=')
+- return (s2);
++ return s2;
+ if (*s1 == '\0' && *(s2 - 1) == '=')
+- return (s2);
+- return (NULL);
++ return s2;
++ return NULL;
+ }
+
+ /*
+@@ -596,108 +876,156 @@ static char *envmatch (char * s1, char * s2)
+ */
+ static int env_init (void)
+ {
++ int crc0, crc0_ok;
++ char flag0;
++ void *addr0;
++
+ int crc1, crc1_ok;
+- char *addr1;
++ char flag1;
++ void *addr1;
+
+- int crc2, crc2_ok;
+- char flag1, flag2, *addr2;
++ struct env_image_single *single;
++ struct env_image_redundant *redundant;
+
+ if (parse_config ()) /* should fill envdevices */
+- return 1;
++ return -1;
+
+- if ((addr1 = calloc (1, ENV_SIZE)) == NULL) {
++ addr0 = calloc (1, CFG_ENV_SIZE);
++ if (addr0 == NULL) {
+ fprintf (stderr,
+ "Not enough memory for environment (%ld bytes)\n",
+- ENV_SIZE);
+- return (errno);
++ CFG_ENV_SIZE);
++ return -1;
+ }
+
+ /* read environment from FLASH to local buffer */
+- environment.data = addr1;
+- curdev = 0;
+- if (flash_io (O_RDONLY)) {
+- return (errno);
++ environment.image = addr0;
++
++ if (HaveRedundEnv) {
++ redundant = addr0;
++ environment.crc = &redundant->crc;
++ environment.flags = &redundant->flags;
++ environment.data = redundant->data;
++ } else {
++ single = addr0;
++ environment.crc = &single->crc;
++ environment.flags = NULL;
++ environment.data = single->data;
+ }
+
+- crc1_ok = ((crc1 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE))
+- == environment.crc);
++ dev_current = 0;
++ if (flash_io (O_RDONLY))
++ return -1;
++
++ crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE);
++ crc0_ok = (crc0 == *environment.crc);
+ if (!HaveRedundEnv) {
+- if (!crc1_ok) {
++ if (!crc0_ok) {
+ fprintf (stderr,
+ "Warning: Bad CRC, using default environment\n");
+ memcpy(environment.data, default_environment, sizeof default_environment);
+ }
+ } else {
+- flag1 = environment.flags;
++ flag0 = *environment.flags;
+
+- curdev = 1;
+- if ((addr2 = calloc (1, ENV_SIZE)) == NULL) {
++ dev_current = 1;
++ addr1 = calloc (1, CFG_ENV_SIZE);
++ if (addr1 == NULL) {
+ fprintf (stderr,
+ "Not enough memory for environment (%ld bytes)\n",
+- ENV_SIZE);
+- return (errno);
++ CFG_ENV_SIZE);
++ return -1;
+ }
+- environment.data = addr2;
++ redundant = addr1;
+
+- if (flash_io (O_RDONLY)) {
+- return (errno);
++ /*
++ * have to set environment.image for flash_read(), careful -
++ * other pointers in environment still point inside addr0
++ */
++ environment.image = addr1;
++ if (flash_io (O_RDONLY))
++ return -1;
++
++ /* Check flag scheme compatibility */
++ if (DEVTYPE(dev_current) == MTD_NORFLASH &&
++ DEVTYPE(!dev_current) == MTD_NORFLASH) {
++ environment.flag_scheme = FLAG_BOOLEAN;
++ } else if (DEVTYPE(dev_current) == MTD_NANDFLASH &&
++ DEVTYPE(!dev_current) == MTD_NANDFLASH) {
++ environment.flag_scheme = FLAG_INCREMENTAL;
++ } else {
++ fprintf (stderr, "Incompatible flash types!\n");
++ return -1;
+ }
+
+- crc2_ok = ((crc2 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE))
+- == environment.crc);
+- flag2 = environment.flags;
+-
+- if (crc1_ok && !crc2_ok) {
+- environment.data = addr1;
+- environment.flags = flag1;
+- environment.crc = crc1;
+- curdev = 0;
+- free (addr2);
+- } else if (!crc1_ok && crc2_ok) {
+- environment.data = addr2;
+- environment.flags = flag2;
+- environment.crc = crc2;
+- curdev = 1;
+- free (addr1);
+- } else if (!crc1_ok && !crc2_ok) {
++ crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE);
++ crc1_ok = (crc1 == redundant->crc);
++ flag1 = redundant->flags;
++
++ if (crc0_ok && !crc1_ok) {
++ dev_current = 0;
++ } else if (!crc0_ok && crc1_ok) {
++ dev_current = 1;
++ } else if (!crc0_ok && !crc1_ok) {
+ fprintf (stderr,
+ "Warning: Bad CRC, using default environment\n");
+- memcpy(environment.data, default_environment, sizeof default_environment);
+- curdev = 0;
+- free (addr1);
+- } else if (flag1 == active_flag && flag2 == obsolete_flag) {
+- environment.data = addr1;
+- environment.flags = flag1;
+- environment.crc = crc1;
+- curdev = 0;
+- free (addr2);
+- } else if (flag1 == obsolete_flag && flag2 == active_flag) {
+- environment.data = addr2;
+- environment.flags = flag2;
+- environment.crc = crc2;
+- curdev = 1;
+- free (addr1);
+- } else if (flag1 == flag2) {
+- environment.data = addr1;
+- environment.flags = flag1;
+- environment.crc = crc1;
+- curdev = 0;
+- free (addr2);
+- } else if (flag1 == 0xFF) {
+- environment.data = addr1;
+- environment.flags = flag1;
+- environment.crc = crc1;
+- curdev = 0;
+- free (addr2);
+- } else if (flag2 == 0xFF) {
+- environment.data = addr2;
+- environment.flags = flag2;
+- environment.crc = crc2;
+- curdev = 1;
++ memcpy (environment.data, default_environment,
++ sizeof default_environment);
++ dev_current = 0;
++ } else {
++ switch (environment.flag_scheme) {
++ case FLAG_BOOLEAN:
++ if (flag0 == active_flag &&
++ flag1 == obsolete_flag) {
++ dev_current = 0;
++ } else if (flag0 == obsolete_flag &&
++ flag1 == active_flag) {
++ dev_current = 1;
++ } else if (flag0 == flag1) {
++ dev_current = 0;
++ } else if (flag0 == 0xFF) {
++ dev_current = 0;
++ } else if (flag1 == 0xFF) {
++ dev_current = 1;
++ } else {
++ dev_current = 0;
++ }
++ break;
++ case FLAG_INCREMENTAL:
++ if ((flag0 == 255 && flag1 == 0) ||
++ flag1 > flag0)
++ dev_current = 1;
++ else if ((flag1 == 255 && flag0 == 0) ||
++ flag0 > flag1)
++ dev_current = 0;
++ else /* flags are equal - almost impossible */
++ dev_current = 0;
++ break;
++ default:
++ fprintf (stderr, "Unknown flag scheme %u \n",
++ environment.flag_scheme);
++ return -1;
++ }
++ }
++
++ /*
++ * If we are reading, we don't need the flag and the CRC any
++ * more, if we are writing, we will re-calculate CRC and update
++ * flags before writing out
++ */
++ if (dev_current) {
++ environment.image = addr1;
++ environment.crc = &redundant->crc;
++ environment.flags = &redundant->flags;
++ environment.data = redundant->data;
++ free (addr0);
++ } else {
++ environment.image = addr0;
++ /* Other pointers are already set */
+ free (addr1);
+ }
+ }
+- return (0);
++ return 0;
+ }
+
+
+@@ -710,18 +1038,20 @@ static int parse_config ()
+ if (get_config (CONFIG_FILE)) {
+ fprintf (stderr,
+ "Cannot parse config file: %s\n", strerror (errno));
+- return 1;
++ return -1;
+ }
+ #else
+ strcpy (DEVNAME (0), DEVICE1_NAME);
+ DEVOFFSET (0) = DEVICE1_OFFSET;
+ ENVSIZE (0) = ENV1_SIZE;
+ DEVESIZE (0) = DEVICE1_ESIZE;
++ ENVSECTORS (0) = DEVICE1_ENVSECTORS;
+ #ifdef HAVE_REDUND
+ strcpy (DEVNAME (1), DEVICE2_NAME);
+ DEVOFFSET (1) = DEVICE2_OFFSET;
+ ENVSIZE (1) = ENV2_SIZE;
+ DEVESIZE (1) = DEVICE2_ESIZE;
++ ENVSECTORS (1) = DEVICE2_ENVSECTORS;
+ HaveRedundEnv = 1;
+ #endif
+ #endif
+@@ -729,14 +1059,14 @@ static int parse_config ()
+ fprintf (stderr,
+ "Cannot access MTD device %s: %s\n",
+ DEVNAME (0), strerror (errno));
+- return 1;
++ return -1;
+ }
+
+ if (HaveRedundEnv && stat (DEVNAME (1), &st)) {
+ fprintf (stderr,
+ "Cannot access MTD device %s: %s\n",
+ DEVNAME (1), strerror (errno));
+- return 1;
++ return -1;
+ }
+ return 0;
+ }
+@@ -749,21 +1079,28 @@ static int get_config (char *fname)
+ int rc;
+ char dump[128];
+
+- if ((fp = fopen (fname, "r")) == NULL) {
+- return 1;
+- }
+-
+- while ((i < 2) && ((rc = fscanf (fp, "%s %lx %lx %lx",
+- DEVNAME (i),
+- &DEVOFFSET (i),
+- &ENVSIZE (i),
+- &DEVESIZE (i) )) != EOF)) {
++ fp = fopen (fname, "r");
++ if (fp == NULL)
++ return -1;
+
++ while (i < 2 && fgets (dump, sizeof (dump), fp)) {
+ /* Skip incomplete conversions and comment strings */
+- if ((rc < 3) || (*DEVNAME (i) == '#')) {
+- fgets (dump, sizeof (dump), fp); /* Consume till end */
++ if (dump[0] == '#')
+ continue;
+- }
++
++ rc = sscanf (dump, "%s %lx %lx %lx %lx",
++ DEVNAME (i),
++ &DEVOFFSET (i),
++ &ENVSIZE (i),
++ &DEVESIZE (i),
++ &ENVSECTORS (i));
++
++ if (rc < 4)
++ continue;
++
++ if (rc < 5)
++ /* Default - 1 sector */
++ ENVSECTORS (i) = 1;
+
+ i++;
+ }
+@@ -772,7 +1109,7 @@ static int get_config (char *fname)
+ HaveRedundEnv = i - 1;
+ if (!i) { /* No valid entries found */
+ errno = EINVAL;
+- return 1;
++ return -1;
+ } else
+ return 0;
+ }
+diff --git a/tools/env/fw_env.config b/tools/env/fw_env.config
+index 2432bd8..0fe37c9 100644
+--- a/tools/env/fw_env.config
++++ b/tools/env/fw_env.config
+@@ -1,7 +1,11 @@
+ # Configuration file for fw_(printenv/saveenv) utility.
+ # Up to two entries are valid, in this case the redundand
+ # environment sector is assumed present.
++# Notice, that the "Number of sectors" is ignored on NOR.
+
+-# MTD device name Device offset Env. size Flash sector size
++# MTD device name Device offset Env. size Flash sector size Number of sectors
+ /dev/mtd1 0x0000 0x4000 0x4000
+ /dev/mtd2 0x0000 0x4000 0x4000
++
++# NAND example
++#/dev/mtd0 0x4000 0x4000 0x20000 2
hooks/post-receive
--
armadeus
|