diff -Naur ../org/configure ./configure
--- ../org/configure	2004-10-16 13:40:04.000000000 +0200
+++ ./configure	2007-08-09 17:56:42.000000000 +0200
@@ -3064,13 +3064,13 @@
 fi
 
 
-echo "$as_me:$LINENO: checking for tputs in -ltermcap" >&5
-echo $ECHO_N "checking for tputs in -ltermcap... $ECHO_C" >&6
-if test "${ac_cv_lib_termcap_tputs+set}" = set; then
+echo "$as_me:$LINENO: checking for tputs in -lncurses" >&5
+echo $ECHO_N "checking for tputs in -lncurses... $ECHO_C" >&6
+if test "${ac_cv_lib_tncurses_tputs+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   ac_check_lib_save_LIBS=$LIBS
-LIBS="-ltermcap  $LIBS"
+LIBS="-lncurses  $LIBS"
 cat >conftest.$ac_ext <<_ACEOF
 #line $LINENO "configure"
 /* confdefs.h.  */
@@ -3106,24 +3106,24 @@
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); }; }; then
-  ac_cv_lib_termcap_tputs=yes
+  ac_cv_lib_tncurses_tputs=yes
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-ac_cv_lib_termcap_tputs=no
+ac_cv_lib_ncurses_tputs=no
 fi
 rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_termcap_tputs" >&5
-echo "${ECHO_T}$ac_cv_lib_termcap_tputs" >&6
-if test $ac_cv_lib_termcap_tputs = yes; then
+echo "$as_me:$LINENO: result: $ac_cv_lib_ncurses_tputs" >&5
+echo "${ECHO_T}$ac_cv_lib_ncurses_tputs" >&6
+if test $ac_cv_lib_ncurses_tputs = yes; then
   cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBTERMCAP 1
+#define HAVE_LIBNCURSES 1
 _ACEOF
 
-  LIBS="-ltermcap $LIBS"
+  LIBS="-lncurses $LIBS"
 
 fi
 
diff -Naur ../org/configure.ac ./configure.ac
--- ../org/configure.ac	2004-10-17 15:54:31.000000000 +0200
+++ ./configure.ac	2007-08-09 17:57:42.000000000 +0200
@@ -67,7 +67,7 @@
 #
 AC_CHECK_LIB([m], [pow])
 AC_CHECK_LIB([readline], [readline])
-AC_CHECK_LIB([termcap], [tputs])
+AC_CHECK_LIB([ncurses], [tputs])
 
 #
 # [6] Checks for header files.
diff -Naur ../org/include/config.h.in ./include/config.h.in
--- ../org/include/config.h.in	2004-09-26 05:59:34.000000000 +0200
+++ ./include/config.h.in	2007-08-09 17:58:35.000000000 +0200
@@ -33,8 +33,8 @@
 /* Define to 1 if you have the `readline' library (-lreadline). */
 #undef HAVE_LIBREADLINE
 
-/* Define to 1 if you have the `termcap' library (-ltermcap). */
-#undef HAVE_LIBTERMCAP
+/* Define to 1 if you have the `ncurses' library (-lncurses). */
+#undef HAVE_LIBNCURSES
 
 /* Define to 1 if your system has a GNU libc compatible `malloc' function, and
    to 0 otherwise. */
diff -Naur ../org/src/Makefile.am ./src/Makefile.am
--- ../org/src/Makefile.am	2004-10-17 15:54:32.000000000 +0200
+++ ./src/Makefile.am	2007-08-09 17:59:07.000000000 +0200
@@ -27,7 +27,7 @@
 	target/libtarget.a
 
 jtager_LDADD = \
-	-lm -lreadline -ltermcap \
+	-lm -lreadline -lncurses \
 	-Lconf -lconf \
 	-Lcmdline -lcmdline \
 	-Ljtag -ljtag \
diff -Naur ../org/src/Makefile.in ./src/Makefile.in
--- ../org/src/Makefile.in	2004-10-17 15:48:26.000000000 +0200
+++ ./src/Makefile.in	2007-08-09 17:59:20.000000000 +0200
@@ -104,7 +104,7 @@
 
 
 jtager_LDADD = \
-	-lm -lreadline -ltermcap \
+	-lm -lreadline -lncurses \
 	-Lconf -lconf \
 	-Lcmdline -lcmdline \
 	-Ljtag -ljtag \
diff -Naur ../org/src/jtag/jtag.c ./src/jtag/jtag.c
--- ../org/src/jtag/jtag.c	2004-10-17 10:04:28.000000000 +0200
+++ ./src/jtag/jtag.c	2007-08-09 17:53:31.000000000 +0200
@@ -427,7 +427,7 @@
 	outb(JTAG_TRST_MASK, par_dataport); /* LOW */
 	usleep(100);
 	outb(0, par_dataport); /* HIGH */
-	usleep(100);
+	sleep(2);
 
 	/* 
 	 * No matter what the original state of the TAP controller, it will
diff -Naur ../org/src/mtd/Makefile.am ./src/mtd/Makefile.am
--- ../org/src/mtd/Makefile.am	2004-09-26 05:59:41.000000000 +0200
+++ ./src/mtd/Makefile.am	2007-08-09 17:24:13.000000000 +0200
@@ -10,4 +10,6 @@
 libmtd_a_SOURCES = \
 	flash.c \
 	sst39vf160.c \
+	s29al016b.c \
+	am29lv800bb.c \
 	mbm29lv650.c
diff -Naur ../org/src/mtd/Makefile.in ./src/mtd/Makefile.in
--- ../org/src/mtd/Makefile.in	2004-09-26 05:59:41.000000000 +0200
+++ ./src/mtd/Makefile.in	2007-08-09 17:24:55.000000000 +0200
@@ -84,6 +84,8 @@
 libmtd_a_SOURCES = \
 	flash.c \
 	sst39vf160.c \
+	s29al016b.c \
+	am29lv800bb.c \
 	mbm29lv650.c
 
 subdir = src/mtd
@@ -95,7 +97,7 @@
 libmtd_a_AR = $(AR) cru
 libmtd_a_LIBADD =
 am_libmtd_a_OBJECTS = flash.$(OBJEXT) sst39vf160.$(OBJEXT) \
-	mbm29lv650.$(OBJEXT)
+	s29al016b.$(OBJEXT) am29lv800bb.$(OBJEXT) mbm29lv650.$(OBJEXT)
 libmtd_a_OBJECTS = $(am_libmtd_a_OBJECTS)
 
 DEFS = @DEFS@
@@ -106,7 +108,8 @@
 depcomp = $(SHELL) $(top_srcdir)/tools/depcomp
 am__depfiles_maybe = depfiles
 @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/flash.Po ./$(DEPDIR)/mbm29lv650.Po \
-@AMDEP_TRUE@	./$(DEPDIR)/sst39vf160.Po
+@AMDEP_TRUE@./$(DEPDIR)/s29al016b.Po ./$(DEPDIR)/am29lv800bb.Po ./$(DEPDIR)/sst39vf160.Po
+
 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
 	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
 CCLD = $(CC)
@@ -144,6 +147,8 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flash.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mbm29lv650.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sst39vf160.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s29al016b.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/am29lv800bb.Po@am__quote@
 
 distclean-depend:
 	-rm -rf ./$(DEPDIR)
diff -Naur ../org/src/mtd/am29lv800bb.c ./src/mtd/am29lv800bb.c
--- ../org/src/mtd/am29lv800bb.c	1970-01-01 01:00:00.000000000 +0100
+++ ./src/mtd/am29lv800bb.c	2007-08-09 17:54:08.000000000 +0200
@@ -0,0 +1,280 @@
+/*
+ * mtd/am29lv800bb.c : implements the operations to mbm29lv650 flash chip.
+ *
+ * Copyright (C) 2003, Rongkai Zhan <zhanrk@163.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
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "jtager.h"
+#include "target.h"
+#include "flash.h"
+
+#define MANU_ID 	0x0001 	/* AMD Manufacturer ID code */
+#define DEVICE_ID	0x225B 	/* am29lv800bb device code */
+
+#define SECTOR_SIZE 	(32 * 1024 * 2) /* 32K words = 64K Bytes */
+#define CHIP_SIZE	(1024 * 1024 * 1) /* 512K words = 1M Bytes */
+#define CHIP_BASE 	(am29lv800bb.base)
+#define SECTOR_MASK	(SECTOR_SIZE - 1)
+
+#define CMD_ADDR1	(am29lv800bb.base + (0x5555 << 1))
+#define CMD_ADDR2	(am29lv800bb.base + (0x2aaa << 1))
+
+#define DQ5_MASK	0x20
+#define DQ6_MASK	0x40
+#define DQ7_MASK	0x80
+
+flash_t am29lv800bb;
+
+static int chip_probe(u32 base)
+{
+	u16 id1 = 0, id2 = 0;
+	u16 softid_cmd[4] = {0xAAAA, 0x5555, 0x9090, 0xF0F0};
+	u16 old1, old2;
+	u32 old_base = CHIP_BASE;
+	int ret;
+
+	CHIP_BASE = base; /* update chip base address */
+	
+	/* save the contents of these two memory units */
+	old1 = read16(CMD_ADDR1);
+	old2 = read16(CMD_ADDR2);
+
+	/* write ID commands */
+	write16(softid_cmd[0], CMD_ADDR1);
+	write16(softid_cmd[1], CMD_ADDR2);
+	write16(softid_cmd[2], CMD_ADDR1);
+	
+	/* read MANU_ID & DEVICE_ID */
+	id1 = read16(base + (0x00 << 1));
+	id2 = read16(base + (0x01 << 1));
+	
+	/* check Manufacture ID and Device ID */
+	if ((id1 == MANU_ID) && (id2 == DEVICE_ID))
+		ret = 0;
+	else
+		ret = -1;
+	
+	/* Software ID Exit / CFI Exit */
+	write16(softid_cmd[0], CMD_ADDR1);
+	write16(softid_cmd[1], CMD_ADDR2);
+	write16(softid_cmd[3], CMD_ADDR1);
+
+	if (ret) {
+		CHIP_BASE = old_base;
+		write16(old1, CMD_ADDR1);
+		write16(old2, CMD_ADDR2);
+	}
+	return ret;
+}
+
+/*
+ * DQ6 is still toggling bit?
+ */
+static int chip_is_busy(u32 addr)
+{
+	u16 oldval, newval;
+	u32 count = 0;
+	int ret = -1, timeout = 0;
+
+	addr = addr16_align(addr);
+	
+	while (1) {
+		oldval = read16(addr);
+		newval = read16(addr);
+		if ((oldval & DQ6_MASK) == (newval & DQ6_MASK)) {
+			/* DQ6 stops toggle */
+			ret = 0;
+			break;
+		}
+		
+		/* DQ5 = 1? */
+		if (newval & DQ5_MASK) {
+			/* exceed timing limits */
+			timeout = 1;
+			break;
+		}
+
+		count++;
+		if (count > 0xF0000000) {
+			timeout = 1;
+			break;
+		}
+	}
+	
+	if (timeout) {
+		/*
+		 * oh, this is the last chance for success.
+		 */
+		oldval = read16(addr);
+		newval = read16(addr);
+		if ((oldval & DQ6_MASK) == (newval & DQ6_MASK))
+			ret = 0;
+		else
+			ret = -1;
+	}
+	return ret;
+}
+
+/*
+ * DQ7 Data Polling
+ */
+static int __attribute__((__unused__)) data_polling(u32 addr, u16 true_data)
+{
+	u16 value;
+	int ret;
+	u32 timeout = 0x10000000;
+
+	ret = -1;
+	while (timeout) {
+		value = read16(addr);
+		if ((value & DQ7_MASK) == (true_data & DQ7_MASK)) {
+			ret = 0;
+			break;
+		}
+		timeout--;
+	}
+	return ret;
+} /* end of data_polling(...) */
+
+/**
+ * erase_sector - erase one sector
+ * @addr: any address in the sector to be erased.
+ *
+ * Return value: If success, return 0. Otherwise, return -1.
+ */
+static int erase_sector(u32 addr)
+{
+	u16 erase_sector_cmd[6] = {0xAAAA, 0x5555, 0x8080,
+				   0xAAAA, 0x5555, 0x3030};
+	u32 sector_addr = addr & (~((u32)SECTOR_SIZE - 1));
+	int ret;
+	
+	write16(erase_sector_cmd[0], CMD_ADDR1);
+	write16(erase_sector_cmd[1], CMD_ADDR2);
+	write16(erase_sector_cmd[2], CMD_ADDR1);
+	write16(erase_sector_cmd[3], CMD_ADDR1);
+	write16(erase_sector_cmd[4], CMD_ADDR2);
+	write16(erase_sector_cmd[5], sector_addr);
+
+	/* chip is busy ? */
+	sector_addr += (SECTOR_SIZE - 2);
+	ret = chip_is_busy(sector_addr);
+	return ret;
+} /* end of erase_sector(...) */
+
+static int erase_chip(void)
+{
+	u16 erase_chip_cmd[6] = {0xAAAA, 0x5555, 0x8080,
+				 0xAAAA, 0x5555, 0x1010};
+	u32 base, wait = 500000;
+	int ret;
+	
+	write16(erase_chip_cmd[0], CMD_ADDR1);
+	write16(erase_chip_cmd[1], CMD_ADDR2);
+	write16(erase_chip_cmd[2], CMD_ADDR1);
+	write16(erase_chip_cmd[3], CMD_ADDR1);
+	write16(erase_chip_cmd[4], CMD_ADDR2);
+	write16(erase_chip_cmd[5], CMD_ADDR1);
+	
+	/*
+	 * Chip erase is a long way, we just wait for a while.
+	 */
+	while (wait)
+		wait--;
+
+	base = CHIP_BASE + (CHIP_SIZE - 2);
+	ret = chip_is_busy(base);
+
+	return ret;
+} /* end of erase_chip() */
+
+/**
+ * flash_write - write flash memory with the source data from target memory or host buffer
+ * @start_address: The flash start address to be written.
+ * @bytenr: how many bytes are to be written.
+ * @source_address: The address of source data.
+ * @from_host: If from_host == 0, we read the source data from a target memory block
+ *             If from_host != 0, we read the source data from a host buffer.
+ */
+static int flash_write(u32 start_address, u32 bytenr, u32 source_address, int from_host)
+{
+	u16 pgm_cmd[3] = {0xAAAA, 0x5555, 0xA0A0};
+	u32 current_addr;
+	int i, retry, ret;
+	u16 data;
+
+	if ((start_address < CHIP_BASE)
+		|| (start_address + bytenr - 1) > (CHIP_BASE + CHIP_SIZE - 1))
+		return -1; /* out of range */
+	
+	/* align address with the 16-bit word boundary */
+	current_addr = addr16_align(start_address);
+	
+	for (i = 0; i < (bytenr/2); i++) {
+		if (from_host)
+			data = *(u16 *)source_address; /* read data from host buffer */
+		else
+			data = read16(source_address);
+		source_address += 2;
+		if (data == 0xFFFF) {
+			current_addr += 2;
+			continue;
+		}
+		retry = 0;
+retry_pgm:
+		write16(pgm_cmd[0], CMD_ADDR1);
+		write16(pgm_cmd[1], CMD_ADDR2);
+		write16(pgm_cmd[2], CMD_ADDR1);
+		write16(data, current_addr);
+
+		ret = chip_is_busy(current_addr);
+		if (ret && retry < 3) {
+			retry++;
+			goto retry_pgm;
+		} else if (ret) {
+			break; /* failure */
+		}
+		
+		current_addr += 2;
+		if ((i + 1)%(2*1024) == 0) {
+			printf(".");
+			fflush(stdout);
+		}
+	} /* end of for (i = 0; ... ) */
+	
+	return ret;
+} /* end of flash_write(...) */
+
+flash_t am29lv800bb = {
+	.name 		= "am29lv800bb",
+	.mfr_id 	= MANU_ID,
+	.dev_id 	= DEVICE_ID,
+	.base       	= 0x0L, /* start physical address */
+	.chip_size 	= CHIP_SIZE,
+	.sector_size 	= SECTOR_SIZE,
+	.bus_width 	= 16,
+
+	.probe 		= chip_probe,
+	.erase_sector 	= erase_sector,
+	.erase_chip 	= erase_chip,
+	.write 		= flash_write,
+};
diff -Naur ../org/src/mtd/flash.c ./src/mtd/flash.c
--- ../org/src/mtd/flash.c	2004-10-17 10:04:28.000000000 +0200
+++ ./src/mtd/flash.c	2007-08-09 17:33:54.000000000 +0200
@@ -31,11 +31,15 @@
 
 extern flash_t sst39vf160;
 extern flash_t mbm29lv650;
+extern flash_t am29lv800bb;
+extern flash_t s29al016b;
 
 /* all supported flash chips */
 flash_t * flashes[] = {
 	&mbm29lv650,
 	&sst39vf160,
+	&am29lv800bb,
+	&s29al016b,
 	NULL /* the last element must be NULL */
 };
 
diff -Naur ../org/src/mtd/s29al016b.c ./src/mtd/s29al016b.c
--- ../org/src/mtd/s29al016b.c	1970-01-01 01:00:00.000000000 +0100
+++ ./src/mtd/s29al016b.c	2007-08-10 12:35:05.000000000 +0200
@@ -0,0 +1,266 @@
+/*
+ * mtd/s29al016b.c : implements the read/write ops of 
+ * Spansion S29AL016 Bottom Bootblock flash chip.
+ *
+ * Copyright (C) 2003, Rongkai Zhan <zhanrk@163.com>
+ * Copyright (C) 2007, Arne Fitzenreiter <arne@fitzenreiter.de>
+ *
+ * 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: s29al016b.c,v 1.0 2007/08/10 10:00:00 arne Exp $ */
+
+/*
+ * References:
+ * [1] <<Spansion S29AL016 datasheet>>
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "jtager.h"
+#include "target.h"
+#include "flash.h"
+
+#define MANU_ID 	0x0001 	/* Spansion Manufacturer code */
+#define DEVICE_ID	0x2249 	/* S29AL016 Bootomboot device code */
+/* 
+ * The bootblock sectors are not implementet yet. To overwrite this area you
+ * have to erase the whole chip
+ */
+#define SECTOR_SIZE 	(32 * 1024 * 2)   /* 32K words = 64K Bytes */
+#define CHIP_SIZE	(1024 * 1024 * 2) /* 1M words = 2M Bytes */
+#define CHIP_BASE 	(s29al016b.base)
+
+#define SECTOR_MASK 	(SECTOR_SIZE - 1)
+
+#define CMD_ADDR1 	(s29al016b.base + (0x5555 << 1))
+#define CMD_ADDR2 	(s29al016b.base + (0x2aaa << 1))
+
+#define DQ6_MASK 	0x40
+#define DQ7_MASK 	0x80
+
+flash_t s29al016b;
+
+static int chip_probe(u32 base)
+{
+	u16 id1 = 0, id2 = 0;
+	u16 softid_cmd[4] = {0xAAAA, 0x5555, 0x9090, 0xF0F0};
+	u16 old1, old2;
+	u32 old_base = CHIP_BASE;
+	int ret;
+	
+	CHIP_BASE = base; /* update chip base address */
+	
+	/* save the contents of these two memory units */
+	old1 = read16(CMD_ADDR1);
+	old2 = read16(CMD_ADDR2);
+	
+	/* write ID commands */
+	write16(softid_cmd[0], CMD_ADDR1);
+	write16(softid_cmd[1], CMD_ADDR2);
+	write16(softid_cmd[2], CMD_ADDR1);
+	
+	/* read MANU_ID & DEVICE_ID */
+	id1 = read16(base + (0x00 << 1));
+	id2 = read16(base + (0x01 << 1));
+	
+//	printf("ID1:%X ID2:%X ",id1,id2);
+	
+	/* check Manufacture ID and Device ID */
+	if ((id1 == MANU_ID) && (id2 == DEVICE_ID))
+		ret = 0;
+	else
+		ret = -1;
+
+	/* Software ID Exit / CFI Exit */
+	write16(softid_cmd[0], CMD_ADDR1);
+	write16(softid_cmd[1], CMD_ADDR2);
+	write16(softid_cmd[3], CMD_ADDR1);
+		
+	if (ret) {
+		CHIP_BASE = old_base;
+		write16(old1, CMD_ADDR1);
+		write16(old2, CMD_ADDR2);
+	}
+	return ret;
+} /* end of chip_probe (...) */
+
+/*
+ * DQ6 is still toggling bit?
+ */
+static int chip_is_busy(u32 addr)
+{
+	u16 oldval, newval;
+	u32 count = 0;
+	int ret = -1, timeout = 0;
+
+	addr = addr16_align(addr);
+	
+	while (1) {
+		oldval = read16(addr);
+		newval = read16(addr);
+		if ((oldval & DQ6_MASK) == (newval & DQ6_MASK)) {
+			/* DQ6 stops toggle */
+			ret = 0;
+			break;
+		}
+
+		count++;
+		if (count > 0xF0000000) {
+			timeout = 1;
+			break;
+		}
+	}
+	
+	if (timeout) {
+		/*
+		 * oh, this is the last chance for success.
+		 */
+		oldval = read16(addr);
+		newval = read16(addr);
+		if ((oldval & DQ6_MASK) == (newval & DQ6_MASK))
+			ret = 0;
+		else
+			ret = -1;
+	}
+	return ret;
+}
+
+/**
+ * erase_sector - erase one sector
+ * @addr: any address in the sector to be erased.
+ *
+ * Return value: If success, return 0. Otherwise, return -1.
+ */
+static int erase_sector(u32 addr)
+{
+	u16 erase_sector_cmd[6] = {0xAAAA, 0x5555, 0x8080,
+				   0xAAAA, 0x5555, 0x3030};
+	u32 sector_addr = addr & (~((u32)SECTOR_SIZE - 1));
+	int ret;
+	
+	write16(erase_sector_cmd[0], CMD_ADDR1);
+	write16(erase_sector_cmd[1], CMD_ADDR2);
+	write16(erase_sector_cmd[2], CMD_ADDR1);
+	write16(erase_sector_cmd[3], CMD_ADDR1);
+	write16(erase_sector_cmd[4], CMD_ADDR2);
+	write16(erase_sector_cmd[5], sector_addr);
+
+	/* chip is busy ? */
+	sector_addr += (SECTOR_SIZE - 2);
+	ret = chip_is_busy(sector_addr);
+	return ret;
+} /* end of erase_sector(...) */
+
+static int erase_chip(void)
+{
+	u16 erase_chip_cmd[6] = {0xAAAA, 0x5555, 0x8080,
+				 0xAAAA, 0x5555, 0x1010};
+	u32 base, wait = 500000;
+	int ret;
+	
+	write16(erase_chip_cmd[0], CMD_ADDR1);
+	write16(erase_chip_cmd[1], CMD_ADDR2);
+	write16(erase_chip_cmd[2], CMD_ADDR1);
+	write16(erase_chip_cmd[3], CMD_ADDR1);
+	write16(erase_chip_cmd[4], CMD_ADDR2);
+	write16(erase_chip_cmd[5], CMD_ADDR1);
+	
+	/*
+	 * Chip erase is a long way, we just wait for a while.
+	 */
+	while (wait)
+		wait--;
+	
+	base = CHIP_BASE + (CHIP_SIZE - 2);
+	ret = chip_is_busy(base);
+
+	return ret;
+} /* end of erase_chip() */
+
+/**
+ * flash_write - write flash memory with the source data from target memory or host buffer
+ * @start_address: The flash start address to be written.
+ * @bytenr: how many bytes are to be written.
+ * @source_address: The address of source data.
+ * @from_host: If from_host == 0, we read the source data from a target memory block
+ *             If from_host != 0, we read the source data from a host buffer.
+ */
+static int flash_write(u32 start_address, u32 bytenr, u32 source_address, int from_host)
+{
+	u16 pgm_cmd[3] = {0xAAAA, 0x5555, 0xA0A0};
+	u32 current_addr;
+	int i, retry, ret;
+	u16 data;
+	
+	if ((start_address < CHIP_BASE)
+		|| (start_address + bytenr - 1) > (CHIP_BASE + CHIP_SIZE - 1))
+		return -1; /* out of range */
+	
+	/* align address with the 16-bit word boundary */
+	current_addr = addr16_align(start_address);
+	
+	for (i = 0; i < (bytenr/2); i++) {
+		if (from_host)
+			data = *(u16 *)source_address; /* read data from host buffer */
+		else
+			data = read16(source_address);
+		source_address += 2;
+		if (data == 0xFFFF) {
+			current_addr += 2;
+			continue;
+		}
+		retry = 0;
+retry_pgm:
+		write16(pgm_cmd[0], CMD_ADDR1);
+		write16(pgm_cmd[1], CMD_ADDR2);
+		write16(pgm_cmd[2], CMD_ADDR1);
+		write16(data, current_addr);
+
+		ret = chip_is_busy(current_addr);
+		if (ret && retry < 3) {
+			retry++;
+			goto retry_pgm;
+		} else if (ret) {
+			break; /* failure */
+		}
+		
+		current_addr += 2;
+		if ((i + 1)%(2*1024) == 0) {
+			printf(".");
+			fflush(stdout);
+		}
+	} /* end of for (i = 0; ... ) */
+	
+	return ret;
+} /* end of flash_write(...) */
+
+flash_t s29al016b = {	
+	.name 		= "s29al016b",
+	.mfr_id 	= MANU_ID,
+	.dev_id 	= DEVICE_ID,
+	.base       	= 0x0L, /* start physical address */
+	.chip_size 	= CHIP_SIZE,
+	.sector_size 	= SECTOR_SIZE,
+	.bus_width 	= 16,
+
+	.probe 		= chip_probe,
+	.erase_sector 	= erase_sector,
+	.erase_chip 	= erase_chip,
+	.write 		= flash_write,
+};
