From 2f3d65dabad91870035f50cd7dc5fcf1f33fd2be Mon Sep 17 00:00:00 2001
From: nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Date: Sun, 12 Feb 2006 06:00:38 +0000
Subject: add support for netgear dg834 and the almost identical sphairon
 jdr454wb: new images, automatic boot loader patcher, updated flash script
 (dlink.pl renamed to adam2flash.pl) - Thanks to Jonathan McDowell (Noodles)

git-svn-id: svn://svn.openwrt.org/openwrt/trunk/openwrt@3221 3c298f89-4303-0410-b956-a3cf2f4a3e73
---
 scripts/adam2flash.pl                              | 174 ++++++++++
 scripts/dlink.pl                                   | 167 ---------
 target/linux/image/ar7/Makefile                    |  13 +
 target/linux/image/ar7/sercomm/adam2.bin           | Bin 0 -> 131072 bytes
 target/linux/image/ar7/sercomm/dg834               | Bin 0 -> 80 bytes
 target/linux/image/ar7/sercomm/jdr454wb            | Bin 0 -> 80 bytes
 target/linux/package/base-files/Makefile           |  15 +-
 .../base-files/files/ar7-2.4/etc/init.d/S00adam2   |   8 +
 target/linux/package/base-files/jffs2root.c        | 133 --------
 target/linux/package/base-files/src/adam2patcher.c |  59 ++++
 target/linux/package/base-files/src/jffs2root.c    | 133 ++++++++
 target/utils/Makefile                              |   2 +-
 target/utils/src/dgfirmware.c                      | 376 +++++++++++++++++++++
 13 files changed, 778 insertions(+), 302 deletions(-)
 create mode 100755 scripts/adam2flash.pl
 delete mode 100755 scripts/dlink.pl
 create mode 100644 target/linux/image/ar7/sercomm/adam2.bin
 create mode 100644 target/linux/image/ar7/sercomm/dg834
 create mode 100644 target/linux/image/ar7/sercomm/jdr454wb
 create mode 100755 target/linux/package/base-files/files/ar7-2.4/etc/init.d/S00adam2
 delete mode 100644 target/linux/package/base-files/jffs2root.c
 create mode 100644 target/linux/package/base-files/src/adam2patcher.c
 create mode 100644 target/linux/package/base-files/src/jffs2root.c
 create mode 100644 target/utils/src/dgfirmware.c

diff --git a/scripts/adam2flash.pl b/scripts/adam2flash.pl
new file mode 100755
index 000000000..bd0fa69a6
--- /dev/null
+++ b/scripts/adam2flash.pl
@@ -0,0 +1,174 @@
+#!/usr/bin/perl
+#
+#   D-Link DSL-G6x4T flash utility
+#
+#   Copyright (C) 2005 Felix Fietkau <mailto@nbd.name>
+#   based on fbox recovery util by Enrik Berkhan
+#
+#   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
+#
+
+use IO::Socket::INET;
+use Socket;
+use strict;
+use warnings;
+
+sub usage() {
+	print STDERR "Usage: $0 <ip> [firmware.bin]\n\n";
+	exit 0;
+}
+
+my $ip = shift @ARGV;
+$ip and $ip =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ or usage();
+
+my $probe = IO::Socket::INET->new(Proto => 'udp',
+                                  Broadcast => 1,
+                                  LocalPort => 5035) or die "socket: $!";
+my $setip = unpack("N", inet_aton($ip));
+$setip > 0 or usage();
+
+my @packets;
+foreach my $ver ([18, 1], [22, 2]) {
+	push @packets, pack("vCCVNV", 0, @$ver, 1, $setip, 0);
+}
+print STDERR "Looking for device: ";
+my $broadcast = sockaddr_in(5035, INADDR_BROADCAST);
+my $scanning;
+my $box;
+
+$SIG{"ALRM"} = sub {
+	return if --$scanning <= 0;
+	foreach my $packet (@packets) {
+		$probe->send($packet, 0, $broadcast);
+	}
+	print STDERR ".";
+};
+
+$scanning = 10;
+foreach my $packet (@packets) {
+	$probe->send($packet, 0, $broadcast);
+}
+print STDERR ".";
+
+while($scanning) {
+	my $reply;
+
+	alarm(1);
+	if (my $peer = $probe->recv($reply, 16)) {
+		next if (length($reply) < 16);
+		my ($port, $addr) = sockaddr_in($peer);
+		my ($major, $minor1, $minor2, $code, $addr2) = unpack("vCCVV", $reply);
+		$addr2 = pack("N", $addr2);
+		if ($code == 2) {
+			$scanning = 0;
+			printf STDERR " found!\nADAM2 version $major.$minor1.$minor2 at %s (%s)\n", inet_ntoa($addr), inet_ntoa($addr2);
+			$box = inet_ntoa($addr);
+		}
+	}
+}
+
+$box or die " not found!\n";
+
+{
+	package ADAM2FTP;
+	use base qw(Net::FTP);
+	
+	# ADAM2 requires upper case commands, some brain dead firewall doesn't ;-)
+	sub _USER {
+		shift->command("USER",@_)->response()
+	}
+	
+	sub _GETENV {
+		my $ftp = shift;
+		my ($ok, $name, $value);
+		
+		$ftp->command("GETENV",@_);
+			while(length($ok = $ftp->response()) < 1) {
+			my $line = $ftp->getline();
+			unless (defined($value)) {
+				chomp($line);
+				($name, $value) = split(/\s+/, $line, 2);
+			}
+		}
+		$ftp->debug_print(0, "getenv: $value\n")
+		if $ftp->debug();
+		return $value;
+	}
+	
+	sub getenv {
+		my $ftp = shift;
+		my $name = shift;
+		return $ftp->_GETENV($name);
+	}
+	
+	sub _REBOOT {
+		shift->command("REBOOT")->response() == Net::FTP::CMD_OK
+	}
+	
+	sub reboot {
+		my $ftp = shift;
+		$ftp->_REBOOT;
+		$ftp->close;
+	}
+}
+
+my $file = shift @ARGV;
+$file || exit 0;
+
+open FILE, "<$file" or die "can't open firmware file\n";
+my $ftp = ADAM2FTP->new($box, Debug => 0, Timeout => 600) or die "can't open control connection\n";
+$ftp->login("adam2", "adam2") or die "can't login\n";
+
+my $mtd0 = $ftp->getenv("mtd0");
+my $mtd1 = $ftp->getenv("mtd1");
+my ($ksize, $fssize);
+
+$mtd1 =~ /^(0x\w+),(0x\w+)$/ and $ksize = hex($2) - hex($1);
+$mtd0 =~ /^(0x\w+),(0x\w+)$/ and $fssize = hex($2) - hex($1);
+$ksize and $fssize or die 'cannot read partition offsets';
+printf STDERR "Available flash space: 0x%08x (0x%08x + 0x%08x)\n", $ksize + $fssize, $ksize, $fssize;
+
+$ftp->command("MEDIA FLSH")->response();
+$ftp->binary();
+print STDERR "Writing to mtd1...\n";
+
+my $dc = $ftp->stor("fs mtd1");
+$dc or die "can't open data connection\n";
+my $rbytes = 1;
+
+while (($ksize > 0) and ($rbytes > 0)) {
+	my $buffer;
+	my $len = ($ksize > 1024 ? 1024 : $ksize);
+	$rbytes = read FILE, $buffer, $len;
+	$rbytes and $ksize -= $dc->write($buffer, $rbytes, 600);
+}
+
+$dc->close();
+$rbytes or die "no more data left to write\n";
+
+print STDERR "Writing to mtd0...\n";
+
+$dc = $ftp->stor("fs mtd0");
+$dc or die "can't open data connection\n";
+
+while (($fssize > 0) and ($rbytes > 0)) {
+	my $buffer;
+	my $len = ($fssize > 1024 ? 1024 : $fssize);
+	$rbytes = read FILE, $buffer, $len;
+	$rbytes and $fssize -= $dc->write($buffer, $rbytes, 600);
+}
+
+$dc->close();
+$ftp->reboot();
diff --git a/scripts/dlink.pl b/scripts/dlink.pl
deleted file mode 100755
index ace6476e9..000000000
--- a/scripts/dlink.pl
+++ /dev/null
@@ -1,167 +0,0 @@
-#!/usr/bin/perl
-#
-#   D-Link DSL-G6x4T flash utility
-#
-#   Copyright (C) 2005 Felix Fietkau <mailto@nbd.name>
-#   based on fbox recovery util by Enrik Berkhan
-#
-#   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
-#
-
-use IO::Socket::INET;
-use Socket;
-use strict;
-use warnings;
-
-sub usage() {
-	print STDERR "Usage: $0 <ip> [firmware.bin]\n\n";
-	exit 0;
-}
-
-my $ip = shift @ARGV;
-$ip and $ip =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ or usage();
-
-my $probe = IO::Socket::INET->new(Proto => 'udp',
-                                  Broadcast => 1,
-                                  LocalPort => 5035) or die "socket: $!";
-my $setip = unpack("N", inet_aton($ip));
-$setip > 0 or usage();
-
-print STDERR "Looking for device: ";
-my $packet = pack("vCCVNV", 0, 22, 2, 1, $setip, 0);
-my $broadcast = sockaddr_in(5035, INADDR_BROADCAST);
-my $scanning;
-my $box;
-
-$SIG{"ALRM"} = sub {
-	return if --$scanning <= 0;
-	$probe->send($packet, 0, $broadcast);
-	print STDERR ".";
-};
-
-$scanning = 10;
-$probe->send($packet, 0, $broadcast);
-print STDERR ".";
-
-while($scanning) {
-	my $reply;
-
-	alarm(1);
-	if (my $peer = $probe->recv($reply, 16)) {
-		next if (length($reply) < 16);
-		my ($port, $addr) = sockaddr_in($peer);
-		my ($major, $minor1, $minor2, $code, $addr2) = unpack("vCCVV", $reply);
-		$addr2 = pack("N", $addr2);
-		if ($code == 2) {
-			$scanning = 0;
-			printf STDERR " found!\nADAM2 version $major.$minor1.$minor2 at %s (%s)\n", inet_ntoa($addr), inet_ntoa($addr2);
-			$box = inet_ntoa($addr);
-		}
-	}
-}
-
-$box or die " not found!\n";
-
-{
-	package ADAM2FTP;
-	use base qw(Net::FTP);
-	
-	# ADAM2 requires upper case commands, some brain dead firewall doesn't ;-)
-	sub _USER {
-		shift->command("USER",@_)->response()
-	}
-	
-	sub _GETENV {
-		my $ftp = shift;
-		my ($ok, $name, $value);
-		
-		$ftp->command("GETENV",@_);
-			while(length($ok = $ftp->response()) < 1) {
-			my $line = $ftp->getline();
-			unless (defined($value)) {
-				chomp($line);
-				($name, $value) = split(/\s+/, $line, 2);
-			}
-		}
-		$ftp->debug_print(0, "getenv: $value\n")
-		if $ftp->debug();
-		return $value;
-	}
-	
-	sub getenv {
-		my $ftp = shift;
-		my $name = shift;
-		return $ftp->_GETENV($name);
-	}
-	
-	sub _REBOOT {
-		shift->command("REBOOT")->response() == Net::FTP::CMD_OK
-	}
-	
-	sub reboot {
-		my $ftp = shift;
-		$ftp->_REBOOT;
-		$ftp->close;
-	}
-}
-
-my $file = shift @ARGV;
-$file || exit 0;
-
-open FILE, "<$file" or die "can't open firmware file\n";
-my $ftp = ADAM2FTP->new($box, Debug => 0, Timeout => 600) or die "can't open control connection\n";
-$ftp->login("adam2", "adam2") or die "can't login\n";
-
-my $mtd0 = $ftp->getenv("mtd0");
-my $mtd1 = $ftp->getenv("mtd1");
-my ($ksize, $fssize);
-
-$mtd1 =~ /^(0x\w+),(0x\w+)$/ and $ksize = hex($2) - hex($1);
-$mtd0 =~ /^(0x\w+),(0x\w+)$/ and $fssize = hex($2) - hex($1);
-$ksize and $fssize or die 'cannot read partition offsets';
-printf STDERR "Available flash space: 0x%08x (0x%08x + 0x%08x)\n", $ksize + $fssize, $ksize, $fssize;
-
-$ftp->command("MEDIA FLSH")->response();
-$ftp->binary();
-print STDERR "Writing to mtd1...\n";
-
-my $dc = $ftp->stor("fs mtd1");
-$dc or die "can't open data connection\n";
-my $rbytes = 1;
-
-while (($ksize > 0) and ($rbytes > 0)) {
-	my $buffer;
-	my $len = ($ksize > 1024 ? 1024 : $ksize);
-	$rbytes = read FILE, $buffer, $len;
-	$rbytes and $ksize -= $dc->write($buffer, $rbytes, 600);
-}
-
-$dc->close();
-$rbytes or die "no more data left to write\n";
-
-print STDERR "Writing to mtd0...\n";
-
-$dc = $ftp->stor("fs mtd0");
-$dc or die "can't open data connection\n";
-
-while (($fssize > 0) and ($rbytes > 0)) {
-	my $buffer;
-	my $len = ($fssize > 1024 ? 1024 : $fssize);
-	$rbytes = read FILE, $buffer, $len;
-	$rbytes and $fssize -= $dc->write($buffer, $rbytes, 600);
-}
-
-$dc->close();
-$ftp->reboot();
diff --git a/target/linux/image/ar7/Makefile b/target/linux/image/ar7/Makefile
index 38fce6bdf..3a803cbd8 100644
--- a/target/linux/image/ar7/Makefile
+++ b/target/linux/image/ar7/Makefile
@@ -83,6 +83,19 @@ $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(FS)-$(1).bin: $(BIN_DIR)/openwrt-$(BOARD
 install: $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(FS)-$(1).bin
 endef
 
+define sercomm_template
+$(BIN_DIR)/openwrt-$(1)-$(KERNEL)-$(FS).bin: $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(FS).bin
+	cat sercomm/adam2.bin "$$^" > "$$@.tmp"
+	dd if=sercomm/$(1) of="$$@.tmp" bs=$$$$((0x3e0000 - 80)) seek=1 conv=notrunc
+	$(STAGING_DIR)/bin/dgfirmware -f -w "$$@" "$$@.tmp"
+	rm -f "$$@.tmp"
+
+install: $(BIN_DIR)/openwrt-$(1)-$(KERNEL)-$(FS).bin
+endef
+
+$(eval $(call sercomm_template,dg834))
+$(eval $(call sercomm_template,jdr454wb))
+
 $(eval $(call pattern_template,AG1B))
 $(eval $(call pattern_template,WA22))
 $(eval $(call pattern_template,WAG2))
diff --git a/target/linux/image/ar7/sercomm/adam2.bin b/target/linux/image/ar7/sercomm/adam2.bin
new file mode 100644
index 000000000..d4aa0cd2d
Binary files /dev/null and b/target/linux/image/ar7/sercomm/adam2.bin differ
diff --git a/target/linux/image/ar7/sercomm/dg834 b/target/linux/image/ar7/sercomm/dg834
new file mode 100644
index 000000000..61fe336e8
Binary files /dev/null and b/target/linux/image/ar7/sercomm/dg834 differ
diff --git a/target/linux/image/ar7/sercomm/jdr454wb b/target/linux/image/ar7/sercomm/jdr454wb
new file mode 100644
index 000000000..821ff1c1a
Binary files /dev/null and b/target/linux/image/ar7/sercomm/jdr454wb differ
diff --git a/target/linux/package/base-files/Makefile b/target/linux/package/base-files/Makefile
index 637904c2e..cf72eabda 100644
--- a/target/linux/package/base-files/Makefile
+++ b/target/linux/package/base-files/Makefile
@@ -15,8 +15,21 @@ $(PKG_BUILD_DIR)/.prepared:
 	mkdir -p $(PKG_BUILD_DIR)
 	touch $@
 
+ifeq ($(BOARD),ar7)
+$(PKG_BUILD_DIR)/adam2patcher: src/adam2patcher.c
+	$(TARGET_CC) -o $@ $<
+
+$(PKG_BUILD_DIR)/.built: $(PKG_BUILD_DIR)/adam2patcher
+
+$(IDIR_OPENWRT)/sbin/adam2patcher: $(PKG_BUILD_DIR)/adam2patcher
+	mkdir -p $(IDIR_OPENWRT)/sbin
+	$(CP) $(PKG_BUILD_DIR)/adam2patcher $(IDIR_OPENWRT)/sbin
+
+$(IPKG_OPENWRT): $(IDIR_OPENWRT)/sbin/adam2patcher
+endif
+
 ifeq ($(BOARD),brcm)
-$(PKG_BUILD_DIR)/jffs2root: jffs2root.c
+$(PKG_BUILD_DIR)/jffs2root: src/jffs2root.c
 	$(TARGET_CC) -o $@ $<
 
 $(PKG_BUILD_DIR)/.built: $(PKG_BUILD_DIR)/jffs2root
diff --git a/target/linux/package/base-files/files/ar7-2.4/etc/init.d/S00adam2 b/target/linux/package/base-files/files/ar7-2.4/etc/init.d/S00adam2
new file mode 100755
index 000000000..0ca4c0145
--- /dev/null
+++ b/target/linux/package/base-files/files/ar7-2.4/etc/init.d/S00adam2
@@ -0,0 +1,8 @@
+#!/bin/sh
+# ADAM2 patcher for Netgear DG834 and compatible
+MD5="$(md5sum /dev/mtdblock/0  | awk '{print $1}')"
+[ "$MD5" = "0530bfdf00ec155f4182afd70da028c1" ] && {
+	mtd unlock adam2
+	/sbin/adam2patcher /dev/mtdblock/0
+}
+rm -f /etc/init.d/S00adam2 /sbin/adam2patcher >&- 2>&-
diff --git a/target/linux/package/base-files/jffs2root.c b/target/linux/package/base-files/jffs2root.c
deleted file mode 100644
index 14662fc94..000000000
--- a/target/linux/package/base-files/jffs2root.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * jffs2root.c
- *
- * Copyright (C) 2005 Mike Baker 
- *
- * 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.
- *
- * $Id$
- *
- */
-
-#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 <linux/mtd/mtd.h>
-
-#define FILENAME "/dev/mtdblock/1"
-
-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 */
-};
-
-unsigned long *crc32;
-
-void init_crc32()
-{
-	unsigned long crc;
-	unsigned long poly = 0xEDB88320L;
-	int n, bit;
-	if ((crc32 = (unsigned long *) malloc(256 * sizeof(unsigned long))) == (void *)-1) {
-		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;
-	}
-}
-
-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 main(int argc, char **argv)
-{
-	int fd;
-	struct mtd_info_user mtdInfo;
-	unsigned long len;
-	struct trx_header *ptr;
-	char *buf;
-	
-	if (((fd = open(FILENAME, O_RDWR))	< 0)
-			|| ((len = lseek(fd, 0, SEEK_END)) < 0)
-			|| ((ptr = (struct trx_header *) mmap(0, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == (void *) (-1))
-			|| (ptr->magic != 0x30524448)) {
-		printf("Error reading trx info\n");
-		exit(-1);
-	}
-	close (fd);
-
-	if (((fd = open("/dev/mtd/1", O_RDWR))	< 0)
-			|| (ioctl(fd, MEMGETINFO, &mtdInfo))) {
-		fprintf(stderr, "Could not get MTD device info from %s\n", FILENAME);
-		close(fd);
-		exit(1);
-	}
-	close(fd);
-
-	if (argc > 1 && !strcmp(argv[1],"--move")) {
-		if (ptr->offsets[2] >= ptr->len) {
-			printf("Partition already moved outside trx\n");
-		} else {
-			init_crc32();
-			ptr->offsets[2] +=	(mtdInfo.erasesize - 1);
-			ptr->offsets[2] &= ~(mtdInfo.erasesize - 1);
-			ptr->len = ptr->offsets[2];
-			ptr->crc32 = crc32buf((void *) &(ptr->flag_version), ptr->len - offsetof(struct trx_header, flag_version));
-			msync(ptr,sizeof(struct trx_header),MS_SYNC|MS_INVALIDATE);
-			printf("Partition moved; please reboot\n");
-		}
-	} else if (argc > 1 && !strcmp(argv[1], "--clean")) {
-		buf = (char *) ptr;
-		if (buf[ptr->offsets[1] - 1] == 0) {
-			init_crc32();
-			buf[ptr->offsets[1] - 1] = 1;
-			ptr->crc32 = crc32buf((void *) &(ptr->flag_version), ptr->len - offsetof(struct trx_header, flag_version));
-			msync(ptr,sizeof(struct trx_header),MS_SYNC|MS_INVALIDATE);
-			printf("Partition marked as clean\n");
-		}
-	} else {
-		int x;
-		printf(" erase: 0x%08x\n",mtdInfo.erasesize);
-		printf("=== trx ===\n");
-		printf("mapped: 0x%08x\n", (unsigned)ptr);
-		printf(" magic: 0x%08x\n", ptr->magic);
-		printf("	 len: 0x%08x\n", ptr->len);
-		printf("	 crc: 0x%08x\n", ptr->crc32);
-		for (x = 0; x < 3; x++)
-			printf(" offset[%d]: 0x%08x\n", x, ptr->offsets[x]);
-	}
-
-	munmap((void *) ptr, len);
-	return 0;
-}
diff --git a/target/linux/package/base-files/src/adam2patcher.c b/target/linux/package/base-files/src/adam2patcher.c
new file mode 100644
index 000000000..25a78074a
--- /dev/null
+++ b/target/linux/package/base-files/src/adam2patcher.c
@@ -0,0 +1,59 @@
+/*
+ * patcher.c - ADAM2 patcher for Netgear DG834 (and compatible)
+ *
+ * Copyright (C) 2006 Felix Fietkau
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+
+int main(int argc, char **argv)
+{
+	int fd;
+	char *ptr;
+	uint32_t *i;
+
+	if (argc != 2) {
+		fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
+		exit(1);
+	}
+
+	if (((fd = open(argv[1], O_RDWR)) < 0)
+			|| ((ptr = mmap(0, 128 * 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == (void *) (-1))) {
+		fprintf(stderr, "Can't open file\n");
+		exit(1);
+	}
+
+	i = (uint32_t *) &ptr[0x3944];
+	if (*i == 0x0c000944) {
+		fprintf(stderr, "Unpatched ADAM2 detected. Patching... ");
+		*i = 0x00000000;
+		msync(i, sizeof(*i), MS_SYNC|MS_INVALIDATE);
+		fprintf(stderr, "done!\n");
+	} else if (*i == 0x00000000) {
+		fprintf(stderr, "Patched ADAM2 detected.\n");
+	} else {
+		fprintf(stderr, "Unknown ADAM2 detected. Can't patch!\n");
+	}
+
+	close(fd);		
+}
diff --git a/target/linux/package/base-files/src/jffs2root.c b/target/linux/package/base-files/src/jffs2root.c
new file mode 100644
index 000000000..14662fc94
--- /dev/null
+++ b/target/linux/package/base-files/src/jffs2root.c
@@ -0,0 +1,133 @@
+/*
+ * jffs2root.c
+ *
+ * Copyright (C) 2005 Mike Baker 
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ */
+
+#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 <linux/mtd/mtd.h>
+
+#define FILENAME "/dev/mtdblock/1"
+
+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 */
+};
+
+unsigned long *crc32;
+
+void init_crc32()
+{
+	unsigned long crc;
+	unsigned long poly = 0xEDB88320L;
+	int n, bit;
+	if ((crc32 = (unsigned long *) malloc(256 * sizeof(unsigned long))) == (void *)-1) {
+		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;
+	}
+}
+
+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 main(int argc, char **argv)
+{
+	int fd;
+	struct mtd_info_user mtdInfo;
+	unsigned long len;
+	struct trx_header *ptr;
+	char *buf;
+	
+	if (((fd = open(FILENAME, O_RDWR))	< 0)
+			|| ((len = lseek(fd, 0, SEEK_END)) < 0)
+			|| ((ptr = (struct trx_header *) mmap(0, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == (void *) (-1))
+			|| (ptr->magic != 0x30524448)) {
+		printf("Error reading trx info\n");
+		exit(-1);
+	}
+	close (fd);
+
+	if (((fd = open("/dev/mtd/1", O_RDWR))	< 0)
+			|| (ioctl(fd, MEMGETINFO, &mtdInfo))) {
+		fprintf(stderr, "Could not get MTD device info from %s\n", FILENAME);
+		close(fd);
+		exit(1);
+	}
+	close(fd);
+
+	if (argc > 1 && !strcmp(argv[1],"--move")) {
+		if (ptr->offsets[2] >= ptr->len) {
+			printf("Partition already moved outside trx\n");
+		} else {
+			init_crc32();
+			ptr->offsets[2] +=	(mtdInfo.erasesize - 1);
+			ptr->offsets[2] &= ~(mtdInfo.erasesize - 1);
+			ptr->len = ptr->offsets[2];
+			ptr->crc32 = crc32buf((void *) &(ptr->flag_version), ptr->len - offsetof(struct trx_header, flag_version));
+			msync(ptr,sizeof(struct trx_header),MS_SYNC|MS_INVALIDATE);
+			printf("Partition moved; please reboot\n");
+		}
+	} else if (argc > 1 && !strcmp(argv[1], "--clean")) {
+		buf = (char *) ptr;
+		if (buf[ptr->offsets[1] - 1] == 0) {
+			init_crc32();
+			buf[ptr->offsets[1] - 1] = 1;
+			ptr->crc32 = crc32buf((void *) &(ptr->flag_version), ptr->len - offsetof(struct trx_header, flag_version));
+			msync(ptr,sizeof(struct trx_header),MS_SYNC|MS_INVALIDATE);
+			printf("Partition marked as clean\n");
+		}
+	} else {
+		int x;
+		printf(" erase: 0x%08x\n",mtdInfo.erasesize);
+		printf("=== trx ===\n");
+		printf("mapped: 0x%08x\n", (unsigned)ptr);
+		printf(" magic: 0x%08x\n", ptr->magic);
+		printf("	 len: 0x%08x\n", ptr->len);
+		printf("	 crc: 0x%08x\n", ptr->crc32);
+		for (x = 0; x < 3; x++)
+			printf(" offset[%d]: 0x%08x\n", x, ptr->offsets[x]);
+	}
+
+	munmap((void *) ptr, len);
+	return 0;
+}
diff --git a/target/utils/Makefile b/target/utils/Makefile
index 753db53de..5b0f2470b 100644
--- a/target/utils/Makefile
+++ b/target/utils/Makefile
@@ -1,6 +1,6 @@
 include $(TOPDIR)/rules.mk
 
-TARGETS := addpattern trx motorola-bin
+TARGETS := addpattern trx motorola-bin dgfirmware
 
 UTILS_BUILD_DIR:=$(BUILD_DIR)/target-utils
 
diff --git a/target/utils/src/dgfirmware.c b/target/utils/src/dgfirmware.c
new file mode 100644
index 000000000..5ff3b6964
--- /dev/null
+++ b/target/utils/src/dgfirmware.c
@@ -0,0 +1,376 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+
+#define IMG_SIZE     0x3e0000
+
+#define KERNEL_START 0x020000
+#define KERNEL_SIZE  0x0b0000
+
+#define ROOTFS_START 0x0d0000
+#define ROOTFS_SIZE  0x30ffb2
+
+char* app_name;
+
+
+
+
+void print_usage(void)
+{
+  fprintf(stderr, "usage: dgfirmware [<opts>] <img>\n");
+  fprintf(stderr, "  <img>               firmware image filename\n");
+  fprintf(stderr, "  <opts>  -h          print this message\n");
+  fprintf(stderr, "          -f          fix the checksum\n");
+  fprintf(stderr, "          -x  <file>  extract the rootfs file to <file>\n");
+  fprintf(stderr, "          -xk <file>  extract the kernel to <file>\n");
+  fprintf(stderr, "          -m  <file>  merge in rootfs fil\e from <file>\n");
+  fprintf(stderr, "          -k  <file>  merge in kernel from <file>\n");
+  fprintf(stderr, "          -w  <file>  write back the modified firmware\n");
+}
+
+
+unsigned char* read_img(const char *fname)
+{
+  FILE *fp;
+  int size;
+  unsigned char *img;
+
+  fp = fopen(fname, "rb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+
+  fseek(fp, 0, SEEK_END);
+  size = ftell(fp);
+  
+  if (size != IMG_SIZE) {
+    fprintf(stderr, "%s: image file has wrong size\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  rewind(fp);
+
+  img = malloc(IMG_SIZE);
+  if (img == NULL) {
+    perror(app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  if (fread(img, 1, IMG_SIZE, fp) != IMG_SIZE) {
+    fprintf(stderr, "%s: can't read image file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  fclose(fp);
+  return img;
+}
+
+
+void write_img(unsigned char* img, const char *fname)
+{
+  FILE *fp;
+
+  fp = fopen(fname, "wb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+
+  if (fwrite(img, 1, IMG_SIZE, fp) != IMG_SIZE) {
+    fprintf(stderr, "%s: can't write image file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+}
+
+
+void write_rootfs(unsigned char* img, const char *fname)
+{
+  FILE *fp;
+
+  fp = fopen(fname, "wb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+  
+  if (fwrite(img+ROOTFS_START, 1, ROOTFS_SIZE, fp) != ROOTFS_SIZE) {
+    fprintf(stderr, "%s: can't write image file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+}
+
+
+void write_kernel(unsigned char* img, const char *fname)
+{
+  FILE *fp;
+
+  fp = fopen(fname, "wb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+  
+  if (fwrite(img+KERNEL_START, 1, KERNEL_SIZE, fp) != KERNEL_SIZE) {
+    fprintf(stderr, "%s: can't write kernel file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+}
+
+
+unsigned char* read_rootfs(unsigned char* img, const char *fname)
+{
+  FILE *fp;
+  int size;
+  int i;
+
+  for (i=ROOTFS_START; i<ROOTFS_START+ROOTFS_SIZE; i++)
+    img[i] = 0xff;
+
+  fp = fopen(fname, "rb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+
+  fseek(fp, 0, SEEK_END);
+  size = ftell(fp);
+  
+  if (size > ROOTFS_SIZE) {
+    fprintf(stderr, "%s: rootfs image file is too big\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  rewind(fp);
+
+  if (fread(img+ROOTFS_START, 1, size, fp) != size) {
+    fprintf(stderr, "%s: can't read rootfs image file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  fclose(fp);
+  return img;
+}
+
+
+unsigned char* read_kernel(unsigned char* img, const char *fname)
+{
+  FILE *fp;
+  int size;
+  int i;
+
+  for (i=KERNEL_START; i<KERNEL_START+KERNEL_SIZE; i++)
+    img[i] = 0xff;
+
+  fp = fopen(fname, "rb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+
+  fseek(fp, 0, SEEK_END);
+  size = ftell(fp);
+  
+  if (size > KERNEL_SIZE) {
+    fprintf(stderr, "%s: kernel binary file is too big\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  rewind(fp);
+
+  if (fread(img+KERNEL_START, 1, size, fp) != size) {
+    fprintf(stderr, "%s: can't read kernel file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  fclose(fp);
+  return img;
+}
+
+
+int get_checksum(unsigned char* img)
+{
+  short unsigned s;
+
+  s = img[0x3dfffc] + (img[0x3dfffd]<<8);
+
+  return s;
+}
+
+
+void set_checksum(unsigned char*img, unsigned short sum)
+{
+  img[0x3dfffc] = sum & 0xff;
+  img[0x3dfffd] = (sum>>8) & 0xff;
+}
+
+
+int compute_checksum(unsigned char* img)
+{
+  int i;
+  short s=0;
+
+  for (i=0; i<0x3dfffc; i++)
+    s += img[i];
+
+  return s;
+}
+
+
+int main(int argc, char* argv[])
+{
+  char *img_fname     = NULL;
+  char *rootfs_fname  = NULL;
+  char *kernel_fname  = NULL;
+  char *new_img_fname = NULL;
+
+  int do_fix_checksum = 0;
+  int do_write        = 0;
+  int do_write_rootfs = 0;
+  int do_read_rootfs  = 0;
+  int do_write_kernel = 0;
+  int do_read_kernel  = 0;
+
+  int i;
+  unsigned char *img;
+  unsigned short img_checksum;
+  unsigned short real_checksum;
+
+  app_name = argv[0];
+
+  for (i=1; i<argc; i++) {
+    if (!strcmp(argv[i], "-h")) {
+      print_usage();
+      return 0;
+    }
+    else if (!strcmp(argv[i], "-f")) {
+      do_fix_checksum = 1;
+    }
+    else if (!strcmp(argv[i], "-x")) {
+      if (i+1 >= argc) {
+	fprintf(stderr, "%s: missing argument\n", app_name);
+	return -1;
+      }
+      do_write_rootfs = 1;
+      rootfs_fname = argv[i+1];
+      i++;
+    }
+    else if (!strcmp(argv[i], "-xk")) {
+      if (i+1 >= argc) {
+	fprintf(stderr, "%s: missing argument\n", app_name);
+	return -1;
+      }
+      do_write_kernel = 1;
+      kernel_fname = argv[i+1];
+      i++;
+    }
+    else if (!strcmp(argv[i], "-m")) {
+      if (i+1 >= argc) {
+	fprintf(stderr, "%s: missing argument\n", app_name);
+	return -1;
+      }
+      do_read_rootfs = 1;
+      rootfs_fname = argv[i+1];
+      i++;
+    }
+    else if (!strcmp(argv[i], "-k")) {
+      if (i+1 >= argc) {
+	fprintf(stderr, "%s: missing argument\n", app_name);
+	return -1;
+      }
+      do_read_kernel = 1;
+      kernel_fname = argv[i+1];
+      i++;
+    }
+    else if (!strcmp(argv[i], "-w")) {
+      if (i+1 >= argc) {
+	fprintf(stderr, "%s: missing argument\n", app_name);
+	return -1;
+      }
+      do_write = 1;
+      new_img_fname = argv[i+1];
+      i++;
+    }
+    else if (img_fname != 0) {
+      fprintf(stderr, "%s: too many arguments\n", app_name);
+      return -1;
+    }
+    else {
+      img_fname = argv[i];
+    }
+  }
+
+  if (img_fname == NULL) {
+    fprintf(stderr, "%s: missing argument\n", app_name);
+    return -1;
+  }
+
+  if ((do_read_rootfs && do_write_rootfs) ||
+      (do_read_kernel && do_write_kernel)) {
+    fprintf(stderr, "%s: conflictuous options\n", app_name);
+    return -1;
+  }
+
+  printf ("** Read firmware file\n");
+  img = read_img(img_fname);
+
+  printf ("Firmware product: %s\n", img+0x3dffbd);
+  printf ("Firmware version: 1.%02d.%02d\n", (img[0x3dffeb] & 0x7f), img[0x3dffec]);
+
+  if (do_write_rootfs) {
+    printf ("** Write rootfs file\n");
+    write_rootfs(img, rootfs_fname);
+  }
+
+  if (do_write_kernel) {
+    printf ("** Write kernel file\n");
+    write_kernel(img, kernel_fname);
+  }
+
+  if (do_read_rootfs) {
+    printf ("** Read rootfs file\n");
+    read_rootfs(img, rootfs_fname);
+    do_fix_checksum = 1;
+  }
+
+  if (do_read_kernel) {
+    printf ("** Read kernel file\n");
+    read_kernel(img, kernel_fname);
+    do_fix_checksum = 1;
+  }
+
+  img_checksum = get_checksum(img);
+  real_checksum = compute_checksum(img);
+  
+  printf ("image checksum = %04x\n", img_checksum);
+  printf ("real checksum  = %04x\n", real_checksum);
+
+  if (do_fix_checksum) {
+    if (img_checksum != real_checksum) {
+      printf ("** Bad Checksum, fix it\n");
+      set_checksum(img, real_checksum);
+    }
+    else {
+      printf ("** Checksum is correct, good\n");
+    }
+  }
+
+  if (do_write) {
+    printf ("** Write image file\n");
+    write_img(img, new_img_fname);
+  }
+
+  free(img);
+  return 0;
+}
+
-- 
cgit v1.2.3