From bbd9eb4669fa5ea124c386e0ba2c680124fa77b5 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@openwrt.org>
Date: Tue, 23 Sep 2008 09:23:58 +0000
Subject: [PATCH] clean up mtd, fix up trx header when integrating jffs2 data
 on broadcom devices

SVN-Revision: 12655
---
 package/mtd/Makefile     |   7 +-
 package/mtd/src/Makefile |   6 +-
 package/mtd/src/jffs2.c  |  13 ++-
 package/mtd/src/mtd.c    |  84 +++-----------------
 package/mtd/src/mtd.h    |  14 +++-
 package/mtd/src/trx.c    | 165 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 209 insertions(+), 80 deletions(-)
 create mode 100644 package/mtd/src/trx.c

diff --git a/package/mtd/Makefile b/package/mtd/Makefile
index d8fa19cb0a..b99e5ed4de 100644
--- a/package/mtd/Makefile
+++ b/package/mtd/Makefile
@@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk
 include $(INCLUDE_DIR)/kernel.mk
 
 PKG_NAME:=mtd
-PKG_RELEASE:=7
+PKG_RELEASE:=8
 
 PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME)
 
@@ -32,10 +32,13 @@ define Build/Prepare
 	$(CP) ./src/* $(PKG_BUILD_DIR)/
 endef
 
+target=$(firstword $(subst -, ,$(BOARD)))
+
 define Build/Compile
 	$(MAKE) -C $(PKG_BUILD_DIR) \
 		$(TARGET_CONFIGURE_OPTS) \
-		CFLAGS="$(TARGET_CFLAGS) -Dtarget_$(firstword $(subst -, ,$(BOARD)))=1"
+		TARGET=$(target) \
+		CFLAGS="$(TARGET_CFLAGS) -Dtarget_$(target)=1 -Wall"
 endef
 
 define Package/mtd/install
diff --git a/package/mtd/src/Makefile b/package/mtd/src/Makefile
index 5ab7d7b1e7..68a632d5ac 100644
--- a/package/mtd/src/Makefile
+++ b/package/mtd/src/Makefile
@@ -1,6 +1,10 @@
 CC = gcc
 CFLAGS += -Wall
 
-mtd: mtd.o jffs2.o crc32.o
+obj = mtd.o jffs2.o crc32.o
+obj.brcm = trx.o
+obj.brcm47xx = $(obj.brcm)
+
+mtd: $(obj) $(obj.$(TARGET))
 clean:
 	rm -f *.o jffs2 
diff --git a/package/mtd/src/jffs2.c b/package/mtd/src/jffs2.c
index d1c6fb66fb..5654f93e07 100644
--- a/package/mtd/src/jffs2.c
+++ b/package/mtd/src/jffs2.c
@@ -140,7 +140,6 @@ static void add_file(const char *name, int parent)
 	struct stat st;
 	char wbuf[4096];
 	const char *fname;
-	FILE *f;
 
 	if (stat(name, &st)) {
 		fprintf(stderr, "File %s does not exist\n", name);
@@ -210,7 +209,7 @@ static void add_file(const char *name, int parent)
 	close(fd);
 }
 
-int mtd_replace_jffs2(int fd, int ofs, const char *filename)
+int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename)
 {
 	outfd = fd;
 	mtdofs = ofs;
@@ -226,6 +225,11 @@ int mtd_replace_jffs2(int fd, int ofs, const char *filename)
 	add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1);
 	pad(erasesize);
 	free(buf);
+
+#ifdef target_brcm
+	trx_fixup(outfd, mtd);
+#endif
+	return 0;
 }
 
 void mtd_parse_jffs2data(const char *buf, const char *dir)
@@ -258,7 +262,6 @@ void mtd_parse_jffs2data(const char *buf, const char *dir)
 int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir)
 {
 	int err = -1, fdeof = 0;
-	off_t offset;
 
 	outfd = mtd_check_open(mtd);
 	if (!outfd)
@@ -326,6 +329,10 @@ int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir)
 
 	err = 0;
 
+#ifdef target_brcm
+	trx_fixup(outfd, mtd);
+#endif
+
 done:
 	close(outfd);
 	if (buf)
diff --git a/package/mtd/src/mtd.c b/package/mtd/src/mtd.c
index 18a73a0a38..18c3e97094 100644
--- a/package/mtd/src/mtd.c
+++ b/package/mtd/src/mtd.c
@@ -46,21 +46,9 @@
 #include "mtd-api.h"
 #include "mtd.h"
 
-#ifdef target_brcm47xx
-#define target_brcm 1
-#endif
-
-#define TRX_MAGIC       0x30524448      /* "HDR0" */
 #define MAX_ARGS 8
-
-#define DEBUG
-
 #define JFFS2_DEFAULT_DIR	"" /* directory name without /, empty means root dir */
 
-#define SYSTYPE_UNKNOWN     0
-#define SYSTYPE_BROADCOM    1
-/* to be continued */
-
 struct trx_header {
 	uint32_t magic;		/* "HDR0" */
 	uint32_t len;		/* Length of file including header */
@@ -77,7 +65,7 @@ int quiet;
 int mtdsize = 0;
 int erasesize = 0;
 
-int mtd_open(const char *mtd)
+int mtd_open(const char *mtd, bool block)
 {
 	FILE *fp;
 	char dev[PATH_MAX];
@@ -88,9 +76,9 @@ int mtd_open(const char *mtd)
 	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/%d", i);
+				snprintf(dev, sizeof(dev), "/dev/mtd%s/%d", (block ? "block" : ""), i);
 				if ((ret=open(dev, flags))<0) {
-					snprintf(dev, sizeof(dev), "/dev/mtd%d", i);
+					snprintf(dev, sizeof(dev), "/dev/mtd%s%d", (block ? "block" : ""), i);
 					ret=open(dev, flags);
 				}
 				fclose(fp);
@@ -108,7 +96,7 @@ int mtd_check_open(const char *mtd)
 	struct mtd_info_user mtdInfo;
 	int fd;
 
-	fd = mtd_open(mtd);
+	fd = mtd_open(mtd, false);
 	if(fd < 0) {
 		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
 		return 0;
@@ -136,68 +124,22 @@ int mtd_erase_block(int fd, int offset)
 		fprintf(stderr, "Erasing mtd failed.\n");
 		exit(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;
 }
 
 
-#ifdef target_brcm
-static int
-image_check_brcm(int imagefd, const char *mtd)
-{
-	struct trx_header *trx = (struct trx_header *) buf;
-	int fd;
-
-	if (strcmp(mtd, "linux") != 0)
-		return 1;
-	
-	buflen = read(imagefd, buf, 32);
-	if (buflen < 32) {
-		fprintf(stdout, "Could not get image header, file too small (%ld bytes)\n", buflen);
-		return 0;
-	}
-
-	if (trx->magic != TRX_MAGIC || 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;
-	}
-
-	/* 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(mtdsize < trx->len) {
-		fprintf(stderr, "Image too big for partition: %s\n", mtd);
-		close(fd);
-		return 0;
-	}	
-	
-	close(fd);
-	return 1;
-}
-#endif /* target_brcm */
-
 static int
 image_check(int imagefd, const char *mtd)
 {
-	int fd, systype;
-	size_t count;
-	char *c;
-	FILE *f;
-
 #ifdef target_brcm
-	return image_check_brcm(imagefd, mtd);
+	return trx_check(imagefd, mtd, buf, &buflen);
 #endif
 }
 
@@ -303,10 +245,8 @@ mtd_refresh(const char *mtd)
 static int
 mtd_write(int imagefd, const char *mtd)
 {
-	int fd, i, result;
+	int fd, result;
 	size_t r, w, e;
-	struct erase_info_user mtdEraseInfo;
-	int ret = 0;
 
 	fd = mtd_check_open(mtd);
 	if(fd < 0) {
@@ -336,7 +276,7 @@ mtd_write(int imagefd, const char *mtd)
 				if (quiet < 2)
 					fprintf(stderr, "\nAppending jffs2 data to from %s to %s...", jffs2file, mtd);
 				/* got an EOF marker - this is the place to add some jffs2 data */
-				mtd_replace_jffs2(fd, e, jffs2file);
+				mtd_replace_jffs2(mtd, fd, e, jffs2file);
 				goto done;
 			}
 			/* no EOF marker, make sure we figure out the last inode number
@@ -425,15 +365,15 @@ static void do_reboot(void)
 
 int main (int argc, char **argv)
 {
-	int ch, i, boot, unlock, imagefd, force, unlocked;
-	char *erase[MAX_ARGS], *device;
+	int ch, i, boot, imagefd = 0, force, unlocked;
+	char *erase[MAX_ARGS], *device = NULL;
 	enum {
 		CMD_ERASE,
 		CMD_WRITE,
 		CMD_UNLOCK,
 		CMD_REFRESH,
 		CMD_JFFS2WRITE
-	} cmd;
+	} cmd = -1;
 	
 	erase[0] = NULL;
 	boot = 0;
diff --git a/package/mtd/src/mtd.h b/package/mtd/src/mtd.h
index 42b6610eb9..a0180319e2 100644
--- a/package/mtd/src/mtd.h
+++ b/package/mtd/src/mtd.h
@@ -1,18 +1,28 @@
 #ifndef __mtd_h
 #define __mtd_h
 
+#include <stdbool.h>
+
+#ifdef target_brcm47xx
+#define target_brcm 1
+#endif
+
 #define JFFS2_EOF "\xde\xad\xc0\xde"
 
 extern int quiet;
 extern int mtdsize;
 extern int erasesize;
 
-extern int mtd_open(const char *mtd);
+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(int fd, int ofs, const char *filename);
+extern int mtd_replace_jffs2(const char *mtd, int fd, 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);
+
 #endif /* __mtd_h */
diff --git a/package/mtd/src/trx.c b/package/mtd/src/trx.c
new file mode 100644
index 0000000000..5457a365bb
--- /dev/null
+++ b/package/mtd/src/trx.c
@@ -0,0 +1,165 @@
+/*
+ * trx.c
+ *
+ * Copyright (C) 2005 Mike Baker 
+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.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.
+ */
+
+#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"
+
+#define TRX_MAGIC       0x30524448      /* "HDR0" */
+struct trx_header {
+	unsigned magic;		/* "HDR0" */
+	unsigned len;		/* Length of file including header */
+	unsigned crc32;		/* 32-bit CRC from flag_version to end of file */
+	unsigned flag_version;	/* 0:15 flags, 16:31 version */
+	unsigned offsets[3];	/* Offsets of partitions from start of header */
+};
+
+static unsigned long *crc32 = NULL;
+
+static void init_crc32()
+{
+	unsigned long crc;
+	unsigned long poly = 0xEDB88320L;
+	int n, bit;
+
+	if (crc32)
+		return;
+
+	crc32 = (unsigned long *) malloc(256 * sizeof(unsigned long));
+	if (!crc32) {
+		perror("malloc");
+		exit(1);
+	}
+
+	for (n = 0; n < 256; n++) {
+		crc = (unsigned long) n;
+		for (bit = 0; bit < 8; bit++)
+			crc = (crc & 1) ? (poly ^ (crc >> 1)) : (crc >> 1);
+		crc32[n] = crc;
+	}
+}
+
+static unsigned int crc32buf(char *buf, size_t len)
+{
+	unsigned int crc = 0xFFFFFFFF;
+	for (; len; len--, buf++)
+		crc = crc32[(crc ^ *buf) & 0xff] ^ (crc >> 8);
+	return crc;
+}
+
+int
+trx_fixup(int fd, const char *name)
+{
+	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;
+	}
+
+	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;
+	}
+
+	init_crc32();
+	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 (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;
+	}
+
+	/* 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(mtdsize < trx->len) {
+		fprintf(stderr, "Image too big for partition: %s\n", mtd);
+		close(fd);
+		return 0;
+	}
+
+	close(fd);
+	return 1;
+}
+
-- 
2.30.2