diff --git a/README.md b/README.md
new file mode 100644
index 0000000..555a4e0
--- /dev/null
+++ b/README.md
@@ -0,0 +1,22 @@
+OpenWRT for old RT2880 routers
+==============================
+
+This is a fork of OpenWRT Attitude Adjustment 12.09.1 that may occasionally
+back out of certain upstream changes, but most importantly adds support for
+some older Ralink RT2880-based routers previously unsupported by OpenWRT and/or
+other alternative firmware.
+
+**Fully supported:**
+
+- Airlink101 AR725W
+- Asante SmartHub AWRT-600N
+
+**Supported with limitations:**
+
+- Linksys WRT100
+- Linksys WRT110
+- Linksys WRT160N v2
+
+The limitations stem from having only 16MB of RAM. More info is in the wiki.
+
+Any contributions are very much welcome!
diff --git a/package/mtd/src/Makefile b/package/mtd/src/Makefile
index 4e6aee8..24c7ba9 100644
--- a/package/mtd/src/Makefile
+++ b/package/mtd/src/Makefile
@@ -3,11 +3,12 @@ CFLAGS += -Wall
 
 obj = mtd.o jffs2.o crc32.o
 obj.seama = seama.o md5.o
+obj.uimage = uimage.o
 obj.ar71xx = trx.o
 obj.brcm = trx.o
 obj.brcm47xx = $(obj.brcm)
 obj.brcm63xx = imagetag.o
-obj.ramips = $(obj.seama)
+obj.ramips = $(obj.seama) $(obj.uimage)
 
 ifdef FIS_SUPPORT
   obj += fis.o
diff --git a/package/mtd/src/image.h b/package/mtd/src/image.h
new file mode 100644
index 0000000..2f575fd
--- /dev/null
+++ b/package/mtd/src/image.h
@@ -0,0 +1,160 @@
+/*
+ * (C) Copyright 2000-2005
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ *
+ ********************************************************************
+ * NOTE: This header file defines an interface to U-Boot. Including
+ * this (unmodified) header file in another file is considered normal
+ * use of U-Boot, and does *not* fall under the heading of "derived
+ * work".
+ ********************************************************************
+ */
+
+#ifndef __IMAGE_H__
+#define __IMAGE_H__
+
+/*
+ * Operating System Codes
+ */
+#define IH_OS_INVALID		0	/* Invalid OS	*/
+#define IH_OS_OPENBSD		1	/* OpenBSD	*/
+#define IH_OS_NETBSD		2	/* NetBSD	*/
+#define IH_OS_FREEBSD		3	/* FreeBSD	*/
+#define IH_OS_4_4BSD		4	/* 4.4BSD	*/
+#define IH_OS_LINUX		5	/* Linux	*/
+#define IH_OS_SVR4		6	/* SVR4		*/
+#define IH_OS_ESIX		7	/* Esix		*/
+#define IH_OS_SOLARIS		8	/* Solaris	*/
+#define IH_OS_IRIX		9	/* Irix		*/
+#define IH_OS_SCO		10	/* SCO		*/
+#define IH_OS_DELL		11	/* Dell		*/
+#define IH_OS_NCR		12	/* NCR		*/
+#define IH_OS_LYNXOS		13	/* LynxOS	*/
+#define IH_OS_VXWORKS		14	/* VxWorks	*/
+#define IH_OS_PSOS		15	/* pSOS		*/
+#define IH_OS_QNX		16	/* QNX		*/
+#define IH_OS_U_BOOT		17	/* Firmware	*/
+#define IH_OS_RTEMS		18	/* RTEMS	*/
+#define IH_OS_ARTOS		19	/* ARTOS	*/
+#define IH_OS_UNITY		20	/* Unity OS	*/
+
+/*
+ * CPU Architecture Codes (supported by Linux)
+ */
+#define IH_CPU_INVALID		0	/* Invalid CPU	*/
+#define IH_CPU_ALPHA		1	/* Alpha	*/
+#define IH_CPU_ARM		2	/* ARM		*/
+#define IH_CPU_I386		3	/* Intel x86	*/
+#define IH_CPU_IA64		4	/* IA64		*/
+#define IH_CPU_MIPS		5	/* MIPS		*/
+#define IH_CPU_MIPS64		6	/* MIPS	 64 Bit */
+#define IH_CPU_PPC		7	/* PowerPC	*/
+#define IH_CPU_S390		8	/* IBM S390	*/
+#define IH_CPU_SH		9	/* SuperH	*/
+#define IH_CPU_SPARC		10	/* Sparc	*/
+#define IH_CPU_SPARC64		11	/* Sparc 64 Bit */
+#define IH_CPU_M68K		12	/* M68K		*/
+#define IH_CPU_NIOS		13	/* Nios-32	*/
+#define IH_CPU_MICROBLAZE	14	/* MicroBlaze   */
+#define IH_CPU_NIOS2		15	/* Nios-II	*/
+#define IH_CPU_BLACKFIN		16	/* Blackfin	*/
+#define IH_CPU_AVR32		17	/* AVR32	*/
+
+/*
+ * Image Types
+ *
+ * "Standalone Programs" are directly runnable in the environment
+ *	provided by U-Boot; it is expected that (if they behave
+ *	well) you can continue to work in U-Boot after return from
+ *	the Standalone Program.
+ * "OS Kernel Images" are usually images of some Embedded OS which
+ *	will take over control completely. Usually these programs
+ *	will install their own set of exception handlers, device
+ *	drivers, set up the MMU, etc. - this means, that you cannot
+ *	expect to re-enter U-Boot except by resetting the CPU.
+ * "RAMDisk Images" are more or less just data blocks, and their
+ *	parameters (address, size) are passed to an OS kernel that is
+ *	being started.
+ * "Multi-File Images" contain several images, typically an OS
+ *	(Linux) kernel image and one or more data images like
+ *	RAMDisks. This construct is useful for instance when you want
+ *	to boot over the network using BOOTP etc., where the boot
+ *	server provides just a single image file, but you want to get
+ *	for instance an OS kernel and a RAMDisk image.
+ *
+ *	"Multi-File Images" start with a list of image sizes, each
+ *	image size (in bytes) specified by an "uint32_t" in network
+ *	byte order. This list is terminated by an "(uint32_t)0".
+ *	Immediately after the terminating 0 follow the images, one by
+ *	one, all aligned on "uint32_t" boundaries (size rounded up to
+ *	a multiple of 4 bytes - except for the last file).
+ *
+ * "Firmware Images" are binary images containing firmware (like
+ *	U-Boot or FPGA images) which usually will be programmed to
+ *	flash memory.
+ *
+ * "Script files" are command sequences that will be executed by
+ *	U-Boot's command interpreter; this feature is especially
+ *	useful when you configure U-Boot to use a real shell (hush)
+ *	as command interpreter (=> Shell Scripts).
+ */
+
+#define IH_TYPE_INVALID		0	/* Invalid Image		*/
+#define IH_TYPE_STANDALONE	1	/* Standalone Program		*/
+#define IH_TYPE_KERNEL		2	/* OS Kernel Image		*/
+#define IH_TYPE_RAMDISK		3	/* RAMDisk Image		*/
+#define IH_TYPE_MULTI		4	/* Multi-File Image		*/
+#define IH_TYPE_FIRMWARE	5	/* Firmware Image		*/
+#define IH_TYPE_SCRIPT		6	/* Script file			*/
+#define IH_TYPE_FILESYSTEM	7	/* Filesystem Image (any type)	*/
+#define IH_TYPE_FLATDT		8	/* Binary Flat Device Tree Blob	*/
+
+/*
+ * Compression Types
+ */
+#define IH_COMP_NONE		0	/*  No	 Compression Used	*/
+#define IH_COMP_GZIP		1	/* gzip	 Compression Used	*/
+#define IH_COMP_BZIP2		2	/* bzip2 Compression Used	*/
+
+#define IH_MAGIC	0x27051956	/* Image Magic Number		*/
+#define IH_NMLEN		32	/* Image Name Length		*/
+
+/*
+ * all data in network byte order (aka natural aka bigendian)
+ */
+
+typedef struct image_header {
+	uint32_t	ih_magic;	/* Image Header Magic Number	*/
+	uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/
+	uint32_t	ih_time;	/* Image Creation Timestamp	*/
+	uint32_t	ih_size;	/* Image Data Size		*/
+	uint32_t	ih_load;	/* Data	 Load  Address		*/
+	uint32_t	ih_ep;		/* Entry Point Address		*/
+	uint32_t	ih_dcrc;	/* Image Data CRC Checksum	*/
+	uint8_t		ih_os;		/* Operating System		*/
+	uint8_t		ih_arch;	/* CPU architecture		*/
+	uint8_t		ih_type;	/* Image Type			*/
+	uint8_t		ih_comp;	/* Compression Type		*/
+	uint8_t		ih_name[IH_NMLEN];	/* Image Name		*/
+} image_header_t;
+
+
+#endif	/* __IMAGE_H__ */
diff --git a/package/mtd/src/mtd.c b/package/mtd/src/mtd.c
index 9a6e65d..9ed3877 100644
--- a/package/mtd/src/mtd.c
+++ b/package/mtd/src/mtd.c
@@ -525,6 +525,10 @@ static void usage(void)
 	    fprintf(stderr,
 	"        fixseama                fix the checksum in a seama header on first boot\n");
 	}
+	if (mtd_fixuimage) {
+	    fprintf(stderr,
+	"        fixuimage               fix the checksum on a WRT160Nv2 header on first boot\n");
+	}
     fprintf(stderr,
 	"Following options are available:\n"
 	"        -q                      quiet mode (once: no [w] on writing,\n"
@@ -580,6 +584,7 @@ int main (int argc, char **argv)
 		CMD_JFFS2WRITE,
 		CMD_FIXTRX,
 		CMD_FIXSEAMA,
+		CMD_FIXUIMAGE,
 	} cmd = -1;
 
 	erase[0] = NULL;
@@ -671,6 +676,9 @@ int main (int argc, char **argv)
 	} else if (((strcmp(argv[0], "fixseama") == 0) && (argc == 2)) && mtd_fixseama) {
 		cmd = CMD_FIXSEAMA;
 		device = argv[1];
+	} else if (((strcmp(argv[0], "fixuimage") == 0) && (argc == 2)) && mtd_fixuimage) {
+		cmd = CMD_FIXUIMAGE;
+		device = argv[1];
 	} else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) {
 		cmd = CMD_WRITE;
 		device = argv[2];
@@ -751,6 +759,10 @@ int main (int argc, char **argv)
 			if (mtd_fixseama)
 			    mtd_fixseama(device, 0);
 			break;
+                case CMD_FIXUIMAGE:
+			if (mtd_fixuimage)
+			    mtd_fixuimage(device, 0);
+			break;
 	}
 
 	sync();
diff --git a/package/mtd/src/mtd.h b/package/mtd/src/mtd.h
index c2133fc..0ccd317 100644
--- a/package/mtd/src/mtd.h
+++ b/package/mtd/src/mtd.h
@@ -26,4 +26,5 @@ extern int trx_fixup(int fd, const char *name)  __attribute__ ((weak));
 extern int trx_check(int imagefd, const char *mtd, char *buf, int *len) __attribute__ ((weak));
 extern int mtd_fixtrx(const char *mtd, size_t offset) __attribute__ ((weak));
 extern int mtd_fixseama(const char *mtd, size_t offset) __attribute__ ((weak));
+extern int mtd_fixuimage(const char *mtd, size_t offset) __attribute__ ((weak));
 #endif /* __mtd_h */
diff --git a/package/mtd/src/uimage.c b/package/mtd/src/uimage.c
new file mode 100644
index 0000000..4d5c034
--- /dev/null
+++ b/package/mtd/src/uimage.c
@@ -0,0 +1,182 @@
+/*
+ * uimage.c
+ *
+ * Fix the uImage header on a Linksys WRT160N v2.
+ *
+ * The WRT160Nv2's header format is a uImage of a TRX
+ * image. In order to allow initial flashing from the
+ * original web interface, the generated OpenWRT image
+ * must include the TRX image of both the kernel and
+ * rootfs, and the uImage must reflect the size/checksum
+ * of the entire thing.
+ *
+ * The issue comes after the first boot, when jffs2
+ * formatting changes the very end of the rootfs
+ * part still within the TRX image size. To work around
+ * this, we use this kludge at firstboot that recreates
+ * the uImage header using only the kernel partition
+ * (the only part the bootloader cares about) and recalculates
+ * the CRCs based on that.
+ *
+ * Copyright (C) 2014 Claudio Leite <leitec@staticky.com>
+ *
+ * Based on the seama fixup code:
+ *   Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Based on the trx fixup code:
+ *   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 <errno.h>
+#include <arpa/inet.h>
+
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+#include "mtd.h"
+#include "image.h"
+#include "crc32.h"
+
+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);
+
+int
+uimage_fix_crc32(char *buf, size_t len)
+{
+	image_header_t *uhdr;
+	char *data;
+        size_t newsize;
+        uint32_t newhcrc, newdcrc;
+
+	if (len < sizeof(struct image_header))
+		return -1;
+
+	uhdr = (struct image_header *) buf;
+	if (uhdr->ih_magic != htonl(IH_MAGIC)) {
+		fprintf(stderr, "no uImage header found\n");
+		return -1;
+	}
+
+        if(ntohl(uhdr->ih_size) <= len - sizeof(struct image_header)) {
+            if(quiet < 2)
+                fprintf(stderr, "header doesn't need fixing, already contained within partition\n");
+
+            return -1;
+        }
+
+        newsize = len - sizeof(struct image_header);
+        data = buf + sizeof(struct image_header);
+        newdcrc = crc32buf(data, newsize) ^ 0xFFFFFFFFL;
+
+        if(uhdr->ih_dcrc == htonl(newdcrc) &&
+           uhdr->ih_size == htonl(newsize)) {
+            if(quiet < 2)
+                fprintf(stderr, "the header is already fixed\n");
+
+            return -1;
+        }
+
+        uhdr->ih_size = htonl(newsize);
+        uhdr->ih_dcrc = htonl(newdcrc);
+        uhdr->ih_hcrc = 0;
+
+        newhcrc = crc32buf(buf, sizeof(struct image_header)) ^ 0xFFFFFFFFL;
+        uhdr->ih_hcrc = htonl(newhcrc);
+
+	if (quiet < 2) {
+		fprintf(stderr, "new size: %u, new data CRC32: %04X\n",
+                        newsize, newdcrc);
+                fprintf(stderr, "new header CRC32: %04X\n", newhcrc);
+	}
+
+	return 0;
+}
+
+int
+mtd_fixuimage(const char *mtd, size_t offset)
+{
+	int fd;
+	char *buf;
+	ssize_t res;
+	size_t block_offset;
+
+	if (quiet < 2)
+		fprintf(stderr, "Trying to fix uImage 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(mtdsize);
+	if (!buf) {
+		perror("malloc");
+		exit(1);
+	}
+
+	res = pread(fd, buf, mtdsize, block_offset);
+	if (res != mtdsize) {
+		perror("pread");
+		exit(1);
+	}
+
+	if (uimage_fix_crc32(buf, mtdsize))
+		goto out;
+
+	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, "Rewriting block at 0x%x\n", block_offset);
+
+	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");
+
+out:
+	close (fd);
+	sync();
+
+	return 0;
+}
+
diff --git a/target/linux/kirkwood/config-3.3 b/target/linux/kirkwood/config-3.3
index 804e547..fbc018d 100644
--- a/target/linux/kirkwood/config-3.3
+++ b/target/linux/kirkwood/config-3.3
@@ -42,6 +42,7 @@ CONFIG_CRC16=y
 CONFIG_DECOMPRESS_LZMA=y
 # CONFIG_DLCI is not set
 CONFIG_DNOTIFY=y
+CONFIG_ETHERNET_PACKET_MANGLE=y
 CONFIG_EXT4_FS=y
 CONFIG_FRAME_POINTER=y
 CONFIG_FS_MBCACHE=y
@@ -86,6 +87,9 @@ CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
 CONFIG_HAVE_SCHED_CLOCK=y
 CONFIG_HAVE_SPARSE_IRQ=y
 CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_MV64XXX=y
 CONFIG_INET_LRO=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_IP_PIMSM_V1=y
@@ -95,12 +99,15 @@ CONFIG_KTIME_SCALAR=y
 CONFIG_LEDS_GPIO=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_LZO_COMPRESS is not set
+# CONFIG_LZO_DECOMPRESS is not set
 # CONFIG_MACH_D2NET_V2 is not set
 # CONFIG_MACH_DB88F6281_BP is not set
+CONFIG_MACH_DIR665=y
 CONFIG_MACH_DOCKSTAR=y
-CONFIG_MACH_GOFLEXNET=y
+CONFIG_MACH_ESATA_SHEEVAPLUG=y
 CONFIG_MACH_GOFLEXHOME=y
-CONFIG_MACH_ESATA_SHEEVAPLUG=y 
+CONFIG_MACH_GOFLEXNET=y
 # CONFIG_MACH_GURUPLUG is not set
 CONFIG_MACH_ICONNECT=y
 # CONFIG_MACH_INETSPACE_V2 is not set
@@ -126,23 +133,22 @@ CONFIG_MMC=y
 CONFIG_MMC_BLOCK=y
 CONFIG_MMC_MVSDIO=y
 # CONFIG_MMC_TIFM_SD is not set
-# CONFIG_MTD_CFI is not set
 CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_IMPA7 is not set
+CONFIG_MTD_JEDECPROBE=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ECC=y
 CONFIG_MTD_NAND_ORION=y
-# CONFIG_MTD_ROOTFS_ROOT_DEV is not set
-# CONFIG_MTD_ROOTFS_SPLIT is not set
 # CONFIG_MTD_SM_COMMON is not set
 CONFIG_MV643XX_ETH=y
+CONFIG_MVSWITCH_PHY=y
 CONFIG_NEED_DMA_MAP_STATE=y
 CONFIG_NEED_PER_CPU_KM=y
 CONFIG_NET_DSA=y
 # CONFIG_NET_DSA_MV88E6060 is not set
-CONFIG_NET_DSA_MV88E6131=y
+CONFIG_NET_DSA_MV88E6123_61_65=y
 CONFIG_NET_DSA_MV88E6XXX=y
-CONFIG_NET_DSA_MV88E6XXX_NEED_PPU=y
-CONFIG_NET_DSA_TAG_DSA=y
+CONFIG_NET_DSA_TAG_EDSA=y
 # CONFIG_NET_DSA_TAG_TRAILER is not set
 CONFIG_NLS=y
 CONFIG_OUTER_CACHE=y
@@ -154,9 +160,15 @@ CONFIG_PHYLIB=y
 CONFIG_PLAT_ORION=y
 # CONFIG_PREEMPT_RCU is not set
 CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MV is not set
 CONFIG_SCSI=y
 # CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_ORION=y
 CONFIG_SPLIT_PTLOCK_CPUS=999999
+CONFIG_SWCONFIG=y
+CONFIG_SWCONFIG_LEDS=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
 CONFIG_UID16=y
 CONFIG_USB=y
diff --git a/target/linux/ramips/base-files/etc/diag.sh b/target/linux/ramips/base-files/etc/diag.sh
index 395ed6f..680f218 100755
--- a/target/linux/ramips/base-files/etc/diag.sh
+++ b/target/linux/ramips/base-files/etc/diag.sh
@@ -33,6 +33,9 @@ get_status_led() {
 	3g-6200n)
 		status_led="edimax:green:power"
 		;;
+        ar725w)
+                status_led="ar725w:green:power"
+                ;;
 	argus-atp52b)
 		status_led="argus-atp52b:green:run"
 		;;
@@ -119,6 +122,15 @@ get_status_led() {
 	wr512-3gn)
 		status_led="wr512:green:wps"
 		;;
+	wrt100)
+		status_led="wrt100:green:power"
+		;;
+	wrt110)
+		status_led="wrt110:blue:power"
+		;;
+	wrt160nv2)
+		status_led="wrt160nv2:blue:power"
+		;;
 	ur-336un)
 		status_led="ur336:green:wps"
 		;;
diff --git a/target/linux/ramips/base-files/etc/hotplug.d/firmware/10-rt2x00-eeprom b/target/linux/ramips/base-files/etc/hotplug.d/firmware/10-rt2x00-eeprom
index bc4ea02..be28745 100644
--- a/target/linux/ramips/base-files/etc/hotplug.d/firmware/10-rt2x00-eeprom
+++ b/target/linux/ramips/base-files/etc/hotplug.d/firmware/10-rt2x00-eeprom
@@ -48,8 +48,11 @@ case "$FIRMWARE" in
 		rt2x00_eeprom_extract "devconf" 0 512
 		;;
 
+	ar725w | \
 	f5d8235-v1 | \
-	f5d8235-v2)
+	f5d8235-v2 | \
+	wrt100 | \
+	wrt110)
 		rt2x00_eeprom_extract "u-boot" 262144 512
 		;;
 
@@ -97,6 +100,10 @@ case "$FIRMWARE" in
 		rt2x00_eeprom_extract "board-nvram" 64880 512
 		;;
 
+        wrt160nv2)
+                rt2x00_eeprom_extract "u-boot" 261632 512
+                ;;
+
 	*)
 		rt2x00_eeprom_die "board $board is not supported yet"
 		;;
diff --git a/target/linux/ramips/base-files/etc/uci-defaults/fixuimage b/target/linux/ramips/base-files/etc/uci-defaults/fixuimage
new file mode 100755
index 0000000..9969685
--- /dev/null
+++ b/target/linux/ramips/base-files/etc/uci-defaults/fixuimage
@@ -0,0 +1,20 @@
+#!/bin/sh
+#
+# Copyright (C) 2012 OpenWrt.org
+#
+
+. /lib/ramips.sh
+
+fix_uimage_header() {
+	local part=$1
+
+	mtd fixuimage $part
+}
+
+board=$(ramips_board_name)
+
+case "$board" in
+wrt160nv2)
+	fix_uimage_header kernel
+	;;
+esac
diff --git a/target/linux/ramips/base-files/etc/uci-defaults/leds b/target/linux/ramips/base-files/etc/uci-defaults/leds
index 8f2a92b..a62e001 100755
--- a/target/linux/ramips/base-files/etc/uci-defaults/leds
+++ b/target/linux/ramips/base-files/etc/uci-defaults/leds
@@ -25,6 +25,12 @@ case $board in
 		ucidef_set_led_rssi "rssihigh" "RSSIHIGH" "all0256n:green:rssihigh" "wlan0" "70" "100" "-69" "8"
 		set_wifi_led "rt2800pci-phy0::radio"
 		;;
+	ar725w|\
+	wrt100|\
+	wrt110|\
+	wrt160nv2)
+		set_wifi_led "rt2800soc-phy0::radio"
+		;;
 	bc2)
 		set_usb_led "bc2:blue:usb"
 		;;
diff --git a/target/linux/ramips/base-files/etc/uci-defaults/network b/target/linux/ramips/base-files/etc/uci-defaults/network
index cf9c0bb..798a3f9 100755
--- a/target/linux/ramips/base-files/etc/uci-defaults/network
+++ b/target/linux/ramips/base-files/etc/uci-defaults/network
@@ -76,15 +76,19 @@ ramips_setup_interfaces()
 		ucidef_set_interfaces_lan_wan "eth0.1" "eth0.2"
 		;;
 
-	v11st-fe)
+	v11st-fe | \
+        wrt160nv2)
 		ucidef_set_interfaces_lan_wan "eth0.1" "eth0.2"
 		ucidef_add_switch "switch0" "1" "1"
 		ucidef_add_switch_vlan "switch0" "1" "1 2 3 4 5t"
 		ucidef_add_switch_vlan "switch0" "2" "0 5t"
 		;;
 
+        ar725w | \
 	rt-n15 | \
-	wl-351)
+	wl-351 | \
+        wrt100 | \
+        wrt110)
 		ucidef_set_interfaces_lan_wan "eth0.1" "eth0.2"
 		ucidef_add_switch "switch0" "1" "1"
 		ucidef_add_switch_vlan "switch0" "1" "0 1 2 3 5t"
@@ -138,6 +142,7 @@ ramips_setup_macs()
 	dir-615-h1)
 		lan_mac=$(ramips_get_mac_binary factory 40)
 		;;
+
 	3g-6200n | \
 	argus-atp52b | \
 	bc2 | \
@@ -192,7 +197,10 @@ ramips_setup_macs()
                 wan_mac=$(ramips_get_mac_binary factory 40)
 		;;
 
-	f5d8235-v2)
+	ar725w | \
+	f5d8235-v2 | \
+        wrt100 | \
+        wrt110)
 		lan_mac=$(ramips_get_mac_binary "u-boot" 262148)
 		wan_mac=$(/usr/sbin/maccalc add "$lan_mac" 1)
 		;;
@@ -228,6 +236,11 @@ ramips_setup_macs()
 		lan_mac=$(ramips_get_mac_binary factory 4)
 		;;
 
+        wrt160nv2)
+                lan_mac=$(ramips_get_mac_nvram u-boot "mac")
+                wan_mac=$(/usr/sbin/maccalc add "$lan_mac" 1)
+                ;;
+
 	esac
 
 	[ -n "$lan_mac" ] && ucidef_set_interface_macaddr lan $lan_mac
diff --git a/target/linux/ramips/base-files/lib/preinit/05_init_interfaces_ramips b/target/linux/ramips/base-files/lib/preinit/05_init_interfaces_ramips
new file mode 100644
index 0000000..0539b82
--- /dev/null
+++ b/target/linux/ramips/base-files/lib/preinit/05_init_interfaces_ramips
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+set_preinit_iface() {
+	ifname=eth0
+}
+
+boot_hook_add preinit_main set_preinit_iface
diff --git a/target/linux/ramips/base-files/lib/preinit/06_set_iface_mac b/target/linux/ramips/base-files/lib/preinit/06_set_iface_mac
index b959479..257bb1f 100644
--- a/target/linux/ramips/base-files/lib/preinit/06_set_iface_mac
+++ b/target/linux/ramips/base-files/lib/preinit/06_set_iface_mac
@@ -15,6 +15,12 @@ preinit_set_mac_address() {
 		mac=$(ramips_get_mac_binary factory 4)
 		ifconfig eth0 hw ether $mac 2>/dev/null
 		;;
+        ar725w |\
+        wrt100 |\
+        wrt110)
+                mac=$(ramips_get_mac_binary u-boot 262148)
+                ifconfig eth0 hw ether $mac 2>/dev/null
+                ;;
 	bc2 |\
 	dir-620-a1 |\
 	esr-9753 |\
@@ -68,6 +74,10 @@ preinit_set_mac_address() {
 		mac=$(ramips_get_mac_binary devconf 4)
 		ifconfig eth0 hw ether $mac 2>/dev/null
 		;;
+        wrt160nv2)
+                mac=$(ramips_get_mac_nvram u-boot "mac")
+                ifconfig eth0 hw ether $mac 2>/dev/null
+                ;;
 	esac
 }
 
diff --git a/target/linux/ramips/base-files/lib/ramips.sh b/target/linux/ramips/base-files/lib/ramips.sh
index 25a1205..d2a2b4e 100755
--- a/target/linux/ramips/base-files/lib/ramips.sh
+++ b/target/linux/ramips/base-files/lib/ramips.sh
@@ -53,6 +53,9 @@ ramips_board_name() {
 	*"Edimax 3g-6200n")
 		name="3g-6200n"
 		;;
+	*"Airlink101 AR725W")
+		name="ar725w"
+		;;
 	*"Allnet ALL0239-3G")
 		name="all0239-3g"
 		;;
@@ -116,6 +119,15 @@ ramips_board_name() {
 	*"La Fonera 2.0N")
 		name="fonera20n"
 		;;
+	*"Linksys WRT100")
+		name="wrt100"
+		;;
+	*"Linksys WRT110")
+		name="wrt110"
+		;;
+        *"Linksys WRT160Nv2")
+                name="wrt160nv2"
+                ;;
 	*"MoFi Network MOFI3500-3GN")
 		name="mofi3500-3gn"
 		;;
diff --git a/target/linux/ramips/base-files/lib/upgrade/platform.sh b/target/linux/ramips/base-files/lib/upgrade/platform.sh
index 25dbe6e..ba6f6cb 100755
--- a/target/linux/ramips/base-files/lib/upgrade/platform.sh
+++ b/target/linux/ramips/base-files/lib/upgrade/platform.sh
@@ -14,6 +14,7 @@ platform_check_image() {
 	[ "$ARGC" -gt 1 ] && return 1
 
 	case "$board" in
+        ar725w | \
 	3g-6200n | \
 	all0239-3g | \
 	all0256n | \
@@ -54,7 +55,10 @@ platform_check_image() {
 	wli-tx4-ag300n | \
 	whr-g300n |\
 	ur-336un |\
-	wr512-3gn)
+	wr512-3gn |\
+        wrt100 |\
+	wrt110 |\
+        wrt160nv2)
 		[ "$magic" != "27051956" ] && {
 			echo "Invalid image type."
 			return 1
diff --git a/target/linux/ramips/files/arch/mips/include/asm/mach-ralink/machine.h b/target/linux/ramips/files/arch/mips/include/asm/mach-ralink/machine.h
index 83d2e26..aec6c53 100644
--- a/target/linux/ramips/files/arch/mips/include/asm/mach-ralink/machine.h
+++ b/target/linux/ramips/files/arch/mips/include/asm/mach-ralink/machine.h
@@ -14,9 +14,13 @@
 enum ramips_mach_type {
 	RAMIPS_MACH_GENERIC,
 	/* RT2880 based machines */
+	RAMIPS_MACH_AR725W,		/* Airlink101 AR725W */
 	RAMIPS_MACH_F5D8235_V1,		/* Belkin F5D8235 v1 */
 	RAMIPS_MACH_RT_N15,		/* Asus RT-N15 */
 	RAMIPS_MACH_V11ST_FE,		/* Ralink V11ST-FE */
+	RAMIPS_MACH_WRT100,		/* Linksys WRT100 */
+	RAMIPS_MACH_WRT110,		/* Linksys WRT110 */
+	RAMIPS_MACH_WRT160NV2,		/* Linksys WRT160Nv2 */
 	RAMIPS_MACH_WLI_TX4_AG300N,	/* Buffalo WLI-TX4-AG300N */
 	RAMIPS_MACH_WZR_AGL300NH,	/* Buffalo WZR-AGL300NH */
 
diff --git a/target/linux/ramips/files/arch/mips/ralink/rt288x/Kconfig b/target/linux/ramips/files/arch/mips/ralink/rt288x/Kconfig
index 31dcc81..774c905 100644
--- a/target/linux/ramips/files/arch/mips/ralink/rt288x/Kconfig
+++ b/target/linux/ramips/files/arch/mips/ralink/rt288x/Kconfig
@@ -2,6 +2,11 @@ if RALINK_RT288X
 
 menu "Ralink RT288x machine selection"
 
+config RT288X_MACH_AR725W
+	bool "Airlink101 AR725W board support"
+	select RALINK_DEV_GPIO_BUTTONS
+	select RALINK_DEV_GPIO_LEDS
+
 config RT288X_MACH_F5D8235_V1
 	bool "Belkin F5D8235 V1 board support"
 	select RALINK_DEV_GPIO_LEDS
@@ -11,6 +16,16 @@ config RT288X_MACH_RT_N15
 	select RALINK_DEV_GPIO_BUTTONS
 	select RALINK_DEV_GPIO_LEDS
 
+config RT288X_MACH_WRT110
+	bool "Linksys WRT110 board support"
+	select RALINK_DEV_GPIO_BUTTONS
+	select RALINK_DEV_GPIO_LEDS
+
+config RT288X_MACH_WRT160NV2
+	bool "Linksys WRT160NV2 board support"
+	select RALINK_DEV_GPIO_BUTTONS
+	select RALINK_DEV_GPIO_LEDS
+
 config RT288X_MACH_V11ST_FE
 	bool "Ralink V11ST-FE board support"
 	select HW_HAS_PCI
diff --git a/target/linux/ramips/files/arch/mips/ralink/rt288x/Makefile b/target/linux/ramips/files/arch/mips/ralink/rt288x/Makefile
index 473f855..6ffc3fb 100644
--- a/target/linux/ramips/files/arch/mips/ralink/rt288x/Makefile
+++ b/target/linux/ramips/files/arch/mips/ralink/rt288x/Makefile
@@ -13,8 +13,11 @@ obj-y	:= irq.o setup.o rt288x.o devices.o clock.o
 
 obj-$(CONFIG_EARLY_PRINTK)		+= early_printk.o
 
+obj-$(CONFIG_RT288X_MACH_AR725W)	+= mach-ar725w.o
 obj-$(CONFIG_RT288X_MACH_F5D8235_V1)	+= mach-f5d8235-v1.o
 obj-$(CONFIG_RT288X_MACH_RT_N15)	+= mach-rt-n15.o
 obj-$(CONFIG_RT288X_MACH_V11ST_FE)	+= mach-v11st-fe.o
 obj-$(CONFIG_RT288X_MACH_WLI_TX4_AG300N) += mach-wli-tx4-ag300n.o
+obj-$(CONFIG_RT288X_MACH_WRT110)	+= mach-wrt110.o
+obj-$(CONFIG_RT288X_MACH_WRT160NV2)	+= mach-wrt160nv2.o
 obj-$(CONFIG_RT288X_MACH_WZR_AGL300NH)	+= mach-wzr-agl300nh.o
diff --git a/target/linux/ramips/files/arch/mips/ralink/rt288x/mach-ar725w.c b/target/linux/ramips/files/arch/mips/ralink/rt288x/mach-ar725w.c
new file mode 100644
index 0000000..873795c
--- /dev/null
+++ b/target/linux/ramips/files/arch/mips/ralink/rt288x/mach-ar725w.c
@@ -0,0 +1,117 @@
+/*
+ *  Airlink101 AR725W support
+ *
+ *  Copyright (C) 2014 Claudio Leite <leitec@staticky.com>
+ *
+ *  Based on V11ST-FE support code:
+ *
+ *  Copyright (C) 2012 Florian Fainelli <florian@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/ethtool.h>
+
+#include <asm/mach-ralink/machine.h>
+#include <asm/mach-ralink/dev-gpio-buttons.h>
+#include <asm/mach-ralink/dev-gpio-leds.h>
+#include <asm/mach-ralink/rt288x.h>
+#include <asm/mach-ralink/rt288x_regs.h>
+#include <asm/mach-ralink/ramips_eth_platform.h>
+
+#include "devices.h"
+
+#define AR725W_GPIO_WPS_RED_LED         8
+#define AR725W_GPIO_WPS_BLUE_LED        13
+
+#define AR725W_GPIO_POWER_LED           7
+
+#define AR725W_GPIO_BUTTON_WPS	        0
+#define AR725W_GPIO_BUTTON_RESET        9
+
+#define AR725W_KEYS_POLL_INTERVAL	20
+#define AR725W_KEYS_DEBOUNCE_INTERVAL	(3 * AR725W_KEYS_POLL_INTERVAL)
+
+static struct gpio_led ar725w_leds_gpio[] __initdata = {
+        {
+                .name           = "ar725w:green:power",
+                .gpio           = AR725W_GPIO_POWER_LED,
+                .active_low     = 0,
+        },
+        {
+                .name           = "ar725w:red:wps",
+                .gpio           = AR725W_GPIO_WPS_RED_LED,
+                .active_low     = 1,
+        },
+        {
+                .name           = "ar725w:blue:wps",
+                .gpio           = AR725W_GPIO_WPS_BLUE_LED,
+                .active_low     = 1,
+        },
+};
+
+static struct gpio_keys_button ar725w_gpio_buttons[] __initdata = {
+	{
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = AR725W_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AR725W_GPIO_BUTTON_WPS,
+                .active_low     = 1,
+	},
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = AR725W_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AR725W_GPIO_BUTTON_RESET,
+		.active_low	= 1,
+	} 
+};
+
+static void __init rt_ar725w_init(void)
+{
+        u32 t;
+
+	rt288x_gpio_init(
+                RT2880_GPIO_MODE_I2C |
+                RT2880_GPIO_MODE_UART0 |
+                RT2880_GPIO_MODE_SPI);
+
+	rt288x_register_flash(0);
+
+	ramips_register_gpio_leds(-1, ARRAY_SIZE(ar725w_leds_gpio),
+				  ar725w_leds_gpio);
+
+	ramips_register_gpio_buttons(-1, AR725W_KEYS_POLL_INTERVAL,
+				     ARRAY_SIZE(ar725w_gpio_buttons),
+				     ar725w_gpio_buttons);
+
+        /* 
+         * Enable GPIOs 8, 10, 13 according to Gemtek
+         * GPL sources (Linksys WRT110)
+         *
+         * Clear bit 6 to <do something>
+         */
+        t = rt288x_sysc_rr(SYSC_REG_SYSTEM_CONFIG);
+        t &= ~BIT(6);
+        rt288x_sysc_wr(t, SYSC_REG_SYSTEM_CONFIG);
+
+	rt288x_register_wifi();
+
+	/* Board is connected to an IC+ IP175C Fast Ethernet switch */
+	rt288x_eth_data.speed = SPEED_100;
+	rt288x_eth_data.duplex = DUPLEX_FULL;
+	rt288x_eth_data.tx_fc = 1;
+	rt288x_eth_data.rx_fc = 1;
+	rt288x_eth_data.phy_mask = BIT(0);
+	rt288x_register_ethernet();
+
+	rt288x_register_wdt();
+}
+
+MIPS_MACHINE(RAMIPS_MACH_AR725W, "AR725W", "Airlink101 AR725W", rt_ar725w_init);
diff --git a/target/linux/ramips/files/arch/mips/ralink/rt288x/mach-wrt110.c b/target/linux/ramips/files/arch/mips/ralink/rt288x/mach-wrt110.c
new file mode 100644
index 0000000..5c73648
--- /dev/null
+++ b/target/linux/ramips/files/arch/mips/ralink/rt288x/mach-wrt110.c
@@ -0,0 +1,155 @@
+/*
+ *  Linksys WRT100/WRT110 support
+ *
+ *  Copyright (C) 2014 Claudio Leite <leitec@staticky.com>
+ *
+ *  Based on V11ST-FE support code:
+ *
+ *  Copyright (C) 2012 Florian Fainelli <florian@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/ethtool.h>
+
+#include <asm/mach-ralink/machine.h>
+#include <asm/mach-ralink/dev-gpio-buttons.h>
+#include <asm/mach-ralink/dev-gpio-leds.h>
+#include <asm/mach-ralink/rt288x.h>
+#include <asm/mach-ralink/rt288x_regs.h>
+#include <asm/mach-ralink/ramips_eth_platform.h>
+
+#include "devices.h"
+
+#define WRT110_GPIO_WPS_BLUE_LED        8
+#define WRT110_GPIO_WPS_AMBER_LED       13
+#define WRT110_GPIO_POWER_LED           12
+
+#define WRT100_GPIO_SECURITY_GREEN_LED  8
+#define WRT100_GPIO_SECURITY_AMBER_LED  13
+#define WRT100_GPIO_POWER_LED           12
+
+#define WRT1X0_GPIO_BUTTON_WPS	        0
+#define WRT1X0_GPIO_BUTTON_RESET        9
+
+#define WRT1X0_KEYS_POLL_INTERVAL	20
+#define WRT1X0_KEYS_DEBOUNCE_INTERVAL	(3 * WRT1X0_KEYS_POLL_INTERVAL)
+
+static struct gpio_led wrt110_leds_gpio[] __initdata = {
+        {
+            .name           = "wrt110:blue:power",
+            .gpio           = WRT110_GPIO_POWER_LED,
+            .active_low     = 0,
+        },
+        {
+            .name           = "wrt110:blue:wps",
+            .gpio           = WRT110_GPIO_WPS_BLUE_LED,
+            .active_low     = 1,
+        },
+        {
+            .name           = "wrt110:amber:wps",
+            .gpio           = WRT110_GPIO_WPS_AMBER_LED,
+            .active_low     = 1,
+        },
+
+};
+
+static struct gpio_led wrt100_leds_gpio[] __initdata = {
+        {
+            .name           = "wrt100:green:power",
+            .gpio           = WRT100_GPIO_POWER_LED,
+            .active_low     = 0,
+        },
+        {
+            .name           = "wrt100:green:security",
+            .gpio           = WRT100_GPIO_SECURITY_GREEN_LED,
+            .active_low     = 1,
+        },
+        {
+            .name           = "wrt100:amber:security",
+            .gpio           = WRT100_GPIO_SECURITY_AMBER_LED,
+            .active_low     = 1,
+        },
+
+};
+
+static struct gpio_keys_button wrt1x0_gpio_buttons[] __initdata = {
+	{
+            .desc              = "wps",
+            .type              = EV_KEY,
+            .code              = KEY_WPS_BUTTON,
+            .debounce_interval = WRT1X0_KEYS_DEBOUNCE_INTERVAL,
+            .gpio              = WRT1X0_GPIO_BUTTON_WPS,
+            .active_low        = 1,
+	},
+	{
+            .desc              = "reset",
+            .type              = EV_KEY,
+            .code              = KEY_RESTART,
+            .debounce_interval = WRT1X0_KEYS_DEBOUNCE_INTERVAL,
+            .gpio              = WRT1X0_GPIO_BUTTON_RESET,
+            .active_low        = 1,
+	} 
+};
+
+static void __init rt_wrt1x0_init(int type)
+{
+        u32 t;
+
+	rt288x_gpio_init(
+                RT2880_GPIO_MODE_I2C |
+                RT2880_GPIO_MODE_UART0 |
+                RT2880_GPIO_MODE_SPI);
+
+	rt288x_register_flash(0);
+
+        if(type == 0) 
+            ramips_register_gpio_leds(-1, ARRAY_SIZE(wrt100_leds_gpio),
+                                      wrt100_leds_gpio);
+        else
+            ramips_register_gpio_leds(-1, ARRAY_SIZE(wrt110_leds_gpio),
+                                      wrt110_leds_gpio);
+
+        ramips_register_gpio_buttons(-1, WRT1X0_KEYS_POLL_INTERVAL,
+                                     ARRAY_SIZE(wrt1x0_gpio_buttons),
+                                     wrt1x0_gpio_buttons);
+
+        /* 
+         * Enable GPIOs 8, 10, 13 according to Gemtek
+         * GPL sources (Linksys WRT110)
+         *
+         * Clear bit 6 to <do something>
+         */
+        t = rt288x_sysc_rr(SYSC_REG_SYSTEM_CONFIG);
+        t &= ~BIT(6);
+        rt288x_sysc_wr(t, SYSC_REG_SYSTEM_CONFIG);
+
+	rt288x_register_wifi();
+
+	/* Board is connected to an IC+ IP175C Fast Ethernet switch */
+	rt288x_eth_data.speed = SPEED_100;
+	rt288x_eth_data.duplex = DUPLEX_FULL;
+	rt288x_eth_data.tx_fc = 1;
+	rt288x_eth_data.rx_fc = 1;
+	rt288x_eth_data.phy_mask = BIT(0);
+	rt288x_register_ethernet();
+
+	rt288x_register_wdt();
+}
+
+static void __init rt_wrt100_init(void)
+{
+    rt_wrt1x0_init(0);
+}
+
+static void __init rt_wrt110_init(void)
+{
+    rt_wrt1x0_init(1);
+}
+
+MIPS_MACHINE(RAMIPS_MACH_WRT100, "WRT100", "Linksys WRT100", rt_wrt100_init);
+MIPS_MACHINE(RAMIPS_MACH_WRT110, "WRT110", "Linksys WRT110", rt_wrt110_init);
diff --git a/target/linux/ramips/files/arch/mips/ralink/rt288x/mach-wrt160nv2.c b/target/linux/ramips/files/arch/mips/ralink/rt288x/mach-wrt160nv2.c
new file mode 100644
index 0000000..afd1b13
--- /dev/null
+++ b/target/linux/ramips/files/arch/mips/ralink/rt288x/mach-wrt160nv2.c
@@ -0,0 +1,118 @@
+/*
+ *  Linksys WRT160Nv2 support
+ *
+ *  Copyright (C) 2014 Claudio Leite <leitec@staticky.com>
+ *
+ *  Based on V11ST-FE support code:
+ *
+ *  Copyright (C) 2012 Florian Fainelli <florian@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/ethtool.h>
+
+#include <asm/mach-ralink/machine.h>
+#include <asm/mach-ralink/dev-gpio-buttons.h>
+#include <asm/mach-ralink/dev-gpio-leds.h>
+#include <asm/mach-ralink/rt288x.h>
+#include <asm/mach-ralink/rt288x_regs.h>
+#include <asm/mach-ralink/ramips_eth_platform.h>
+
+#include "devices.h"
+
+#define WRT160NV2_GPIO_WPS_AMBER_LED       8
+#define WRT160NV2_GPIO_WPS_BLUE_LED       13
+
+#define WRT160NV2_GPIO_POWER_LED          12
+
+#define WRT160NV2_GPIO_BUTTON_WPS	   0
+#define WRT160NV2_GPIO_BUTTON_RESET        9
+
+#define WRT160NV2_KEYS_POLL_INTERVAL	20
+#define WRT160NV2_KEYS_DEBOUNCE_INTERVAL	(3 * WRT160NV2_KEYS_POLL_INTERVAL)
+
+static struct gpio_led wrt160nv2_leds_gpio[] __initdata = {
+        {
+                .name           = "wrt160nv2:blue:power",
+                .gpio           = WRT160NV2_GPIO_POWER_LED,
+                .active_low     = 1,
+        },
+        {
+                .name           = "wrt160nv2:amber:wps",
+                .gpio           = WRT160NV2_GPIO_WPS_AMBER_LED,
+                .active_low     = 1,
+        },
+        {
+                .name           = "wrt160nv2:blue:wps",
+                .gpio           = WRT160NV2_GPIO_WPS_BLUE_LED,
+                .active_low     = 1,
+        },
+};
+
+static struct gpio_keys_button wrt160nv2_gpio_buttons[] __initdata = {
+	{
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WRT160NV2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WRT160NV2_GPIO_BUTTON_WPS,
+                .active_low     = 1,
+	},
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WRT160NV2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WRT160NV2_GPIO_BUTTON_RESET,
+		.active_low	= 1,
+	} 
+};
+
+static void __init rt_wrt160nv2_init(void)
+{
+        u32 t;
+
+	rt288x_gpio_init(
+                RT2880_GPIO_MODE_I2C |
+                RT2880_GPIO_MODE_UART0 |
+                RT2880_GPIO_MODE_SPI |
+                RT2880_GPIO_MODE_PCI);
+
+	rt288x_register_flash(0);
+
+	ramips_register_gpio_leds(-1, ARRAY_SIZE(wrt160nv2_leds_gpio),
+				  wrt160nv2_leds_gpio);
+
+	ramips_register_gpio_buttons(-1, WRT160NV2_KEYS_POLL_INTERVAL,
+				     ARRAY_SIZE(wrt160nv2_gpio_buttons),
+				     wrt160nv2_gpio_buttons);
+
+        /* 
+         * Enable GPIOs 8, 10, 13 according to Gemtek
+         * GPL sources (Linksys WRT110)
+         *
+         * Clear bit 6 to <do something>
+         */
+        t = rt288x_sysc_rr(SYSC_REG_SYSTEM_CONFIG);
+        t &= ~BIT(6);
+        rt288x_sysc_wr(t, SYSC_REG_SYSTEM_CONFIG);
+
+	rt288x_register_wifi();
+
+	/* Board is connected to a RTL8306 Fast Ethernet switch */
+	rt288x_eth_data.speed = SPEED_100;
+	rt288x_eth_data.duplex = DUPLEX_FULL;
+	rt288x_eth_data.tx_fc = 1;
+	rt288x_eth_data.rx_fc = 1;
+	rt288x_eth_data.phy_mask = BIT(0);
+	rt288x_register_ethernet();
+
+	rt288x_register_wdt();
+}
+
+MIPS_MACHINE(RAMIPS_MACH_WRT160NV2, "WRT160NV2", "Linksys WRT160Nv2", rt_wrt160nv2_init);
diff --git a/target/linux/ramips/image/Makefile b/target/linux/ramips/image/Makefile
index 3c0024b..32c36ad 100644
--- a/target/linux/ramips/image/Makefile
+++ b/target/linux/ramips/image/Makefile
@@ -254,6 +254,117 @@ define BuildFirmware/F5D8235
 	$(call BuildFirmware/Generic,$(1),$(2),$(call mkcmdline,$(3),ttyS1,57600) $(call  mkmtd/phys,$(mtdlayout_f5d8235)),$(mtd_f5d8235_kernel_part_size),$(mtd_f5d8235_rootfs_part_size))
 endef
 
+# Factory layout is 2432k(rootfs),320k(langpack),64k(nvram),64k(factory_nvram)
+# rootfs_part_size=2490368
+#
+# not sure what langpack is, and it seems to be erased by the
+# factory flash (at least the Asante one) so it should be
+# safe to erase for us, too.
+#
+# erasing NVRAM doesn't seem to be a problem.
+# very little appears to be in "factory_nvram" -- the only HW
+# info is in the u-boot partition @ 0x40000.
+# 
+# this does mean you lose your prefs. if reverting to the
+# factory FW, but you can back that up first if that's
+# important.
+#
+# factory flash images have a max size of 0x340000 bytes,
+# since the factory firmware's upgrade process deletes
+# the "langpack" partition
+mtdlayout_ar725w=320k(u-boot)ro,896k(kernel),2880k(rootfs),3776k@0x50000(firmware)
+mtd_ar725w_kernel_part_size=917504
+mtd_ar725w_rootfs_part_size=2949120
+define BuildFirmware/AR725W
+	$(call BuildFirmware/Generic,$(1),$(2),$(call mkcmdline,$(3),ttyS1,57600) $(call  mkmtd/phys,$(mtdlayout_ar725w)),$(mtd_ar725w_kernel_part_size),$(mtd_ar725w_rootfs_part_size))
+	if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+		mkheader_gemtek "$(call sysupname,$(1),$(2))" \
+		 "$(call imgname,$(1),$(2))-factory.bin" 0 || \
+		   rm -f "$(call imgname,$(1),$(2))-factory.bin"; \
+	fi
+endef
+
+define BuildFirmware/AWRT600N
+	$(call BuildFirmware/Generic,$(1),$(2),$(call mkcmdline,$(3),ttyS1,57600) $(call  mkmtd/phys,$(mtdlayout_ar725w)),$(mtd_ar725w_kernel_part_size),$(mtd_ar725w_rootfs_part_size))
+	if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+		mkheader_gemtek "$(call sysupname,$(1),$(2))" \
+		 "$(call imgname,$(1),$(2))-factory.bin" 1 || \
+		   rm -f "$(call imgname,$(1),$(2))-factory.bin"; \
+	fi
+endef
+
+# Linksys WRT110's layout is the same as the AR725W
+define BuildFirmware/WRT110
+	$(call BuildFirmware/Generic,$(1),$(2),$(call mkcmdline,$(3),ttyS1,57600) $(call  mkmtd/phys,$(mtdlayout_ar725w)),$(mtd_ar725w_kernel_part_size),$(mtd_ar725w_rootfs_part_size))
+	if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+		mkheader_gemtek "$(call sysupname,$(1),$(2))" \
+		 "$(call imgname,$(1),$(2))-factory.bin" 2 || \
+		   rm -f "$(call imgname,$(1),$(2))-factory.bin"; \
+	fi
+endef
+
+# The WRT160N v2 uses a wacky combination of uImage and TRX.
+# u-Boot is actually modified to allow that.
+#
+# We can get away with packing only the kernel in the TRX for
+# booting purposes, but if we want to make a firmware image
+# that the factory firmware can use we have to stick the
+# rootfs in there, too.
+mtdlayout_wrt160nv2=256k(u-boot)ro,896k(kernel),2880k(rootfs),64k(nvram)ro,3776k@0x40000(firmware)
+mtd_wrt160nv2_kernel_part_size=917504
+mtd_wrt160nv2_rootfs_part_size=2949120
+
+define BuildFirmware/WRT160NV2
+	$(call PatchKernelLzma,$(2),$(call mkcmdline,$(3),ttyS1,115200) $(call  mkmtd/phys,$(mtdlayout_wrt160nv2)))
+
+	$(eval imagename=MIPS OpenWrt Linux-$(LINUX_VERSION))
+
+	# build a sysupgrade-compatible image. the uImage
+	# and TRX contain only the kernel. this image needs
+	# no header adjustment post-firstboot
+	
+	trx -o $(KDIR)/vmlinux-$(2).trx \
+	    -f $(KDIR)/vmlinux-$(2).bin.lzma
+
+	mkimage -A mips -O linux -T kernel -C lzma $(call kernel_entry)\
+		-n "$(imagename)" \
+		-d $(KDIR)/vmlinux-$(2).trx $(KDIR)/vmlinux-$(2).uImage
+
+	$(call Sysupgrade/KRuImage,$(1),$(2),$(mtd_wrt160nv2_kernel_part_size),$(mtd_wrt160nv2_rootfs_part_size))
+	# stuff for web-compatible image
+	#
+	# the web flash needs a TRX with both kernel and rootfs,
+	# and the uImage wraps the whole TRX. We pad the kernel
+	# so that the rootfs partition lines up still
+	#
+	# The uImage header needs to be adjusted post-firstboot
+	# otherwise the jffs2 formatting causes boot-time CRC check
+	# to fail.
+	
+	# 92 = trx header (28) + uImage header (64)
+	# XXX check if image is too big
+	dd if=$(KDIR)/vmlinux-$(2).bin.lzma \
+	   of=$(KDIR)/vmlinux-$(2).bin.lzma.pad \
+	   bs=`expr $(mtd_wrt160nv2_kernel_part_size) - 92` conv=sync
+
+	trx -o $(KDIR)/image-$(2).trx \
+	    -f $(KDIR)/vmlinux-$(2).bin.lzma.pad \
+	    -f $(KDIR)/root.$(1)
+
+	mkimage -A mips -O linux -T kernel -C lzma $(call kernel_entry)\
+		-n "$(imagename)" \
+		-d $(KDIR)/image-$(2).trx $(KDIR)/image-$(2).uImage
+	
+	# append web/tftp "code" header 
+	# the "-code.bin" is something the TFTP recovery requires
+	
+	addpattern -g \
+	           -p "N160" \
+	           -v v2.0.02 \
+		   -i $(KDIR)/image-$(2).uImage \
+		   -o "$(call imgname,$(1),$(2))-factory-code.bin"
+endef
+
 define BuildFirmware/FONERA20N
 	$(call BuildFirmware/GENERIC_8M,$(1),fonera20n,FONERA20N,ttyS1,57600,phys)
 	$(call BuildFirmware/Edimax,$(1),fonera20n,RSDK,NL1T,0x50000,0xc0000)
@@ -408,6 +519,20 @@ endef
 #
 # RT288X Profiles
 #
+define Image/Build/Profile/AR725W
+	$(call Image/Build/Template/$(fs_squash)/$(1),AR725W,ar725w,AR725W)
+	$(call Image/Build/Template/$(fs_squash)/$(1),AWRT600N,awrt600n,AR725W)
+endef
+
+define Image/Build/Profile/WRT110
+	$(call Image/Build/Template/$(fs_squash)/$(1),WRT110,wrt110,WRT110)
+	$(call Image/Build/Template/$(fs_squash)/$(1),WRT110,wrt100,WRT100)
+endef
+
+define Image/Build/Profile/WRT160NV2
+	$(call Image/Build/Template/$(fs_squash)/$(1),WRT160NV2,wrt160nv2,WRT160NV2)
+endef
+
 define Image/Build/Profile/F5D8235V1
 	$(call Image/Build/Template/$(fs_squash)/$(1),F5D8235,f5d8235v1,F5D8235_V1)
 endef
@@ -426,6 +551,7 @@ endef
 
 ifeq ($(CONFIG_RALINK_RT288X),y)
 define Image/Build/Profile/Default
+	$(call Image/Build/Profile/AR725W,$(1))
 	$(call Image/Build/Profile/F5D8235V1,$(1))
 	$(call Image/Build/Profile/RTN15,$(1))
 	$(call Image/Build/Profile/V11STFE,$(1))
diff --git a/target/linux/ramips/rt288x/config-3.3 b/target/linux/ramips/rt288x/config-3.3
index d472e64..990a8ff 100644
--- a/target/linux/ramips/rt288x/config-3.3
+++ b/target/linux/ramips/rt288x/config-3.3
@@ -62,6 +62,8 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_IP17XX_PHY=y
 CONFIG_IRQ_CPU=y
 CONFIG_IRQ_FORCED_THREADING=y
+# CONFIG_LZO_COMPRESS is not set
+# CONFIG_LZO_DECOMPRESS is not set
 CONFIG_MDIO_BOARDINFO=y
 # CONFIG_MII is not set
 CONFIG_MIPS=y
@@ -91,11 +93,15 @@ CONFIG_RALINK_RT288X=y
 # CONFIG_RALINK_RT305X is not set
 # CONFIG_RALINK_RT3883 is not set
 CONFIG_RAMIPS_WDT=y
+CONFIG_RT288X_MACH_AR725W=y
 CONFIG_RT288X_MACH_F5D8235_V1=y
 CONFIG_RT288X_MACH_RT_N15=y
 CONFIG_RT288X_MACH_V11ST_FE=y
 CONFIG_RT288X_MACH_WLI_TX4_AG300N=y
+CONFIG_RT288X_MACH_WRT110=y
+CONFIG_RT288X_MACH_WRT160NV2=y
 CONFIG_RT288X_MACH_WZR_AGL300NH=y
+CONFIG_RTL8306_PHY=y
 CONFIG_RTL8366S_PHY=y
 CONFIG_RTL8366_SMI=y
 # CONFIG_SCSI_DMA is not set
diff --git a/target/linux/ramips/rt288x/profiles/airlink101.mk b/target/linux/ramips/rt288x/profiles/airlink101.mk
new file mode 100644
index 0000000..36a4ccc
--- /dev/null
+++ b/target/linux/ramips/rt288x/profiles/airlink101.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/AR725W
+       NAME:=Airlink101 AR725W
+       PACKAGES:=kmod-switch-ip17xx kmod-swconfig swconfig
+endef
+
+define Profile/AR725W/Description
+       Package set for Airlink101 AR725W
+endef
+
+$(eval $(call Profile,AR725W))
+
diff --git a/target/linux/ramips/rt288x/profiles/linksys.mk b/target/linux/ramips/rt288x/profiles/linksys.mk
new file mode 100644
index 0000000..0f4d189
--- /dev/null
+++ b/target/linux/ramips/rt288x/profiles/linksys.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/WRT110
+       NAME:=Linksys WRT100/WRT110
+       PACKAGES:=kmod-switch-ip17xx kmod-swconfig swconfig
+endef
+
+define Profile/WRT110/Description
+       Package set for Linksys WRT100/WRT110
+endef
+
+$(eval $(call Profile,WRT110))
+
+define Profile/WRT160NV2
+       NAME:=Linksys WRT160N v2
+       PACKAGES:=kmod-switch-rtl8306 kmod-swconfig swconfig
+endef
+
+define Profile/WRT160NV2/Description
+       Package set for Linksys WRT160N v2
+endef
+
+$(eval $(call Profile,WRT160NV2))
diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile
index 3fdf2d0..bd8d71c 100644
--- a/tools/firmware-utils/Makefile
+++ b/tools/firmware-utils/Makefile
@@ -62,6 +62,7 @@ define Host/Compile
 	$(call cc, mkcameofw, -Wall)
 	$(call cc,seama md5)
 	$(call cc,fix-u-media-header cyg_crc32,-Wall)
+	$(call cc,mkheader_gemtek,-lz)
 endef
 
 define Host/Install
diff --git a/tools/firmware-utils/src/mkheader_gemtek.c b/tools/firmware-utils/src/mkheader_gemtek.c
new file mode 100644
index 0000000..2ca6f2a
--- /dev/null
+++ b/tools/firmware-utils/src/mkheader_gemtek.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2014  Claudio Leite <leitec@staticky.com>
+ *
+ * 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
+ */
+
+/*
+ * Builds a proper flash image for routers using some Gemtek
+ * OEM boards. These include the Airlink101 AR725W, the
+ * Asante SmartHub 600 (AWRT-600N), and Linksys WRT110.
+ *
+ * The resulting image is compatible with the factory firmware
+ * web upgrade and TFTP interface.
+ *
+ * To build:
+ *  gcc -O2 -o mkheader_gemtek mkheader_gemtek.c -lz
+ *
+ * Claudio Leite <leitec@staticky.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <zlib.h> /* for crc32() */
+
+/*
+ * The header is in little-endian format. In case
+ * we are on a BE host, we need to swap binary
+ * values.
+ */
+#if defined(__linux__)
+# include <endian.h>
+#elif defined(__APPLE__)
+#include <libkern/OSByteOrder.h>
+#define le32 OSSwapHostToLittleInt32
+#else
+# include <sys/endian.h> /* BSD's should have this */
+#endif
+
+#ifndef __APPLE__
+# if __BYTE_ORDER == __BIG_ENDIAN
+#  define le32(x) (((x & 0xFF000000) >> 24) | \
+                   ((x & 0x00FF0000) >> 8)  | \
+                   ((x & 0x0000FF00) << 8)  | \
+                   ((x & 0x000000FF) << 24))
+# else
+#  define le32(x) (x)
+# endif
+#endif
+
+struct gemtek_header {
+    uint8_t magic[4];
+    uint8_t version[4];
+    uint32_t product_id;
+    uint32_t imagesz;
+    uint32_t checksum;
+    uint32_t fast_checksum;
+    uint8_t build[4];
+    uint8_t lang[4];
+};
+
+struct machines {
+    char *desc;
+    uint32_t maxsize;
+    struct gemtek_header header;
+};
+
+struct machines mach_def[] = {
+    { "Airlink101 AR725W", 0x340000,
+      { "GMTK", "1003", le32(0x03000001), 0, 0,
+          0, "01\0\0",  "EN\0\0" }},
+    { "Asante AWRT-1600N", 0x340000,
+      { "A600", "1005", le32(0x03000001), 0, 0,
+          0, "01\0\0",  "EN\0\0" }},
+    { "Linksys WRT110",    0x320000,
+      { "GMTK", "1007", le32(0x03040001), 0, 0,
+          0, "2\0\0\0", "EN\0\0" }},
+    { 0 }
+};
+
+int main(int argc, char *argv[])
+{
+    unsigned long res, flen;
+    struct gemtek_header my_hdr;
+    FILE *f, *f_out;
+    int image_type = 0, index;
+    uint8_t *buf;
+    uint32_t crc;
+
+    if(argc < 3) {
+        fprintf(stderr, "mkheader_gemtek <uImage> <webflash image> [machine ID]\n");
+        fprintf(stderr, "  where [machine ID] is one of:\n");
+        for(index = 0; mach_def[index].desc != 0; index++) {
+            fprintf(stderr, "    %2d  %s", index, mach_def[index].desc);
+            if(index == 0)
+                fprintf(stderr, " (default)\n");
+            else
+                fprintf(stderr, "\n");
+        }
+
+        exit(-1);
+    }
+
+    if(argc == 4) {
+        image_type = atoi(argv[3]);
+    }
+
+    printf("Opening %s...\n", argv[1]);
+
+    f = fopen(argv[1], "r");
+
+    fseek(f, 0, SEEK_END);
+    flen = (unsigned long)ftell(f);
+
+    printf("  %lu (0x%lX) bytes long\n", flen, flen);
+
+    if(flen > mach_def[image_type].maxsize) {
+        fprintf(stderr, "\nERROR: image exceeds maximum compatible size\n");
+        fclose(f);
+        exit(-1);
+    }
+
+    buf = malloc(flen+32);
+
+    rewind(f);
+    res = fread(buf+32, 1, flen, f);
+    if(res != flen) {
+        perror("Couldn't read entire file: fread()");
+        fclose(f);
+        exit(-1);
+    }
+
+    fclose(f);
+
+    printf("\nCreating %s...\n", argv[2]);
+
+    memcpy(&my_hdr, &mach_def[image_type].header, sizeof(struct gemtek_header));
+
+    printf("  Using %s magic\n", mach_def[image_type].desc);
+
+    my_hdr.imagesz = le32(flen + 0x20);
+    memcpy(my_hdr.lang, "EN", 2);
+
+    memcpy(buf, &my_hdr, 32);
+
+    crc = crc32(0, buf, flen+32);
+    printf("  CRC32: %08X\n", crc);
+
+    my_hdr.checksum = le32(crc);
+    memcpy(buf, &my_hdr, 32);
+
+    printf("  Writing...\n");
+    f_out = fopen(argv[2], "w");
+
+    fwrite(buf, 1, flen + 32, f_out);
+
+    fclose(f_out);
+
+    free(buf);
+    return 0;
+}
