Index: package/mtd/src/fis.c
===================================================================
--- package/mtd/src/fis.c	(revision 20862)
+++ package/mtd/src/fis.c	(working copy)
@@ -42,51 +42,29 @@
 	struct fis_image_crc crc;
 } __attribute__((packed));
 
-static int fis_fd = -1;
+static struct mtd_device *fisdev = NULL;
 static struct fis_image_desc *fis_desc;
-static int fis_erasesize = 0;
 
 static void
 fis_close(void)
 {
-	if (fis_desc)
-		munmap(fis_desc, fis_erasesize);
-
-	if (fis_fd >= 0)
-		close(fis_fd);
-
-	fis_fd = -1;
+	mtd_close(fisdev);
+	fisdev = NULL;
 	fis_desc = NULL;
 }
 
 static struct fis_image_desc *
 fis_open(void)
 {
-	struct fis_image_desc *desc;
-
-	if (fis_fd >= 0)
+	if (fisdev)
 		fis_close();
 
-	fis_fd = mtd_check_open("FIS directory");
-	if (fis_fd < 0)
-		goto error;
+	fisdev = mtd_open("FIS directory", true);
+	if (!fisdev)
+		return NULL;
 
-	close(fis_fd);
-	fis_fd = mtd_open("FIS directory", true);
-	if (fis_fd < 0)
-		goto error;
-
-	fis_erasesize = erasesize;
-	desc = mmap(NULL, erasesize, PROT_READ|PROT_WRITE, MAP_SHARED, fis_fd, 0);
-	if (desc == MAP_FAILED)
-		goto error;
-
-	fis_desc = desc;
-	return desc;
-
-error:
-	fis_close();
-	return NULL;
+	fis_desc = fisdev->mmap;;
+	return fis_desc;
 }
 
 int
@@ -110,7 +88,7 @@
 	}
 
 	end = desc;
-	end = (char *) end + fis_erasesize;
+	end = (char *) end + fisdev->info.erasesize;
 	while ((void *) desc < end) {
 		if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff))
 			break;
@@ -157,7 +135,7 @@
 		fprintf(stderr, "Updating FIS table... \n");
 
 	start = (char *) desc;
-	end = (char *) desc + fis_erasesize;
+	end = (char *) desc + fisdev->info.erasesize;
 	while ((char *) desc < end) {
 		if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff))
 			break;
@@ -245,7 +223,7 @@
 		size -= desc->hdr.size;
 	}
 
-	msync(fis_desc, fis_erasesize, MS_SYNC|MS_INVALIDATE);
+	msync(fis_desc, fisdev->info.erasesize, MS_SYNC|MS_INVALIDATE);
 	fis_close();
 
 	return 0;
Index: package/mtd/src/mtd.c
===================================================================
--- package/mtd/src/mtd.c	(revision 20862)
+++ package/mtd/src/mtd.c	(working copy)
@@ -1,8 +1,9 @@
 /*
  * mtd - simple memory technology device manipulation tool
  *
- * Copyright (C) 2005      Waldemar Brodkorb <wbx@dass-it.de>,
+ * Copyright (C) 2005      Waldemar Brodkorb <wbx@dass-it.de>
  * Copyright (C) 2005-2009 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2010 Bernhard Loos <bernhardloos@googlemail.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License v2
@@ -21,7 +22,6 @@
  * The code is based on the linux-mtd examples.
  */
 
-#include <limits.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -31,350 +31,68 @@
 #include <sys/syscall.h>
 #include <fcntl.h>
 #include <errno.h>
-#include <error.h>
-#include <time.h>
 #include <string.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
 #include <sys/reboot.h>
 #include <linux/reboot.h>
-#include "mtd-api.h"
 #include "fis.h"
 #include "mtd.h"
-#include "crc32.h"
 
 #define MAX_ARGS 8
 #define JFFS2_DEFAULT_DIR	"" /* directory name without /, empty means root dir */
 
-#if __BYTE_ORDER == __BIG_ENDIAN
-#define STORE32_LE(X)           ((((X) & 0x000000FF) << 24) | (((X) & 0x0000FF00) << 8) | (((X) & 0x00FF0000) >> 8) | (((X) & 0xFF000000) >> 24))
-#elif __BYTE_ORDER == __LITTLE_ENDIAN
-#define STORE32_LE(X)           (X)
-#else
-#error unkown endianness!
-#endif
-
-ssize_t pread(int fd, void *buf, size_t count, off_t offset);
-ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
-
-#define TRX_MAGIC       0x30524448      /* "HDR0" */
-struct trx_header {
-	uint32_t magic;		/* "HDR0" */
-	uint32_t len;		/* Length of file including header */
-	uint32_t crc32;		/* 32-bit CRC from flag_version to end of file */
-	uint32_t flag_version;	/* 0:15 flags, 16:31 version */
-	uint32_t offsets[3];    /* Offsets of partitions from start of header */
-};
-
 static char *buf = NULL;
 static char *imagefile = NULL;
 static char *jffs2file = NULL, *jffs2dir = JFFS2_DEFAULT_DIR;
 static int buflen = 0;
 int quiet;
-int mtdsize = 0;
-int erasesize = 0;
 
-int mtd_open(const char *mtd, bool block)
-{
-	FILE *fp;
-	char dev[PATH_MAX];
-	int i;
-	int ret;
-	int flags = O_RDWR | O_SYNC;
+struct platform_imageops imageops __attribute__((weak)) = {
+	.firmware_partition = "firmware"
+};
 
-	if ((fp = fopen("/proc/mtd", "r"))) {
-		while (fgets(dev, sizeof(dev), fp)) {
-			if (sscanf(dev, "mtd%d:", &i) && strstr(dev, mtd)) {
-				snprintf(dev, sizeof(dev), "/dev/mtd%s/%d", (block ? "block" : ""), i);
-				if ((ret=open(dev, flags))<0) {
-					snprintf(dev, sizeof(dev), "/dev/mtd%s%d", (block ? "block" : ""), i);
-					ret=open(dev, flags);
-				}
-				fclose(fp);
-				return ret;
-			}
-		}
-		fclose(fp);
-	}
-
-	return open(mtd, flags);
-}
-
-int mtd_check_open(const char *mtd)
-{
-	struct mtd_info_user mtdInfo;
-	int fd;
-
-	fd = mtd_open(mtd, false);
-	if(fd < 0) {
-		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
-		return -1;
-	}
-
-	if(ioctl(fd, MEMGETINFO, &mtdInfo)) {
-		fprintf(stderr, "Could not get MTD device info from %s\n", mtd);
-		close(fd);
-		return -1;
-	}
-	mtdsize = mtdInfo.size;
-	erasesize = mtdInfo.erasesize;
-
-	return fd;
-}
-
-int mtd_erase_block(int fd, int offset)
-{
-	struct erase_info_user mtdEraseInfo;
-
-	mtdEraseInfo.start = offset;
-	mtdEraseInfo.length = erasesize;
-	ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
-	if (ioctl (fd, MEMERASE, &mtdEraseInfo) < 0)
-		return -1;
-
-	return 0;
-}
-
-int mtd_write_buffer(int fd, const char *buf, int offset, int length)
-{
-	lseek(fd, offset, SEEK_SET);
-	write(fd, buf, length);
-	return 0;
-}
-
-
 static int
-image_check(int imagefd, const char *mtd)
+cmd_erase(struct mtd_device **mtddevs)
 {
-	int ret = 1;
-#ifdef target_brcm
-	ret = trx_check(imagefd, mtd, buf, &buflen);
-#endif
-	return ret;
-}
-
-static int mtd_check(const char *mtd)
-{
-	char *next = NULL;
-	char *str = NULL;
-	int fd;
-
-	if (strchr(mtd, ':')) {
-		str = strdup(mtd);
-		mtd = str;
-	}
-
-	do {
-		next = strchr(mtd, ':');
-		if (next) {
-			*next = 0;
-			next++;
-		}
-
-		fd = mtd_check_open(mtd);
-		if (fd < 0)
-			return 0;
-
-		if (!buf)
-			buf = malloc(erasesize);
-
-		close(fd);
-		mtd = next;
-	} while (next);
-
-	if (str)
-		free(str);
-
-	return 1;
-}
-
-static int
-mtd_unlock(const char *mtd)
-{
-	struct erase_info_user mtdLockInfo;
-	char *next = NULL;
-	char *str = NULL;
-	int fd;
-
-	if (strchr(mtd, ':')) {
-		str = strdup(mtd);
-		mtd = str;
-	}
-
-	do {
-		next = strchr(mtd, ':');
-		if (next) {
-			*next = 0;
-			next++;
-		}
-
-		fd = mtd_check_open(mtd);
-		if(fd < 0) {
-			fprintf(stderr, "Could not open mtd device: %s\n", mtd);
-			exit(1);
-		}
-
+	int i = 0;
+	int ret;
+	
+	while (mtddevs[i]) {
 		if (quiet < 2)
-			fprintf(stderr, "Unlocking %s ...\n", mtd);
-
-		mtdLockInfo.start = 0;
-		mtdLockInfo.length = mtdsize;
-		ioctl(fd, MEMUNLOCK, &mtdLockInfo);
-		close(fd);
-		mtd = next;
-	} while (next);
-
-	if (str)
-		free(str);
-
-	return 0;
-}
-
-static int
-mtd_erase(const char *mtd)
-{
-	int fd;
-	struct erase_info_user mtdEraseInfo;
-
-	if (quiet < 2)
-		fprintf(stderr, "Erasing %s ...\n", mtd);
-
-	fd = mtd_check_open(mtd);
-	if(fd < 0) {
-		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
-		exit(1);
+			fprintf(stderr, "Erasing %s ...\n", mtddevs[i]->name);
+		
+		ret = mtd_erase(mtddevs[i++]);
+		if (ret < 0)
+			return ret;
 	}
-
-	mtdEraseInfo.length = erasesize;
-
-	for (mtdEraseInfo.start = 0;
-		 mtdEraseInfo.start < mtdsize;
-		 mtdEraseInfo.start += erasesize) {
-
-		ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
-		if(ioctl(fd, MEMERASE, &mtdEraseInfo))
-			fprintf(stderr, "Failed to erase block on %s at 0x%x\n", mtd, mtdEraseInfo.start);
-	}
-
-	close(fd);
+	
 	return 0;
-
 }
 
 static int
-mtd_fixtrx(const char *mtd, size_t offset)
+cmd_refresh(struct mtd_device **mtddevs)
 {
-	int fd;
-	struct trx_header *trx;
-	char *buf;
-	ssize_t res;
-	size_t block_offset;
-
-	if (quiet < 2)
-		fprintf(stderr, "Trying to fix trx header in %s at 0x%x...\n", mtd, offset);
-
-	block_offset = offset & ~(erasesize - 1);
-	offset -= block_offset;
-
-	fd = mtd_check_open(mtd);
-	if(fd < 0) {
-		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
-		exit(1);
-	}
-
-	if (block_offset + erasesize > mtdsize) {
-		fprintf(stderr, "Offset too large, device size 0x%x\n", mtdsize);
-		exit(1);
-	}
-
-	buf = malloc(erasesize);
-	if (!buf) {
-		perror("malloc");
-		exit(1);
-	}
-
-	res = pread(fd, buf, erasesize, block_offset);
-	if (res != erasesize) {
-		perror("pread");
-		exit(1);
-	}
-
-	trx = (struct trx_header *) (buf + offset);
-	if (trx->magic != STORE32_LE(0x30524448)) {
-		fprintf(stderr, "No trx magic found\n");
-		exit(1);
-	}
-
-	if (trx->len == STORE32_LE(erasesize - offset)) {
+	int i = 0;
+	int ret;
+	
+	while (mtddevs[i]) {
 		if (quiet < 2)
-			fprintf(stderr, "Header already fixed, exiting\n");
-		close(fd);
-		return 0;
+			fprintf(stderr, "Refreshing mtd partition %s ... \n", mtddevs[i]->name);
+		
+		ret = ioctl(mtddevs[i++]->fd, MTDREFRESH, NULL);
+		if (ret < 0)
+			return ret;
 	}
-
-	trx->len = STORE32_LE(erasesize - offset);
-
-	trx->crc32 = STORE32_LE(crc32buf((char*) &trx->flag_version, erasesize - offset - 3*4));
-	if (mtd_erase_block(fd, block_offset)) {
-		fprintf(stderr, "Can't erease block at 0x%x (%s)\n", block_offset, strerror(errno));
-		exit(1);
-	}
-
-	if (quiet < 2)
-		fprintf(stderr, "New crc32: 0x%x, rewriting block\n", trx->crc32);
-
-	if (pwrite(fd, buf, erasesize, block_offset) != erasesize) {
-		fprintf(stderr, "Error writing block (%s)\n", strerror(errno));
-		exit(1);
-	}
-
-	if (quiet < 2)
-		fprintf(stderr, "Done.\n");
-
-	close (fd);
-	sync();
+	
 	return 0;
-
 }
 
 static int
-mtd_refresh(const char *mtd)
+cmd_write(int imagefd, struct mtd_device **mtddevs, char *fis_layout)
 {
-	int fd;
-
-	if (quiet < 2)
-		fprintf(stderr, "Refreshing mtd partition %s ... ", mtd);
-
-	fd = mtd_check_open(mtd);
-	if(fd < 0) {
-		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
-		exit(1);
-	}
-
-	if (ioctl(fd, MTDREFRESH, NULL)) {
-		fprintf(stderr, "Failed to refresh the MTD device\n");
-		close(fd);
-		exit(1);
-	}
-	close(fd);
-
-	if (quiet < 2)
-		fprintf(stderr, "\n");
-
-	return 0;
-}
-
-static int
-mtd_write(int imagefd, const char *mtd, char *fis_layout)
-{
-	char *next = NULL;
-	char *str = NULL;
-	int fd, result;
+	int result;
 	ssize_t r, w, e;
 	uint32_t offset = 0;
+	int i;
 
 #ifdef FIS_SUPPORT
 	static struct fis_part new_parts[MAX_ARGS];
@@ -382,24 +100,19 @@
 	int n_new = 0, n_old = 0;
 
 	if (fis_layout) {
-		const char *tmp = mtd;
+		const char *tmp;
 		char *word, *brkt;
 		int ret;
 
 		memset(&old_parts, 0, sizeof(old_parts));
 		memset(&new_parts, 0, sizeof(new_parts));
 
-		do {
-			next = strchr(tmp, ':');
-			if (!next)
-				next = (char *) tmp + strlen(tmp);
+		i = 0;
+		while (mtddevs[i]) {
+			memcpy(old_parts[n_old++].name, mtddevs[i]->name, strlen(mtddevs[i]->name));
+			i++;
+		}
 
-			memcpy(old_parts[n_old].name, tmp, next - tmp);
-
-			n_old++;
-			tmp = next + 1;
-		} while(*next);
-
 		for (word = strtok_r(fis_layout, ",", &brkt);
 		     word;
 			 word = strtok_r(NULL, ",", &brkt)) {
@@ -431,28 +144,11 @@
 	}
 #endif
 
-	if (strchr(mtd, ':')) {
-		str = strdup(mtd);
-		mtd = str;
-	}
-
 	r = 0;
-
+	i = 0;
 resume:
-	next = strchr(mtd, ':');
-	if (next) {
-		*next = 0;
-		next++;
-	}
-
-	fd = mtd_check_open(mtd);
-	if(fd < 0) {
-		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
-		exit(1);
-	}
-
 	if (quiet < 2)
-		fprintf(stderr, "Writing from %s to %s ... ", imagefile, mtd);
+		fprintf(stderr, "Writing from %s to %s ... ", imagefile, mtddevs[i]->name);
 
 	w = e = 0;
 	if (!quiet)
@@ -460,8 +156,8 @@
 
 	for (;;) {
 		/* buffer may contain data already (from trx check or last mtd partition write attempt) */
-		while (buflen < erasesize) {
-			r = read(imagefd, buf + buflen, erasesize - buflen);
+		while (buflen < mtddevs[i]->info.erasesize) {
+			r = read(imagefd, buf + buflen, mtddevs[i]->info.erasesize - buflen);
 			if (r < 0) {
 				if ((errno == EINTR) || (errno == EAGAIN))
 					continue;
@@ -485,9 +181,9 @@
 				if (!quiet)
 					fprintf(stderr, "\b\b\b   ");
 				if (quiet < 2)
-					fprintf(stderr, "\nAppending jffs2 data from %s to %s...", jffs2file, mtd);
+					fprintf(stderr, "\nAppending jffs2 data from %s to %s...", jffs2file, mtddevs[i]->name);
 				/* got an EOF marker - this is the place to add some jffs2 data */
-				mtd_replace_jffs2(mtd, fd, e, jffs2file);
+				mtd_replace_jffs2(mtddevs[i], e, jffs2file);
 				goto done;
 			}
 			/* no EOF marker, make sure we figure out the last inode number
@@ -501,16 +197,15 @@
 				fprintf(stderr, "\b\b\b[e]");
 
 
-			if (mtd_erase_block(fd, e) < 0) {
-				if (next) {
+			if (mtd_erase_block(mtddevs[i], e) < 0) {
+				if (mtddevs[i + 1]) {
 					if (w < e) {
-						write(fd, buf + offset, e - w);
+						write(mtddevs[i]->fd, buf + offset, e - w);
 						offset = e - w;
 					}
 					w = 0;
 					e = 0;
-					close(fd);
-					mtd = next;
+					i++;
 					fprintf(stderr, "\b\b\b   \n");
 					goto resume;
 				} else {
@@ -520,13 +215,13 @@
 			}
 
 			/* erase the chunk */
-			e += erasesize;
+			e += mtddevs[i]->info.erasesize;
 		}
 
 		if (!quiet)
 			fprintf(stderr, "\b\b\b[w]");
 
-		if ((result = write(fd, buf + offset, buflen)) < buflen) {
+		if ((result = write(mtddevs[i]->fd, buf + offset, buflen)) < buflen) {
 			if (result < 0) {
 				fprintf(stderr, "Error writing image.\n");
 				exit(1);
@@ -555,7 +250,6 @@
 	}
 #endif
 
-	close(fd);
 	return 0;
 }
 
@@ -569,7 +263,7 @@
 	"        erase                   erase all data on device\n"
 	"        write <imagefile>|-     write <imagefile> (use - for stdin) to device\n"
 	"        jffs2write <file>       append <file> to the jffs2 partition on the device\n"
-	"        fixtrx                  fix the checksum in a trx header on first boot\n"
+	"        fixcrc                  fix the checksum in the image header on first boot (device is not needed)\n"
 	"Following options are available:\n"
 	"        -q                      quiet mode (once: no [w] on writing,\n"
 	"                                           twice: no status messages)\n"
@@ -578,7 +272,6 @@
 	"        -e <device>             erase <device> before executing the command\n"
 	"        -d <name>               directory for jffs2write, defaults to \"tmp\"\n"
 	"        -j <name>               integrate <file> into jffs2 data when writing an image\n"
-	"        -o offset               offset of the trx header in the partition (for fixtrx)\n"
 #ifdef FIS_SUPPORT
 	"        -F <part>[:<size>[:<entrypoint>]][,<part>...]\n"
 	"                                alter the fis partition table to create new partitions replacing\n"
@@ -606,19 +299,19 @@
 
 int main (int argc, char **argv)
 {
-	int ch, i, boot, imagefd = 0, force, unlocked;
+	int ch, i, boot, imagefd = 0, force;
 	char *erase[MAX_ARGS], *device = NULL;
 	char *fis_layout = NULL;
-	size_t offset = 0;
+	struct mtd_device **mtddevs;
 	enum {
 		CMD_ERASE,
 		CMD_WRITE,
 		CMD_UNLOCK,
 		CMD_REFRESH,
 		CMD_JFFS2WRITE,
-		CMD_FIXTRX,
+		CMD_FIXCRC,
 	} cmd = -1;
-
+	
 	erase[0] = NULL;
 	boot = 0;
 	force = 0;
@@ -629,7 +322,7 @@
 #ifdef FIS_SUPPORT
 			"F:"
 #endif
-			"frqe:d:j:o:")) != -1)
+			"frqe:d:j:")) != -1)
 		switch (ch) {
 			case 'f':
 				force = 1;
@@ -654,14 +347,6 @@
 			case 'd':
 				jffs2dir = optarg;
 				break;
-			case 'o':
-				errno = 0;
-				offset = strtoul(optarg, 0, 0);
-				if (errno) {
-					fprintf(stderr, "-o: illegal numeric string\n");
-					usage();
-				}
-				break;
 #ifdef FIS_SUPPORT
 			case 'F':
 				fis_layout = optarg;
@@ -674,7 +359,7 @@
 	argc -= optind;
 	argv += optind;
 
-	if (argc < 2)
+	if (argc < 1)
 		usage();
 
 	if ((strcmp(argv[0], "unlock") == 0) && (argc == 2)) {
@@ -686,9 +371,28 @@
 	} else if ((strcmp(argv[0], "erase") == 0) && (argc == 2)) {
 		cmd = CMD_ERASE;
 		device = argv[1];
-	} else if ((strcmp(argv[0], "fixtrx") == 0) && (argc == 2)) {
-		cmd = CMD_FIXTRX;
-		device = argv[1];
+	} else if ((strcmp(argv[0], "fixcrc") == 0) && (argc == 1)) {
+		struct mtd_device *mtd = 0;
+		int res;
+
+		cmd = CMD_FIXCRC;
+
+		if (imageops.checkimage) {
+			mtd = mtd_open(imageops.firmware_partition, true);
+			if (!mtd)
+				exit(1);
+			if (quiet < 2)
+				fprintf(stderr, "Checking image and fixing crc ...\n");
+			res = imageops.checkimage((char *) mtd->mmap, mtd->info.erasesize, mtd->info.size);
+			if (res < 0) {
+				fprintf(stderr, "Image check failed.\n");
+				exit(1);
+			} else if (res > 0 && quiet < 2)
+				fprintf(stderr, "CRC already fixed\n");
+		}
+
+		mtd_close(mtd);
+		return 0;	/* leave early, there is nothing else to do for us */
 	} else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) {
 		cmd = CMD_WRITE;
 		device = argv[2];
@@ -703,68 +407,102 @@
 				exit(1);
 			}
 		}
-
-		if (!mtd_check(device)) {
-			fprintf(stderr, "Can't open device for writing!\n");
-			exit(1);
-		}
-		/* check trx file before erasing or writing anything */
-		if (!image_check(imagefd, device) && !force) {
-			fprintf(stderr, "Image check failed.\n");
-			exit(1);
-		}
 	} else if ((strcmp(argv[0], "jffs2write") == 0) && (argc == 3)) {
 		cmd = CMD_JFFS2WRITE;
 		device = argv[2];
 
 		imagefile = argv[1];
-		if (!mtd_check(device)) {
-			fprintf(stderr, "Can't open device for writing!\n");
-			exit(1);
-		}
 	} else {
 		usage();
 	}
 
 	sync();
 
+	mtddevs = mtd_open_multiple(device);
+	if (!mtddevs)
+		exit(1);
+	
+	buf = malloc(mtddevs[0]->info.erasesize);
+	if (!buf) {
+		perror("malloc");
+		exit(1);
+	}
+	
+	if (strcmp(device, imageops.firmware_partition) == 0 && imageops.checkimage && !force && cmd == CMD_WRITE) {
+		int res;
+		size_t mtd_length = 0;
+		int i = 0;
+
+		while (mtddevs[i])
+			mtd_length += mtddevs[i++]->info.size;
+
+		buflen = read(imagefd, buf, mtddevs[0]->info.erasesize);
+		if (buflen < mtddevs[0]->info.erasesize) {
+			fprintf(stdout, "Could not get image header, file too small (%d bytes)\n", buflen);
+			exit(1);
+		}
+
+		if (quiet < 2)
+			fprintf(stderr, "Checking image and fixing crc ...\n");
+		res = imageops.checkimage(buf, buflen, mtd_length);
+		if (res < 0) {
+			fprintf(stderr, "Image check failed.\n");
+			exit(1);
+		} else if (res > 0 && quiet < 2)
+			fprintf(stderr, "CRC already fixed\n");
+	}
+
 	i = 0;
-	unlocked = 0;
 	while (erase[i] != NULL) {
-		mtd_unlock(erase[i]);
-		mtd_erase(erase[i]);
-		if (strcmp(erase[i], device) == 0)
-			unlocked = 1;
+		struct mtd_device *erasedev;
+		int j = 0;
+		
+		while (mtddevs[j]) {
+			if (strcmp(erase[i], mtddevs[j]->name) == 0)
+				erasedev =  mtddevs[j];
+			j++;
+		}
+		if (!mtddevs[j])
+			erasedev = mtd_open(erase[i], false);
+		if (!erasedev)
+			exit(1);
+		mtd_unlock(erasedev);
+		mtd_erase(erasedev);
+		if (!mtddevs[j])
+			mtd_close(erasedev);
+
 		i++;
 	}
-
+	
+	i = 0;
+	while (mtddevs[i]) {
+		if (quiet < 2)
+			fprintf(stderr, "Unlocking %s ...\n", mtddevs[i]->name);
+		mtd_unlock(mtddevs[i++]);
+	}
+	
 	switch (cmd) {
 		case CMD_UNLOCK:
-			if (!unlocked)
-				mtd_unlock(device);
+			/* nothing to do */
 			break;
 		case CMD_ERASE:
-			if (!unlocked)
-				mtd_unlock(device);
-			mtd_erase(device);
+			cmd_erase(mtddevs);
 			break;
 		case CMD_WRITE:
-			if (!unlocked)
-				mtd_unlock(device);
-			mtd_write(imagefd, device, fis_layout);
+			cmd_write(imagefd, mtddevs, fis_layout);
 			break;
 		case CMD_JFFS2WRITE:
-			if (!unlocked)
-				mtd_unlock(device);
-			mtd_write_jffs2(device, imagefile, jffs2dir);
+			cmd_write_jffs2(mtddevs, imagefile, jffs2dir);
 			break;
 		case CMD_REFRESH:
-			mtd_refresh(device);
+			cmd_refresh(mtddevs);
 			break;
-		case CMD_FIXTRX:
-			mtd_fixtrx(device, offset);
+		case CMD_FIXCRC:
+			/* nothing to do */
 			break;
 	}
+	
+	mtd_close_multiple(mtddevs);
 
 	sync();
 
Index: package/mtd/src/mtd.h
===================================================================
--- package/mtd/src/mtd.h	(revision 20862)
+++ package/mtd/src/mtd.h	(working copy)
@@ -3,6 +3,8 @@
 
 #include <stdbool.h>
 
+#include "mtd-api.h"
+
 #ifdef target_brcm47xx
 #define target_brcm 1
 #endif
@@ -10,19 +12,30 @@
 #define JFFS2_EOF "\xde\xad\xc0\xde"
 
 extern int quiet;
-extern int mtdsize;
-extern int erasesize;
 
-extern int mtd_open(const char *mtd, bool block);
-extern int mtd_check_open(const char *mtd);
-extern int mtd_erase_block(int fd, int offset);
-extern int mtd_write_buffer(int fd, const char *buf, int offset, int length);
-extern int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir);
-extern int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename);
+struct mtd_device {
+	const char *name;
+	int fd;
+	struct mtd_info_user info;
+	int unlocked	: 1;
+	void *mmap;	/* only first eraseblock */
+};
+
+extern struct mtd_device *mtd_open(const char *mtd, bool block);
+extern struct mtd_device **mtd_open_multiple(const char *mtds);
+extern void mtd_close_multiple(struct mtd_device **mtds);
+extern void mtd_close(struct mtd_device *mtd);
+extern int mtd_erase_block(struct mtd_device *mtd, size_t offset);
+extern int mtd_erase(struct mtd_device *mtd);
+extern int mtd_unlock(struct mtd_device *mtd);
+
+extern int cmd_write_jffs2(struct mtd_device **mtds, const char *filename, const char *dir);
+extern int mtd_replace_jffs2(struct mtd_device *mtd, int ofs, const char *filename);
 extern void mtd_parse_jffs2data(const char *buf, const char *dir);
 
-/* target specific */
-extern int trx_fixup(int fd, const char *name);
-extern int trx_check(int imagefd, const char *mtd, char *buf, int *len);
+struct platform_imageops {
+	int (*checkimage)(char *imagedata, size_t datalength, size_t mtdlength);
+	const char *firmware_partition;
+};
 
 #endif /* __mtd_h */
Index: package/mtd/src/jffs2.c
===================================================================
--- package/mtd/src/jffs2.c	(revision 20862)
+++ package/mtd/src/jffs2.c	(working copy)
@@ -42,7 +42,8 @@
 static int last_version = 0;
 static char *buf = NULL;
 static int ofs = 0;
-static int outfd = -1;
+static struct mtd_device *mtddev = NULL;
+static int erasesize = 0;
 static int mtdofs = 0;
 static int target_ino = 0;
 
@@ -59,8 +60,8 @@
 	}
 	ofs = ofs % erasesize;
 	if (ofs == 0) {
-		mtd_erase_block(outfd, mtdofs);
-		write(outfd, buf, erasesize);
+		mtd_erase_block(mtddev, mtdofs);
+		write(mtddev->fd, buf, erasesize);
 		mtdofs += erasesize;
 	}
 }
@@ -227,9 +228,10 @@
 	close(fd);
 }
 
-int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename)
+int mtd_replace_jffs2(struct mtd_device *mtd, int ofs, const char *filename)
 {
-	outfd = fd;
+	mtddev = mtd;
+	erasesize = mtd->info.erasesize;
 	mtdofs = ofs;
 
 	buf = malloc(erasesize);
@@ -244,9 +246,6 @@
 	pad(erasesize);
 	free(buf);
 
-#ifdef target_brcm
-	trx_fixup(outfd, mtd);
-#endif
 	return 0;
 }
 
@@ -277,16 +276,15 @@
 	}
 }
 
-int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir)
+int cmd_write_jffs2(struct mtd_device **mtd, const char *filename, const char *dir)
 {
 	int err = -1, fdeof = 0;
 
-	outfd = mtd_check_open(mtd);
-	if (outfd < 0)
-		return -1;
+	mtddev = mtd[0];
+	erasesize = mtddev->info.erasesize;
 
 	if (quiet < 2)
-		fprintf(stderr, "Appending %s to jffs2 partition %s\n", filename, mtd);
+		fprintf(stderr, "Appending %s to jffs2 partition %s\n", filename, mtddev->name);
 	
 	buf = malloc(erasesize);
 	if (!buf) {
@@ -302,7 +300,7 @@
 	for(;;) {
 		struct jffs2_unknown_node *node = (struct jffs2_unknown_node *) buf;
 
-		if (read(outfd, buf, erasesize) != erasesize) {
+		if (read(mtddev->fd, buf, erasesize) != erasesize) {
 			fdeof = 1;
 			break;
 		}
@@ -328,7 +326,7 @@
 
 	/* jump back one eraseblock */
 	mtdofs -= erasesize;
-	lseek(outfd, mtdofs, SEEK_SET);
+	lseek(mtddev->fd, mtdofs, SEEK_SET);
 
 	ofs = 0;
 
@@ -347,12 +345,7 @@
 
 	err = 0;
 
-#ifdef target_brcm
-	trx_fixup(outfd, mtd);
-#endif
-
 done:
-	close(outfd);
 	if (buf)
 		free(buf);
 
Index: package/mtd/src/libmtd.c
===================================================================
--- package/mtd/src/libmtd.c	(revision 0)
+++ package/mtd/src/libmtd.c	(revision 0)
@@ -0,0 +1,219 @@
+/*
+ * mtd - simple memory technology device manipulation tool
+ *
+ * Copyright (C) 2005      Waldemar Brodkorb <wbx@dass-it.de>
+ * Copyright (C) 2005-2009 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2010 Bernhard Loos <bernhardloos@googlemail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License v2
+ * as published by the Free Software Foundation.
+ *
+ * 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 code is based on the linux-mtd examples.
+ */
+
+#include <limits.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#include "mtd.h"
+
+#define MULTIPLE_MAX 100
+
+struct mtd_device *mtd_open(const char *mtd, bool block)
+{
+	FILE *fp;
+	char number[3] = { 0 };
+	int flags = O_RDWR | O_SYNC;
+	struct mtd_device *mtddev;
+	char dev[PATH_MAX];
+
+	mtddev = malloc(sizeof(*mtddev));
+	if (!mtddev) {
+		perror("malloc");
+		exit(1);
+	}
+	memset(mtddev, 0, sizeof(struct mtd_device));
+
+	fp = fopen("/proc/mtd", "r");
+	if (!fp) {
+		fprintf(stderr, "Can't open /proc/mtd\n");
+		free(mtddev);
+		return NULL;
+	}
+
+	fscanf(fp, "%*[^\n]\n"); //skip fist line
+
+	while (fscanf(fp, "mtd%2[0-9]: %x %x \"%20[^\"]\"\n", number, &mtddev->info.size, &mtddev->info.erasesize, dev) == 4) {
+		if (strcmp(dev, mtd) == 0)
+			break;
+	}
+
+	fclose(fp);
+
+	mtddev->fd = -1;
+
+	if (number[0]) {
+		snprintf(dev, sizeof(dev), "/dev/mtd%s/%s", (block ? "block" : ""), number);
+		if ((mtddev->fd = open(dev, flags)) < 0) {
+			snprintf(dev, sizeof(dev), "/dev/mtd%s%s", (block ? "block" : ""), number);
+			mtddev->fd = open(dev, flags);
+		}
+	} else {
+		if (block) {
+			fprintf(stderr, "mtd_open needs a partition name for block mode, not a device\n");
+			free(mtddev);
+			return NULL;
+		}
+		open(mtd, flags);
+	}
+	
+	if(mtddev->fd < 0) {
+		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+		return NULL;
+	}
+
+	mtddev->name = mtd;
+
+	if (block) {
+			mtddev->mmap = mmap(NULL, mtddev->info.erasesize, PROT_READ|PROT_WRITE, MAP_SHARED, mtddev->fd, 0);
+			if (mtddev->mmap == MAP_FAILED) {
+				mtddev->mmap = NULL;
+				perror("mmap");
+				mtd_close(mtddev);
+				return NULL;
+			}
+	} else {
+		if(ioctl(mtddev->fd, MEMGETINFO, &mtddev->info) < 0) {
+			fprintf(stderr, "Could not get MTD device info for %s\n", mtd);
+			mtd_close(mtddev);
+			return NULL;
+		}
+	}
+
+	return mtddev;
+}
+
+int mtd_unlock(struct mtd_device *mtd)
+{
+	struct erase_info_user mtdEraseInfo;
+	
+	if (mtd->unlocked)
+		return 0;
+
+	mtdEraseInfo.start = 0;
+	mtdEraseInfo.length = mtd->info.size;
+	if (ioctl(mtd->fd, MEMUNLOCK, &mtdEraseInfo) < 0) {
+		if (errno != EOPNOTSUPP) {
+			fprintf(stderr, "Failed to unlock %s\n", mtd->name);
+			return -1;
+		}
+	}
+
+	mtd->unlocked = 1;
+
+	return 0;
+}
+
+int mtd_erase_block(struct mtd_device *mtd, size_t offset)
+{
+	struct erase_info_user mtdEraseInfo;
+
+	mtdEraseInfo.start = offset;
+	mtdEraseInfo.length = mtd->info.erasesize;
+	if (ioctl (mtd->fd, MEMERASE, &mtdEraseInfo) < 0) {
+		fprintf(stderr, "Failed to erase block on %s at 0x%x\n", mtd->name, mtdEraseInfo.start);
+		return -1;
+	}
+
+	return 0;
+}
+
+int mtd_erase(struct mtd_device *mtd)
+{
+	size_t pos = 0;
+	
+	while (pos < mtd->info.size) {
+		if (mtd_erase_block(mtd, pos) < 0)
+			return -1;
+		
+		pos += mtd->info.erasesize;
+	}
+	return 0;
+}
+
+void mtd_close(struct mtd_device *mtd)
+{
+	if (mtd->mmap)
+		munmap(mtd->mmap, mtd->info.erasesize);
+	close(mtd->fd);
+	free(mtd);
+}
+
+struct mtd_device **mtd_open_multiple(const char *mtds)
+{
+	int count = 0;
+	char *str = strdup(mtds);
+	struct mtd_device *devs[MULTIPLE_MAX];
+	char *next;
+	char *mtd = str;
+	struct mtd_device **ret;
+	
+	do {
+		next = strchr(mtd, ':');
+		if (next) {
+			*next = 0;
+			next++;
+		}
+
+		devs[count] = mtd_open(mtd, false);
+		if (!devs[count])
+			goto error;
+		count++;
+		
+		mtd = next;
+	} while (next);
+
+	devs[count] = NULL;
+	count++;
+	
+	ret = malloc(sizeof(struct mtd_device *) * count);
+	memcpy(ret, devs, sizeof(struct mtd_device *) * count);
+	
+	return ret;
+error:
+	while(count > 0) {
+		--count;
+		mtd_close(devs[count]);
+	}
+	free(str);
+	return NULL;
+}
+
+void mtd_close_multiple(struct mtd_device **mtds)
+{
+	const char *str = mtds[0]->name;
+	int pos = 0;
+	
+	while(mtds[pos])
+		mtd_close(mtds[pos++]);
+	
+	free((char *) str);
+	free(mtds);
+}
Index: package/mtd/src/Makefile
===================================================================
--- package/mtd/src/Makefile	(revision 20862)
+++ package/mtd/src/Makefile	(working copy)
@@ -1,9 +1,10 @@
 CC = gcc
 CFLAGS += -Wall
 
-obj = mtd.o jffs2.o crc32.o
+obj = mtd.o jffs2.o crc32.o libmtd.o
 obj.brcm = trx.o
 obj.brcm47xx = $(obj.brcm)
+obj.ar71xx = $(obj.brcm)
 
 ifdef FIS_SUPPORT
   obj += fis.o
Index: package/mtd/src/trx.c
===================================================================
--- package/mtd/src/trx.c	(revision 20862)
+++ package/mtd/src/trx.c	(working copy)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2005 Mike Baker
  * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2010 Bernhard Loos <bernhardloos@googlemail.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -22,17 +23,16 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stddef.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <string.h>
 
-#include <sys/ioctl.h>
-#include "mtd-api.h"
 #include "mtd.h"
 #include "crc32.h"
 
+#if __BYTE_ORDER == __BIG_ENDIAN
+#  define STORE32_LE(val) bswap_32(val)
+#else
+#  define STORE32_LE(val) (val)
+#endif
+
 #define TRX_MAGIC       0x30524448      /* "HDR0" */
 struct trx_header {
 	unsigned magic;		/* "HDR0" */
@@ -42,91 +42,44 @@
 	unsigned offsets[3];	/* Offsets of partitions from start of header */
 };
 
-int
-trx_fixup(int fd, const char *name)
+static int
+trx_check(char *imagedata, size_t datalength, size_t mtdlength)
 {
-	struct mtd_info_user mtdInfo;
-	unsigned long len;
 	struct trx_header *trx;
-	void *ptr, *scan;
-	int bfd;
 
-	if (ioctl(fd, MEMGETINFO, &mtdInfo) < 0) {
-		fprintf(stderr, "Failed to get mtd info\n");
-		goto err;
-	}
+#ifdef TARGET_ar71xx
+	imagedata += 32;	/* used on the wrt160nl */
+	datelength -= 32;
+#endif
+	trx = (struct trx_header *) imagedata;
 
-	len = mtdInfo.size;
-	if (mtdInfo.size <= 0) {
-		fprintf(stderr, "Invalid MTD device size\n");
-		goto err;
-	}
-
-	bfd = mtd_open(name, true);
-	ptr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, bfd, 0);
-	if (!ptr || (ptr == (void *) -1)) {
-		perror("mmap");
-		goto err1;
-	}
-
-	trx = ptr;
-	if (trx->magic != TRX_MAGIC) {
-		fprintf(stderr, "TRX header not found\n");
-		goto err;
-	}
-
-	scan = ptr + offsetof(struct trx_header, flag_version);
-	trx->crc32 = crc32buf(scan, trx->len - (scan - ptr));
-	msync(ptr, sizeof(struct trx_header), MS_SYNC|MS_INVALIDATE);
-	munmap(ptr, len);
-	close(bfd);
-	return 0;
-
-err1:
-	close(bfd);
-err:
-	fprintf(stderr, "Error fixing up TRX header\n");
-	return -1;
-}
-
-int
-trx_check(int imagefd, const char *mtd, char *buf, int *len)
-{
-	const struct trx_header *trx = (const struct trx_header *) buf;
-	int fd;
-
-	if (strcmp(mtd, "linux") != 0)
-		return 1;
-
-	*len = read(imagefd, buf, 32);
-	if (*len < 32) {
-		fprintf(stdout, "Could not get image header, file too small (%d bytes)\n", *len);
-		return 0;
-	}
-
-	if (trx->magic != TRX_MAGIC || trx->len < sizeof(struct trx_header)) {
+	if (trx->magic != STORE32_LE(TRX_MAGIC) || STORE32_LE(trx->len) < sizeof(struct trx_header)) {
 		if (quiet < 2) {
 			fprintf(stderr, "Bad trx header\n");
 			fprintf(stderr, "This is not the correct file format; refusing to flash.\n"
 					"Please specify the correct file or use -f to force.\n");
 		}
-		return 0;
+		return -1;
 	}
 
-	/* check if image fits to mtd device */
-	fd = mtd_check_open(mtd);
-	if(fd < 0) {
-		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
-		exit(1);
+	if(mtdlength < STORE32_LE(trx->len)) {
+		fprintf(stderr, "Image too big\n");
+		return -1;
 	}
+	
+	if (trx->len == STORE32_LE(datalength))
+		return 1;
 
-	if(mtdsize < trx->len) {
-		fprintf(stderr, "Image too big for partition: %s\n", mtd);
-		close(fd);
-		return 0;
-	}
+	trx->len = STORE32_LE(datalength);
+	
+	trx->crc32 = STORE32_LE(crc32buf((char*) &trx->flag_version, datalength - 3*4));
+	if (quiet < 2)
+		fprintf(stderr, "New crc32: 0x%x\n", trx->crc32);
 
-	close(fd);
-	return 1;
+	return 0;
 }
 
+struct platform_imageops imageops = {
+	.checkimage = trx_check,
+	.firmware_partition = "linux"
+};
