diff --git a/82802ab.c b/82802ab.c
deleted file mode 100644
index 58d3467..0000000
--- a/82802ab.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/*
- * Datasheet:
- *  - Name: Intel 82802AB/82802AC Firmware Hub (FWH)
- *  - URL: http://www.intel.com/design/chipsets/datashts/290658.htm
- *  - PDF: http://download.intel.com/design/chipsets/datashts/29065804.pdf
- *  - Order number: 290658-004
- */
-
-#include <string.h>
-#include <stdlib.h>
-#include "flash.h"
-
-// I need that Berkeley bit-map printer
-void print_82802ab_status(uint8_t status)
-{
-	printf_debug("%s", status & 0x80 ? "Ready:" : "Busy:");
-	printf_debug("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:");
-	printf_debug("%s", status & 0x20 ? "BE ERROR:" : "BE OK:");
-	printf_debug("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:");
-	printf_debug("%s", status & 0x8 ? "VP ERR:" : "VPP OK:");
-	printf_debug("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:");
-	printf_debug("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:");
-}
-
-int probe_82802ab(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-	uint8_t id1, id2;
-
-	/* Reset to get a clean state */
-	chip_writeb(0xFF, bios);
-	programmer_delay(10);
-
-	/* Enter ID mode */
-	chip_writeb(0x90, bios);
-	programmer_delay(10);
-
-	id1 = chip_readb(bios);
-	id2 = chip_readb(bios + 0x01);
-
-	/* Leave ID mode */
-	chip_writeb(0xFF, bios);
-
-	programmer_delay(10);
-
-	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
-
-	if (id1 != flash->manufacture_id || id2 != flash->model_id)
-		return 0;
-
-	map_flash_registers(flash);
-
-	return 1;
-}
-
-uint8_t wait_82802ab(chipaddr bios)
-{
-	uint8_t status;
-
-	chip_writeb(0x70, bios);
-	if ((chip_readb(bios) & 0x80) == 0) {	// it's busy
-		while ((chip_readb(bios) & 0x80) == 0) ;
-	}
-
-	status = chip_readb(bios);
-
-	/* Reset to get a clean state */
-	chip_writeb(0xFF, bios);
-
-	return status;
-}
-
-int erase_82802ab_block(struct flashchip *flash, int offset)
-{
-	chipaddr bios = flash->virtual_memory + offset;
-	chipaddr wrprotect = flash->virtual_registers + offset + 2;
-	uint8_t status;
-
-	// clear status register
-	chip_writeb(0x50, bios);
-
-	// clear write protect
-	chip_writeb(0, wrprotect);
-
-	// now start it
-	chip_writeb(0x20, bios);
-	chip_writeb(0xd0, bios);
-	programmer_delay(10);
-
-	// now let's see what the register is
-	status = wait_82802ab(flash->virtual_memory);
-	print_82802ab_status(status);
-
-	if (check_erased_range(flash, offset, flash->page_size)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	printf("DONE BLOCK 0x%x\n", offset);
-
-	return 0;
-}
-
-int erase_82802ab(struct flashchip *flash)
-{
-	int i;
-	unsigned int total_size = flash->total_size * 1024;
-
-	printf("total_size is %d; flash->page_size is %d\n",
-	       total_size, flash->page_size);
-	for (i = 0; i < total_size; i += flash->page_size)
-		if (erase_82802ab_block(flash, i)) {
-			fprintf(stderr, "ERASE FAILED!\n");
-			return -1;
-		}
-	printf("DONE ERASE\n");
-
-	return 0;
-}
-
-void write_page_82802ab(chipaddr bios, uint8_t *src,
-			chipaddr dst, int page_size)
-{
-	int i;
-
-	for (i = 0; i < page_size; i++) {
-		/* transfer data from source to destination */
-		chip_writeb(0x40, dst);
-		chip_writeb(*src++, dst++);
-		wait_82802ab(bios);
-	}
-}
-
-int write_82802ab(struct flashchip *flash, uint8_t *buf)
-{
-	int i;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-	chipaddr bios = flash->virtual_memory;
-	uint8_t *tmpbuf = malloc(page_size);
-
-	if (!tmpbuf) {
-		printf("Could not allocate memory!\n");
-		exit(1);
-	}
-	printf("Programming page: \n");
-	for (i = 0; i < total_size / page_size; i++) {
-		printf
-		    ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-		printf("%04d at address: 0x%08x", i, i * page_size);
-
-		/* Auto Skip Blocks, which already contain the desired data
-		 * Faster, because we only write, what has changed
-		 * More secure, because blocks, which are excluded
-		 * (with the exclude or layout feature)
-		 * or not erased and rewritten; their data is retained also in
-		 * sudden power off situations
-		 */
-		chip_readn(tmpbuf, bios + i * page_size, page_size);
-		if (!memcmp((void *)(buf + i * page_size), tmpbuf, page_size)) {
-			printf("SKIPPED\n");
-			continue;
-		}
-
-		/* erase block by block and write block by block; this is the most secure way */
-		if (erase_82802ab_block(flash, i * page_size)) {
-			fprintf(stderr, "ERASE FAILED!\n");
-			return -1;
-		}
-		write_page_82802ab(bios, buf + i * page_size,
-				   bios + i * page_size, page_size);
-	}
-	printf("\n");
-	free(tmpbuf);
-
-	return 0;
-}
diff --git a/Makefile b/Makefile
index ae06d7c..aad8393 100644
--- a/Makefile
+++ b/Makefile
@@ -25,7 +25,7 @@ INSTALL = install
 DIFF    = diff
 PREFIX  ?= /usr/local
 MANDIR  ?= $(PREFIX)/share/man
-CFLAGS  ?= -Os -Wall -Werror
+CFLAGS  ?= -Os -Wall -Werror -Ilibflashrom/
 EXPORTDIR ?= .
 
 OS_ARCH	= $(shell uname)
@@ -43,13 +43,17 @@ endif
 
 LIBS += -lpci
 
-OBJS = chipset_enable.o board_enable.o udelay.o jedec.o stm50flw0x0x.o \
-	sst28sf040.o am29f040b.o mx29f002.o m29f400bt.o pm29f002.o \
-	w49f002u.o 82802ab.o pm49fl00x.o sst49lf040.o en29f002a.o \
-	sst49lfxxxc.o sst_fwhub.o layout.o cbtable.o flashchips.o physmap.o \
-	flashrom.o w39v080fa.o sharplhf00l04.o w29ee011.o spi.o it87spi.o \
-	ichspi.o w39v040c.o sb600spi.o wbsio_spi.o m29f002.o internal.o \
-	pcidev.o print.o
+OBJS = libflashrom/chipset_enable.o libflashrom/board_enable.o \
+    libflashrom/jedec.o libflashrom/stm50flw0x0x.o libflashrom/sst28sf040.o \
+    libflashrom/am29f040b.o libflashrom/mx29f002.o libflashrom/m29f400bt.o \
+    libflashrom/pm29f002.o libflashrom/w49f002u.o libflashrom/82802ab.o \
+    libflashrom/pm49fl00x.o libflashrom/sst49lf040.o libflashrom/en29f002a.o \
+	libflashrom/sst49lfxxxc.o libflashrom/sst_fwhub.o libflashrom/flashchips.o \
+    libflashrom/w39v080fa.o libflashrom/sharplhf00l04.o libflashrom/w29ee011.o \
+    libflashrom/spi.o libflashrom/it87spi.o libflashrom/ichspi.o \
+    libflashrom/w39v040c.o libflashrom/sb600spi.o libflashrom/wbsio_spi.o \
+    libflashrom/m29f002.o libflashrom/internal.o libflashrom/pcidev.o \
+    cli/print.o cli/udelay.o cli/cbtable.o cli/physmap.o cli/flashrom.o cli/layout.o 
 
 all: pciutils features dep $(PROGRAM)
 
@@ -97,7 +101,7 @@ CONFIG_PRINT_WIKI ?= no
 
 ifeq ($(CONFIG_SERPROG), yes)
 FEATURE_CFLAGS += -D'SERPROG_SUPPORT=1'
-OBJS += serprog.o
+OBJS += libflashrom/serprog.o
 ifeq ($(OS_ARCH), SunOS)
 LIBS += -lsocket
 endif
@@ -105,22 +109,22 @@ endif
 
 ifeq ($(CONFIG_BITBANG_SPI), yes)
 FEATURE_CFLAGS += -D'BITBANG_SPI_SUPPORT=1'
-OBJS += bitbang_spi.o
+OBJS += libflashrom/bitbang_spi.o
 endif
 
 ifeq ($(CONFIG_NIC3COM), yes)
 FEATURE_CFLAGS += -D'NIC3COM_SUPPORT=1'
-OBJS += nic3com.o
+OBJS += libflashrom/nic3com.o
 endif
 
 ifeq ($(CONFIG_GFXNVIDIA), yes)
 FEATURE_CFLAGS += -D'GFXNVIDIA_SUPPORT=1'
-OBJS += gfxnvidia.o
+OBJS += libflashrom/gfxnvidia.o
 endif
 
 ifeq ($(CONFIG_SATASII), yes)
 FEATURE_CFLAGS += -D'SATASII_SUPPORT=1'
-OBJS += satasii.o
+OBJS += libflashrom/satasii.o
 endif
 
 FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb")
@@ -128,36 +132,36 @@ ifeq ($(CONFIG_FT2232SPI), yes)
 # This is a totally ugly hack.
 FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "-D'FT2232_SPI_SUPPORT=1'")
 FEATURE_LIBS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "$(FTDILIBS)")
-OBJS += ft2232_spi.o
+OBJS += libflashrom/ft2232_spi.o
 endif
 
 ifeq ($(CONFIG_DUMMY), yes)
 FEATURE_CFLAGS += -D'DUMMY_SUPPORT=1'
-OBJS += dummyflasher.o
+OBJS += libflashrom/dummyflasher.o
 endif
 
 ifeq ($(CONFIG_DRKAISER), yes)
 FEATURE_CFLAGS += -D'DRKAISER_SUPPORT=1'
-OBJS += drkaiser.o
+OBJS += libflashrom/drkaiser.o
 endif
 
 ifeq ($(CONFIG_BUSPIRATESPI), yes)
 FEATURE_CFLAGS += -D'BUSPIRATE_SPI_SUPPORT=1'
-OBJS += buspirate_spi.o
+OBJS += libflashrom/buspirate_spi.o
 endif
 
 # Ugly, but there's no elif/elseif.
 ifeq ($(CONFIG_SERPROG), yes)
-OBJS += serial.o
+OBJS += libflashrom/serial.o
 else
 ifeq ($(CONFIG_BUSPIRATESPI), yes)
-OBJS += serial.o
+OBJS += libflashrom/serial.o
 endif
 endif
 
 ifeq ($(CONFIG_PRINT_WIKI), yes)
 FEATURE_CFLAGS += -D'PRINT_WIKI_SUPPORT=1'
-OBJS += print_wiki.o
+OBJS += cli/print_wiki.o
 endif
 
 # We could use PULLED_IN_LIBS, but that would be ugly.
@@ -175,13 +179,13 @@ TAROPTIONS = $(shell LC_ALL=C tar --version|grep -q GNU && echo "--owner=root --
 	$(CC) $(CFLAGS) $(CPPFLAGS) $(FEATURE_CFLAGS) $(SVNDEF) -o $@ -c $<
 
 clean:
-	rm -f $(PROGRAM) *.o
+	rm -f $(PROGRAM) libflashrom/*.o cli/*.o
 
 distclean: clean
 	rm -f .dependencies .features .libdeps
 
 dep:
-	@$(CC) $(CPPFLAGS) $(SVNDEF) -MM *.c > .dependencies
+	@$(CC) $(CPPFLAGS) $(SVNDEF) -MM libflashrom/*.c cli/*.c > .dependencies
 
 strip: $(PROGRAM)
 	$(STRIP) $(STRIP_ARGS) $(PROGRAM)
diff --git a/am29f040b.c b/am29f040b.c
deleted file mode 100644
index 46a5ef4..0000000
--- a/am29f040b.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "flash.h"
-
-/* FIMXE: check that the 2 second delay is really needed.
-          Use erase_sector_jedec if not? */
-static int erase_sector_29f040b(struct flashchip *flash, unsigned long address)
-{
-	int page_size = flash->page_size;
-	chipaddr bios = flash->virtual_memory;
-
-	chip_writeb(0xAA, bios + 0x555);
-	chip_writeb(0x55, bios + 0x2AA);
-	chip_writeb(0x80, bios + 0x555);
-	chip_writeb(0xAA, bios + 0x555);
-	chip_writeb(0x55, bios + 0x2AA);
-	chip_writeb(0x30, bios + address);
-
-	programmer_delay(2 * 1000 * 1000);
-
-	/* wait for Toggle bit ready         */
-	toggle_ready_jedec(bios + address);
-
-	if (check_erased_range(flash, address, page_size)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-/* FIXME: use write_sector_jedec? */
-static int write_sector_29f040b(chipaddr bios, uint8_t *src, chipaddr dst,
-				unsigned int page_size)
-{
-	int i;
-
-	for (i = 0; i < page_size; i++) {
-		if ((i & 0xfff) == 0xfff)
-			printf("0x%08lx", dst - bios);
-
-		chip_writeb(0xAA, bios + 0x555);
-		chip_writeb(0x55, bios + 0x2AA);
-		chip_writeb(0xA0, bios + 0x555);
-		chip_writeb(*src++, dst++);
-
-		/* wait for Toggle bit ready */
-		toggle_ready_jedec(bios);
-
-		if ((i & 0xfff) == 0xfff)
-			printf("\b\b\b\b\b\b\b\b\b\b");
-	}
-
-	return 0;
-}
-
-int probe_29f040b(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-	uint8_t id1, id2;
-
-	chip_writeb(0xAA, bios + 0x555);
-	chip_writeb(0x55, bios + 0x2AA);
-	chip_writeb(0x90, bios + 0x555);
-
-	id1 = chip_readb(bios);
-	id2 = chip_readb(bios + 0x01);
-
-	chip_writeb(0xF0, bios);
-
-	programmer_delay(10);
-
-	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
-	if (id1 == flash->manufacture_id && id2 == flash->model_id)
-		return 1;
-
-	return 0;
-}
-
-/* FIXME: use erase_chip_jedec? */
-int erase_29f040b(struct flashchip *flash)
-{
-	int total_size = flash->total_size * 1024;
-	chipaddr bios = flash->virtual_memory;
-
-	chip_writeb(0xAA, bios + 0x555);
-	chip_writeb(0x55, bios + 0x2AA);
-	chip_writeb(0x80, bios + 0x555);
-	chip_writeb(0xAA, bios + 0x555);
-	chip_writeb(0x55, bios + 0x2AA);
-	chip_writeb(0x10, bios + 0x555);
-
-	programmer_delay(10);
-	toggle_ready_jedec(bios);
-
-	if (check_erased_range(flash, 0, total_size)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-int write_29f040b(struct flashchip *flash, uint8_t *buf)
-{
-	int i;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-	chipaddr bios = flash->virtual_memory;
-
-	printf("Programming page ");
-	for (i = 0; i < total_size / page_size; i++) {
-		/* erase the page before programming */
-		if (erase_sector_29f040b(flash, i * page_size)) {
-			fprintf(stderr, "ERASE FAILED!\n");
-			return -1;
-		}
-
-		/* write to the sector */
-		printf("%04d at address: ", i);
-		write_sector_29f040b(bios, buf + i * page_size,
-				     bios + i * page_size, page_size);
-		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-	}
-	printf("\n");
-
-	return 0;
-}
diff --git a/bitbang_spi.c b/bitbang_spi.c
deleted file mode 100644
index abf5530..0000000
--- a/bitbang_spi.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Carl-Daniel Hailfinger
- *
- * 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; version 2 of the License.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include "flash.h"
-#include "spi.h"
-
-/* Length of half a clock period in usecs */
-int bitbang_spi_half_period = 0;
-
-enum bitbang_spi_master bitbang_spi_master = BITBANG_SPI_INVALID;
-
-const struct bitbang_spi_master_entry bitbang_spi_master_table[] = {
-	{}, /* This entry corresponds to BITBANG_SPI_INVALID. */
-};
-
-const int bitbang_spi_master_count = ARRAY_SIZE(bitbang_spi_master_table);
-
-void bitbang_spi_set_cs(int val)
-{
-	bitbang_spi_master_table[bitbang_spi_master].set_cs(val);
-}
-
-void bitbang_spi_set_sck(int val)
-{
-	bitbang_spi_master_table[bitbang_spi_master].set_sck(val);
-}
-
-void bitbang_spi_set_mosi(int val)
-{
-	bitbang_spi_master_table[bitbang_spi_master].set_mosi(val);
-}
-
-int bitbang_spi_get_miso(void)
-{
-	return bitbang_spi_master_table[bitbang_spi_master].get_miso();
-}
-
-int bitbang_spi_init(void)
-{
-	bitbang_spi_set_cs(1);
-	bitbang_spi_set_sck(0);
-	buses_supported = CHIP_BUSTYPE_SPI;
-	return 0;
-}
-
-uint8_t bitbang_spi_readwrite_byte(uint8_t val)
-{
-	uint8_t ret = 0;
-	int i;
-
-	for (i = 7; i >= 0; i--) {
-		bitbang_spi_set_mosi((val >> i) & 1);
-		programmer_delay(bitbang_spi_half_period);
-		bitbang_spi_set_sck(1);
-		ret <<= 1;
-		ret |= bitbang_spi_get_miso();
-		programmer_delay(bitbang_spi_half_period);
-		bitbang_spi_set_sck(0);
-	}
-	return ret;
-}
-
-int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-		const unsigned char *writearr, unsigned char *readarr)
-{
-	static unsigned char *bufout = NULL;
-	static unsigned char *bufin = NULL;
-	static int oldbufsize = 0;
-	int bufsize;
-	int i;
-
-	/* Arbitrary size limitation here. We're only constrained by memory. */
-	if (writecnt > 65536 || readcnt > 65536)
-		return SPI_INVALID_LENGTH;
-
-	bufsize = max(writecnt + readcnt, 260);
-	/* Never shrink. realloc() calls are expensive. */
-	if (bufsize > oldbufsize) {
-		bufout = realloc(bufout, bufsize);
-		if (!bufout) {
-			fprintf(stderr, "Out of memory!\n");
-			if (bufin)
-				free(bufin);
-			exit(1);
-		}
-		bufin = realloc(bufout, bufsize);
-		if (!bufin) {
-			fprintf(stderr, "Out of memory!\n");
-			if (bufout)
-				free(bufout);
-			exit(1);
-		}
-		oldbufsize = bufsize;
-	}
-		
-	memcpy(bufout, writearr, writecnt);
-	/* Shift out 0x00 while reading data. */
-	memset(bufout + writecnt, 0x00, readcnt);
-	/* Make sure any non-read data is 0xff. */
-	memset(bufin + writecnt, 0xff, readcnt);
-
-	bitbang_spi_set_cs(0);
-	for (i = 0; i < readcnt + writecnt; i++) {
-		bufin[i] = bitbang_spi_readwrite_byte(bufout[i]);
-	}
-	programmer_delay(bitbang_spi_half_period);
-	bitbang_spi_set_cs(1);
-	programmer_delay(bitbang_spi_half_period);
-	memcpy(readarr, bufin + writecnt, readcnt);
-
-	return 0;
-}
-
-int bitbang_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
-{
-	/* Maximum read length is unlimited, use 64k bytes. */
-	return spi_read_chunked(flash, buf, start, len, 64 * 1024);
-}
-
-int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf)
-{
-	int total_size = 1024 * flash->total_size;
-	int i;
-
-	printf_debug("total_size is %d\n", total_size);
-	for (i = 0; i < total_size; i += 256) {
-		int l, r;
-		if (i + 256 <= total_size)
-			l = 256;
-		else
-			l = total_size - i;
-
-		if ((r = spi_nbyte_program(i, &buf[i], l))) {
-			fprintf(stderr, "%s: write fail %d\n", __func__, r);
-			return 1;
-		}
-		
-		while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
-			/* loop */;
-	}
-
-	return 0;
-}
diff --git a/board_enable.c b/board_enable.c
deleted file mode 100644
index 769b402..0000000
--- a/board_enable.c
+++ /dev/null
@@ -1,1326 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2005-2007 coresystems GmbH <stepan@coresystems.de>
- * Copyright (C) 2006 Uwe Hermann <uwe@hermann-uwe.de>
- * Copyright (C) 2007-2009 Luc Verhaegen <libv@skynet.be>
- * Copyright (C) 2007 Carl-Daniel Hailfinger
- *
- * 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; version 2 of the License.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/*
- * Contains the board specific flash enables.
- */
-
-#include <string.h>
-#include <fcntl.h>
-#include "flash.h"
-
-/*
- * Helper functions for many Winbond Super I/Os of the W836xx range.
- */
-/* Enter extended functions */
-void w836xx_ext_enter(uint16_t port)
-{
-	OUTB(0x87, port);
-	OUTB(0x87, port);
-}
-
-/* Leave extended functions */
-void w836xx_ext_leave(uint16_t port)
-{
-	OUTB(0xAA, port);
-}
-
-/* Generic Super I/O helper functions */
-uint8_t sio_read(uint16_t port, uint8_t reg)
-{
-	OUTB(reg, port);
-	return INB(port + 1);
-}
-
-void sio_write(uint16_t port, uint8_t reg, uint8_t data)
-{
-	OUTB(reg, port);
-	OUTB(data, port + 1);
-}
-
-void sio_mask(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask)
-{
-	uint8_t tmp;
-
-	OUTB(reg, port);
-	tmp = INB(port + 1) & ~mask;
-	OUTB(tmp | (data & mask), port + 1);
-}
-
-/**
- * Winbond W83627HF: Raise GPIO24.
- *
- * Suited for:
- *  - Agami Aruma
- *  - IWILL DK8-HTX
- */
-static int w83627hf_gpio24_raise(uint16_t port, const char *name)
-{
-	w836xx_ext_enter(port);
-
-	/* Is this the W83627HF? */
-	if (sio_read(port, 0x20) != 0x52) {	/* Super I/O device ID reg. */
-		fprintf(stderr, "\nERROR: %s: W83627HF: Wrong ID: 0x%02X.\n",
-			name, sio_read(port, 0x20));
-		w836xx_ext_leave(port);
-		return -1;
-	}
-
-	/* PIN89S: WDTO/GP24 multiplex -> GPIO24 */
-	sio_mask(port, 0x2B, 0x10, 0x10);
-
-	/* Select logical device 8: GPIO port 2 */
-	sio_write(port, 0x07, 0x08);
-
-	sio_mask(port, 0x30, 0x01, 0x01);	/* Activate logical device. */
-	sio_mask(port, 0xF0, 0x00, 0x10);	/* GPIO24 -> output */
-	sio_mask(port, 0xF2, 0x00, 0x10);	/* Clear GPIO24 inversion */
-	sio_mask(port, 0xF1, 0x10, 0x10);	/* Raise GPIO24 */
-
-	w836xx_ext_leave(port);
-
-	return 0;
-}
-
-static int w83627hf_gpio24_raise_2e(const char *name)
-{
-	return w83627hf_gpio24_raise(0x2e, name);
-}
-
-/**
- * Winbond W83627THF: GPIO 4, bit 4
- *
- * Suited for:
- *  - MSI K8T Neo2-F
- *  - MSI K8N-NEO3
- */
-static int w83627thf_gpio4_4_raise(uint16_t port, const char *name)
-{
-	w836xx_ext_enter(port);
-
-	/* Is this the W83627THF? */
-	if (sio_read(port, 0x20) != 0x82) {	/* Super I/O device ID reg. */
-		fprintf(stderr, "\nERROR: %s: W83627THF: Wrong ID: 0x%02X.\n",
-			name, sio_read(port, 0x20));
-		w836xx_ext_leave(port);
-		return -1;
-	}
-
-	/* PINxxxxS: GPIO4/bit 4 multiplex -> GPIOXXX */
-
-	sio_write(port, 0x07, 0x09);      /* Select LDN 9: GPIO port 4 */
-	sio_mask(port, 0x30, 0x02, 0x02); /* Activate logical device. */
-	sio_mask(port, 0xF4, 0x00, 0x10); /* GPIO4 bit 4 -> output */
-	sio_mask(port, 0xF6, 0x00, 0x10); /* Clear GPIO4 bit 4 inversion */
-	sio_mask(port, 0xF5, 0x10, 0x10); /* Raise GPIO4 bit 4 */
-
-	w836xx_ext_leave(port);
-
-	return 0;
-}
-
-static int w83627thf_gpio4_4_raise_2e(const char *name)
-{
-	return w83627thf_gpio4_4_raise(0x2e, name);
-}
-
-static int w83627thf_gpio4_4_raise_4e(const char *name)
-{
-	return w83627thf_gpio4_4_raise(0x4e, name);
-}
-
-/**
- * w83627: Enable MEMW# and set ROM size to max.
- */
-static void w836xx_memw_enable(uint16_t port)
-{
-	w836xx_ext_enter(port);
-	if (!(sio_read(port, 0x24) & 0x02)) {	/* Flash ROM enabled? */
-		/* Enable MEMW# and set ROM size select to max. (4M). */
-		sio_mask(port, 0x24, 0x28, 0x28);
-	}
-	w836xx_ext_leave(port);
-}
-
-/**
- * Common routine for several VT823x based boards.
- */
-static void vt823x_set_all_writes_to_lpc(struct pci_dev *dev)
-{
-	uint8_t val;
-
-	/* All memory cycles, not just ROM ones, go to LPC. */
-	val = pci_read_byte(dev, 0x59);
-	val &= ~0x80;
-	pci_write_byte(dev, 0x59, val);
-}
-
-/**
- * VT823x: Set one of the GPIO pins.
- */
-static void vt823x_gpio_set(struct pci_dev *dev, uint8_t gpio, int raise)
-{
-	uint16_t base;
-	uint8_t val, bit, offset;
-
-	if ((gpio >= 12) && (gpio <= 15)) {
-		/* GPIO12-15 -> output */
-		val = pci_read_byte(dev, 0xE4);
-		val |= 0x10;
-		pci_write_byte(dev, 0xE4, val);
-	} else if (gpio == 9) {
-		/* GPIO9 -> Output */
-		val = pci_read_byte(dev, 0xE4);
-		val |= 0x20;
-		pci_write_byte(dev, 0xE4, val);
-	} else if (gpio == 5) {
-		val = pci_read_byte(dev, 0xE4);
-		val |= 0x01;
-		pci_write_byte(dev, 0xE4, val);
-	} else {
-		fprintf(stderr, "\nERROR: "
-			"VT823x GPIO%02d is not implemented.\n", gpio);
-		return;
-	}
-
-	/* We need the I/O Base Address for this board's flash enable. */
-	base = pci_read_word(dev, 0x88) & 0xff80;
-
-	offset = 0x4C + gpio / 8;
-	bit = 0x01 << (gpio % 8);
-
-	val = INB(base + offset);
-	if (raise)
-		val |= bit;
-	else
-		val &= ~bit;
-	OUTB(val, base + offset);
-}
-
-/**
- * Suited for VIAs EPIA M and MII, and maybe other CLE266 based EPIAs.
- *
- * We don't need to do this when using coreboot, GPIO15 is never lowered there.
- */
-static int board_via_epia_m(const char *name)
-{
-	struct pci_dev *dev;
-
-	dev = pci_dev_find(0x1106, 0x3177);	/* VT8235 ISA bridge */
-	if (!dev) {
-		fprintf(stderr, "\nERROR: VT8235 ISA bridge not found.\n");
-		return -1;
-	}
-
-	/* GPIO15 is connected to write protect. */
-	vt823x_gpio_set(dev, 15, 1);
-
-	return 0;
-}
-
-/**
- * Suited for:
- *   - ASUS A7V8X-MX SE and A7V400-MX: AMD K7 + VIA KM400A + VT8235
- *   - Tyan S2498 (Tomcat K7M): AMD Geode NX + VIA KM400 + VT8237.
- */
-static int board_asus_a7v8x_mx(const char *name)
-{
-	struct pci_dev *dev;
-
-	dev = pci_dev_find(0x1106, 0x3177);	/* VT8235 ISA bridge */
-	if (!dev)
-		dev = pci_dev_find(0x1106, 0x3227);	/* VT8237 ISA bridge */
-	if (!dev) {
-		fprintf(stderr, "\nERROR: VT823x ISA bridge not found.\n");
-		return -1;
-	}
-
-	vt823x_set_all_writes_to_lpc(dev);
-	w836xx_memw_enable(0x2E);
-
-	return 0;
-}
-
-/**
- * Suited for VIAs EPIA SP and EPIA CN.
- */
-static int board_via_epia_sp(const char *name)
-{
-	struct pci_dev *dev;
-
-	dev = pci_dev_find(0x1106, 0x3227);	/* VT8237R ISA bridge */
-	if (!dev) {
-		fprintf(stderr, "\nERROR: VT8237R ISA bridge not found.\n");
-		return -1;
-	}
-
-	vt823x_set_all_writes_to_lpc(dev);
-
-	return 0;
-}
-
-/**
- * Suited for VIAs EPIA N & NL.
- */
-static int board_via_epia_n(const char *name)
-{
-	struct pci_dev *dev;
-
-	dev = pci_dev_find(0x1106, 0x3227);	/* VT8237R ISA bridge */
-	if (!dev) {
-		fprintf(stderr, "\nERROR: VT8237R ISA bridge not found.\n");
-		return -1;
-	}
-
-	/* All memory cycles, not just ROM ones, go to LPC */
-	vt823x_set_all_writes_to_lpc(dev);
-
-	/* GPIO9 -> output */
-	vt823x_gpio_set(dev, 9, 1);
-
-	return 0;
-}
-
-/**
- * Suited for:
- *   - EPoX EP-8K5A2: VIA KT333 + VT8235.
- *   - Albatron PM266A Pro: VIA P4M266A + VT8235.
- *   - Shuttle AK31 (all versions): VIA KT266 + VT8233.
- */
-static int w836xx_memw_enable_2e(const char *name)
-{
-	w836xx_memw_enable(0x2E);
-
-	return 0;
-}
-
-/**
- * Suited for ASUS P5A.
- *
- * This is rather nasty code, but there's no way to do this cleanly.
- * We're basically talking to some unknown device on SMBus, my guess
- * is that it is the Winbond W83781D that lives near the DIP BIOS.
- */
-static int board_asus_p5a(const char *name)
-{
-	uint8_t tmp;
-	int i;
-
-#define ASUSP5A_LOOP 5000
-
-	OUTB(0x00, 0xE807);
-	OUTB(0xEF, 0xE803);
-
-	OUTB(0xFF, 0xE800);
-
-	for (i = 0; i < ASUSP5A_LOOP; i++) {
-		OUTB(0xE1, 0xFF);
-		if (INB(0xE800) & 0x04)
-			break;
-	}
-
-	if (i == ASUSP5A_LOOP) {
-		printf("%s: Unable to contact device.\n", name);
-		return -1;
-	}
-
-	OUTB(0x20, 0xE801);
-	OUTB(0x20, 0xE1);
-
-	OUTB(0xFF, 0xE802);
-
-	for (i = 0; i < ASUSP5A_LOOP; i++) {
-		tmp = INB(0xE800);
-		if (tmp & 0x70)
-			break;
-	}
-
-	if ((i == ASUSP5A_LOOP) || !(tmp & 0x10)) {
-		printf("%s: failed to read device.\n", name);
-		return -1;
-	}
-
-	tmp = INB(0xE804);
-	tmp &= ~0x02;
-
-	OUTB(0x00, 0xE807);
-	OUTB(0xEE, 0xE803);
-
-	OUTB(tmp, 0xE804);
-
-	OUTB(0xFF, 0xE800);
-	OUTB(0xE1, 0xFF);
-
-	OUTB(0x20, 0xE801);
-	OUTB(0x20, 0xE1);
-
-	OUTB(0xFF, 0xE802);
-
-	for (i = 0; i < ASUSP5A_LOOP; i++) {
-		tmp = INB(0xE800);
-		if (tmp & 0x70)
-			break;
-	}
-
-	if ((i == ASUSP5A_LOOP) || !(tmp & 0x10)) {
-		printf("%s: failed to write to device.\n", name);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*
- * Set GPIO lines in the Broadcom HT-1000 southbridge.
- *
- *  It's not a Super I/O but it uses the same index/data port method.
- */
-static int board_hp_dl145_g3_enable(const char *name)
-{
-	/* GPIO 0 reg from PM regs */
-	/* Set GPIO 2 and 5 high, connected to flash WP# and TBL# pins. */
-	sio_mask(0xcd6, 0x44, 0x24, 0x24);
-
-	return 0;
-}
-
-static int board_ibm_x3455(const char *name)
-{
-	/* raise gpio13 */
-	sio_mask(0xcd6, 0x45, 0x20, 0x20);
-
-	return 0;
-}
-
-/**
- * Suited for Shuttle FN25 (SN25P): AMD S939 + Nvidia CK804 (nForce4).
- */
-static int board_shuttle_fn25(const char *name)
-{
-	struct pci_dev *dev;
-
-	dev = pci_dev_find(0x10DE, 0x0050);	/* NVIDIA CK804 ISA Bridge. */
-	if (!dev) {
-		fprintf(stderr,
-			"\nERROR: NVIDIA nForce4 ISA bridge not found.\n");
-		return -1;
-	}
-
-	/* one of those bits seems to be connected to TBL#, but -ENOINFO. */
-	pci_write_byte(dev, 0x92, 0);
-
-	return 0;
-}
-
-/**
- * Very similar to AMD 8111 IO Hub.
- */
-static int nvidia_mcp_gpio_set(int gpio, int raise)
-{
-	struct pci_dev *dev;
-	uint16_t base;
-	uint8_t tmp;
-
-	if ((gpio < 0) || (gpio > 31)) {
-		fprintf(stderr, "\nERROR: unsupported GPIO: %d.\n", gpio);
-		return -1;
-	}
-
-	dev = pci_dev_find_vendorclass(0x10DE, 0x0C05);
-	switch (dev->device_id) {
-	case 0x0030: /* CK804 */
-	case 0x0050: /* MCP04 */
-	case 0x0060: /* MCP2 */
-		break;
-	default:
-		fprintf(stderr, "\nERROR: no nVidia SMBus controller found.\n");
-		return -1;
-	}
-
-	base = pci_read_long(dev, 0x64) & 0x0000FF00; /* System control area */
-	base += 0xC0;
-
-	tmp = INB(base + gpio);
-	tmp &= ~0x0F; /* null lower nibble */
-	tmp |= 0x04; /* gpio -> output. */
-	if (raise)
-		tmp |= 0x01;
-	OUTB(tmp, base + gpio);
-
-	return 0;
-}
-
-/**
- * Suited for ASUS P5ND2-SLI Deluxe: LGA775 + nForce4 SLI + MCP04.
- */
-static int nvidia_mcp_gpio10_raise(const char *name)
-{
-	return nvidia_mcp_gpio_set(0x10, 1);
-}
-
-/**
- * Suited for the Gigabyte GA-K8N-SLI: CK804 southbridge.
- */
-static int nvidia_mcp_gpio21_raise(const char *name)
-{
-	return nvidia_mcp_gpio_set(0x21, 0x01);
-}
-
-/**
- * Suited for EPoX EP-8RDA3+: Socket A + nForce2 Ultra 400 + MCP2.
- */
-static int nvidia_mcp_gpio31_raise(const char *name)
-{
-	return nvidia_mcp_gpio_set(0x31, 0x01);
-}
-
-/**
- * Suited for EPoX EP-BX3, and maybe some other Intel 440BX based boards.
- */
-static int board_epox_ep_bx3(const char *name)
-{
-	uint8_t tmp;
-
-	/* Raise GPIO22. */
-	tmp = INB(0x4036);
-	OUTB(tmp, 0xEB);
-
-	tmp |= 0x40;
-
-	OUTB(tmp, 0x4036);
-	OUTB(tmp, 0xEB);
-
-	return 0;
-}
-
-/**
- * Suited for Artec Group DBE61 and DBE62.
- */
-static int board_artecgroup_dbe6x(const char *name)
-{
-#define DBE6x_MSR_DIVIL_BALL_OPTS	0x51400015
-#define DBE6x_PRI_BOOT_LOC_SHIFT	(2)
-#define DBE6x_BOOT_OP_LATCHED_SHIFT	(8)
-#define DBE6x_SEC_BOOT_LOC_SHIFT	(10)
-#define DBE6x_PRI_BOOT_LOC		(3 << DBE6x_PRI_BOOT_LOC_SHIFT)
-#define DBE6x_BOOT_OP_LATCHED		(3 << DBE6x_BOOT_OP_LATCHED_SHIFT)
-#define DBE6x_SEC_BOOT_LOC		(3 << DBE6x_SEC_BOOT_LOC_SHIFT)
-#define DBE6x_BOOT_LOC_FLASH		(2)
-#define DBE6x_BOOT_LOC_FWHUB		(3)
-
-	msr_t msr;
-	unsigned long boot_loc;
-
-	/* Geode only has a single core */
-	if (setup_cpu_msr(0))
-		return -1;
-
-	msr = rdmsr(DBE6x_MSR_DIVIL_BALL_OPTS);
-
-	if ((msr.lo & (DBE6x_BOOT_OP_LATCHED)) ==
-	    (DBE6x_BOOT_LOC_FWHUB << DBE6x_BOOT_OP_LATCHED_SHIFT))
-		boot_loc = DBE6x_BOOT_LOC_FWHUB;
-	else
-		boot_loc = DBE6x_BOOT_LOC_FLASH;
-
-	msr.lo &= ~(DBE6x_PRI_BOOT_LOC | DBE6x_SEC_BOOT_LOC);
-	msr.lo |= ((boot_loc << DBE6x_PRI_BOOT_LOC_SHIFT) |
-		   (boot_loc << DBE6x_SEC_BOOT_LOC_SHIFT));
-
-	wrmsr(DBE6x_MSR_DIVIL_BALL_OPTS, msr);
-
-	cleanup_cpu_msr();
-
-	return 0;
-}
-
-/**
- * Set a GPIO line on a given intel ICH LPC controller.
- */
-static int intel_ich_gpio_set(int gpio, int raise)
-{
-	/* table mapping the different intel ICH LPC chipsets. */
-	static struct {
-		uint16_t id;
-		uint8_t base_reg;
-		uint32_t bank0;
-		uint32_t bank1;
-		uint32_t bank2;
-	} intel_ich_gpio_table[] = {
-		{0x2410, 0x58, 0x0FE30000,          0,          0}, /* 82801AA (ICH) */
-		{0x2420, 0x58, 0x0FE30000,          0,          0}, /* 82801AB (ICH0) */
-		{0x2440, 0x58, 0x1BFF391B,          0,          0}, /* 82801BA (ICH2) */
-		{0x244C, 0x58, 0x1A23399B,          0,          0}, /* 82801BAM (ICH2M) */
-		{0x2450, 0x58, 0x1BFF0000,          0,          0}, /* 82801E (C-ICH) */
-		{0x2480, 0x58, 0x1BFF0000, 0x00000FFF,          0}, /* 82801CA (ICH3-S) */
-		{0x248C, 0x58, 0x1A230000, 0x00000FFF,          0}, /* 82801CAM (ICH3-M) */
-		{0x24C0, 0x58, 0x1BFF0000, 0x00000FFF,          0}, /* 82801DB/DBL (ICH4/ICH4-L) */
-		{0x24CC, 0x58, 0x1A030000, 0x00000FFF,          0}, /* 82801DBM (ICH4-M) */
-		{0x24D0, 0x58, 0x1BFF0000, 0x00030305,          0}, /* 82801EB/ER (ICH5/ICH5R) */
-		{0x2640, 0x48, 0x1BFF0000, 0x00030307,          0}, /* 82801FB/FR (ICH6/ICH6R) */
-		{0x2641, 0x48, 0x1BFF0000, 0x00030307,          0}, /* 82801FBM (ICH6M) */
-		{0x27B8, 0x48, 0xFFFFFFFF, 0x000300FF,          0}, /* 82801GB/GR (ICH7 Family) */
-		{0x27B9, 0x48, 0xFFEBFFFE, 0x000300FE,          0}, /* 82801GBM (ICH7-M) */
-		{0x27BD, 0x48, 0xFFEBFFFE, 0x000300FE,          0}, /* 82801GHM (ICH7-M DH) */
-		{0x2810, 0x48, 0xFFFFFFFF, 0x00FF0FFF,          0}, /* 82801HB/HR (ICH8/R) */
-		{0x2811, 0x48, 0xFFFFFFFF, 0x00FF0FFF,          0}, /* 82801HBM (ICH8M-E) */
-		{0x2812, 0x48, 0xFFFFFFFF, 0x00FF0FFF,          0}, /* 82801HH (ICH8DH) */
-		{0x2814, 0x48, 0xFFFFFFFF, 0x00FF0FFF,          0}, /* 82801HO (ICH8DO) */
-		{0x2815, 0x48, 0xFFFFFFFF, 0x00FF0FFF,          0}, /* 82801HEM (ICH8M) */
-		{0x2912, 0x48, 0xFFFFFFFF, 0x00FFFFFF,          0}, /* 82801IH (ICH9DH) */
-		{0x2914, 0x48, 0xFFFFFFFF, 0x00FFFFFF,          0}, /* 82801IO (ICH9DO) */
-		{0x2916, 0x48, 0xFFFFFFFF, 0x00FFFFFF,          0}, /* 82801IR (ICH9R) */
-		{0x2917, 0x48, 0xFFFFFFFF, 0x00FFFFFF,          0}, /* 82801IEM (ICH9M-E) */
-		{0x2918, 0x48, 0xFFFFFFFF, 0x00FFFFFF,          0}, /* 82801IB (ICH9) */
-		{0x2919, 0x48, 0xFFFFFFFF, 0x00FFFFFF,          0}, /* 82801IBM (ICH9M) */
-		{0x3A14, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JDO (ICH10DO) */
-		{0x3A16, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JIR (ICH10R) */
-		{0x3A18, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JIB (ICH10) */
-		{0x3A1A, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JD (ICH10D) */
-		{0, 0, 0, 0, 0} /* end marker */
-	};
-
-	struct pci_dev *dev;
-	uint16_t base;
-	uint32_t tmp;
-	int i, allowed;
-
-	/* First, look for a known LPC bridge */
-	for (dev = pacc->devices; dev; dev = dev->next)
-		if ((dev->vendor_id == 0x8086) &&
-		    (dev->device_class == 0x0601)) { /* ISA Bridge */
-			/* Is this device in our list? */
-			for (i = 0; intel_ich_gpio_table[i].id; i++)
-				if (dev->device_id == intel_ich_gpio_table[i].id)
-					break;
-
-			if (intel_ich_gpio_table[i].id)
-				break;
-		}
-
-	if (!dev) {
-		fprintf(stderr, "\nERROR: No Known Intel LPC Bridge found.\n");
-		return -1;
-	}
-
-	/* According to the datasheets, all intel ICHs have the gpio bar 5:1
-	   strapped to zero. From some mobile ich9 version on, this becomes
-	   6:1. The mask below catches all. */
-	base = pci_read_word(dev, intel_ich_gpio_table[i].base_reg) & 0xFFC0;
-
-	/* check whether the line is allowed */
-	if (gpio < 32)
-		allowed = (intel_ich_gpio_table[i].bank0 >> gpio) & 0x01;
-	else if (gpio < 64)
-		allowed = (intel_ich_gpio_table[i].bank1 >> (gpio - 32)) & 0x01;
-	else
-		allowed = (intel_ich_gpio_table[i].bank2 >> (gpio - 64)) & 0x01;
-
-	if (!allowed) {
-		fprintf(stderr, "\nERROR: This Intel LPC Bridge does not allow"
-			" setting GPIO%02d\n", gpio);
-		return -1;
-	}
-
-	printf("\nIntel ICH LPC Bridge: %sing GPIO%02d.\n",
-	       raise ? "Rais" : "Dropp", gpio);
-
-	if (gpio < 32) {
-		/* Set line to GPIO */
-		tmp = INL(base);
-		/* ICH/ICH0 multiplexes 27/28 on the line set. */
-		if ((gpio == 28) &&
-		    ((dev->device_id == 0x2410) || (dev->device_id == 0x2420)))
-			tmp |= 1 << 27;
-		else
-			tmp |= 1 << gpio;
-		OUTL(tmp, base);
-
-		/* As soon as we are talking to ICH8 and above, this register
-		   decides whether we can set the gpio or not. */
-		if (dev->device_id > 0x2800) {
-			tmp = INL(base);
-			if (!(tmp & (1 << gpio))) {
-				fprintf(stderr, "\nERROR: This Intel LPC Bridge"
-					" does not allow setting GPIO%02d\n",
-					gpio);
-				return -1;
-			}
-		}
-
-		/* Set GPIO to OUTPUT */
-		tmp = INL(base + 0x04);
-		tmp &= ~(1 << gpio);
-		OUTL(tmp, base + 0x04);
-
-		/* Raise GPIO line */
-		tmp = INL(base + 0x0C);
-		if (raise)
-			tmp |= 1 << gpio;
-		else
-			tmp &= ~(1 << gpio);
-		OUTL(tmp, base + 0x0C);
-	} else if (gpio < 64) {
-		gpio -= 32;
-
-		/* Set line to GPIO */
-		tmp = INL(base + 0x30);
-		tmp |= 1 << gpio;
-		OUTL(tmp, base + 0x30);
-
-		/* As soon as we are talking to ICH8 and above, this register
-		   decides whether we can set the gpio or not. */
-		if (dev->device_id > 0x2800) {
-			tmp = INL(base + 30);
-			if (!(tmp & (1 << gpio))) {
-				fprintf(stderr, "\nERROR: This Intel LPC Bridge"
-					" does not allow setting GPIO%02d\n",
-					gpio + 32);
-				return -1;
-			}
-		}
-
-		/* Set GPIO to OUTPUT */
-		tmp = INL(base + 0x34);
-		tmp &= ~(1 << gpio);
-		OUTL(tmp, base + 0x34);
-
-		/* Raise GPIO line */
-		tmp = INL(base + 0x38);
-		if (raise)
-			tmp |= 1 << gpio;
-		else
-			tmp &= ~(1 << gpio);
-		OUTL(tmp, base + 0x38);
-	} else {
-		gpio -= 64;
-
-		/* Set line to GPIO */
-		tmp = INL(base + 0x40);
-		tmp |= 1 << gpio;
-		OUTL(tmp, base + 0x40);
-
-		tmp = INL(base + 40);
-		if (!(tmp & (1 << gpio))) {
-			fprintf(stderr, "\nERROR: This Intel LPC Bridge does "
-				"not allow setting GPIO%02d\n", gpio + 64);
-			return -1;
-		}
-
-		/* Set GPIO to OUTPUT */
-		tmp = INL(base + 0x44);
-		tmp &= ~(1 << gpio);
-		OUTL(tmp, base + 0x44);
-
-		/* Raise GPIO line */
-		tmp = INL(base + 0x48);
-		if (raise)
-			tmp |= 1 << gpio;
-		else
-			tmp &= ~(1 << gpio);
-		OUTL(tmp, base + 0x48);
-	}
-
-	return 0;
-}
-
-/**
- * Suited for Abit IP35: Intel P35 + ICH9R.
- */
-static int intel_ich_gpio16_raise(const char *name)
-{
-	return intel_ich_gpio_set(16, 1);
-}
-
-/**
- * Suited for MSI MS-7046: LGA775 + 915P + ICH6.
- */
-static int intel_ich_gpio19_raise(const char *name)
-{
-	return intel_ich_gpio_set(19, 1);
-}
-
-/**
- * Suited for:
- * - Asus P4B266LM (Sony Vaio PCV-RX650): socket478 + 845D + ICH2.
- * - Asus P4P800-E Deluxe: Intel socket478 + 865PE + ICH5R.
- */
-static int intel_ich_gpio21_raise(const char *name)
-{
-	return intel_ich_gpio_set(21, 1);
-}
-
-/**
- * Suited for ASUS P4B266: socket478 + intel 845D + ICH2.
- */
-static int intel_ich_gpio22_raise(const char *name)
-{
-	return intel_ich_gpio_set(22, 1);
-}
-
-/**
- * Suited for:
- * - Dell Poweredge 1850: Intel PPGA604 + E7520 + ICH5R.
- * - ASRock P4i65GV: Intel Socket478 + 865GV + ICH5R.
- */
-static int intel_ich_gpio23_raise(const char *name)
-{
-	return intel_ich_gpio_set(23, 1);
-}
-
-/**
- * Suited for Acorp 6A815EPD: socket 370 + intel 815 + ICH2.
- */
-static int board_acorp_6a815epd(const char *name)
-{
-	int ret;
-
-	/* Lower Blocks Lock -- pin 7 of PLCC32 */
-	ret = intel_ich_gpio_set(22, 1);
-	if (!ret) /* Top Block Lock -- pin 8 of PLCC32 */
-		ret = intel_ich_gpio_set(23, 1);
-
-	return ret;
-}
-
-/**
- * Suited for Kontron 986LCD-M: socket478 + 915GM + ICH7R.
- */
-static int board_kontron_986lcd_m(const char *name)
-{
-	int ret;
-
-	ret = intel_ich_gpio_set(34, 1); /* #TBL */
-	if (!ret)
-		ret = intel_ich_gpio_set(35, 1); /* #WP */
-
-	return ret;
-}
-
-/**
- * Suited for:
- *   - Biostar P4M80-M4: VIA P4M800 + VT8237 + IT8705AF
- *   - GIGABYTE GA-7VT600: VIA KT600 + VT8237 + IT8705
- *
- * SIS950 superio probably requires the same flash write enable.
- */
-static int it8705_rom_write_enable(const char *name)
-{
-	/* enter IT87xx conf mode */
-	enter_conf_mode_ite(0x2e);
-
-	/* select right flash chip */
-	sio_mask(0x2e, 0x22, 0x80, 0x80);
-
-	/* bit 3: flash chip write enable
-	 * bit 7: map flash chip at 1MB-128K (why though? ignoring this.)
-	 */
-	sio_mask(0x2e, 0x24, 0x04, 0x04);
-
-	/* exit IT87xx conf mode */
-	exit_conf_mode_ite(0x2e);
-
-	return 0;
-}
-
-/**
- * Suited for AOpen vKM400Am-S: VIA KM400 + VT8237 + IT8705F.
- */
-static int board_aopen_vkm400(const char *name)
-{
-	struct pci_dev *dev;
-
-	dev = pci_dev_find(0x1106, 0x3227);	/* VT8237 ISA bridge */
-	if (!dev) {
-		fprintf(stderr, "\nERROR: VT8237 ISA bridge not found.\n");
-		return -1;
-	}
-
-	vt823x_set_all_writes_to_lpc(dev);
-
-	return it8705_rom_write_enable(name);
-}
-
-/**
- * Winbond W83697HF Super I/O + VIA VT8235 southbridge
- *
- * Suited for:
- *   - MSI KT4V and KT4V-L: AMD K7 + VIA KT400 + VT8235
- *   - MSI KT4 Ultra: AMD K7 + VIA KT400 + VT8235
- */
-static int board_msi_kt4v(const char *name)
-{
-	struct pci_dev *dev;
-
-	dev = pci_dev_find(0x1106, 0x3177);	/* VT8235 ISA bridge */
-	if (!dev) {
-		fprintf(stderr, "\nERROR: VT823x ISA bridge not found.\n");
-		return -1;
-	}
-
-	vt823x_set_all_writes_to_lpc(dev);
-
-	vt823x_gpio_set(dev, 12, 1);
-	w836xx_memw_enable(0x2E);
-
-	return 0;
-}
-
-/**
- * Suited for Soyo SY-7VCA: Pro133A + VT82C686.
- */
-static int board_soyo_sy_7vca(const char *name)
-{
-    	struct pci_dev *dev;
-	uint32_t base;
-	uint8_t tmp;
-
-	/* VT82C686 Power management */
-	dev = pci_dev_find(0x1106, 0x3057);
-	if (!dev) {
-		fprintf(stderr, "\nERROR: VT82C686 PM device not found.\n");
-		return -1;
-	}
-
-	/* GPO0 output from PM IO base + 0x4C */
-	tmp = pci_read_byte(dev, 0x54);
-	tmp &= ~0x03;
-	pci_write_byte(dev, 0x54, tmp);
-
-	/* PM IO base */
-	base = pci_read_long(dev, 0x48) & 0x0000FF00;
-
-	/* Drop GPO0 */
-	tmp = INB(base + 0x4C);
-	tmp &= ~0x01;
-	OUTB(tmp, base + 0x4C);
-
-	return 0;
-}
-
-static int it8705f_write_enable(uint8_t port, const char *name)
-{
-	enter_conf_mode_ite(port);
-	sio_mask(port, 0x24, 0x04, 0x04); /* Flash ROM I/F Writes Enable */
-	exit_conf_mode_ite(port);
-
-	return 0;
-}
-
-/**
- * Suited for:
- *   - Shuttle AK38N: VIA KT333CF + VIA VT8235 + ITE IT8705F
- *   - Elitegroup K7VTA3: VIA Apollo KT266/A/333 + VIA VT8235 + ITE IT8705F
- */
-static int it8705f_write_enable_2e(const char *name)
-{
-	return it8705f_write_enable(0x2e, name);
-}
-
-/**
- * Find the runtime registers of an SMSC Super I/O, after verifying its
- * chip ID.
- *
- * Returns the base port of the runtime register block, or 0 on error.
- */
-static uint16_t smsc_find_runtime(uint16_t sio_port, uint16_t chip_id,
-                                  uint8_t logical_device)
-{
-	uint16_t rt_port = 0;
-
-	/* Verify the chip ID. */
-	OUTB(0x55, sio_port);  /* Enable configuration. */
-	if (sio_read(sio_port, 0x20) != chip_id) {
-		fprintf(stderr, "\nERROR: SMSC Super I/O not found.\n");
-		goto out;
-	}
-
-	/* If the runtime block is active, get its address. */
-	sio_write(sio_port, 0x07, logical_device);
-	if (sio_read(sio_port, 0x30) & 1) {
-		rt_port = (sio_read(sio_port, 0x60) << 8)
-		          | sio_read(sio_port, 0x61);
-	}
-
-	if (rt_port == 0) {
-		fprintf(stderr, "\nERROR: "
-			"Super I/O runtime interface not available.\n");
-	}
-out:
-	OUTB(0xaa, sio_port);  /* Disable configuration. */
-	return rt_port;
-}
-
-/**
- * Disable write protection on the Mitac 6513WU.  WP# on the FWH is
- * connected to GP30 on the Super I/O, and TBL# is always high.
- */
-static int board_mitac_6513wu(const char *name)
-{
-	struct pci_dev *dev;
-	uint16_t rt_port;
-	uint8_t val;
-
-	dev = pci_dev_find(0x8086, 0x2410);	/* Intel 82801AA ISA bridge */
-	if (!dev) {
-		fprintf(stderr, "\nERROR: Intel 82801AA ISA bridge not found.\n");
-		return -1;
-	}
-
-	rt_port = smsc_find_runtime(0x4e, 0x54 /* LPC47U33x */, 0xa);
-	if (rt_port == 0)
-		return -1;
-
-	/* Configure the GPIO pin. */
-	val = INB(rt_port + 0x33);  /* GP30 config */
-	val &= ~0x87;               /* Output, non-inverted, GPIO, push/pull */
-	OUTB(val, rt_port + 0x33);
-
-	/* Disable write protection. */
-	val = INB(rt_port + 0x4d);  /* GP3 values */
-	val |= 0x01;                /* Set GP30 high. */
-	OUTB(val, rt_port + 0x4d);
-
-	return 0;
-}
-
-/**
- * Suited for Asus A7V8X: VIA KT400 + VT8235 + IT8703F-A
- */
-static int board_asus_a7v8x(const char *name)
-{
-	uint16_t id, base;
-	uint8_t tmp;
-
-	/* find the IT8703F */
-	w836xx_ext_enter(0x2E);
-	id = (sio_read(0x2E, 0x20) << 8) | sio_read(0x2E, 0x21);
-	w836xx_ext_leave(0x2E);
-
-	if (id != 0x8701) {
-		fprintf(stderr, "\nERROR: IT8703F SuperIO not found.\n");
-		return -1;
-	}
-
-	/* Get the GP567 IO base */
-	w836xx_ext_enter(0x2E);
-	sio_write(0x2E, 0x07, 0x0C);
-	base = (sio_read(0x2E, 0x60) << 8) | sio_read(0x2E, 0x61);
-	w836xx_ext_leave(0x2E);
-
-	if (!base) {
-		fprintf(stderr, "\nERROR: Failed to read IT8703F SuperIO GPIO"
-			" Base.\n");
-		return -1;
-	}
-
-	/* Raise GP51. */
-	tmp = INB(base);
-	tmp |= 0x02;
-	OUTB(tmp, base);
-
-	return 0;
-}
-
-/*
- * General routine for raising/dropping GPIO lines on the ITE IT8712F.
- * There is only some limited checking on the port numbers.
- */
-static int
-it8712f_gpio_set(unsigned int line, int raise)
-{
-	unsigned int port;
-	uint16_t id, base;
-	uint8_t tmp;
-
-	port = line / 10;
-	port--;
-	line %= 10;
-
-	/* Check line */
-	if ((port > 4) || /* also catches unsigned -1 */
-	    ((port < 4) && (line > 7)) || ((port == 4) && (line > 5))) {
-	    fprintf(stderr,
-		    "\nERROR: Unsupported IT8712F GPIO Line %02d.\n", line);
-	    return -1;
-	}
-
-	/* find the IT8712F */
-	enter_conf_mode_ite(0x2E);
-	id = (sio_read(0x2E, 0x20) << 8) | sio_read(0x2E, 0x21);
-	exit_conf_mode_ite(0x2E);
-
-	if (id != 0x8712) {
-		fprintf(stderr, "\nERROR: IT8712F SuperIO not found.\n");
-		return -1;
-	}
-
-	/* Get the GPIO base */
-	enter_conf_mode_ite(0x2E);
-	sio_write(0x2E, 0x07, 0x07);
-	base = (sio_read(0x2E, 0x62) << 8) | sio_read(0x2E, 0x63);
-	exit_conf_mode_ite(0x2E);
-
-	if (!base) {
-		fprintf(stderr, "\nERROR: Failed to read IT8712F SuperIO GPIO"
-			" Base.\n");
-		return -1;
-	}
-
-	/* set GPIO. */
-	tmp = INB(base + port);
-	if (raise)
-	    tmp |= 1 << line;
-	else
-	    tmp &= ~(1 << line);
-	OUTB(tmp, base + port);
-
-	return 0;
-}
-
-/**
- * Suited for Asus A7V600-X: VIA KT600 + VT8237 + IT8712F
- */
-static int board_asus_a7v600x(const char *name)
-{
-	return it8712f_gpio_set(32, 1);
-}
-
-/**
- * Suited for Asus M2V-MX: VIA K8M890 + VT8237A + IT8716F
- */
-static int board_asus_m2v_mx(const char *name)
-{
-	struct pci_dev *dev;
-
-	dev = pci_dev_find(0x1106, 0x3337);	/* VT8237A ISA bridge */
-	if (!dev) {
-		fprintf(stderr, "\nERROR: VT8237A ISA bridge not found.\n");
-		return -1;
-	}
-
-	/* GPO5 is connected to WP# and TBL#. */
-	vt823x_gpio_set(dev, 5, 1);
-
-	return 0;
-}
-
-
-/**
- * Below is the list of boards which need a special "board enable" code in
- * flashrom before their ROM chip can be accessed/written to.
- *
- * NOTE: Please add boards that _don't_ need such enables or don't work yet
- *       to the respective tables in print.c. Thanks!
- *
- * We use 2 sets of IDs here, you're free to choose which is which. This
- * is to provide a very high degree of certainty when matching a board on
- * the basis of subsystem/card IDs. As not every vendor handles
- * subsystem/card IDs in a sane manner.
- *
- * Keep the second set NULLed if it should be ignored. Keep the subsystem IDs
- * NULLed if they don't identify the board fully. But please take care to
- * provide an as complete set of pci ids as possible; autodetection is the
- * preferred behaviour and we would like to make sure that matches are unique.
- *
- * The coreboot ids are used two fold. When running with a coreboot firmware,
- * the ids uniquely matches the coreboot board identification string. When a
- * legacy bios is installed and when autodetection is not possible, these ids
- * can be used to identify the board through the -m command line argument.
- *
- * When a board is identified through its coreboot ids (in both cases), the
- * main pci ids are still required to match, as a safeguard.
- */
-
-/* Please keep this list alphabetically ordered by vendor/board name. */
-struct board_pciid_enable board_pciid_enables[] = {
-	/* first pci-id set [4],          second pci-id set [4],          coreboot id [2],             vendor name    board name            flash enable */
-	{0x8086, 0x2926, 0x147b, 0x1084,  0x11ab, 0x4364, 0x147b, 0x1084, NULL,         NULL,          "Abit",        "IP35",               intel_ich_gpio16_raise},
-	{0x105a, 0x0d30, 0x105a, 0x4d33,  0x8086, 0x1130, 0x8086,      0, NULL,         NULL,          "Acorp",       "6A815EPD",           board_acorp_6a815epd},
-	{0x8086, 0x24D4, 0x1849, 0x24D0,  0x8086, 0x24D5, 0x1849, 0x9739, NULL,         NULL,          "ASRock",      "P4i65GV",            intel_ich_gpio23_raise},
-	{0x1022, 0x746B,      0,      0,       0,      0,      0,      0, "AGAMI",      "ARUMA",       "agami",       "Aruma",              w83627hf_gpio24_raise_2e},
-	{0x1106, 0x3177, 0x17F2, 0x3177,  0x1106, 0x3148, 0x17F2, 0x3148, NULL,         NULL,          "Albatron",    "PM266A",             w836xx_memw_enable_2e},
-	{0x1106, 0x3205, 0x1106, 0x3205,  0x10EC, 0x8139, 0xA0A0, 0x0477, NULL,         NULL,          "AOpen",       "vKM400Am-S",         board_aopen_vkm400},
-	{0x1022, 0x2090,      0,      0,  0x1022, 0x2080,      0,      0, "artecgroup", "dbe61",       "Artec Group", "DBE61",              board_artecgroup_dbe6x},
-	{0x1022, 0x2090,      0,      0,  0x1022, 0x2080,      0,      0, "artecgroup", "dbe62",       "Artec Group", "DBE62",              board_artecgroup_dbe6x},
-	{0x1106, 0x3189, 0x1043, 0x807F,  0x1106, 0x3065, 0x1043, 0x80ED, NULL,         NULL,          "ASUS",        "A7V600-X",           board_asus_a7v600x},
-	{0x1106, 0x3189, 0x1043, 0x807F,  0x1106, 0x3177, 0x1043, 0x808C, NULL,         NULL,          "ASUS",        "A7V8X",              board_asus_a7v8x},
-	{0x1106, 0x3177, 0x1043, 0x80A1,  0x1106, 0x3205, 0x1043, 0x8118, NULL,         NULL,          "ASUS",        "A7V8X-MX SE",        board_asus_a7v8x_mx},
-	{0x1106, 0x1336, 0x1043, 0x80ed,  0x1106, 0x3288, 0x1043, 0x8249, NULL,         NULL,          "ASUS",        "M2V-MX",             board_asus_m2v_mx},
-	{0x8086, 0x1a30, 0x1043, 0x8070,  0x8086, 0x244b, 0x1043, 0x8028, NULL,         NULL,          "ASUS",        "P4B266",             intel_ich_gpio22_raise},
-	{0x8086, 0x1A30, 0x1043, 0x8025,  0x8086, 0x244B, 0x104D, 0x80F0, NULL,         NULL,          "ASUS",        "P4B266-LM",          intel_ich_gpio21_raise},
-	{0x8086, 0x2570, 0x1043, 0x80F2,  0x105A, 0x3373, 0x1043, 0x80F5, NULL,         NULL,          "ASUS",        "P4P800-E Deluxe",    intel_ich_gpio21_raise},
-	{0x10B9, 0x1541,      0,      0,  0x10B9, 0x1533,      0,      0, "asus",       "p5a",         "ASUS",        "P5A",                board_asus_p5a},
-	{0x10DE, 0x0030, 0x1043, 0x818a,  0x8086, 0x100E, 0x1043, 0x80EE, NULL,         NULL,          "ASUS",        "P5ND2-SLI Deluxe",   nvidia_mcp_gpio10_raise},
-	{0x1106, 0x3149, 0x1565, 0x3206,  0x1106, 0x3344, 0x1565, 0x1202, NULL,         NULL,          "Biostar",     "P4M80-M4",           it8705_rom_write_enable},
-	{0x8086, 0x3590, 0x1028, 0x016c,  0x1000, 0x0030, 0x1028, 0x016c, NULL,         NULL,          "Dell",        "PowerEdge 1850",     intel_ich_gpio23_raise},
-	{0x1106, 0x3038, 0x1019, 0x0996,  0x1106, 0x3177, 0x1019, 0x0996, NULL,         NULL,          "Elitegroup",  "K7VTA3",             it8705f_write_enable_2e},
-	{0x1106, 0x3177, 0x1106, 0x3177,  0x1106, 0x3059, 0x1695, 0x3005, NULL,         NULL,          "EPoX",        "EP-8K5A2",           w836xx_memw_enable_2e},
-	{0x10EC, 0x8139, 0x1695, 0x9001,  0x11C1, 0x5811, 0x1695, 0x9015, NULL,         NULL,          "EPoX",        "EP-8RDA3+",          nvidia_mcp_gpio31_raise},
-	{0x8086, 0x7110,      0,      0,  0x8086, 0x7190,      0,      0, "epox",       "ep-bx3",      "EPoX",        "EP-BX3",             board_epox_ep_bx3},
-	{0x1039, 0x0761,      0,      0,  0x10EC, 0x8168,      0,      0, "gigabyte",   "2761gxdk",    "GIGABYTE",    "GA-2761GXDK",        it87xx_probe_spi_flash},
-	{0x1106, 0x3227, 0x1458, 0x5001,  0x10ec, 0x8139, 0x1458, 0xe000, NULL,         NULL,          "GIGABYTE",    "GA-7VT600",          it8705_rom_write_enable},
-	{0x10DE, 0x0050, 0x1458, 0x0C11,  0x10DE, 0x005e, 0x1458, 0x5000, NULL,         NULL,          "GIGABYTE",    "GA-K8N-SLI",         nvidia_mcp_gpio21_raise},
-	{0x10DE, 0x0360, 0x1458, 0x0C11,  0x10DE, 0x0369, 0x1458, 0x5001, "gigabyte",   "m57sli",      "GIGABYTE",    "GA-M57SLI-S4",       it87xx_probe_spi_flash},
-	{0x10de, 0x03e0,      0,      0,  0x10DE, 0x03D0,      0,      0, NULL,         NULL,          "GIGABYTE",    "GA-M61P-S3",         it87xx_probe_spi_flash},
-	{0x1002, 0x4398, 0x1458, 0x5004,  0x1002, 0x4391, 0x1458, 0xb000, NULL,         NULL,          "GIGABYTE",    "GA-MA78G-DS3H",      it87xx_probe_spi_flash},
-	{0x1002, 0x4398, 0x1458, 0x5004,  0x1002, 0x4391, 0x1458, 0xb002, NULL,         NULL,          "GIGABYTE",    "GA-MA78GM-S2H",      it87xx_probe_spi_flash},
-	{0x1002, 0x438d, 0x1458, 0x5001,  0x1002, 0x5956, 0x1002, 0x5956, NULL,         NULL,          "GIGABYTE",    "GA-MA790FX-DQ6",     it87xx_probe_spi_flash},
-	{0x1166, 0x0223, 0x103c, 0x320d,  0x102b, 0x0522, 0x103c, 0x31fa, "hp",         "dl145_g3",    "HP",          "DL145 G3",           board_hp_dl145_g3_enable},
-	{0x1166, 0x0205, 0x1014, 0x0347,  0x1002, 0x515E, 0x1014, 0x0325, NULL,         NULL,          "IBM",         "x3455",              board_ibm_x3455},
-	{0x1039, 0x5513, 0x8086, 0xd61f,  0x1039, 0x6330, 0x8086, 0xd61f, NULL,         NULL,          "Intel",       "D201GLY",            wbsio_check_for_spi},
-	{0x1022, 0x7468,      0,      0,       0,      0,      0,      0, "iwill",      "dk8_htx",     "IWILL",       "DK8-HTX",            w83627hf_gpio24_raise_2e},
-	{0x8086, 0x27A0,      0,      0,  0x8086, 0x27b8,      0,      0, "kontron",    "986lcd-m",    "Kontron",     "986LCD-M",           board_kontron_986lcd_m},
-	{0x8086, 0x2411, 0x8086, 0x2411,  0x8086, 0x7125, 0x0e11, 0xb165, NULL,         NULL,          "Mitac",       "6513WU",             board_mitac_6513wu},
-	{0x13f6, 0x0111, 0x1462, 0x5900,  0x1106, 0x3177, 0x1106,      0, NULL,         NULL,          "MSI",         "MS-6590 (KT4 Ultra)",board_msi_kt4v},
-	{0x1106, 0x3149, 0x1462, 0x7094,  0x10ec, 0x8167, 0x1462, 0x094c, NULL,         NULL,          "MSI",         "MS-6702E (K8T Neo2-F)",w83627thf_gpio4_4_raise_2e},
-	{0x1106, 0x0571, 0x1462, 0x7120,  0x1106, 0x3065, 0x1462, 0x7120, NULL,         NULL,          "MSI",         "MS-6712 (KT4V)",     board_msi_kt4v},
-	{0x8086, 0x2658, 0x1462, 0x7046,  0x1106, 0x3044, 0x1462, 0x046d, NULL,         NULL,          "MSI",         "MS-7046",            intel_ich_gpio19_raise},
-	{0x10DE, 0x005E, 0x1462, 0x7135,  0x10DE, 0x0050, 0x1462, 0x7135, "msi",        "k8n-neo3",    "MSI",         "MS-7135 (K8N Neo3)", w83627thf_gpio4_4_raise_4e},
-	{0x1106, 0x3099,      0,      0,  0x1106, 0x3074,      0,      0, "shuttle",    "ak31",        "Shuttle",     "AK31",               w836xx_memw_enable_2e},
-	{0x1106, 0x3104, 0x1297, 0xa238,  0x1106, 0x3059, 0x1297, 0xc063, NULL,         NULL,          "Shuttle",     "AK38N",              it8705f_write_enable_2e},
-	{0x10DE, 0x0050, 0x1297, 0x5036,  0x1412, 0x1724, 0x1297, 0x5036, NULL,         NULL,          "Shuttle",     "FN25",               board_shuttle_fn25},
-	{0x1106, 0x3038, 0x0925, 0x1234,  0x1106, 0x3058, 0x15DD, 0x7609, NULL,         NULL,          "Soyo",        "SY-7VCA",            board_soyo_sy_7vca},
-	{0x8086, 0x1076, 0x8086, 0x1176,  0x1106, 0x3059, 0x10f1, 0x2498, NULL,         NULL,          "Tyan",        "S2498 (Tomcat K7M)", board_asus_a7v8x_mx},
-	{0x1106, 0x0314, 0x1106, 0xaa08,  0x1106, 0x3227, 0x1106, 0xAA08, NULL,         NULL,          "VIA",         "EPIA-CN",            board_via_epia_sp},
-	{0x1106, 0x3177, 0x1106, 0xAA01,  0x1106, 0x3123, 0x1106, 0xAA01, NULL,         NULL,          "VIA",         "EPIA M/MII/...",     board_via_epia_m},
-	{0x1106, 0x0259, 0x1106, 0x3227,  0x1106, 0x3065, 0x1106, 0x3149, NULL,         NULL,          "VIA",         "EPIA-N/NL",          board_via_epia_n},
-	{0x1106, 0x3227, 0x1106, 0xAA01,  0x1106, 0x0259, 0x1106, 0xAA01, NULL,         NULL,          "VIA",         "EPIA SP",            board_via_epia_sp},
-	{0x1106, 0x5337, 0x1458, 0xb003,  0x1106, 0x287e, 0x1106, 0x337e, NULL,         NULL,          "VIA",         "PC3500G",            it87xx_probe_spi_flash},
-
-	{     0,      0,      0,      0,       0,      0,      0,      0, NULL,         NULL,          NULL,          NULL,                 NULL}, /* end marker */
-};
-
-/**
- * Match boards on coreboot table gathered vendor and part name.
- * Require main PCI IDs to match too as extra safety.
- */
-static struct board_pciid_enable *board_match_coreboot_name(const char *vendor,
-							    const char *part)
-{
-	struct board_pciid_enable *board = board_pciid_enables;
-	struct board_pciid_enable *partmatch = NULL;
-
-	for (; board->vendor_name; board++) {
-		if (vendor && (!board->lb_vendor
-			       || strcasecmp(board->lb_vendor, vendor)))
-			continue;
-
-		if (!board->lb_part || strcasecmp(board->lb_part, part))
-			continue;
-
-		if (!pci_dev_find(board->first_vendor, board->first_device))
-			continue;
-
-		if (board->second_vendor &&
-		    !pci_dev_find(board->second_vendor, board->second_device))
-			continue;
-
-		if (vendor)
-			return board;
-
-		if (partmatch) {
-			/* a second entry has a matching part name */
-			printf("AMBIGUOUS BOARD NAME: %s\n", part);
-			printf("At least vendors '%s' and '%s' match.\n",
-			       partmatch->lb_vendor, board->lb_vendor);
-			printf("Please use the full -m vendor:part syntax.\n");
-			return NULL;
-		}
-		partmatch = board;
-	}
-
-	if (partmatch)
-		return partmatch;
-
-	if (!partvendor_from_cbtable) {
-		/* Only warn if the mainboard type was not gathered from the
-		 * coreboot table. If it was, the coreboot implementor is
-		 * expected to fix flashrom, too.
-		 */
-		printf("\nUnknown vendor:board from -m option: %s:%s\n\n",
-		       vendor, part);
-	}
-	return NULL;
-}
-
-/**
- * Match boards on PCI IDs and subsystem IDs.
- * Second set of IDs can be main only or missing completely.
- */
-static struct board_pciid_enable *board_match_pci_card_ids(void)
-{
-	struct board_pciid_enable *board = board_pciid_enables;
-
-	for (; board->vendor_name; board++) {
-		if (!board->first_card_vendor || !board->first_card_device)
-			continue;
-
-		if (!pci_card_find(board->first_vendor, board->first_device,
-				   board->first_card_vendor,
-				   board->first_card_device))
-			continue;
-
-		if (board->second_vendor) {
-			if (board->second_card_vendor) {
-				if (!pci_card_find(board->second_vendor,
-						   board->second_device,
-						   board->second_card_vendor,
-						   board->second_card_device))
-					continue;
-			} else {
-				if (!pci_dev_find(board->second_vendor,
-						  board->second_device))
-					continue;
-			}
-		}
-
-		return board;
-	}
-
-	return NULL;
-}
-
-int board_flash_enable(const char *vendor, const char *part)
-{
-	struct board_pciid_enable *board = NULL;
-	int ret = 0;
-
-	if (part)
-		board = board_match_coreboot_name(vendor, part);
-
-	if (!board)
-		board = board_match_pci_card_ids();
-
-	if (board) {
-		printf("Disabling flash write protection for board \"%s %s\"... ",
-		       board->vendor_name, board->board_name);
-
-		ret = board->enable(board->vendor_name);
-		if (ret)
-			printf("FAILED!\n");
-		else
-			printf("OK.\n");
-	}
-
-	return ret;
-}
diff --git a/buspirate_spi.c b/buspirate_spi.c
deleted file mode 100644
index a1c8265..0000000
--- a/buspirate_spi.c
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Carl-Daniel Hailfinger
- *
- * 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; version 2 of the License.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include "flash.h"
-#include "spi.h"
-
-/* Change this to #define if you want to test without a serial implementation */
-#undef FAKE_COMMUNICATION
-
-#ifndef FAKE_COMMUNICATION
-int buspirate_serialport_setup(char *dev)
-{
-	/* 115200bps, 8 databits, no parity, 1 stopbit */
-	sp_fd = sp_openserport(dev, 115200);
-	return 0;
-}
-
-int buspirate_serialport_shutdown(void)
-{
-	close(sp_fd);
-	return 0;
-}
-
-int serialport_write(unsigned char *buf, unsigned int writecnt)
-{
-	int tmp = 0;
-
-	while (tmp != writecnt) {
-		tmp = write(sp_fd, buf + tmp, writecnt - tmp);
-		if (tmp == -1)
-			return 1;
-		if (!tmp)
-			printf_debug("Empty write\n");
-	}
-
-	return 0;
-}
-
-int serialport_read(unsigned char *buf, unsigned int readcnt)
-{
-	int tmp = 0;
-
-	while (tmp != readcnt) {
-		tmp = read(sp_fd, buf + tmp, readcnt - tmp);
-		if (tmp == -1)
-			return 1;
-		if (!tmp)
-			printf_debug("Empty read\n");
-	}
-
-	return 0;
-}
-
-int buspirate_discard_read(void)
-{
-	int flags;
-
-	printf_debug("%s\n", __func__);
-	flags = fcntl(sp_fd, F_GETFL);
-	flags |= O_NONBLOCK;
-	fcntl(sp_fd, F_SETFL, flags);
-	sp_flush_incoming();
-	flags &= ~O_NONBLOCK;
-	fcntl(sp_fd, F_SETFL, flags);
-
-	return 0;
-}
-#else
-#define buspirate_serialport_setup(...) 0
-#define buspirate_serialport_shutdown(...) 0
-#define serialport_write(...) 0
-#define serialport_read(...) 0
-#define buspirate_discard_read(...) 0
-#endif
-
-int buspirate_sendrecv(unsigned char *buf, unsigned int writecnt, unsigned int readcnt)
-{
-	int i, ret = 0;
-
-	printf_debug("%s: write %i, read %i\n", __func__, writecnt, readcnt);
-	if (!writecnt && !readcnt) {
-		fprintf(stderr, "Zero length command!\n");
-		return 1;
-	}
-	printf_debug("Sending");
-	for (i = 0; i < writecnt; i++)
-		printf_debug(" 0x%02x", buf[i]);
-#ifdef FAKE_COMMUNICATION
-	/* Placate the caller for now. */
-	if (readcnt) {
-		buf[0] = 0x01;
-		memset(buf + 1, 0xff, readcnt - 1);
-	}
-	ret = 0;
-#else
-	if (writecnt)
-		ret = serialport_write(buf, writecnt);
-	if (ret)
-		return ret;
-	if (readcnt)
-		ret = serialport_read(buf, readcnt);
-	if (ret)
-		return ret;
-#endif
-	printf_debug(", receiving");
-	for (i = 0; i < readcnt; i++)
-		printf_debug(" 0x%02x", buf[i]);
-	printf_debug("\n");
-	return 0;
-}
-
-static const struct buspirate_spispeeds spispeeds[] = {
-	{"30k",		0x0},
-	{"125k",	0x1},
-	{"250k",	0x2},
-	{"1M",		0x3},
-	{"2M",		0x4},
-	{"2.6M",	0x5},
-	{"4M",		0x6},
-	{"8M",		0x7},
-	{NULL,		0x0}
-};
-
-int buspirate_spi_init(void)
-{
-	unsigned char buf[512];
-	int ret = 0;
-	int i;
-	char *dev = NULL;
-	char *speed = NULL;
-	int spispeed = 0x7;
-
-	if (programmer_param && !strlen(programmer_param)) {
-		free(programmer_param);
-		programmer_param = NULL;
-	}
-	if (programmer_param) {
-		dev = extract_param(&programmer_param, "dev=", ",:");
-		speed = extract_param(&programmer_param, "spispeed=", ",:");
-		if (strlen(programmer_param))
-			fprintf(stderr, "Unhandled programmer parameters: %s\n",
-				programmer_param);
-		free(programmer_param);
-		programmer_param = NULL;
-	}
-	if (!dev) {
-		fprintf(stderr, "No serial device given. Use flashrom -p "
-			"buspiratespi:dev=/dev/ttyUSB0\n");
-		return 1;
-	}
-	if (speed) {
-		for (i = 0; spispeeds[i].name; i++)
-			if (!strncasecmp(spispeeds[i].name, speed,
-			    strlen(spispeeds[i].name))) {
-				spispeed = spispeeds[i].speed;
-				break;
-			}
-		if (!spispeeds[i].name)
-			fprintf(stderr, "Invalid SPI speed, using default.\n");
-	}
-	/* This works because speeds numbering starts at 0 and is contiguous. */
-	printf_debug("SPI speed is %sHz\n", spispeeds[spispeed].name);
-
-	ret = buspirate_serialport_setup(dev);
-	if (ret)
-		return ret;
-
-	/* This is the brute force version, but it should work. */
-	for (i = 0; i < 19; i++) {
-		/* Enter raw bitbang mode */
-		buf[0] = 0x00;
-		/* Send the command, don't read the response. */
-		ret = buspirate_sendrecv(buf, 1, 0);
-		if (ret)
-			return ret;
-		/* Read any response and discard it. */
-		ret = buspirate_discard_read();
-		if (ret)
-			return ret;
-	}
-	/* Enter raw bitbang mode */
-	buf[0] = 0x00;
-	ret = buspirate_sendrecv(buf, 1, 5);
-	if (ret)
-		return ret;
-	if (memcmp(buf, "BBIO", 4)) {
-		fprintf(stderr, "Entering raw bitbang mode failed!\n");
-		return 1;
-	}
-	printf_debug("Raw bitbang mode version %c\n", buf[4]);
-	if (buf[4] != '1') {
-		fprintf(stderr, "Can't handle raw bitbang mode version %c!\n",
-			buf[4]);
-		return 1;
-	}
-	/* Enter raw SPI mode */
-	buf[0] = 0x01;
-	ret = buspirate_sendrecv(buf, 1, 4);
-	if (memcmp(buf, "SPI", 3)) {
-		fprintf(stderr, "Entering raw SPI mode failed!\n");
-		return 1;
-	}
-	printf_debug("Raw SPI mode version %c\n", buf[3]);
-	if (buf[3] != '1') {
-		fprintf(stderr, "Can't handle raw SPI mode version %c!\n",
-			buf[3]);
-		return 1;
-	}
-
-	/* Initial setup (SPI peripherals config): Enable power, CS high, AUX */
-	buf[0] = 0x40 | 0xb;
-	ret = buspirate_sendrecv(buf, 1, 1);
-	if (ret)
-		return 1;
-	if (buf[0] != 0x01) {
-		fprintf(stderr, "Protocol error while setting power/CS/AUX!\n");
-		return 1;
-	}
-
-	/* Set SPI speed */
-	buf[0] = 0x60 | spispeed;
-	ret = buspirate_sendrecv(buf, 1, 1);
-	if (ret)
-		return 1;
-	if (buf[0] != 0x01) {
-		fprintf(stderr, "Protocol error while setting SPI speed!\n");
-		return 1;
-	}
-	
-	/* Set SPI config: output type, idle, clock edge, sample */
-	buf[0] = 0x80 | 0xa;
-	ret = buspirate_sendrecv(buf, 1, 1);
-	if (ret)
-		return 1;
-	if (buf[0] != 0x01) {
-		fprintf(stderr, "Protocol error while setting SPI config!\n");
-		return 1;
-	}
-
-	/* De-assert CS# */
-	buf[0] = 0x03;
-	ret = buspirate_sendrecv(buf, 1, 1);
-	if (ret)
-		return 1;
-	if (buf[0] != 0x01) {
-		fprintf(stderr, "Protocol error while raising CS#!\n");
-		return 1;
-	}
-
-	buses_supported = CHIP_BUSTYPE_SPI;
-	spi_controller = SPI_CONTROLLER_BUSPIRATE;
-
-	return 0;
-}
-
-int buspirate_spi_shutdown(void)
-{
-	unsigned char buf[5];
-	int ret = 0;
-
-	/* Exit raw SPI mode (enter raw bitbang mode) */
-	buf[0] = 0x00;
-	ret = buspirate_sendrecv(buf, 1, 5);
-	if (ret)
-		return ret;
-	if (memcmp(buf, "BBIO", 4)) {
-		fprintf(stderr, "Entering raw bitbang mode failed!\n");
-		return 1;
-	}
-	printf_debug("Raw bitbang mode version %c\n", buf[4]);
-	if (buf[4] != '1') {
-		fprintf(stderr, "Can't handle raw bitbang mode version %c!\n",
-			buf[4]);
-		return 1;
-	}
-	/* Reset Bus Pirate (return to user terminal) */
-	buf[0] = 0x0f;
-	ret = buspirate_sendrecv(buf, 1, 0);
-	if (ret)
-		return ret;
-
-	/* Shut down serial port communication */
-	ret = buspirate_serialport_shutdown();
-	if (ret)
-		return ret;
-	printf_debug("Bus Pirate shutdown completed.\n");
-
-	return 0;
-}
-
-int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-		const unsigned char *writearr, unsigned char *readarr)
-{
-	static unsigned char *buf = NULL;
-	int i = 0, ret = 0;
-
-	if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
-		return SPI_INVALID_LENGTH;
-
-	/* +2 is pretty arbitrary. */
-	buf = realloc(buf, writecnt + readcnt + 2);
-	if (!buf) {
-		fprintf(stderr, "Out of memory!\n");
-		exit(1); // -1
-	}
-
-	/* Assert CS# */
-	buf[i++] = 0x02;
-	ret = buspirate_sendrecv(buf, 1, 1);
-	if (ret)
-		return SPI_GENERIC_ERROR;
-	if (buf[0] != 0x01) {
-		fprintf(stderr, "Protocol error while lowering CS#!\n");
-		return SPI_GENERIC_ERROR;
-	}
-
-	i = 0;
-	buf[i++] = 0x10 | (writecnt + readcnt - 1);
-	memcpy(buf + i, writearr, writecnt);
-	i += writecnt;
-	memset(buf + i, 0, readcnt);
-	ret = buspirate_sendrecv(buf, i + readcnt, i + readcnt);
-	if (ret)
-		return SPI_GENERIC_ERROR;
-	if (buf[0] != 0x01) {
-		fprintf(stderr, "Protocol error while reading/writing SPI!\n");
-		return SPI_GENERIC_ERROR;
-	}
-	memcpy(readarr, buf + i, readcnt);
-
-	i = 0;
-	/* De-assert CS# */
-	buf[i++] = 0x03;
-	ret = buspirate_sendrecv(buf, 1, 1);
-	if (ret)
-		return SPI_GENERIC_ERROR;
-	if (buf[0] != 0x01) {
-		fprintf(stderr, "Protocol error while raising CS#!\n");
-		return SPI_GENERIC_ERROR;
-	}
-
-	return ret;
-}
-
-int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
-{
-	return spi_read_chunked(flash, buf, start, len, 12);
-}
-
-/* We could do 12-byte writes, but for now we use the generic 1-byte code. */
diff --git a/cbtable.c b/cbtable.c
deleted file mode 100644
index 9d7e758..0000000
--- a/cbtable.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2002 Steven James <pyro@linuxlabs.com>
- * Copyright (C) 2002 Linux Networx
- * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx)
- * Copyright (C) 2006-2009 coresystems GmbH
- * (Written by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH)
- *
- * 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; version 2 of the License.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <sys/types.h>
-#include <string.h>
-#include "flash.h"
-#include "coreboot_tables.h"
-
-char *lb_part = NULL, *lb_vendor = NULL;
-int partvendor_from_cbtable = 0;
-
-static unsigned long compute_checksum(void *addr, unsigned long length)
-{
-	uint8_t *ptr;
-	volatile union {
-		uint8_t byte[2];
-		uint16_t word;
-	} value;
-	unsigned long sum;
-	unsigned long i;
-
-	/* In the most straight forward way possible,
-	 * compute an ip style checksum.
-	 */
-	sum = 0;
-	ptr = addr;
-	for (i = 0; i < length; i++) {
-		unsigned long value;
-		value = ptr[i];
-		if (i & 1) {
-			value <<= 8;
-		}
-		/* Add the new value */
-		sum += value;
-		/* Wrap around the carry */
-		if (sum > 0xFFFF) {
-			sum = (sum + (sum >> 16)) & 0xFFFF;
-		}
-	}
-	value.byte[0] = sum & 0xff;
-	value.byte[1] = (sum >> 8) & 0xff;
-
-	return (~value.word) & 0xFFFF;
-}
-
-#define for_each_lbrec(head, rec) \
-	for(rec = (struct lb_record *)(((char *)head) + sizeof(*head)); \
-		(((char *)rec) < (((char *)head) + sizeof(*head) + head->table_bytes))  && \
-		(rec->size >= 1) && \
-		((((char *)rec) + rec->size) <= (((char *)head) + sizeof(*head) + head->table_bytes)); \
-		rec = (struct lb_record *)(((char *)rec) + rec->size))
-
-static int count_lb_records(struct lb_header *head)
-{
-	struct lb_record *rec;
-	int count;
-
-	count = 0;
-	for_each_lbrec(head, rec) {
-		count++;
-	}
-
-	return count;
-}
-
-static struct lb_header *find_lb_table(void *base, unsigned long start,
-				       unsigned long end)
-{
-	unsigned long addr;
-
-	/* For now be stupid.... */
-	for (addr = start; addr < end; addr += 16) {
-		struct lb_header *head =
-		    (struct lb_header *)(((char *)base) + addr);
-		struct lb_record *recs =
-		    (struct lb_record *)(((char *)base) + addr + sizeof(*head));
-		if (memcmp(head->signature, "LBIO", 4) != 0)
-			continue;
-		printf_debug("Found candidate at: %08lx-%08lx\n",
-			     addr, addr + head->table_bytes);
-		if (head->header_bytes != sizeof(*head)) {
-			fprintf(stderr, "Header bytes of %d are incorrect.\n",
-				head->header_bytes);
-			continue;
-		}
-		if (count_lb_records(head) != head->table_entries) {
-			fprintf(stderr, "Bad record count: %d.\n",
-				head->table_entries);
-			continue;
-		}
-		if (compute_checksum((uint8_t *) head, sizeof(*head)) != 0) {
-			fprintf(stderr, "Bad header checksum.\n");
-			continue;
-		}
-		if (compute_checksum(recs, head->table_bytes)
-		    != head->table_checksum) {
-			fprintf(stderr, "Bad table checksum: %04x.\n",
-				head->table_checksum);
-			continue;
-		}
-		printf_debug("Found coreboot table at 0x%08lx.\n", addr);
-		return head;
-
-	};
-
-	return 0;
-}
-
-static void find_mainboard(struct lb_record *ptr, unsigned long addr)
-{
-	struct lb_mainboard *rec;
-	int max_size;
-	char vendor[256], part[256];
-
-	rec = (struct lb_mainboard *)ptr;
-	max_size = rec->size - sizeof(*rec);
-	printf("Vendor ID: %.*s, part ID: %.*s\n",
-	       max_size - rec->vendor_idx,
-	       rec->strings + rec->vendor_idx,
-	       max_size - rec->part_number_idx,
-	       rec->strings + rec->part_number_idx);
-	snprintf(vendor, 255, "%.*s", max_size - rec->vendor_idx,
-		 rec->strings + rec->vendor_idx);
-	snprintf(part, 255, "%.*s", max_size - rec->part_number_idx,
-		 rec->strings + rec->part_number_idx);
-
-	if (lb_part) {
-		printf("Overwritten by command line, vendor ID: %s, part ID: %s.\n", lb_vendor, lb_part);
-	} else {
-		partvendor_from_cbtable = 1;
-		lb_part = strdup(part);
-		lb_vendor = strdup(vendor);
-	}
-}
-
-static struct lb_record *next_record(struct lb_record *rec)
-{
-	return (struct lb_record *)(((char *)rec) + rec->size);
-}
-
-static void search_lb_records(struct lb_record *rec, struct lb_record *last,
-			      unsigned long addr)
-{
-	struct lb_record *next;
-	int count;
-	count = 0;
-
-	for (next = next_record(rec); (rec < last) && (next <= last);
-	     rec = next, addr += rec->size) {
-		next = next_record(rec);
-		count++;
-		if (rec->tag == LB_TAG_MAINBOARD) {
-			find_mainboard(rec, addr);
-			break;
-		}
-	}
-}
-
-#define BYTES_TO_MAP (1024*1024)
-int coreboot_init(void)
-{
-	uint8_t *table_area;
-	unsigned long addr, start;
-	struct lb_header *lb_table;
-	struct lb_record *rec, *last;
-
-#ifdef __DARWIN__
-	/* This is a hack. DirectIO fails to map physical address 0x00000000.
-	 * Why?
-	 */
-	start = 0x400;
-#else
-	start = 0x0;
-#endif
-	table_area = physmap("low megabyte", start, BYTES_TO_MAP);
-
-	lb_table = find_lb_table(table_area, 0x00000, 0x1000);
-	if (!lb_table)
-		lb_table = find_lb_table(table_area, 0xf0000, BYTES_TO_MAP);
-	if (lb_table) {
-		struct lb_forward *forward = (struct lb_forward *)
-			(((char *)lb_table) + lb_table->header_bytes);
-		if (forward->tag == LB_TAG_FORWARD) {
-			start = forward->forward;
-			start &= ~(getpagesize() - 1);
-			physunmap(table_area, BYTES_TO_MAP);
-			table_area = physmap("high tables", start, BYTES_TO_MAP);
-			lb_table = find_lb_table(table_area, 0x00000, 0x1000);
-		}
-	}
-
-	if (!lb_table) {
-		printf("No coreboot table found.\n");
-		return -1;
-	}
-
-	addr = ((char *)lb_table) - ((char *)table_area) + start;
-	fprintf(stdout, "coreboot table found at 0x%lx.\n", 
-		(unsigned long)lb_table - (unsigned long)table_area + start);
-	rec = (struct lb_record *)(((char *)lb_table) + lb_table->header_bytes);
-	last = (struct lb_record *)(((char *)rec) + lb_table->table_bytes);
-	printf_debug("coreboot header(%d) checksum: %04x table(%d) checksum: %04x entries: %d\n",
-	     lb_table->header_bytes, lb_table->header_checksum,
-	     lb_table->table_bytes, lb_table->table_checksum,
-	     lb_table->table_entries);
-	search_lb_records(rec, last, addr + lb_table->header_bytes);
-
-	return 0;
-}
diff --git a/chipset_enable.c b/chipset_enable.c
deleted file mode 100644
index 3bdd7d0..0000000
--- a/chipset_enable.c
+++ /dev/null
@@ -1,1202 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- * Copyright (C) 2005-2009 coresystems GmbH
- * Copyright (C) 2006 Uwe Hermann <uwe@hermann-uwe.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; version 2 of the License.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/*
- * Contains the chipset specific flash enables.
- */
-
-#define _LARGEFILE64_SOURCE
-
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include "flash.h"
-
-unsigned long flashbase = 0;
-
-/**
- * flashrom defaults to Parallel/LPC/FWH flash devices. If a known host
- * controller is found, the init routine sets the buses_supported bitfield to
- * contain the supported buses for that controller.
- */
-
-enum chipbustype buses_supported = CHIP_BUSTYPE_NONSPI;
-
-/**
- * Programmers supporting multiple buses can have differing size limits on
- * each bus. Store the limits for each bus in a common struct.
- */
-struct decode_sizes max_rom_decode = {
-	.parallel	= 0xffffffff,
-	.lpc		= 0xffffffff,
-	.fwh		= 0xffffffff,
-	.spi		= 0xffffffff
-};
-
-extern int ichspi_lock;
-
-static int enable_flash_ali_m1533(struct pci_dev *dev, const char *name)
-{
-	uint8_t tmp;
-
-	/*
-	 * ROM Write enable, 0xFFFC0000-0xFFFDFFFF and
-	 * 0xFFFE0000-0xFFFFFFFF ROM select enable.
-	 */
-	tmp = pci_read_byte(dev, 0x47);
-	tmp |= 0x46;
-	pci_write_byte(dev, 0x47, tmp);
-
-	return 0;
-}
-
-static int enable_flash_sis85c496(struct pci_dev *dev, const char *name)
-{
-	uint8_t tmp;
-
-	tmp = pci_read_byte(dev, 0xd0);
-	tmp |= 0xf8;
-	pci_write_byte(dev, 0xd0, tmp);
-
-	return 0;
-}
-
-static int enable_flash_sis_mapping(struct pci_dev *dev, const char *name)
-{
-	uint8_t new, newer;
-
-	/* Extended BIOS enable = 1, Lower BIOS Enable = 1 */
-	/* This is 0xFFF8000~0xFFFF0000 decoding on SiS 540/630. */
-	new = pci_read_byte(dev, 0x40);
-	new &= (~0x04); /* No idea why we clear bit 2. */
-	new |= 0xb; /* 0x3 for some chipsets, bit 7 seems to be don't care. */
-	pci_write_byte(dev, 0x40, new);
-	newer = pci_read_byte(dev, 0x40);
-	if (newer != new) {
-		printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x40, new, name);
-		printf_debug("Stuck at 0x%x\n", newer);
-		return -1;
-	}
-	return 0;
-}
-
-static struct pci_dev *find_southbridge(uint16_t vendor, const char *name)
-{
-	struct pci_dev *sbdev;
-	
-	sbdev = pci_dev_find_vendorclass(vendor, 0x0601);
-	if (!sbdev)
-		sbdev = pci_dev_find_vendorclass(vendor, 0x0680);
-	if (!sbdev)
-		sbdev = pci_dev_find_vendorclass(vendor, 0x0000);
-	if (!sbdev)
-		fprintf(stderr, "No southbridge found for %s!\n", name);
-	if (sbdev)
-		printf_debug("Found southbridge %04x:%04x at %02x:%02x:%01x\n",
-			     sbdev->vendor_id, sbdev->device_id,
-			     sbdev->bus, sbdev->dev, sbdev->func);
-	return sbdev;
-}
-
-static int enable_flash_sis501(struct pci_dev *dev, const char *name)
-{
-	uint8_t tmp;
-	int ret = 0;
-	struct pci_dev *sbdev;
-
-	sbdev = find_southbridge(dev->vendor_id, name);
-	if (!sbdev)
-		return -1;
-
-	ret = enable_flash_sis_mapping(sbdev, name);
-
-	tmp = sio_read(0x22, 0x80);
-	tmp &= (~0x20);
-	tmp |= 0x4;
-	sio_write(0x22, 0x80, tmp);
-
-	tmp = sio_read(0x22, 0x70);
-	tmp &= (~0x20);
-	tmp |= 0x4;
-	sio_write(0x22, 0x70, tmp);
-	
-	return ret;
-}
-
-static int enable_flash_sis5511(struct pci_dev *dev, const char *name)
-{
-	uint8_t tmp;
-	int ret = 0;
-	struct pci_dev *sbdev;
-
-	sbdev = find_southbridge(dev->vendor_id, name);
-	if (!sbdev)
-		return -1;
-
-	ret = enable_flash_sis_mapping(sbdev, name);
-
-	tmp = sio_read(0x22, 0x50);
-	tmp &= (~0x20);
-	tmp |= 0x4;
-	sio_write(0x22, 0x50, tmp);
-
-	return ret;
-}
-
-static int enable_flash_sis5596(struct pci_dev *dev, const char *name)
-{
-	int ret;
-
-	ret = enable_flash_sis5511(dev, name);
-
-	/* FIXME: Needs same superio handling as enable_flash_sis630 */
-	return ret;
-}
-
-static int enable_flash_sis530(struct pci_dev *dev, const char *name)
-{
-	uint8_t new, newer;
-	int ret = 0;
-	struct pci_dev *sbdev;
-
-	sbdev = find_southbridge(dev->vendor_id, name);
-	if (!sbdev)
-		return -1;
-
-	ret = enable_flash_sis_mapping(sbdev, name);
-
-	new = pci_read_byte(sbdev, 0x45);
-	new &= (~0x20);
-	new |= 0x4;
-	pci_write_byte(sbdev, 0x45, new);
-	newer = pci_read_byte(dev, 0x45);
-	if (newer != new) {
-		printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x45, new, name);
-		printf_debug("Stuck at 0x%x\n", newer);
-		ret = -1;
-	}
-
-	return ret;
-}
-
-static int enable_flash_sis540(struct pci_dev *dev, const char *name)
-{
-	uint8_t new, newer;
-	int ret = 0;
-	struct pci_dev *sbdev;
-
-	sbdev = find_southbridge(dev->vendor_id, name);
-	if (!sbdev)
-		return -1;
-
-	ret = enable_flash_sis_mapping(sbdev, name);
-
-	new = pci_read_byte(sbdev, 0x45);
-	new &= (~0x80);
-	new |= 0x40;
-	pci_write_byte(sbdev, 0x45, new);
-	newer = pci_read_byte(dev, 0x45);
-	if (newer != new) {
-		printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x45, new, name);
-		printf_debug("Stuck at 0x%x\n", newer);
-		ret = -1;
-	}
-
-	return ret;
-}
-
-/* Datasheet:
- *   - Name: 82371AB PCI-TO-ISA / IDE XCELERATOR (PIIX4)
- *   - URL: http://www.intel.com/design/intarch/datashts/290562.htm
- *   - PDF: http://www.intel.com/design/intarch/datashts/29056201.pdf
- *   - Order Number: 290562-001
- */
-static int enable_flash_piix4(struct pci_dev *dev, const char *name)
-{
-	uint16_t old, new;
-	uint16_t xbcs = 0x4e;	/* X-Bus Chip Select register. */
-
-	buses_supported = CHIP_BUSTYPE_PARALLEL;
-
-	old = pci_read_word(dev, xbcs);
-
-	/* Set bit 9: 1-Meg Extended BIOS Enable (PCI master accesses to
-	 *            FFF00000-FFF7FFFF are forwarded to ISA).
-	 *            Note: This bit is reserved on PIIX/PIIX3/MPIIX.
-	 * Set bit 7: Extended BIOS Enable (PCI master accesses to
-	 *            FFF80000-FFFDFFFF are forwarded to ISA).
-	 * Set bit 6: Lower BIOS Enable (PCI master, or ISA master accesses to
-	 *            the lower 64-Kbyte BIOS block (E0000-EFFFF) at the top
-	 *            of 1 Mbyte, or the aliases at the top of 4 Gbyte
-	 *            (FFFE0000-FFFEFFFF) result in the generation of BIOSCS#.
-	 * Note: Accesses to FFFF0000-FFFFFFFF are always forwarded to ISA.
-	 * Set bit 2: BIOSCS# Write Enable (1=enable, 0=disable).
-	 */
-	if (dev->device_id == 0x122e || dev->device_id == 0x7000
-	    || dev->device_id == 0x1234)
-		new = old | 0x00c4; /* PIIX/PIIX3/MPIIX: Bit 9 is reserved. */
-	else
-		new = old | 0x02c4;
-
-	if (new == old)
-		return 0;
-
-	pci_write_word(dev, xbcs, new);
-
-	if (pci_read_word(dev, xbcs) != new) {
-		printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", xbcs, new, name);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*
- * See ie. page 375 of "Intel I/O Controller Hub 7 (ICH7) Family Datasheet"
- * http://download.intel.com/design/chipsets/datashts/30701303.pdf
- */
-static int enable_flash_ich(struct pci_dev *dev, const char *name,
-			    int bios_cntl)
-{
-	uint8_t old, new;
-
-	/*
-	 * Note: the ICH0-ICH5 BIOS_CNTL register is actually 16 bit wide, but
-	 * just treating it as 8 bit wide seems to work fine in practice.
-	 */
-	old = pci_read_byte(dev, bios_cntl);
-
-	printf_debug("\nBIOS Lock Enable: %sabled, ",
-		     (old & (1 << 1)) ? "en" : "dis");
-	printf_debug("BIOS Write Enable: %sabled, ",
-		     (old & (1 << 0)) ? "en" : "dis");
-	printf_debug("BIOS_CNTL is 0x%x\n", old);
-
-	new = old | 1;
-
-	if (new == old)
-		return 0;
-
-	pci_write_byte(dev, bios_cntl, new);
-
-	if (pci_read_byte(dev, bios_cntl) != new) {
-		printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", bios_cntl, new, name);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int enable_flash_ich_4e(struct pci_dev *dev, const char *name)
-{
-	/*
-	 * Note: ICH5 has registers similar to FWH_SEL1, FWH_SEL2 and
-	 * FWH_DEC_EN1, but they are called FB_SEL1, FB_SEL2, FB_DEC_EN1 and
-	 * FB_DEC_EN2.
-	 */
-	return enable_flash_ich(dev, name, 0x4e);
-}
-
-static int enable_flash_ich_dc(struct pci_dev *dev, const char *name)
-{
-	uint32_t fwh_conf;
-	int i;
-	char *idsel = NULL;
-
-	/* Ignore all legacy ranges below 1 MB. */
-	/* FWH_SEL1 */
-	fwh_conf = pci_read_long(dev, 0xd0);
-	for (i = 7; i >= 0; i--)
-		printf_debug("\n0x%08x/0x%08x FWH IDSEL: 0x%x",
-			     (0x1ff8 + i) * 0x80000,
-			     (0x1ff0 + i) * 0x80000,
-			     (fwh_conf >> (i * 4)) & 0xf);
-	/* FWH_SEL2 */
-	fwh_conf = pci_read_word(dev, 0xd4);
-	for (i = 3; i >= 0; i--)
-		printf_debug("\n0x%08x/0x%08x FWH IDSEL: 0x%x",
-			     (0xff4 + i) * 0x100000,
-			     (0xff0 + i) * 0x100000,
-			     (fwh_conf >> (i * 4)) & 0xf);
-	/* FWH_DEC_EN1 */
-	fwh_conf = pci_read_word(dev, 0xd8);
-	for (i = 7; i >= 0; i--)
-		printf_debug("\n0x%08x/0x%08x FWH decode %sabled",
-			     (0x1ff8 + i) * 0x80000,
-			     (0x1ff0 + i) * 0x80000,
-			     (fwh_conf >> (i + 0x8)) & 0x1 ? "en" : "dis");
-	for (i = 3; i >= 0; i--)
-		printf_debug("\n0x%08x/0x%08x FWH decode %sabled",
-			     (0xff4 + i) * 0x100000,
-			     (0xff0 + i) * 0x100000,
-			     (fwh_conf >> i) & 0x1 ? "en" : "dis");
-
-	if (programmer_param)
-		idsel = strstr(programmer_param, "fwh_idsel=");
-
-	if (idsel) {
-		idsel += strlen("fwh_idsel=");
-		fwh_conf = (uint32_t)strtoul(idsel, NULL, 0);
-
-		/* FIXME: Need to undo this on shutdown. */
-		printf("\nSetting IDSEL=0x%x for top 16 MB", fwh_conf);
-		pci_write_long(dev, 0xd0, fwh_conf);
-		pci_write_word(dev, 0xd4, fwh_conf);
-	}
-
-	return enable_flash_ich(dev, name, 0xdc);
-}
-
-#define ICH_STRAP_RSVD 0x00
-#define ICH_STRAP_SPI  0x01
-#define ICH_STRAP_PCI  0x02
-#define ICH_STRAP_LPC  0x03
-
-static int enable_flash_vt8237s_spi(struct pci_dev *dev, const char *name)
-{
-	uint32_t mmio_base;
-
-	mmio_base = (pci_read_long(dev, 0xbc)) << 8;
-	printf_debug("MMIO base at = 0x%x\n", mmio_base);
-	spibar = physmap("VT8237S MMIO registers", mmio_base, 0x70);
-
-	printf_debug("0x6c: 0x%04x     (CLOCK/DEBUG)\n",
-		     mmio_readw(spibar + 0x6c));
-
-	/* Not sure if it speaks all these bus protocols. */
-	buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI;
-	spi_controller = SPI_CONTROLLER_VIA;
-	ich_init_opcodes();
-
-	return 0;
-}
-
-static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name,
-				   int ich_generation)
-{
-	int ret, i;
-	uint8_t old, new, bbs, buc;
-	uint16_t spibar_offset, tmp2;
-	uint32_t tmp, gcs;
-	void *rcrb;
-	//TODO: These names are incorrect for EP80579. For that, the solution would look like the commented line
-	//static const char *straps_names[] = {"SPI", "reserved", "reserved", "LPC" };
-	static const char *straps_names[] = { "reserved", "SPI", "PCI", "LPC" };
-
-	/* Enable Flash Writes */
-	ret = enable_flash_ich_dc(dev, name);
-
-	/* Get physical address of Root Complex Register Block */
-	tmp = pci_read_long(dev, 0xf0) & 0xffffc000;
-	printf_debug("\nRoot Complex Register Block address = 0x%x\n", tmp);
-
-	/* Map RCBA to virtual memory */
-	rcrb = physmap("ICH RCRB", tmp, 0x4000);
-
-	gcs = mmio_readl(rcrb + 0x3410);
-	printf_debug("GCS = 0x%x: ", gcs);
-	printf_debug("BIOS Interface Lock-Down: %sabled, ",
-		     (gcs & 0x1) ? "en" : "dis");
-	bbs = (gcs >> 10) & 0x3;
-	printf_debug("BOOT BIOS Straps: 0x%x (%s)\n", bbs, straps_names[bbs]);
-
-	buc = mmio_readb(rcrb + 0x3414);
-	printf_debug("Top Swap : %s\n",
-		     (buc & 1) ? "enabled (A16 inverted)" : "not enabled");
-
-	/* It seems the ICH7 does not support SPI and LPC chips at the same
-	 * time. At least not with our current code. So we prevent searching
-	 * on ICH7 when the southbridge is strapped to LPC
-	 */
-
-	if (ich_generation == 7 && bbs == ICH_STRAP_LPC) {
-		/* Not sure if it speaks LPC as well. */
-		buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH;
-		/* No further SPI initialization required */
-		return ret;
-	}
-
-	switch (ich_generation) {
-	case 7:
-		buses_supported = CHIP_BUSTYPE_SPI;
-		spi_controller = SPI_CONTROLLER_ICH7;
-		spibar_offset = 0x3020;
-		break;
-	case 8:
-		/* Not sure if it speaks LPC as well. */
-		buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI;
-		spi_controller = SPI_CONTROLLER_ICH9;
-		spibar_offset = 0x3020;
-		break;
-	case 9:
-	case 10:
-	default:		/* Future version might behave the same */
-		/* Not sure if it speaks LPC as well. */
-		buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI;
-		spi_controller = SPI_CONTROLLER_ICH9;
-		spibar_offset = 0x3800;
-		break;
-	}
-
-	/* SPIBAR is at RCRB+0x3020 for ICH[78] and RCRB+0x3800 for ICH9. */
-	printf_debug("SPIBAR = 0x%x + 0x%04x\n", tmp, spibar_offset);
-
-	/* Assign Virtual Address */
-	spibar = rcrb + spibar_offset;
-
-	switch (spi_controller) {
-	case SPI_CONTROLLER_ICH7:
-		printf_debug("0x00: 0x%04x     (SPIS)\n",
-			     mmio_readw(spibar + 0));
-		printf_debug("0x02: 0x%04x     (SPIC)\n",
-			     mmio_readw(spibar + 2));
-		printf_debug("0x04: 0x%08x (SPIA)\n",
-			     mmio_readl(spibar + 4));
-		for (i = 0; i < 8; i++) {
-			int offs;
-			offs = 8 + (i * 8);
-			printf_debug("0x%02x: 0x%08x (SPID%d)\n", offs,
-				     mmio_readl(spibar + offs), i);
-			printf_debug("0x%02x: 0x%08x (SPID%d+4)\n", offs + 4,
-				     mmio_readl(spibar + offs + 4), i);
-		}
-		printf_debug("0x50: 0x%08x (BBAR)\n",
-			     mmio_readl(spibar + 0x50));
-		printf_debug("0x54: 0x%04x     (PREOP)\n",
-			     mmio_readw(spibar + 0x54));
-		printf_debug("0x56: 0x%04x     (OPTYPE)\n",
-			     mmio_readw(spibar + 0x56));
-		printf_debug("0x58: 0x%08x (OPMENU)\n",
-			     mmio_readl(spibar + 0x58));
-		printf_debug("0x5c: 0x%08x (OPMENU+4)\n",
-			     mmio_readl(spibar + 0x5c));
-		for (i = 0; i < 4; i++) {
-			int offs;
-			offs = 0x60 + (i * 4);
-			printf_debug("0x%02x: 0x%08x (PBR%d)\n", offs,
-				     mmio_readl(spibar + offs), i);
-		}
-		printf_debug("\n");
-		if (mmio_readw(spibar) & (1 << 15)) {
-			printf("WARNING: SPI Configuration Lockdown activated.\n");
-			ichspi_lock = 1;
-		}
-		ich_init_opcodes();
-		break;
-	case SPI_CONTROLLER_ICH9:
-		tmp2 = mmio_readw(spibar + 4);
-		printf_debug("0x04: 0x%04x (HSFS)\n", tmp2);
-		printf_debug("FLOCKDN %i, ", (tmp2 >> 15 & 1));
-		printf_debug("FDV %i, ", (tmp2 >> 14) & 1);
-		printf_debug("FDOPSS %i, ", (tmp2 >> 13) & 1);
-		printf_debug("SCIP %i, ", (tmp2 >> 5) & 1);
-		printf_debug("BERASE %i, ", (tmp2 >> 3) & 3);
-		printf_debug("AEL %i, ", (tmp2 >> 2) & 1);
-		printf_debug("FCERR %i, ", (tmp2 >> 1) & 1);
-		printf_debug("FDONE %i\n", (tmp2 >> 0) & 1);
-
-		tmp = mmio_readl(spibar + 0x50);
-		printf_debug("0x50: 0x%08x (FRAP)\n", tmp);
-		printf_debug("BMWAG %i, ", (tmp >> 24) & 0xff);
-		printf_debug("BMRAG %i, ", (tmp >> 16) & 0xff);
-		printf_debug("BRWA %i, ", (tmp >> 8) & 0xff);
-		printf_debug("BRRA %i\n", (tmp >> 0) & 0xff);
-
-		printf_debug("0x54: 0x%08x (FREG0)\n",
-			     mmio_readl(spibar + 0x54));
-		printf_debug("0x58: 0x%08x (FREG1)\n",
-			     mmio_readl(spibar + 0x58));
-		printf_debug("0x5C: 0x%08x (FREG2)\n",
-			     mmio_readl(spibar + 0x5C));
-		printf_debug("0x60: 0x%08x (FREG3)\n",
-			     mmio_readl(spibar + 0x60));
-		printf_debug("0x64: 0x%08x (FREG4)\n",
-			     mmio_readl(spibar + 0x64));
-		printf_debug("0x74: 0x%08x (PR0)\n",
-			     mmio_readl(spibar + 0x74));
-		printf_debug("0x78: 0x%08x (PR1)\n",
-			     mmio_readl(spibar + 0x78));
-		printf_debug("0x7C: 0x%08x (PR2)\n",
-			     mmio_readl(spibar + 0x7C));
-		printf_debug("0x80: 0x%08x (PR3)\n",
-			     mmio_readl(spibar + 0x80));
-		printf_debug("0x84: 0x%08x (PR4)\n",
-			     mmio_readl(spibar + 0x84));
-		printf_debug("0x90: 0x%08x (SSFS, SSFC)\n",
-			     mmio_readl(spibar + 0x90));
-		printf_debug("0x94: 0x%04x     (PREOP)\n",
-			     mmio_readw(spibar + 0x94));
-		printf_debug("0x96: 0x%04x     (OPTYPE)\n",
-			     mmio_readw(spibar + 0x96));
-		printf_debug("0x98: 0x%08x (OPMENU)\n",
-			     mmio_readl(spibar + 0x98));
-		printf_debug("0x9C: 0x%08x (OPMENU+4)\n",
-			     mmio_readl(spibar + 0x9C));
-		printf_debug("0xA0: 0x%08x (BBAR)\n",
-			     mmio_readl(spibar + 0xA0));
-		printf_debug("0xB0: 0x%08x (FDOC)\n",
-			     mmio_readl(spibar + 0xB0));
-		if (tmp2 & (1 << 15)) {
-			printf("WARNING: SPI Configuration Lockdown activated.\n");
-			ichspi_lock = 1;
-		}
-		ich_init_opcodes();
-		break;
-	default:
-		/* Nothing */
-		break;
-	}
-
-	old = pci_read_byte(dev, 0xdc);
-	printf_debug("SPI Read Configuration: ");
-	new = (old >> 2) & 0x3;
-	switch (new) {
-	case 0:
-	case 1:
-	case 2:
-		printf_debug("prefetching %sabled, caching %sabled, ",
-			     (new & 0x2) ? "en" : "dis",
-			     (new & 0x1) ? "dis" : "en");
-		break;
-	default:
-		printf_debug("invalid prefetching/caching settings, ");
-		break;
-	}
-
-	return ret;
-}
-
-static int enable_flash_ich7(struct pci_dev *dev, const char *name)
-{
-	return enable_flash_ich_dc_spi(dev, name, 7);
-}
-
-static int enable_flash_ich8(struct pci_dev *dev, const char *name)
-{
-	return enable_flash_ich_dc_spi(dev, name, 8);
-}
-
-static int enable_flash_ich9(struct pci_dev *dev, const char *name)
-{
-	return enable_flash_ich_dc_spi(dev, name, 9);
-}
-
-static int enable_flash_ich10(struct pci_dev *dev, const char *name)
-{
-	return enable_flash_ich_dc_spi(dev, name, 10);
-}
-
-static int enable_flash_vt823x(struct pci_dev *dev, const char *name)
-{
-	uint8_t val;
-
-	/* enable ROM decode range (1MB) FFC00000 - FFFFFFFF */
-	pci_write_byte(dev, 0x41, 0x7f);
-
-	/* ROM write enable */
-	val = pci_read_byte(dev, 0x40);
-	val |= 0x10;
-	pci_write_byte(dev, 0x40, val);
-
-	if (pci_read_byte(dev, 0x40) != val) {
-		printf("\nWARNING: Failed to enable flash write on \"%s\"\n",
-		       name);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int enable_flash_cs5530(struct pci_dev *dev, const char *name)
-{
-	uint8_t reg8;
-
-#define DECODE_CONTROL_REG2		0x5b	/* F0 index 0x5b */
-#define ROM_AT_LOGIC_CONTROL_REG	0x52	/* F0 index 0x52 */
-
-#define LOWER_ROM_ADDRESS_RANGE		(1 << 0)
-#define ROM_WRITE_ENABLE		(1 << 1)
-#define UPPER_ROM_ADDRESS_RANGE		(1 << 2)
-#define BIOS_ROM_POSITIVE_DECODE	(1 << 5)
-
-	/* Decode 0x000E0000-0x000FFFFF (128 KB), not just 64 KB, and
-	 * decode 0xFF000000-0xFFFFFFFF (16 MB), not just 256 KB.
-	 * Make the configured ROM areas writable.
-	 */
-	reg8 = pci_read_byte(dev, ROM_AT_LOGIC_CONTROL_REG);
-	reg8 |= LOWER_ROM_ADDRESS_RANGE;
-	reg8 |= UPPER_ROM_ADDRESS_RANGE;
-	reg8 |= ROM_WRITE_ENABLE;
-	pci_write_byte(dev, ROM_AT_LOGIC_CONTROL_REG, reg8);
-
-	/* Set positive decode on ROM. */
-	reg8 = pci_read_byte(dev, DECODE_CONTROL_REG2);
-	reg8 |= BIOS_ROM_POSITIVE_DECODE;
-	pci_write_byte(dev, DECODE_CONTROL_REG2, reg8);
-
-	return 0;
-}
-
-/**
- * Geode systems write protect the BIOS via RCONFs (cache settings similar
- * to MTRRs). To unlock, change MSR 0x1808 top byte to 0x22. 
- *
- * Geode systems also write protect the NOR flash chip itself via MSR_NORF_CTL.
- * To enable write to NOR Boot flash for the benefit of systems that have such
- * a setup, raise MSR 0x51400018 WE_CS3 (write enable Boot Flash Chip Select).
- */
-static int enable_flash_cs5536(struct pci_dev *dev, const char *name)
-{
-#define MSR_RCONF_DEFAULT	0x1808
-#define MSR_NORF_CTL		0x51400018
-
-	msr_t msr;
-
-	/* Geode only has a single core */
-	if (setup_cpu_msr(0))
-		return -1;
-
-	msr = rdmsr(MSR_RCONF_DEFAULT);
-	if ((msr.hi >> 24) != 0x22) {
-		msr.hi &= 0xfbffffff;
-		wrmsr(MSR_RCONF_DEFAULT, msr);
-	}
-
-	msr = rdmsr(MSR_NORF_CTL);
-	/* Raise WE_CS3 bit. */
-	msr.lo |= 0x08;
-	wrmsr(MSR_NORF_CTL, msr);
-
-	cleanup_cpu_msr();
-
-#undef MSR_RCONF_DEFAULT
-#undef MSR_NORF_CTL
-	return 0;
-}
-
-static int enable_flash_sc1100(struct pci_dev *dev, const char *name)
-{
-	uint8_t new;
-
-	pci_write_byte(dev, 0x52, 0xee);
-
-	new = pci_read_byte(dev, 0x52);
-
-	if (new != 0xee) {
-		printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x52, new, name);
-		return -1;
-	}
-
-	return 0;
-}
-
-/* Works for AMD-8111, VIA VT82C586A/B, VIA VT82C686A/B. */
-static int enable_flash_amd8111(struct pci_dev *dev, const char *name)
-{
-	uint8_t old, new;
-
-	/* Enable decoding at 0xffb00000 to 0xffffffff. */
-	old = pci_read_byte(dev, 0x43);
-	new = old | 0xC0;
-	if (new != old) {
-		pci_write_byte(dev, 0x43, new);
-		if (pci_read_byte(dev, 0x43) != new) {
-			printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x43, new, name);
-		}
-	}
-
-	/* Enable 'ROM write' bit. */
-	old = pci_read_byte(dev, 0x40);
-	new = old | 0x01;
-	if (new == old)
-		return 0;
-	pci_write_byte(dev, 0x40, new);
-
-	if (pci_read_byte(dev, 0x40) != new) {
-		printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x40, new, name);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int enable_flash_sb600(struct pci_dev *dev, const char *name)
-{
-	uint32_t tmp, prot;
-	uint8_t reg;
-	struct pci_dev *smbus_dev;
-	int has_spi = 1;
-
-	/* Clear ROM protect 0-3. */
-	for (reg = 0x50; reg < 0x60; reg += 4) {
-		prot = pci_read_long(dev, reg);
-		/* No protection flags for this region?*/
-		if ((prot & 0x3) == 0)
-			continue;
-		printf_debug("SB600 %s%sprotected from %u to %u\n",
-			(prot & 0x1) ? "write " : "",
-			(prot & 0x2) ? "read " : "",
-			(prot & 0xfffffc00),
-			(prot & 0xfffffc00) + ((prot & 0x3ff) << 8));
-		prot &= 0xfffffffc;
-		pci_write_byte(dev, reg, prot);
-		prot = pci_read_long(dev, reg);
-		if (prot & 0x3)
-			printf("SB600 %s%sunprotect failed from %u to %u\n",
-				(prot & 0x1) ? "write " : "",
-				(prot & 0x2) ? "read " : "",
-				(prot & 0xfffffc00),
-				(prot & 0xfffffc00) + ((prot & 0x3ff) << 8));
-	}
-
-	/* Read SPI_BaseAddr */
-	tmp = pci_read_long(dev, 0xa0);
-	tmp &= 0xffffffe0;	/* remove bits 4-0 (reserved) */
-	printf_debug("SPI base address is at 0x%x\n", tmp);
-
-	/* If the BAR has address 0, it is unlikely SPI is used. */
-	if (!tmp)
-		has_spi = 0;
-
-	if (has_spi) {
-		/* Physical memory has to be mapped at page (4k) boundaries. */
-		sb600_spibar = physmap("SB600 SPI registers", tmp & 0xfffff000,
-				       0x1000);
-		/* The low bits of the SPI base address are used as offset into
-		 * the mapped page.
-		 */
-		sb600_spibar += tmp & 0xfff;
-
-		tmp = pci_read_long(dev, 0xa0);
-		printf_debug("AltSpiCSEnable=%i, SpiRomEnable=%i, "
-			     "AbortEnable=%i\n", tmp & 0x1, (tmp & 0x2) >> 1,
-			     (tmp & 0x4) >> 2);
-		tmp = (pci_read_byte(dev, 0xba) & 0x4) >> 2;
-		printf_debug("PrefetchEnSPIFromIMC=%i, ", tmp);
-
-		tmp = pci_read_byte(dev, 0xbb);
-		printf_debug("PrefetchEnSPIFromHost=%i, SpiOpEnInLpcMode=%i\n",
-			     tmp & 0x1, (tmp & 0x20) >> 5);
-		tmp = mmio_readl(sb600_spibar);
-		printf_debug("SpiArbEnable=%i, SpiAccessMacRomEn=%i, "
-			     "SpiHostAccessRomEn=%i, ArbWaitCount=%i, "
-			     "SpiBridgeDisable=%i, DropOneClkOnRd=%i\n",
-			     (tmp >> 19) & 0x1, (tmp >> 22) & 0x1,
-			     (tmp >> 23) & 0x1, (tmp >> 24) & 0x7,
-			     (tmp >> 27) & 0x1, (tmp >> 28) & 0x1);
-	}
-
-	/* Look for the SMBus device. */
-	smbus_dev = pci_dev_find(0x1002, 0x4385);
-
-	if (has_spi && !smbus_dev) {
-		fprintf(stderr, "ERROR: SMBus device not found. Not enabling SPI.\n");
-		has_spi = 0;
-	}
-	if (has_spi) {
-		/* Note about the bit tests below: If a bit is zero, the GPIO is SPI. */
-		/* GPIO11/SPI_DO and GPIO12/SPI_DI status */
-		reg = pci_read_byte(smbus_dev, 0xAB);
-		reg &= 0xC0;
-		printf_debug("GPIO11 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_DO");
-		printf_debug("GPIO12 used for %s\n", (reg & (1 << 7)) ? "GPIO" : "SPI_DI");
-		if (reg != 0x00)
-			has_spi = 0;
-		/* GPIO31/SPI_HOLD and GPIO32/SPI_CS status */
-		reg = pci_read_byte(smbus_dev, 0x83);
-		reg &= 0xC0;
-		printf_debug("GPIO31 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_HOLD");
-		printf_debug("GPIO32 used for %s\n", (reg & (1 << 7)) ? "GPIO" : "SPI_CS");
-		/* SPI_HOLD is not used on all boards, filter it out. */
-		if ((reg & 0x80) != 0x00)
-			has_spi = 0;
-		/* GPIO47/SPI_CLK status */
-		reg = pci_read_byte(smbus_dev, 0xA7);
-		reg &= 0x40;
-		printf_debug("GPIO47 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_CLK");
-		if (reg != 0x00)
-			has_spi = 0;
-	}
-
-	buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH;
-	if (has_spi) {
-		buses_supported |= CHIP_BUSTYPE_SPI;
-		spi_controller = SPI_CONTROLLER_SB600;
-	}
-
-	/* Read ROM strap override register. */
-	OUTB(0x8f, 0xcd6);
-	reg = INB(0xcd7);
-	reg &= 0x0e;
-	printf_debug("ROM strap override is %sactive", (reg & 0x02) ? "" : "not ");
-	if (reg & 0x02) {
-		switch ((reg & 0x0c) >> 2) {
-		case 0x00:
-			printf_debug(": LPC");
-			break;
-		case 0x01:
-			printf_debug(": PCI");
-			break;
-		case 0x02:
-			printf_debug(": FWH");
-			break;
-		case 0x03:
-			printf_debug(": SPI");
-			break;
-		}
-	}
-	printf_debug("\n");
-
-	/* Force enable SPI ROM in SB600 PM register.
-	 * If we enable SPI ROM here, we have to disable it after we leave.
-	 * But how can we know which ROM we are going to handle? So we have
-	 * to trade off. We only access LPC ROM if we boot via LPC ROM. And
-	 * only SPI ROM if we boot via SPI ROM. If you want to access SPI on
-	 * boards with LPC straps, you have to use the code below.
-	 */
-	/*
-	OUTB(0x8f, 0xcd6);
-	OUTB(0x0e, 0xcd7);
-	*/
-
-	return 0;
-}
-
-static int enable_flash_nvidia_nforce2(struct pci_dev *dev, const char *name)
-{
-	uint8_t tmp;
-
-	pci_write_byte(dev, 0x92, 0);
-
-	tmp = pci_read_byte(dev, 0x6d);
-	tmp |= 0x01;
-	pci_write_byte(dev, 0x6d, tmp);
-
-	return 0;
-}
-
-static int enable_flash_ck804(struct pci_dev *dev, const char *name)
-{
-	uint8_t old, new;
-
-	old = pci_read_byte(dev, 0x88);
-	new = old | 0xc0;
-	if (new != old) {
-		pci_write_byte(dev, 0x88, new);
-		if (pci_read_byte(dev, 0x88) != new) {
-			printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x88, new, name);
-		}
-	}
-
-	old = pci_read_byte(dev, 0x6d);
-	new = old | 0x01;
-	if (new == old)
-		return 0;
-	pci_write_byte(dev, 0x6d, new);
-
-	if (pci_read_byte(dev, 0x6d) != new) {
-		printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x6d, new, name);
-		return -1;
-	}
-
-	return 0;
-}
-
-/* ATI Technologies Inc IXP SB400 PCI-ISA Bridge (rev 80) */
-static int enable_flash_sb400(struct pci_dev *dev, const char *name)
-{
-	uint8_t tmp;
-	struct pci_dev *smbusdev;
-
-	/* Look for the SMBus device. */
-	smbusdev = pci_dev_find(0x1002, 0x4372);
-
-	if (!smbusdev) {
-		fprintf(stderr, "ERROR: SMBus device not found. Aborting.\n");
-		exit(1);
-	}
-
-	/* Enable some SMBus stuff. */
-	tmp = pci_read_byte(smbusdev, 0x79);
-	tmp |= 0x01;
-	pci_write_byte(smbusdev, 0x79, tmp);
-
-	/* Change southbridge. */
-	tmp = pci_read_byte(dev, 0x48);
-	tmp |= 0x21;
-	pci_write_byte(dev, 0x48, tmp);
-
-	/* Now become a bit silly. */
-	tmp = INB(0xc6f);
-	OUTB(tmp, 0xeb);
-	OUTB(tmp, 0xeb);
-	tmp |= 0x40;
-	OUTB(tmp, 0xc6f);
-	OUTB(tmp, 0xeb);
-	OUTB(tmp, 0xeb);
-
-	return 0;
-}
-
-static int enable_flash_mcp55(struct pci_dev *dev, const char *name)
-{
-	uint8_t old, new, byte;
-	uint16_t word;
-
-	/* Set the 0-16 MB enable bits. */
-	byte = pci_read_byte(dev, 0x88);
-	byte |= 0xff;		/* 256K */
-	pci_write_byte(dev, 0x88, byte);
-	byte = pci_read_byte(dev, 0x8c);
-	byte |= 0xff;		/* 1M */
-	pci_write_byte(dev, 0x8c, byte);
-	word = pci_read_word(dev, 0x90);
-	word |= 0x7fff;		/* 16M */
-	pci_write_word(dev, 0x90, word);
-
-	old = pci_read_byte(dev, 0x6d);
-	new = old | 0x01;
-	if (new == old)
-		return 0;
-	pci_write_byte(dev, 0x6d, new);
-
-	if (pci_read_byte(dev, 0x6d) != new) {
-		printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x6d, new, name);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int enable_flash_ht1000(struct pci_dev *dev, const char *name)
-{
-	uint8_t byte;
-
-	/* Set the 4MB enable bit. */
-	byte = pci_read_byte(dev, 0x41);
-	byte |= 0x0e;
-	pci_write_byte(dev, 0x41, byte);
-
-	byte = pci_read_byte(dev, 0x43);
-	byte |= (1 << 4);
-	pci_write_byte(dev, 0x43, byte);
-
-	return 0;
-}
-
-/**
- * Usually on the x86 architectures (and on other PC-like platforms like some
- * Alphas or Itanium) the system flash is mapped right below 4G. On the AMD
- * Elan SC520 only a small piece of the system flash is mapped there, but the
- * complete flash is mapped somewhere below 1G. The position can be determined
- * by the BOOTCS PAR register.
- */
-static int get_flashbase_sc520(struct pci_dev *dev, const char *name)
-{
-	int i, bootcs_found = 0;
-	uint32_t parx = 0;
-	void *mmcr;
-
-	/* 1. Map MMCR */
-	mmcr = physmap("Elan SC520 MMCR", 0xfffef000, getpagesize());
-
-	/* 2. Scan PAR0 (0x88) - PAR15 (0xc4) for
-	 *    BOOTCS region (PARx[31:29] = 100b)e
-	 */
-	for (i = 0x88; i <= 0xc4; i += 4) {
-		parx = mmio_readl(mmcr + i);
-		if ((parx >> 29) == 4) {
-			bootcs_found = 1;
-			break; /* BOOTCS found */
-		}
-	}
-
-	/* 3. PARx[25] = 1b --> flashbase[29:16] = PARx[13:0]
-	 *    PARx[25] = 0b --> flashbase[29:12] = PARx[17:0]
-	 */
-	if (bootcs_found) {
-		if (parx & (1 << 25)) {
-			parx &= (1 << 14) - 1; /* Mask [13:0] */
-			flashbase = parx << 16;
-		} else {
-			parx &= (1 << 18) - 1; /* Mask [17:0] */
-			flashbase = parx << 12;
-		}
-	} else {
-		printf("AMD Elan SC520 detected, but no BOOTCS. Assuming flash at 4G\n");
-	}
-
-	/* 4. Clean up */
-	physunmap(mmcr, getpagesize());
-	return 0;
-}
-
-/* Please keep this list alphabetically sorted by vendor/device. */
-const struct penable chipset_enables[] = {
-	{0x10B9, 0x1533, OK, "ALi", "M1533",		enable_flash_ali_m1533},
-	{0x1022, 0x7440, OK, "AMD", "AMD-768",		enable_flash_amd8111},
-	{0x1022, 0x7468, OK, "AMD", "AMD8111",		enable_flash_amd8111},
-	{0x1078, 0x0100, OK, "AMD", "CS5530(A)",	enable_flash_cs5530},
-	{0x1022, 0x2080, OK, "AMD", "CS5536",		enable_flash_cs5536},
-	{0x1022, 0x2090, OK, "AMD", "CS5536",		enable_flash_cs5536},
-	{0x1022, 0x3000, OK, "AMD", "Elan SC520",	get_flashbase_sc520},
-	{0x1002, 0x438D, OK, "AMD", "SB600",		enable_flash_sb600},
-	{0x1002, 0x439d, OK, "AMD", "SB700/SB710/SB750", enable_flash_sb600},
-	{0x100b, 0x0510, NT, "AMD", "SC1100",		enable_flash_sc1100},
-	{0x1002, 0x4377, OK, "ATI", "SB400",		enable_flash_sb400},
-	{0x1166, 0x0205, OK, "Broadcom", "HT-1000",	enable_flash_ht1000},
-	{0x8086, 0x3b00, NT, "Intel", "3400 Desktop",	enable_flash_ich10},
-	{0x8086, 0x3b01, NT, "Intel", "3400 Mobile",	enable_flash_ich10},
-	{0x8086, 0x3b0d, NT, "Intel", "3400 Mobile SFF", enable_flash_ich10},
-	{0x8086, 0x7198, OK, "Intel", "440MX",		enable_flash_piix4},
-	{0x8086, 0x25a1, OK, "Intel", "6300ESB",	enable_flash_ich_4e},
-	{0x8086, 0x2670, OK, "Intel", "631xESB/632xESB/3100", enable_flash_ich_dc},
-	{0x8086, 0x5031, OK, "Intel", "EP80579",	enable_flash_ich7},
-	{0x8086, 0x2420, OK, "Intel", "ICH0",		enable_flash_ich_4e},
-	{0x8086, 0x3a18, OK, "Intel", "ICH10",		enable_flash_ich10},
-	{0x8086, 0x3a1a, OK, "Intel", "ICH10D",		enable_flash_ich10},
-	{0x8086, 0x3a14, OK, "Intel", "ICH10DO",	enable_flash_ich10},
-	{0x8086, 0x3a16, OK, "Intel", "ICH10R",		enable_flash_ich10},
-	{0x8086, 0x2440, OK, "Intel", "ICH2",		enable_flash_ich_4e},
-	{0x8086, 0x244c, OK, "Intel", "ICH2-M",		enable_flash_ich_4e},
-	{0x8086, 0x248c, OK, "Intel", "ICH3-M",		enable_flash_ich_4e},
-	{0x8086, 0x2480, OK, "Intel", "ICH3-S",		enable_flash_ich_4e},
-	{0x8086, 0x24c0, OK, "Intel", "ICH4/ICH4-L",	enable_flash_ich_4e},
-	{0x8086, 0x24cc, OK, "Intel", "ICH4-M",		enable_flash_ich_4e},
-	{0x8086, 0x24d0, OK, "Intel", "ICH5/ICH5R",	enable_flash_ich_4e},
-	{0x8086, 0x2640, OK, "Intel", "ICH6/ICH6R",	enable_flash_ich_dc},
-	{0x8086, 0x2641, OK, "Intel", "ICH6-M",		enable_flash_ich_dc},
-	{0x8086, 0x27b0, OK, "Intel", "ICH7DH",		enable_flash_ich7},
-	{0x8086, 0x27b8, OK, "Intel", "ICH7/ICH7R",	enable_flash_ich7},
-	{0x8086, 0x27b9, OK, "Intel", "ICH7M",		enable_flash_ich7},
-	{0x8086, 0x27bd, OK, "Intel", "ICH7MDH",	enable_flash_ich7},
-	{0x8086, 0x2410, OK, "Intel", "ICH",		enable_flash_ich_4e},
-	{0x8086, 0x2812, OK, "Intel", "ICH8DH",		enable_flash_ich8},
-	{0x8086, 0x2814, OK, "Intel", "ICH8DO",		enable_flash_ich8},
-	{0x8086, 0x2810, OK, "Intel", "ICH8/ICH8R",	enable_flash_ich8},
-	{0x8086, 0x2815, OK, "Intel", "ICH8M",		enable_flash_ich8},
-	{0x8086, 0x2811, OK, "Intel", "ICH8M-E",	enable_flash_ich8},
-	{0x8086, 0x2918, OK, "Intel", "ICH9",		enable_flash_ich9},
-	{0x8086, 0x2912, OK, "Intel", "ICH9DH",		enable_flash_ich9},
-	{0x8086, 0x2914, OK, "Intel", "ICH9DO",		enable_flash_ich9},
-	{0x8086, 0x2919, OK, "Intel", "ICH9M",		enable_flash_ich9},
-	{0x8086, 0x2917, OK, "Intel", "ICH9M-E",	enable_flash_ich9},
-	{0x8086, 0x2916, OK, "Intel", "ICH9R",		enable_flash_ich9},
-	{0x8086, 0x2910, OK, "Intel", "ICH9 Engineering Sample", enable_flash_ich9},
-	{0x8086, 0x1234, NT, "Intel", "MPIIX",		enable_flash_piix4},
-	{0x8086, 0x7000, OK, "Intel", "PIIX3",		enable_flash_piix4},
-	{0x8086, 0x7110, OK, "Intel", "PIIX4/4E/4M",	enable_flash_piix4},
-	{0x8086, 0x122e, OK, "Intel", "PIIX",		enable_flash_piix4},
-	{0x10de, 0x0030, OK, "NVIDIA", "nForce4/MCP4",  enable_flash_nvidia_nforce2},
-	{0x10de, 0x0050, OK, "NVIDIA", "CK804",		enable_flash_ck804}, /* LPC */
-	{0x10de, 0x0051, OK, "NVIDIA", "CK804",		enable_flash_ck804}, /* Pro */
-	{0x10de, 0x0060, OK, "NVIDIA", "NForce2",       enable_flash_nvidia_nforce2},
-	/* Slave, should not be here, to fix known bug for A01. */
-	{0x10de, 0x00d3, OK, "NVIDIA", "CK804",		enable_flash_ck804},
-	{0x10de, 0x0260, NT, "NVIDIA", "MCP51",		enable_flash_ck804},
-	{0x10de, 0x0261, NT, "NVIDIA", "MCP51",		enable_flash_ck804},
-	{0x10de, 0x0262, NT, "NVIDIA", "MCP51",		enable_flash_ck804},
-	{0x10de, 0x0263, NT, "NVIDIA", "MCP51",		enable_flash_ck804},
-	{0x10de, 0x0360, OK, "NVIDIA", "MCP55",		enable_flash_mcp55}, /* M57SLI*/
-	{0x10de, 0x0361, OK, "NVIDIA", "MCP55",		enable_flash_mcp55}, /* LPC */
-	{0x10de, 0x0362, OK, "NVIDIA", "MCP55",		enable_flash_mcp55}, /* LPC */
-	{0x10de, 0x0363, OK, "NVIDIA", "MCP55",		enable_flash_mcp55}, /* LPC */
-	{0x10de, 0x0364, OK, "NVIDIA", "MCP55",		enable_flash_mcp55}, /* LPC */
-	{0x10de, 0x0365, OK, "NVIDIA", "MCP55",		enable_flash_mcp55}, /* LPC */
-	{0x10de, 0x0366, OK, "NVIDIA", "MCP55",		enable_flash_mcp55}, /* LPC */
-	{0x10de, 0x0367, OK, "NVIDIA", "MCP55",		enable_flash_mcp55}, /* Pro */
-	{0x10de, 0x0548, OK, "NVIDIA", "MCP67",		enable_flash_mcp55},
-	{0x1039, 0x0496, NT, "SiS", "85C496+497",	enable_flash_sis85c496},
-	{0x1039, 0x0406, NT, "SiS", "501/5101/5501",	enable_flash_sis501},
-	{0x1039, 0x5511, NT, "SiS", "5511",		enable_flash_sis5511},
-	{0x1039, 0x5596, NT, "SiS", "5596",		enable_flash_sis5596},
-	{0x1039, 0x5571, NT, "SiS", "5571",		enable_flash_sis530},
-	{0x1039, 0x5591, NT, "SiS", "5591/5592",	enable_flash_sis530},
-	{0x1039, 0x5597, NT, "SiS", "5597/5598/5581/5120", enable_flash_sis530},
-	{0x1039, 0x0530, NT, "SiS", "530",		enable_flash_sis530},
-	{0x1039, 0x5600, NT, "SiS", "600",		enable_flash_sis530},
-	{0x1039, 0x0620, NT, "SiS", "620",		enable_flash_sis530},
-	{0x1039, 0x0540, NT, "SiS", "540",		enable_flash_sis540},
-	{0x1039, 0x0630, NT, "SiS", "630",		enable_flash_sis540},
-	{0x1039, 0x0635, NT, "SiS", "635",		enable_flash_sis540},
-	{0x1039, 0x0640, NT, "SiS", "640",		enable_flash_sis540},
-	{0x1039, 0x0645, NT, "SiS", "645",		enable_flash_sis540},
-	{0x1039, 0x0646, NT, "SiS", "645DX",		enable_flash_sis540},
-	{0x1039, 0x0648, NT, "SiS", "648",		enable_flash_sis540},
-	{0x1039, 0x0650, NT, "SiS", "650",		enable_flash_sis540},
-	{0x1039, 0x0651, NT, "SiS", "651",		enable_flash_sis540},
-	{0x1039, 0x0655, NT, "SiS", "655",		enable_flash_sis540},
-	{0x1039, 0x0730, NT, "SiS", "730",		enable_flash_sis540},
-	{0x1039, 0x0733, NT, "SiS", "733",		enable_flash_sis540},
-	{0x1039, 0x0735, OK, "SiS", "735",		enable_flash_sis540},
-	{0x1039, 0x0740, NT, "SiS", "740",		enable_flash_sis540},
-	{0x1039, 0x0745, NT, "SiS", "745",		enable_flash_sis540},
-	{0x1039, 0x0746, NT, "SiS", "746",		enable_flash_sis540},
-	{0x1039, 0x0748, NT, "SiS", "748",		enable_flash_sis540},
-	{0x1039, 0x0755, NT, "SiS", "755",		enable_flash_sis540},
-	{0x1106, 0x8324, OK, "VIA", "CX700",		enable_flash_vt823x},
-	{0x1106, 0x8231, NT, "VIA", "VT8231",		enable_flash_vt823x},
-	{0x1106, 0x3074, NT, "VIA", "VT8233",		enable_flash_vt823x},
-	{0x1106, 0x3177, OK, "VIA", "VT8235",		enable_flash_vt823x},
-	{0x1106, 0x3227, OK, "VIA", "VT8237",		enable_flash_vt823x},
-	{0x1106, 0x3337, OK, "VIA", "VT8237A",		enable_flash_vt823x},
-	{0x1106, 0x3372, OK, "VIA", "VT8237S",		enable_flash_vt8237s_spi},
-	{0x1106, 0x8353, OK, "VIA", "VX800",		enable_flash_vt8237s_spi},
-	{0x1106, 0x0596, OK, "VIA", "VT82C596",		enable_flash_amd8111},
-	{0x1106, 0x0586, OK, "VIA", "VT82C586A/B",	enable_flash_amd8111},
-	{0x1106, 0x0686, NT, "VIA", "VT82C686A/B",	enable_flash_amd8111},
-
-	{},
-};
-
-int chipset_flash_enable(void)
-{
-	struct pci_dev *dev = 0;
-	int ret = -2;		/* Nothing! */
-	int i;
-
-	/* Now let's try to find the chipset we have... */
-	for (i = 0; chipset_enables[i].vendor_name != NULL; i++) {
-		dev = pci_dev_find(chipset_enables[i].vendor_id,
-				   chipset_enables[i].device_id);
-		if (dev)
-			break;
-	}
-
-	if (dev) {
-		printf("Found chipset \"%s %s\", enabling flash write... ",
-		       chipset_enables[i].vendor_name,
-		       chipset_enables[i].device_name);
-
-		ret = chipset_enables[i].doit(dev,
-					      chipset_enables[i].device_name);
-		if (ret)
-			printf("FAILED!\n");
-		else
-			printf("OK.\n");
-	}
-	printf("This chipset supports the following protocols: %s.\n",
-	       flashbuses_to_text(buses_supported));
-
-	return ret;
-}
diff --git a/cli/cbtable.c b/cli/cbtable.c
new file mode 100644
index 0000000..7bd4718
--- /dev/null
+++ b/cli/cbtable.c
@@ -0,0 +1,230 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2002 Steven James <pyro@linuxlabs.com>
+ * Copyright (C) 2002 Linux Networx
+ * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx)
+ * Copyright (C) 2006-2009 coresystems GmbH
+ * (Written by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH)
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#include "../libflashrom/flash.h"
+#include "coreboot_tables.h"
+
+char *lb_part = NULL, *lb_vendor = NULL;
+int partvendor_from_cbtable = 0;
+
+static unsigned long compute_checksum(void *addr, unsigned long length)
+{
+	uint8_t *ptr;
+	volatile union {
+		uint8_t byte[2];
+		uint16_t word;
+	} value;
+	unsigned long sum;
+	unsigned long i;
+
+	/* In the most straight forward way possible,
+	 * compute an ip style checksum.
+	 */
+	sum = 0;
+	ptr = addr;
+	for (i = 0; i < length; i++) {
+		unsigned long value;
+		value = ptr[i];
+		if (i & 1) {
+			value <<= 8;
+		}
+		/* Add the new value */
+		sum += value;
+		/* Wrap around the carry */
+		if (sum > 0xFFFF) {
+			sum = (sum + (sum >> 16)) & 0xFFFF;
+		}
+	}
+	value.byte[0] = sum & 0xff;
+	value.byte[1] = (sum >> 8) & 0xff;
+
+	return (~value.word) & 0xFFFF;
+}
+
+#define for_each_lbrec(head, rec) \
+	for(rec = (struct lb_record *)(((char *)head) + sizeof(*head)); \
+		(((char *)rec) < (((char *)head) + sizeof(*head) + head->table_bytes))  && \
+		(rec->size >= 1) && \
+		((((char *)rec) + rec->size) <= (((char *)head) + sizeof(*head) + head->table_bytes)); \
+		rec = (struct lb_record *)(((char *)rec) + rec->size))
+
+static int count_lb_records(struct lb_header *head)
+{
+	struct lb_record *rec;
+	int count;
+
+	count = 0;
+	for_each_lbrec(head, rec) {
+		count++;
+	}
+
+	return count;
+}
+
+static struct lb_header *find_lb_table(void *base, unsigned long start,
+				       unsigned long end)
+{
+	unsigned long addr;
+
+	/* For now be stupid.... */
+	for (addr = start; addr < end; addr += 16) {
+		struct lb_header *head =
+		    (struct lb_header *)(((char *)base) + addr);
+		struct lb_record *recs =
+		    (struct lb_record *)(((char *)base) + addr + sizeof(*head));
+		if (memcmp(head->signature, "LBIO", 4) != 0)
+			continue;
+		printf_debug("Found candidate at: %08lx-%08lx\n",
+			     addr, addr + head->table_bytes);
+		if (head->header_bytes != sizeof(*head)) {
+			fprintf(stderr, "Header bytes of %d are incorrect.\n",
+				head->header_bytes);
+			continue;
+		}
+		if (count_lb_records(head) != head->table_entries) {
+			fprintf(stderr, "Bad record count: %d.\n",
+				head->table_entries);
+			continue;
+		}
+		if (compute_checksum((uint8_t *) head, sizeof(*head)) != 0) {
+			fprintf(stderr, "Bad header checksum.\n");
+			continue;
+		}
+		if (compute_checksum(recs, head->table_bytes)
+		    != head->table_checksum) {
+			fprintf(stderr, "Bad table checksum: %04x.\n",
+				head->table_checksum);
+			continue;
+		}
+		printf_debug("Found coreboot table at 0x%08lx.\n", addr);
+		return head;
+
+	};
+
+	return 0;
+}
+
+static void find_mainboard(struct lb_record *ptr, unsigned long addr)
+{
+	struct lb_mainboard *rec;
+	int max_size;
+	char vendor[256], part[256];
+
+	rec = (struct lb_mainboard *)ptr;
+	max_size = rec->size - sizeof(*rec);
+	printf("Vendor ID: %.*s, part ID: %.*s\n",
+	       max_size - rec->vendor_idx,
+	       rec->strings + rec->vendor_idx,
+	       max_size - rec->part_number_idx,
+	       rec->strings + rec->part_number_idx);
+	snprintf(vendor, 255, "%.*s", max_size - rec->vendor_idx,
+		 rec->strings + rec->vendor_idx);
+	snprintf(part, 255, "%.*s", max_size - rec->part_number_idx,
+		 rec->strings + rec->part_number_idx);
+
+	if (lb_part) {
+		printf("Overwritten by command line, vendor ID: %s, part ID: %s.\n", lb_vendor, lb_part);
+	} else {
+		partvendor_from_cbtable = 1;
+		lb_part = strdup(part);
+		lb_vendor = strdup(vendor);
+	}
+}
+
+static struct lb_record *next_record(struct lb_record *rec)
+{
+	return (struct lb_record *)(((char *)rec) + rec->size);
+}
+
+static void search_lb_records(struct lb_record *rec, struct lb_record *last,
+			      unsigned long addr)
+{
+	struct lb_record *next;
+	int count;
+	count = 0;
+
+	for (next = next_record(rec); (rec < last) && (next <= last);
+	     rec = next, addr += rec->size) {
+		next = next_record(rec);
+		count++;
+		if (rec->tag == LB_TAG_MAINBOARD) {
+			find_mainboard(rec, addr);
+			break;
+		}
+	}
+}
+
+#define BYTES_TO_MAP (1024*1024)
+int coreboot_init(void)
+{
+	uint8_t *table_area;
+	unsigned long addr, start;
+	struct lb_header *lb_table;
+	struct lb_record *rec, *last;
+
+#ifdef __DARWIN__
+	/* This is a hack. DirectIO fails to map physical address 0x00000000.
+	 * Why?
+	 */
+	start = 0x400;
+#else
+	start = 0x0;
+#endif
+	table_area = physmap("low megabyte", start, BYTES_TO_MAP);
+
+	lb_table = find_lb_table(table_area, 0x00000, 0x1000);
+	if (!lb_table)
+		lb_table = find_lb_table(table_area, 0xf0000, BYTES_TO_MAP);
+	if (lb_table) {
+		struct lb_forward *forward = (struct lb_forward *)
+			(((char *)lb_table) + lb_table->header_bytes);
+		if (forward->tag == LB_TAG_FORWARD) {
+			start = forward->forward;
+			start &= ~(getpagesize() - 1);
+			physunmap(table_area, BYTES_TO_MAP);
+			table_area = physmap("high tables", start, BYTES_TO_MAP);
+			lb_table = find_lb_table(table_area, 0x00000, 0x1000);
+		}
+	}
+
+	if (!lb_table) {
+		printf("No coreboot table found.\n");
+		return -1;
+	}
+
+	addr = ((char *)lb_table) - ((char *)table_area) + start;
+	fprintf(stdout, "coreboot table found at 0x%lx.\n", 
+		(unsigned long)lb_table - (unsigned long)table_area + start);
+	rec = (struct lb_record *)(((char *)lb_table) + lb_table->header_bytes);
+	last = (struct lb_record *)(((char *)rec) + lb_table->table_bytes);
+	printf_debug("coreboot header(%d) checksum: %04x table(%d) checksum: %04x entries: %d\n",
+	     lb_table->header_bytes, lb_table->header_checksum,
+	     lb_table->table_bytes, lb_table->table_checksum,
+	     lb_table->table_entries);
+	search_lb_records(rec, last, addr + lb_table->header_bytes);
+
+	return 0;
+}
diff --git a/cli/coreboot_tables.h b/cli/coreboot_tables.h
new file mode 100644
index 0000000..6944559
--- /dev/null
+++ b/cli/coreboot_tables.h
@@ -0,0 +1,150 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2002 Linux Networx
+ * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx)
+ * Copyright (C) 2005-2007 coresystems GmbH
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+#ifndef COREBOOT_TABLES_H
+#define COREBOOT_TABLES_H
+
+#include <stdint.h>
+
+/* The coreboot table information is for conveying information
+ * from the firmware to the loaded OS image.  Primarily this
+ * is expected to be information that cannot be discovered by
+ * other means, such as quering the hardware directly.
+ *
+ * All of the information should be Position Independent Data.  
+ * That is it should be safe to relocated any of the information
+ * without it's meaning/correctnes changing.   For table that
+ * can reasonably be used on multiple architectures the data
+ * size should be fixed.  This should ease the transition between
+ * 32 bit and 64 bit architectures etc.
+ *
+ * The completeness test for the information in this table is:
+ * - Can all of the hardware be detected?
+ * - Are the per motherboard constants available?
+ * - Is there enough to allow a kernel to run that was written before
+ *   a particular motherboard is constructed? (Assuming the kernel
+ *   has drivers for all of the hardware but it does not have
+ *   assumptions on how the hardware is connected together).
+ *
+ * With this test it should be straight forward to determine if a
+ * table entry is required or not.  This should remove much of the
+ * long term compatibility burden as table entries which are
+ * irrelevant or have been replaced by better alternatives may be
+ * dropped.  Of course it is polite and expidite to include extra
+ * table entries and be backwards compatible, but it is not required.
+ */
+
+/* Since coreboot is usually compiled 32bit, gcc will align 64bit 
+ * types to 32bit boundaries. If the coreboot table is dumped on a 
+ * 64bit system, a uint64_t would be aligned to 64bit boundaries, 
+ * breaking the table format.
+ *
+ * lb_uint64 will keep 64bit coreboot table values aligned to 32bit
+ * to ensure compatibility. They can be accessed with the two functions
+ * below: unpack_lb64() and pack_lb64()
+ *
+ * See also: util/lbtdump/lbtdump.c
+ */
+
+struct lb_uint64 {
+	uint32_t lo;
+	uint32_t hi;
+};
+
+struct lb_header {
+	uint8_t signature[4];	/* LBIO */
+	uint32_t header_bytes;
+	uint32_t header_checksum;
+	uint32_t table_bytes;
+	uint32_t table_checksum;
+	uint32_t table_entries;
+};
+
+/* Every entry in the boot enviroment list will correspond to a boot
+ * info record.  Encoding both type and size.  The type is obviously
+ * so you can tell what it is.  The size allows you to skip that
+ * boot enviroment record if you don't know what it easy.  This allows
+ * forward compatibility with records not yet defined.
+ */
+struct lb_record {
+	uint32_t tag;		/* tag ID */
+	uint32_t size;		/* size of record (in bytes) */
+};
+
+#define LB_TAG_UNUSED	0x0000
+
+#define LB_TAG_MEMORY	0x0001
+
+struct lb_memory_range {
+	struct lb_uint64 start;
+	struct lb_uint64 size;
+	uint32_t type;
+#define LB_MEM_RAM       1	/* Memory anyone can use */
+#define LB_MEM_RESERVED  2	/* Don't use this memory region */
+#define LB_MEM_TABLE     16	/* Ram configuration tables are kept in */
+};
+
+struct lb_memory {
+	uint32_t tag;
+	uint32_t size;
+	struct lb_memory_range map[0];
+};
+
+#define LB_TAG_HWRPB	0x0002
+struct lb_hwrpb {
+	uint32_t tag;
+	uint32_t size;
+	uint64_t hwrpb;
+};
+
+#define LB_TAG_MAINBOARD	0x0003
+struct lb_mainboard {
+	uint32_t tag;
+	uint32_t size;
+	uint8_t vendor_idx;
+	uint8_t part_number_idx;
+	uint8_t strings[0];
+};
+
+#define LB_TAG_VERSION		0x0004
+#define LB_TAG_EXTRA_VERSION	0x0005
+#define LB_TAG_BUILD		0x0006
+#define LB_TAG_COMPILE_TIME	0x0007
+#define LB_TAG_COMPILE_BY	0x0008
+#define LB_TAG_COMPILE_HOST	0x0009
+#define LB_TAG_COMPILE_DOMAIN	0x000a
+#define LB_TAG_COMPILER		0x000b
+#define LB_TAG_LINKER		0x000c
+#define LB_TAG_ASSEMBLER	0x000d
+struct lb_string {
+	uint32_t tag;
+	uint32_t size;
+	uint8_t string[0];
+};
+
+#define LB_TAG_FORWARD		0x0011
+struct lb_forward {
+	uint32_t tag;
+	uint32_t size;
+	uint64_t forward;
+};
+
+#endif				/* COREBOOT_TABLES_H */
diff --git a/cli/flashrom.8 b/cli/flashrom.8
new file mode 100644
index 0000000..011840c
--- /dev/null
+++ b/cli/flashrom.8
@@ -0,0 +1,302 @@
+.TH FLASHROM 8 "May 21, 2009"
+.SH NAME
+flashrom \- detect, read, write, verify and erase flash chips
+.SH SYNOPSIS
+.B flashrom \fR[\fB\-VfLzhRn\fR] [\fB\-E\fR|\fB\-r\fR file|\fB\-w\fR file|\fB\-v\fR file] [\fB\-c\fR chipname]
+         [\fB\-m\fR [vendor:]part] [\fB\-l\fR file] [\fB\-i\fR image] [\fB\-p\fR programmer]
+.SH DESCRIPTION
+.B flashrom
+is a utility for detecting, reading, writing, verifying and erasing flash
+chips. It's often used to flash BIOS/EFI/coreboot/firmware images in-system
+using a supported mainboard, but it also supports flashing of network cards
+(NICs), SATA controller cards, and other external devices which can program
+flash chips.
+.PP
+It supports a wide range of DIP32, PLCC32, DIP8, SO8/SOIC8, TSOP32, and
+TSOP40 chips, which use various protocols such as LPC, FWH, parallel flash,
+or SPI.
+.SH OPTIONS
+Please note that the command line interface for flashrom will change before
+flashrom 1.0. Do not use flashrom in scripts or other automated tools without
+checking that your flashrom version won't interpret options in a different way.
+.PP
+You can specify one of \-E, \-r, \-w, \-v or no operation.
+If no operation is specified, then all that happens
+is that flash info is dumped and the flash chip is set to writable.
+.TP
+.B "\-r, \-\-read <file>"
+Read flash ROM contents and save them into the given
+.BR <file> .
+.TP
+.B "\-w, \-\-write <file>"
+Write file into flash ROM.
+.TP
+.B "\-n, \-\-noverify"
+Do
+.B not
+verify the flash ROM contents after writing them to the chip. Using this
+option is
+.B not
+recommended, you should only use it if you know what you are doing and you
+feel that the time for verification takes too long.
+.sp
+Typical usage is:
+.B "flashrom -wn file"
+.sp
+This option is only useful in combination with
+.BR \-\-write .
+.TP
+.B "\-v, \-\-verify <file>"
+Verify the flash ROM contents against the given
+.BR <file> .
+.TP
+.B "\-E, \-\-erase"
+Erase the flash ROM chip.
+.TP
+.B "\-V, \-\-verbose"
+More verbose output.
+.TP
+.B "\-c, \-\-chip" <chipname>
+Probe only for specified flash ROM chip.
+.sp
+flashrom supports ROM layouts. This allows you to flash certain parts of
+the flash chip only. A ROM layout file looks like follows:
+.sp
+  00000000:00008fff gfxrom
+  00009000:0003ffff normal
+  00040000:0007ffff fallback
+.sp
+  i.e.:
+  startaddr:endaddr name
+.sp
+All addresses are offsets within the file, not absolute addresses!
+If you only want to update the normal image in a ROM you can say:
+.sp
+.B "  flashrom -w --layout rom.layout --image normal agami_aruma.rom"
+.sp
+To update normal and fallback but leave the VGA BIOS alone, say:
+.sp
+.B "  flashrom -w -l rom.layout -i normal \"
+.br
+.B "           -i fallback agami_aruma.rom"
+.sp
+Currently overlapping sections are not supported.
+.sp
+ROM layouts should replace the \-s and \-e option since they are more
+flexible and they should lead to a ROM update file format with the
+ROM layout and the ROM image in one file (cpio, zip or something?).
+.TP
+.B "\-m, \-\-mainboard" <[vendor:]part>
+Override mainboard settings.
+.sp
+flashrom reads the coreboot table to determine the current mainboard. If no
+coreboot table could be read or if you want to override these values, you can
+specify \-m, e.g.:
+.sp
+.B "  flashrom -w --mainboard AGAMI:ARUMA agami_aruma.rom"
+.sp
+See the 'Supported mainboards' section in the output of 'flashrom \-L' for
+a list of boards which require the specification of the board name, if no
+coreboot table is found.
+.TP
+.B "\-f, \-\-force"
+Force write without checking whether the ROM image file is really meant
+to be used on this board.
+.sp
+Note: This check only works while coreboot is running, and only for those
+boards where the coreboot code supports it.
+.TP
+.B "\-l, \-\-layout <file>"
+Read ROM layout from
+.BR <file> .
+.TP
+.B "\-i, \-\-image <name>"
+Only flash image
+.B <name>
+from flash layout.
+.TP
+.B "\-L, \-\-list\-supported"
+List the flash chips, chipsets, mainboards, and PCI card "programmers"
+supported by flashrom.
+.sp
+There are many unlisted boards which will work out of the box, without
+special support in flashrom. Please let us know if you can verify that
+other boards work or do not work out of the box. For verification you have
+to test an ERASE and/or WRITE operation, so make sure you only do that
+if you have proper means to recover from failure!
+.TP
+.B "\-z, \-\-list\-supported-wiki"
+Same as
+.BR \-\-list\-supported ,
+but outputs the supported hardware in MediaWiki syntax, so that it can be
+easily pasted into the wiki page at http://www.flashrom.org/.
+.TP
+.B "\-p, \-\-programmer <name>"
+Specify the programmer device. Currently supported are:
+.sp
+.BR "* internal" " (default, for in-system flashing in the mainboard)"
+.sp
+.BR "* dummy" " (just prints all operations and accesses)"
+.sp
+.BR "* nic3com" " (for flash ROMs on 3COM network cards)"
+.sp
+.BR "* gfxnvidia" " (for flash ROMs on NVIDIA graphics cards)"
+.sp
+.BR "* drkaiser" " (for flash ROMs on Dr. Kaiser PC-Waechter PCI cards)"
+.sp
+.BR "* satasii" " (for flash ROMs on Silicon Image SATA/IDE controllers)"
+.sp
+.BR "* it87spi" " (for flash ROMs behind an ITE IT87xx Super I/O LPC/SPI translation unit)"
+.sp
+.BR "* ft2232spi" " (for flash ROMs attached to a FT2232H/FT4232H based USB SPI programmer)"
+.sp
+.BR "* serprog" " (for flash ROMs attached to Urja's AVR programmer)"
+.sp
+.BR "* buspiratespi" " (for flash ROMs attached to a Bus Pirate)"
+.sp
+The dummy programmer has an optional parameter specifying the bus types it
+should support. For that you have to use the
+.B "flashrom -p dummy:type"
+syntax where
+.B type
+can be any comma-separated combination of
+.B parallel lpc fwh spi all
+in any order.
+.sp
+Example:
+.B "flashrom -p dummy:lpc,fwh"
+.sp
+If you have multiple supported PCI cards which can program flash chips
+(NICs, SATA/IDE controllers, etc.) in your system, you must use the
+.B "flashrom -p xxxx:bb:dd.f"
+syntax to explicitly select one of them, where
+.B xxxx
+is the name of the programmer
+.B bb
+is the PCI bus number,
+.B dd
+is the PCI device number, and
+.B f
+is the PCI function number of the desired NIC.
+.sp
+Example:
+.B "flashrom -p nic3com:05:04.0"
+.sp
+Currently the following programmers support this mechanism:
+.BR nic3com ,
+.BR gfxnvidia ,
+.BR satasii .
+.sp
+The it87spi programmer has an optional parameter which will set the I/O base
+port of the IT87* SPI controller interface to the port specified in the
+parameter. For that you have to use the
+.B "flashrom -p it87spi:port=portnum"
+syntax where
+.B portnum
+is an I/O port number which must be a multiple of 8.
+.sp
+The ft2232spi programmer has an optional parameter specifying the controller
+type and interface/port it should support. For that you have to use the
+.B "flashrom -p ft2232spi:model,port=interface"
+syntax where
+.B model
+can be any of
+.B 2232H 4232H
+and
+.B interface
+can be any of
+.B A
+.BR B .
+The default model is
+.B 4232H
+and the default interface is
+.BR B .
+.sp
+The serprog programmer has an optional parameter specifying either a serial
+device/baud combination or an IP/port combination for communication with the
+programmer. For serial, you have to use the
+.B "flashrom -p serprog:/dev/device:baud"
+syntax and for IP, you have to use
+.B "flashrom -p serprog:ip:port"
+instead. More information about serprog is available in serprog-protocol.txt in
+the source distribution.
+.sp
+The buspiratespi programmer has a required dev parameter specifying the Bus
+Pirate device node and an optional spispeed parameter specifying the frequency
+of the SPI bus. The parameter delimiter is a comma. Syntax is
+.B "flashrom -p buspiratespi:dev=/dev/device,spispeed=frequency"
+where
+.B frequency
+can be any of
+.B 30k 125k 250k 1M 2M 2.6M 4M 8M
+(in Hz).
+.sp
+Support for some programmers can be disabled at compile time.
+.B "flashrom -h"
+lists all supported programmers.
+.TP
+.B "\-h, \-\-help"
+Show a help text and exit.
+.TP
+.B "\-R, \-\-version"
+Show version information and exit.
+.SH EXIT STATUS
+flashrom exits with 0 on success, 1 on most failures but with 2 if /dev/mem
+(/dev/xsvc on Solaris) can not be opened and with 3 if a call to mmap() fails.
+.SH BUGS
+Please report any bugs at
+.BR http://www.flashrom.org/trac/flashrom/newticket ","
+or on the flashrom mailing list
+.RB "(" http://www.flashrom.org/mailman/listinfo/flashrom ")."
+.SH LICENCE
+.B flashrom
+is covered by the GNU General Public License (GPL), version 2. Some files are
+additionally available under the GPL (version 2, or any later version).
+.SH COPYRIGHT
+.br
+Please see the individual files.
+.SH AUTHORS
+Carl-Daniel Hailfinger
+.br
+Claus Gindhart <claus.gindhart@kontron.com>
+.br
+Dominik Geyer <dominik.geyer@kontron.com>
+.br
+Eric Biederman <ebiederman@lnxi.com>
+.br
+Giampiero Giancipoli <gianci@email.it>
+.br
+Joe Bao <Zheng.Bao@amd.com>
+.br
+Luc Verhaegen <libv@skynet.be>
+.br
+Li-Ta Lo
+.br
+Markus Boas <ryven@ryven.de>
+.br
+Nikolay Petukhov <nikolay.petukhov@gmail.com>
+.br
+Peter Stuge <peter@stuge.se>
+.br
+Reinder E.N. de Haan <lb_reha@mveas.com>
+.br
+Ronald G. Minnich <rminnich@gmail.com>
+.br
+Ronald Hoogenboom <ronald@zonnet.nl>
+.br
+Stefan Reinauer <stepan@coresystems.de>
+.br
+Stefan Wildemann <stefan.wildemann@kontron.com>
+.br
+Steven James <pyro@linuxlabs.com>
+.br
+Uwe Hermann <uwe@hermann-uwe.de>
+.br
+Wang Qingpei <Qingpei.Wang@amd.com>
+.br
+Yinghai Lu <yinghai.lu@amd.com>
+.br
+some others 
+.PP
+This manual page was written by Uwe Hermann <uwe@hermann-uwe.de>.
+It is licensed under the terms of the GNU GPL (version 2 or later).
diff --git a/cli/flashrom.c b/cli/flashrom.c
new file mode 100644
index 0000000..8a6bdfe
--- /dev/null
+++ b/cli/flashrom.c
@@ -0,0 +1,1369 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2004 Tyan Corp <yhlu@tyan.com>
+ * Copyright (C) 2005-2008 coresystems GmbH
+ * Copyright (C) 2008,2009 Carl-Daniel Hailfinger
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include "../libflashrom/flash.h"
+#include "../libflashrom/flashchips.h"
+
+const char *flashrom_version = FLASHROM_VERSION;
+char *chip_to_probe = NULL;
+int verbose = 0;
+enum programmer programmer = PROGRAMMER_INTERNAL;
+char *programmer_param = NULL;
+
+const struct programmer_entry programmer_table[] = {
+	{
+		.name			= "internal",
+		.init			= internal_init,
+		.shutdown		= internal_shutdown,
+		.map_flash_region	= physmap,
+		.unmap_flash_region	= physunmap,
+		.chip_readb		= internal_chip_readb,
+		.chip_readw		= internal_chip_readw,
+		.chip_readl		= internal_chip_readl,
+		.chip_readn		= internal_chip_readn,
+		.chip_writeb		= internal_chip_writeb,
+		.chip_writew		= internal_chip_writew,
+		.chip_writel		= internal_chip_writel,
+		.chip_writen		= fallback_chip_writen,
+		.delay			= internal_delay,
+	},
+
+#if DUMMY_SUPPORT == 1
+	{
+		.name			= "dummy",
+		.init			= dummy_init,
+		.shutdown		= dummy_shutdown,
+		.map_flash_region	= dummy_map,
+		.unmap_flash_region	= dummy_unmap,
+		.chip_readb		= dummy_chip_readb,
+		.chip_readw		= dummy_chip_readw,
+		.chip_readl		= dummy_chip_readl,
+		.chip_readn		= dummy_chip_readn,
+		.chip_writeb		= dummy_chip_writeb,
+		.chip_writew		= dummy_chip_writew,
+		.chip_writel		= dummy_chip_writel,
+		.chip_writen		= dummy_chip_writen,
+		.delay			= internal_delay,
+	},
+#endif
+
+#if NIC3COM_SUPPORT == 1
+	{
+		.name			= "nic3com",
+		.init			= nic3com_init,
+		.shutdown		= nic3com_shutdown,
+		.map_flash_region	= fallback_map,
+		.unmap_flash_region	= fallback_unmap,
+		.chip_readb		= nic3com_chip_readb,
+		.chip_readw		= fallback_chip_readw,
+		.chip_readl		= fallback_chip_readl,
+		.chip_readn		= fallback_chip_readn,
+		.chip_writeb		= nic3com_chip_writeb,
+		.chip_writew		= fallback_chip_writew,
+		.chip_writel		= fallback_chip_writel,
+		.chip_writen		= fallback_chip_writen,
+		.delay			= internal_delay,
+	},
+#endif
+
+#if GFXNVIDIA_SUPPORT == 1
+	{
+		.name			= "gfxnvidia",
+		.init			= gfxnvidia_init,
+		.shutdown		= gfxnvidia_shutdown,
+		.map_flash_region	= fallback_map,
+		.unmap_flash_region	= fallback_unmap,
+		.chip_readb		= gfxnvidia_chip_readb,
+		.chip_readw		= fallback_chip_readw,
+		.chip_readl		= fallback_chip_readl,
+		.chip_readn		= fallback_chip_readn,
+		.chip_writeb		= gfxnvidia_chip_writeb,
+		.chip_writew		= fallback_chip_writew,
+		.chip_writel		= fallback_chip_writel,
+		.chip_writen		= fallback_chip_writen,
+		.delay			= internal_delay,
+	},
+#endif
+
+#if DRKAISER_SUPPORT == 1
+	{
+		.name			= "drkaiser",
+		.init			= drkaiser_init,
+		.shutdown		= drkaiser_shutdown,
+		.map_flash_region	= fallback_map,
+		.unmap_flash_region	= fallback_unmap,
+		.chip_readb		= drkaiser_chip_readb,
+		.chip_readw		= fallback_chip_readw,
+		.chip_readl		= fallback_chip_readl,
+		.chip_readn		= fallback_chip_readn,
+		.chip_writeb		= drkaiser_chip_writeb,
+		.chip_writew		= fallback_chip_writew,
+		.chip_writel		= fallback_chip_writel,
+		.chip_writen		= fallback_chip_writen,
+		.delay			= internal_delay,
+	},
+#endif
+
+#if SATASII_SUPPORT == 1
+	{
+		.name			= "satasii",
+		.init			= satasii_init,
+		.shutdown		= satasii_shutdown,
+		.map_flash_region	= fallback_map,
+		.unmap_flash_region	= fallback_unmap,
+		.chip_readb		= satasii_chip_readb,
+		.chip_readw		= fallback_chip_readw,
+		.chip_readl		= fallback_chip_readl,
+		.chip_readn		= fallback_chip_readn,
+		.chip_writeb		= satasii_chip_writeb,
+		.chip_writew		= fallback_chip_writew,
+		.chip_writel		= fallback_chip_writel,
+		.chip_writen		= fallback_chip_writen,
+		.delay			= internal_delay,
+	},
+#endif
+
+	{
+		.name			= "it87spi",
+		.init			= it87spi_init,
+		.shutdown		= noop_shutdown,
+		.map_flash_region	= fallback_map,
+		.unmap_flash_region	= fallback_unmap,
+		.chip_readb		= noop_chip_readb,
+		.chip_readw		= fallback_chip_readw,
+		.chip_readl		= fallback_chip_readl,
+		.chip_readn		= fallback_chip_readn,
+		.chip_writeb		= noop_chip_writeb,
+		.chip_writew		= fallback_chip_writew,
+		.chip_writel		= fallback_chip_writel,
+		.chip_writen		= fallback_chip_writen,
+		.delay			= internal_delay,
+	},
+
+#if FT2232_SPI_SUPPORT == 1
+	{
+		.name			= "ft2232spi",
+		.init			= ft2232_spi_init,
+		.shutdown		= noop_shutdown, /* Missing shutdown */
+		.map_flash_region	= fallback_map,
+		.unmap_flash_region	= fallback_unmap,
+		.chip_readb		= noop_chip_readb,
+		.chip_readw		= fallback_chip_readw,
+		.chip_readl		= fallback_chip_readl,
+		.chip_readn		= fallback_chip_readn,
+		.chip_writeb		= noop_chip_writeb,
+		.chip_writew		= fallback_chip_writew,
+		.chip_writel		= fallback_chip_writel,
+		.chip_writen		= fallback_chip_writen,
+		.delay			= internal_delay,
+	},
+#endif
+
+#if SERPROG_SUPPORT == 1
+	{
+		.name			= "serprog",
+		.init			= serprog_init,
+		.shutdown		= serprog_shutdown,
+		.map_flash_region	= fallback_map,
+		.unmap_flash_region	= fallback_unmap,
+		.chip_readb		= serprog_chip_readb,
+		.chip_readw		= fallback_chip_readw,
+		.chip_readl		= fallback_chip_readl,
+		.chip_readn		= serprog_chip_readn,
+		.chip_writeb		= serprog_chip_writeb,
+		.chip_writew		= fallback_chip_writew,
+		.chip_writel		= fallback_chip_writel,
+		.chip_writen		= fallback_chip_writen,
+		.delay			= serprog_delay,
+	},
+#endif
+
+#if BUSPIRATE_SPI_SUPPORT == 1
+	{
+		.name			= "buspiratespi",
+		.init			= buspirate_spi_init,
+		.shutdown		= buspirate_spi_shutdown,
+		.map_flash_region	= fallback_map,
+		.unmap_flash_region	= fallback_unmap,
+		.chip_readb		= noop_chip_readb,
+		.chip_readw		= fallback_chip_readw,
+		.chip_readl		= fallback_chip_readl,
+		.chip_readn		= fallback_chip_readn,
+		.chip_writeb		= noop_chip_writeb,
+		.chip_writew		= fallback_chip_writew,
+		.chip_writel		= fallback_chip_writel,
+		.chip_writen		= fallback_chip_writen,
+		.delay			= internal_delay,
+	},
+#endif
+
+	{}, /* This entry corresponds to PROGRAMMER_INVALID. */
+};
+
+int programmer_init(void)
+{
+	return programmer_table[programmer].init();
+}
+
+int programmer_shutdown(void)
+{
+	return programmer_table[programmer].shutdown();
+}
+
+void *programmer_map_flash_region(const char *descr, unsigned long phys_addr,
+				  size_t len)
+{
+	return programmer_table[programmer].map_flash_region(descr,
+							     phys_addr, len);
+}
+
+void programmer_unmap_flash_region(void *virt_addr, size_t len)
+{
+	programmer_table[programmer].unmap_flash_region(virt_addr, len);
+}
+
+void chip_writeb(uint8_t val, chipaddr addr)
+{
+	programmer_table[programmer].chip_writeb(val, addr);
+}
+
+void chip_writew(uint16_t val, chipaddr addr)
+{
+	programmer_table[programmer].chip_writew(val, addr);
+}
+
+void chip_writel(uint32_t val, chipaddr addr)
+{
+	programmer_table[programmer].chip_writel(val, addr);
+}
+
+void chip_writen(uint8_t *buf, chipaddr addr, size_t len)
+{
+	programmer_table[programmer].chip_writen(buf, addr, len);
+}
+
+uint8_t chip_readb(const chipaddr addr)
+{
+	return programmer_table[programmer].chip_readb(addr);
+}
+
+uint16_t chip_readw(const chipaddr addr)
+{
+	return programmer_table[programmer].chip_readw(addr);
+}
+
+uint32_t chip_readl(const chipaddr addr)
+{
+	return programmer_table[programmer].chip_readl(addr);
+}
+
+void chip_readn(uint8_t *buf, chipaddr addr, size_t len)
+{
+	programmer_table[programmer].chip_readn(buf, addr, len);
+}
+
+void programmer_delay(int usecs)
+{
+	programmer_table[programmer].delay(usecs);
+}
+
+void map_flash_registers(struct flashchip *flash)
+{
+	size_t size = flash->total_size * 1024;
+	/* Flash registers live 4 MByte below the flash. */
+	/* FIXME: This is incorrect for nonstandard flashbase. */
+	flash->virtual_registers = (chipaddr)programmer_map_flash_region("flash chip registers", (0xFFFFFFFF - 0x400000 - size + 1), size);
+}
+
+int read_memmapped(struct flashchip *flash, uint8_t *buf, int start, int len)
+{
+	chip_readn(buf, flash->virtual_memory + start, len);
+		
+	return 0;
+}
+
+int min(int a, int b)
+{
+	return (a < b) ? a : b;
+}
+
+int max(int a, int b)
+{
+	return (a > b) ? a : b;
+}
+
+int bitcount(unsigned long a)
+{
+	int i = 0;
+	for (; a != 0; a >>= 1)
+		if (a & 1)
+			i++;
+	return i;
+}
+
+char *strcat_realloc(char *dest, const char *src)
+{
+	dest = realloc(dest, strlen(dest) + strlen(src) + 1);
+	if (!dest)
+		return NULL;
+	strcat(dest, src);
+	return dest;
+}
+
+/* This is a somewhat hacked function similar in some ways to strtok().
+ * It will look for needle in haystack, return a copy of needle and remove
+ * everything from the first occurrence of needle to the next delimiter
+ * from haystack.
+ */
+char *extract_param(char **haystack, char *needle, char *delim)
+{
+	char *param_pos, *rest, *tmp;
+	char *dev = NULL;
+	int devlen;
+
+	param_pos = strstr(*haystack, needle);
+	do {
+		if (!param_pos)
+			return NULL;
+		/* Beginning of the string? */
+		if (param_pos == *haystack)
+			break;
+		/* After a delimiter? */
+		if (strchr(delim, *(param_pos - 1)))
+			break;
+		/* Continue searching. */
+		param_pos++;
+		param_pos = strstr(param_pos, needle);
+	} while (1);
+		
+	if (param_pos) {
+		param_pos += strlen(needle);
+		devlen = strcspn(param_pos, delim);
+		if (devlen) {
+			dev = malloc(devlen + 1);
+			if (!dev) {
+				fprintf(stderr, "Out of memory!\n");
+				exit(1);
+			}
+			strncpy(dev, param_pos, devlen);
+			dev[devlen] = '\0';
+		}
+		rest = param_pos + devlen;
+		rest += strspn(rest, delim);
+		param_pos -= strlen(needle);
+		memmove(param_pos, rest, strlen(rest) + 1);
+		tmp = realloc(*haystack, strlen(*haystack) + 1);
+		if (!tmp) {
+			fprintf(stderr, "Out of memory!\n");
+			exit(1);
+		}
+		*haystack = tmp;
+	}
+	
+
+	return dev;
+}
+
+/* start is an offset to the base address of the flash chip */
+int check_erased_range(struct flashchip *flash, int start, int len)
+{
+	int ret;
+	uint8_t *cmpbuf = malloc(len);
+
+	if (!cmpbuf) {
+		fprintf(stderr, "Could not allocate memory!\n");
+		exit(1);
+	}
+	memset(cmpbuf, 0xff, len);
+	ret = verify_range(flash, cmpbuf, start, len, "ERASE");
+	free(cmpbuf);
+	return ret;
+}
+
+/**
+ * @cmpbuf	buffer to compare against, cmpbuf[0] is expected to match the
+		flash content at location start
+ * @start	offset to the base address of the flash chip
+ * @len		length of the verified area
+ * @message	string to print in the "FAILED" message
+ * @return	0 for success, -1 for failure
+ */
+int verify_range(struct flashchip *flash, uint8_t *cmpbuf, int start, int len, char *message)
+{
+	int i, j, starthere, lenhere, ret = 0;
+	int page_size = flash->page_size;
+	uint8_t *readbuf = malloc(page_size);
+	int failcount = 0;
+
+	if (!len)
+		goto out_free;
+
+	if (!flash->read) {
+		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
+		return 1;
+	}
+	if (!readbuf) {
+		fprintf(stderr, "Could not allocate memory!\n");
+		exit(1);
+	}
+
+	if (start + len > flash->total_size * 1024) {
+		fprintf(stderr, "Error: %s called with start 0x%x + len 0x%x >"
+			" total_size 0x%x\n", __func__, start, len,
+			flash->total_size * 1024);
+		ret = -1;
+		goto out_free;
+	}
+	if (!message)
+		message = "VERIFY";
+	
+	/* Warning: This loop has a very unusual condition and body.
+	 * The loop needs to go through each page with at least one affected
+	 * byte. The lowest page number is (start / page_size) since that
+	 * division rounds down. The highest page number we want is the page
+	 * where the last byte of the range lives. That last byte has the
+	 * address (start + len - 1), thus the highest page number is
+	 * (start + len - 1) / page_size. Since we want to include that last
+	 * page as well, the loop condition uses <=.
+	 */
+	for (i = start / page_size; i <= (start + len - 1) / page_size; i++) {
+		/* Byte position of the first byte in the range in this page. */
+		starthere = max(start, i * page_size);
+		/* Length of bytes in the range in this page. */
+		lenhere = min(start + len, (i + 1) * page_size) - starthere;
+		flash->read(flash, readbuf, starthere, lenhere);
+		for (j = 0; j < lenhere; j++) {
+			if (cmpbuf[starthere - start + j] != readbuf[j]) {
+				/* Only print the first failure. */
+				if (!failcount++)
+					fprintf(stderr, "%s FAILED at 0x%08x! "
+						"Expected=0x%02x, Read=0x%02x,",
+						message, starthere + j,
+						cmpbuf[starthere - start + j],
+						readbuf[j]);
+			}
+		}
+	}
+	if (failcount) {
+		fprintf(stderr, " failed byte count from 0x%08x-0x%08x: 0x%x\n",
+			start, start + len - 1, failcount);
+		ret = -1;
+	}
+
+out_free:
+	free(readbuf);
+	return ret;
+}
+
+/* This function generates various test patterns useful for testing controller
+ * and chip communication as well as chip behaviour.
+ *
+ * If a byte can be written multiple times, each time keeping 0-bits at 0
+ * and changing 1-bits to 0 if the new value for that bit is 0, the effect
+ * is essentially an AND operation. That's also the reason why this function
+ * provides the result of AND between various patterns.
+ *
+ * Below is a list of patterns (and their block length).
+ * Pattern 0 is 05 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 (16 Bytes)
+ * Pattern 1 is 0a 1a 2a 3a 4a 5a 6a 7a 8a 9a aa ba ca da ea fa (16 Bytes)
+ * Pattern 2 is 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f (16 Bytes)
+ * Pattern 3 is a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af (16 Bytes)
+ * Pattern 4 is 00 10 20 30 40 50 60 70 80 90 a0 b0 c0 d0 e0 f0 (16 Bytes)
+ * Pattern 5 is 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f (16 Bytes)
+ * Pattern 6 is 00 (1 Byte)
+ * Pattern 7 is ff (1 Byte)
+ * Patterns 0-7 have a big-endian block number in the last 2 bytes of each 256
+ * byte block.
+ *
+ * Pattern 8 is 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11... (256 B)
+ * Pattern 9 is ff fe fd fc fb fa f9 f8 f7 f6 f5 f4 f3 f2 f1 f0 ef ee... (256 B)
+ * Pattern 10 is 00 00 00 01 00 02 00 03 00 04... (128 kB big-endian counter)
+ * Pattern 11 is ff ff ff fe ff fd ff fc ff fb... (128 kB big-endian downwards)
+ * Pattern 12 is 00 (1 Byte)
+ * Pattern 13 is ff (1 Byte)
+ * Patterns 8-13 have no block number.
+ *
+ * Patterns 0-3 are created to detect and efficiently diagnose communication
+ * slips like missed bits or bytes and their repetitive nature gives good visual
+ * cues to the person inspecting the results. In addition, the following holds:
+ * AND Pattern 0/1 == Pattern 4
+ * AND Pattern 2/3 == Pattern 5
+ * AND Pattern 0/1/2/3 == AND Pattern 4/5 == Pattern 6
+ * A weakness of pattern 0-5 is the inability to detect swaps/copies between
+ * any two 16-byte blocks except for the last 16-byte block in a 256-byte bloc.
+ * They work perfectly for detecting any swaps/aliasing of blocks >= 256 bytes.
+ * 0x5 and 0xa were picked because they are 0101 and 1010 binary.
+ * Patterns 8-9 are best for detecting swaps/aliasing of blocks < 256 bytes.
+ * Besides that, they provide for bit testing of the last two bytes of every
+ * 256 byte block which contains the block number for patterns 0-6.
+ * Patterns 10-11 are special purpose for detecting subblock aliasing with
+ * block sizes >256 bytes (some Dataflash chips etc.)
+ * AND Pattern 8/9 == Pattern 12
+ * AND Pattern 10/11 == Pattern 12
+ * Pattern 13 is the completely erased state.
+ * None of the patterns can detect aliasing at boundaries which are a multiple
+ * of 16 MBytes (but such chips do not exist anyway for Parallel/LPC/FWH/SPI).
+ */
+int generate_testpattern(uint8_t *buf, uint32_t size, int variant)
+{
+	int i;
+
+	if (!buf) {
+		fprintf(stderr, "Invalid buffer!\n");
+		return 1;
+	}
+
+	switch (variant) {
+	case 0:
+		for (i = 0; i < size; i++)
+			buf[i] = (i & 0xf) << 4 | 0x5;
+		break;
+	case 1:
+		for (i = 0; i < size; i++)
+			buf[i] = (i & 0xf) << 4 | 0xa;
+		break;
+	case 2:
+		for (i = 0; i < size; i++)
+			buf[i] = 0x50 | (i & 0xf);
+		break;
+	case 3:
+		for (i = 0; i < size; i++)
+			buf[i] = 0xa0 | (i & 0xf);
+		break;
+	case 4:
+		for (i = 0; i < size; i++)
+			buf[i] = (i & 0xf) << 4;
+		break;
+	case 5:
+		for (i = 0; i < size; i++)
+			buf[i] = i & 0xf;
+		break;
+	case 6:
+		memset(buf, 0x00, size);
+		break;
+	case 7:
+		memset(buf, 0xff, size);
+		break;
+	case 8:
+		for (i = 0; i < size; i++)
+			buf[i] = i & 0xff;
+		break;
+	case 9:
+		for (i = 0; i < size; i++)
+			buf[i] = ~(i & 0xff);
+		break;
+	case 10:
+		for (i = 0; i < size % 2; i++) {
+			buf[i * 2] = (i >> 8) & 0xff;
+			buf[i * 2 + 1] = i & 0xff;
+		}
+		if (size & 0x1)
+			buf[i * 2] = (i >> 8) & 0xff;
+		break;
+	case 11:
+		for (i = 0; i < size % 2; i++) {
+			buf[i * 2] = ~((i >> 8) & 0xff);
+			buf[i * 2 + 1] = ~(i & 0xff);
+		}
+		if (size & 0x1)
+			buf[i * 2] = ~((i >> 8) & 0xff);
+		break;
+	case 12:
+		memset(buf, 0x00, size);
+		break;
+	case 13:
+		memset(buf, 0xff, size);
+		break;
+	}
+
+	if ((variant >= 0) && (variant <= 7)) {
+		/* Write block number in the last two bytes of each 256-byte
+		 * block, big endian for easier reading of the hexdump.
+		 * Note that this wraps around for chips larger than 2^24 bytes
+		 * (16 MB).
+		 */
+		for (i = 0; i < size / 256; i++) {
+			buf[i * 256 + 254] = (i >> 8) & 0xff;
+			buf[i * 256 + 255] = i & 0xff;
+		}
+	}
+
+	return 0;
+}
+
+int check_max_decode(enum chipbustype buses, uint32_t size)
+{
+	int limitexceeded = 0;
+	if ((buses & CHIP_BUSTYPE_PARALLEL) &&
+	    (max_rom_decode.parallel < size)) {
+		limitexceeded++;
+		printf_debug("Chip size %u kB is bigger than supported "
+			     "size %u kB of chipset/board/programmer "
+			     "for %s interface, "
+			     "probe/read/erase/write may fail. ", size / 1024,
+			     max_rom_decode.parallel / 1024, "Parallel");
+	}
+	if ((buses & CHIP_BUSTYPE_LPC) && (max_rom_decode.lpc < size)) {
+		limitexceeded++;
+		printf_debug("Chip size %u kB is bigger than supported "
+			     "size %u kB of chipset/board/programmer "
+			     "for %s interface, "
+			     "probe/read/erase/write may fail. ", size / 1024,
+			     max_rom_decode.lpc / 1024, "LPC");
+	}
+	if ((buses & CHIP_BUSTYPE_FWH) && (max_rom_decode.fwh < size)) {
+		limitexceeded++;
+		printf_debug("Chip size %u kB is bigger than supported "
+			     "size %u kB of chipset/board/programmer "
+			     "for %s interface, "
+			     "probe/read/erase/write may fail. ", size / 1024,
+			     max_rom_decode.fwh / 1024, "FWH");
+	}
+	if ((buses & CHIP_BUSTYPE_SPI) && (max_rom_decode.spi < size)) {
+		limitexceeded++;
+		printf_debug("Chip size %u kB is bigger than supported "
+			     "size %u kB of chipset/board/programmer "
+			     "for %s interface, "
+			     "probe/read/erase/write may fail. ", size / 1024,
+			     max_rom_decode.spi / 1024, "SPI");
+	}
+	if (!limitexceeded)
+		return 0;
+	/* Sometimes chip and programmer have more than one bus in common,
+	 * and the limit is not exceeded on all buses. Tell the user.
+	 */
+	if (bitcount(buses) > limitexceeded)
+		printf_debug("There is at least one common chip/programmer "
+			     "interface which can support a chip of this size. "
+			     "You can try --force at your own risk.\n");
+	return 1;
+}
+
+struct flashchip *probe_flash(struct flashchip *first_flash, int force)
+{
+	struct flashchip *flash;
+	unsigned long base = 0;
+	uint32_t size;
+	enum chipbustype buses_common;
+	char *tmp;
+
+	for (flash = first_flash; flash && flash->name; flash++) {
+		if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0)
+			continue;
+		printf_debug("Probing for %s %s, %d KB: ",
+			     flash->vendor, flash->name, flash->total_size);
+		if (!flash->probe && !force) {
+			printf_debug("failed! flashrom has no probe function for this flash chip.\n");
+			continue;
+		}
+		buses_common = buses_supported & flash->bustype;
+		if (!buses_common) {
+			tmp = flashbuses_to_text(buses_supported);
+			printf_debug("skipped. Host bus type %s ", tmp);
+			free(tmp);
+			tmp = flashbuses_to_text(flash->bustype);
+			printf_debug("and chip bus type %s are incompatible.\n", tmp);
+			free(tmp);
+			continue;
+		}
+
+		size = flash->total_size * 1024;
+		check_max_decode(buses_common, size);
+
+		base = flashbase ? flashbase : (0xffffffff - size + 1);
+		flash->virtual_memory = (chipaddr)programmer_map_flash_region("flash chip", base, size);
+
+		if (force)
+			break;
+
+		if (flash->probe(flash) != 1)
+			goto notfound;
+
+		if (first_flash == flashchips
+		    || flash->model_id != GENERIC_DEVICE_ID)
+			break;
+
+notfound:
+		programmer_unmap_flash_region((void *)flash->virtual_memory, size);
+	}
+
+	if (!flash || !flash->name)
+		return NULL;
+
+	printf("Found chip \"%s %s\" (%d KB, %s) at physical address 0x%lx.\n",
+	       flash->vendor, flash->name, flash->total_size,
+	       flashbuses_to_text(flash->bustype), base);
+
+	return flash;
+}
+
+int verify_flash(struct flashchip *flash, uint8_t *buf)
+{
+	int ret;
+	int total_size = flash->total_size * 1024;
+
+	printf("Verifying flash... ");
+
+	ret = verify_range(flash, buf, 0, total_size, NULL);
+
+	if (!ret)
+		printf("VERIFIED.          \n");
+
+	return ret;
+}
+
+int read_flash(struct flashchip *flash, char *filename)
+{
+	unsigned long numbytes;
+	FILE *image;
+	unsigned long size = flash->total_size * 1024;
+	unsigned char *buf = calloc(size, sizeof(char));
+
+	if (!filename) {
+		printf("Error: No filename specified.\n");
+		return 1;
+	}
+	if ((image = fopen(filename, "w")) == NULL) {
+		perror(filename);
+		exit(1);
+	}
+	printf("Reading flash... ");
+	if (!flash->read) {
+		printf("FAILED!\n");
+		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
+		return 1;
+	} else
+		flash->read(flash, buf, 0, size);
+
+	numbytes = fwrite(buf, 1, size, image);
+	fclose(image);
+	free(buf);
+	printf("%s.\n", numbytes == size ? "done" : "FAILED");
+	if (numbytes != size)
+		return 1;
+	return 0;
+}
+
+int erase_flash(struct flashchip *flash)
+{
+	int i, j, k, ret = 0, found = 0;
+
+	printf("Erasing flash chip... ");
+	for (k = 0; k < NUM_ERASEFUNCTIONS; k++) {
+		unsigned long done = 0;
+		struct block_eraser eraser = flash->block_erasers[k];
+
+		printf_debug("Looking at blockwise erase function %i... ", k);
+		if (!eraser.block_erase && !eraser.eraseblocks[0].count) {
+			printf_debug("not defined. "
+				"Looking for another erase function.\n");
+			continue;
+		}
+		if (!eraser.block_erase && eraser.eraseblocks[0].count) {
+			printf_debug("eraseblock layout is known, but no "
+				"matching block erase function found. "
+				"Looking for another erase function.\n");
+			continue;
+		}
+		if (eraser.block_erase && !eraser.eraseblocks[0].count) {
+			printf_debug("block erase function found, but "
+				"eraseblock layout is unknown. "
+				"Looking for another erase function.\n");
+			continue;
+		}
+		found = 1;
+		printf_debug("trying... ");
+		for (i = 0; i < NUM_ERASEREGIONS; i++) {
+			/* count==0 for all automatically initialized array
+			 * members so the loop below won't be executed for them.
+			 */
+			for (j = 0; j < eraser.eraseblocks[i].count; j++) {
+				ret = eraser.block_erase(flash, done + eraser.eraseblocks[i].size * j, eraser.eraseblocks[i].size);
+				if (ret)
+					break;
+			}
+			if (ret)
+				break;
+		}
+		/* If everything is OK, don't try another erase function. */
+		if (!ret)
+			break;
+	}
+	/* If no block erase function was found or block erase failed, retry. */
+	if ((!found || ret) && (flash->erase)) {
+		found = 1;
+		printf_debug("Trying whole-chip erase function... ");
+		ret = flash->erase(flash);
+	}
+	if (!found) {
+		fprintf(stderr, "ERROR: flashrom has no erase function for this flash chip.\n");
+		return 1;
+	}
+
+	if (ret) {
+		fprintf(stderr, "FAILED!\n");
+	} else {
+		printf("SUCCESS.\n");
+	}
+	return ret;
+}
+
+void emergency_help_message(void)
+{
+	fprintf(stderr, "Your flash chip is in an unknown state.\n"
+		"Get help on IRC at irc.freenode.net (channel #flashrom) or\n"
+		"mail flashrom@flashrom.org!\n--------------------"
+		"-----------------------------------------------------------\n"
+		"DO NOT REBOOT OR POWEROFF!\n");
+}
+
+void usage(const char *name)
+{
+	const char *pname;
+	int pnamelen;
+	int remaining = 0;
+	enum programmer p;
+
+	printf("usage: %s [-VfLzhR] [-E|-r file|-w file|-v file] [-c chipname]\n"
+              "       [-m [vendor:]part] [-l file] [-i image] [-p programmer]\n\n", name);
+
+	printf("Please note that the command line interface for flashrom will "
+		"change before\nflashrom 1.0. Do not use flashrom in scripts "
+		"or other automated tools without\nchecking that your flashrom"
+		" version won't interpret options in a different way.\n\n");
+
+	printf
+	    ("   -r | --read:                      read flash and save into file\n"
+	     "   -w | --write:                     write file into flash\n"
+	     "   -v | --verify:                    verify flash against file\n"
+	     "   -n | --noverify:                  don't verify flash against file\n"
+	     "   -E | --erase:                     erase flash device\n"
+	     "   -V | --verbose:                   more verbose output\n"
+	     "   -c | --chip <chipname>:           probe only for specified flash chip\n"
+	     "   -m | --mainboard <[vendor:]part>: override mainboard settings\n"
+	     "   -f | --force:                     force write without checking image\n"
+	     "   -l | --layout <file.layout>:      read ROM layout from file\n"
+	     "   -i | --image <name>:              only flash image name from flash layout\n"
+	     "   -L | --list-supported:            print supported devices\n"
+#if PRINT_WIKI_SUPPORT == 1
+	     "   -z | --list-supported-wiki:       print supported devices in wiki syntax\n"
+#endif
+	     "   -p | --programmer <name>:         specify the programmer device");
+
+	for (p = 0; p < PROGRAMMER_INVALID; p++) {
+		pname = programmer_table[p].name;
+		pnamelen = strlen(pname);
+		if (remaining - pnamelen - 2 < 0) {
+			printf("\n                                     ");
+			remaining = 43;
+		} else {
+			printf(" ");
+			remaining--;
+		}
+		if (p == 0) {
+			printf("(");
+			remaining--;
+		}
+		printf("%s", pname);
+		remaining -= pnamelen;
+		if (p < PROGRAMMER_INVALID - 1) {
+			printf(",");
+			remaining--;
+		} else {
+			printf(")\n");
+		}
+	}
+		
+	printf(
+	     "   -h | --help:                      print this help text\n"
+	     "   -R | --version:                   print the version (release)\n"
+	     "\nYou can specify one of -E, -r, -w, -v or no operation. If no operation is\n"
+	     "specified, then all that happens is that flash info is dumped.\n\n");
+	exit(1);
+}
+
+void print_version(void)
+{
+	printf("flashrom v%s\n", flashrom_version);
+}
+
+int main(int argc, char *argv[])
+{
+	uint8_t *buf;
+	unsigned long size, numbytes;
+	FILE *image;
+	/* Probe for up to three flash chips. */
+	struct flashchip *flash, *flashes[3];
+	const char *name;
+	int namelen;
+	int opt;
+	int option_index = 0;
+	int force = 0;
+	int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0;
+	int dont_verify_it = 0, list_supported = 0;
+#if PRINT_WIKI_SUPPORT == 1
+	int list_supported_wiki = 0;
+#endif
+	int operation_specified = 0;
+	int ret = 0, i;
+
+#if PRINT_WIKI_SUPPORT == 1
+	const char *optstring = "rRwvnVEfc:m:l:i:p:Lzh";
+#else
+	const char *optstring = "rRwvnVEfc:m:l:i:p:Lh";
+#endif
+	static struct option long_options[] = {
+		{"read", 0, 0, 'r'},
+		{"write", 0, 0, 'w'},
+		{"erase", 0, 0, 'E'},
+		{"verify", 0, 0, 'v'},
+		{"noverify", 0, 0, 'n'},
+		{"chip", 1, 0, 'c'},
+		{"mainboard", 1, 0, 'm'},
+		{"verbose", 0, 0, 'V'},
+		{"force", 0, 0, 'f'},
+		{"layout", 1, 0, 'l'},
+		{"image", 1, 0, 'i'},
+		{"list-supported", 0, 0, 'L'},
+#if PRINT_WIKI_SUPPORT == 1
+		{"list-supported-wiki", 0, 0, 'z'},
+#endif
+		{"programmer", 1, 0, 'p'},
+		{"help", 0, 0, 'h'},
+		{"version", 0, 0, 'R'},
+		{0, 0, 0, 0}
+	};
+
+	char *filename = NULL;
+
+	char *tempstr = NULL, *tempstr2 = NULL;
+
+	print_version();
+
+	if (argc > 1) {
+		/* Yes, print them. */
+		int i;
+		printf_debug("The arguments are:\n");
+		for (i = 1; i < argc; ++i)
+			printf_debug("%s\n", argv[i]);
+	}
+
+	/* Safety check. */
+	if (ARRAY_SIZE(programmer_table) - 1 != PROGRAMMER_INVALID) {
+		fprintf(stderr, "Programmer table miscompilation!\n");
+		exit(1);
+	}
+	if (spi_programmer_count - 1 != SPI_CONTROLLER_INVALID) {
+		fprintf(stderr, "SPI programmer table miscompilation!\n");
+		exit(1);
+	}
+#if BITBANG_SPI_SUPPORT == 1
+	if (bitbang_spi_master_count - 1 != BITBANG_SPI_INVALID) {
+		fprintf(stderr, "Bitbanging SPI master table miscompilation!\n");
+		exit(1);
+	}
+#endif
+
+	setbuf(stdout, NULL);
+	while ((opt = getopt_long(argc, argv, optstring,
+				  long_options, &option_index)) != EOF) {
+		switch (opt) {
+		case 'r':
+			if (++operation_specified > 1) {
+				fprintf(stderr, "More than one operation "
+					"specified. Aborting.\n");
+				exit(1);
+			}
+			read_it = 1;
+			break;
+		case 'w':
+			if (++operation_specified > 1) {
+				fprintf(stderr, "More than one operation "
+					"specified. Aborting.\n");
+				exit(1);
+			}
+			write_it = 1;
+			break;
+		case 'v':
+			//FIXME: gracefully handle superfluous -v
+			if (++operation_specified > 1) {
+				fprintf(stderr, "More than one operation "
+					"specified. Aborting.\n");
+				exit(1);
+			}
+			if (dont_verify_it) {
+				fprintf(stderr, "--verify and --noverify are"
+					"mutually exclusive. Aborting.\n");
+				exit(1);
+			}
+			verify_it = 1;
+			break;
+		case 'n':
+			if (verify_it) {
+				fprintf(stderr, "--verify and --noverify are"
+					"mutually exclusive. Aborting.\n");
+				exit(1);
+			}
+			dont_verify_it = 1;
+			break;
+		case 'c':
+			chip_to_probe = strdup(optarg);
+			break;
+		case 'V':
+			verbose = 1;
+			break;
+		case 'E':
+			if (++operation_specified > 1) {
+				fprintf(stderr, "More than one operation "
+					"specified. Aborting.\n");
+				exit(1);
+			}
+			erase_it = 1;
+			break;
+		case 'm':
+			tempstr = strdup(optarg);
+			strtok(tempstr, ":");
+			tempstr2 = strtok(NULL, ":");
+			if (tempstr2) {
+				lb_vendor = tempstr;
+				lb_part = tempstr2;
+			} else {
+				lb_vendor = NULL;
+				lb_part = tempstr;
+			}
+			break;
+		case 'f':
+			force = 1;
+			break;
+		case 'l':
+			tempstr = strdup(optarg);
+			if (read_romlayout(tempstr))
+				exit(1);
+			break;
+		case 'i':
+			tempstr = strdup(optarg);
+			find_romentry(tempstr);
+			break;
+		case 'L':
+			list_supported = 1;
+			break;
+#if PRINT_WIKI_SUPPORT == 1
+		case 'z':
+			list_supported_wiki = 1;
+			break;
+#endif
+		case 'p':
+			for (programmer = 0; programmer < PROGRAMMER_INVALID; programmer++) {
+				name = programmer_table[programmer].name;
+				namelen = strlen(name);
+				if (strncmp(optarg, name, namelen) == 0) {
+					switch (optarg[namelen]) {
+					case ':':
+						programmer_param = strdup(optarg + namelen + 1);
+						break;
+					case '\0':
+						break;
+					default:
+						/* The continue refers to the
+						 * for loop. It is here to be
+						 * able to differentiate between
+						 * foo and foobar.
+						 */
+						continue;
+					}
+					break;
+				}
+			}
+			if (programmer == PROGRAMMER_INVALID) {
+				printf("Error: Unknown programmer %s.\n", optarg);
+				exit(1);
+			}
+			break;
+		case 'R':
+			/* print_version() is always called during startup. */
+			exit(0);
+			break;
+		case 'h':
+		default:
+			usage(argv[0]);
+			break;
+		}
+	}
+
+	if (list_supported) {
+		print_supported();
+		exit(0);
+	}
+
+#if PRINT_WIKI_SUPPORT == 1
+	if (list_supported_wiki) {
+		print_supported_wiki();
+		exit(0);
+	}
+#endif
+
+	if (read_it && write_it) {
+		printf("Error: -r and -w are mutually exclusive.\n");
+		usage(argv[0]);
+	}
+
+	if (optind < argc)
+		filename = argv[optind++];
+	
+	if (optind < argc) {
+		printf("Error: Extra parameter found.\n");
+		usage(argv[0]);
+	}
+
+	if (programmer_init()) {
+		fprintf(stderr, "Error: Programmer initialization failed.\n");
+		exit(1);
+	}
+
+	myusec_calibrate_delay();
+
+	for (i = 0; i < ARRAY_SIZE(flashes); i++) {
+		flashes[i] =
+		    probe_flash(i ? flashes[i - 1] + 1 : flashchips, 0);
+		if (!flashes[i])
+			for (i++; i < ARRAY_SIZE(flashes); i++)
+				flashes[i] = NULL;
+	}
+
+	if (flashes[1]) {
+		printf("Multiple flash chips were detected:");
+		for (i = 0; i < ARRAY_SIZE(flashes) && flashes[i]; i++)
+			printf(" %s", flashes[i]->name);
+		printf("\nPlease specify which chip to use with the -c <chipname> option.\n");
+		programmer_shutdown();
+		exit(1);
+	} else if (!flashes[0]) {
+		printf("No EEPROM/flash device found.\n");
+		if (!force || !chip_to_probe) {
+			printf("If you know which flash chip you have, and if this version of flashrom\n");
+			printf("supports a similar flash chip, you can try to force read your chip. Run:\n");
+			printf("flashrom -f -r -c similar_supported_flash_chip filename\n");
+			printf("\n");
+			printf("Note: flashrom can never write when the flash chip isn't found automatically.\n");
+		}
+		if (force && read_it && chip_to_probe) {
+			printf("Force read (-f -r -c) requested, forcing chip probe success:\n");
+			flashes[0] = probe_flash(flashchips, 1);
+			if (!flashes[0]) {
+				printf("flashrom does not support a flash chip named '%s'.\n", chip_to_probe);
+				printf("Run flashrom -L to view the hardware supported in this flashrom version.\n");
+				exit(1);
+			}
+			printf("Please note that forced reads most likely contain garbage.\n");
+			return read_flash(flashes[0], filename);
+		}
+		// FIXME: flash writes stay enabled!
+		programmer_shutdown();
+		exit(1);
+	}
+
+	flash = flashes[0];
+
+	if (TEST_OK_MASK != (flash->tested & TEST_OK_MASK)) {
+		printf("===\n");
+		if (flash->tested & TEST_BAD_MASK) {
+			printf("This flash part has status NOT WORKING for operations:");
+			if (flash->tested & TEST_BAD_PROBE)
+				printf(" PROBE");
+			if (flash->tested & TEST_BAD_READ)
+				printf(" READ");
+			if (flash->tested & TEST_BAD_ERASE)
+				printf(" ERASE");
+			if (flash->tested & TEST_BAD_WRITE)
+				printf(" WRITE");
+			printf("\n");
+		}
+		if ((!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE)) ||
+		    (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ)) ||
+		    (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE)) ||
+		    (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))) {
+			printf("This flash part has status UNTESTED for operations:");
+			if (!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE))
+				printf(" PROBE");
+			if (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ))
+				printf(" READ");
+			if (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE))
+				printf(" ERASE");
+			if (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))
+				printf(" WRITE");
+			printf("\n");
+		}
+		printf("Please email a report to flashrom@flashrom.org if any "
+		       "of the above operations\nwork correctly for you with "
+		       "this flash part. Please include the flashrom\noutput "
+		       "with the additional -V option for all operations you "
+		       "tested (-V, -rV,\n-wV, -EV), and mention which "
+		       "mainboard you tested. Thanks for your help!\n===\n");
+	}
+
+	size = flash->total_size * 1024;
+	if (check_max_decode((buses_supported & flash->bustype), size) &&
+	    (!force)) {
+		fprintf(stderr, "Chip is too big for this programmer "
+			"(-V gives details). Use --force to override.\n");
+		programmer_shutdown();
+		return 1;
+	}
+
+	if (!(read_it | write_it | verify_it | erase_it)) {
+		printf("No operations were specified.\n");
+		// FIXME: flash writes stay enabled!
+		programmer_shutdown();
+		exit(1);
+	}
+
+	if (!filename && !erase_it) {
+		printf("Error: No filename specified.\n");
+		// FIXME: flash writes stay enabled!
+		programmer_shutdown();
+		exit(1);
+	}
+
+	/* Always verify write operations unless -n is used. */
+	if (write_it && !dont_verify_it)
+		verify_it = 1;
+
+	buf = (uint8_t *) calloc(size, sizeof(char));
+
+	if (erase_it) {
+		if (flash->tested & TEST_BAD_ERASE) {
+			fprintf(stderr, "Erase is not working on this chip. ");
+			if (!force) {
+				fprintf(stderr, "Aborting.\n");
+				programmer_shutdown();
+				return 1;
+			} else {
+				fprintf(stderr, "Continuing anyway.\n");
+			}
+		}
+		if (erase_flash(flash)) {
+			emergency_help_message();
+			programmer_shutdown();
+			return 1;
+		}
+	} else if (read_it) {
+		if (read_flash(flash, filename)) {
+			programmer_shutdown();
+			return 1;
+		}
+	} else {
+		struct stat image_stat;
+
+		if (flash->tested & TEST_BAD_ERASE) {
+			fprintf(stderr, "Erase is not working on this chip "
+				"and erase is needed for write. ");
+			if (!force) {
+				fprintf(stderr, "Aborting.\n");
+				programmer_shutdown();
+				return 1;
+			} else {
+				fprintf(stderr, "Continuing anyway.\n");
+			}
+		}
+		if (flash->tested & TEST_BAD_WRITE) {
+			fprintf(stderr, "Write is not working on this chip. ");
+			if (!force) {
+				fprintf(stderr, "Aborting.\n");
+				programmer_shutdown();
+				return 1;
+			} else {
+				fprintf(stderr, "Continuing anyway.\n");
+			}
+		}
+		if ((image = fopen(filename, "r")) == NULL) {
+			perror(filename);
+			programmer_shutdown();
+			exit(1);
+		}
+		if (fstat(fileno(image), &image_stat) != 0) {
+			perror(filename);
+			programmer_shutdown();
+			exit(1);
+		}
+		if (image_stat.st_size != flash->total_size * 1024) {
+			fprintf(stderr, "Error: Image size doesn't match\n");
+			programmer_shutdown();
+			exit(1);
+		}
+
+		numbytes = fread(buf, 1, size, image);
+		show_id(buf, size, force);
+		fclose(image);
+		if (numbytes != size) {
+			fprintf(stderr, "Error: Failed to read file. Got %ld bytes, wanted %ld!\n", numbytes, size);
+			programmer_shutdown();
+			return 1;
+		}
+	}
+
+	// This should be moved into each flash part's code to do it 
+	// cleanly. This does the job.
+	handle_romentries(buf, flash);
+
+	// ////////////////////////////////////////////////////////////
+
+	if (write_it) {
+		printf("Writing flash chip... ");
+		if (!flash->write) {
+			fprintf(stderr, "Error: flashrom has no write function for this flash chip.\n");
+			programmer_shutdown();
+			return 1;
+		}
+		ret = flash->write(flash, buf);
+		if (ret) {
+			fprintf(stderr, "FAILED!\n");
+			emergency_help_message();
+			programmer_shutdown();
+			return 1;
+		} else {
+			printf("COMPLETE.\n");
+		}
+	}
+
+	if (verify_it) {
+		/* Work around chips which need some time to calm down. */
+		if (write_it)
+			programmer_delay(1000*1000);
+		ret = verify_flash(flash, buf);
+		/* If we tried to write, and verification now fails, we
+		 * might have an emergency situation.
+		 */
+		if (ret && write_it)
+			emergency_help_message();
+	}
+
+	programmer_shutdown();
+
+	return ret;
+}
diff --git a/cli/layout.c b/cli/layout.c
new file mode 100644
index 0000000..7610466
--- /dev/null
+++ b/cli/layout.c
@@ -0,0 +1,229 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2005-2008 coresystems GmbH
+ * (Written by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH)
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "../libflashrom/flash.h"
+
+char *mainboard_vendor = NULL;
+char *mainboard_part = NULL;
+int romimages = 0;
+
+#define MAX_ROMLAYOUT	16
+
+typedef struct {
+	unsigned int start;
+	unsigned int end;
+	unsigned int included;
+	char name[256];
+} romlayout_t;
+
+romlayout_t rom_entries[MAX_ROMLAYOUT];
+
+static char *def_name = "DEFAULT";
+
+int show_id(uint8_t *bios, int size, int force)
+{
+	unsigned int *walk;
+	unsigned int mb_part_offset, mb_vendor_offset;
+	char *mb_part, *mb_vendor;
+
+	mainboard_vendor = def_name;
+	mainboard_part = def_name;
+
+	walk = (unsigned int *)(bios + size - 0x10);
+	walk--;
+
+	if ((*walk) == 0 || ((*walk) & 0x3ff) != 0) {
+		/* We might have an NVIDIA chipset BIOS which stores the ID
+		 * information at a different location.
+		 */
+		walk = (unsigned int *)(bios + size - 0x80);
+		walk--;
+	}
+
+	/*
+	 * Check if coreboot last image size is 0 or not a multiple of 1k or
+	 * bigger than the chip or if the pointers to vendor ID or mainboard ID
+	 * are outside the image of if the start of ID strings are nonsensical
+	 * (nonprintable and not \0).
+	 */
+	mb_part_offset = *(walk - 1);
+	mb_vendor_offset = *(walk - 2);
+	if ((*walk) == 0 || ((*walk) & 0x3ff) != 0 || (*walk) > size ||
+	    mb_part_offset > size || mb_vendor_offset > size) {
+		printf("Flash image seems to be a legacy BIOS. Disabling checks.\n");
+		return 0;
+	}
+
+	mb_part = (char *)(bios + size - mb_part_offset);
+	mb_vendor = (char *)(bios + size - mb_vendor_offset);
+	if (!isprint((unsigned char)*mb_part) ||
+	    !isprint((unsigned char)*mb_vendor)) {
+		printf("Flash image seems to have garbage in the ID location."
+		       " Disabling checks.\n");
+		return 0;
+	}
+
+	printf_debug("coreboot last image size "
+		     "(not ROM size) is %d bytes.\n", *walk);
+
+	mainboard_part = strdup(mb_part);
+	mainboard_vendor = strdup(mb_vendor);
+	printf_debug("Manufacturer: %s\n", mainboard_vendor);
+	printf_debug("Mainboard ID: %s\n", mainboard_part);
+
+	/*
+	 * If lb_vendor is not set, the coreboot table was
+	 * not found. Nor was -m VENDOR:PART specified.
+	 */
+	if (!lb_vendor || !lb_part) {
+		printf("Note: If the following flash access fails, "
+		       "try -m <vendor>:<mainboard>.\n");
+		return 0;
+	}
+
+	/* These comparisons are case insensitive to make things
+	 * a little less user^Werror prone. 
+	 */
+	if (!strcasecmp(mainboard_vendor, lb_vendor) &&
+	    !strcasecmp(mainboard_part, lb_part)) {
+		printf_debug("This firmware image matches this mainboard.\n");
+	} else {
+		if (force) {
+			printf("WARNING: This firmware image does not "
+			       "seem to fit to this machine - forcing it.\n");
+		} else {
+			printf("ERROR: Your firmware image (%s:%s) does not "
+			       "appear to\n       be correct for the detected "
+			       "mainboard (%s:%s)\n\nOverride with --force if you "
+			       "are absolutely sure that you\nare using a correct "
+			       "image for this mainboard or override\nthe detected "
+			       "values with --mainboard <vendor>:<mainboard>.\n\n",
+			       mainboard_vendor, mainboard_part, lb_vendor,
+			       lb_part);
+			exit(1);
+		}
+	}
+
+	return 0;
+}
+
+int read_romlayout(char *name)
+{
+	FILE *romlayout;
+	char tempstr[256];
+	int i;
+
+	romlayout = fopen(name, "r");
+
+	if (!romlayout) {
+		fprintf(stderr, "ERROR: Could not open ROM layout (%s).\n",
+			name);
+		return -1;
+	}
+
+	while (!feof(romlayout)) {
+		char *tstr1, *tstr2;
+		if (2 != fscanf(romlayout, "%s %s\n", tempstr, rom_entries[romimages].name))
+			continue;
+#if 0
+		// fscanf does not like arbitrary comments like that :( later
+		if (tempstr[0] == '#') {
+			continue;
+		}
+#endif
+		tstr1 = strtok(tempstr, ":");
+		tstr2 = strtok(NULL, ":");
+		if (!tstr1 || !tstr2) {
+			fprintf(stderr, "Error parsing layout file.\n");
+			fclose(romlayout);
+			return 1;
+		}
+		rom_entries[romimages].start = strtol(tstr1, (char **)NULL, 16);
+		rom_entries[romimages].end = strtol(tstr2, (char **)NULL, 16);
+		rom_entries[romimages].included = 0;
+		romimages++;
+	}
+
+	for (i = 0; i < romimages; i++) {
+		printf_debug("romlayout %08x - %08x named %s\n",
+			     rom_entries[i].start,
+			     rom_entries[i].end, rom_entries[i].name);
+	}
+
+	fclose(romlayout);
+
+	return 0;
+}
+
+int find_romentry(char *name)
+{
+	int i;
+
+	if (!romimages)
+		return -1;
+
+	printf("Looking for \"%s\"... ", name);
+
+	for (i = 0; i < romimages; i++) {
+		if (!strcmp(rom_entries[i].name, name)) {
+			rom_entries[i].included = 1;
+			printf("found.\n");
+			return i;
+		}
+	}
+	printf("not found.\n");	// Not found. Error.
+
+	return -1;
+}
+
+int handle_romentries(uint8_t *buffer, struct flashchip *flash)
+{
+	int i;
+
+	// This function does not save flash write cycles.
+	// 
+	// Also it does not cope with overlapping rom layout
+	// sections. 
+	// example:
+	// 00000000:00008fff gfxrom
+	// 00009000:0003ffff normal
+	// 00040000:0007ffff fallback
+	// 00000000:0007ffff all
+	//
+	// If you'd specify -i all the included flag of all other
+	// sections is still 0, so no changes will be made to the
+	// flash. Same thing if you specify -i normal -i all only 
+	// normal will be updated and the rest will be kept.
+
+	for (i = 0; i < romimages; i++) {
+
+		if (rom_entries[i].included)
+			continue;
+
+		flash->read(flash, buffer + rom_entries[i].start,
+			    rom_entries[i].start,
+			    rom_entries[i].end - rom_entries[i].start + 1);
+	}
+
+	return 0;
+}
diff --git a/cli/physmap.c b/cli/physmap.c
new file mode 100644
index 0000000..6b86ba6
--- /dev/null
+++ b/cli/physmap.c
@@ -0,0 +1,340 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Peter Stuge <peter@stuge.se>
+ * Copyright (C) 2009 coresystems GmbH
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "../libflashrom/flash.h"
+
+#ifdef __DARWIN__
+#include <DirectIO/darwinio.h>
+
+#define MEM_DEV "DirectIO"
+
+void *sys_physmap(unsigned long phys_addr, size_t len)
+{
+	return map_physical(phys_addr, len);
+}
+
+void physunmap(void *virt_addr, size_t len)
+{
+	unmap_physical(virt_addr, len);
+}
+
+#else
+#include <sys/mman.h>
+
+#if defined (__sun) && (defined(__i386) || defined(__amd64))
+#  define MEM_DEV "/dev/xsvc"
+#else
+#  define MEM_DEV "/dev/mem"
+#endif
+
+static int fd_mem = -1;
+
+void *sys_physmap(unsigned long phys_addr, size_t len)
+{
+	void *virt_addr;
+
+	if (-1 == fd_mem) {
+		/* Open the memory device UNCACHED. Important for MMIO. */
+		if (-1 == (fd_mem = open(MEM_DEV, O_RDWR | O_SYNC))) {
+			perror("Critical error: open(" MEM_DEV ")");
+			exit(2);
+		}
+	}
+
+	virt_addr = mmap(0, len, PROT_WRITE | PROT_READ, MAP_SHARED,
+			 fd_mem, (off_t)phys_addr);
+	return MAP_FAILED == virt_addr ? NULL : virt_addr;
+}
+
+void physunmap(void *virt_addr, size_t len)
+{
+	if (len == 0) {
+		printf_debug("Not unmapping zero size at %p\n", virt_addr);
+		return;
+	}
+		
+	munmap(virt_addr, len);
+}
+#endif
+
+void *physmap(const char *descr, unsigned long phys_addr, size_t len)
+{
+	void *virt_addr;
+
+	if (len == 0) {
+		printf_debug("Not mapping %s, zero size at 0x%08lx.\n",
+			     descr, phys_addr);
+		return NULL;
+	}
+		
+	if ((getpagesize() - 1) & len) {
+		fprintf(stderr, "Mapping %s at 0x%08lx, unaligned size 0x%lx.\n",
+			descr, phys_addr, (unsigned long)len);
+	}
+
+	if ((getpagesize() - 1) & phys_addr) {
+		fprintf(stderr, "Mapping %s, 0x%lx bytes at unaligned 0x%08lx.\n",
+			descr, (unsigned long)len, phys_addr);
+	}
+
+	virt_addr = sys_physmap(phys_addr, len);
+
+	if (NULL == virt_addr) {
+		if (NULL == descr)
+			descr = "memory";
+		fprintf(stderr, "Error accessing %s, 0x%lx bytes at 0x%08lx\n", descr, (unsigned long)len, phys_addr);
+		perror(MEM_DEV " mmap failed");
+		if (EINVAL == errno) {
+			fprintf(stderr, "In Linux this error can be caused by the CONFIG_NONPROMISC_DEVMEM (<2.6.27),\n");
+			fprintf(stderr, "CONFIG_STRICT_DEVMEM (>=2.6.27) and CONFIG_X86_PAT kernel options.\n");
+			fprintf(stderr, "Please check if either is enabled in your kernel before reporting a failure.\n");
+			fprintf(stderr, "You can override CONFIG_X86_PAT at boot with the nopat kernel parameter but\n");
+			fprintf(stderr, "disabling the other option unfortunately requires a kernel recompile. Sorry!\n");
+		}
+		exit(3);
+	}
+
+	return virt_addr;
+}
+
+#ifdef __linux__
+/*
+ * Reading and writing to MSRs, however requires instructions rdmsr/wrmsr,
+ * which are ring0 privileged instructions so only the kernel can do the
+ * read/write.  This function, therefore, requires that the msr kernel module
+ * be loaded to access these instructions from user space using device
+ * /dev/cpu/0/msr.
+ */
+
+static int fd_msr = -1;
+
+msr_t rdmsr(int addr)
+{
+	uint32_t buf[2];
+	msr_t msr = { 0xffffffff, 0xffffffff };
+
+	if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) {
+		perror("Could not lseek() to MSR");
+		close(fd_msr);
+		exit(1);
+	}
+
+	if (read(fd_msr, buf, 8) == 8) {
+		msr.lo = buf[0];
+		msr.hi = buf[1];
+
+		return msr;
+	}
+
+	if (errno != EIO) {
+		// A severe error.
+		perror("Could not read() MSR");
+		close(fd_msr);
+		exit(1);
+	}
+
+	return msr;
+}
+
+int wrmsr(int addr, msr_t msr)
+{
+	if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) {
+		perror("Could not lseek() to MSR");
+		close(fd_msr);
+		exit(1);
+	}
+
+	if (write(fd_msr, &msr, 8) != 8 && errno != EIO) {
+		perror("Could not write() MSR");
+		close(fd_msr);
+		exit(1);
+	}
+
+	/* some MSRs must not be written */
+	if (errno == EIO)
+		return -1;
+
+	return 0;
+}
+
+int setup_cpu_msr(int cpu)
+{
+	char msrfilename[64];
+	memset(msrfilename, 0, 64);
+	sprintf(msrfilename, "/dev/cpu/%d/msr", cpu);
+
+	if (fd_msr != -1) {
+		printf("MSR was already initialized\n");
+		return -1;
+	}
+
+	fd_msr = open(msrfilename, O_RDWR);
+
+	if (fd_msr < 0) {
+		perror("Error while opening /dev/cpu/0/msr");
+		printf("Did you run 'modprobe msr'?\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+void cleanup_cpu_msr(void)
+{
+	if (fd_msr == -1) {
+		printf("No MSR initialized.\n");
+		return;
+	}
+
+	close(fd_msr);
+
+	/* Clear MSR file descriptor */
+	fd_msr = -1;
+}
+#else
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+#include <sys/ioctl.h>
+
+typedef struct {
+	int msr;
+	uint64_t data;
+} cpu_msr_args_t;
+#define CPU_RDMSR _IOWR('c', 1, cpu_msr_args_t)
+#define CPU_WRMSR _IOWR('c', 2, cpu_msr_args_t)
+
+static int fd_msr = -1;
+
+msr_t rdmsr(int addr)
+{
+	cpu_msr_args_t args;
+
+	msr_t msr = { 0xffffffff, 0xffffffff };
+
+	args.msr = addr;
+
+	if (ioctl(fd_msr, CPU_RDMSR, &args) < 0) {
+		perror("CPU_RDMSR");
+		close(fd_msr);
+		exit(1);
+	}
+
+	msr.lo = args.data & 0xffffffff;
+	msr.hi = args.data >> 32;
+
+	return msr;
+}
+
+int wrmsr(int addr, msr_t msr)
+{
+	cpu_msr_args_t args;
+
+	args.msr = addr;
+	args.data = (((uint64_t)msr.hi) << 32) | msr.lo;
+
+	if (ioctl(fd_msr, CPU_WRMSR, &args) < 0) {
+		perror("CPU_WRMSR");
+		close(fd_msr);
+		exit(1);
+	}
+
+	return 0;
+}
+
+int setup_cpu_msr(int cpu)
+{
+	char msrfilename[64];
+	memset(msrfilename, 0, 64);
+	sprintf(msrfilename, "/dev/cpu%d", cpu);
+
+	if (fd_msr != -1) {
+		printf("MSR was already initialized\n");
+		return -1;
+	}
+
+	fd_msr = open(msrfilename, O_RDWR);
+
+	if (fd_msr < 0) {
+		perror("Error while opening /dev/cpu0");
+		printf("Did you install ports/sysutils/devcpu?\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+void cleanup_cpu_msr(void)
+{
+	if (fd_msr == -1) {
+		printf("No MSR initialized.\n");
+		return;
+	}
+
+	close(fd_msr);
+
+	/* Clear MSR file descriptor */
+	fd_msr = -1;
+}
+
+#else
+
+#ifdef __DARWIN__
+int setup_cpu_msr(int cpu)
+{
+	// Always succeed for now
+	return 0;
+}
+
+void cleanup_cpu_msr(void)
+{
+	// Nothing, yet.
+}
+#else
+msr_t rdmsr(int addr)
+{
+	msr_t ret = { 0xffffffff, 0xffffffff };
+
+	return ret;
+}
+
+int wrmsr(int addr, msr_t msr)
+{
+	return -1;
+}
+
+int setup_cpu_msr(int cpu)
+{
+	printf("No MSR support for your OS yet.\n");
+	return -1;
+}
+
+void cleanup_cpu_msr(void)
+{
+	// Nothing, yet.
+}
+#endif
+#endif
+#endif
+
diff --git a/cli/print.c b/cli/print.c
new file mode 100644
index 0000000..e887334
--- /dev/null
+++ b/cli/print.c
@@ -0,0 +1,397 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "../libflashrom/flash.h"
+#include "../libflashrom/flashchips.h"
+
+/*
+ * Return a string corresponding to the bustype parameter.
+ * Memory is obtained with malloc() and can be freed with free().
+ */
+char *flashbuses_to_text(enum chipbustype bustype)
+{
+	char *ret = calloc(1, 1);
+	if (bustype == CHIP_BUSTYPE_UNKNOWN) {
+		ret = strcat_realloc(ret, "Unknown,");
+	/*
+	 * FIXME: Once all chipsets and flash chips have been updated, NONSPI
+	 * will cease to exist and should be eliminated here as well.
+	 */
+	} else if (bustype == CHIP_BUSTYPE_NONSPI) {
+		ret = strcat_realloc(ret, "Non-SPI,");
+	} else {
+		if (bustype & CHIP_BUSTYPE_PARALLEL)
+			ret = strcat_realloc(ret, "Parallel,");
+		if (bustype & CHIP_BUSTYPE_LPC)
+			ret = strcat_realloc(ret, "LPC,");
+		if (bustype & CHIP_BUSTYPE_FWH)
+			ret = strcat_realloc(ret, "FWH,");
+		if (bustype & CHIP_BUSTYPE_SPI)
+			ret = strcat_realloc(ret, "SPI,");
+		if (bustype == CHIP_BUSTYPE_NONE)
+			ret = strcat_realloc(ret, "None,");
+	}
+	/* Kill last comma. */
+	ret[strlen(ret) - 1] = '\0';
+	ret = realloc(ret, strlen(ret) + 1);
+	return ret;
+}
+
+#define POS_PRINT(x) do { pos += strlen(x); printf(x); } while (0)
+
+static int digits(int n)
+{
+	int i;
+
+	if (!n)
+		return 1;
+
+	for (i = 0; n; ++i)
+		n /= 10;
+
+	return i;
+}
+
+void print_supported_chips(void)
+{
+	int okcol = 0, pos = 0, i, chipcount = 0;
+	struct flashchip *f;
+
+	for (f = flashchips; f->name != NULL; f++) {
+		if (GENERIC_DEVICE_ID == f->model_id)
+			continue;
+		okcol = max(okcol, strlen(f->vendor) + 1 + strlen(f->name));
+	}
+	okcol = (okcol + 7) & ~7;
+
+	for (f = flashchips; f->name != NULL; f++)
+		chipcount++;
+
+	printf("\nSupported flash chips (total: %d):\n\n", chipcount);
+	POS_PRINT("Vendor:   Device:");
+	while (pos < okcol) {
+		printf("\t");
+		pos += 8 - (pos % 8);
+	}
+
+	printf("Tested OK:\tKnown BAD:  Size/KB:  Type:\n\n");
+	printf("(P = PROBE, R = READ, E = ERASE, W = WRITE)\n\n");
+
+	for (f = flashchips; f->name != NULL; f++) {
+		/* Don't print "unknown XXXX SPI chip" entries. */
+		if (!strncmp(f->name, "unknown", 7))
+			continue;
+
+		printf("%s", f->vendor);
+		for (i = 0; i < 10 - strlen(f->vendor); i++)
+			printf(" ");
+		printf("%s", f->name);
+
+		pos = 10 + strlen(f->name);
+		while (pos < okcol) {
+			printf("\t");
+			pos += 8 - (pos % 8);
+		}
+		if ((f->tested & TEST_OK_MASK)) {
+			if ((f->tested & TEST_OK_PROBE))
+				POS_PRINT("P ");
+			if ((f->tested & TEST_OK_READ))
+				POS_PRINT("R ");
+			if ((f->tested & TEST_OK_ERASE))
+				POS_PRINT("E ");
+			if ((f->tested & TEST_OK_WRITE))
+				POS_PRINT("W ");
+		}
+		while (pos < okcol + 9) {
+			printf("\t");
+			pos += 8 - (pos % 8);
+		}
+		if ((f->tested & TEST_BAD_MASK)) {
+			if ((f->tested & TEST_BAD_PROBE))
+				printf("P ");
+			if ((f->tested & TEST_BAD_READ))
+				printf("R ");
+			if ((f->tested & TEST_BAD_ERASE))
+				printf("E ");
+			if ((f->tested & TEST_BAD_WRITE))
+				printf("W ");
+		}
+
+		printf("\t    %d", f->total_size);
+		for (i = 0; i < 10 - digits(f->total_size); i++)
+			printf(" ");
+		printf("%s\n", flashbuses_to_text(f->bustype));
+	}
+}
+
+void print_supported_chipsets(void)
+{
+	int i, j, chipsetcount = 0;
+	const struct penable *c = chipset_enables;
+
+	for (i = 0; c[i].vendor_name != NULL; i++)
+		chipsetcount++;
+
+	printf("\nSupported chipsets (total: %d):\n\nVendor:                  "
+	       "Chipset:                 PCI IDs:\n\n", chipsetcount);
+
+	for (i = 0; c[i].vendor_name != NULL; i++) {
+		printf("%s", c[i].vendor_name);
+		for (j = 0; j < 25 - strlen(c[i].vendor_name); j++)
+			printf(" ");
+		printf("%s", c[i].device_name);
+		for (j = 0; j < 25 - strlen(c[i].device_name); j++)
+			printf(" ");
+		printf("%04x:%04x%s\n", c[i].vendor_id, c[i].device_id,
+		       (c[i].status == OK) ? "" : " (untested)");
+	}
+}
+
+void print_supported_boards_helper(const struct board_info *b, const char *msg)
+{
+	int i, j, boardcount = 0;
+
+	for (i = 0; b[i].vendor != NULL; i++)
+		boardcount++;
+
+	printf("\n%s (total: %d):\n\n", msg, boardcount);
+
+	for (i = 0; b[i].vendor != NULL; i++) {
+		printf("%s", b[i].vendor);
+		for (j = 0; j < 25 - strlen(b[i].vendor); j++)
+			printf(" ");
+		printf("%s", b[i].name);
+		for (j = 0; j < 28 - strlen(b[i].name); j++)
+			printf(" ");
+		printf("\n");
+	}
+}
+
+void print_supported_boards(void)
+{
+	int i, j, boardcount = 0;
+	struct board_pciid_enable *b = board_pciid_enables;
+
+	for (i = 0; b[i].vendor_name != NULL; i++)
+		boardcount++;
+
+	printf("\nSupported boards which need write-enable code (total: %d):"
+	       "\n\nVendor:                  Board:                        "
+	       "Required option:\n\n", boardcount);
+
+	for (i = 0; b[i].vendor_name != NULL; i++) {
+		printf("%s", b[i].vendor_name);
+		for (j = 0; j < 25 - strlen(b[i].vendor_name); j++)
+			printf(" ");
+		printf("%s", b[i].board_name);
+		for (j = 0; j < 30 - strlen(b[i].board_name); j++)
+			printf(" ");
+		if (b[i].lb_vendor != NULL)
+			printf("-m %s:%s\n", b[i].lb_vendor, b[i].lb_part);
+		else
+			printf("(none, board is autodetected)\n");
+	}
+
+	print_supported_boards_helper(boards_ok,
+		"Supported boards which don't need write-enable code");
+	print_supported_boards_helper(boards_bad,
+		"Boards which have been verified to NOT work yet");
+	print_supported_boards_helper(laptops_ok,
+		"Laptops which have been verified to work");
+	print_supported_boards_helper(laptops_bad,
+		"Laptops which have been verified to NOT work yet");
+}
+
+void print_supported(void)
+{
+		print_supported_chips();
+		print_supported_chipsets();
+		print_supported_boards();
+		printf("\nSupported PCI devices flashrom can use "
+		       "as programmer:\n\n");
+#if NIC3COM_SUPPORT == 1
+		print_supported_pcidevs(nics_3com);
+#endif
+#if GFXNVIDIA_SUPPORT == 1
+		print_supported_pcidevs(gfx_nvidia);
+#endif
+#if DRKAISER_SUPPORT == 1
+		print_supported_pcidevs(drkaiser_pcidev);
+#endif
+#if SATASII_SUPPORT == 1
+		print_supported_pcidevs(satas_sii);
+#endif
+}
+
+
+/* Please keep this list alphabetically ordered by vendor/board. */
+const struct board_info boards_ok[] = {
+	/* Verified working boards that don't need write-enables. */
+	{ "Abit",		"AX8", },
+	{ "Abit",		"Fatal1ty F-I90HD", },
+	{ "Advantech",		"PCM-5820", },
+	{ "ASI",		"MB-5BLMP", },
+	{ "ASRock",		"A770CrossFire", },
+	{ "ASRock",		"K8S8X", },
+	{ "ASUS",		"A7N8X Deluxe", },
+	{ "ASUS",		"A7N8X-E Deluxe", },
+	{ "ASUS",		"A7V400-MX", },
+	{ "ASUS",		"A7V8X-MX", },
+	{ "ASUS",		"A8N-E", },
+	{ "ASUS",		"A8NE-FM/S", },
+	{ "ASUS",		"A8N-SLI", },
+	{ "ASUS",		"A8N-SLI Premium", },
+	{ "ASUS",		"A8V Deluxe", },
+	{ "ASUS",		"A8V-E Deluxe", },
+	{ "ASUS",		"A8V-E SE", },
+	{ "ASUS",		"K8V", },
+	{ "ASUS",		"K8V SE Deluxe", },
+	{ "ASUS",		"K8V-X SE", },
+	{ "ASUS",		"M2A-MX", },
+	{ "ASUS",		"M2A-VM", },
+	{ "ASUS",		"M2N-E", },
+	{ "ASUS",		"M2V", },
+	{ "ASUS",		"M3A78-EM", },
+	{ "ASUS",		"P2B", },
+	{ "ASUS",		"P2B-D", },
+	{ "ASUS",		"P2B-DS", },
+	{ "ASUS",		"P2B-F", },
+	{ "ASUS",		"P2L97-S", },
+	{ "ASUS",		"P5B-Deluxe", },
+	{ "ASUS",		"P5KC", },
+	{ "ASUS",		"P5L-MX", },
+	{ "ASUS",		"P6T Deluxe V2", },
+	{ "A-Trend",		"ATC-6220", },
+	{ "BCOM",		"WinNET100", },
+	{ "DFI",		"Blood-Iron P35 T2RL", },
+	{ "Elitegroup",		"K7S5A", },
+	{ "Elitegroup",		"P6VAP-A+", },
+	{ "GIGABYTE",		"GA-6BXC", },
+	{ "GIGABYTE",		"GA-6BXDU", },
+	{ "GIGABYTE",		"GA-6ZMA", },
+	{ "GIGABYTE",		"GA-7ZM", },
+	{ "GIGABYTE",		"GA-EP35-DS3L", },
+	{ "GIGABYTE",		"GA-EX58-UD4P", },
+	{ "GIGABYTE",		"GA-MA78GPM-DS2H", },
+	{ "GIGABYTE",		"GA-MA790GP-DS4H", },
+	{ "GIGABYTE",		"GA-MA770T-UD3P", },
+	{ "Intel",		"EP80759", },
+	{ "Jetway",		"J7F4K1G5D-PB", },
+	{ "MSI",                "MS-6153", },
+	{ "MSI",                "MS-6156", },
+	{ "MSI",		"MS-6570 (K7N2)", },
+	{ "MSI",		"MS-7065", },
+	{ "MSI",		"MS-7168 (Orion)", },
+	{ "MSI",		"MS-7236 (945PL Neo3)", },
+	{ "MSI",		"MS-7255 (P4M890M)", },
+	{ "MSI",		"MS-7345 (P35 Neo2-FIR)", },
+	{ "MSI",		"MS-7368 (K9AG Neo2-Digital)", },
+	{ "NEC",		"PowerMate 2000", },
+	{ "PC Engines",		"Alix.1c", },
+	{ "PC Engines",		"Alix.2c2", },
+	{ "PC Engines",		"Alix.2c3", },
+	{ "PC Engines",		"Alix.3c3", },
+	{ "PC Engines",		"Alix.3d3", },
+	{ "RCA",		"RM4100", },
+	{ "Sun",		"Blade x6250", },
+	{ "Supermicro",		"H8QC8", },
+	{ "Thomson",		"IP1000", },
+	{ "TriGem",		"Lomita", },
+	{ "T-Online",		"S-100", },
+	{ "Tyan",		"iS5375-1U", },
+	{ "Tyan",		"S1846", },
+	{ "Tyan",		"S2466", },
+	{ "Tyan",		"S2881", },
+	{ "Tyan",		"S2882", },
+	{ "Tyan",		"S2882-D", },
+	{ "Tyan",		"S2891", },
+	{ "Tyan",		"S2892", },
+	{ "Tyan",		"S2895", },
+	{ "Tyan",		"S3095", },
+	{ "Tyan",		"S5180", },
+	{ "Tyan",		"S5191", },
+	{ "Tyan",		"S5197", },
+	{ "Tyan",		"S5211", },
+	{ "Tyan",		"S5211-1U", },
+	{ "Tyan",		"S5220", },
+	{ "Tyan",		"S5375", },
+	{ "Tyan",		"S5376G2NR/S5376WAG2NR", },
+	{ "Tyan",		"S5377", },
+	{ "Tyan",		"S5397", },
+	{ "VIA",		"EPIA-EX15000G", },
+	{ "VIA",		"EPIA-LN", },
+	{ "VIA",		"EPIA-M700", },
+	{ "VIA",		"EPIA-NX15000G", },
+	{ "VIA",		"NAB74X0", },
+	{ "VIA",		"pc2500e", },
+	{ "VIA",		"VB700X", },
+
+	{},
+};
+
+/* Please keep this list alphabetically ordered by vendor/board. */
+const struct board_info boards_bad[] = {
+	/* Verified non-working boards (for now). */
+	{ "Abit",		"IS-10", },
+	{ "ASRock",		"K7VT4A+", },
+	{ "ASUS",		"MEW-AM", },
+	{ "ASUS",		"MEW-VM", },
+	{ "ASUS",		"P3B-F", },
+	{ "ASUS",		"P5B", },
+	{ "ASUS",		"P5BV-M", },
+	{ "Biostar",		"M6TBA", },
+	{ "Boser",		"HS-6637", },
+	{ "DFI",		"855GME-MGF", },
+	{ "FIC",		"VA-502", },
+	{ "MSI",		"MS-6178", },
+	{ "MSI",		"MS-7260 (K9N Neo)", },
+	{ "Soyo",		"SY-5VD", },
+	{ "Sun",		"Fire x4150", },
+	{ "Sun",		"Fire x4200", },
+	{ "Sun",		"Fire x4540", },
+	{ "Sun",		"Fire x4600", },
+
+	{},
+};
+
+/* Please keep this list alphabetically ordered by vendor/board. */
+const struct board_info laptops_ok[] = {
+	/* Verified working laptops. */
+	{ "Lenovo",		"3000 V100 TF05Cxx", },
+
+	{},
+};
+
+/* Please keep this list alphabetically ordered by vendor/board. */
+const struct board_info laptops_bad[] = {
+	/* Verified non-working laptops (for now). */
+	{ "Acer",		"Aspire One", },
+	{ "ASUS",		"Eee PC 701 4G", },
+	{ "Dell",		"Latitude CPi A366XT", },
+	{ "HP/Compaq",		"nx9010", },
+	{ "IBM/Lenovo",		"Thinkpad T40p", },
+	{ "IBM/Lenovo",		"240", },
+
+	{},
+};
+
diff --git a/cli/print_wiki.c b/cli/print_wiki.c
new file mode 100644
index 0000000..86f9510
--- /dev/null
+++ b/cli/print_wiki.c
@@ -0,0 +1,569 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include "../libflashrom/flash.h"
+#include "../libflashrom/flashchips.h"
+
+struct board_info_url {
+	const char *vendor;
+	const char *name;
+	const char *url;
+};
+
+struct board_info_notes {
+	const char *vendor;
+	const char *name;
+	const char *note;
+};
+
+const char *wiki_header = "= Supported devices =\n\n\
+<div style=\"margin-top:0.5em; padding:0.5em 0.5em 0.5em 0.5em; \
+background-color:#eeeeee; align:right; border:1px solid #aabbcc;\"><small>\n\
+Please do '''not''' edit these tables in the wiki directly, they are \
+generated by pasting '''flashrom -z''' output.<br />\
+'''Last update:''' %s(generated by flashrom %s)\n</small></div>\n";
+
+const char *chipset_th = "{| border=\"0\" style=\"font-size: smaller\"\n\
+|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\
+! align=\"left\" | Southbridge\n! align=\"left\" | PCI IDs\n\
+! align=\"left\" | Status\n\n";
+
+const char *board_th = "{| border=\"0\" style=\"font-size: smaller\" \
+valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\
+! align=\"left\" | Mainboard\n! align=\"left\" | Status\n\n";
+
+const char *board_th2 = "{| border=\"0\" style=\"font-size: smaller\" \
+valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\
+! align=\"left\" | Mainboard\n! align=\"left\" | Required option\n\
+! align=\"left\" | Status\n\n";
+
+const char *board_intro = "\
+\n== Supported mainboards ==\n\n\
+In general, it is very likely that flashrom works out of the box even if your \
+mainboard is not listed below.\n\nThis is a list of mainboards where we have \
+verified that they either do or do not need any special initialization to \
+make flashrom work (given flashrom supports the respective chipset and flash \
+chip), or that they do not yet work at all. If they do not work, support may \
+or may not be added later.\n\n\
+Mainboards which don't appear in the list may or may not work (we don't \
+know, someone has to give it a try). Please report any further verified \
+mainboards on the [[Mailinglist|mailing list]].\n";
+
+const char *chip_th = "{| border=\"0\" style=\"font-size: smaller\" \
+valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\
+! align=\"left\" | Device\n! align=\"left\" | Size / KB\n\
+! align=\"left\" | Type\n! align=\"left\" colspan=\"4\" | Status\n\n\
+|- bgcolor=\"#6699ff\"\n| colspan=\"4\" | &nbsp;\n\
+| Probe\n| Read\n| Write\n| Erase\n\n";
+
+const char *programmer_section = "\
+\n== Supported programmers ==\n\nThis is a list \
+of supported PCI devices flashrom can use as programmer:\n\n{| border=\"0\" \
+valign=\"top\"\n| valign=\"top\"|\n\n{| border=\"0\" style=\"font-size: \
+smaller\" valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\
+! align=\"left\" | Device\n! align=\"left\" | PCI IDs\n\
+! align=\"left\" | Status\n\n";
+
+const char *laptop_intro = "\n== Supported laptops/notebooks ==\n\n\
+In general, flashing laptops is more difficult because laptops\n\n\
+* often use the flash chip for stuff besides the BIOS,\n\
+* often have special protection stuff which has to be handled by flashrom,\n\
+* often use flash translation circuits which need drivers in flashrom.\n\n\
+<div style=\"margin-top:0.5em; padding:0.5em 0.5em 0.5em 0.5em; \
+background-color:#ff6666; align:right; border:1px solid #000000;\">\n\
+'''IMPORTANT:''' At this point we recommend to '''not''' use flashrom on \
+untested laptops unless you have a means to recover from a flashing that goes \
+wrong (a working backup flash chip and/or good soldering skills).\n</div>\n";
+
+/* Please keep these lists alphabetically ordered by vendor/board. */
+const struct board_info_url boards_url[] = {
+	/* Verified working boards that don't need write-enables. */
+	{ "Abit",		"AX8",			"http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?DEFTITLE=Y&fMTYPE=Socket%20939&pMODEL_NAME=AX8" },
+	{ "Abit",		"Fatal1ty F-I90HD",	"http://www.abit.com.tw/page/de/motherboard/motherboard_detail.php?pMODEL_NAME=Fatal1ty+F-I90HD&fMTYPE=LGA775" },
+	{ "Advantech",		"PCM-5820", 		"http://www.emacinc.com/sbc_pc_compatible/pcm_5820.htm" },
+	{ "ASI",		"MB-5BLMP",		"http://www.hojerteknik.com/winnet.htm" },
+	{ "ASRock",		"A770CrossFire",	"http://www.asrock.com/mb/overview.asp?Model=A770CrossFire&s=AM2\%2b" },
+	{ "ASRock",		"K8S8X",		"http://www.asrock.com/mb/overview.asp?Model=K8S8X" },
+	{ "ASUS",		"A7N8X Deluxe",		"http://www.asus.com/Product.aspx?P_ID=wAsRYm41KTp78MFC" },
+	{ "ASUS",		"A7N8X-E Deluxe",	"http://www.asus.com/products.aspx?l1=3&l2=13&l3=56&l4=0&model=217&modelmenu=1" },
+	{ "ASUS",		"A7V400-MX",		"http://www.asus.com.tw/products.aspx?l1=3&l2=13&l3=63&l4=0&model=228&modelmenu=1" },
+	{ "ASUS",		"A7V8X-MX",		"http://www.asus.com.tw/products.aspx?l1=3&l2=13&l3=64&l4=0&model=229&modelmenu=1" },
+	{ "ASUS",		"A8N-E",		"http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=171&l4=0&model=455&modelmenu=2" },
+	{ "ASUS",		"A8NE-FM/S",		"http://www.hardwareschotte.de/hardware/preise/proid_1266090/preis_ASUS+A8NE-FM" },
+	{ "ASUS",		"A8N-SLI",		"http://asus.com/product.aspx?P_ID=J9FKa8z2xVId3pDK" },
+	{ "ASUS",		"A8N-SLI Premium",	"http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=148&l4=0&model=539&modelmenu=1" },
+	{ "ASUS",		"A8V Deluxe",		"http://www.asus.com/product.aspx?P_ID=tvpdgPNCPaABZRVU" },
+	{ "ASUS",		"A8V-E Deluxe",		"http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=143&l4=0&model=376&modelmenu=1" },
+	{ "ASUS",		"A8V-E SE",		"http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=143&l4=0&model=576&modelmenu=1" },
+	{ "ASUS",		"K8V",			"http://www.asus.com/product.aspx?P_ID=fG2KZOWF7v6MRFRm" },
+	{ "ASUS",		"K8V SE Deluxe",	"http://www.asus.com/product.aspx?P_ID=65HeDI8XM1u6Uy6o" },
+	{ "ASUS",		"K8V-X SE",		"http://asus.com/product.aspx?P_ID=lzDXlbBVHkdckHVr" },
+	{ "ASUS",		"M2A-MX",		"http://www.asus.com/products.aspx?l1=3&l2=101&l3=583&l4=0&model=1909&modelmenu=1" },
+	{ "ASUS",		"M2A-VM",		"http://www.asus.com.tw/products.aspx?l1=3&l2=101&l3=496&l4=0&model=1568&modelmenu=1" },
+	{ "ASUS",		"M2N-E",		"http://www.asus.com/products.aspx?l1=3&l2=101&l3=308&l4=0&model=1181&modelmenu=1" },
+	{ "ASUS",		"M2V",			"http://asus.com/Product.aspx?P_ID=OqYlEDFfF6ZqZGvp" },
+	{ "ASUS",		"M3A78-EM",		"http://www.asus.com/product.aspx?P_ID=KjpYqzmAd9vsTM2D" },
+	{ "ASUS",		"P2B",			"http://www.motherboard.cz/mb/asus/P2B.htm" },
+	{ "ASUS",		"P2B-D",		"ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-d/" },
+	{ "ASUS",		"P2B-DS",		"ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-ds/" },
+	{ "ASUS",		"P2B-F",		"http://www.motherboard.cz/mb/asus/P2B-F.htm" },
+	{ "ASUS",		"P2L97-S",		"http://www.motherboard.cz/mb/asus/P2L97-S.htm" },
+	{ "ASUS",		"P5B-Deluxe",		"ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B-Deluxe/" },
+	{ "ASUS",		"P5KC",			"http://www.asus.com/product.aspx?P_ID=fFZ8oUIGmLpwNMjj" },
+	{ "ASUS",		"P5L-MX",		"http://www.asus.com/product.aspx?P_ID=X70d3NCzH2DE9vWH" },
+	{ "ASUS",		"P6T Deluxe V2",	"http://www.asus.com/product.aspx?P_ID=iRlP8RG9han6saZx" },
+	{ "A-Trend",		"ATC-6220",		"http://www.motherboard.cz/mb/atrend/atc6220.htm" },
+	{ "BCOM",		"WinNET100",		"http://www.coreboot.org/BCOM_WINNET100" },
+	{ "DFI",		"Blood-Iron P35 T2RL",	"http://lp.lanparty.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?itemId=516&downloadFlag=false&action=1" },
+	{ "Elitegroup",		"K7S5A",		"http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=279&CategoryID=1&DetailName=Specification&MenuID=1&LanID=0" },
+	{ "Elitegroup",		"P6VAP-A+",		"http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=117&CategoryID=1&DetailName=Specification&MenuID=1&LanID=0" },
+	{ "GIGABYTE",		"GA-6BXC",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ClassValue=Motherboard&ProductID=1445&ProductName=GA-6BXC" },
+	{ "GIGABYTE",		"GA-6BXDU",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1429" },
+	{ "GIGABYTE",		"GA-6ZMA",		"http://www.gigabyte.de/Support/Motherboard/BIOS_Model.aspx?ProductID=3289" },
+	{ "GIGABYTE",		"GA-EX58-UD4P",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Overview.aspx?ProductID=2986" },
+	{ "GIGABYTE",		"GA-EP35-DS3L",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Overview.aspx?ProductID=2778" },
+	{ "GIGABYTE",		"GA-MA790GP-DS4H",	"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2887" },
+	{ "GIGABYTE",		"GA-MA78GPM-DS2H",	"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2859" },
+	{ "GIGABYTE",		"GA-MA770T-UD3P",	"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=3096" },
+	{ "Intel",		"EP80759",		NULL },
+	{ "Jetway",		"J7F4K1G5D-PB",		"http://www.jetway.com.tw/jetway/system/productshow2.asp?id=389&proname=J7F4K1G5D-P" },
+	{ "MSI",		"MS-6153",		"http://www.msi.com/index.php?func=proddesc&maincat_no=1&cat2_no=&cat3_no=&prod_no=336" },
+	{ "MSI",		"MS-6156",		"http://uk.ts.fujitsu.com/rl/servicesupport/techsupport/boards/Motherboards/MicroStar/Ms6156/MS6156.htm" },
+	{ "MSI",		"MS-6570 (K7N2)",	"http://www.msi-computer.de/index.php?func=proddesc&prod_no=519&maincat_no=1" },
+	{ "MSI",		"MS-7065",		"http://browse.geekbench.ca/geekbench2/view/53114" },
+	{ "MSI",		"MS-7168 (Orion)",	"http://support.packardbell.co.uk/uk/item/index.php?i=spec_orion&pi=platform_honeymoon_istart" },
+	{ "MSI",		"MS-7236 (945PL Neo3)",	"http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=1173" },
+	{ "MSI",		"MS-7255 (P4M890M)",	"http://www.tcsbahamas.com/P4M89.htm" },
+	{ "MSI",		"MS-7345 (P35 Neo2-FIR)","http://www.msi.com/index.php?func=prodcpusupport&maincat_no=1&cat2_no=170&cat3_no=&prod_no=1261" },
+	{ "MSI",		"MS-7368 (K9AG Neo2-Digital)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=1241" },
+	{ "NEC",		"PowerMate 2000",	"http://support.necam.com/mobilesolutions/hardware/Desktops/pm2000/celeron/" },
+	{ "PC Engines",		"Alix.1c",		"http://pcengines.ch/alix1c.htm" },
+	{ "PC Engines",		"Alix.2c2",		"http://pcengines.ch/alix2c2.htm" },
+	{ "PC Engines",		"Alix.2c3",		"http://pcengines.ch/alix2c3.htm" },
+	{ "PC Engines",		"Alix.3c3",		"http://pcengines.ch/alix3c3.htm" },
+	{ "PC Engines",		"Alix.3d3",		"http://pcengines.ch/alix3d3.htm" },
+	{ "RCA",		"RM4100",		"http://www.settoplinux.org/index.php?title=RCA_RM4100" },
+	{ "Sun",		"Blade x6250",		"http://www.sun.com/servers/blades/x6250/" },
+	{ "Supermicro",		"H8QC8",		"http://www.supermicro.com/Aplus/motherboard/Opteron/nforce/H8QC8.cfm" },
+	{ "Thomson",		"IP1000",		"http://www.settoplinux.org/index.php?title=Thomson_IP1000" },
+	{ "TriGem",		"Lomita",		"http://www.e4allupgraders.info/dir1/motherboards/socket370/lomita.shtml" },
+	{ "T-Online",		"S-100",		"http://wiki.freifunk-hannover.de/T-Online_S_100" },
+	{ "Tyan",		"iS5375-1U",		"http://www.tyan.com/product_board_detail.aspx?pid=610" },
+	{ "Tyan",		"S1846",		"http://www.tyan.com/archive/products/html/tsunamiatx.html" },
+	{ "Tyan",		"S2466",		"http://www.tyan.com/product_board_detail.aspx?pid=461" },
+	{ "Tyan",		"S2881",		"http://www.tyan.com/product_board_detail.aspx?pid=115" },
+	{ "Tyan",		"S2882",		"http://www.tyan.com/product_board_detail.aspx?pid=121" },
+	{ "Tyan",		"S2882-D",		"http://www.tyan.com/product_board_detail.aspx?pid=127" },
+	{ "Tyan",		"S2891",		"http://www.tyan.com/product_board_detail.aspx?pid=144" },
+	{ "Tyan",		"S2892",		"http://www.tyan.com/product_board_detail.aspx?pid=145" },
+	{ "Tyan",		"S2895",		"http://www.tyan.com/archive/products/html/thunderk8we.html" },
+	{ "Tyan",		"S3095",		"http://www.tyan.com/product_board_detail.aspx?pid=181" },
+	{ "Tyan",		"S5180",		"http://www.tyan.com/product_board_detail.aspx?pid=456" },
+	{ "Tyan",		"S5191",		"http://www.tyan.com/product_board_detail.aspx?pid=343" },
+	{ "Tyan",		"S5197",		"http://www.tyan.com/product_board_detail.aspx?pid=349" },
+	{ "Tyan",		"S5211",		"http://www.tyan.com/product_board_detail.aspx?pid=591" },
+	{ "Tyan",		"S5211-1U",		"http://www.tyan.com/product_board_detail.aspx?pid=593" },
+	{ "Tyan",		"S5220",		"http://www.tyan.com/product_board_detail.aspx?pid=597" },
+	{ "Tyan",		"S5375",		"http://www.tyan.com/product_board_detail.aspx?pid=566" },
+	{ "Tyan",		"S5376G2NR/S5376WAG2NR","http://www.tyan.com/product_board_detail.aspx?pid=605" },
+	{ "Tyan",		"S5377",		"http://www.tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=642&SKU=600000017" },
+	{ "Tyan",		"S5397",		"http://www.tyan.com/product_board_detail.aspx?pid=560" },
+	{ "VIA",		"EPIA-EX15000G",	"http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=450" },
+	{ "VIA",		"EPIA-LN",		"http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=473" },
+	{ "VIA",		"EPIA-M700",		"http://via.com.tw/servlet/downloadSvl?motherboard_id=670&download_file_id=3700" },
+	{ "VIA",		"EPIA-NX15000G",	"http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=470" },
+	{ "VIA",		"NAB74X0",		"http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=590" },
+	{ "VIA",		"pc2500e",		"http://www.via.com.tw/en/initiatives/empowered/pc2500_mainboard/index.jsp" },
+	{ "VIA",		"VB700X",		"http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=490" },
+
+	/* Verified working boards that DO need write-enables. */
+	{ "Abit",		"IP35",			"http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?fMTYPE=LGA775&pMODEL_NAME=IP35" },
+	{ "Acorp",		"6A815EPD",		"http://web.archive.org/web/20021206163652/www.acorp.com.tw/English/default.asp" },
+	{ "agami",		"Aruma",		"http://web.archive.org/web/20080212111524/http://www.agami.com/site/ais-6000-series" },
+	{ "Albatron",		"PM266A Pro",		"http://www.albatron.com.tw/English/Product/MB/pro_detail.asp?rlink=Overview&no=56" }, /* FIXME */
+	{ "AOpen",		"vKM400Am-S",		"http://usa.aopen.com/products_detail.aspx?Auno=824" },
+	{ "Artec Group",	"DBE61",		"http://wiki.thincan.org/DBE61" },
+	{ "Artec Group",	"DBE62",		"http://wiki.thincan.org/DBE62" },
+	{ "ASUS",		"A7V600-X",		"http://www.asus.com/product.aspx?P_ID=L2XYS0rmtCjeOr4k" },
+	{ "ASUS",		"A7V8X",		"http://www.asus.com/product.aspx?P_ID=qfpaGrAy2kLVo0f2" },
+	{ "ASUS",		"A7V8X-MX SE",		"http://www.asus.com/product.aspx?P_ID=1guVBT1qV5oqhHyZ" },
+	{ "ASUS",		"P4B266",		"http://www.ciao.co.uk/ASUS_Intel_845D_Chipset_P4B266__5409807#productdetail" },
+	{ "ASUS",		"P4P800-E Deluxe",	"http://www.asus.com/product.aspx?P_ID=INIJUvLlif7LHp3g" },
+	{ "ASUS",		"P5ND2-SLI Deluxe",	"http://www.asus.com/product.aspx?P_ID=WY7XroDuUImVbgp5" },
+	{ "ASUS",		"P5A",			"ftp://ftp.asus.com.tw/pub/ASUS/mb/sock7/ali/p5a/" },
+	{ "Biostar",		"P4M80-M4",		"http://www.biostar-usa.com/mbdetails.asp?model=p4m80-m4" },
+	{ "Dell",		"PowerEdge 1850",	"http://support.dell.com/support/edocs/systems/pe1850/en/index.htm" },
+	{ "Elitegroup",		"K7VTA3",		"http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=264&CategoryID=1&DetailName=Specification&MenuID=52&LanID=0" },
+	{ "EPoX",		"EP-8K5A2",		"http://www.epox.com/product.asp?ID=EP-8K5A2" },
+	{ "EPoX",		"EP-8RDA3+",		"http://www.epox.com/product.asp?ID=EP-8RDA3plus" },
+	{ "EPoX",		"EP-BX3",		"http://www.epox.com/product.asp?ID=EP-BX3" },
+	{ "GIGABYTE",		"GA-2761GXDK",		"http://www.computerbase.de/news/hardware/mainboards/amd-systeme/2007/mai/gigabyte_dtx-mainboard/" },
+	{ "GIGABYTE",		"GA-7VT600",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1666" },
+	{ "GIGABYTE",		"GA-7ZM",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1366" },
+	{ "GIGABYTE",		"GA-K8N-SLI",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1928" },
+	{ "GIGABYTE",		"GA-M57SLI-S4",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Overview.aspx?ProductID=2287&ModelName=GA-M57SLI-S4" },
+	{ "GIGABYTE",		"GA-M61P-S3",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2434" },
+	{ "GIGABYTE",		"GA-MA78G-DS3H",	"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2800" }, /* TODO: Rev 1.x or 2.x? */
+	{ "GIGABYTE",		"GA-MA78GM-S2H",	"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2758" }, /* TODO: Rev. 1.0, 1.1, or 2.x? */
+	{ "GIGABYTE",		"GA-MA790FX-DQ6",	"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2690" },
+	{ "HP",			"DL145 G3",		"http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00816835&lang=en&cc=us&taskId=101&prodSeriesId=3219755&prodTypeId=15351" },
+	{ "IBM",		"x3455",		"http://www-03.ibm.com/systems/x/hardware/rack/x3455/index.html" },
+	{ "Intel",		"D201GLY",		"http://www.intel.com/support/motherboards/desktop/d201gly/index.htm" },
+	{ "IWILL",		"DK8-HTX",		"http://web.archive.org/web/20060507170150/http://www.iwill.net/product_2.asp?p_id=98" },
+	{ "Kontron",		"986LCD-M",		"http://de.kontron.com/products/boards+and+mezzanines/embedded+motherboards/miniitx+motherboards/986lcdmmitx.html" },
+	{ "Mitac",		"6513WU",		"http://web.archive.org/web/20050313054828/http://www.mitac.com/micweb/products/tyan/6513wu/6513wu.htm" },
+	{ "MSI",		"MS-6590 (KT4 Ultra)",	"http://www.msicomputer.com/product/p_spec.asp?model=KT4_Ultra&class=mb" },
+	{ "MSI",		"MS-6702E (K8T Neo2-F)","http://www.msicomputer.com/product/p_spec.asp?model=K8T_Neo2-F&class=mb" },
+	{ "MSI",		"MS-6712 (KT4V)",	"http://www.msi.com/index.php?func=proddesc&maincat_no=1&cat2_no=&cat3_no=&prod_no=505" },
+	{ "MSI",		"MS-7046",		"http://www.heimir.de/ms7046/" },
+	{ "MSI",		"MS-7135 (K8N Neo3)",	"http://www.msi-computer.de/index.php?func=proddesc&prod_no=170&maincat_no=1" },
+	{ "Shuttle",		"AK38N",		"http://eu.shuttle.com/en/desktopdefault.aspx/tabid-36/558_read-9889/" },
+	{ "Soyo",		"SY-7VCA",		"http://www.tomshardware.com/reviews/12-socket-370-motherboards,196-15.html" },
+	{ "Tyan",		"S2498 (Tomcat K7M)",	"http://www.tyan.com/archive/products/html/tomcatk7m.html" },
+	{ "VIA",		"EPIA-CN",		"http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=400" },
+	{ "VIA",		"EPIA M/MII/...",	"http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=202" }, /* EPIA-MII link for now */
+	{ "VIA",		"EPIA-N/NL",		"http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=221" }, /* EPIA-N link for now */
+	{ "VIA",		"EPIA SP",		"http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=261" },
+	{ "VIA",		"PC3500G",		"http://www.via.com.tw/en/initiatives/empowered/pc3500_mainboard/index.jsp" },
+ 
+	/* Verified non-working boards (for now). */
+	{ "Abit",		"IS-10",		"http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?pMODEL_NAME=IS-10&fMTYPE=Socket+478" },
+	{ "ASRock",		"K7VT4A+",		"http://www.asrock.com/mb/overview.asp?Model=K7VT4A%%2b&s=" },
+	{ "ASUS",		"MEW-AM",		"ftp://ftp.asus.com.tw/pub/ASUS/mb/sock370/810/mew-am/" },
+	{ "ASUS",		"MEW-VM",		"http://www.elhvb.com/mboards/OEM/HP/manual/ASUS%20MEW-VM.htm" },
+	{ "ASUS",		"P3B-F",		"ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p3b-f/" },
+	{ "ASUS",		"P5B",			"ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B/" },
+	{ "ASUS",		"P5BV-M",		"ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B-VM/" },
+	{ "Biostar",		"M6TBA",		"ftp://ftp.biostar-usa.com/manuals/M6TBA/" },
+	{ "Boser",		"HS-6637",		"http://www.boser.com.tw/manual/HS-62376637v3.4.pdf" },
+	{ "DFI",		"855GME-MGF",		"http://www.dfi.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?action=e&downloadType=&windowstate=normal&mode=view&downloadFlag=false&itemId=433" },
+	{ "FIC",		"VA-502",		"ftp://ftp.fic.com.tw/motherboard/manual/socket7/va-502/" },
+	{ "MSI",		"MS-6178",		"http://www.msi-technology.de/index.php?func=proddesc&prod_no=343&maincat_no=1" },
+	{ "MSI",		"MS-7260 (K9N Neo)",	"http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=255" },
+	{ "Soyo",		"SY-5VD",		"http://www.soyo.com/content/Downloads/163/&c=80&p=464&l=English" },
+	{ "Sun",		"Fire x4540",		"http://www.sun.com/servers/x64/x4540/" },
+	{ "Sun",		"Fire x4150",		"http://www.sun.com/servers/x64/x4150/" },
+	{ "Sun",		"Fire x4200",		"http://www.sun.com/servers/entry/x4200/" },
+	{ "Sun",		"Fire x4600",		"http://www.sun.com/servers/x64/x4600/" },
+
+	/* Verified working laptops. */
+	{ "Lenovo",		"3000 V100 TF05Cxx",	"http://www5.pc.ibm.com/europe/products.nsf/products?openagent&brand=Lenovo3000Notebook&series=Lenovo+3000+V+Series#viewallmodelstop" },
+
+	/* Verified non-working laptops (for now). */
+	{ "Acer",		"Aspire One",		NULL },
+	{ "ASUS",		"Eee PC 701 4G",	"http://www.asus.com/product.aspx?P_ID=h6SPd3tEzLEsrEiS" },
+	{ "Dell",		"Latitude CPi A366XT",	"http://www.coreboot.org/Dell_Latitude_CPi_A366XT" },
+	{ "HP/Compaq",		"nx9010",		"http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?lang=en&cc=us&objectID=c00348514" },
+	{ "IBM/Lenovo",		"Thinkpad T40p",	"http://www.thinkwiki.org/wiki/Category:T40p" },
+	{ "IBM/Lenovo",		"240",			"http://www.stanford.edu/~bresnan//tp240.html" },
+
+	{ NULL,			NULL,			0 },
+};
+
+/* Please keep these lists alphabetically ordered by vendor/board. */
+const struct board_info_notes boards_notes[] = {
+	/* Verified working boards that don't need write-enables. */
+	{ "ASI",		"MB-5BLMP",		"Used in the IGEL WinNET III thin client." },
+	{ "ASRock",		"K8S8X",		"The Super I/O isn't found on this board. See http://www.flashrom.org/pipermail/flashrom/2009-November/000937.html." },
+	{ "ASUS",		"A8V-E SE",		"See http://www.coreboot.org/pipermail/coreboot/2007-October/026496.html." },
+	{ "ASUS",		"M2A-VM",		"See http://www.coreboot.org/pipermail/coreboot/2007-September/025281.html." },
+	{ "BCOM",		"WinNET100",		"Used in the IGEL-316 thin client." },
+	{ "GIGABYTE",		"GA-7ZM",		"Works fine if you remove jumper JP9 on the board and disable the flash protection BIOS option." },
+	{ "ASUS",		"M2N-E",		"If the machine doesn't come up again after flashing, try resetting the NVRAM(CMOS). The MAC address of the onboard network card will change to the value stored in the new image, so backup the old address first. See http://www.flashrom.org/pipermail/flashrom/2009-November/000879.html" },
+
+	/* Verified working boards that DO need write-enables. */
+	{ "Acer",		"Aspire One",		"See http://www.coreboot.org/pipermail/coreboot/2009-May/048041.html." },
+
+	/* Verified non-working boards (for now). */
+	{ "MSI",		"MS-6178",		"Immediately powers off if you try to hot-plug the chip. However, this does '''not''' happen if you use coreboot." },
+	{ "MSI",		"MS-7260 (K9N Neo)",	"Interestingly flashrom does not work when the vendor BIOS is booted, but it ''does'' work flawlessly when the machine is booted with coreboot." },
+
+	/* Verified working laptops. */
+	/* None which need comments, yet... */
+
+	/* Verified non-working laptops (for now). */
+	{ "Acer",		"Aspire One",		"http://www.coreboot.org/pipermail/coreboot/2009-May/048041.html" },
+	{ "ASUS",		"Eee PC 701 4G",	"It seems the chip (25X40VSIG) is behind some SPI flash translation layer (likely in the EC, the ENE KB3310)." },
+	{ "Dell",		"Latitude CPi A366XT",	"The laptop immediately powers off if you try to hot-swap the chip. It's not yet tested if write/erase would work on this laptop." },
+	{ "HP/Compaq",		"nx9010",		"Hangs upon '''flashrom -V''' (needs hard power-cycle then)." },
+	{ "IBM/Lenovo",		"Thinkpad T40p",	"Seems to (partially) work at first, but one block/sector cannot be written which then leaves you with a bricked laptop. Maybe this can be investigated and fixed in software later." },
+
+	{ NULL,			NULL,			0 },
+};
+
+static int url(const char *vendor, const char *board)
+{
+	int i;
+	const struct board_info_url *b = boards_url;
+
+        for (i = 0; b[i].vendor != NULL; i++) {
+		if (!strcmp(vendor, b[i].vendor) && !strcmp(board, b[i].name))
+			return i;
+	}
+
+	return -1;
+}
+
+static int note(const char *vendor, const char *board)
+{
+	int i;
+	const struct board_info_notes *n = boards_notes;
+
+        for (i = 0; n[i].vendor != NULL; i++) {
+		if (!strcmp(vendor, n[i].vendor) && !strcmp(board, n[i].name))
+			return i;
+	}
+
+	return -1;
+}
+
+void print_supported_chipsets_wiki(void)
+{
+	int i, j, enablescount = 0, color = 1;
+	const struct penable *e;
+
+	for (e = chipset_enables; e->vendor_name != NULL; e++)
+		enablescount++;
+
+	printf("\n== Supported chipsets ==\n\nTotal amount of supported "
+	       "chipsets: '''%d'''\n\n{| border=\"0\" valign=\"top\"\n| "
+	       "valign=\"top\"|\n\n%s", enablescount, chipset_th);
+
+	e = chipset_enables;
+	for (i = 0, j = 0; e[i].vendor_name != NULL; i++, j++) {
+		/* Alternate colors if the vendor changes. */
+		if (i > 0 && strcmp(e[i].vendor_name, e[i - 1].vendor_name))
+			color = !color;
+
+		printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s "
+		       "|| %04x:%04x || %s\n", (color) ? "eeeeee" : "dddddd",
+		       e[i].vendor_name, e[i].device_name,
+		       e[i].vendor_id, e[i].device_id,
+		       (e[i].status == OK) ? "{{OK}}" : "?");
+
+		/* Split table in three columns. */
+		if (j >= (enablescount / 3 + 1)) {
+			printf("\n|}\n\n| valign=\"top\"|\n\n%s", chipset_th);
+			j = 0;
+		}
+	}
+
+	printf("\n|}\n\n|}\n");
+}
+
+static void wiki_helper(const char *heading, const char *status,
+			int cols, const struct board_info boards[])
+{
+	int i, j, k, c, boardcount = 0, color = 1, num_notes = 0;
+	const struct board_info *b;
+	const struct board_info_url *u = boards_url;
+	char *notes = calloc(1, 1);
+	char tmp[900 + 1];
+
+	for (b = boards; b->vendor != NULL; b++)
+		boardcount++;
+
+	printf("\n'''%s'''\n\nTotal amount of boards: '''%d'''\n\n"
+	       "{| border=\"0\" valign=\"top\"\n| valign=\"top\"|\n\n%s",
+	       heading, boardcount, board_th);
+
+        for (i = 0, j = 0, b = boards; b[i].vendor != NULL; i++, j++) {
+		/* Alternate colors if the vendor changes. */
+		if (i > 0 && strcmp(b[i].vendor, b[i - 1].vendor))
+			color = !color;
+
+		k = url(b[i].vendor, b[i].name);
+		c = note(b[i].vendor, b[i].name);
+
+		printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s%s %s%s ||"
+		       " {{%s}}", (color) ? "eeeeee" : "dddddd", b[i].vendor,
+		       (k != -1 && u[k].url) ? "[" : "",
+		       (k != -1 && u[k].url) ? u[k].url : "",
+		       b[i].name, (k != -1 && u[k].url) ? "]" : "", status);
+
+		if (c != -1) {
+			printf("<sup>%d</sup>\n", num_notes + 1);
+			snprintf((char *)&tmp, 900, "<sup>%d</sup> %s<br />\n",
+				 1 + num_notes++, boards_notes[c].note);
+			notes = strcat_realloc(notes, (char *)&tmp);
+		} else {
+			printf("\n");
+		}
+
+		/* Split table in 'cols' columns. */
+		if (j >= (boardcount / cols + 1)) {
+			printf("\n|}\n\n| valign=\"top\"|\n\n%s", board_th);
+			j = 0;
+		}
+	}
+
+	printf("\n|}\n\n|}\n");
+
+	if (num_notes > 0)
+		printf("\n<small>\n%s</small>\n", notes);
+	free(notes);
+}
+
+static void wiki_helper2(const char *heading, int cols)
+{
+	int i, j, k, boardcount = 0, color = 1;
+	struct board_pciid_enable *b;
+	const struct board_info_url *u = boards_url;
+
+	for (b = board_pciid_enables; b->vendor_name != NULL; b++)
+		boardcount++;
+
+	printf("\n'''%s'''\n\nTotal amount of boards: '''%d'''\n\n"
+	       "{| border=\"0\" valign=\"top\"\n| valign=\"top\"|\n\n%s",
+	       heading, boardcount, board_th2);
+
+	b = board_pciid_enables;
+	for (i = 0, j = 0; b[i].vendor_name != NULL; i++, j++) {
+		/* Alternate colors if the vendor changes. */
+		if (i > 0 && strcmp(b[i].vendor_name, b[i - 1].vendor_name))
+			color = !color;
+
+		k = url(b[i].vendor_name, b[i].board_name);
+
+		printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s%s %s%s "
+		       "|| %s%s%s%s || {{OK}}\n", (color) ? "eeeeee" : "dddddd",
+		       b[i].vendor_name, (k != -1 && u[k].url) ? "[" : "",
+		       (k != -1 && u[k].url) ? u[k].url : "", b[i].board_name,
+		       (k != -1 && u[k].url) ? "]" : "",
+		       (b[i].lb_vendor) ? "-m " : "&mdash;",
+		       (b[i].lb_vendor) ? b[i].lb_vendor : "",
+		       (b[i].lb_vendor) ? ":" : "",
+		       (b[i].lb_vendor) ? b[i].lb_part : "");
+
+		/* Split table in three columns. */
+		if (j >= (boardcount / cols + 1)) {
+			printf("\n|}\n\n| valign=\"top\"|\n\n%s", board_th2);
+			j = 0;
+		}
+	}
+
+	printf("\n|}\n\n|}\n");
+}
+
+void print_supported_boards_wiki(void)
+{
+	printf("%s", board_intro);
+	wiki_helper("Known good (worked out of the box)", "OK", 3, boards_ok);
+	wiki_helper2("Known good (with write-enable code in flashrom)", 3);
+	wiki_helper("Not supported (yet)", "No", 3, boards_bad);
+
+	printf("%s", laptop_intro);
+	wiki_helper("Known good (worked out of the box)", "OK", 1, laptops_ok);
+	wiki_helper("Not supported (yet)", "No", 1, laptops_bad);
+}
+
+void print_supported_chips_wiki(void)
+{
+	int i = 0, c = 1, chipcount = 0;
+	struct flashchip *f, *old = NULL;
+	uint32_t t;
+
+	for (f = flashchips; f->name != NULL; f++)
+		chipcount++;
+
+	printf("\n== Supported chips ==\n\nTotal amount of supported "
+	       "chips: '''%d'''\n\n{| border=\"0\" valign=\"top\"\n"
+		"| valign=\"top\"|\n\n%s", chipcount, chip_th);
+
+	for (f = flashchips; f->name != NULL; f++, i++) {
+		/* Don't print "unknown XXXX SPI chip" entries. */
+		if (!strncmp(f->name, "unknown", 7))
+			continue;
+
+		/* Alternate colors if the vendor changes. */
+		if (old != NULL && strcmp(old->vendor, f->vendor))
+			c = !c;
+
+		t = f->tested;
+		printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s || %d "
+		       "|| %s || {{%s}} || {{%s}} || {{%s}} || {{%s}}\n",
+		       (c == 1) ? "eeeeee" : "dddddd", f->vendor, f->name,
+		       f->total_size, flashbuses_to_text(f->bustype),
+		       (t & TEST_OK_PROBE) ? "OK" :
+		       (t & TEST_BAD_PROBE) ? "No" : ((c) ? "?2" : "?"),
+		       (t & TEST_OK_READ) ? "OK" :
+		       (t & TEST_BAD_READ) ? "No" : ((c) ? "?2" : "?"),
+		       (t & TEST_OK_ERASE) ? "OK" :
+		       (t & TEST_BAD_ERASE) ? "No" : ((c) ? "?2" : "?"),
+		       (t & TEST_OK_WRITE) ? "OK" :
+		       (t & TEST_BAD_WRITE) ? "No" : ((c) ? "?2" : "?"));
+
+		/* Split table into three columns. */
+		if (i >= (chipcount / 3 + 1)) {
+			printf("\n|}\n\n| valign=\"top\"|\n\n%s", chip_th);
+			i = 0;
+		}
+
+		old = f;
+	}
+
+	printf("\n|}\n\n|}\n");
+}
+
+void print_supported_pcidevs_wiki(struct pcidev_status *devs)
+{
+	int i = 0;
+	static int c = 0;
+
+	/* Alternate colors if the vendor changes. */
+	c = !c;
+
+	for (i = 0; devs[i].vendor_name != NULL; i++) {
+		printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s || "
+		       "%04x:%04x || {{%s}}\n", (c) ? "eeeeee" : "dddddd",
+		       devs[i].vendor_name, devs[i].device_name,
+		       devs[i].vendor_id, devs[i].device_id,
+		       (devs[i].status == PCI_NT) ? (c) ? "?2" : "?" : "OK");
+	}
+}
+
+void print_supported_wiki(void)
+{
+	time_t t = time(NULL);
+
+	printf(wiki_header, ctime(&t), flashrom_version);
+	print_supported_chips_wiki();
+	print_supported_chipsets_wiki();
+	print_supported_boards_wiki();
+	printf("%s", programmer_section);
+#if NIC3COM_SUPPORT == 1
+	print_supported_pcidevs_wiki(nics_3com);
+#endif
+#if GFXNVIDIA_SUPPORT == 1
+	print_supported_pcidevs_wiki(gfx_nvidia);
+#endif
+#if DRKAISER_SUPPORT == 1
+	print_supported_pcidevs_wiki(drkaiser_pcidev);
+#endif
+#if SATASII_SUPPORT == 1
+	print_supported_pcidevs_wiki(satas_sii);
+#endif
+	printf("\n|}\n");
+}
+
diff --git a/cli/udelay.c b/cli/udelay.c
new file mode 100644
index 0000000..bebe122
--- /dev/null
+++ b/cli/udelay.c
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <sys/time.h>
+#include "../libflashrom/flash.h"
+
+// count to a billion. Time it. If it's < 1 sec, count to 10B, etc.
+unsigned long micro = 1;
+
+void myusec_delay(int usecs)
+{
+	volatile unsigned long i;
+	for (i = 0; i < usecs * micro; i++) ;
+}
+
+void myusec_calibrate_delay(void)
+{
+	int count = 1000;
+	unsigned long timeusec;
+	struct timeval start, end;
+	int ok = 0;
+
+	printf("Calibrating delay loop... ");
+
+	while (!ok) {
+		gettimeofday(&start, 0);
+		myusec_delay(count);
+		gettimeofday(&end, 0);
+		timeusec = 1000000 * (end.tv_sec - start.tv_sec) +
+		    (end.tv_usec - start.tv_usec);
+		count *= 2;
+		if (timeusec < 1000000 / 4)
+			continue;
+		ok = 1;
+	}
+
+	// compute one microsecond. That will be count / time
+	micro = count / timeusec;
+
+	gettimeofday(&start, 0);
+	myusec_delay(100);
+	gettimeofday(&end, 0);
+	timeusec = 1000000 * (end.tv_sec - start.tv_sec) +
+	    (end.tv_usec - start.tv_usec);
+	printf_debug("%ldM loops per second, 100 myus = %ld us. ",
+		     (unsigned long)micro, timeusec);
+	printf("OK.\n");
+}
diff --git a/coreboot_tables.h b/coreboot_tables.h
deleted file mode 100644
index 6944559..0000000
--- a/coreboot_tables.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2002 Linux Networx
- * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx)
- * Copyright (C) 2005-2007 coresystems GmbH
- *
- * 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; version 2 of the License.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
- */
-
-#ifndef COREBOOT_TABLES_H
-#define COREBOOT_TABLES_H
-
-#include <stdint.h>
-
-/* The coreboot table information is for conveying information
- * from the firmware to the loaded OS image.  Primarily this
- * is expected to be information that cannot be discovered by
- * other means, such as quering the hardware directly.
- *
- * All of the information should be Position Independent Data.  
- * That is it should be safe to relocated any of the information
- * without it's meaning/correctnes changing.   For table that
- * can reasonably be used on multiple architectures the data
- * size should be fixed.  This should ease the transition between
- * 32 bit and 64 bit architectures etc.
- *
- * The completeness test for the information in this table is:
- * - Can all of the hardware be detected?
- * - Are the per motherboard constants available?
- * - Is there enough to allow a kernel to run that was written before
- *   a particular motherboard is constructed? (Assuming the kernel
- *   has drivers for all of the hardware but it does not have
- *   assumptions on how the hardware is connected together).
- *
- * With this test it should be straight forward to determine if a
- * table entry is required or not.  This should remove much of the
- * long term compatibility burden as table entries which are
- * irrelevant or have been replaced by better alternatives may be
- * dropped.  Of course it is polite and expidite to include extra
- * table entries and be backwards compatible, but it is not required.
- */
-
-/* Since coreboot is usually compiled 32bit, gcc will align 64bit 
- * types to 32bit boundaries. If the coreboot table is dumped on a 
- * 64bit system, a uint64_t would be aligned to 64bit boundaries, 
- * breaking the table format.
- *
- * lb_uint64 will keep 64bit coreboot table values aligned to 32bit
- * to ensure compatibility. They can be accessed with the two functions
- * below: unpack_lb64() and pack_lb64()
- *
- * See also: util/lbtdump/lbtdump.c
- */
-
-struct lb_uint64 {
-	uint32_t lo;
-	uint32_t hi;
-};
-
-struct lb_header {
-	uint8_t signature[4];	/* LBIO */
-	uint32_t header_bytes;
-	uint32_t header_checksum;
-	uint32_t table_bytes;
-	uint32_t table_checksum;
-	uint32_t table_entries;
-};
-
-/* Every entry in the boot enviroment list will correspond to a boot
- * info record.  Encoding both type and size.  The type is obviously
- * so you can tell what it is.  The size allows you to skip that
- * boot enviroment record if you don't know what it easy.  This allows
- * forward compatibility with records not yet defined.
- */
-struct lb_record {
-	uint32_t tag;		/* tag ID */
-	uint32_t size;		/* size of record (in bytes) */
-};
-
-#define LB_TAG_UNUSED	0x0000
-
-#define LB_TAG_MEMORY	0x0001
-
-struct lb_memory_range {
-	struct lb_uint64 start;
-	struct lb_uint64 size;
-	uint32_t type;
-#define LB_MEM_RAM       1	/* Memory anyone can use */
-#define LB_MEM_RESERVED  2	/* Don't use this memory region */
-#define LB_MEM_TABLE     16	/* Ram configuration tables are kept in */
-};
-
-struct lb_memory {
-	uint32_t tag;
-	uint32_t size;
-	struct lb_memory_range map[0];
-};
-
-#define LB_TAG_HWRPB	0x0002
-struct lb_hwrpb {
-	uint32_t tag;
-	uint32_t size;
-	uint64_t hwrpb;
-};
-
-#define LB_TAG_MAINBOARD	0x0003
-struct lb_mainboard {
-	uint32_t tag;
-	uint32_t size;
-	uint8_t vendor_idx;
-	uint8_t part_number_idx;
-	uint8_t strings[0];
-};
-
-#define LB_TAG_VERSION		0x0004
-#define LB_TAG_EXTRA_VERSION	0x0005
-#define LB_TAG_BUILD		0x0006
-#define LB_TAG_COMPILE_TIME	0x0007
-#define LB_TAG_COMPILE_BY	0x0008
-#define LB_TAG_COMPILE_HOST	0x0009
-#define LB_TAG_COMPILE_DOMAIN	0x000a
-#define LB_TAG_COMPILER		0x000b
-#define LB_TAG_LINKER		0x000c
-#define LB_TAG_ASSEMBLER	0x000d
-struct lb_string {
-	uint32_t tag;
-	uint32_t size;
-	uint8_t string[0];
-};
-
-#define LB_TAG_FORWARD		0x0011
-struct lb_forward {
-	uint32_t tag;
-	uint32_t size;
-	uint64_t forward;
-};
-
-#endif				/* COREBOOT_TABLES_H */
diff --git a/drkaiser.c b/drkaiser.c
deleted file mode 100644
index f13c13e..0000000
--- a/drkaiser.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Joerg Fischer <turboj@web.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include "flash.h"
-
-#define PCI_VENDOR_ID_DRKAISER		0x1803
-
-#define PCI_MAGIC_DRKAISER_ADDR		0x50
-#define PCI_MAGIC_DRKAISER_VALUE	0xa971
-
-struct pcidev_status drkaiser_pcidev[] = {
-	{0x1803, 0x5057, PCI_OK, "Dr. Kaiser", "PC-Waechter (Actel FPGA)"},
-	{},
-};
-
-uint8_t *drkaiser_bar;
-
-int drkaiser_init(void)
-{
-	uint32_t addr;
-
-	get_io_perms();
-	pcidev_init(PCI_VENDOR_ID_DRKAISER, PCI_BASE_ADDRESS_2,
-		    drkaiser_pcidev, programmer_param);
-
-	/* Write magic register to enable flash write. */
-	pci_write_word(pcidev_dev, PCI_MAGIC_DRKAISER_ADDR,
-		       PCI_MAGIC_DRKAISER_VALUE);
-
-	/* TODO: Mask lower bits? How many? 3? 7? */
-	addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_2) & ~0x03;
-
-	/* Map 128KB flash memory window. */
-	drkaiser_bar = physmap("Dr. Kaiser PC-Waechter flash memory",
-			       addr, 128 * 1024);
-
-	buses_supported = CHIP_BUSTYPE_PARALLEL;
-	return 0;
-}
-
-int drkaiser_shutdown(void)
-{
-	/* Write protect the flash again. */
-	pci_write_word(pcidev_dev, PCI_MAGIC_DRKAISER_ADDR, 0);
-	free(programmer_param);
-	pci_cleanup(pacc);
-	release_io_perms();
-	return 0;
-};
-
-void drkaiser_chip_writeb(uint8_t val, chipaddr addr)
-{
-	mmio_writeb(val, drkaiser_bar + addr);
-}
-
-uint8_t drkaiser_chip_readb(const chipaddr addr)
-{
-	return mmio_readb(drkaiser_bar + addr);
-}
diff --git a/dummyflasher.c b/dummyflasher.c
deleted file mode 100644
index 903f88b..0000000
--- a/dummyflasher.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Carl-Daniel Hailfinger
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include "flash.h"
-
-int dummy_init(void)
-{
-	int i;
-	printf_debug("%s\n", __func__);
-
-	/* "all" is equivalent to specifying no type. */
-	if (programmer_param && (!strcmp(programmer_param, "all"))) {
-		free(programmer_param);
-		programmer_param = NULL;
-	}
-	if (!programmer_param)
-		programmer_param = strdup("parallel,lpc,fwh,spi");
-	/* Convert the parameters to lowercase. */
-	for (i = 0; programmer_param[i] != '\0'; i++)
-		programmer_param[i] = (char)tolower(programmer_param[i]);
-
-	buses_supported = CHIP_BUSTYPE_NONE;
-	if (strstr(programmer_param, "parallel")) {
-		buses_supported |= CHIP_BUSTYPE_PARALLEL;
-		printf_debug("Enabling support for %s flash.\n", "parallel");
-	}
-	if (strstr(programmer_param, "lpc")) {
-		buses_supported |= CHIP_BUSTYPE_LPC;
-		printf_debug("Enabling support for %s flash.\n", "LPC");
-	}
-	if (strstr(programmer_param, "fwh")) {
-		buses_supported |= CHIP_BUSTYPE_FWH;
-		printf_debug("Enabling support for %s flash.\n", "FWH");
-	}
-	if (strstr(programmer_param, "spi")) {
-		buses_supported |= CHIP_BUSTYPE_SPI;
-		spi_controller = SPI_CONTROLLER_DUMMY;
-		printf_debug("Enabling support for %s flash.\n", "SPI");
-	}
-	if (buses_supported == CHIP_BUSTYPE_NONE)
-		printf_debug("Support for all flash bus types disabled.\n");
-	free(programmer_param);
-	return 0;
-}
-
-int dummy_shutdown(void)
-{
-	printf_debug("%s\n", __func__);
-	return 0;
-}
-
-void *dummy_map(const char *descr, unsigned long phys_addr, size_t len)
-{
-	printf_debug("%s: Mapping %s, 0x%lx bytes at 0x%08lx\n",
-		__func__, descr, (unsigned long)len, phys_addr);
-	return (void *)phys_addr;
-}
-
-void dummy_unmap(void *virt_addr, size_t len)
-{
-	printf_debug("%s: Unmapping 0x%lx bytes at %p\n",
-		__func__, (unsigned long)len, virt_addr);
-}
-
-void dummy_chip_writeb(uint8_t val, chipaddr addr)
-{
-	printf_debug("%s: addr=0x%lx, val=0x%02x\n", __func__, addr, val);
-}
-
-void dummy_chip_writew(uint16_t val, chipaddr addr)
-{
-	printf_debug("%s: addr=0x%lx, val=0x%04x\n", __func__, addr, val);
-}
-
-void dummy_chip_writel(uint32_t val, chipaddr addr)
-{
-	printf_debug("%s: addr=0x%lx, val=0x%08x\n", __func__, addr, val);
-}
-
-void dummy_chip_writen(uint8_t *buf, chipaddr addr, size_t len)
-{
-	size_t i;
-	printf_debug("%s: addr=0x%lx, len=0x%08lx, writing data (hex):",
-		     __func__, addr, (unsigned long)len);
-	for (i = 0; i < len; i++) {
-		if ((i % 16) == 0)
-			printf_debug("\n");
-		printf_debug("%02x ", buf[i])
-	}
-}
-
-uint8_t dummy_chip_readb(const chipaddr addr)
-{
-	printf_debug("%s:  addr=0x%lx, returning 0xff\n", __func__, addr);
-	return 0xff;
-}
-
-uint16_t dummy_chip_readw(const chipaddr addr)
-{
-	printf_debug("%s:  addr=0x%lx, returning 0xffff\n", __func__, addr);
-	return 0xffff;
-}
-
-uint32_t dummy_chip_readl(const chipaddr addr)
-{
-	printf_debug("%s:  addr=0x%lx, returning 0xffffffff\n", __func__, addr);
-	return 0xffffffff;
-}
-
-void dummy_chip_readn(uint8_t *buf, const chipaddr addr, size_t len)
-{
-	printf_debug("%s:  addr=0x%lx, len=0x%lx, returning array of 0xff\n",
-		     __func__, addr, (unsigned long)len);
-	memset(buf, 0xff, len);
-	return;
-}
-
-int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-		      const unsigned char *writearr, unsigned char *readarr)
-{
-	int i;
-
-	printf_debug("%s:", __func__);
-
-	printf_debug(" writing %u bytes:", writecnt);
-	for (i = 0; i < writecnt; i++)
-		printf_debug(" 0x%02x", writearr[i]);
-
-	printf_debug(" reading %u bytes:", readcnt);
-	for (i = 0; i < readcnt; i++) {
-		printf_debug(" 0xff");
-		readarr[i] = 0xff;
-	}
-
-	printf_debug("\n");
-	return 0;
-}
diff --git a/en29f002a.c b/en29f002a.c
deleted file mode 100644
index 020df32..0000000
--- a/en29f002a.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2007 Carl-Daniel Hailfinger
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/*
- * EN29F512 has 1C,21
- * EN29F010 has 1C,20
- * EN29F040A has 1C,04
- * EN29LV010 has 1C,6E and uses short F0 reset sequence
- * EN29LV040(A) has 1C,4F and uses short F0 reset sequence
- */
-
-#include "flash.h"
-
-int probe_en29f512(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-	uint8_t id1, id2;
-
-	chip_writeb(0xAA, bios + 0x555);
-	chip_writeb(0x55, bios + 0x2AA);
-	chip_writeb(0x90, bios + 0x555);
-
-	programmer_delay(10);
-
-	id1 = chip_readb(bios + 0x100);
-	id2 = chip_readb(bios + 0x101);
-
-	/* exit by writing F0 anywhere? or the code below */
-	chip_writeb(0xAA, bios + 0x555);
-	chip_writeb(0x55, bios + 0x2AA);
-	chip_writeb(0xF0, bios + 0x555);
-
-	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
-
-	if (id1 == flash->manufacture_id && id2 == flash->model_id)
-		return 1;
-
-	return 0;
-}
-
-/*
- * EN29F002AT has 1C,92
- * EN29F002AB has 1C,97
- */
-
-/* This does not seem to function properly for EN29F002NT. */
-int probe_en29f002a(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-	uint8_t id1, id2;
-
-	chip_writeb(0xAA, bios + 0x555);
-	chip_writeb(0x55, bios + 0xAAA);
-	chip_writeb(0x90, bios + 0x555);
-
-	programmer_delay(10);
-
-	id1 = chip_readb(bios + 0x100);
-	id2 = chip_readb(bios + 0x101);
-
-	/* exit by writing F0 anywhere? or the code below */
-	chip_writeb(0xAA, bios + 0x555);
-	chip_writeb(0x55, bios + 0xAAA);
-	chip_writeb(0xF0, bios + 0x555);
-
-	printf_debug("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
-
-	if (id1 == flash->manufacture_id && id2 == flash->model_id)
-		return 1;
-
-	return 0;
-}
diff --git a/flash.h b/flash.h
deleted file mode 100644
index 4178d47..0000000
--- a/flash.h
+++ /dev/null
@@ -1,763 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- * Copyright (C) 2000 Ronald G. Minnich <rminnich@gmail.com>
- * Copyright (C) 2005-2009 coresystems GmbH
- * Copyright (C) 2006-2009 Carl-Daniel Hailfinger
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#ifndef __FLASH_H__
-#define __FLASH_H__ 1
-
-#if defined(__GLIBC__)
-#include <sys/io.h>
-#endif
-#include <unistd.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <pci/pci.h>
-
-/* for iopl and outb under Solaris */
-#if defined (__sun) && (defined(__i386) || defined(__amd64))
-#include <strings.h>
-#include <sys/sysi86.h>
-#include <sys/psw.h>
-#include <asm/sunddi.h>
-#endif
-
-#if (defined(__MACH__) && defined(__APPLE__))
-#define __DARWIN__
-#endif
-
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-  #include <machine/cpufunc.h>
-  #define off64_t off_t
-  #define lseek64 lseek
-  #define OUTB(x, y) do { u_int tmp = (y); outb(tmp, (x)); } while (0)
-  #define OUTW(x, y) do { u_int tmp = (y); outw(tmp, (x)); } while (0)
-  #define OUTL(x, y) do { u_int tmp = (y); outl(tmp, (x)); } while (0)
-  #define INB(x) __extension__ ({ u_int tmp = (x); inb(tmp); })
-  #define INW(x) __extension__ ({ u_int tmp = (x); inw(tmp); })
-  #define INL(x) __extension__ ({ u_int tmp = (x); inl(tmp); })
-#else
-#if defined(__DARWIN__)
-    #include <DirectIO/darwinio.h>
-    #define off64_t off_t
-    #define lseek64 lseek
-#endif
-#if defined (__sun) && (defined(__i386) || defined(__amd64))
-  /* Note different order for outb */
-  #define OUTB(x,y) outb(y, x)
-  #define OUTW(x,y) outw(y, x)
-  #define OUTL(x,y) outl(y, x)
-  #define INB  inb
-  #define INW  inw
-  #define INL  inl
-#else
-  #define OUTB outb
-  #define OUTW outw
-  #define OUTL outl
-  #define INB  inb
-  #define INW  inw
-  #define INL  inl
-#endif
-#endif
-
-typedef unsigned long chipaddr;
-
-enum programmer {
-	PROGRAMMER_INTERNAL,
-#if DUMMY_SUPPORT == 1
-	PROGRAMMER_DUMMY,
-#endif
-#if NIC3COM_SUPPORT == 1
-	PROGRAMMER_NIC3COM,
-#endif
-#if GFXNVIDIA_SUPPORT == 1
-	PROGRAMMER_GFXNVIDIA,
-#endif
-#if DRKAISER_SUPPORT == 1
-	PROGRAMMER_DRKAISER,
-#endif
-#if SATASII_SUPPORT == 1
-	PROGRAMMER_SATASII,
-#endif
-	PROGRAMMER_IT87SPI,
-#if FT2232_SPI_SUPPORT == 1
-	PROGRAMMER_FT2232SPI,
-#endif
-#if SERPROG_SUPPORT == 1
-	PROGRAMMER_SERPROG,
-#endif
-#if BUSPIRATE_SPI_SUPPORT == 1
-	PROGRAMMER_BUSPIRATESPI,
-#endif
-	PROGRAMMER_INVALID /* This must always be the last entry. */
-};
-
-extern enum programmer programmer;
-
-struct programmer_entry {
-	const char *vendor;
-	const char *name;
-
-	int (*init) (void);
-	int (*shutdown) (void);
-
-	void * (*map_flash_region) (const char *descr, unsigned long phys_addr,
-				    size_t len);
-	void (*unmap_flash_region) (void *virt_addr, size_t len);
-
-	void (*chip_writeb) (uint8_t val, chipaddr addr);
-	void (*chip_writew) (uint16_t val, chipaddr addr);
-	void (*chip_writel) (uint32_t val, chipaddr addr);
-	void (*chip_writen) (uint8_t *buf, chipaddr addr, size_t len);
-	uint8_t (*chip_readb) (const chipaddr addr);
-	uint16_t (*chip_readw) (const chipaddr addr);
-	uint32_t (*chip_readl) (const chipaddr addr);
-	void (*chip_readn) (uint8_t *buf, const chipaddr addr, size_t len);
-	void (*delay) (int usecs);
-};
-
-extern const struct programmer_entry programmer_table[];
-
-int programmer_init(void);
-int programmer_shutdown(void);
-void *programmer_map_flash_region(const char *descr, unsigned long phys_addr,
-				  size_t len);
-void programmer_unmap_flash_region(void *virt_addr, size_t len);
-void chip_writeb(uint8_t val, chipaddr addr);
-void chip_writew(uint16_t val, chipaddr addr);
-void chip_writel(uint32_t val, chipaddr addr);
-void chip_writen(uint8_t *buf, chipaddr addr, size_t len);
-uint8_t chip_readb(const chipaddr addr);
-uint16_t chip_readw(const chipaddr addr);
-uint32_t chip_readl(const chipaddr addr);
-void chip_readn(uint8_t *buf, const chipaddr addr, size_t len);
-void programmer_delay(int usecs);
-
-enum bitbang_spi_master {
-	BITBANG_SPI_INVALID /* This must always be the last entry. */
-};
-
-extern const int bitbang_spi_master_count;
-
-extern enum bitbang_spi_master bitbang_spi_master;
-
-struct bitbang_spi_master_entry {
-	void (*set_cs) (int val);
-	void (*set_sck) (int val);
-	void (*set_mosi) (int val);
-	int (*get_miso) (void);
-};
-
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-
-enum chipbustype {
-	CHIP_BUSTYPE_NONE	= 0,
-	CHIP_BUSTYPE_PARALLEL	= 1 << 0,
-	CHIP_BUSTYPE_LPC	= 1 << 1,
-	CHIP_BUSTYPE_FWH	= 1 << 2,
-	CHIP_BUSTYPE_SPI	= 1 << 3,
-	CHIP_BUSTYPE_NONSPI	= CHIP_BUSTYPE_PARALLEL | CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH,
-	CHIP_BUSTYPE_UNKNOWN	= CHIP_BUSTYPE_PARALLEL | CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI,
-};
-
-/*
- * How many different contiguous runs of erase blocks with one size each do
- * we have for a given erase function?
- */
-#define NUM_ERASEREGIONS 5
-
-/*
- * How many different erase functions do we have per chip?
- */
-#define NUM_ERASEFUNCTIONS 5
-
-struct flashchip {
-	const char *vendor;
-	const char *name;
-
-	enum chipbustype bustype;
-
-	/*
-	 * With 32bit manufacture_id and model_id we can cover IDs up to
-	 * (including) the 4th bank of JEDEC JEP106W Standard Manufacturer's
-	 * Identification code.
-	 */
-	uint32_t manufacture_id;
-	uint32_t model_id;
-
-	int total_size;
-	int page_size;
-
-	/*
-	 * Indicate if flashrom has been tested with this flash chip and if
-	 * everything worked correctly.
-	 */
-	uint32_t tested;
-
-	int (*probe) (struct flashchip *flash);
-
-	/* Delay after "enter/exit ID mode" commands in microseconds. */
-	int probe_timing;
-	int (*erase) (struct flashchip *flash);
-
-	/*
-	 * Erase blocks and associated erase function. The default entry is a
-	 * chip-sized virtual block together with the chip erase function.
-	 */
-	struct block_eraser {
-		struct eraseblock{
-			unsigned int size; /* Eraseblock size */
-			unsigned int count; /* Number of contiguous blocks with that size */
-		} eraseblocks[NUM_ERASEREGIONS];
-		int (*block_erase) (struct flashchip *flash, unsigned int blockaddr, unsigned int blocklen);
-	} block_erasers[NUM_ERASEFUNCTIONS];
-
-	int (*write) (struct flashchip *flash, uint8_t *buf);
-	int (*read) (struct flashchip *flash, uint8_t *buf, int start, int len);
-
-	/* Some flash devices have an additional register space. */
-	chipaddr virtual_memory;
-	chipaddr virtual_registers;
-};
-
-#define TEST_UNTESTED	0
-
-#define TEST_OK_PROBE	(1 << 0)
-#define TEST_OK_READ	(1 << 1)
-#define TEST_OK_ERASE	(1 << 2)
-#define TEST_OK_WRITE	(1 << 3)
-#define TEST_OK_PR	(TEST_OK_PROBE | TEST_OK_READ)
-#define TEST_OK_PRE	(TEST_OK_PROBE | TEST_OK_READ | TEST_OK_ERASE)
-#define TEST_OK_PRW	(TEST_OK_PROBE | TEST_OK_READ | TEST_OK_WRITE)
-#define TEST_OK_PREW	(TEST_OK_PROBE | TEST_OK_READ | TEST_OK_ERASE | TEST_OK_WRITE)
-#define TEST_OK_MASK	0x0f
-
-#define TEST_BAD_PROBE	(1 << 4)
-#define TEST_BAD_READ	(1 << 5)
-#define TEST_BAD_ERASE	(1 << 6)
-#define TEST_BAD_WRITE	(1 << 7)
-#define TEST_BAD_PREW	(TEST_BAD_PROBE | TEST_BAD_READ | TEST_BAD_ERASE | TEST_BAD_WRITE)
-#define TEST_BAD_MASK	0xf0
-
-/* Timing used in probe routines. ZERO is -2 to differentiate between an unset
- * field and zero delay.
- * 
- * SPI devices will always have zero delay and ignore this field.
- */
-#define TIMING_FIXME	-1
-/* this is intentionally same value as fixme */
-#define TIMING_IGNORED	-1
-#define TIMING_ZERO	-2
-
-extern struct flashchip flashchips[];
-
-struct penable {
-	uint16_t vendor_id;
-	uint16_t device_id;
-	int status;
-	const char *vendor_name;
-	const char *device_name;
-	int (*doit) (struct pci_dev *dev, const char *name);
-};
-
-extern const struct penable chipset_enables[];
-
-struct board_pciid_enable {
-	/* Any device, but make it sensible, like the ISA bridge. */
-	uint16_t first_vendor;
-	uint16_t first_device;
-	uint16_t first_card_vendor;
-	uint16_t first_card_device;
-
-	/* Any device, but make it sensible, like
-	 * the host bridge. May be NULL.
-	 */
-	uint16_t second_vendor;
-	uint16_t second_device;
-	uint16_t second_card_vendor;
-	uint16_t second_card_device;
-
-	/* The vendor / part name from the coreboot table. */
-	const char *lb_vendor;
-	const char *lb_part;
-
-	const char *vendor_name;
-	const char *board_name;
-
-	int (*enable) (const char *name);
-};
-
-extern struct board_pciid_enable board_pciid_enables[];
-
-struct board_info {
-	const char *vendor;
-	const char *name;
-};
-
-extern const struct board_info boards_ok[];
-extern const struct board_info boards_bad[];
-extern const struct board_info laptops_ok[];
-extern const struct board_info laptops_bad[];
-
-/* udelay.c */
-void myusec_delay(int usecs);
-void myusec_calibrate_delay(void);
-
-/* pcidev.c */
-#define PCI_OK 0
-#define PCI_NT 1    /* Not tested */
-
-extern uint32_t io_base_addr;
-extern struct pci_access *pacc;
-extern struct pci_filter filter;
-extern struct pci_dev *pcidev_dev;
-struct pcidev_status {
-	uint16_t vendor_id;
-	uint16_t device_id;
-	int status;
-	const char *vendor_name;
-	const char *device_name;
-};
-uint32_t pcidev_validate(struct pci_dev *dev, uint32_t bar, struct pcidev_status *devs);
-uint32_t pcidev_init(uint16_t vendor_id, uint32_t bar, struct pcidev_status *devs, char *pcidev_bdf);
-
-/* print.c */
-char *flashbuses_to_text(enum chipbustype bustype);
-void print_supported(void);
-void print_supported_pcidevs(struct pcidev_status *devs);
-void print_supported_wiki(void);
-
-/* board_enable.c */
-void w836xx_ext_enter(uint16_t port);
-void w836xx_ext_leave(uint16_t port);
-uint8_t sio_read(uint16_t port, uint8_t reg);
-void sio_write(uint16_t port, uint8_t reg, uint8_t data);
-void sio_mask(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask);
-int board_flash_enable(const char *vendor, const char *part);
-
-struct decode_sizes {
-	uint32_t parallel;
-	uint32_t lpc;
-	uint32_t fwh;
-	uint32_t spi;
-};
-
-/* chipset_enable.c */
-extern enum chipbustype buses_supported;
-int chipset_flash_enable(void);
-extern struct decode_sizes max_rom_decode;
-
-extern unsigned long flashbase;
-
-/* physmap.c */
-void *physmap(const char *descr, unsigned long phys_addr, size_t len);
-void physunmap(void *virt_addr, size_t len);
-int setup_cpu_msr(int cpu);
-void cleanup_cpu_msr(void);
-#if !defined(__DARWIN__) && !defined(__FreeBSD__) && !defined(__DragonFly__)
-typedef struct { uint32_t hi, lo; } msr_t;
-msr_t rdmsr(int addr);
-int wrmsr(int addr, msr_t msr);
-#endif
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-/* FreeBSD already has conflicting definitions for wrmsr/rdmsr. */
-#undef rdmsr
-#undef wrmsr
-#define rdmsr freebsd_rdmsr
-#define wrmsr freebsd_wrmsr
-typedef struct { uint32_t hi, lo; } msr_t;
-msr_t freebsd_rdmsr(int addr);
-int freebsd_wrmsr(int addr, msr_t msr);
-#endif
-
-/* internal.c */
-struct pci_dev *pci_dev_find_filter(struct pci_filter filter);
-struct pci_dev *pci_dev_find_vendorclass(uint16_t vendor, uint16_t class);
-struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device);
-struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device,
-			      uint16_t card_vendor, uint16_t card_device);
-void get_io_perms(void);
-void release_io_perms(void);
-int internal_init(void);
-int internal_shutdown(void);
-void internal_chip_writeb(uint8_t val, chipaddr addr);
-void internal_chip_writew(uint16_t val, chipaddr addr);
-void internal_chip_writel(uint32_t val, chipaddr addr);
-uint8_t internal_chip_readb(const chipaddr addr);
-uint16_t internal_chip_readw(const chipaddr addr);
-uint32_t internal_chip_readl(const chipaddr addr);
-void internal_chip_readn(uint8_t *buf, const chipaddr addr, size_t len);
-void mmio_writeb(uint8_t val, void *addr);
-void mmio_writew(uint16_t val, void *addr);
-void mmio_writel(uint32_t val, void *addr);
-uint8_t mmio_readb(void *addr);
-uint16_t mmio_readw(void *addr);
-uint32_t mmio_readl(void *addr);
-void internal_delay(int usecs);
-int noop_shutdown(void);
-void *fallback_map(const char *descr, unsigned long phys_addr, size_t len);
-void fallback_unmap(void *virt_addr, size_t len);
-uint8_t noop_chip_readb(const chipaddr addr);
-void noop_chip_writeb(uint8_t val, chipaddr addr);
-void fallback_chip_writew(uint16_t val, chipaddr addr);
-void fallback_chip_writel(uint32_t val, chipaddr addr);
-void fallback_chip_writen(uint8_t *buf, chipaddr addr, size_t len);
-uint16_t fallback_chip_readw(const chipaddr addr);
-uint32_t fallback_chip_readl(const chipaddr addr);
-void fallback_chip_readn(uint8_t *buf, const chipaddr addr, size_t len);
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-extern int io_fd;
-#endif
-
-/* dummyflasher.c */
-int dummy_init(void);
-int dummy_shutdown(void);
-void *dummy_map(const char *descr, unsigned long phys_addr, size_t len);
-void dummy_unmap(void *virt_addr, size_t len);
-void dummy_chip_writeb(uint8_t val, chipaddr addr);
-void dummy_chip_writew(uint16_t val, chipaddr addr);
-void dummy_chip_writel(uint32_t val, chipaddr addr);
-void dummy_chip_writen(uint8_t *buf, chipaddr addr, size_t len);
-uint8_t dummy_chip_readb(const chipaddr addr);
-uint16_t dummy_chip_readw(const chipaddr addr);
-uint32_t dummy_chip_readl(const chipaddr addr);
-void dummy_chip_readn(uint8_t *buf, const chipaddr addr, size_t len);
-int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-		      const unsigned char *writearr, unsigned char *readarr);
-
-/* nic3com.c */
-int nic3com_init(void);
-int nic3com_shutdown(void);
-void nic3com_chip_writeb(uint8_t val, chipaddr addr);
-uint8_t nic3com_chip_readb(const chipaddr addr);
-extern struct pcidev_status nics_3com[];
-
-/* gfxnvidia.c */
-int gfxnvidia_init(void);
-int gfxnvidia_shutdown(void);
-void gfxnvidia_chip_writeb(uint8_t val, chipaddr addr);
-uint8_t gfxnvidia_chip_readb(const chipaddr addr);
-extern struct pcidev_status gfx_nvidia[];
-
-/* drkaiser.c */
-int drkaiser_init(void);
-int drkaiser_shutdown(void);
-void drkaiser_chip_writeb(uint8_t val, chipaddr addr);
-uint8_t drkaiser_chip_readb(const chipaddr addr);
-extern struct pcidev_status drkaiser_pcidev[];
-
-/* satasii.c */
-int satasii_init(void);
-int satasii_shutdown(void);
-void satasii_chip_writeb(uint8_t val, chipaddr addr);
-uint8_t satasii_chip_readb(const chipaddr addr);
-extern struct pcidev_status satas_sii[];
-
-/* ft2232_spi.c */
-#define FTDI_FT2232H 0x6010
-#define FTDI_FT4232H 0x6011
-int ft2232_spi_init(void);
-int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
-int ft2232_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
-int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf);
-
-/* bitbang_spi.c */
-extern int bitbang_spi_half_period;
-extern const struct bitbang_spi_master_entry bitbang_spi_master_table[];
-int bitbang_spi_init(void);
-int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
-int bitbang_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
-int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf);
-
-/* buspirate_spi.c */
-struct buspirate_spispeeds {
-	const char *name;
-	const int speed;
-};
-int buspirate_spi_init(void);
-int buspirate_spi_shutdown(void);
-int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
-int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
-
-/* flashrom.c */
-extern char *programmer_param;
-extern int verbose;
-extern const char *flashrom_version;
-#define printf_debug(x...) { if (verbose) printf(x); }
-void map_flash_registers(struct flashchip *flash);
-int read_memmapped(struct flashchip *flash, uint8_t *buf, int start, int len);
-int erase_flash(struct flashchip *flash);
-int min(int a, int b);
-int max(int a, int b);
-char *extract_param(char **haystack, char *needle, char *delim);
-int check_erased_range(struct flashchip *flash, int start, int len);
-int verify_range(struct flashchip *flash, uint8_t *cmpbuf, int start, int len, char *message);
-char *strcat_realloc(char *dest, const char *src);
-
-#define OK 0
-#define NT 1    /* Not tested */
-
-/* layout.c */
-int show_id(uint8_t *bios, int size, int force);
-int read_romlayout(char *name);
-int find_romentry(char *name);
-int handle_romentries(uint8_t *buffer, struct flashchip *flash);
-
-/* cbtable.c */
-int coreboot_init(void);
-extern char *lb_part, *lb_vendor;
-extern int partvendor_from_cbtable;
-
-/* spi.c */
-enum spi_controller {
-	SPI_CONTROLLER_NONE,
-	SPI_CONTROLLER_ICH7,
-	SPI_CONTROLLER_ICH9,
-	SPI_CONTROLLER_IT87XX,
-	SPI_CONTROLLER_SB600,
-	SPI_CONTROLLER_VIA,
-	SPI_CONTROLLER_WBSIO,
-#if FT2232_SPI_SUPPORT == 1
-	SPI_CONTROLLER_FT2232,
-#endif
-#if DUMMY_SUPPORT == 1
-	SPI_CONTROLLER_DUMMY,
-#endif
-#if BUSPIRATE_SPI_SUPPORT == 1
-	SPI_CONTROLLER_BUSPIRATE,
-#endif
-	SPI_CONTROLLER_INVALID /* This must always be the last entry. */
-};
-extern const int spi_programmer_count;
-struct spi_command {
-	unsigned int writecnt;
-	unsigned int readcnt;
-	const unsigned char *writearr;
-	unsigned char *readarr;
-};
-struct spi_programmer {
-	int (*command)(unsigned int writecnt, unsigned int readcnt,
-		   const unsigned char *writearr, unsigned char *readarr);
-	int (*multicommand)(struct spi_command *cmds);
-
-	/* Optimized functions for this programmer */
-	int (*read)(struct flashchip *flash, uint8_t *buf, int start, int len);
-	int (*write_256)(struct flashchip *flash, uint8_t *buf);
-};
-
-extern enum spi_controller spi_controller;
-extern const struct spi_programmer spi_programmer[];
-extern void *spibar;
-int probe_spi_rdid(struct flashchip *flash);
-int probe_spi_rdid4(struct flashchip *flash);
-int probe_spi_rems(struct flashchip *flash);
-int probe_spi_res(struct flashchip *flash);
-int spi_send_command(unsigned int writecnt, unsigned int readcnt,
-		const unsigned char *writearr, unsigned char *readarr);
-int spi_send_multicommand(struct spi_command *cmds);
-int spi_write_enable(void);
-int spi_write_disable(void);
-int spi_chip_erase_60(struct flashchip *flash);
-int spi_chip_erase_c7(struct flashchip *flash);
-int spi_chip_erase_60_c7(struct flashchip *flash);
-int spi_chip_erase_d8(struct flashchip *flash);
-int spi_block_erase_20(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
-int spi_block_erase_52(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
-int spi_block_erase_d8(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
-int spi_block_erase_60(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
-int spi_block_erase_c7(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
-int spi_chip_write_1(struct flashchip *flash, uint8_t *buf);
-int spi_chip_write_256(struct flashchip *flash, uint8_t *buf);
-int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len);
-uint8_t spi_read_status_register(void);
-int spi_disable_blockprotect(void);
-int spi_byte_program(int addr, uint8_t byte);
-int spi_nbyte_program(int addr, uint8_t *bytes, int len);
-int spi_nbyte_read(int addr, uint8_t *bytes, int len);
-int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize);
-int spi_aai_write(struct flashchip *flash, uint8_t *buf);
-uint32_t spi_get_valid_read_addr(void);
-int default_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-			     const unsigned char *writearr, unsigned char *readarr);
-int default_spi_send_multicommand(struct spi_command *cmds);
-
-/* 82802ab.c */
-int probe_82802ab(struct flashchip *flash);
-int erase_82802ab(struct flashchip *flash);
-int write_82802ab(struct flashchip *flash, uint8_t *buf);
-
-/* am29f040b.c */
-int probe_29f040b(struct flashchip *flash);
-int erase_29f040b(struct flashchip *flash);
-int write_29f040b(struct flashchip *flash, uint8_t *buf);
-
-/* pm29f002.c */
-int write_pm29f002(struct flashchip *flash, uint8_t *buf);
-
-/* en29f002a.c */
-int probe_en29f002a(struct flashchip *flash);
-int erase_en29f002a(struct flashchip *flash);
-int write_en29f002a(struct flashchip *flash, uint8_t *buf);
-
-/* ichspi.c */
-int ich_init_opcodes(void);
-int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-		    const unsigned char *writearr, unsigned char *readarr);
-int ich_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
-int ich_spi_write_256(struct flashchip *flash, uint8_t * buf);
-int ich_spi_send_multicommand(struct spi_command *cmds);
-
-/* it87spi.c */
-extern uint16_t it8716f_flashport;
-void enter_conf_mode_ite(uint16_t port);
-void exit_conf_mode_ite(uint16_t port);
-int it87spi_init(void);
-int it87xx_probe_spi_flash(const char *name);
-int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-			const unsigned char *writearr, unsigned char *readarr);
-int it8716f_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len);
-int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf);
-
-/* sb600spi.c */
-int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-		      const unsigned char *writearr, unsigned char *readarr);
-int sb600_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
-int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf);
-extern uint8_t *sb600_spibar;
-
-/* jedec.c */
-uint8_t oddparity(uint8_t val);
-void toggle_ready_jedec(chipaddr dst);
-void data_polling_jedec(chipaddr dst, uint8_t data);
-void start_program_jedec(chipaddr bios);
-int write_byte_program_jedec(chipaddr bios, uint8_t *src,
-			     chipaddr dst);
-int probe_jedec(struct flashchip *flash);
-int erase_chip_jedec(struct flashchip *flash);
-int write_jedec(struct flashchip *flash, uint8_t *buf);
-int write_jedec_1(struct flashchip *flash, uint8_t *buf);
-int erase_sector_jedec(struct flashchip *flash, unsigned int page, unsigned int pagesize);
-int erase_block_jedec(struct flashchip *flash, unsigned int page, unsigned int blocksize);
-int write_sector_jedec(chipaddr bios, uint8_t *src,
-		       chipaddr dst, unsigned int page_size);
-
-/* m29f002.c */
-int erase_m29f002(struct flashchip *flash);
-int write_m29f002t(struct flashchip *flash, uint8_t *buf);
-int write_m29f002b(struct flashchip *flash, uint8_t *buf);
-
-/* m29f400bt.c */
-int probe_m29f400bt(struct flashchip *flash);
-int erase_m29f400bt(struct flashchip *flash);
-int block_erase_m29f400bt(struct flashchip *flash, int start, int len);
-int write_m29f400bt(struct flashchip *flash, uint8_t *buf);
-int write_coreboot_m29f400bt(struct flashchip *flash, uint8_t *buf);
-void toggle_ready_m29f400bt(chipaddr dst);
-void data_polling_m29f400bt(chipaddr dst, uint8_t data);
-void protect_m29f400bt(chipaddr bios);
-void write_page_m29f400bt(chipaddr bios, uint8_t *src,
-			  chipaddr dst, int page_size);
-
-/* mx29f002.c */
-int probe_29f002(struct flashchip *flash);
-int erase_29f002(struct flashchip *flash);
-int write_29f002(struct flashchip *flash, uint8_t *buf);
-
-/* pm49fl00x.c */
-int probe_49fl00x(struct flashchip *flash);
-int erase_49fl00x(struct flashchip *flash);
-int write_49fl00x(struct flashchip *flash, uint8_t *buf);
-
-/* sharplhf00l04.c */
-int probe_lhf00l04(struct flashchip *flash);
-int erase_lhf00l04(struct flashchip *flash);
-int write_lhf00l04(struct flashchip *flash, uint8_t *buf);
-void toggle_ready_lhf00l04(chipaddr dst);
-void data_polling_lhf00l04(chipaddr dst, uint8_t data);
-void protect_lhf00l04(chipaddr bios);
-
-/* sst28sf040.c */
-int probe_28sf040(struct flashchip *flash);
-int erase_28sf040(struct flashchip *flash);
-int write_28sf040(struct flashchip *flash, uint8_t *buf);
-
-/* sst39sf020.c */
-int probe_39sf020(struct flashchip *flash);
-int write_39sf020(struct flashchip *flash, uint8_t *buf);
-
-/* sst49lf040.c */
-int erase_49lf040(struct flashchip *flash);
-int write_49lf040(struct flashchip *flash, uint8_t *buf);
-
-/* sst49lfxxxc.c */
-int probe_49lfxxxc(struct flashchip *flash);
-int erase_49lfxxxc(struct flashchip *flash);
-int write_49lfxxxc(struct flashchip *flash, uint8_t *buf);
-
-/* sst_fwhub.c */
-int probe_sst_fwhub(struct flashchip *flash);
-int erase_sst_fwhub(struct flashchip *flash);
-int erase_sst_fwhub_block(struct flashchip *flash, unsigned int offset, unsigned int page_size);
-int write_sst_fwhub(struct flashchip *flash, uint8_t *buf);
-
-/* w39v040c.c */
-int probe_w39v040c(struct flashchip *flash);
-int erase_w39v040c(struct flashchip *flash);
-int write_w39v040c(struct flashchip *flash, uint8_t *buf);
-
-/* w39V080fa.c */
-int probe_winbond_fwhub(struct flashchip *flash);
-int erase_winbond_fwhub(struct flashchip *flash);
-int write_winbond_fwhub(struct flashchip *flash, uint8_t *buf);
-
-/* w29ee011.c */
-int probe_w29ee011(struct flashchip *flash);
-
-/* w49f002u.c */
-int write_49f002(struct flashchip *flash, uint8_t *buf);
-
-/* wbsio_spi.c */
-int wbsio_check_for_spi(const char *name);
-int wbsio_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-		      const unsigned char *writearr, unsigned char *readarr);
-int wbsio_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
-int wbsio_spi_write_1(struct flashchip *flash, uint8_t *buf);
-
-/* stm50flw0x0x.c */
-int probe_stm50flw0x0x(struct flashchip *flash);
-int erase_stm50flw0x0x(struct flashchip *flash);
-int write_stm50flw0x0x(struct flashchip *flash, uint8_t *buf);
-
-/* serprog.c */
-int serprog_init(void);
-int serprog_shutdown(void);
-void serprog_chip_writeb(uint8_t val, chipaddr addr);
-uint8_t serprog_chip_readb(const chipaddr addr);
-void serprog_chip_readn(uint8_t *buf, const chipaddr addr, size_t len);
-void serprog_delay(int delay);
-
-/* serial.c */
-void sp_flush_incoming(void);
-int sp_openserport(char *dev, unsigned int baud);
-void __attribute__((noreturn)) sp_die(char *msg);
-extern int sp_fd;
-
-#endif				/* !__FLASH_H__ */
diff --git a/flashchips.c b/flashchips.c
deleted file mode 100644
index 5e74ccf..0000000
--- a/flashchips.c
+++ /dev/null
@@ -1,3435 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- * Copyright (C) 2004 Tyan Corp
- * Copyright (C) 2005-2008 coresystems GmbH <stepan@openbios.org>
- * Copyright (C) 2006-2009 Carl-Daniel Hailfinger
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "flash.h"
-#include "flashchips.h"
-
-/**
- * List of supported flash chips.
- *
- * Please keep the list sorted by vendor name and chip name, so that
- * the output of 'flashrom -L' is alphabetically sorted.
- */
-struct flashchip flashchips[] = {
-
-	/*
-	 * .vendor		= Vendor name
-	 * .name		= Chip name
-	 * .bustype		= Supported flash bus types (Parallel, LPC...)
-	 * .manufacture_id	= Manufacturer chip ID
-	 * .model_id		= Model chip ID
-	 * .total_size		= Total size in (binary) kbytes
-	 * .page_size		= Page or eraseblock(?) size in bytes
-	 * .tested		= Test status
-	 * .probe		= Probe function
-	 * .probe_timing	= Probe function delay
-	 * .erase		= Chip erase function
-	 * .block_erasers[]	= Array of erase layouts and erase functions
-	 * {
-	 *	.eraseblocks[]	= Array of { blocksize, blockcount }
-	 *	.block_erase	= Block erase function
-	 * }
-	 * .write		= Chip write function
-	 * .read		= Chip read function
-	 */
-
-	{
-		.vendor		= "AMD",
-		.name		= "Am29F010A/B",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AM_29F010B,	/* Same as Am29F010A */
-		.total_size	= 128,
-		.page_size	= 16 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_29f040b,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= erase_29f040b,
-		.write		= write_pm29f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "AMD",
-		.name		= "Am29F002(N)BB",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AM_29F002BB,
-		.total_size	= 256,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec_1,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "AMD",
-		.name		= "Am29F002(N)BT",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AM_29F002BT,
-		.total_size	= 256,
-		.page_size	= 256,
-		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec_1,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "AMD",
-		.name		= "Am29F016D",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AM_29F016D,
-		.total_size	= 2048,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_29f040b,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */
-		.erase		= erase_29f040b,
-		.write		= write_29f040b,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "AMD",
-		.name		= "Am29F040B",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AM_29F040B,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_29f040b,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */
-		.erase		= erase_29f040b,
-		.write		= write_29f040b,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "AMD",
-		.name		= "Am29F080B",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AM_29F080B,
-		.total_size	= 1024,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= erase_29f040b,
-		.write		= write_29f040b,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "AMD",
-		.name		= "Am29LV040B",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AM_29LV040B,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_29f040b,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */
-		.erase		= erase_29f040b,
-		.write		= write_29f040b,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "AMD",
-		.name		= "Am29LV081B",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AM_29LV080B,
-		.total_size	= 1024,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_29f040b,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */
-		.erase		= erase_29f040b,
-		.write		= write_29f040b,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "ASD",
-		.name		= "AE49F2008",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= ASD_ID,
-		.model_id	= ASD_AE49F2008,
-		.total_size	= 256,
-		.page_size	= 128,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_FIXME, 
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT25DF021",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_25DF021,
-		.total_size	= 256,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT25DF041A",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_25DF041A,
-		.total_size	= 512,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT25DF081",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_25DF081,
-		.total_size	= 1024,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT25DF161",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_25DF161,
-		.total_size	= 2048,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT25DF321",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_25DF321,
-		.total_size	= 4096,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT25DF321A",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_25DF321A,
-		.total_size	= 4096,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT25DF641",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_25DF641,
-		.total_size	= 8192,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT25F512B",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_25F512B,
-		.total_size	= 64,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT25FS010",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_25FS010,
-		.total_size	= 128,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT25FS040",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_25FS040,
-		.total_size	= 512,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT26DF041",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_26DF041,
-		.total_size	= 512,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL /* Incompatible Page write */,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT26DF081A",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_26DF081A,
-		.total_size	= 1024,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT26DF161",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_26DF161,
-		.total_size	= 2048,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT26DF161A",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_26DF161A,
-		.total_size	= 2048,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	/*The AT26DF321 has the same ID as the AT25DF321. */
-	/*{
-		.vendor		= "Atmel",
-		.name		= "AT26DF321",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_26DF321,
-		.total_size	= 4096,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	  },*/
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT26F004",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_26F004,
-		.total_size	= 512,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= NULL /* Incompatible Page write */,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT29C512",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_29C512,
-		.total_size	= 64,
-		.page_size	= 128,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec, 
-		.probe_timing	= 10000, /* 10mS, Enter=Exec */
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec,
-		.read		= read_memmapped,
-
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT29C010A",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_29C010A,
-		.total_size	= 128,
-		.page_size	= 128,
-		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
-		.probe_timing	= 10000, /* 10mS, Enter=Exec */
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec,	/* FIXME */
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT29C020",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_29C020,
-		.total_size	= 256,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 10000,			/* 10ms */ 
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT29C040A",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_29C040A,
-		.total_size	= 512,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= 10000,			/* 10 ms */
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT45CS1282",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_45CS1282,
-		.total_size	= 16896 /* No power of two sizes */,
-		.page_size	= 1056 /* No power of two sizes */,
-		.tested		= TEST_BAD_READ,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL /* Incompatible Page write */,
-		.read		= NULL /* Incompatible read */,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT45DB011D",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_45DB011D,
-		.total_size	= 128 /* Size can only be determined from status register */,
-		.page_size	= 256 /* Size can only be determined from status register */,
-		.tested		= TEST_BAD_READ,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT45DB021D",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_45DB021D,
-		.total_size	= 256 /* Size can only be determined from status register */,
-		.page_size	= 256 /* Size can only be determined from status register */,
-		.tested		= TEST_BAD_READ,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT45DB041D",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_45DB041D,
-		.total_size	= 512 /* Size can only be determined from status register */,
-		.page_size	= 256 /* Size can only be determined from status register */,
-		.tested		= TEST_BAD_READ,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT45DB081D",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_45DB081D,
-		.total_size	= 1024 /* Size can only be determined from status register */,
-		.page_size	= 256 /* Size can only be determined from status register */,
-		.tested		= TEST_BAD_READ,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT45DB161D",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_45DB161D,
-		.total_size	= 2048 /* Size can only be determined from status register */,
-		.page_size	= 512 /* Size can only be determined from status register */,
-		.tested		= TEST_BAD_READ,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT45DB321C",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_45DB321C,
-		.total_size	= 4224 /* No power of two sizes */,
-		.page_size	= 528 /* No power of two sizes */,
-		.tested		= TEST_BAD_READ,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= NULL /* Incompatible read */,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT45DB321D",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_45DB321D,
-		.total_size	= 4096 /* Size can only be determined from status register */,
-		.page_size	= 512 /* Size can only be determined from status register */,
-		.tested		= TEST_BAD_READ,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT45DB642D",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_45DB642D,
-		.total_size	= 8192 /* Size can only be determined from status register */,
-		.page_size	= 1024 /* Size can only be determined from status register */,
-		.tested		= TEST_BAD_READ,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT49BV512",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_49BV512,
-		.total_size	= 64,
-		.page_size	= 64,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT49F002(N)",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_49F002N,
-		.total_size	= 256,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "AT49F002(N)T",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= AT_49F002NT,
-		.total_size	= 256,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "AMIC",
-		.name		= "A25L40P",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= AMIC_ID,
-		.model_id	= AMIC_A25L40P,
-		.total_size	= 512,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid4,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "AMIC",
-		.name		= "A29002B",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A29002B,
-		.total_size	= 256,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_29f002,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */
-		.erase		= erase_29f002,
-		.write		= write_jedec_1,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "AMIC",
-		.name		= "A29002T",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A29002T,
-		.total_size	= 256,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PRE,
-		.probe		= probe_29f002,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */
-		.erase		= erase_29f002,
-		.write		= write_jedec_1,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "AMIC",
-		.name		= "A29040B",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A29040B,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PR,
-		.probe		= probe_29f040b,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */
-		.erase		= erase_29f040b,
-		.write		= write_29f040b,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "AMIC",
-		.name		= "A49LF040A",
-		.bustype	= CHIP_BUSTYPE_LPC,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A49LF040A,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_49fl00x,
-		.probe_timing	= TIMING_ZERO,	/* routine is wrapper to probe_jedec (pm49fl00x.c) */
-		.erase		= erase_49fl00x,
-		.write		= write_49fl00x,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "EMST",
-		.name		= "F49B002UA",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= EMST_ID,
-		.model_id	= EMST_F49B002UA,
-		.total_size	= 256,
-		.page_size	= 4096,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "EN25B05",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EN_25B05,
-		.total_size	= 64,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "EN25B10",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EN_25B10,
-		.total_size	= 128,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "EN25B20",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EN_25B20,
-		.total_size	= 256,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "EN25B40",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EN_25B40,
-		.total_size	= 512,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "EN25B80",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EN_25B80,
-		.total_size	= 1024,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "EN25B16",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EN_25B16,
-		.total_size	= 2048,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "EN25B32",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EN_25B32,
-		.total_size	= 4096,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "EN25B64",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EN_25B64,
-		.total_size	= 8192,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "EN25D16",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EN_25D16,
-		.total_size	= 2048,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "EN25F05",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EN_25F05,
-		.total_size	= 64,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "EN25F10",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EN_25F10,
-		.total_size	= 128,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "EN25F20",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EN_25F20,
-		.total_size	= 256,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "EN25F40",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EN_25F40,
-		.total_size	= 512,
-		.page_size	= 256,
-		.tested		= TEST_OK_PROBE,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "EN25F80",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EN_25F80,
-		.total_size	= 1024,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "EN25F16",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EN_25F16,
-		.total_size	= 2048,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "EN25F32",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EN_25F32,
-		.total_size	= 4096,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "EON",
-		.name		= "EN29F002(A)(N)B",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= EON_ID,
-		.model_id	= EN_29F002B,
-		.total_size	= 256,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec_1,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "EON",
-		.name		= "EN29F002(A)(N)T",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= EON_ID,
-		.model_id	= EN_29F002T,
-		.total_size	= 256,
-		.page_size	= 256,
-		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec_1,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Fujitsu",
-		.name		= "MBM29F004BC",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= FUJITSU_ID,
-		.model_id	= MBM29F004BC,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Fujitsu",
-		.name		= "MBM29F004TC",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= FUJITSU_ID,
-		.model_id	= MBM29F004TC,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Fujitsu",
-		.name		= "MBM29F400BC",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= FUJITSU_ID,
-		.model_id	= MBM29F400BC,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_m29f400bt,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (m29f400bt.c) */
-		.erase		= erase_m29f400bt,
-		.write		= write_coreboot_m29f400bt,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Fujitsu",
-		.name		= "MBM29F400TC",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= FUJITSU_ID,
-		.model_id	= MBM29F400TC,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_m29f400bt,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (m29f400bt.c) */
-		.erase		= erase_m29f400bt,
-		.write		= write_coreboot_m29f400bt,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Intel",
-		.name		= "28F001BX-B",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= P28F001BXB,
-		.total_size	= 128,
-		.page_size	= 128 * 1024, /* 8k + 2x4k + 112k */
-		.tested		= TEST_BAD_ERASE|TEST_BAD_WRITE,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Intel",
-		.name		= "28F001BX-T",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= P28F001BXT,
-		.total_size	= 128,
-		.page_size	= 128 * 1024, /* 112k + 2x4k + 8k */
-		.tested		= TEST_OK_PR|TEST_BAD_ERASE|TEST_BAD_WRITE,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Intel",
-		.name		= "82802AB",
-		.bustype	= CHIP_BUSTYPE_FWH,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= I_82802AB,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_82802ab,
-		.probe_timing	= TIMING_IGNORED, /* routine does not use probe_timing (82802ab.c) */
-		.erase		= erase_82802ab,
-		.write		= write_82802ab,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Intel",
-		.name		= "82802AC",
-		.bustype	= CHIP_BUSTYPE_FWH,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= I_82802AC,
-		.total_size	= 1024,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_82802ab,
-		.probe_timing	= TIMING_IGNORED, /* routine does not use probe_timing (82802ab.c) */
-		.erase		= erase_82802ab,
-		.write		= write_82802ab,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "MX25L512",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= MX_ID,
-		.model_id	= MX_25L512,
-		.total_size	= 64,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.block_erasers	=
-		{
-			{
-				.eraseblocks = { {4 * 1024, 16} },
-				.block_erase = spi_block_erase_20,
-			}, {
-				.eraseblocks = { {64 * 1024, 1} },
-				.block_erase = spi_block_erase_52,
-			}, {
-				.eraseblocks = { {64 * 1024, 1} },
-				.block_erase = spi_block_erase_d8,
-			}, {
-				.eraseblocks = { {64 * 1024, 1} },
-				.block_erase = spi_block_erase_60,
-			}, {
-				.eraseblocks = { {64 * 1024, 1} },
-				.block_erase = spi_block_erase_c7,
-			},
-		},
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "MX25L1005",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= MX_ID,
-		.model_id	= MX_25L1005,
-		.total_size	= 128,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.block_erasers	=
-		{
-			{
-				.eraseblocks = { {4 * 1024, 32} },
-				.block_erase = spi_block_erase_20,
-			}, {
-				.eraseblocks = { {64 * 1024, 2} },
-				.block_erase = spi_block_erase_d8,
-			}, {
-				.eraseblocks = { {128 * 1024, 1} },
-				.block_erase = spi_block_erase_60,
-			}, {
-				.eraseblocks = { {128 * 1024, 1} },
-				.block_erase = spi_block_erase_c7,
-			},
-		},
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "MX25L2005",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= MX_ID,
-		.model_id	= MX_25L2005,
-		.total_size	= 256,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.block_erasers	=
-		{
-			{
-				.eraseblocks = { {4 * 1024, 64} },
-				.block_erase = spi_block_erase_20,
-			}, {
-				.eraseblocks = { {64 * 1024, 4} },
-				.block_erase = spi_block_erase_52,
-			}, {
-				.eraseblocks = { {64 * 1024, 4} },
-				.block_erase = spi_block_erase_d8,
-			}, {
-				.eraseblocks = { {256 * 1024, 1} },
-				.block_erase = spi_block_erase_60,
-			}, {
-				.eraseblocks = { {256 * 1024, 1} },
-				.block_erase = spi_block_erase_c7,
-			},
-		},
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "MX25L4005",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= MX_ID,
-		.model_id	= MX_25L4005,
-		.total_size	= 512,
-		.page_size	= 256,
-		.tested		= TEST_OK_PRW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.block_erasers	=
-		{
-			{
-				.eraseblocks = { {4 * 1024, 128} },
-				.block_erase = spi_block_erase_20,
-			}, {
-				.eraseblocks = { {64 * 1024, 8} },
-				.block_erase = spi_block_erase_52,
-			}, {
-				.eraseblocks = { {64 * 1024, 8} },
-				.block_erase = spi_block_erase_d8,
-			}, {
-				.eraseblocks = { {512 * 1024, 1} },
-				.block_erase = spi_block_erase_60,
-			}, {
-				.eraseblocks = { {512 * 1024, 1} },
-				.block_erase = spi_block_erase_c7,
-			},
-		},
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "MX25L8005",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= MX_ID,
-		.model_id	= MX_25L8005,
-		.total_size	= 1024,
-		.page_size	= 256,
-		.tested		= TEST_OK_PRW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.block_erasers	=
-		{
-			{
-				.eraseblocks = { {4 * 1024, 256} },
-				.block_erase = spi_block_erase_20,
-			}, {
-				.eraseblocks = { {64 * 1024, 16} },
-				.block_erase = spi_block_erase_52,
-			}, {
-				.eraseblocks = { {64 * 1024, 16} },
-				.block_erase = spi_block_erase_d8,
-			}, {
-				.eraseblocks = { {1024 * 1024, 1} },
-				.block_erase = spi_block_erase_60,
-			}, {
-				.eraseblocks = { {1024 * 1024, 1} },
-				.block_erase = spi_block_erase_c7,
-			},
-		},
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "MX25L1605",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= MX_ID,
-		.model_id	= MX_25L1605,
-		.total_size	= 2048,
-		.page_size	= 256,
-		.tested		= TEST_OK_PRW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.block_erasers	=
-		{
-			{
-				.eraseblocks = { {4 * 1024, 512} },
-				.block_erase = spi_block_erase_20,	/* This erase function has 64k blocksize for eLiteFlash */
-			}, {
-				.eraseblocks = { {64 * 1024, 32} },	/* Not supported in MX25L1605 (eLiteFlash) and MX25L1605D */
-				.block_erase = spi_block_erase_52,
-			}, {
-				.eraseblocks = { {64 * 1024, 32} },
-				.block_erase = spi_block_erase_d8,
-			}, {
-				.eraseblocks = { {2 * 1024 * 1024, 1} },
-				.block_erase = spi_block_erase_60,
-			}, {
-				.eraseblocks = { {2 * 1024 * 1024, 1} },
-				.block_erase = spi_block_erase_c7,
-			},
-		},
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "MX25L1635D",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= MX_ID,
-		.model_id	= MX_25L1635D,
-		.total_size	= 2048,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "MX25L3205",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= MX_ID,
-		.model_id	= MX_25L3205,
-		.total_size	= 4096,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "MX25L3235D",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= MX_ID,
-		.model_id	= MX_25L3235D,
-		.total_size	= 4096,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "MX25L6405",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= MX_ID,
-		.model_id	= MX_25L6405,
-		.total_size	= 8192,
-		.page_size	= 256,
-		.tested		= TEST_OK_PROBE,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "MX25L12805",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= MX_ID,
-		.model_id	= MX_25L12805,
-		.total_size	= 16384,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "MX29F001B",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= MX_ID,
-		.model_id	= MX_29F001B,
-		.total_size	= 128,
-		.page_size	= 32 * 1024,
-		.tested		= TEST_OK_PRE,
-		.probe		= probe_29f002,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */
-		.erase		= erase_29f002,
-		.write		= write_jedec_1,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "MX29F001T",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= MX_ID,
-		.model_id	= MX_29F001T,
-		.total_size	= 128,
-		.page_size	= 32 * 1024,
-		.tested		= TEST_OK_PRE,
-		.probe		= probe_29f002,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */
-		.erase		= erase_29f002,
-		.write		= write_jedec_1,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "MX29F002B",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= MX_ID,
-		.model_id	= MX_29F002B,
-		.total_size	= 256,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_29f002,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */
-		.erase		= erase_29f002,
-		.write		= write_jedec_1,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "MX29F002T",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= MX_ID,
-		.model_id	= MX_29F002T,
-		.total_size	= 256,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PRE,
-		.probe		= probe_29f002,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */
-		.erase		= erase_29f002,
-		.write		= write_jedec_1,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "MX29LV040",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= MX_ID,
-		.model_id	= MX_29LV040,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PR,
-		.probe		= probe_29f002,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */
-		.erase		= erase_29f002,
-		.write		= write_jedec_1,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Numonyx",
-		.name		= "M25PE10",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25PE10,
-		.total_size	= 128,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_d8,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Numonyx",
-		.name		= "M25PE20",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25PE20,
-		.total_size	= 256,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_d8,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Numonyx",
-		.name		= "M25PE40",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25PE40,
-		.total_size	= 256,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_d8,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Numonyx",
-		.name		= "M25PE80",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25PE80,
-		.total_size	= 1024,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_d8,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Numonyx",
-		.name		= "M25PE16",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25PE16,
-		.total_size	= 2048,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_d8,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "PMC",
-		.name		= "Pm25LV010",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= PMC_25LV010,
-		.total_size	= 128,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "PMC",
-		.name		= "Pm25LV016B",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= PMC_25LV016B,
-		.total_size	= 2048,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "PMC",
-		.name		= "Pm25LV020",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= PMC_25LV020,
-		.total_size	= 256,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "PMC",
-		.name		= "Pm25LV040",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= PMC_25LV040,
-		.total_size	= 512,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "PMC",
-		.name		= "Pm25LV080B",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= PMC_25LV080B,
-		.total_size	= 1024,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "PMC",
-		.name		= "Pm25LV512",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= PMC_25LV512,
-		.total_size	= 64,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "PMC",
-		.name		= "Pm29F0002T",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= PMC_ID_NOPREFIX,
-		.model_id	= PMC_29F002T,
-		.total_size	= 256,
-		.page_size	= 8192,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_29f040b,
-		.probe_timing	= TIMING_FIXME, 
-		.erase		= erase_29f040b,
-		.write		= write_pm29f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "PMC",
-		.name		= "Pm29F0002B",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= PMC_ID_NOPREFIX,
-		.model_id	= PMC_29F002B,
-		.total_size	= 256,
-		.page_size	= 8192,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_29f040b,
-		.probe_timing	= TIMING_FIXME, 
-		.erase		= erase_29f040b,
-		.write		= write_pm29f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "PMC",
-		.name		= "Pm39LV010",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= PMC_ID_NOPREFIX,
-		.model_id	= PMC_39F010,
-		.total_size	= 128,
-		.page_size	= 4096,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "PMC",
-		.name		= "Pm49FL002",
-		.bustype	= CHIP_BUSTYPE_LPC|CHIP_BUSTYPE_FWH, /* A/A Mux*/
-		.manufacture_id	= PMC_ID_NOPREFIX,
-		.model_id	= PMC_49FL002,
-		.total_size	= 256,
-		.page_size	= 16 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_49fl00x,
-		.probe_timing	= TIMING_ZERO,	/* routine is wrapper to probe_jedec (pm49fl00x.c) */
-		.erase		= erase_49fl00x,
-		.write		= write_49fl00x,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "PMC",
-		.name		= "Pm49FL004",
-		.bustype	= CHIP_BUSTYPE_LPC|CHIP_BUSTYPE_FWH, /* A/A Mux*/
-		.manufacture_id	= PMC_ID_NOPREFIX,
-		.model_id	= PMC_49FL004,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_49fl00x,
-		.probe_timing	= TIMING_ZERO,	/* routine is wrapper to probe_jedec (pm49fl00x.c) */
-		.erase		= erase_49fl00x,
-		.write		= write_49fl00x,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Sanyo",
-		.name		= "LF25FW203A",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= SANYO_ID,
-		.model_id	= SANYO_LE25FW203A,
-		.total_size	= 2048,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Sharp",
-		.name		= "LHF00L04",
-		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
-		.manufacture_id	= SHARP_ID,
-		.model_id	= SHARP_LHF00L04,
-		.total_size	= 1024,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_lhf00l04,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (sharplhf00l04.c) */
-		.erase		= erase_lhf00l04,
-		.write		= write_lhf00l04,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Spansion",
-		.name		= "S25FL016A",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= SPANSION_ID,
-		.model_id	= SPANSION_S25FL016A,
-		.total_size	= 2048,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST25VF016B",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_25VF016B,
-		.total_size	= 2048,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_1,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST25VF032B",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_25VF032B,
-		.total_size	= 4096,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_1,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST25VF040B",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_25VF040B,
-		.total_size	= 512,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_1,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST25VF040.REMS",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_25VF040_REMS,
-		.total_size	= 512,
-		.page_size	= 64*1024,
-		.tested		= TEST_OK_PR,
-		.probe		= probe_spi_rems,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60,
-		.write		= spi_chip_write_1,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST25VF040B.REMS",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_25VF040B_REMS,
-		.total_size	= 512,
-		.page_size	= 64*1024,
-		.tested		= TEST_OK_PR,
-		.probe		= probe_spi_rems,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_1,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST25VF080B",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_25VF080B,
-		.total_size	= 1024,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_60_c7,
-		.write		= spi_chip_write_1,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST28SF040A",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_28SF040,
-		.total_size	= 512,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_28sf040,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (sst28sf040.c) */
-		.erase		= erase_28sf040,
-		.write		= write_28sf040,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST29EE010",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_29EE010,
-		.total_size	= 128,
-		.page_size	= 128,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 10, 
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST29LE010",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_29LE010,
-		.total_size	= 128,
-		.page_size	= 128,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= 10, 
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST29EE020A",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_29EE020A,
-		.total_size	= 256,
-		.page_size	= 128,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 10,
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST29LE020",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_29LE020,
-		.total_size	= 256,
-		.page_size	= 128,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= 10, 
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST39SF010A",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_39SF010,
-		.total_size	= 128,
-		.page_size	= 4096,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 1,			/* 150 ns */
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST39SF020A",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_39SF020,
-		.total_size	= 256,
-		.page_size	= 4096,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 1,			/* 150 ns */ 
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST39SF040",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_39SF040,
-		.total_size	= 512,
-		.page_size	= 4096,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 1,			/* 150 ns */ 
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST39VF512",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_39VF512,
-		.total_size	= 64,
-		.page_size	= 4096,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 1,			/* 150 ns*/ 
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST39VF010",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_39VF010,
-		.total_size	= 128,
-		.page_size	= 4096,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 1,			/* 150 ns */ 
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST39VF020",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_39VF020,
-		.total_size	= 256,
-		.page_size	= 4096,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 1,			/* 150 ns */ 
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST39VF040",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_39VF040,
-		.total_size	= 512,
-		.page_size	= 4096,
-		.tested		= TEST_OK_PROBE,
-		.probe		= probe_jedec,
-		.probe_timing	= 1,			/* 150 ns */ 
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST39VF080",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_39VF080,
-		.total_size	= 1024,
-		.page_size	= 4096,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= 1,			/* 150 ns */ 
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST49LF002A/B",
-		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_49LF002A,
-		.total_size	= 256,
-		.page_size	= 16 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_sst_fwhub,
-		.probe_timing	= 1,		/* 150 ns | routine is wrapper to probe_jedec (sst_fwhub.c) */
-		.erase		= erase_sst_fwhub,
-		.write		= write_sst_fwhub,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST49LF003A/B",
-		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_49LF003A,
-		.total_size	= 384,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PR,
-		.probe		= probe_sst_fwhub,
-		.probe_timing	= 1,		/* 150 ns | routine is wrapper to probe_jedec (sst_fwhub.c) */
-		.erase		= erase_sst_fwhub,
-		.write		= write_sst_fwhub,
-		.read		= read_memmapped,
-	},
-
-	{
-		/* Contrary to the data sheet, TBL# on the SST49LF004B affects the top 128kB (instead of 64kB)
-		 * and is only honored for 64k block erase, but not 4k sector erase.
-		 */
-		.vendor		= "SST",
-		.name		= "SST49LF004A/B",
-		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_49LF004A,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_sst_fwhub,
-		.probe_timing	= 1,		/* 150 ns | routine is wrapper to probe_jedec (sst_fwhub.c) */
-		.erase		= NULL,
-		.block_erasers	=
-		{
-			{
-				.eraseblocks = { {4 * 1024, 128} },
-				.block_erase = erase_sector_jedec, /* missing unlock */
-			}, {
-				.eraseblocks = { {64 * 1024, 8} },
-				.block_erase = erase_sst_fwhub_block, /* same as erase_block_jedec, but with unlock */
-			}, {
-				.eraseblocks = { {512 * 1024, 1} },
-				.block_erase = NULL, /* AA 55 80 AA 55 10, only in PP mode */
-			},
-		},
-		.write		= write_sst_fwhub,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST49LF004C",
-		.bustype	= CHIP_BUSTYPE_FWH,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_49LF004C,
-		.total_size	= 512,
-		.page_size	= 4 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_49lfxxxc,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */
-		.erase		= erase_49lfxxxc,
-		.write		= write_49lfxxxc,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST49LF008A",
-		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_49LF008A,
-		.total_size	= 1024,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_sst_fwhub,
-		.probe_timing	= 1,		/* 150 ns | routine is wrapper to probe_jedec (sst_fwhub.c) */
-		.erase		= erase_sst_fwhub,
-		.write		= write_sst_fwhub,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST49LF008C",
-		.bustype	= CHIP_BUSTYPE_FWH,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_49LF008C,
-		.total_size	= 1024,
-		.page_size	= 4 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_49lfxxxc,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */
-		.erase		= erase_49lfxxxc,
-		.write		= write_49lfxxxc,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST49LF016C",
-		.bustype	= CHIP_BUSTYPE_FWH,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_49LF016C,
-		.total_size	= 2048,
-		.page_size	= 4 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_49lfxxxc,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */
-		.erase		= erase_49lfxxxc,
-		.write		= write_49lfxxxc,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST49LF020",
-		.bustype	= CHIP_BUSTYPE_LPC,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_49LF020,
-		.total_size	= 256,
-		.page_size	= 16 * 1024,
-		.tested		= TEST_OK_PR,
-		.probe		= probe_jedec,
-		.probe_timing	= 1,			/* 150 ns */ 
-		.erase		= erase_49lf040,
-		.write		= write_49lf040,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST49LF020A",
-		.bustype	= CHIP_BUSTYPE_LPC,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_49LF020A,
-		.total_size	= 256,
-		.page_size	= 4 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 1,			/* 150 ns */ 
-		.erase		= erase_49lf040,
-		.write		= write_49lf040,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST49LF040",
-		.bustype	= CHIP_BUSTYPE_LPC,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_49LF040,
-		.total_size	= 512,
-		.page_size	= 4096,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 1,			/* 150 ns */ 
-		.erase		= erase_49lf040,
-		.write		= write_49lf040,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST49LF040B",
-		.bustype	= CHIP_BUSTYPE_LPC, /* A/A Mux */
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_49LF040B,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_sst_fwhub,
-		.probe_timing	= 1,		/* 150ns | routine is wrapper to probe_jedec (sst_fwhub.c) */
-		.erase		= erase_sst_fwhub,
-		.write		= write_sst_fwhub,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST49LF080A",
-		.bustype	= CHIP_BUSTYPE_LPC, /* A/A Mux */
-		.manufacture_id	= SST_ID,
- 		.model_id	= SST_49LF080A,
-		.total_size	= 1024,
-		.page_size	= 4096,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_FIXME, 
-		.erase		= erase_49lf040,
-		.write		= write_49lf040,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "SST49LF160C",
-		.bustype	= CHIP_BUSTYPE_LPC,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_49LF160C,
-		.total_size	= 2048,
-		.page_size	= 4 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_49lfxxxc,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */
-		.erase		= erase_49lfxxxc,
-		.write		= write_49lfxxxc,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M25P05-A",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P05A,
-		.total_size	= 64,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	/* The ST M25P05 is a bit of a problem. It has the same ID as the
-	 * ST M25P05-A in RES mode, but supports only 128 byte writes instead
-	 * of 256 byte writes. We rely heavily on the fact that probe_spi_res
-	 * only is successful if RDID does not work.
-	 */
-	{
-		.vendor		= "ST",
-		.name		= "M25P05.RES",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P05_RES,
-		.total_size	= 64,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_res,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_1, /* 128 */
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M25P10-A",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P10A,
-		.total_size	= 128,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	/* The ST M25P10 has the same problem as the M25P05. */
-	{
-		.vendor		= "ST",
-		.name		= "M25P10.RES",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P10_RES,
-		.total_size	= 128,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_res,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_1, /* 128 */
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M25P20",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P20,
-		.total_size	= 256,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M25P40",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P40,
-		.total_size	= 512,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M25P40-old",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P40_RES,
-		.total_size	= 512,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_res,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M25P80",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P80,
-		.total_size	= 1024,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M25P16",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P16,
-		.total_size	= 2048,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M25P32",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P32,
-		.total_size	= 4096,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M25P64",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P64,
-		.total_size	= 8192,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M25P128",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P128,
-		.total_size	= 16384,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M29F002B",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M29F002B,
-		.total_size	= 256,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= erase_m29f002,
-		.write		= write_m29f002b,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M29F002T/NT",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M29F002T,
-		.total_size	= 256,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= erase_m29f002,
-		.write		= write_m29f002t,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M29F040B",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M29F040B,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_29f040b,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */
-		.erase		= erase_29f040b,
-		.write		= write_29f040b,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M29F400BT",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M29F400BT,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_m29f400bt,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (m29f400bt.c) */
-		.erase		= erase_m29f400bt,
-		.write		= write_coreboot_m29f400bt,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M29W010B",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M29W010B,
-		.total_size	= 128,
-		.page_size	= 16 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M29W040B",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M29W040B,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M50FLW040A",
-		.bustype	= CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50FLW040A,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_stm50flw0x0x,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */
-		.erase		= erase_stm50flw0x0x,
-		.write		= write_stm50flw0x0x,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M50FLW040B",
-		.bustype	= CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50FLW040B,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_stm50flw0x0x,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */
-		.erase		= erase_stm50flw0x0x,
-		.write		= write_stm50flw0x0x,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M50FLW080A",
-		.bustype	= CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50FLW080A,
-		.total_size	= 1024,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_stm50flw0x0x,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */
-		.erase		= erase_stm50flw0x0x,
-		.write		= write_stm50flw0x0x,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M50FLW080B",
-		.bustype	= CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50FLW080B,
-		.total_size	= 1024,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_stm50flw0x0x,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */
-		.erase		= erase_stm50flw0x0x,
-		.write		= write_stm50flw0x0x,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M50FW002",
-		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50FW002,
-		.total_size	= 256,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_49lfxxxc,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M50FW016",
-		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50FW016,
-		.total_size	= 2048,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (82802ab.c) */
-		.erase		= erase_82802ab,
-		.write		= write_82802ab,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M50FW040",
-		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50FW040,
-		.total_size	= 512,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_82802ab,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (82802ab.c) */
-		.erase		= erase_82802ab,
-		.write		= write_82802ab,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M50FW080",
-		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50FW080,
-		.total_size	= 1024,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_82802ab,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (82802ab.c) */
-		.erase		= erase_82802ab,
-		.write		= write_82802ab,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "M50LPW116",
-		.bustype	= CHIP_BUSTYPE_LPC, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50LPW116,
-		.total_size	= 2048,
-		.page_size	= 64 * 1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SyncMOS",
-		.name		= "S29C31004T",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SYNCMOS_ID,
-		.model_id	= S29C31004T,
-		.total_size	= 512,
-		.page_size	= 128,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SyncMOS",
-		.name		= "S29C51001T",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SYNCMOS_ID,
-		.model_id	= S29C51001T,
-		.total_size	= 128,
-		.page_size	= 128,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SyncMOS",
-		.name		= "S29C51002T",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SYNCMOS_ID,
-		.model_id	= S29C51002T,
-		.total_size	= 256,
-		.page_size	= 128,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "SyncMOS",
-		.name		= "S29C51004T",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= SYNCMOS_ID,
-		.model_id	= S29C51004T,
-		.total_size	= 512,
-		.page_size	= 128,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "TI",
-		.name		= "TMS29F002RB",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= TI_OLD_ID,
-		.model_id	= TI_TMS29F002RB,
-		.total_size	= 256,
-		.page_size	= 16384, /* Non-uniform sectors */
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "TI",
-		.name		= "TMS29F002RT",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= TI_OLD_ID,
-		.model_id	= TI_TMS29F002RT,
-		.total_size	= 256,
-		.page_size	= 16384, /* Non-uniform sectors */
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W25x10",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= W_25X10,
-		.total_size	= 128,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W25x20",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= W_25X20,
-		.total_size	= 256,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W25x40",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= W_25X40,
-		.total_size	= 512,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W25x80",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= W_25X80,
-		.total_size	= 1024,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W25x16",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= W_25X16,
-		.total_size	= 2048,
-		.page_size	= 256,
-		.tested		= TEST_OK_PR,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W25x32",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= W_25X32,
-		.total_size	= 4096,
-		.page_size	= 256,
-		.tested		= TEST_OK_PROBE,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W25x64",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= W_25X64,
-		.total_size	= 8192,
-		.page_size	= 256,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= spi_chip_erase_c7,
-		.write		= spi_chip_write_256,
-		.read		= spi_chip_read,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W29C011",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= W_29C011,
-		.total_size	= 128,
-		.page_size	= 128,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 10,		/* used datasheet for the W29C011A */
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W29C020C",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= W_29C020C,
-		.total_size	= 256,
-		.page_size	= 128,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 10, 
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W29C040P",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= W_29C040P,
-		.total_size	= 512,
-		.page_size	= 256,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 10, 
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W29EE011",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= W_29C011,
-		.total_size	= 128,
-		.page_size	= 128,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_w29ee011,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (w29ee011.c) */
-		.erase		= erase_chip_jedec,
-		.write		= write_jedec,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W39V040A",
-		.bustype	= CHIP_BUSTYPE_LPC,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= W_39V040A,
-		.total_size	= 512,
-		.page_size	= 64*1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 10, 
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W39V040B",
-		.bustype	= CHIP_BUSTYPE_LPC,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= W_39V040B,
-		.total_size	= 512,
-		.page_size	= 64*1024,
-		.tested		= TEST_OK_PR | TEST_BAD_ERASE | TEST_BAD_WRITE,
-		.probe		= probe_jedec,
-		.probe_timing	= 10, 
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W39V040C",
-		.bustype	= CHIP_BUSTYPE_LPC,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= W_39V040C,
-		.total_size	= 512,
-		.page_size	= 64*1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_w39v040c,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (w39v040c.c) */
-		.erase		= erase_w39v040c,
-		.write		= write_w39v040c,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W39V040FA",
-		.bustype	= CHIP_BUSTYPE_FWH,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= W_39V040FA,
-		.total_size	= 512,
-		.page_size	= 64*1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 10, 
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W39V080A",
-		.bustype	= CHIP_BUSTYPE_LPC,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= W_39V080A,
-		.total_size	= 1024,
-		.page_size	= 64*1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 10, 
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W49F002U",
-		.bustype	= CHIP_BUSTYPE_PARALLEL,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= W_49F002U,
-		.total_size	= 256,
-		.page_size	= 128,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 10,
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W49V002A",
-		.bustype	= CHIP_BUSTYPE_LPC,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= W_49V002A,
-		.total_size	= 256,
-		.page_size	= 128,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
-		.probe_timing	= 10, 
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W49V002FA",
-		.bustype	= CHIP_BUSTYPE_FWH,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= W_49V002FA,
-		.total_size	= 256,
-		.page_size	= 128,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
-		.probe_timing	= 10,
-		.erase		= erase_chip_jedec,
-		.write		= write_49f002,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W39V080FA",
-		.bustype	= CHIP_BUSTYPE_FWH,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= W_39V080FA,
-		.total_size	= 1024,
-		.page_size	= 64*1024,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_winbond_fwhub,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (w39v080fa.c) */
-		.erase		= erase_winbond_fwhub,
-		.write		= write_winbond_fwhub,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "W39V080FA (dual mode)",
-		.bustype	= CHIP_BUSTYPE_FWH,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= W_39V080FA_DM,
-		.total_size	= 512,
-		.page_size	= 64*1024,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_winbond_fwhub,
-		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (w39v080fa.c) */
-		.erase		= erase_winbond_fwhub,
-		.write		= write_winbond_fwhub,
-		.read		= read_memmapped,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "unknown Atmel SPI chip",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "EON",
-		.name		= "unknown EON SPI chip",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "unknown Macronix SPI chip",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= MX_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "PMC",
-		.name		= "unknown PMC SPI chip",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "unknown SST SPI chip",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "unknown ST SPI chip",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "Sanyo",
-		.name		= "unknown Sanyo SPI chip",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= SANYO_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.probe_timing	= TIMING_ZERO,
-		.erase		= NULL,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "Generic",
-		.name		= "unknown SPI chip (RDID)",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= GENERIC_MANUF_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.erase		= NULL,
-		.write		= NULL,
-	},
-	{
-		.vendor		= "Generic",
-		.name		= "unknown SPI chip (REMS)",
-		.bustype	= CHIP_BUSTYPE_SPI,
-		.manufacture_id	= GENERIC_MANUF_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rems,
-		.erase		= NULL,
-		.write		= NULL,
-	},
-
-	{ NULL 	}
-};
diff --git a/flashchips.h b/flashchips.h
deleted file mode 100644
index 684b8b9..0000000
--- a/flashchips.h
+++ /dev/null
@@ -1,501 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- * Copyright (C) 2000 Ronald G. Minnich <rminnich@gmail.com>
- * Copyright (C) 2005-2007 coresystems GmbH <stepan@coresystems.de>
- * Copyright (C) 2006-2009 Carl-Daniel Hailfinger
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#ifndef __FLASHCHIPS_H__
-#define __FLASHCHIPS_H__ 1
-
-/*
- * Please keep this list sorted alphabetically by manufacturer. The first
- * entry of each section should be the manufacturer ID, followed by the
- * list of devices from that manufacturer (sorted by device IDs).
- *
- * All LPC/FWH parts (parallel flash) have 8-bit device IDs if there is no
- * continuation code.
- * SPI parts have 16-bit device IDs if they support RDID.
- */
-
-#define GENERIC_MANUF_ID	0xffff	/* Check if there is a vendor ID */
-#define GENERIC_DEVICE_ID	0xffff	/* Only match the vendor ID */
-
-#define ALLIANCE_ID		0x52	/* Alliance Semiconductor */
-
-#define AMD_ID			0x01	/* AMD */
-#define AM_29DL400BT		0x0C
-#define AM_29DL400BB		0x0F
-#define AM_29DL800BT		0x4A
-#define AM_29DL800BB		0xCB
-#define AM_29F002BB		0x34	/* Same as Am29F002NBB */
-#define AM_29F002BT		0xB0	/* Same as Am29F002NBT */
-#define AM_29F004BB		0x7B
-#define AM_29F004BT		0x77
-#define AM_29F016D		0xAD
-#define AM_29F010B		0x20	/* Same as Am29F010A */
-#define AM_29F040B		0xA4
-#define AM_29F080B		0xD5
-#define AM_29F200BB		0x57
-#define AM_29F200BT		0x51
-#define AM_29F400BB		0xAB
-#define AM_29F400BT		0x23
-#define AM_29F800BB		0x58
-#define AM_29F800BT		0xD6
-#define AM_29LV002BB		0xC2
-#define AM_29LV002BT		0x40
-#define AM_29LV004BB		0xB6
-#define AM_29LV004BT		0xB5
-#define AM_29LV008BB		0x37
-#define AM_29LV008BT		0x3E
-#define AM_29LV040B		0x4F
-#define AM_29LV080B		0x38	/* Same as Am29LV081B */
-#define AM_29LV200BB		0xBF
-#define AM_29LV200BT		0x3B
-#define AM_29LV800BB		0x5B	/* Same as Am29LV800DB */
-#define AM_29LV400BT		0xB9
-#define AM_29LV400BB		0xBA
-#define AM_29LV800BT		0xDA	/* Same as Am29LV800DT */
-
-#define AMIC_ID			0x7F37	/* AMIC */
-#define AMIC_ID_NOPREFIX	0x37	/* AMIC */
-#define AMIC_A25L40P		0x2013
-#define AMIC_A29002B		0x0d
-#define AMIC_A29002T		0x8C	/* Same as A290021T */
-#define AMIC_A29040B		0x86
-#define AMIC_A29400T		0xB0	/* Same as 294001T */
-#define AMIC_A29400U		0x31	/* Same as A294001U */
-#define AMIC_A29800T		0x0E
-#define AMIC_A29800U		0x8F
-#define AMIC_A29L004T		0x34	/* Same as A29L400T */
-#define AMIC_A29L004U		0xB5	/* Same as A29L400U */
-#define AMIC_A29L008T		0x1A	/* Same as A29L800T */
-#define AMIC_A29L008U		0x9B	/* Same as A29L800U */
-#define AMIC_A29L040		0x92
-#define AMIC_A49LF040A		0x9d
-
-/* This chip vendor/device ID is probably a misinterpreted LHA header. */
-#define ASD_ID			0x25	/* ASD, not listed in JEP106W */
-#define ASD_AE49F2008		0x52
-
-#define ATMEL_ID		0x1F	/* Atmel */
-#define AT_25DF021		0x4300
-#define AT_25DF041A		0x4401
-#define AT_25DF081		0x4502
-#define AT_25DF161		0x4602
-#define AT_25DF321		0x4700	/* Same as 26DF321 */
-#define AT_25DF321A		0x4701
-#define AT_25DF641		0x4800
-#define AT_25F512A		0x65 /* Needs special RDID. AT25F512A_RDID 15 1d */
-#define AT_25F512B		0x6500
-#define AT_25FS010		0x6601
-#define AT_25FS040		0x6604
-#define AT_26DF041		0x4400
-#define AT_26DF081		0x4500	/* guessed, no datasheet available */
-#define AT_26DF081A		0x4501
-#define AT_26DF161		0x4600
-#define AT_26DF161A		0x4601
-#define AT_26DF321		0x4700	/* Same as 25DF321 */
-#define AT_26F004		0x0400
-#define AT_29C040A		0xA4
-#define AT_29C010A		0xD5	
-#define AT_29C020		0xDA
-#define AT_29C512		0x5D	
-#define AT_45BR3214B		/* No ID available */
-#define AT_45CS1282		0x2920
-#define AT_45D011		/* No ID available */
-#define AT_45D021A		/* No ID available */
-#define AT_45D041A		/* No ID available */
-#define AT_45D081A		/* No ID available */
-#define AT_45D161		/* No ID available */
-#define AT_45DB011		/* No ID available */
-#define AT_45DB011B		/* No ID available */
-#define AT_45DB011D		0x2200
-#define AT_45DB021A		/* No ID available */
-#define AT_45DB021B		/* No ID available */
-#define AT_45DB021D		0x2300
-#define AT_45DB041A		/* No ID available */
-#define AT_45DB041D		0x2400
-#define AT_45DB081A		/* No ID available */
-#define AT_45DB081D		0x2500
-#define AT_45DB161		/* No ID available */
-#define AT_45DB161B		/* No ID available */
-#define AT_45DB161D		0x2600
-#define AT_45DB321		/* No ID available */
-#define AT_45DB321B		/* No ID available */
-#define AT_45DB321C		0x2700
-#define AT_45DB321D		0x2701 /* Buggy data sheet */
-#define AT_45DB642		/* No ID available */
-#define AT_45DB642D		0x2800
-#define AT_49BV512		0x03
-#define AT_49F002N		0x07	/* for AT49F002(N)  */
-#define AT_49F002NT		0x08	/* for AT49F002(N)T */
-
-#define CATALYST_ID		0x31	/* Catalyst */
-
-#define EMST_ID			0x8C	/* EMST / EFST Elite Flash Storage */
-#define EMST_F49B002UA		0x00
-
-/*
- * EN25 chips are SPI, first byte of device ID is memory type,
- * second byte of device ID is log(bitsize)-9.
- * Vendor and device ID of EN29 series are both prefixed with 0x7F, which
- * is the continuation code for IDs in bank 2.
- * Vendor ID of EN25 series is NOT prefixed with 0x7F, this results in
- * a collision with Mitsubishi. Mitsubishi once manufactured flash chips.
- * Let's hope they are not manufacturing SPI flash chips as well.
- */
-#define EON_ID			0x7F1C	/* EON Silicon Devices */
-#define EON_ID_NOPREFIX		0x1C	/* EON, missing 0x7F prefix */
-#define EN_25B05		0x2010	/* Same as P05, 2^19 kbit or 2^16 kByte */
-#define EN_25B10		0x2011	/* Same as P10 */
-#define EN_25B20		0x2012	/* Same as P20 */
-#define EN_25B40		0x2013	/* Same as P40 */
-#define EN_25B80		0x2014	/* Same as P80 */
-#define EN_25B16		0x2015	/* Same as P16 */
-#define EN_25B32		0x2016	/* Same as P32 */
-#define EN_25B64		0x2017	/* Same as P64 */
-#define EN_25D16		0x3015
-#define EN_25F05		0x3110
-#define EN_25F10		0x3111
-#define EN_25F20		0x3112
-#define EN_25F40		0x3113
-#define EN_25F80		0x3114
-#define EN_25F16		0x3115
-#define EN_25F32		0x3116
-#define EN_29F512		0x7F21
-#define EN_29F010		0x7F20
-#define EN_29F040A		0x7F04
-#define EN_29LV010		0x7F6E
-#define EN_29LV040A		0x7F4F	/* EN_29LV040(A) */
-#define EN_29F002T		0x7F92	/* Same as EN29F002A */
-#define EN_29F002B		0x7F97	/* Same as EN29F002AN */
-
-#define FUJITSU_ID		0x04	/* Fujitsu */
-#define MBM29DL400BC		0x0F
-#define MBM29DL400TC		0x0C
-#define MBM29DL800BA		0xCB
-#define MBM29DL800TA		0x4A
-#define MBM29F002BC		0x34
-#define MBM29F002TC		0xB0
-#define MBM29F004BC		0x7B
-#define MBM29F004TC		0x77
-#define MBM29F040C		0xA4
-#define MBM29F080A		0xD5
-#define MBM29F200BC		0x57
-#define MBM29F200TC		0x51
-#define MBM29F400BC		0xAB
-#define MBM29F400TC		0x23
-#define MBM29F800BA		0x58
-#define MBM29F800TA		0xD6
-#define MBM29LV002BC		0xC2
-#define MBM29LV002TC		0x40
-#define MBM29LV004BC		0xB6
-#define MBM29LV004TC		0xB5
-#define MBM29LV008BA		0x37
-#define MBM29LV008TA		0x3E
-#define MBM29LV080A		0x38
-#define MBM29LV200BC		0xBF
-#define MBM29LV200TC		0x3B
-#define MBM29LV400BC		0xBA
-#define MBM29LV400TC		0xB9
-#define MBM29LV800BA		0x5B	/* Same as MBM29LV800BE */
-#define MBM29LV800TA		0xDA	/* Same as MBM29LV800TE */
-
-#define HYUNDAI_ID		0xAD	/* Hyundai */
-#define HY_29F400T		0x23	/* Same as HY_29F400AT */
-#define HY_29F800B		0x58	/* Same as HY_29F800AB */
-#define HY_29LV800B		0x5B
-#define HY_29F040A		0xA4
-#define HY_29F400B		0xAB	/* Same as HY_29F400AB */
-#define HY_29F002		0xB0
-#define HY_29LV400T		0xB9
-#define HY_29LV400B		0xBA
-#define HY_29F080		0xD5
-#define HY_29F800T		0xD6	/* Same as HY_29F800AT */
-#define HY_29LV800T		0xDA
-
-#define IMT_ID			0x7F1F	/* Integrated Memory Technologies */
-#define IM_29F004B		0xAE
-#define IM_29F004T		0xAF
-
-#define INTEL_ID		0x89	/* Intel */
-#define I_82802AB		0xAD
-#define I_82802AC		0xAC
-#define P28F001BXT		0x94	/* 28F001BX-T */
-#define P28F001BXB		0x95	/* 28F001BX-B */
-#define SHARP_LH28F008SA	0xA2	/* Sharp chip, Intel Vendor ID */
-#define SHARP_LH28F008SC	0xA6	/* Sharp chip, Intel Vendor ID */
-
-#define ISSI_ID			0xD5	/* ISSI Integrated Silicon Solutions */
-
-/*
- * MX25 chips are SPI, first byte of device ID is memory type,
- * second byte of device ID is log(bitsize)-9.
- * Generalplus SPI chips seem to be compatible with Macronix
- * and use the same set of IDs.
- */
-#define MX_ID			0xC2	/* Macronix (MX) */
-#define MX_25L512		0x2010	/* Same as MX25V512 */
-#define MX_25L1005		0x2011
-#define MX_25L2005		0x2012
-#define MX_25L4005		0x2013	/* MX25L4005{,A} */
-#define MX_25L8005		0x2014	/* Same as MX25V8005 */
-#define MX_25L1605		0x2015	/* MX25L1605{,A,D} */
-#define MX_25L3205		0x2016	/* MX25L3205{,A} */
-#define MX_25L6405		0x2017	/* MX25L3205{,D} */
-#define MX_25L12805		0x2018	/* MX25L12805 */
-#define MX_25L1635D		0x2415
-#define MX_25L3235D		0x5E16	/* MX25L3225D/MX25L3235D/MX25L3237D */
-#define MX_29F001B		0x19
-#define MX_29F001T		0x18
-#define MX_29F002B		0x34	/* Same as MX29F002NB */
-#define MX_29F002T		0xB0	/* Same as MX29F002NT */
-#define MX_29F004B		0x46
-#define MX_29F004T		0x45
-#define MX_29F022T		0x36	/* Same as MX29F022NT */
-#define MX_29F040		0xA4	/* Same as MX29F040C */
-#define MX_29F080		0xD5
-#define MX_29F200B		0x57	/* Same as MX29F200CB */
-#define MX_29F200T		0x51	/* Same as MX29F200CT */
-#define MX_29F400B		0xAB	/* Same as MX29F400CB */
-#define MX_29F400T		0x23	/* Same as MX29F400CT */
-#define MX_29F800B		0x58
-#define MX_29F800T		0xD6
-#define MX_29LV002CB		0x5A
-#define MX_29LV002CT		0x59
-#define MX_29LV004B		0xB6	/* Same as MX29LV004CB */
-#define MX_29LV004T		0xB5	/* Same as MX29LV004CT */
-#define MX_29LV008B		0x37	/* Same as MX29LV008CB */
-#define MX_29LV008T		0x3E	/* Same as MX29LV008CT */
-#define MX_29LV040		0x4F	/* Same as MX29LV040C */
-#define MX_29LV081		0x38
-#define MX_29LV128DB		0x7A
-#define MX_29LV128DT		0x7E
-#define MX_29LV160DB		0x49	/* Same as MX29LV161DB/MX29LV160CB */
-#define MX_29LV160DT		0xC4	/* Same as MX29LV161DT/MX29LV160CT */
-#define MX_29LV320DB		0xA8	/* Same as MX29LV321DB */
-#define MX_29LV320DT		0xA7	/* Same as MX29LV321DT */
-#define MX_29LV400B		0xBA	/* Same as MX29LV400CB */
-#define MX_29LV400T		0xB9	/* Same as MX29LV400CT */
-#define MX_29LV640DB		0xCB	/* Same as MX29LV640EB */
-#define MX_29LV640DT		0xC9	/* Same as MX29LV640ET */
-#define MX_29LV800B		0x5B	/* Same as MX29LV800CB */
-#define MX_29LV800T		0xDA	/* Same as MX29LV800CT */
-#define MX_29SL402CB		0xF1
-#define MX_29SL402CT		0x70
-#define MX_29SL800CB		0x6B	/* Same as MX29SL802CB */
-#define MX_29SL800CT		0xEA	/* Same as MX29SL802CT */
-
-/*
- * Programmable Micro Corp is listed in JEP106W in bank 2, so it should
- * have a 0x7F continuation code prefix.
- */
-#define PMC_ID			0x7F9D	/* PMC */
-#define PMC_ID_NOPREFIX		0x9D	/* PMC, missing 0x7F prefix */
-#define PMC_25LV512		0x7B
-#define PMC_25LV010		0x7C
-#define PMC_25LV020		0x7D
-#define PMC_25LV040		0x7E
-#define PMC_25LV080B		0x13
-#define PMC_25LV016B		0x14
-#define PMC_29F002T		0x1D
-#define PMC_29F002B		0x2D
-#define PMC_39LV512		0x1B
-#define PMC_39F010		0x1C	/* Same as Pm39LV010 */
-#define PMC_39LV020		0x3D
-#define PMC_39LV040		0x3E
-#define PMC_39F020		0x4D
-#define PMC_39F040		0x4E
-#define PMC_49FL002		0x6D
-#define PMC_49FL004		0x6E
-
-/* 
- * The Sanyo chip found so far uses SPI, first byte is manufacture code,
- * second byte is the device code,
- * third byte is a dummy byte.
- */
-#define SANYO_ID		0x62
-#define SANYO_LE25FW203A	0x1600
-
-#define SHARP_ID		0xB0	/* Sharp */
-#define SHARP_LH28F008BJxxPT	0xEC
-#define SHARP_LH28F008BJxxPB	0xED
-#define SHARP_LH28F800BVxxBTL	0x4B
-#define SHARP_LH28F800BVxxBV	0x4D
-#define SHARP_LH28F800BVxxTV	0x4C
-#define SHARP_LHF00L02		0xC9	/* Same as LHF00L06/LHF00L07 */
-#define SHARP_LHF00L04		0xCF	/* Same as LHF00L03/LHF00L05 */
-
-/*
- * Spansion was previously a joint venture of AMD and Fujitsu.
- * S25 chips are SPI. The first device ID byte is memory type and
- * the second device ID byte is memory capacity.
- */
-#define SPANSION_ID		0x01	/* Spansion, same ID as AMD */
-#define SPANSION_S25FL016A	0x0214
-
-/*
- * SST25 chips are SPI, first byte of device ID is memory type, second
- * byte of device ID is related to log(bitsize) at least for some chips.
- */
-#define SST_ID			0xBF	/* SST */
-#define SST_25WF512		0x2501
-#define SST_25WF010		0x2502
-#define SST_25WF020		0x2503
-#define SST_25WF040		0x2504
-#define SST_25VF512A_REMS	0x48	/* REMS or RES opcode */
-#define SST_25VF010_REMS	0x49	/* REMS or RES opcode */
-#define SST_25VF020_REMS	0x43	/* REMS or RES opcode */
-#define SST_25VF040_REMS	0x44	/* REMS or RES opcode */
-#define SST_25VF040B		0x258D
-#define SST_25VF040B_REMS	0x8D	/* REMS or RES opcode */
-#define SST_25VF080_REMS	0x80	/* REMS or RES opcode */
-#define SST_25VF080B		0x258E
-#define SST_25VF080B_REMS	0x8E	/* REMS or RES opcode */
-#define SST_25VF016B		0x2541
-#define SST_25VF032B		0x254A
-#define SST_25VF032B_REMS	0x4A	/* REMS or RES opcode */
-#define SST_26VF016		0x2601
-#define SST_26VF032		0x2602
-#define SST_27SF512		0xA4
-#define SST_27SF010		0xA5
-#define SST_27SF020		0xA6
-#define SST_27VF010		0xA9
-#define SST_27VF020		0xAA
-#define SST_28SF040		0x04
-#define SST_29EE512		0x5D
-#define SST_29EE010		0x07
-#define SST_29LE010		0x08	/* Same as SST29VE010 */
-#define SST_29EE020A		0x10	/* Same as SST29EE020 */
-#define SST_29LE020		0x12	/* Same as SST29VE020 */
-#define SST_29SF020		0x24
-#define SST_29VF020		0x25
-#define SST_29SF040		0x13
-#define SST_29VF040		0x14
-#define SST_39SF010		0xB5
-#define SST_39SF020		0xB6	/* Same as 39SF020A */
-#define SST_39SF040		0xB7
-#define SST_39VF512		0xD4
-#define SST_39VF010		0xD5
-#define SST_39VF020		0xD6	/* Same as 39LF020 */
-#define SST_39VF040		0xD7	/* Same as 39LF040 */
-#define SST_39VF080		0xD8	/* Same as 39LF080/39VF080/39VF088 */
-#define SST_49LF040B		0x50
-#define SST_49LF040		0x51
-#define SST_49LF020		0x61
-#define SST_49LF020A		0x52
-#define SST_49LF030A		0x1C
-#define SST_49LF080A		0x5B
-#define SST_49LF002A		0x57
-#define SST_49LF003A		0x1B
-#define SST_49LF004A		0x60	/* Same as 49LF004B */
-#define SST_49LF008A		0x5A
-#define SST_49LF004C		0x54
-#define SST_49LF008C		0x59
-#define SST_49LF016C		0x5C
-#define SST_49LF160C		0x4C
-
-/*
- * ST25P chips are SPI, first byte of device ID is memory type, second
- * byte of device ID is related to log(bitsize) at least for some chips.
- */
-#define ST_ID			0x20	/* ST / SGS/Thomson */
-#define ST_M25P05A		0x2010
-#define ST_M25P05_RES		0x10	/* Same code as M25P10. */
-#define ST_M25P10A		0x2011
-#define ST_M25P10_RES		0x10	/* Same code as M25P05. */
-#define ST_M25P20		0x2012
-#define ST_M25P40		0x2013
-#define ST_M25P40_RES		0x12
-#define ST_M25P80		0x2014
-#define ST_M25P16		0x2015
-#define ST_M25P32		0x2016
-#define ST_M25P64		0x2017
-#define ST_M25P128		0x2018
-#define ST_M25PE10		0x8011
-#define ST_M25PE20		0x8012
-#define ST_M25PE40		0x8013
-#define ST_M25PE80		0x8014
-#define ST_M25PE16		0x8015
-#define ST_M50FLW040A		0x08
-#define ST_M50FLW040B		0x28
-#define ST_M50FLW080A		0x80
-#define ST_M50FLW080B		0x81
-#define ST_M50FW002		0x29
-#define ST_M50FW040		0x2C
-#define ST_M50FW080		0x2D
-#define ST_M50FW016		0x2E
-#define ST_M50LPW116		0x30
-#define ST_M29F002B		0x34	/* Same as M29F002BB */
-#define ST_M29F002T		0xB0	/* Same as M29F002BT/M29F002NT/M29F002BNT */
-#define ST_M29F040B		0xE2	/* Same as M29F040 */
-#define ST_M29F080		0xF1
-#define ST_M29F200BT		0xD3
-#define ST_M29F200BB		0xD4
-#define ST_M29F400BT		0xD5	/* Same as M29F400T */
-#define ST_M29F400BB		0xD6	/* Same as M29F400B */
-#define ST_M29F800DB		0x58
-#define ST_M29F800DT		0xEC
-#define ST_M29W010B		0x23
-#define ST_M29W040B		0xE3
-
-#define SYNCMOS_ID		0x40	/* SyncMOS and Mosel Vitelic */
-#define S29C51001T		0x01
-#define S29C51002T		0x02
-#define S29C51004T		0x03
-#define S29C31004T		0x63
-
-#define TI_ID			0x97	/* Texas Instruments */
-#define TI_OLD_ID		0x01	/* TI chips from last century */
-#define TI_TMS29F002RT		0xB0
-#define TI_TMS29F002RB		0x34
-
-/*
- * W25X chips are SPI, first byte of device ID is memory type, second
- * byte of device ID is related to log(bitsize).
- */
-#define WINBOND_ID		0xDA	/* Winbond */
-#define WINBOND_NEX_ID		0xEF	/* Winbond (ex Nexcom) serial flashes */
-#define W_25X10			0x3011
-#define W_25X20			0x3012
-#define W_25X40			0x3013
-#define W_25X80			0x3014
-#define W_25X16			0x3015
-#define W_25X32			0x3016
-#define W_25X64			0x3017
-#define W_29C011		0xC1
-#define W_29C020C		0x45	/* Same as W29C020 and ASD AE29F2008 */
-#define W_29C040P		0x46	/* Same as W29C040 */
-#define W_29EE011		0xC1
-#define W_39L020		0xB5
-#define W_39L040		0xB6
-#define W_39V040FA		0x34
-#define W_39V040A		0x3D
-#define W_39V040B		0x54
-#define W_39V040C		0x50
-#define W_39V080A		0xD0
-#define W_39V080FA		0xD3
-#define W_39V080FA_DM		0x93
-#define W_49F002U		0x0B
-#define W_49F020		0x8C
-#define W_49V002A		0xB0
-#define W_49V002FA		0x32
-
-#endif /* !FLASHCHIPS_H */
diff --git a/flashrom.8 b/flashrom.8
deleted file mode 100644
index 011840c..0000000
--- a/flashrom.8
+++ /dev/null
@@ -1,302 +0,0 @@
-.TH FLASHROM 8 "May 21, 2009"
-.SH NAME
-flashrom \- detect, read, write, verify and erase flash chips
-.SH SYNOPSIS
-.B flashrom \fR[\fB\-VfLzhRn\fR] [\fB\-E\fR|\fB\-r\fR file|\fB\-w\fR file|\fB\-v\fR file] [\fB\-c\fR chipname]
-         [\fB\-m\fR [vendor:]part] [\fB\-l\fR file] [\fB\-i\fR image] [\fB\-p\fR programmer]
-.SH DESCRIPTION
-.B flashrom
-is a utility for detecting, reading, writing, verifying and erasing flash
-chips. It's often used to flash BIOS/EFI/coreboot/firmware images in-system
-using a supported mainboard, but it also supports flashing of network cards
-(NICs), SATA controller cards, and other external devices which can program
-flash chips.
-.PP
-It supports a wide range of DIP32, PLCC32, DIP8, SO8/SOIC8, TSOP32, and
-TSOP40 chips, which use various protocols such as LPC, FWH, parallel flash,
-or SPI.
-.SH OPTIONS
-Please note that the command line interface for flashrom will change before
-flashrom 1.0. Do not use flashrom in scripts or other automated tools without
-checking that your flashrom version won't interpret options in a different way.
-.PP
-You can specify one of \-E, \-r, \-w, \-v or no operation.
-If no operation is specified, then all that happens
-is that flash info is dumped and the flash chip is set to writable.
-.TP
-.B "\-r, \-\-read <file>"
-Read flash ROM contents and save them into the given
-.BR <file> .
-.TP
-.B "\-w, \-\-write <file>"
-Write file into flash ROM.
-.TP
-.B "\-n, \-\-noverify"
-Do
-.B not
-verify the flash ROM contents after writing them to the chip. Using this
-option is
-.B not
-recommended, you should only use it if you know what you are doing and you
-feel that the time for verification takes too long.
-.sp
-Typical usage is:
-.B "flashrom -wn file"
-.sp
-This option is only useful in combination with
-.BR \-\-write .
-.TP
-.B "\-v, \-\-verify <file>"
-Verify the flash ROM contents against the given
-.BR <file> .
-.TP
-.B "\-E, \-\-erase"
-Erase the flash ROM chip.
-.TP
-.B "\-V, \-\-verbose"
-More verbose output.
-.TP
-.B "\-c, \-\-chip" <chipname>
-Probe only for specified flash ROM chip.
-.sp
-flashrom supports ROM layouts. This allows you to flash certain parts of
-the flash chip only. A ROM layout file looks like follows:
-.sp
-  00000000:00008fff gfxrom
-  00009000:0003ffff normal
-  00040000:0007ffff fallback
-.sp
-  i.e.:
-  startaddr:endaddr name
-.sp
-All addresses are offsets within the file, not absolute addresses!
-If you only want to update the normal image in a ROM you can say:
-.sp
-.B "  flashrom -w --layout rom.layout --image normal agami_aruma.rom"
-.sp
-To update normal and fallback but leave the VGA BIOS alone, say:
-.sp
-.B "  flashrom -w -l rom.layout -i normal \"
-.br
-.B "           -i fallback agami_aruma.rom"
-.sp
-Currently overlapping sections are not supported.
-.sp
-ROM layouts should replace the \-s and \-e option since they are more
-flexible and they should lead to a ROM update file format with the
-ROM layout and the ROM image in one file (cpio, zip or something?).
-.TP
-.B "\-m, \-\-mainboard" <[vendor:]part>
-Override mainboard settings.
-.sp
-flashrom reads the coreboot table to determine the current mainboard. If no
-coreboot table could be read or if you want to override these values, you can
-specify \-m, e.g.:
-.sp
-.B "  flashrom -w --mainboard AGAMI:ARUMA agami_aruma.rom"
-.sp
-See the 'Supported mainboards' section in the output of 'flashrom \-L' for
-a list of boards which require the specification of the board name, if no
-coreboot table is found.
-.TP
-.B "\-f, \-\-force"
-Force write without checking whether the ROM image file is really meant
-to be used on this board.
-.sp
-Note: This check only works while coreboot is running, and only for those
-boards where the coreboot code supports it.
-.TP
-.B "\-l, \-\-layout <file>"
-Read ROM layout from
-.BR <file> .
-.TP
-.B "\-i, \-\-image <name>"
-Only flash image
-.B <name>
-from flash layout.
-.TP
-.B "\-L, \-\-list\-supported"
-List the flash chips, chipsets, mainboards, and PCI card "programmers"
-supported by flashrom.
-.sp
-There are many unlisted boards which will work out of the box, without
-special support in flashrom. Please let us know if you can verify that
-other boards work or do not work out of the box. For verification you have
-to test an ERASE and/or WRITE operation, so make sure you only do that
-if you have proper means to recover from failure!
-.TP
-.B "\-z, \-\-list\-supported-wiki"
-Same as
-.BR \-\-list\-supported ,
-but outputs the supported hardware in MediaWiki syntax, so that it can be
-easily pasted into the wiki page at http://www.flashrom.org/.
-.TP
-.B "\-p, \-\-programmer <name>"
-Specify the programmer device. Currently supported are:
-.sp
-.BR "* internal" " (default, for in-system flashing in the mainboard)"
-.sp
-.BR "* dummy" " (just prints all operations and accesses)"
-.sp
-.BR "* nic3com" " (for flash ROMs on 3COM network cards)"
-.sp
-.BR "* gfxnvidia" " (for flash ROMs on NVIDIA graphics cards)"
-.sp
-.BR "* drkaiser" " (for flash ROMs on Dr. Kaiser PC-Waechter PCI cards)"
-.sp
-.BR "* satasii" " (for flash ROMs on Silicon Image SATA/IDE controllers)"
-.sp
-.BR "* it87spi" " (for flash ROMs behind an ITE IT87xx Super I/O LPC/SPI translation unit)"
-.sp
-.BR "* ft2232spi" " (for flash ROMs attached to a FT2232H/FT4232H based USB SPI programmer)"
-.sp
-.BR "* serprog" " (for flash ROMs attached to Urja's AVR programmer)"
-.sp
-.BR "* buspiratespi" " (for flash ROMs attached to a Bus Pirate)"
-.sp
-The dummy programmer has an optional parameter specifying the bus types it
-should support. For that you have to use the
-.B "flashrom -p dummy:type"
-syntax where
-.B type
-can be any comma-separated combination of
-.B parallel lpc fwh spi all
-in any order.
-.sp
-Example:
-.B "flashrom -p dummy:lpc,fwh"
-.sp
-If you have multiple supported PCI cards which can program flash chips
-(NICs, SATA/IDE controllers, etc.) in your system, you must use the
-.B "flashrom -p xxxx:bb:dd.f"
-syntax to explicitly select one of them, where
-.B xxxx
-is the name of the programmer
-.B bb
-is the PCI bus number,
-.B dd
-is the PCI device number, and
-.B f
-is the PCI function number of the desired NIC.
-.sp
-Example:
-.B "flashrom -p nic3com:05:04.0"
-.sp
-Currently the following programmers support this mechanism:
-.BR nic3com ,
-.BR gfxnvidia ,
-.BR satasii .
-.sp
-The it87spi programmer has an optional parameter which will set the I/O base
-port of the IT87* SPI controller interface to the port specified in the
-parameter. For that you have to use the
-.B "flashrom -p it87spi:port=portnum"
-syntax where
-.B portnum
-is an I/O port number which must be a multiple of 8.
-.sp
-The ft2232spi programmer has an optional parameter specifying the controller
-type and interface/port it should support. For that you have to use the
-.B "flashrom -p ft2232spi:model,port=interface"
-syntax where
-.B model
-can be any of
-.B 2232H 4232H
-and
-.B interface
-can be any of
-.B A
-.BR B .
-The default model is
-.B 4232H
-and the default interface is
-.BR B .
-.sp
-The serprog programmer has an optional parameter specifying either a serial
-device/baud combination or an IP/port combination for communication with the
-programmer. For serial, you have to use the
-.B "flashrom -p serprog:/dev/device:baud"
-syntax and for IP, you have to use
-.B "flashrom -p serprog:ip:port"
-instead. More information about serprog is available in serprog-protocol.txt in
-the source distribution.
-.sp
-The buspiratespi programmer has a required dev parameter specifying the Bus
-Pirate device node and an optional spispeed parameter specifying the frequency
-of the SPI bus. The parameter delimiter is a comma. Syntax is
-.B "flashrom -p buspiratespi:dev=/dev/device,spispeed=frequency"
-where
-.B frequency
-can be any of
-.B 30k 125k 250k 1M 2M 2.6M 4M 8M
-(in Hz).
-.sp
-Support for some programmers can be disabled at compile time.
-.B "flashrom -h"
-lists all supported programmers.
-.TP
-.B "\-h, \-\-help"
-Show a help text and exit.
-.TP
-.B "\-R, \-\-version"
-Show version information and exit.
-.SH EXIT STATUS
-flashrom exits with 0 on success, 1 on most failures but with 2 if /dev/mem
-(/dev/xsvc on Solaris) can not be opened and with 3 if a call to mmap() fails.
-.SH BUGS
-Please report any bugs at
-.BR http://www.flashrom.org/trac/flashrom/newticket ","
-or on the flashrom mailing list
-.RB "(" http://www.flashrom.org/mailman/listinfo/flashrom ")."
-.SH LICENCE
-.B flashrom
-is covered by the GNU General Public License (GPL), version 2. Some files are
-additionally available under the GPL (version 2, or any later version).
-.SH COPYRIGHT
-.br
-Please see the individual files.
-.SH AUTHORS
-Carl-Daniel Hailfinger
-.br
-Claus Gindhart <claus.gindhart@kontron.com>
-.br
-Dominik Geyer <dominik.geyer@kontron.com>
-.br
-Eric Biederman <ebiederman@lnxi.com>
-.br
-Giampiero Giancipoli <gianci@email.it>
-.br
-Joe Bao <Zheng.Bao@amd.com>
-.br
-Luc Verhaegen <libv@skynet.be>
-.br
-Li-Ta Lo
-.br
-Markus Boas <ryven@ryven.de>
-.br
-Nikolay Petukhov <nikolay.petukhov@gmail.com>
-.br
-Peter Stuge <peter@stuge.se>
-.br
-Reinder E.N. de Haan <lb_reha@mveas.com>
-.br
-Ronald G. Minnich <rminnich@gmail.com>
-.br
-Ronald Hoogenboom <ronald@zonnet.nl>
-.br
-Stefan Reinauer <stepan@coresystems.de>
-.br
-Stefan Wildemann <stefan.wildemann@kontron.com>
-.br
-Steven James <pyro@linuxlabs.com>
-.br
-Uwe Hermann <uwe@hermann-uwe.de>
-.br
-Wang Qingpei <Qingpei.Wang@amd.com>
-.br
-Yinghai Lu <yinghai.lu@amd.com>
-.br
-some others 
-.PP
-This manual page was written by Uwe Hermann <uwe@hermann-uwe.de>.
-It is licensed under the terms of the GNU GPL (version 2 or later).
diff --git a/flashrom.c b/flashrom.c
deleted file mode 100644
index 64a6835..0000000
--- a/flashrom.c
+++ /dev/null
@@ -1,1369 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- * Copyright (C) 2004 Tyan Corp <yhlu@tyan.com>
- * Copyright (C) 2005-2008 coresystems GmbH
- * Copyright (C) 2008,2009 Carl-Daniel Hailfinger
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include "flash.h"
-#include "flashchips.h"
-
-const char *flashrom_version = FLASHROM_VERSION;
-char *chip_to_probe = NULL;
-int verbose = 0;
-enum programmer programmer = PROGRAMMER_INTERNAL;
-char *programmer_param = NULL;
-
-const struct programmer_entry programmer_table[] = {
-	{
-		.name			= "internal",
-		.init			= internal_init,
-		.shutdown		= internal_shutdown,
-		.map_flash_region	= physmap,
-		.unmap_flash_region	= physunmap,
-		.chip_readb		= internal_chip_readb,
-		.chip_readw		= internal_chip_readw,
-		.chip_readl		= internal_chip_readl,
-		.chip_readn		= internal_chip_readn,
-		.chip_writeb		= internal_chip_writeb,
-		.chip_writew		= internal_chip_writew,
-		.chip_writel		= internal_chip_writel,
-		.chip_writen		= fallback_chip_writen,
-		.delay			= internal_delay,
-	},
-
-#if DUMMY_SUPPORT == 1
-	{
-		.name			= "dummy",
-		.init			= dummy_init,
-		.shutdown		= dummy_shutdown,
-		.map_flash_region	= dummy_map,
-		.unmap_flash_region	= dummy_unmap,
-		.chip_readb		= dummy_chip_readb,
-		.chip_readw		= dummy_chip_readw,
-		.chip_readl		= dummy_chip_readl,
-		.chip_readn		= dummy_chip_readn,
-		.chip_writeb		= dummy_chip_writeb,
-		.chip_writew		= dummy_chip_writew,
-		.chip_writel		= dummy_chip_writel,
-		.chip_writen		= dummy_chip_writen,
-		.delay			= internal_delay,
-	},
-#endif
-
-#if NIC3COM_SUPPORT == 1
-	{
-		.name			= "nic3com",
-		.init			= nic3com_init,
-		.shutdown		= nic3com_shutdown,
-		.map_flash_region	= fallback_map,
-		.unmap_flash_region	= fallback_unmap,
-		.chip_readb		= nic3com_chip_readb,
-		.chip_readw		= fallback_chip_readw,
-		.chip_readl		= fallback_chip_readl,
-		.chip_readn		= fallback_chip_readn,
-		.chip_writeb		= nic3com_chip_writeb,
-		.chip_writew		= fallback_chip_writew,
-		.chip_writel		= fallback_chip_writel,
-		.chip_writen		= fallback_chip_writen,
-		.delay			= internal_delay,
-	},
-#endif
-
-#if GFXNVIDIA_SUPPORT == 1
-	{
-		.name			= "gfxnvidia",
-		.init			= gfxnvidia_init,
-		.shutdown		= gfxnvidia_shutdown,
-		.map_flash_region	= fallback_map,
-		.unmap_flash_region	= fallback_unmap,
-		.chip_readb		= gfxnvidia_chip_readb,
-		.chip_readw		= fallback_chip_readw,
-		.chip_readl		= fallback_chip_readl,
-		.chip_readn		= fallback_chip_readn,
-		.chip_writeb		= gfxnvidia_chip_writeb,
-		.chip_writew		= fallback_chip_writew,
-		.chip_writel		= fallback_chip_writel,
-		.chip_writen		= fallback_chip_writen,
-		.delay			= internal_delay,
-	},
-#endif
-
-#if DRKAISER_SUPPORT == 1
-	{
-		.name			= "drkaiser",
-		.init			= drkaiser_init,
-		.shutdown		= drkaiser_shutdown,
-		.map_flash_region	= fallback_map,
-		.unmap_flash_region	= fallback_unmap,
-		.chip_readb		= drkaiser_chip_readb,
-		.chip_readw		= fallback_chip_readw,
-		.chip_readl		= fallback_chip_readl,
-		.chip_readn		= fallback_chip_readn,
-		.chip_writeb		= drkaiser_chip_writeb,
-		.chip_writew		= fallback_chip_writew,
-		.chip_writel		= fallback_chip_writel,
-		.chip_writen		= fallback_chip_writen,
-		.delay			= internal_delay,
-	},
-#endif
-
-#if SATASII_SUPPORT == 1
-	{
-		.name			= "satasii",
-		.init			= satasii_init,
-		.shutdown		= satasii_shutdown,
-		.map_flash_region	= fallback_map,
-		.unmap_flash_region	= fallback_unmap,
-		.chip_readb		= satasii_chip_readb,
-		.chip_readw		= fallback_chip_readw,
-		.chip_readl		= fallback_chip_readl,
-		.chip_readn		= fallback_chip_readn,
-		.chip_writeb		= satasii_chip_writeb,
-		.chip_writew		= fallback_chip_writew,
-		.chip_writel		= fallback_chip_writel,
-		.chip_writen		= fallback_chip_writen,
-		.delay			= internal_delay,
-	},
-#endif
-
-	{
-		.name			= "it87spi",
-		.init			= it87spi_init,
-		.shutdown		= noop_shutdown,
-		.map_flash_region	= fallback_map,
-		.unmap_flash_region	= fallback_unmap,
-		.chip_readb		= noop_chip_readb,
-		.chip_readw		= fallback_chip_readw,
-		.chip_readl		= fallback_chip_readl,
-		.chip_readn		= fallback_chip_readn,
-		.chip_writeb		= noop_chip_writeb,
-		.chip_writew		= fallback_chip_writew,
-		.chip_writel		= fallback_chip_writel,
-		.chip_writen		= fallback_chip_writen,
-		.delay			= internal_delay,
-	},
-
-#if FT2232_SPI_SUPPORT == 1
-	{
-		.name			= "ft2232spi",
-		.init			= ft2232_spi_init,
-		.shutdown		= noop_shutdown, /* Missing shutdown */
-		.map_flash_region	= fallback_map,
-		.unmap_flash_region	= fallback_unmap,
-		.chip_readb		= noop_chip_readb,
-		.chip_readw		= fallback_chip_readw,
-		.chip_readl		= fallback_chip_readl,
-		.chip_readn		= fallback_chip_readn,
-		.chip_writeb		= noop_chip_writeb,
-		.chip_writew		= fallback_chip_writew,
-		.chip_writel		= fallback_chip_writel,
-		.chip_writen		= fallback_chip_writen,
-		.delay			= internal_delay,
-	},
-#endif
-
-#if SERPROG_SUPPORT == 1
-	{
-		.name			= "serprog",
-		.init			= serprog_init,
-		.shutdown		= serprog_shutdown,
-		.map_flash_region	= fallback_map,
-		.unmap_flash_region	= fallback_unmap,
-		.chip_readb		= serprog_chip_readb,
-		.chip_readw		= fallback_chip_readw,
-		.chip_readl		= fallback_chip_readl,
-		.chip_readn		= serprog_chip_readn,
-		.chip_writeb		= serprog_chip_writeb,
-		.chip_writew		= fallback_chip_writew,
-		.chip_writel		= fallback_chip_writel,
-		.chip_writen		= fallback_chip_writen,
-		.delay			= serprog_delay,
-	},
-#endif
-
-#if BUSPIRATE_SPI_SUPPORT == 1
-	{
-		.name			= "buspiratespi",
-		.init			= buspirate_spi_init,
-		.shutdown		= buspirate_spi_shutdown,
-		.map_flash_region	= fallback_map,
-		.unmap_flash_region	= fallback_unmap,
-		.chip_readb		= noop_chip_readb,
-		.chip_readw		= fallback_chip_readw,
-		.chip_readl		= fallback_chip_readl,
-		.chip_readn		= fallback_chip_readn,
-		.chip_writeb		= noop_chip_writeb,
-		.chip_writew		= fallback_chip_writew,
-		.chip_writel		= fallback_chip_writel,
-		.chip_writen		= fallback_chip_writen,
-		.delay			= internal_delay,
-	},
-#endif
-
-	{}, /* This entry corresponds to PROGRAMMER_INVALID. */
-};
-
-int programmer_init(void)
-{
-	return programmer_table[programmer].init();
-}
-
-int programmer_shutdown(void)
-{
-	return programmer_table[programmer].shutdown();
-}
-
-void *programmer_map_flash_region(const char *descr, unsigned long phys_addr,
-				  size_t len)
-{
-	return programmer_table[programmer].map_flash_region(descr,
-							     phys_addr, len);
-}
-
-void programmer_unmap_flash_region(void *virt_addr, size_t len)
-{
-	programmer_table[programmer].unmap_flash_region(virt_addr, len);
-}
-
-void chip_writeb(uint8_t val, chipaddr addr)
-{
-	programmer_table[programmer].chip_writeb(val, addr);
-}
-
-void chip_writew(uint16_t val, chipaddr addr)
-{
-	programmer_table[programmer].chip_writew(val, addr);
-}
-
-void chip_writel(uint32_t val, chipaddr addr)
-{
-	programmer_table[programmer].chip_writel(val, addr);
-}
-
-void chip_writen(uint8_t *buf, chipaddr addr, size_t len)
-{
-	programmer_table[programmer].chip_writen(buf, addr, len);
-}
-
-uint8_t chip_readb(const chipaddr addr)
-{
-	return programmer_table[programmer].chip_readb(addr);
-}
-
-uint16_t chip_readw(const chipaddr addr)
-{
-	return programmer_table[programmer].chip_readw(addr);
-}
-
-uint32_t chip_readl(const chipaddr addr)
-{
-	return programmer_table[programmer].chip_readl(addr);
-}
-
-void chip_readn(uint8_t *buf, chipaddr addr, size_t len)
-{
-	programmer_table[programmer].chip_readn(buf, addr, len);
-}
-
-void programmer_delay(int usecs)
-{
-	programmer_table[programmer].delay(usecs);
-}
-
-void map_flash_registers(struct flashchip *flash)
-{
-	size_t size = flash->total_size * 1024;
-	/* Flash registers live 4 MByte below the flash. */
-	/* FIXME: This is incorrect for nonstandard flashbase. */
-	flash->virtual_registers = (chipaddr)programmer_map_flash_region("flash chip registers", (0xFFFFFFFF - 0x400000 - size + 1), size);
-}
-
-int read_memmapped(struct flashchip *flash, uint8_t *buf, int start, int len)
-{
-	chip_readn(buf, flash->virtual_memory + start, len);
-		
-	return 0;
-}
-
-int min(int a, int b)
-{
-	return (a < b) ? a : b;
-}
-
-int max(int a, int b)
-{
-	return (a > b) ? a : b;
-}
-
-int bitcount(unsigned long a)
-{
-	int i = 0;
-	for (; a != 0; a >>= 1)
-		if (a & 1)
-			i++;
-	return i;
-}
-
-char *strcat_realloc(char *dest, const char *src)
-{
-	dest = realloc(dest, strlen(dest) + strlen(src) + 1);
-	if (!dest)
-		return NULL;
-	strcat(dest, src);
-	return dest;
-}
-
-/* This is a somewhat hacked function similar in some ways to strtok().
- * It will look for needle in haystack, return a copy of needle and remove
- * everything from the first occurrence of needle to the next delimiter
- * from haystack.
- */
-char *extract_param(char **haystack, char *needle, char *delim)
-{
-	char *param_pos, *rest, *tmp;
-	char *dev = NULL;
-	int devlen;
-
-	param_pos = strstr(*haystack, needle);
-	do {
-		if (!param_pos)
-			return NULL;
-		/* Beginning of the string? */
-		if (param_pos == *haystack)
-			break;
-		/* After a delimiter? */
-		if (strchr(delim, *(param_pos - 1)))
-			break;
-		/* Continue searching. */
-		param_pos++;
-		param_pos = strstr(param_pos, needle);
-	} while (1);
-		
-	if (param_pos) {
-		param_pos += strlen(needle);
-		devlen = strcspn(param_pos, delim);
-		if (devlen) {
-			dev = malloc(devlen + 1);
-			if (!dev) {
-				fprintf(stderr, "Out of memory!\n");
-				exit(1);
-			}
-			strncpy(dev, param_pos, devlen);
-			dev[devlen] = '\0';
-		}
-		rest = param_pos + devlen;
-		rest += strspn(rest, delim);
-		param_pos -= strlen(needle);
-		memmove(param_pos, rest, strlen(rest) + 1);
-		tmp = realloc(*haystack, strlen(*haystack) + 1);
-		if (!tmp) {
-			fprintf(stderr, "Out of memory!\n");
-			exit(1);
-		}
-		*haystack = tmp;
-	}
-	
-
-	return dev;
-}
-
-/* start is an offset to the base address of the flash chip */
-int check_erased_range(struct flashchip *flash, int start, int len)
-{
-	int ret;
-	uint8_t *cmpbuf = malloc(len);
-
-	if (!cmpbuf) {
-		fprintf(stderr, "Could not allocate memory!\n");
-		exit(1);
-	}
-	memset(cmpbuf, 0xff, len);
-	ret = verify_range(flash, cmpbuf, start, len, "ERASE");
-	free(cmpbuf);
-	return ret;
-}
-
-/**
- * @cmpbuf	buffer to compare against, cmpbuf[0] is expected to match the
-		flash content at location start
- * @start	offset to the base address of the flash chip
- * @len		length of the verified area
- * @message	string to print in the "FAILED" message
- * @return	0 for success, -1 for failure
- */
-int verify_range(struct flashchip *flash, uint8_t *cmpbuf, int start, int len, char *message)
-{
-	int i, j, starthere, lenhere, ret = 0;
-	int page_size = flash->page_size;
-	uint8_t *readbuf = malloc(page_size);
-	int failcount = 0;
-
-	if (!len)
-		goto out_free;
-
-	if (!flash->read) {
-		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
-		return 1;
-	}
-	if (!readbuf) {
-		fprintf(stderr, "Could not allocate memory!\n");
-		exit(1);
-	}
-
-	if (start + len > flash->total_size * 1024) {
-		fprintf(stderr, "Error: %s called with start 0x%x + len 0x%x >"
-			" total_size 0x%x\n", __func__, start, len,
-			flash->total_size * 1024);
-		ret = -1;
-		goto out_free;
-	}
-	if (!message)
-		message = "VERIFY";
-	
-	/* Warning: This loop has a very unusual condition and body.
-	 * The loop needs to go through each page with at least one affected
-	 * byte. The lowest page number is (start / page_size) since that
-	 * division rounds down. The highest page number we want is the page
-	 * where the last byte of the range lives. That last byte has the
-	 * address (start + len - 1), thus the highest page number is
-	 * (start + len - 1) / page_size. Since we want to include that last
-	 * page as well, the loop condition uses <=.
-	 */
-	for (i = start / page_size; i <= (start + len - 1) / page_size; i++) {
-		/* Byte position of the first byte in the range in this page. */
-		starthere = max(start, i * page_size);
-		/* Length of bytes in the range in this page. */
-		lenhere = min(start + len, (i + 1) * page_size) - starthere;
-		flash->read(flash, readbuf, starthere, lenhere);
-		for (j = 0; j < lenhere; j++) {
-			if (cmpbuf[starthere - start + j] != readbuf[j]) {
-				/* Only print the first failure. */
-				if (!failcount++)
-					fprintf(stderr, "%s FAILED at 0x%08x! "
-						"Expected=0x%02x, Read=0x%02x,",
-						message, starthere + j,
-						cmpbuf[starthere - start + j],
-						readbuf[j]);
-			}
-		}
-	}
-	if (failcount) {
-		fprintf(stderr, " failed byte count from 0x%08x-0x%08x: 0x%x\n",
-			start, start + len - 1, failcount);
-		ret = -1;
-	}
-
-out_free:
-	free(readbuf);
-	return ret;
-}
-
-/* This function generates various test patterns useful for testing controller
- * and chip communication as well as chip behaviour.
- *
- * If a byte can be written multiple times, each time keeping 0-bits at 0
- * and changing 1-bits to 0 if the new value for that bit is 0, the effect
- * is essentially an AND operation. That's also the reason why this function
- * provides the result of AND between various patterns.
- *
- * Below is a list of patterns (and their block length).
- * Pattern 0 is 05 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 (16 Bytes)
- * Pattern 1 is 0a 1a 2a 3a 4a 5a 6a 7a 8a 9a aa ba ca da ea fa (16 Bytes)
- * Pattern 2 is 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f (16 Bytes)
- * Pattern 3 is a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af (16 Bytes)
- * Pattern 4 is 00 10 20 30 40 50 60 70 80 90 a0 b0 c0 d0 e0 f0 (16 Bytes)
- * Pattern 5 is 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f (16 Bytes)
- * Pattern 6 is 00 (1 Byte)
- * Pattern 7 is ff (1 Byte)
- * Patterns 0-7 have a big-endian block number in the last 2 bytes of each 256
- * byte block.
- *
- * Pattern 8 is 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11... (256 B)
- * Pattern 9 is ff fe fd fc fb fa f9 f8 f7 f6 f5 f4 f3 f2 f1 f0 ef ee... (256 B)
- * Pattern 10 is 00 00 00 01 00 02 00 03 00 04... (128 kB big-endian counter)
- * Pattern 11 is ff ff ff fe ff fd ff fc ff fb... (128 kB big-endian downwards)
- * Pattern 12 is 00 (1 Byte)
- * Pattern 13 is ff (1 Byte)
- * Patterns 8-13 have no block number.
- *
- * Patterns 0-3 are created to detect and efficiently diagnose communication
- * slips like missed bits or bytes and their repetitive nature gives good visual
- * cues to the person inspecting the results. In addition, the following holds:
- * AND Pattern 0/1 == Pattern 4
- * AND Pattern 2/3 == Pattern 5
- * AND Pattern 0/1/2/3 == AND Pattern 4/5 == Pattern 6
- * A weakness of pattern 0-5 is the inability to detect swaps/copies between
- * any two 16-byte blocks except for the last 16-byte block in a 256-byte bloc.
- * They work perfectly for detecting any swaps/aliasing of blocks >= 256 bytes.
- * 0x5 and 0xa were picked because they are 0101 and 1010 binary.
- * Patterns 8-9 are best for detecting swaps/aliasing of blocks < 256 bytes.
- * Besides that, they provide for bit testing of the last two bytes of every
- * 256 byte block which contains the block number for patterns 0-6.
- * Patterns 10-11 are special purpose for detecting subblock aliasing with
- * block sizes >256 bytes (some Dataflash chips etc.)
- * AND Pattern 8/9 == Pattern 12
- * AND Pattern 10/11 == Pattern 12
- * Pattern 13 is the completely erased state.
- * None of the patterns can detect aliasing at boundaries which are a multiple
- * of 16 MBytes (but such chips do not exist anyway for Parallel/LPC/FWH/SPI).
- */
-int generate_testpattern(uint8_t *buf, uint32_t size, int variant)
-{
-	int i;
-
-	if (!buf) {
-		fprintf(stderr, "Invalid buffer!\n");
-		return 1;
-	}
-
-	switch (variant) {
-	case 0:
-		for (i = 0; i < size; i++)
-			buf[i] = (i & 0xf) << 4 | 0x5;
-		break;
-	case 1:
-		for (i = 0; i < size; i++)
-			buf[i] = (i & 0xf) << 4 | 0xa;
-		break;
-	case 2:
-		for (i = 0; i < size; i++)
-			buf[i] = 0x50 | (i & 0xf);
-		break;
-	case 3:
-		for (i = 0; i < size; i++)
-			buf[i] = 0xa0 | (i & 0xf);
-		break;
-	case 4:
-		for (i = 0; i < size; i++)
-			buf[i] = (i & 0xf) << 4;
-		break;
-	case 5:
-		for (i = 0; i < size; i++)
-			buf[i] = i & 0xf;
-		break;
-	case 6:
-		memset(buf, 0x00, size);
-		break;
-	case 7:
-		memset(buf, 0xff, size);
-		break;
-	case 8:
-		for (i = 0; i < size; i++)
-			buf[i] = i & 0xff;
-		break;
-	case 9:
-		for (i = 0; i < size; i++)
-			buf[i] = ~(i & 0xff);
-		break;
-	case 10:
-		for (i = 0; i < size % 2; i++) {
-			buf[i * 2] = (i >> 8) & 0xff;
-			buf[i * 2 + 1] = i & 0xff;
-		}
-		if (size & 0x1)
-			buf[i * 2] = (i >> 8) & 0xff;
-		break;
-	case 11:
-		for (i = 0; i < size % 2; i++) {
-			buf[i * 2] = ~((i >> 8) & 0xff);
-			buf[i * 2 + 1] = ~(i & 0xff);
-		}
-		if (size & 0x1)
-			buf[i * 2] = ~((i >> 8) & 0xff);
-		break;
-	case 12:
-		memset(buf, 0x00, size);
-		break;
-	case 13:
-		memset(buf, 0xff, size);
-		break;
-	}
-
-	if ((variant >= 0) && (variant <= 7)) {
-		/* Write block number in the last two bytes of each 256-byte
-		 * block, big endian for easier reading of the hexdump.
-		 * Note that this wraps around for chips larger than 2^24 bytes
-		 * (16 MB).
-		 */
-		for (i = 0; i < size / 256; i++) {
-			buf[i * 256 + 254] = (i >> 8) & 0xff;
-			buf[i * 256 + 255] = i & 0xff;
-		}
-	}
-
-	return 0;
-}
-
-int check_max_decode(enum chipbustype buses, uint32_t size)
-{
-	int limitexceeded = 0;
-	if ((buses & CHIP_BUSTYPE_PARALLEL) &&
-	    (max_rom_decode.parallel < size)) {
-		limitexceeded++;
-		printf_debug("Chip size %u kB is bigger than supported "
-			     "size %u kB of chipset/board/programmer "
-			     "for %s interface, "
-			     "probe/read/erase/write may fail. ", size / 1024,
-			     max_rom_decode.parallel / 1024, "Parallel");
-	}
-	if ((buses & CHIP_BUSTYPE_LPC) && (max_rom_decode.lpc < size)) {
-		limitexceeded++;
-		printf_debug("Chip size %u kB is bigger than supported "
-			     "size %u kB of chipset/board/programmer "
-			     "for %s interface, "
-			     "probe/read/erase/write may fail. ", size / 1024,
-			     max_rom_decode.lpc / 1024, "LPC");
-	}
-	if ((buses & CHIP_BUSTYPE_FWH) && (max_rom_decode.fwh < size)) {
-		limitexceeded++;
-		printf_debug("Chip size %u kB is bigger than supported "
-			     "size %u kB of chipset/board/programmer "
-			     "for %s interface, "
-			     "probe/read/erase/write may fail. ", size / 1024,
-			     max_rom_decode.fwh / 1024, "FWH");
-	}
-	if ((buses & CHIP_BUSTYPE_SPI) && (max_rom_decode.spi < size)) {
-		limitexceeded++;
-		printf_debug("Chip size %u kB is bigger than supported "
-			     "size %u kB of chipset/board/programmer "
-			     "for %s interface, "
-			     "probe/read/erase/write may fail. ", size / 1024,
-			     max_rom_decode.spi / 1024, "SPI");
-	}
-	if (!limitexceeded)
-		return 0;
-	/* Sometimes chip and programmer have more than one bus in common,
-	 * and the limit is not exceeded on all buses. Tell the user.
-	 */
-	if (bitcount(buses) > limitexceeded)
-		printf_debug("There is at least one common chip/programmer "
-			     "interface which can support a chip of this size. "
-			     "You can try --force at your own risk.\n");
-	return 1;
-}
-
-struct flashchip *probe_flash(struct flashchip *first_flash, int force)
-{
-	struct flashchip *flash;
-	unsigned long base = 0;
-	uint32_t size;
-	enum chipbustype buses_common;
-	char *tmp;
-
-	for (flash = first_flash; flash && flash->name; flash++) {
-		if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0)
-			continue;
-		printf_debug("Probing for %s %s, %d KB: ",
-			     flash->vendor, flash->name, flash->total_size);
-		if (!flash->probe && !force) {
-			printf_debug("failed! flashrom has no probe function for this flash chip.\n");
-			continue;
-		}
-		buses_common = buses_supported & flash->bustype;
-		if (!buses_common) {
-			tmp = flashbuses_to_text(buses_supported);
-			printf_debug("skipped. Host bus type %s ", tmp);
-			free(tmp);
-			tmp = flashbuses_to_text(flash->bustype);
-			printf_debug("and chip bus type %s are incompatible.\n", tmp);
-			free(tmp);
-			continue;
-		}
-
-		size = flash->total_size * 1024;
-		check_max_decode(buses_common, size);
-
-		base = flashbase ? flashbase : (0xffffffff - size + 1);
-		flash->virtual_memory = (chipaddr)programmer_map_flash_region("flash chip", base, size);
-
-		if (force)
-			break;
-
-		if (flash->probe(flash) != 1)
-			goto notfound;
-
-		if (first_flash == flashchips
-		    || flash->model_id != GENERIC_DEVICE_ID)
-			break;
-
-notfound:
-		programmer_unmap_flash_region((void *)flash->virtual_memory, size);
-	}
-
-	if (!flash || !flash->name)
-		return NULL;
-
-	printf("Found chip \"%s %s\" (%d KB, %s) at physical address 0x%lx.\n",
-	       flash->vendor, flash->name, flash->total_size,
-	       flashbuses_to_text(flash->bustype), base);
-
-	return flash;
-}
-
-int verify_flash(struct flashchip *flash, uint8_t *buf)
-{
-	int ret;
-	int total_size = flash->total_size * 1024;
-
-	printf("Verifying flash... ");
-
-	ret = verify_range(flash, buf, 0, total_size, NULL);
-
-	if (!ret)
-		printf("VERIFIED.          \n");
-
-	return ret;
-}
-
-int read_flash(struct flashchip *flash, char *filename)
-{
-	unsigned long numbytes;
-	FILE *image;
-	unsigned long size = flash->total_size * 1024;
-	unsigned char *buf = calloc(size, sizeof(char));
-
-	if (!filename) {
-		printf("Error: No filename specified.\n");
-		return 1;
-	}
-	if ((image = fopen(filename, "w")) == NULL) {
-		perror(filename);
-		exit(1);
-	}
-	printf("Reading flash... ");
-	if (!flash->read) {
-		printf("FAILED!\n");
-		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
-		return 1;
-	} else
-		flash->read(flash, buf, 0, size);
-
-	numbytes = fwrite(buf, 1, size, image);
-	fclose(image);
-	free(buf);
-	printf("%s.\n", numbytes == size ? "done" : "FAILED");
-	if (numbytes != size)
-		return 1;
-	return 0;
-}
-
-int erase_flash(struct flashchip *flash)
-{
-	int i, j, k, ret = 0, found = 0;
-
-	printf("Erasing flash chip... ");
-	for (k = 0; k < NUM_ERASEFUNCTIONS; k++) {
-		unsigned long done = 0;
-		struct block_eraser eraser = flash->block_erasers[k];
-
-		printf_debug("Looking at blockwise erase function %i... ", k);
-		if (!eraser.block_erase && !eraser.eraseblocks[0].count) {
-			printf_debug("not defined. "
-				"Looking for another erase function.\n");
-			continue;
-		}
-		if (!eraser.block_erase && eraser.eraseblocks[0].count) {
-			printf_debug("eraseblock layout is known, but no "
-				"matching block erase function found. "
-				"Looking for another erase function.\n");
-			continue;
-		}
-		if (eraser.block_erase && !eraser.eraseblocks[0].count) {
-			printf_debug("block erase function found, but "
-				"eraseblock layout is unknown. "
-				"Looking for another erase function.\n");
-			continue;
-		}
-		found = 1;
-		printf_debug("trying... ");
-		for (i = 0; i < NUM_ERASEREGIONS; i++) {
-			/* count==0 for all automatically initialized array
-			 * members so the loop below won't be executed for them.
-			 */
-			for (j = 0; j < eraser.eraseblocks[i].count; j++) {
-				ret = eraser.block_erase(flash, done + eraser.eraseblocks[i].size * j, eraser.eraseblocks[i].size);
-				if (ret)
-					break;
-			}
-			if (ret)
-				break;
-		}
-		/* If everything is OK, don't try another erase function. */
-		if (!ret)
-			break;
-	}
-	/* If no block erase function was found or block erase failed, retry. */
-	if ((!found || ret) && (flash->erase)) {
-		found = 1;
-		printf_debug("Trying whole-chip erase function... ");
-		ret = flash->erase(flash);
-	}
-	if (!found) {
-		fprintf(stderr, "ERROR: flashrom has no erase function for this flash chip.\n");
-		return 1;
-	}
-
-	if (ret) {
-		fprintf(stderr, "FAILED!\n");
-	} else {
-		printf("SUCCESS.\n");
-	}
-	return ret;
-}
-
-void emergency_help_message(void)
-{
-	fprintf(stderr, "Your flash chip is in an unknown state.\n"
-		"Get help on IRC at irc.freenode.net (channel #flashrom) or\n"
-		"mail flashrom@flashrom.org!\n--------------------"
-		"-----------------------------------------------------------\n"
-		"DO NOT REBOOT OR POWEROFF!\n");
-}
-
-void usage(const char *name)
-{
-	const char *pname;
-	int pnamelen;
-	int remaining = 0;
-	enum programmer p;
-
-	printf("usage: %s [-VfLzhR] [-E|-r file|-w file|-v file] [-c chipname]\n"
-              "       [-m [vendor:]part] [-l file] [-i image] [-p programmer]\n\n", name);
-
-	printf("Please note that the command line interface for flashrom will "
-		"change before\nflashrom 1.0. Do not use flashrom in scripts "
-		"or other automated tools without\nchecking that your flashrom"
-		" version won't interpret options in a different way.\n\n");
-
-	printf
-	    ("   -r | --read:                      read flash and save into file\n"
-	     "   -w | --write:                     write file into flash\n"
-	     "   -v | --verify:                    verify flash against file\n"
-	     "   -n | --noverify:                  don't verify flash against file\n"
-	     "   -E | --erase:                     erase flash device\n"
-	     "   -V | --verbose:                   more verbose output\n"
-	     "   -c | --chip <chipname>:           probe only for specified flash chip\n"
-	     "   -m | --mainboard <[vendor:]part>: override mainboard settings\n"
-	     "   -f | --force:                     force write without checking image\n"
-	     "   -l | --layout <file.layout>:      read ROM layout from file\n"
-	     "   -i | --image <name>:              only flash image name from flash layout\n"
-	     "   -L | --list-supported:            print supported devices\n"
-#if PRINT_WIKI_SUPPORT == 1
-	     "   -z | --list-supported-wiki:       print supported devices in wiki syntax\n"
-#endif
-	     "   -p | --programmer <name>:         specify the programmer device");
-
-	for (p = 0; p < PROGRAMMER_INVALID; p++) {
-		pname = programmer_table[p].name;
-		pnamelen = strlen(pname);
-		if (remaining - pnamelen - 2 < 0) {
-			printf("\n                                     ");
-			remaining = 43;
-		} else {
-			printf(" ");
-			remaining--;
-		}
-		if (p == 0) {
-			printf("(");
-			remaining--;
-		}
-		printf("%s", pname);
-		remaining -= pnamelen;
-		if (p < PROGRAMMER_INVALID - 1) {
-			printf(",");
-			remaining--;
-		} else {
-			printf(")\n");
-		}
-	}
-		
-	printf(
-	     "   -h | --help:                      print this help text\n"
-	     "   -R | --version:                   print the version (release)\n"
-	     "\nYou can specify one of -E, -r, -w, -v or no operation. If no operation is\n"
-	     "specified, then all that happens is that flash info is dumped.\n\n");
-	exit(1);
-}
-
-void print_version(void)
-{
-	printf("flashrom v%s\n", flashrom_version);
-}
-
-int main(int argc, char *argv[])
-{
-	uint8_t *buf;
-	unsigned long size, numbytes;
-	FILE *image;
-	/* Probe for up to three flash chips. */
-	struct flashchip *flash, *flashes[3];
-	const char *name;
-	int namelen;
-	int opt;
-	int option_index = 0;
-	int force = 0;
-	int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0;
-	int dont_verify_it = 0, list_supported = 0;
-#if PRINT_WIKI_SUPPORT == 1
-	int list_supported_wiki = 0;
-#endif
-	int operation_specified = 0;
-	int ret = 0, i;
-
-#if PRINT_WIKI_SUPPORT == 1
-	const char *optstring = "rRwvnVEfc:m:l:i:p:Lzh";
-#else
-	const char *optstring = "rRwvnVEfc:m:l:i:p:Lh";
-#endif
-	static struct option long_options[] = {
-		{"read", 0, 0, 'r'},
-		{"write", 0, 0, 'w'},
-		{"erase", 0, 0, 'E'},
-		{"verify", 0, 0, 'v'},
-		{"noverify", 0, 0, 'n'},
-		{"chip", 1, 0, 'c'},
-		{"mainboard", 1, 0, 'm'},
-		{"verbose", 0, 0, 'V'},
-		{"force", 0, 0, 'f'},
-		{"layout", 1, 0, 'l'},
-		{"image", 1, 0, 'i'},
-		{"list-supported", 0, 0, 'L'},
-#if PRINT_WIKI_SUPPORT == 1
-		{"list-supported-wiki", 0, 0, 'z'},
-#endif
-		{"programmer", 1, 0, 'p'},
-		{"help", 0, 0, 'h'},
-		{"version", 0, 0, 'R'},
-		{0, 0, 0, 0}
-	};
-
-	char *filename = NULL;
-
-	char *tempstr = NULL, *tempstr2 = NULL;
-
-	print_version();
-
-	if (argc > 1) {
-		/* Yes, print them. */
-		int i;
-		printf_debug("The arguments are:\n");
-		for (i = 1; i < argc; ++i)
-			printf_debug("%s\n", argv[i]);
-	}
-
-	/* Safety check. */
-	if (ARRAY_SIZE(programmer_table) - 1 != PROGRAMMER_INVALID) {
-		fprintf(stderr, "Programmer table miscompilation!\n");
-		exit(1);
-	}
-	if (spi_programmer_count - 1 != SPI_CONTROLLER_INVALID) {
-		fprintf(stderr, "SPI programmer table miscompilation!\n");
-		exit(1);
-	}
-#if BITBANG_SPI_SUPPORT == 1
-	if (bitbang_spi_master_count - 1 != BITBANG_SPI_INVALID) {
-		fprintf(stderr, "Bitbanging SPI master table miscompilation!\n");
-		exit(1);
-	}
-#endif
-
-	setbuf(stdout, NULL);
-	while ((opt = getopt_long(argc, argv, optstring,
-				  long_options, &option_index)) != EOF) {
-		switch (opt) {
-		case 'r':
-			if (++operation_specified > 1) {
-				fprintf(stderr, "More than one operation "
-					"specified. Aborting.\n");
-				exit(1);
-			}
-			read_it = 1;
-			break;
-		case 'w':
-			if (++operation_specified > 1) {
-				fprintf(stderr, "More than one operation "
-					"specified. Aborting.\n");
-				exit(1);
-			}
-			write_it = 1;
-			break;
-		case 'v':
-			//FIXME: gracefully handle superfluous -v
-			if (++operation_specified > 1) {
-				fprintf(stderr, "More than one operation "
-					"specified. Aborting.\n");
-				exit(1);
-			}
-			if (dont_verify_it) {
-				fprintf(stderr, "--verify and --noverify are"
-					"mutually exclusive. Aborting.\n");
-				exit(1);
-			}
-			verify_it = 1;
-			break;
-		case 'n':
-			if (verify_it) {
-				fprintf(stderr, "--verify and --noverify are"
-					"mutually exclusive. Aborting.\n");
-				exit(1);
-			}
-			dont_verify_it = 1;
-			break;
-		case 'c':
-			chip_to_probe = strdup(optarg);
-			break;
-		case 'V':
-			verbose = 1;
-			break;
-		case 'E':
-			if (++operation_specified > 1) {
-				fprintf(stderr, "More than one operation "
-					"specified. Aborting.\n");
-				exit(1);
-			}
-			erase_it = 1;
-			break;
-		case 'm':
-			tempstr = strdup(optarg);
-			strtok(tempstr, ":");
-			tempstr2 = strtok(NULL, ":");
-			if (tempstr2) {
-				lb_vendor = tempstr;
-				lb_part = tempstr2;
-			} else {
-				lb_vendor = NULL;
-				lb_part = tempstr;
-			}
-			break;
-		case 'f':
-			force = 1;
-			break;
-		case 'l':
-			tempstr = strdup(optarg);
-			if (read_romlayout(tempstr))
-				exit(1);
-			break;
-		case 'i':
-			tempstr = strdup(optarg);
-			find_romentry(tempstr);
-			break;
-		case 'L':
-			list_supported = 1;
-			break;
-#if PRINT_WIKI_SUPPORT == 1
-		case 'z':
-			list_supported_wiki = 1;
-			break;
-#endif
-		case 'p':
-			for (programmer = 0; programmer < PROGRAMMER_INVALID; programmer++) {
-				name = programmer_table[programmer].name;
-				namelen = strlen(name);
-				if (strncmp(optarg, name, namelen) == 0) {
-					switch (optarg[namelen]) {
-					case ':':
-						programmer_param = strdup(optarg + namelen + 1);
-						break;
-					case '\0':
-						break;
-					default:
-						/* The continue refers to the
-						 * for loop. It is here to be
-						 * able to differentiate between
-						 * foo and foobar.
-						 */
-						continue;
-					}
-					break;
-				}
-			}
-			if (programmer == PROGRAMMER_INVALID) {
-				printf("Error: Unknown programmer %s.\n", optarg);
-				exit(1);
-			}
-			break;
-		case 'R':
-			/* print_version() is always called during startup. */
-			exit(0);
-			break;
-		case 'h':
-		default:
-			usage(argv[0]);
-			break;
-		}
-	}
-
-	if (list_supported) {
-		print_supported();
-		exit(0);
-	}
-
-#if PRINT_WIKI_SUPPORT == 1
-	if (list_supported_wiki) {
-		print_supported_wiki();
-		exit(0);
-	}
-#endif
-
-	if (read_it && write_it) {
-		printf("Error: -r and -w are mutually exclusive.\n");
-		usage(argv[0]);
-	}
-
-	if (optind < argc)
-		filename = argv[optind++];
-	
-	if (optind < argc) {
-		printf("Error: Extra parameter found.\n");
-		usage(argv[0]);
-	}
-
-	if (programmer_init()) {
-		fprintf(stderr, "Error: Programmer initialization failed.\n");
-		exit(1);
-	}
-
-	myusec_calibrate_delay();
-
-	for (i = 0; i < ARRAY_SIZE(flashes); i++) {
-		flashes[i] =
-		    probe_flash(i ? flashes[i - 1] + 1 : flashchips, 0);
-		if (!flashes[i])
-			for (i++; i < ARRAY_SIZE(flashes); i++)
-				flashes[i] = NULL;
-	}
-
-	if (flashes[1]) {
-		printf("Multiple flash chips were detected:");
-		for (i = 0; i < ARRAY_SIZE(flashes) && flashes[i]; i++)
-			printf(" %s", flashes[i]->name);
-		printf("\nPlease specify which chip to use with the -c <chipname> option.\n");
-		programmer_shutdown();
-		exit(1);
-	} else if (!flashes[0]) {
-		printf("No EEPROM/flash device found.\n");
-		if (!force || !chip_to_probe) {
-			printf("If you know which flash chip you have, and if this version of flashrom\n");
-			printf("supports a similar flash chip, you can try to force read your chip. Run:\n");
-			printf("flashrom -f -r -c similar_supported_flash_chip filename\n");
-			printf("\n");
-			printf("Note: flashrom can never write when the flash chip isn't found automatically.\n");
-		}
-		if (force && read_it && chip_to_probe) {
-			printf("Force read (-f -r -c) requested, forcing chip probe success:\n");
-			flashes[0] = probe_flash(flashchips, 1);
-			if (!flashes[0]) {
-				printf("flashrom does not support a flash chip named '%s'.\n", chip_to_probe);
-				printf("Run flashrom -L to view the hardware supported in this flashrom version.\n");
-				exit(1);
-			}
-			printf("Please note that forced reads most likely contain garbage.\n");
-			return read_flash(flashes[0], filename);
-		}
-		// FIXME: flash writes stay enabled!
-		programmer_shutdown();
-		exit(1);
-	}
-
-	flash = flashes[0];
-
-	if (TEST_OK_MASK != (flash->tested & TEST_OK_MASK)) {
-		printf("===\n");
-		if (flash->tested & TEST_BAD_MASK) {
-			printf("This flash part has status NOT WORKING for operations:");
-			if (flash->tested & TEST_BAD_PROBE)
-				printf(" PROBE");
-			if (flash->tested & TEST_BAD_READ)
-				printf(" READ");
-			if (flash->tested & TEST_BAD_ERASE)
-				printf(" ERASE");
-			if (flash->tested & TEST_BAD_WRITE)
-				printf(" WRITE");
-			printf("\n");
-		}
-		if ((!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE)) ||
-		    (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ)) ||
-		    (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE)) ||
-		    (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))) {
-			printf("This flash part has status UNTESTED for operations:");
-			if (!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE))
-				printf(" PROBE");
-			if (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ))
-				printf(" READ");
-			if (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE))
-				printf(" ERASE");
-			if (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))
-				printf(" WRITE");
-			printf("\n");
-		}
-		printf("Please email a report to flashrom@flashrom.org if any "
-		       "of the above operations\nwork correctly for you with "
-		       "this flash part. Please include the flashrom\noutput "
-		       "with the additional -V option for all operations you "
-		       "tested (-V, -rV,\n-wV, -EV), and mention which "
-		       "mainboard you tested. Thanks for your help!\n===\n");
-	}
-
-	size = flash->total_size * 1024;
-	if (check_max_decode((buses_supported & flash->bustype), size) &&
-	    (!force)) {
-		fprintf(stderr, "Chip is too big for this programmer "
-			"(-V gives details). Use --force to override.\n");
-		programmer_shutdown();
-		return 1;
-	}
-
-	if (!(read_it | write_it | verify_it | erase_it)) {
-		printf("No operations were specified.\n");
-		// FIXME: flash writes stay enabled!
-		programmer_shutdown();
-		exit(1);
-	}
-
-	if (!filename && !erase_it) {
-		printf("Error: No filename specified.\n");
-		// FIXME: flash writes stay enabled!
-		programmer_shutdown();
-		exit(1);
-	}
-
-	/* Always verify write operations unless -n is used. */
-	if (write_it && !dont_verify_it)
-		verify_it = 1;
-
-	buf = (uint8_t *) calloc(size, sizeof(char));
-
-	if (erase_it) {
-		if (flash->tested & TEST_BAD_ERASE) {
-			fprintf(stderr, "Erase is not working on this chip. ");
-			if (!force) {
-				fprintf(stderr, "Aborting.\n");
-				programmer_shutdown();
-				return 1;
-			} else {
-				fprintf(stderr, "Continuing anyway.\n");
-			}
-		}
-		if (erase_flash(flash)) {
-			emergency_help_message();
-			programmer_shutdown();
-			return 1;
-		}
-	} else if (read_it) {
-		if (read_flash(flash, filename)) {
-			programmer_shutdown();
-			return 1;
-		}
-	} else {
-		struct stat image_stat;
-
-		if (flash->tested & TEST_BAD_ERASE) {
-			fprintf(stderr, "Erase is not working on this chip "
-				"and erase is needed for write. ");
-			if (!force) {
-				fprintf(stderr, "Aborting.\n");
-				programmer_shutdown();
-				return 1;
-			} else {
-				fprintf(stderr, "Continuing anyway.\n");
-			}
-		}
-		if (flash->tested & TEST_BAD_WRITE) {
-			fprintf(stderr, "Write is not working on this chip. ");
-			if (!force) {
-				fprintf(stderr, "Aborting.\n");
-				programmer_shutdown();
-				return 1;
-			} else {
-				fprintf(stderr, "Continuing anyway.\n");
-			}
-		}
-		if ((image = fopen(filename, "r")) == NULL) {
-			perror(filename);
-			programmer_shutdown();
-			exit(1);
-		}
-		if (fstat(fileno(image), &image_stat) != 0) {
-			perror(filename);
-			programmer_shutdown();
-			exit(1);
-		}
-		if (image_stat.st_size != flash->total_size * 1024) {
-			fprintf(stderr, "Error: Image size doesn't match\n");
-			programmer_shutdown();
-			exit(1);
-		}
-
-		numbytes = fread(buf, 1, size, image);
-		show_id(buf, size, force);
-		fclose(image);
-		if (numbytes != size) {
-			fprintf(stderr, "Error: Failed to read file. Got %ld bytes, wanted %ld!\n", numbytes, size);
-			programmer_shutdown();
-			return 1;
-		}
-	}
-
-	// This should be moved into each flash part's code to do it 
-	// cleanly. This does the job.
-	handle_romentries(buf, flash);
-
-	// ////////////////////////////////////////////////////////////
-
-	if (write_it) {
-		printf("Writing flash chip... ");
-		if (!flash->write) {
-			fprintf(stderr, "Error: flashrom has no write function for this flash chip.\n");
-			programmer_shutdown();
-			return 1;
-		}
-		ret = flash->write(flash, buf);
-		if (ret) {
-			fprintf(stderr, "FAILED!\n");
-			emergency_help_message();
-			programmer_shutdown();
-			return 1;
-		} else {
-			printf("COMPLETE.\n");
-		}
-	}
-
-	if (verify_it) {
-		/* Work around chips which need some time to calm down. */
-		if (write_it)
-			programmer_delay(1000*1000);
-		ret = verify_flash(flash, buf);
-		/* If we tried to write, and verification now fails, we
-		 * might have an emergency situation.
-		 */
-		if (ret && write_it)
-			emergency_help_message();
-	}
-
-	programmer_shutdown();
-
-	return ret;
-}
diff --git a/ft2232_spi.c b/ft2232_spi.c
deleted file mode 100644
index d565a6f..0000000
--- a/ft2232_spi.c
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Paul Fox <pgf@laptop.org>
- * Copyright (C) 2009 Carl-Daniel Hailfinger
- *
- * 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; version 2 of the License.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#if FT2232_SPI_SUPPORT == 1
-
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include "flash.h"
-#include "spi.h"
-#include <ftdi.h>
-
-/*
- * The 'H' chips can run internally at either 12MHz or 60MHz.
- * The non-H chips can only run at 12MHz.
- */
-#define CLOCK_5X 1
-
-/*
- * In either case, the divisor is a simple integer clock divider.
- * If CLOCK_5X is set, this divisor divides 30MHz, else it divides 6MHz.
- */
-#define DIVIDE_BY 3  /* e.g. '3' will give either 10MHz or 2MHz SPI clock. */
-
-#define BITMODE_BITBANG_NORMAL	1
-#define BITMODE_BITBANG_SPI	2
-
-static struct ftdi_context ftdic_context;
-
-int send_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size)
-{
-	int r;
-	r = ftdi_write_data(ftdic, (unsigned char *) buf, size);
-	if (r < 0) {
-		fprintf(stderr, "ftdi_write_data: %d, %s\n", r,
-				ftdi_get_error_string(ftdic));
-		return 1;
-	}
-	return 0;
-}
-
-int get_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size)
-{
-	int r;
-	r = ftdi_read_data(ftdic, (unsigned char *) buf, size);
-	if (r < 0) {
-		fprintf(stderr, "ftdi_read_data: %d, %s\n", r,
-				ftdi_get_error_string(ftdic));
-		return 1;
-	}
-	return 0;
-}
-
-int ft2232_spi_init(void)
-{
-	int f;
-	struct ftdi_context *ftdic = &ftdic_context;
-	unsigned char buf[512];
-	char *portpos = NULL;
-	int ft2232_type = FTDI_FT4232H;
-	enum ftdi_interface ft2232_interface = INTERFACE_B;
-
-	if (ftdi_init(ftdic) < 0) {
-		fprintf(stderr, "ftdi_init failed\n");
-		return EXIT_FAILURE; // TODO
-	}
-
-	if (programmer_param && !strlen(programmer_param)) {
-		free(programmer_param);
-		programmer_param = NULL;
-	}
-	if (programmer_param) {
-		if (strstr(programmer_param, "2232"))
-			ft2232_type = FTDI_FT2232H;
-		if (strstr(programmer_param, "4232"))
-			ft2232_type = FTDI_FT4232H;
-		portpos = strstr(programmer_param, "port=");
-		if (portpos) {
-			portpos += 5;
-			switch (toupper(*portpos)) {
-			case 'A':
-				ft2232_interface = INTERFACE_A;
-				break;
-			case 'B':
-				ft2232_interface = INTERFACE_B;
-				break;
-			default:
-				fprintf(stderr, "Invalid interface specified, "
-					"using default.\n");
-			}
-		}
-		free(programmer_param);
-	}
-	printf_debug("Using device type %s ",
-		     (ft2232_type == FTDI_FT2232H) ? "2232H" : "4232H");
-	printf_debug("interface %s\n",
-		     (ft2232_interface == INTERFACE_A) ? "A" : "B");
-
-	f = ftdi_usb_open(ftdic, 0x0403, ft2232_type);
-
-	if (f < 0 && f != -5) {
-		fprintf(stderr, "Unable to open FTDI device: %d (%s)\n", f,
-				ftdi_get_error_string(ftdic));
-		exit(-1); // TODO
-	}
-
-	if (ftdi_set_interface(ftdic, ft2232_interface) < 0) {
-		fprintf(stderr, "Unable to select interface: %s\n",
-				ftdic->error_str);
-	}
-
-	if (ftdi_usb_reset(ftdic) < 0) {
-		fprintf(stderr, "Unable to reset FTDI device\n");
-	}
-
-	if (ftdi_set_latency_timer(ftdic, 2) < 0) {
-		fprintf(stderr, "Unable to set latency timer\n");
-	}
-
-	if (ftdi_write_data_set_chunksize(ftdic, 512)) {
-		fprintf(stderr, "Unable to set chunk size\n");
-	}
-
-	if (ftdi_set_bitmode(ftdic, 0x00, BITMODE_BITBANG_SPI) < 0) {
-		fprintf(stderr, "Unable to set bitmode to SPI\n");
-	}
-
-#if CLOCK_5X
-	printf_debug("Disable divide-by-5 front stage\n");
-	buf[0] = 0x8a;		/* Disable divide-by-5. */
-	if (send_buf(ftdic, buf, 1))
-		return -1;
-#define MPSSE_CLK 60.0
-
-#else
-
-#define MPSSE_CLK 12.0
-
-#endif
-	printf_debug("Set clock divisor\n");
-	buf[0] = 0x86;		/* command "set divisor" */
-	/* valueL/valueH are (desired_divisor - 1) */
-	buf[1] = (DIVIDE_BY - 1) & 0xff;
-	buf[2] = ((DIVIDE_BY - 1) >> 8) & 0xff;
-	if (send_buf(ftdic, buf, 3))
-		return -1;
-
-	printf("SPI clock is %fMHz\n",
-	       (double)(MPSSE_CLK / (((DIVIDE_BY - 1) + 1) * 2)));
-
-	/* Disconnect TDI/DO to TDO/DI for loopback. */
-	printf_debug("No loopback of TDI/DO TDO/DI\n");
-	buf[0] = 0x85;
-	if (send_buf(ftdic, buf, 1))
-		return -1;
-
-	printf_debug("Set data bits\n");
-	/* Set data bits low-byte command:
-	 *  value: 0x08  CS=high, DI=low, DO=low, SK=low
-	 *    dir: 0x0b  CS=output, DI=input, DO=output, SK=output
-	 */
-#define CS_BIT 0x08
-	buf[0] = SET_BITS_LOW;
-	buf[1] = CS_BIT;
-	buf[2] = 0x0b;
-	if (send_buf(ftdic, buf, 3))
-		return -1;
-
-	// printf_debug("\nft2232 chosen\n");
-
-	buses_supported = CHIP_BUSTYPE_SPI;
-	spi_controller = SPI_CONTROLLER_FT2232;
-
-	return 0;
-}
-
-int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-		const unsigned char *writearr, unsigned char *readarr)
-{
-	struct ftdi_context *ftdic = &ftdic_context;
-	static unsigned char *buf = NULL;
-	/* failed is special. We use bitwise ops, but it is essentially bool. */
-	int i = 0, ret = 0, failed = 0;
-	int bufsize;
-	static int oldbufsize = 0;
-
-	if (writecnt > 65536 || readcnt > 65536)
-		return SPI_INVALID_LENGTH;
-
-	/* buf is not used for the response from the chip. */
-	bufsize = max(writecnt + 9, 260 + 9);
-	/* Never shrink. realloc() calls are expensive. */
-	if (bufsize > oldbufsize) {
-		buf = realloc(buf, bufsize);
-		if (!buf) {
-			fprintf(stderr, "Out of memory!\n");
-			exit(1);
-		}
-		oldbufsize = bufsize;
-	}
-
-	/*
-	 * Minimize USB transfers by packing as many commands as possible
-	 * together. If we're not expecting to read, we can assert CS#, write,
-	 * and deassert CS# all in one shot. If reading, we do three separate
-	 * operations.
-	 */
-	printf_debug("Assert CS#\n");
-	buf[i++] = SET_BITS_LOW;
-	buf[i++] = 0 & ~CS_BIT; /* assertive */
-	buf[i++] = 0x0b;
-
-	if (writecnt) {
-		buf[i++] = 0x11;
-		buf[i++] = (writecnt - 1) & 0xff;
-		buf[i++] = ((writecnt - 1) >> 8) & 0xff;
-		memcpy(buf + i, writearr, writecnt);
-		i += writecnt;
-	}
-
-	/*
-	 * Optionally terminate this batch of commands with a
-	 * read command, then do the fetch of the results.
-	 */
-	if (readcnt) {
-		buf[i++] = 0x20;
-		buf[i++] = (readcnt - 1) & 0xff;
-		buf[i++] = ((readcnt - 1) >> 8) & 0xff;
-		ret = send_buf(ftdic, buf, i);
-		failed = ret;
-		/* We can't abort here, we still have to deassert CS#. */
-		if (ret)
-			fprintf(stderr, "send_buf failed before read: %i\n",
-				ret);
-		i = 0;
-		if (ret == 0) {
-			/*
-			 * FIXME: This is unreliable. There's no guarantee that
-			 * we read the response directly after sending the read
-			 * command. We may be scheduled out etc.
-			 */
-			ret = get_buf(ftdic, readarr, readcnt);
-			failed |= ret;
-			/* We can't abort here either. */
-			if (ret)
-				fprintf(stderr, "get_buf failed: %i\n", ret);
-		}
-	}
-
-	printf_debug("De-assert CS#\n");
-	buf[i++] = SET_BITS_LOW;
-	buf[i++] = CS_BIT;
-	buf[i++] = 0x0b;
-	ret = send_buf(ftdic, buf, i);
-	failed |= ret;
-	if (ret)
-		fprintf(stderr, "send_buf failed at end: %i\n", ret);
-
-	return failed ? -1 : 0;
-}
-
-int ft2232_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
-{
-	/* Maximum read length is 64k bytes. */
-	return spi_read_chunked(flash, buf, start, len, 64 * 1024);
-}
-
-int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf)
-{
-	int total_size = 1024 * flash->total_size;
-	int i;
-
-	spi_disable_blockprotect();
-	/* Erase first. */
-	printf("Erasing flash before programming... ");
-	if (erase_flash(flash)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	printf("done.\n");
-	printf_debug("total_size is %d\n", total_size);
-	for (i = 0; i < total_size; i += 256) {
-		int l, r;
-		if (i + 256 <= total_size)
-			l = 256;
-		else
-			l = total_size - i;
-
-		if ((r = spi_nbyte_program(i, &buf[i], l))) {
-			fprintf(stderr, "%s: write fail %d\n", __func__, r);
-			return 1;
-		}
-
-		while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
-			/* loop */;
-	}
-
-	return 0;
-}
-
-#endif
diff --git a/gfxnvidia.c b/gfxnvidia.c
deleted file mode 100644
index 1e9b679..0000000
--- a/gfxnvidia.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include "flash.h"
-
-#define PCI_VENDOR_ID_NVIDIA	0x10de
-
-uint8_t *nvidia_bar;
-
-struct pcidev_status gfx_nvidia[] = {
-	{0x10de, 0x0010, PCI_NT, "NVIDIA", "Mutara V08 [NV2]" },
-	{0x10de, 0x0018, PCI_NT, "NVIDIA", "RIVA 128" },
-	{0x10de, 0x0020, PCI_NT, "NVIDIA", "RIVA TNT" },
-	{0x10de, 0x0028, PCI_NT, "NVIDIA", "RIVA TNT2/TNT2 Pro" },
-	{0x10de, 0x0029, PCI_NT, "NVIDIA", "RIVA TNT2 Ultra" },
-	{0x10de, 0x002c, PCI_NT, "NVIDIA", "Vanta/Vanta LT" },
-	{0x10de, 0x002d, PCI_OK, "NVIDIA", "RIVA TNT2 Model 64/Model 64 Pro" },
-	{0x10de, 0x00a0, PCI_NT, "NVIDIA", "Aladdin TNT2" },
-	{0x10de, 0x0100, PCI_NT, "NVIDIA", "GeForce 256" },
-	{0x10de, 0x0101, PCI_NT, "NVIDIA", "GeForce DDR" },
-	{0x10de, 0x0103, PCI_NT, "NVIDIA", "Quadro" },
-	{0x10de, 0x0110, PCI_NT, "NVIDIA", "GeForce2 MX" },
-	{0x10de, 0x0111, PCI_NT, "NVIDIA", "GeForce2 MX" },
-	{0x10de, 0x0112, PCI_NT, "NVIDIA", "GeForce2 GO" },
-	{0x10de, 0x0113, PCI_NT, "NVIDIA", "Quadro2 MXR" },
-	{0x10de, 0x0150, PCI_NT, "NVIDIA", "GeForce2 GTS/Pro" },
-	{0x10de, 0x0151, PCI_NT, "NVIDIA", "GeForce2 GTS" },
-	{0x10de, 0x0152, PCI_NT, "NVIDIA", "GeForce2 Ultra" },
-	{0x10de, 0x0153, PCI_NT, "NVIDIA", "Quadro2 Pro" },
-	{0x10de, 0x0200, PCI_NT, "NVIDIA", "GeForce 3 nFX" },
-	{0x10de, 0x0201, PCI_NT, "NVIDIA", "GeForce 3 nFX" },
-	{0x10de, 0x0202, PCI_NT, "NVIDIA", "GeForce 3 nFX Ultra" },
-	{0x10de, 0x0203, PCI_NT, "NVIDIA", "Quadro 3 DDC" },
-
-	{},
-};
-
-int gfxnvidia_init(void)
-{
-	uint32_t reg32;
-
-	get_io_perms();
-
-	io_base_addr = pcidev_init(PCI_VENDOR_ID_NVIDIA, PCI_BASE_ADDRESS_0,
-				   gfx_nvidia, programmer_param);
-	io_base_addr += 0x300000;
-	printf("Detected NVIDIA I/O base address: 0x%x.\n", io_base_addr);
-
-	/* Allow access to flash interface (will disable screen). */
-	reg32 = pci_read_long(pcidev_dev, 0x50);
-	reg32 &= ~(1 << 0);
-	pci_write_long(pcidev_dev, 0x50, reg32);
-
-	nvidia_bar = physmap("NVIDIA", io_base_addr, 16 * 1024 * 1024);
-
-	buses_supported = CHIP_BUSTYPE_PARALLEL;
-
-	return 0;
-}
-
-int gfxnvidia_shutdown(void)
-{
-	uint32_t reg32;
-
-	/* Disallow access to flash interface (and re-enable screen). */
-	reg32 = pci_read_long(pcidev_dev, 0x50);
-	reg32 |= (1 << 0);
-	pci_write_long(pcidev_dev, 0x50, reg32);
-
-	free(programmer_param);
-	pci_cleanup(pacc);
-	release_io_perms();
-	return 0;
-}
-
-void gfxnvidia_chip_writeb(uint8_t val, chipaddr addr)
-{
-	mmio_writeb(val, nvidia_bar + addr);
-}
-
-uint8_t gfxnvidia_chip_readb(const chipaddr addr)
-{
-	return mmio_readb(nvidia_bar + addr);
-}
diff --git a/ichspi.c b/ichspi.c
deleted file mode 100644
index cd02b96..0000000
--- a/ichspi.c
+++ /dev/null
@@ -1,763 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2008 Stefan Wildemann <stefan.wildemann@kontron.com>
- * Copyright (C) 2008 Claus Gindhart <claus.gindhart@kontron.com>
- * Copyright (C) 2008 Dominik Geyer <dominik.geyer@kontron.com>
- * Copyright (C) 2008 coresystems GmbH <info@coresystems.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/*
- * This module is designed for supporting the devices
- * ST M25P40
- * ST M25P80
- * ST M25P16
- * ST M25P32 already tested
- * ST M25P64
- * AT 25DF321 already tested
- *
- */
-
-#include <string.h>
-#include "flash.h"
-#include "spi.h"
-
-/* ICH9 controller register definition */
-#define ICH9_REG_FADDR         0x08	/* 32 Bits */
-#define ICH9_REG_FDATA0                0x10	/* 64 Bytes */
-
-#define ICH9_REG_SSFS          0x90	/* 08 Bits */
-#define SSFS_SCIP		0x00000001
-#define SSFS_CDS		0x00000004
-#define SSFS_FCERR		0x00000008
-#define SSFS_AEL		0x00000010
-
-#define ICH9_REG_SSFC          0x91	/* 24 Bits */
-#define SSFC_SCGO		0x00000200
-#define SSFC_ACS		0x00000400
-#define SSFC_SPOP		0x00000800
-#define SSFC_COP		0x00001000
-#define SSFC_DBC		0x00010000
-#define SSFC_DS			0x00400000
-#define SSFC_SME		0x00800000
-#define SSFC_SCF		0x01000000
-#define SSFC_SCF_20MHZ 0x00000000
-#define SSFC_SCF_33MHZ 0x01000000
-
-#define ICH9_REG_PREOP         0x94	/* 16 Bits */
-#define ICH9_REG_OPTYPE                0x96	/* 16 Bits */
-#define ICH9_REG_OPMENU                0x98	/* 64 Bits */
-
-// ICH9R SPI commands
-#define SPI_OPCODE_TYPE_READ_NO_ADDRESS     0
-#define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS    1
-#define SPI_OPCODE_TYPE_READ_WITH_ADDRESS   2
-#define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS  3
-
-// ICH7 registers
-#define ICH7_REG_SPIS          0x00	/* 16 Bits */
-#define SPIS_SCIP              0x00000001
-#define SPIS_CDS               0x00000004
-#define SPIS_FCERR             0x00000008
-
-/* VIA SPI is compatible with ICH7, but maxdata
-   to transfer is 16 bytes.
-
-   DATA byte count on ICH7 is 8:13, on VIA 8:11
-
-   bit 12 is port select CS0 CS1
-   bit 13 is FAST READ enable
-   bit 7  is used with fast read and one shot controls CS de-assert?
-*/
-
-#define ICH7_REG_SPIC          0x02	/* 16 Bits */
-#define SPIC_SCGO              0x0002
-#define SPIC_ACS               0x0004
-#define SPIC_SPOP              0x0008
-#define SPIC_DS                0x4000
-
-#define ICH7_REG_SPIA          0x04	/* 32 Bits */
-#define ICH7_REG_SPID0         0x08	/* 64 Bytes */
-#define ICH7_REG_PREOP         0x54	/* 16 Bits */
-#define ICH7_REG_OPTYPE                0x56	/* 16 Bits */
-#define ICH7_REG_OPMENU                0x58	/* 64 Bits */
-
-/* ICH SPI configuration lock-down. May be set during chipset enabling. */
-int ichspi_lock = 0;
-
-typedef struct _OPCODE {
-	uint8_t opcode;		//This commands spi opcode
-	uint8_t spi_type;	//This commands spi type
-	uint8_t atomic;		//Use preop: (0: none, 1: preop0, 2: preop1
-} OPCODE;
-
-/* Opcode definition:
- * Preop 1: Write Enable
- * Preop 2: Write Status register enable
- *
- * OP 0: Write address
- * OP 1: Read Address
- * OP 2: ERASE block
- * OP 3: Read Status register
- * OP 4: Read ID
- * OP 5: Write Status register
- * OP 6: chip private (read JDEC id)
- * OP 7: Chip erase
- */
-typedef struct _OPCODES {
-	uint8_t preop[2];
-	OPCODE opcode[8];
-} OPCODES;
-
-static OPCODES *curopcodes = NULL;
-
-/* HW access functions */
-static uint32_t REGREAD32(int X)
-{
-	return mmio_readl(spibar + X);
-}
-
-static uint16_t REGREAD16(int X)
-{
-	return mmio_readw(spibar + X);
-}
-
-#define REGWRITE32(X,Y) mmio_writel(Y, spibar+X)
-#define REGWRITE16(X,Y) mmio_writew(Y, spibar+X)
-#define REGWRITE8(X,Y)  mmio_writeb(Y, spibar+X)
-
-/* Common SPI functions */
-static int find_opcode(OPCODES *op, uint8_t opcode);
-static int find_preop(OPCODES *op, uint8_t preop);
-static int generate_opcodes(OPCODES * op);
-static int program_opcodes(OPCODES * op);
-static int run_opcode(OPCODE op, uint32_t offset,
-		      uint8_t datalength, uint8_t * data);
-static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes,
-			      int offset, int maxdata);
-
-/* for pairing opcodes with their required preop */
-struct preop_opcode_pair {
-	uint8_t preop;
-	uint8_t opcode;
-};
-
-struct preop_opcode_pair pops[] = {
-	{JEDEC_WREN, JEDEC_BYTE_PROGRAM},
-	{JEDEC_WREN, JEDEC_SE}, /* sector erase */
-	{JEDEC_WREN, JEDEC_BE_52}, /* block erase */
-	{JEDEC_WREN, JEDEC_BE_D8}, /* block erase */
-	{JEDEC_WREN, JEDEC_CE_60}, /* chip erase */
-	{JEDEC_WREN, JEDEC_CE_C7}, /* chip erase */
-	{JEDEC_EWSR, JEDEC_WRSR},
-	{0,}
-};
-
-OPCODES O_ST_M25P = {
-	{
-	 JEDEC_WREN,
-	 0},
-	{
-	 {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1},	// Write Byte
-	 {JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0},	// Read Data
-	 {JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1},	// Erase Sector
-	 {JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0},	// Read Device Status Reg
-	 {JEDEC_REMS, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0},	// Read Electronic Manufacturer Signature
-	 {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1},	// Write Status Register
-	 {JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0},	// Read JDEC ID
-	 {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1},	// Bulk erase
-	 }
-};
-
-OPCODES O_EXISTING = {};
-
-static int find_opcode(OPCODES *op, uint8_t opcode)
-{
-	int a;
-
-	for (a = 0; a < 8; a++) {
-		if (op->opcode[a].opcode == opcode)
-			return a;
-	}
-
-	return -1;
-}
-
-static int find_preop(OPCODES *op, uint8_t preop)
-{
-	int a;
-
-	for (a = 0; a < 2; a++) {
-		if (op->preop[a] == preop)
-			return a;
-	}
-
-	return -1;
-}
-
-static int generate_opcodes(OPCODES * op)
-{
-	int a, b, i;
-	uint16_t preop, optype;
-	uint32_t opmenu[2];
-
-	if (op == NULL) {
-		printf_debug("\n%s: null OPCODES pointer!\n", __func__);
-		return -1;
-	}
-
-	switch (spi_controller) {
-	case SPI_CONTROLLER_ICH7:
-	case SPI_CONTROLLER_VIA:
-		preop = REGREAD16(ICH7_REG_PREOP);
-		optype = REGREAD16(ICH7_REG_OPTYPE);
-		opmenu[0] = REGREAD32(ICH7_REG_OPMENU);
-		opmenu[1] = REGREAD32(ICH7_REG_OPMENU + 4);
-		break;
-	case SPI_CONTROLLER_ICH9:
-		preop = REGREAD16(ICH9_REG_PREOP);
-		optype = REGREAD16(ICH9_REG_OPTYPE);
-		opmenu[0] = REGREAD32(ICH9_REG_OPMENU);
-		opmenu[1] = REGREAD32(ICH9_REG_OPMENU + 4);
-		break;
-	default:
-		printf_debug("%s: unsupported chipset\n", __func__);
-		return -1;
-	}
-
-	op->preop[0] = (uint8_t) preop;
-	op->preop[1] = (uint8_t) (preop >> 8);
-
-	for (a = 0; a < 8; a++) {
-		op->opcode[a].spi_type = (uint8_t) (optype & 0x3);
-		optype >>= 2;
-	}
-
-	for (a = 0; a < 4; a++) {
-		op->opcode[a].opcode = (uint8_t) (opmenu[0] & 0xff);
-		opmenu[0] >>= 8;
-	}
-
-	for (a = 4; a < 8; a++) {
-		op->opcode[a].opcode = (uint8_t) (opmenu[1] & 0xff);
-		opmenu[1] >>= 8;
-	}
-
-	/* atomic (link opcode with required pre-op) */
-	for (a = 4; a < 8; a++)
-		op->opcode[a].atomic = 0;
-
-	for (i = 0; pops[i].opcode; i++) {
-		a = find_opcode(op, pops[i].opcode);
-		b = find_preop(op, pops[i].preop);
-		if ((a != -1) && (b != -1))
-			op->opcode[a].atomic = (uint8_t) ++b;
-	}
-
-	return 0;
-}
-
-int program_opcodes(OPCODES * op)
-{
-	uint8_t a;
-	uint16_t preop, optype;
-	uint32_t opmenu[2];
-
-	/* Program Prefix Opcodes */
-	/* 0:7 Prefix Opcode 1 */
-	preop = (op->preop[0]);
-	/* 8:16 Prefix Opcode 2 */
-	preop |= ((uint16_t) op->preop[1]) << 8;
-
-	/* Program Opcode Types 0 - 7 */
-	optype = 0;
-	for (a = 0; a < 8; a++) {
-		optype |= ((uint16_t) op->opcode[a].spi_type) << (a * 2);
-	}
-
-	/* Program Allowable Opcodes 0 - 3 */
-	opmenu[0] = 0;
-	for (a = 0; a < 4; a++) {
-		opmenu[0] |= ((uint32_t) op->opcode[a].opcode) << (a * 8);
-	}
-
-	/*Program Allowable Opcodes 4 - 7 */
-	opmenu[1] = 0;
-	for (a = 4; a < 8; a++) {
-		opmenu[1] |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8);
-	}
-
-	printf_debug("\n%s: preop=%04x optype=%04x opmenu=%08x%08x\n", __func__, preop, optype, opmenu[0], opmenu[1]);
-	switch (spi_controller) {
-	case SPI_CONTROLLER_ICH7:
-	case SPI_CONTROLLER_VIA:
-		REGWRITE16(ICH7_REG_PREOP, preop);
-		REGWRITE16(ICH7_REG_OPTYPE, optype);
-		REGWRITE32(ICH7_REG_OPMENU, opmenu[0]);
-		REGWRITE32(ICH7_REG_OPMENU + 4, opmenu[1]);
-		break;
-	case SPI_CONTROLLER_ICH9:
-		REGWRITE16(ICH9_REG_PREOP, preop);
-		REGWRITE16(ICH9_REG_OPTYPE, optype);
-		REGWRITE32(ICH9_REG_OPMENU, opmenu[0]);
-		REGWRITE32(ICH9_REG_OPMENU + 4, opmenu[1]);
-		break;
-	default:
-		printf_debug("%s: unsupported chipset\n", __func__);
-		return -1;
-	}
-
-	return 0;
-}
-
-/* This function generates OPCODES from or programs OPCODES to ICH according to
- * the chipset's SPI configuration lock.
- *
- * It should be called before ICH sends any spi command.
- */
-int ich_init_opcodes(void)
-{
-	int rc = 0;
-	OPCODES *curopcodes_done;
-
-	if (curopcodes)
-		return 0;
-
-	if (ichspi_lock) {
-		printf_debug("Generating OPCODES... ");
-		curopcodes_done = &O_EXISTING;
-		rc = generate_opcodes(curopcodes_done);
-	} else {
-		printf_debug("Programming OPCODES... ");
-		curopcodes_done = &O_ST_M25P;
-		rc = program_opcodes(curopcodes_done);
-	}
-
-	if (rc) {
-		curopcodes = NULL;
-		printf_debug("failed\n");
-		return 1;
-	} else {
-		curopcodes = curopcodes_done;
-		printf_debug("done\n");
-		return 0;
-	}
-}
-
-static int ich7_run_opcode(OPCODE op, uint32_t offset,
-			   uint8_t datalength, uint8_t * data, int maxdata)
-{
-	int write_cmd = 0;
-	int timeout;
-	uint32_t temp32 = 0;
-	uint16_t temp16;
-	uint32_t a;
-	uint64_t opmenu;
-	int opcode_index;
-
-	/* Is it a write command? */
-	if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
-	    || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
-		write_cmd = 1;
-	}
-
-	/* Programm Offset in Flash into FADDR */
-	REGWRITE32(ICH7_REG_SPIA, (offset & 0x00FFFFFF));	/* SPI addresses are 24 BIT only */
-
-	/* Program data into FDATA0 to N */
-	if (write_cmd && (datalength != 0)) {
-		temp32 = 0;
-		for (a = 0; a < datalength; a++) {
-			if ((a % 4) == 0) {
-				temp32 = 0;
-			}
-
-			temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
-
-			if ((a % 4) == 3) {
-				REGWRITE32(ICH7_REG_SPID0 + (a - (a % 4)),
-					   temp32);
-			}
-		}
-		if (((a - 1) % 4) != 3) {
-			REGWRITE32(ICH7_REG_SPID0 +
-				   ((a - 1) - ((a - 1) % 4)), temp32);
-		}
-
-	}
-
-	/* Assemble SPIS */
-	temp16 = 0;
-	/* clear error status registers */
-	temp16 |= (SPIS_CDS + SPIS_FCERR);
-	REGWRITE16(ICH7_REG_SPIS, temp16);
-
-	/* Assemble SPIC */
-	temp16 = 0;
-
-	if (datalength != 0) {
-		temp16 |= SPIC_DS;
-		temp16 |= ((uint32_t) ((datalength - 1) & (maxdata - 1))) << 8;
-	}
-
-	/* Select opcode */
-	opmenu = REGREAD32(ICH7_REG_OPMENU);
-	opmenu |= ((uint64_t)REGREAD32(ICH7_REG_OPMENU + 4)) << 32;
-
-	for (opcode_index = 0; opcode_index < 8; opcode_index++) {
-		if ((opmenu & 0xff) == op.opcode) {
-			break;
-		}
-		opmenu >>= 8;
-	}
-	if (opcode_index == 8) {
-		printf_debug("Opcode %x not found.\n", op.opcode);
-		return 1;
-	}
-	temp16 |= ((uint16_t) (opcode_index & 0x07)) << 4;
-
-	/* Handle Atomic */
-	if (op.atomic != 0) {
-		/* Select atomic command */
-		temp16 |= SPIC_ACS;
-		/* Select prefix opcode */
-		if ((op.atomic - 1) == 1) {
-			/*Select prefix opcode 2 */
-			temp16 |= SPIC_SPOP;
-		}
-	}
-
-	/* Start */
-	temp16 |= SPIC_SCGO;
-
-	/* write it */
-	REGWRITE16(ICH7_REG_SPIC, temp16);
-
-	/* wait for cycle complete */
-	timeout = 100 * 1000 * 60;	// 60s is a looong timeout.
-	while (((REGREAD16(ICH7_REG_SPIS) & SPIS_CDS) == 0) && --timeout) {
-		programmer_delay(10);
-	}
-	if (!timeout) {
-		printf_debug("timeout\n");
-	}
-
-	if ((REGREAD16(ICH7_REG_SPIS) & SPIS_FCERR) != 0) {
-		printf_debug("Transaction error!\n");
-		return 1;
-	}
-
-	if ((!write_cmd) && (datalength != 0)) {
-		for (a = 0; a < datalength; a++) {
-			if ((a % 4) == 0) {
-				temp32 = REGREAD32(ICH7_REG_SPID0 + (a));
-			}
-
-			data[a] =
-			    (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8)))
-			    >> ((a % 4) * 8);
-		}
-	}
-
-	return 0;
-}
-
-static int ich9_run_opcode(OPCODE op, uint32_t offset,
-			   uint8_t datalength, uint8_t * data)
-{
-	int write_cmd = 0;
-	int timeout;
-	uint32_t temp32;
-	uint32_t a;
-	uint64_t opmenu;
-	int opcode_index;
-
-	/* Is it a write command? */
-	if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
-	    || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
-		write_cmd = 1;
-	}
-
-	/* Programm Offset in Flash into FADDR */
-	REGWRITE32(ICH9_REG_FADDR, (offset & 0x00FFFFFF));	/* SPI addresses are 24 BIT only */
-
-	/* Program data into FDATA0 to N */
-	if (write_cmd && (datalength != 0)) {
-		temp32 = 0;
-		for (a = 0; a < datalength; a++) {
-			if ((a % 4) == 0) {
-				temp32 = 0;
-			}
-
-			temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
-
-			if ((a % 4) == 3) {
-				REGWRITE32(ICH9_REG_FDATA0 + (a - (a % 4)),
-					   temp32);
-			}
-		}
-		if (((a - 1) % 4) != 3) {
-			REGWRITE32(ICH9_REG_FDATA0 +
-				   ((a - 1) - ((a - 1) % 4)), temp32);
-		}
-	}
-
-	/* Assemble SSFS + SSFC */
-	temp32 = 0;
-
-	/* clear error status registers */
-	temp32 |= (SSFS_CDS + SSFS_FCERR);
-	/* USE 20 MhZ */
-	temp32 |= SSFC_SCF_20MHZ;
-
-	if (datalength != 0) {
-		uint32_t datatemp;
-		temp32 |= SSFC_DS;
-		datatemp = ((uint32_t) ((datalength - 1) & 0x3f)) << (8 + 8);
-		temp32 |= datatemp;
-	}
-
-	/* Select opcode */
-	opmenu = REGREAD32(ICH9_REG_OPMENU);
-	opmenu |= ((uint64_t)REGREAD32(ICH9_REG_OPMENU + 4)) << 32;
-
-	for (opcode_index = 0; opcode_index < 8; opcode_index++) {
-		if ((opmenu & 0xff) == op.opcode) {
-			break;
-		}
-		opmenu >>= 8;
-	}
-	if (opcode_index == 8) {
-		printf_debug("Opcode %x not found.\n", op.opcode);
-		return 1;
-	}
-	temp32 |= ((uint32_t) (opcode_index & 0x07)) << (8 + 4);
-
-	/* Handle Atomic */
-	if (op.atomic != 0) {
-		/* Select atomic command */
-		temp32 |= SSFC_ACS;
-		/* Selct prefix opcode */
-		if ((op.atomic - 1) == 1) {
-			/*Select prefix opcode 2 */
-			temp32 |= SSFC_SPOP;
-		}
-	}
-
-	/* Start */
-	temp32 |= SSFC_SCGO;
-
-	/* write it */
-	REGWRITE32(ICH9_REG_SSFS, temp32);
-
-	/*wait for cycle complete */
-	timeout = 100 * 1000 * 60;	// 60s is a looong timeout.
-	while (((REGREAD32(ICH9_REG_SSFS) & SSFS_CDS) == 0) && --timeout) {
-		programmer_delay(10);
-	}
-	if (!timeout) {
-		printf_debug("timeout\n");
-	}
-
-	if ((REGREAD32(ICH9_REG_SSFS) & SSFS_FCERR) != 0) {
-		printf_debug("Transaction error!\n");
-		return 1;
-	}
-
-	if ((!write_cmd) && (datalength != 0)) {
-		for (a = 0; a < datalength; a++) {
-			if ((a % 4) == 0) {
-				temp32 = REGREAD32(ICH9_REG_FDATA0 + (a));
-			}
-
-			data[a] =
-			    (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8)))
-			    >> ((a % 4) * 8);
-		}
-	}
-
-	return 0;
-}
-
-static int run_opcode(OPCODE op, uint32_t offset,
-		      uint8_t datalength, uint8_t * data)
-{
-	switch (spi_controller) {
-	case SPI_CONTROLLER_VIA:
-		if (datalength > 16)
-			return SPI_INVALID_LENGTH;
-		return ich7_run_opcode(op, offset, datalength, data, 16);
-	case SPI_CONTROLLER_ICH7:
-		if (datalength > 64)
-			return SPI_INVALID_LENGTH;
-		return ich7_run_opcode(op, offset, datalength, data, 64);
-	case SPI_CONTROLLER_ICH9:
-		if (datalength > 64)
-			return SPI_INVALID_LENGTH;
-		return ich9_run_opcode(op, offset, datalength, data);
-	default:
-		printf_debug("%s: unsupported chipset\n", __func__);
-	}
-
-	/* If we ever get here, something really weird happened */
-	return -1;
-}
-
-static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes,
-			      int offset, int maxdata)
-{
-	int page_size = flash->page_size;
-	uint32_t remaining = page_size;
-	int towrite;
-
-	printf_debug("ich_spi_write_page: offset=%d, number=%d, buf=%p\n",
-		     offset, page_size, bytes);
-
-	for (; remaining > 0; remaining -= towrite) {
-		towrite = min(remaining, maxdata);
-		if (spi_nbyte_program(offset + (page_size - remaining),
-				      &bytes[page_size - remaining], towrite)) {
-			printf_debug("Error writing");
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-int ich_spi_read(struct flashchip *flash, uint8_t * buf, int start, int len)
-{
-	int maxdata = 64;
-
-	if (spi_controller == SPI_CONTROLLER_VIA)
-		maxdata = 16;
-
-	return spi_read_chunked(flash, buf, start, len, maxdata);
-}
-
-int ich_spi_write_256(struct flashchip *flash, uint8_t * buf)
-{
-	int i, j, rc = 0;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-	int erase_size = 64 * 1024;
-	int maxdata = 64;
-
-	spi_disable_blockprotect();
-	/* Erase first */
-	printf("Erasing flash before programming... ");
-	if (erase_flash(flash)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	printf("done.\n");
-
-	printf("Programming page: \n");
-	for (i = 0; i < total_size / erase_size; i++) {
-		if (spi_controller == SPI_CONTROLLER_VIA)
-			maxdata = 16;
-
-		for (j = 0; j < erase_size / page_size; j++) {
-			ich_spi_write_page(flash,
-			   (void *)(buf + (i * erase_size) + (j * page_size)),
-			   (i * erase_size) + (j * page_size), maxdata);
-		}
-	}
-
-	printf("\n");
-
-	return rc;
-}
-
-int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-		    const unsigned char *writearr, unsigned char *readarr)
-{
-	int a;
-	int result;
-	int opcode_index = -1;
-	const unsigned char cmd = *writearr;
-	OPCODE *opcode;
-	uint32_t addr = 0;
-	uint8_t *data;
-	int count;
-
-	/* find cmd in opcodes-table */
-	for (a = 0; a < 8; a++) {
-		if ((curopcodes->opcode[a]).opcode == cmd) {
-			opcode_index = a;
-			break;
-		}
-	}
-
-	/* unknown / not programmed command */
-	if (opcode_index == -1) {
-		printf_debug("Invalid OPCODE 0x%02x\n", cmd);
-		return SPI_INVALID_OPCODE;
-	}
-
-	opcode = &(curopcodes->opcode[opcode_index]);
-
-	/* if opcode-type requires an address */
-	if (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS ||
-	    opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
-		addr = (writearr[1] << 16) |
-		    (writearr[2] << 8) | (writearr[3] << 0);
-	}
-
-	/* translate read/write array/count */
-	if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) {
-		data = (uint8_t *) (writearr + 1);
-		count = writecnt - 1;
-	} else if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
-		data = (uint8_t *) (writearr + 4);
-		count = writecnt - 4;
-	} else {
-		data = (uint8_t *) readarr;
-		count = readcnt;
-	}
-
-	result = run_opcode(*opcode, addr, count, data);
-	if (result) {
-		printf_debug("run OPCODE 0x%02x failed\n", opcode->opcode);
-	}
-
-	return result;
-}
-
-int ich_spi_send_multicommand(struct spi_command *cmds)
-{
-	int ret = 0;
-	int oppos, preoppos;
-	for (; (cmds->writecnt || cmds->readcnt) && !ret; cmds++) {
-		/* Is the next command valid or a terminator? */
-		if ((cmds + 1)->writecnt || (cmds + 1)->readcnt) {
-			preoppos = find_preop(curopcodes, cmds->writearr[0]);
-			oppos = find_opcode(curopcodes, (cmds + 1)->writearr[0]);
-			/* Is the opcode of the current command listed in the
-			 * ICH struct OPCODES as associated preopcode for the
-			 * opcode of the next command?
-			 */
-			if ((oppos != -1) && (preoppos != -1) &&
-			    ((curopcodes->opcode[oppos].atomic - 1) == preoppos))
-				continue;
-		}	
-			
-		ret = ich_spi_send_command(cmds->writecnt, cmds->readcnt,
-					   cmds->writearr, cmds->readarr);
-	}
-	return ret;
-}
diff --git a/internal.c b/internal.c
deleted file mode 100644
index fc662c5..0000000
--- a/internal.c
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Carl-Daniel Hailfinger
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdint.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include "flash.h"
-
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-int io_fd;
-#endif
-
-struct pci_dev *pci_dev_find_filter(struct pci_filter filter)
-{
-	struct pci_dev *temp;
-
-	for (temp = pacc->devices; temp; temp = temp->next)
-		if (pci_filter_match(&filter, temp))
-			return temp;
-
-	return NULL;
-}
-
-struct pci_dev *pci_dev_find_vendorclass(uint16_t vendor, uint16_t class)
-{
-	struct pci_dev *temp;
-	struct pci_filter filter;
-	uint16_t tmp2;
-
-	pci_filter_init(NULL, &filter);
-	filter.vendor = vendor;
-
-	for (temp = pacc->devices; temp; temp = temp->next)
-		if (pci_filter_match(&filter, temp)) {
-			/* Read PCI class */
-			tmp2 = pci_read_word(temp, 0x0a);
-			if (tmp2 == class)
-				return temp;
-		}
-
-	return NULL;
-}
-
-struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device)
-{
-	struct pci_dev *temp;
-	struct pci_filter filter;
-
-	pci_filter_init(NULL, &filter);
-	filter.vendor = vendor;
-	filter.device = device;
-
-	for (temp = pacc->devices; temp; temp = temp->next)
-		if (pci_filter_match(&filter, temp))
-			return temp;
-
-	return NULL;
-}
-
-struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device,
-			      uint16_t card_vendor, uint16_t card_device)
-{
-	struct pci_dev *temp;
-	struct pci_filter filter;
-
-	pci_filter_init(NULL, &filter);
-	filter.vendor = vendor;
-	filter.device = device;
-
-	for (temp = pacc->devices; temp; temp = temp->next)
-		if (pci_filter_match(&filter, temp)) {
-			if ((card_vendor ==
-			     pci_read_word(temp, PCI_SUBSYSTEM_VENDOR_ID))
-			    && (card_device ==
-				pci_read_word(temp, PCI_SUBSYSTEM_ID)))
-				return temp;
-		}
-
-	return NULL;
-}
-
-void get_io_perms(void)
-{
-#if defined (__sun) && (defined(__i386) || defined(__amd64))
-	if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) {
-#elif defined(__FreeBSD__) || defined (__DragonFly__)
-	if ((io_fd = open("/dev/io", O_RDWR)) < 0) {
-#else
-	if (iopl(3) != 0) {
-#endif
-		fprintf(stderr, "ERROR: Could not get I/O privileges (%s).\n"
-			"You need to be root.\n", strerror(errno));
-		exit(1);
-	}
-}
-
-void release_io_perms(void)
-{
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-	close(io_fd);
-#endif
-}
-
-int internal_init(void)
-{
-	int ret = 0;
-
-	get_io_perms();
-
-	/* Initialize PCI access for flash enables */
-	pacc = pci_alloc();	/* Get the pci_access structure */
-	/* Set all options you want -- here we stick with the defaults */
-	pci_init(pacc);		/* Initialize the PCI library */
-	pci_scan_bus(pacc);	/* We want to get the list of devices */
-
-	/* We look at the lbtable first to see if we need a
-	 * mainboard specific flash enable sequence.
-	 */
-	coreboot_init();
-
-	/* try to enable it. Failure IS an option, since not all motherboards
-	 * really need this to be done, etc., etc.
-	 */
-	ret = chipset_flash_enable();
-	if (ret == -2) {
-		printf("WARNING: No chipset found. Flash detection "
-		       "will most likely fail.\n");
-	}
-
-	board_flash_enable(lb_vendor, lb_part);
-
-	/* Even if chipset init returns an error code, we don't want to abort.
-	 * The error code might have been a warning only.
-	 * Besides that, we don't check the board enable return code either.
-	 */
-	return 0; 
-}
-
-int internal_shutdown(void)
-{
-	release_io_perms();
-
-	return 0;
-}
-
-void internal_chip_writeb(uint8_t val, chipaddr addr)
-{
-	mmio_writeb(val, (void *) addr);
-}
-
-void internal_chip_writew(uint16_t val, chipaddr addr)
-{
-	mmio_writew(val, (void *) addr);
-}
-
-void internal_chip_writel(uint32_t val, chipaddr addr)
-{
-	mmio_writel(val, (void *) addr);
-}
-
-uint8_t internal_chip_readb(const chipaddr addr)
-{
-	return mmio_readb((void *) addr);
-}
-
-uint16_t internal_chip_readw(const chipaddr addr)
-{
-	return mmio_readw((void *) addr);
-}
-
-uint32_t internal_chip_readl(const chipaddr addr)
-{
-	return mmio_readl((void *) addr);
-}
-
-void internal_chip_readn(uint8_t *buf, const chipaddr addr, size_t len)
-{
-	memcpy(buf, (void *)addr, len);
-	return;
-}
-
-void mmio_writeb(uint8_t val, void *addr)
-{
-	*(volatile uint8_t *) addr = val;
-}
-
-void mmio_writew(uint16_t val, void *addr)
-{
-	*(volatile uint16_t *) addr = val;
-}
-
-void mmio_writel(uint32_t val, void *addr)
-{
-	*(volatile uint32_t *) addr = val;
-}
-
-uint8_t mmio_readb(void *addr)
-{
-	return *(volatile uint8_t *) addr;
-}
-
-uint16_t mmio_readw(void *addr)
-{
-	return *(volatile uint16_t *) addr;
-}
-
-uint32_t mmio_readl(void *addr)
-{
-	return *(volatile uint32_t *) addr;
-}
-
-void internal_delay(int usecs)
-{
-	/* If the delay is >1 s, use usleep because timing does not need to
-	 * be so precise.
-	 */
-	if (usecs > 1000000) {
-		usleep(usecs);
-	} else {
-		myusec_delay(usecs);
-	}
-}
-
-/* No-op shutdown() for programmers which don't need special handling */
-int noop_shutdown(void)
-{
-	return 0;
-}
-
-/* Fallback map() for programmers which don't need special handling */
-void *fallback_map(const char *descr, unsigned long phys_addr, size_t len)
-{
-	/* FIXME: Should return phys_addr. */
-	return 0;
-}
-
-/* No-op/fallback unmap() for programmers which don't need special handling */
-void fallback_unmap(void *virt_addr, size_t len)
-{
-}
-
-/* No-op chip_writeb() for drivers not supporting addr/data pair accesses */
-uint8_t noop_chip_readb(const chipaddr addr)
-{
-	return 0xff;
-}
-
-/* No-op chip_writeb() for drivers not supporting addr/data pair accesses */
-void noop_chip_writeb(uint8_t val, chipaddr addr)
-{
-}
-
-/* Little-endian fallback for drivers not supporting 16 bit accesses */
-void fallback_chip_writew(uint16_t val, chipaddr addr)
-{
-	chip_writeb(val & 0xff, addr);
-	chip_writeb((val >> 8) & 0xff, addr + 1);
-}
-
-/* Little-endian fallback for drivers not supporting 16 bit accesses */
-uint16_t fallback_chip_readw(const chipaddr addr)
-{
-	uint16_t val;
-	val = chip_readb(addr);
-	val |= chip_readb(addr + 1) << 8;
-	return val;
-}
-
-/* Little-endian fallback for drivers not supporting 32 bit accesses */
-void fallback_chip_writel(uint32_t val, chipaddr addr)
-{
-	chip_writew(val & 0xffff, addr);
-	chip_writew((val >> 16) & 0xffff, addr + 2);
-}
-
-/* Little-endian fallback for drivers not supporting 32 bit accesses */
-uint32_t fallback_chip_readl(const chipaddr addr)
-{
-	uint32_t val;
-	val = chip_readw(addr);
-	val |= chip_readw(addr + 2) << 16;
-	return val;
-}
-
-void fallback_chip_writen(uint8_t *buf, chipaddr addr, size_t len)
-{
-	size_t i;
-	for (i = 0; i < len; i++)
-		chip_writeb(buf[i], addr + i);
-	return;
-}
-
-void fallback_chip_readn(uint8_t *buf, chipaddr addr, size_t len)
-{
-	size_t i;
-	for (i = 0; i < len; i++)
-		buf[i] = chip_readb(addr + i);
-	return;
-}
diff --git a/it87spi.c b/it87spi.c
deleted file mode 100644
index a5dc06e..0000000
--- a/it87spi.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2007, 2008, 2009 Carl-Daniel Hailfinger
- * Copyright (C) 2008 Ronald Hoogenboom <ronald@zonnet.nl>
- * Copyright (C) 2008 coresystems GmbH
- *
- * 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; version 2 of the License.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/*
- * Contains the ITE IT87* SPI specific routines
- */
-
-#include <string.h>
-#include <stdlib.h>
-#include "flash.h"
-#include "spi.h"
-
-#define ITE_SUPERIO_PORT1	0x2e
-#define ITE_SUPERIO_PORT2	0x4e
-
-uint16_t it8716f_flashport = 0;
-/* use fast 33MHz SPI (<>0) or slow 16MHz (0) */
-int fast_spi = 1;
-
-/* Helper functions for most recent ITE IT87xx Super I/O chips */
-#define CHIP_ID_BYTE1_REG	0x20
-#define CHIP_ID_BYTE2_REG	0x21
-void enter_conf_mode_ite(uint16_t port)
-{
-	OUTB(0x87, port);
-	OUTB(0x01, port);
-	OUTB(0x55, port);
-	if (port == ITE_SUPERIO_PORT1)
-		OUTB(0x55, port);
-	else
-		OUTB(0xaa, port);
-}
-
-void exit_conf_mode_ite(uint16_t port)
-{
-	sio_write(port, 0x02, 0x02);
-}
-
-static uint16_t find_ite_spi_flash_port(uint16_t port)
-{
-	uint8_t tmp = 0;
-	char *portpos = NULL;
-	uint16_t id, flashport = 0;
-
-	enter_conf_mode_ite(port);
-
-	id = sio_read(port, CHIP_ID_BYTE1_REG) << 8;
-	id |= sio_read(port, CHIP_ID_BYTE2_REG);
-
-	/* TODO: Handle more IT87xx if they support flash translation */
-	if (0x8716 == id || 0x8718 == id) {
-		/* NOLDN, reg 0x24, mask out lowest bit (suspend) */
-		tmp = sio_read(port, 0x24) & 0xFE;
-		printf("Serial flash segment 0x%08x-0x%08x %sabled\n",
-		       0xFFFE0000, 0xFFFFFFFF, (tmp & 1 << 1) ? "en" : "dis");
-		printf("Serial flash segment 0x%08x-0x%08x %sabled\n",
-		       0x000E0000, 0x000FFFFF, (tmp & 1 << 1) ? "en" : "dis");
-		printf("Serial flash segment 0x%08x-0x%08x %sabled\n",
-		       0xFFEE0000, 0xFFEFFFFF, (tmp & 1 << 2) ? "en" : "dis");
-		printf("Serial flash segment 0x%08x-0x%08x %sabled\n",
-		       0xFFF80000, 0xFFFEFFFF, (tmp & 1 << 3) ? "en" : "dis");
-		printf("LPC write to serial flash %sabled\n",
-		       (tmp & 1 << 4) ? "en" : "dis");
-		/* The LPC->SPI force write enable below only makes sense for
-		 * non-programmer mode.
-		 */
-		/* If any serial flash segment is enabled, enable writing. */
-		if ((tmp & 0xe) && (!(tmp & 1 << 4))) {
-			printf("Enabling LPC write to serial flash\n");
-			tmp |= 1 << 4;
-			sio_write(port, 0x24, tmp);
-		}
-		printf("Serial flash pin %i\n", (tmp & 1 << 5) ? 87 : 29);
-		/* LDN 0x7, reg 0x64/0x65 */
-		sio_write(port, 0x07, 0x7);
-		flashport = sio_read(port, 0x64) << 8;
-		flashport |= sio_read(port, 0x65);
-		printf("Serial flash port 0x%04x\n", flashport);
-		if (programmer_param && !strlen(programmer_param)) {
-			free(programmer_param);
-			programmer_param = NULL;
-		}
-		if (programmer_param && (portpos = strstr(programmer_param, "port="))) {
-			portpos += 5;
-			flashport = strtol(portpos, (char **)NULL, 0);
-			printf("Forcing serial flash port 0x%04x\n", flashport);
-			sio_write(port, 0x64, (flashport >> 8));
-			sio_write(port, 0x65, (flashport & 0xff));
-		}
-	}
-	exit_conf_mode_ite(port);
-	return flashport;
-}
-
-int it87spi_common_init(void)
-{
-	it8716f_flashport = find_ite_spi_flash_port(ITE_SUPERIO_PORT1);
-
-	if (!it8716f_flashport)
-		it8716f_flashport = find_ite_spi_flash_port(ITE_SUPERIO_PORT2);
-
-	if (it8716f_flashport)
-		spi_controller = SPI_CONTROLLER_IT87XX;
-
-	return (!it8716f_flashport);
-}
-
-
-int it87spi_init(void)
-{
-	int ret;
-
-	get_io_perms();
-	ret = it87spi_common_init();
-	if (!ret) {
-		buses_supported = CHIP_BUSTYPE_SPI;
-	} else {
-		buses_supported = CHIP_BUSTYPE_NONE;
-	}
-	return ret;
-}
-
-int it87xx_probe_spi_flash(const char *name)
-{
-	int ret;
-
-	ret = it87spi_common_init();
-	if (!ret)
-		buses_supported |= CHIP_BUSTYPE_SPI;
-	return ret;
-}
-
-/*
- * The IT8716F only supports commands with length 1,2,4,5 bytes including
- * command byte and can not read more than 3 bytes from the device.
- *
- * This function expects writearr[0] to be the first byte sent to the device,
- * whereas the IT8716F splits commands internally into address and non-address
- * commands with the address in inverse wire order. That's why the register
- * ordering in case 4 and 5 may seem strange.
- */
-int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-			const unsigned char *writearr, unsigned char *readarr)
-{
-	uint8_t busy, writeenc;
-	int i;
-
-	do {
-		busy = INB(it8716f_flashport) & 0x80;
-	} while (busy);
-	if (readcnt > 3) {
-		printf("%s called with unsupported readcnt %i.\n",
-		       __func__, readcnt);
-		return SPI_INVALID_LENGTH;
-	}
-	switch (writecnt) {
-	case 1:
-		OUTB(writearr[0], it8716f_flashport + 1);
-		writeenc = 0x0;
-		break;
-	case 2:
-		OUTB(writearr[0], it8716f_flashport + 1);
-		OUTB(writearr[1], it8716f_flashport + 7);
-		writeenc = 0x1;
-		break;
-	case 4:
-		OUTB(writearr[0], it8716f_flashport + 1);
-		OUTB(writearr[1], it8716f_flashport + 4);
-		OUTB(writearr[2], it8716f_flashport + 3);
-		OUTB(writearr[3], it8716f_flashport + 2);
-		writeenc = 0x2;
-		break;
-	case 5:
-		OUTB(writearr[0], it8716f_flashport + 1);
-		OUTB(writearr[1], it8716f_flashport + 4);
-		OUTB(writearr[2], it8716f_flashport + 3);
-		OUTB(writearr[3], it8716f_flashport + 2);
-		OUTB(writearr[4], it8716f_flashport + 7);
-		writeenc = 0x3;
-		break;
-	default:
-		printf("%s called with unsupported writecnt %i.\n",
-		       __func__, writecnt);
-		return SPI_INVALID_LENGTH;
-	}
-	/*
-	 * Start IO, 33 or 16 MHz, readcnt input bytes, writecnt output bytes.
-	 * Note:
-	 * We can't use writecnt directly, but have to use a strange encoding.
-	 */
-	OUTB(((0x4 + (fast_spi ? 1 : 0)) << 4)
-		| ((readcnt & 0x3) << 2) | (writeenc), it8716f_flashport);
-
-	if (readcnt > 0) {
-		do {
-			busy = INB(it8716f_flashport) & 0x80;
-		} while (busy);
-
-		for (i = 0; i < readcnt; i++)
-			readarr[i] = INB(it8716f_flashport + 5 + i);
-	}
-
-	return 0;
-}
-
-/* Page size is usually 256 bytes */
-static int it8716f_spi_page_program(struct flashchip *flash, int block, uint8_t *buf)
-{
-	int i;
-	int result;
-	chipaddr bios = flash->virtual_memory;
-
-	result = spi_write_enable();
-	if (result)
-		return result;
-	/* FIXME: The command below seems to be redundant or wrong. */
-	OUTB(0x06, it8716f_flashport + 1);
-	OUTB(((2 + (fast_spi ? 1 : 0)) << 4), it8716f_flashport);
-	for (i = 0; i < 256; i++) {
-		chip_writeb(buf[256 * block + i], bios + 256 * block + i);
-	}
-	OUTB(0, it8716f_flashport);
-	/* Wait until the Write-In-Progress bit is cleared.
-	 * This usually takes 1-10 ms, so wait in 1 ms steps.
-	 */
-	while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
-		programmer_delay(1000);
-	return 0;
-}
-
-/*
- * IT8716F only allows maximum of 512 kb SPI mapped to LPC memory cycles
- * Need to read this big flash using firmware cycles 3 byte at a time.
- */
-int it8716f_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len)
-{
-	int total_size = 1024 * flash->total_size;
-	fast_spi = 0;
-
-	if ((programmer == PROGRAMMER_IT87SPI) || (total_size > 512 * 1024)) {
-		spi_read_chunked(flash, buf, start, len, 3);
-	} else {
-		read_memmapped(flash, buf, start, len);
-	}
-
-	return 0;
-}
-
-int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf)
-{
-	int total_size = 1024 * flash->total_size;
-	int i;
-
-	/*
-	 * IT8716F only allows maximum of 512 kb SPI chip size for memory
-	 * mapped access.
-	 */
-	if ((programmer == PROGRAMMER_IT87SPI) || (total_size > 512 * 1024)) {
-		spi_chip_write_1(flash, buf);
-	} else {
-		spi_disable_blockprotect();
-		/* Erase first */
-		printf("Erasing flash before programming... ");
-		if (erase_flash(flash)) {
-			fprintf(stderr, "ERASE FAILED!\n");
-			return -1;
-		}
-		printf("done.\n");
-		for (i = 0; i < total_size / 256; i++) {
-			it8716f_spi_page_program(flash, i, buf);
-		}
-	}
-
-	return 0;
-}
diff --git a/jedec.c b/jedec.c
deleted file mode 100644
index 83a0b83..0000000
--- a/jedec.c
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- * Copyright (C) 2006 Giampiero Giancipoli <gianci@email.it>
- * Copyright (C) 2006 coresystems GmbH <info@coresystems.de>
- * Copyright (C) 2007 Carl-Daniel Hailfinger
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "flash.h"
-
-#define MAX_REFLASH_TRIES 0x10
-
-/* Check one byte for odd parity */
-uint8_t oddparity(uint8_t val)
-{
-	val = (val ^ (val >> 4)) & 0xf;
-	val = (val ^ (val >> 2)) & 0x3;
-	return (val ^ (val >> 1)) & 0x1;
-}
-
-void toggle_ready_jedec(chipaddr dst)
-{
-	unsigned int i = 0;
-	uint8_t tmp1, tmp2;
-
-	tmp1 = chip_readb(dst) & 0x40;
-
-	while (i++ < 0xFFFFFFF) {
-		tmp2 = chip_readb(dst) & 0x40;
-		if (tmp1 == tmp2) {
-			break;
-		}
-		tmp1 = tmp2;
-	}
-}
-
-void data_polling_jedec(chipaddr dst, uint8_t data)
-{
-	unsigned int i = 0;
-	uint8_t tmp;
-
-	data &= 0x80;
-
-	while (i++ < 0xFFFFFFF) {
-		tmp = chip_readb(dst) & 0x80;
-		if (tmp == data) {
-			break;
-		}
-	}
-}
-
-void start_program_jedec(chipaddr bios)
-{
-	chip_writeb(0xAA, bios + 0x5555);
-	chip_writeb(0x55, bios + 0x2AAA);
-	chip_writeb(0xA0, bios + 0x5555);
-}
-
-int probe_jedec(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-	uint8_t id1, id2;
-	uint32_t largeid1, largeid2;
-	uint32_t flashcontent1, flashcontent2;
-	int probe_timing_enter, probe_timing_exit;
-
-	if (flash->probe_timing > 0) 
-		probe_timing_enter = probe_timing_exit = flash->probe_timing;
-	else if (flash->probe_timing == TIMING_ZERO) { /* No delay. */
-		probe_timing_enter = probe_timing_exit = 0;
-	} else if (flash->probe_timing == TIMING_FIXME) { /* == _IGNORED */
-		printf_debug("Chip lacks correct probe timing information, "
-			     "using default 10mS/40uS. ");
-		probe_timing_enter = 10000;
-		probe_timing_exit = 40;
-	} else {
-		printf("Chip has negative value in probe_timing, failing "
-		       "without chip access\n");
-		return 0;
-	}
-
-	/* Issue JEDEC Product ID Entry command */
-	chip_writeb(0xAA, bios + 0x5555);
-	programmer_delay(10);
-	chip_writeb(0x55, bios + 0x2AAA);
-	programmer_delay(10);
-	chip_writeb(0x90, bios + 0x5555);
-	programmer_delay(probe_timing_enter);
-
-	/* Read product ID */
-	id1 = chip_readb(bios);
-	id2 = chip_readb(bios + 0x01);
-	largeid1 = id1;
-	largeid2 = id2;
-
-	/* Check if it is a continuation ID, this should be a while loop. */
-	if (id1 == 0x7F) {
-		largeid1 <<= 8;
-		id1 = chip_readb(bios + 0x100);
-		largeid1 |= id1;
-	}
-	if (id2 == 0x7F) {
-		largeid2 <<= 8;
-		id2 = chip_readb(bios + 0x101);
-		largeid2 |= id2;
-	}
-
-	/* Issue JEDEC Product ID Exit command */
-	chip_writeb(0xAA, bios + 0x5555);
-	programmer_delay(10);
-	chip_writeb(0x55, bios + 0x2AAA);
-	programmer_delay(10);
-	chip_writeb(0xF0, bios + 0x5555);
-	programmer_delay(probe_timing_exit);
-
-	printf_debug("%s: id1 0x%02x, id2 0x%02x", __func__, largeid1, largeid2);
-	if (!oddparity(id1))
-		printf_debug(", id1 parity violation");
-
-	/* Read the product ID location again. We should now see normal flash contents. */
-	flashcontent1 = chip_readb(bios);
-	flashcontent2 = chip_readb(bios + 0x01);
-
-	/* Check if it is a continuation ID, this should be a while loop. */
-	if (flashcontent1 == 0x7F) {
-		flashcontent1 <<= 8;
-		flashcontent1 |= chip_readb(bios + 0x100);
-	}
-	if (flashcontent2 == 0x7F) {
-		flashcontent2 <<= 8;
-		flashcontent2 |= chip_readb(bios + 0x101);
-	}
-
-	if (largeid1 == flashcontent1)
-		printf_debug(", id1 is normal flash content");
-	if (largeid2 == flashcontent2)
-		printf_debug(", id2 is normal flash content");
-
-	printf_debug("\n");
-	if (largeid1 == flash->manufacture_id && largeid2 == flash->model_id)
-		return 1;
-
-	return 0;
-}
-
-int erase_sector_jedec(struct flashchip *flash, unsigned int page, unsigned int pagesize)
-{
-	chipaddr bios = flash->virtual_memory;
-
-	/*  Issue the Sector Erase command   */
-	chip_writeb(0xAA, bios + 0x5555);
-	programmer_delay(10);
-	chip_writeb(0x55, bios + 0x2AAA);
-	programmer_delay(10);
-	chip_writeb(0x80, bios + 0x5555);
-	programmer_delay(10);
-
-	chip_writeb(0xAA, bios + 0x5555);
-	programmer_delay(10);
-	chip_writeb(0x55, bios + 0x2AAA);
-	programmer_delay(10);
-	chip_writeb(0x30, bios + page);
-	programmer_delay(10);
-
-	/* wait for Toggle bit ready         */
-	toggle_ready_jedec(bios);
-
-	if (check_erased_range(flash, page, pagesize)) {
-		fprintf(stderr,"ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-int erase_block_jedec(struct flashchip *flash, unsigned int block, unsigned int blocksize)
-{
-	chipaddr bios = flash->virtual_memory;
-
-	/*  Issue the Sector Erase command   */
-	chip_writeb(0xAA, bios + 0x5555);
-	programmer_delay(10);
-	chip_writeb(0x55, bios + 0x2AAA);
-	programmer_delay(10);
-	chip_writeb(0x80, bios + 0x5555);
-	programmer_delay(10);
-
-	chip_writeb(0xAA, bios + 0x5555);
-	programmer_delay(10);
-	chip_writeb(0x55, bios + 0x2AAA);
-	programmer_delay(10);
-	chip_writeb(0x50, bios + block);
-	programmer_delay(10);
-
-	/* wait for Toggle bit ready         */
-	toggle_ready_jedec(bios);
-
-	if (check_erased_range(flash, block, blocksize)) {
-		fprintf(stderr,"ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-int erase_chip_jedec(struct flashchip *flash)
-{
-	int total_size = flash->total_size * 1024;
-	chipaddr bios = flash->virtual_memory;
-
-	/*  Issue the JEDEC Chip Erase command   */
-	chip_writeb(0xAA, bios + 0x5555);
-	programmer_delay(10);
-	chip_writeb(0x55, bios + 0x2AAA);
-	programmer_delay(10);
-	chip_writeb(0x80, bios + 0x5555);
-	programmer_delay(10);
-
-	chip_writeb(0xAA, bios + 0x5555);
-	programmer_delay(10);
-	chip_writeb(0x55, bios + 0x2AAA);
-	programmer_delay(10);
-	chip_writeb(0x10, bios + 0x5555);
-	programmer_delay(10);
-
-	toggle_ready_jedec(bios);
-
-	if (check_erased_range(flash, 0, total_size)) {
-		fprintf(stderr,"ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-int write_page_write_jedec(struct flashchip *flash, uint8_t *src,
-			   int start, int page_size)
-{
-	int i, tried = 0, failed;
-	uint8_t *s = src;
-	chipaddr bios = flash->virtual_memory;
-	chipaddr dst = bios + start;
-	chipaddr d = dst;
-
-retry:
-	/* Issue JEDEC Data Unprotect comand */
-	start_program_jedec(bios);
-
-	/* transfer data from source to destination */
-	for (i = 0; i < page_size; i++) {
-		/* If the data is 0xFF, don't program it */
-		if (*src != 0xFF)
-			chip_writeb(*src, dst);
-		dst++;
-		src++;
-	}
-
-	toggle_ready_jedec(dst - 1);
-
-	dst = d;
-	src = s;
-	failed = verify_range(flash, src, start, page_size, NULL);
-
-	if (failed && tried++ < MAX_REFLASH_TRIES) {
-		fprintf(stderr, "retrying.\n");
-		goto retry;
-	}
-	if (failed) {
-		fprintf(stderr, " page 0x%lx failed!\n",
-			(d - bios) / page_size);
-	}
-	return failed;
-}
-
-int write_byte_program_jedec(chipaddr bios, uint8_t *src,
-			     chipaddr dst)
-{
-	int tried = 0, failed = 0;
-
-	/* If the data is 0xFF, don't program it and don't complain. */
-	if (*src == 0xFF) {
-		return 0;
-	}
-
-retry:
-	/* Issue JEDEC Byte Program command */
-	start_program_jedec(bios);
-
-	/* transfer data from source to destination */
-	chip_writeb(*src, dst);
-	toggle_ready_jedec(bios);
-
-	if (chip_readb(dst) != *src && tried++ < MAX_REFLASH_TRIES) {
-		goto retry;
-	}
-
-	if (tried >= MAX_REFLASH_TRIES)
-		failed = 1;
-
-	return failed;
-}
-
-int write_sector_jedec(chipaddr bios, uint8_t *src,
-		       chipaddr dst, unsigned int page_size)
-{
-	int i, failed = 0;
-	chipaddr olddst;
-
-	olddst = dst;
-	for (i = 0; i < page_size; i++) {
-		if (write_byte_program_jedec(bios, src, dst))
-			failed = 1;
-		dst++, src++;
-	}
-	if (failed)
-		fprintf(stderr, " writing sector at 0x%lx failed!\n", olddst);
-
-	return failed;
-}
-
-int write_jedec(struct flashchip *flash, uint8_t *buf)
-{
-	int i, failed = 0;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-
-	if (erase_chip_jedec(flash)) {
-		fprintf(stderr,"ERASE FAILED!\n");
-		return -1;
-	}
-	
-	printf("Programming page: ");
-	for (i = 0; i < total_size / page_size; i++) {
-		printf("%04d at address: 0x%08x", i, i * page_size);
-		if (write_page_write_jedec(flash, buf + i * page_size,
-					   i * page_size, page_size))
-			failed = 1;
-		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-	}
-	printf("\n");
-
-	return failed;
-}
-
-int write_jedec_1(struct flashchip *flash, uint8_t * buf)
-{
-	int i;
-	chipaddr bios = flash->virtual_memory;
-	chipaddr dst = bios;
-
-	programmer_delay(10);
-	if (erase_flash(flash)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-
-	printf("Programming page: ");
-	for (i = 0; i < flash->total_size; i++) {
-		if ((i & 0x3) == 0)
-			printf("address: 0x%08lx", (unsigned long)i * 1024);
-
-                write_sector_jedec(bios, buf + i * 1024, dst + i * 1024, 1024);
-
-		if ((i & 0x3) == 0)
-			printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-	}
-
-	printf("\n");
-	return 0;
-}
diff --git a/layout.c b/layout.c
deleted file mode 100644
index c432ebe..0000000
--- a/layout.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2005-2008 coresystems GmbH
- * (Written by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH)
- *
- * 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; version 2 of the License.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include "flash.h"
-
-char *mainboard_vendor = NULL;
-char *mainboard_part = NULL;
-int romimages = 0;
-
-#define MAX_ROMLAYOUT	16
-
-typedef struct {
-	unsigned int start;
-	unsigned int end;
-	unsigned int included;
-	char name[256];
-} romlayout_t;
-
-romlayout_t rom_entries[MAX_ROMLAYOUT];
-
-static char *def_name = "DEFAULT";
-
-int show_id(uint8_t *bios, int size, int force)
-{
-	unsigned int *walk;
-	unsigned int mb_part_offset, mb_vendor_offset;
-	char *mb_part, *mb_vendor;
-
-	mainboard_vendor = def_name;
-	mainboard_part = def_name;
-
-	walk = (unsigned int *)(bios + size - 0x10);
-	walk--;
-
-	if ((*walk) == 0 || ((*walk) & 0x3ff) != 0) {
-		/* We might have an NVIDIA chipset BIOS which stores the ID
-		 * information at a different location.
-		 */
-		walk = (unsigned int *)(bios + size - 0x80);
-		walk--;
-	}
-
-	/*
-	 * Check if coreboot last image size is 0 or not a multiple of 1k or
-	 * bigger than the chip or if the pointers to vendor ID or mainboard ID
-	 * are outside the image of if the start of ID strings are nonsensical
-	 * (nonprintable and not \0).
-	 */
-	mb_part_offset = *(walk - 1);
-	mb_vendor_offset = *(walk - 2);
-	if ((*walk) == 0 || ((*walk) & 0x3ff) != 0 || (*walk) > size ||
-	    mb_part_offset > size || mb_vendor_offset > size) {
-		printf("Flash image seems to be a legacy BIOS. Disabling checks.\n");
-		return 0;
-	}
-
-	mb_part = (char *)(bios + size - mb_part_offset);
-	mb_vendor = (char *)(bios + size - mb_vendor_offset);
-	if (!isprint((unsigned char)*mb_part) ||
-	    !isprint((unsigned char)*mb_vendor)) {
-		printf("Flash image seems to have garbage in the ID location."
-		       " Disabling checks.\n");
-		return 0;
-	}
-
-	printf_debug("coreboot last image size "
-		     "(not ROM size) is %d bytes.\n", *walk);
-
-	mainboard_part = strdup(mb_part);
-	mainboard_vendor = strdup(mb_vendor);
-	printf_debug("Manufacturer: %s\n", mainboard_vendor);
-	printf_debug("Mainboard ID: %s\n", mainboard_part);
-
-	/*
-	 * If lb_vendor is not set, the coreboot table was
-	 * not found. Nor was -m VENDOR:PART specified.
-	 */
-	if (!lb_vendor || !lb_part) {
-		printf("Note: If the following flash access fails, "
-		       "try -m <vendor>:<mainboard>.\n");
-		return 0;
-	}
-
-	/* These comparisons are case insensitive to make things
-	 * a little less user^Werror prone. 
-	 */
-	if (!strcasecmp(mainboard_vendor, lb_vendor) &&
-	    !strcasecmp(mainboard_part, lb_part)) {
-		printf_debug("This firmware image matches this mainboard.\n");
-	} else {
-		if (force) {
-			printf("WARNING: This firmware image does not "
-			       "seem to fit to this machine - forcing it.\n");
-		} else {
-			printf("ERROR: Your firmware image (%s:%s) does not "
-			       "appear to\n       be correct for the detected "
-			       "mainboard (%s:%s)\n\nOverride with --force if you "
-			       "are absolutely sure that you\nare using a correct "
-			       "image for this mainboard or override\nthe detected "
-			       "values with --mainboard <vendor>:<mainboard>.\n\n",
-			       mainboard_vendor, mainboard_part, lb_vendor,
-			       lb_part);
-			exit(1);
-		}
-	}
-
-	return 0;
-}
-
-int read_romlayout(char *name)
-{
-	FILE *romlayout;
-	char tempstr[256];
-	int i;
-
-	romlayout = fopen(name, "r");
-
-	if (!romlayout) {
-		fprintf(stderr, "ERROR: Could not open ROM layout (%s).\n",
-			name);
-		return -1;
-	}
-
-	while (!feof(romlayout)) {
-		char *tstr1, *tstr2;
-		if (2 != fscanf(romlayout, "%s %s\n", tempstr, rom_entries[romimages].name))
-			continue;
-#if 0
-		// fscanf does not like arbitrary comments like that :( later
-		if (tempstr[0] == '#') {
-			continue;
-		}
-#endif
-		tstr1 = strtok(tempstr, ":");
-		tstr2 = strtok(NULL, ":");
-		if (!tstr1 || !tstr2) {
-			fprintf(stderr, "Error parsing layout file.\n");
-			fclose(romlayout);
-			return 1;
-		}
-		rom_entries[romimages].start = strtol(tstr1, (char **)NULL, 16);
-		rom_entries[romimages].end = strtol(tstr2, (char **)NULL, 16);
-		rom_entries[romimages].included = 0;
-		romimages++;
-	}
-
-	for (i = 0; i < romimages; i++) {
-		printf_debug("romlayout %08x - %08x named %s\n",
-			     rom_entries[i].start,
-			     rom_entries[i].end, rom_entries[i].name);
-	}
-
-	fclose(romlayout);
-
-	return 0;
-}
-
-int find_romentry(char *name)
-{
-	int i;
-
-	if (!romimages)
-		return -1;
-
-	printf("Looking for \"%s\"... ", name);
-
-	for (i = 0; i < romimages; i++) {
-		if (!strcmp(rom_entries[i].name, name)) {
-			rom_entries[i].included = 1;
-			printf("found.\n");
-			return i;
-		}
-	}
-	printf("not found.\n");	// Not found. Error.
-
-	return -1;
-}
-
-int handle_romentries(uint8_t *buffer, struct flashchip *flash)
-{
-	int i;
-
-	// This function does not save flash write cycles.
-	// 
-	// Also it does not cope with overlapping rom layout
-	// sections. 
-	// example:
-	// 00000000:00008fff gfxrom
-	// 00009000:0003ffff normal
-	// 00040000:0007ffff fallback
-	// 00000000:0007ffff all
-	//
-	// If you'd specify -i all the included flag of all other
-	// sections is still 0, so no changes will be made to the
-	// flash. Same thing if you specify -i normal -i all only 
-	// normal will be updated and the rest will be kept.
-
-	for (i = 0; i < romimages; i++) {
-
-		if (rom_entries[i].included)
-			continue;
-
-		flash->read(flash, buffer + rom_entries[i].start,
-			    rom_entries[i].start,
-			    rom_entries[i].end - rom_entries[i].start + 1);
-	}
-
-	return 0;
-}
diff --git a/libflashrom/82802ab.c b/libflashrom/82802ab.c
new file mode 100644
index 0000000..58d3467
--- /dev/null
+++ b/libflashrom/82802ab.c
@@ -0,0 +1,196 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Datasheet:
+ *  - Name: Intel 82802AB/82802AC Firmware Hub (FWH)
+ *  - URL: http://www.intel.com/design/chipsets/datashts/290658.htm
+ *  - PDF: http://download.intel.com/design/chipsets/datashts/29065804.pdf
+ *  - Order number: 290658-004
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "flash.h"
+
+// I need that Berkeley bit-map printer
+void print_82802ab_status(uint8_t status)
+{
+	printf_debug("%s", status & 0x80 ? "Ready:" : "Busy:");
+	printf_debug("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:");
+	printf_debug("%s", status & 0x20 ? "BE ERROR:" : "BE OK:");
+	printf_debug("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:");
+	printf_debug("%s", status & 0x8 ? "VP ERR:" : "VPP OK:");
+	printf_debug("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:");
+	printf_debug("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:");
+}
+
+int probe_82802ab(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+	uint8_t id1, id2;
+
+	/* Reset to get a clean state */
+	chip_writeb(0xFF, bios);
+	programmer_delay(10);
+
+	/* Enter ID mode */
+	chip_writeb(0x90, bios);
+	programmer_delay(10);
+
+	id1 = chip_readb(bios);
+	id2 = chip_readb(bios + 0x01);
+
+	/* Leave ID mode */
+	chip_writeb(0xFF, bios);
+
+	programmer_delay(10);
+
+	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+
+	if (id1 != flash->manufacture_id || id2 != flash->model_id)
+		return 0;
+
+	map_flash_registers(flash);
+
+	return 1;
+}
+
+uint8_t wait_82802ab(chipaddr bios)
+{
+	uint8_t status;
+
+	chip_writeb(0x70, bios);
+	if ((chip_readb(bios) & 0x80) == 0) {	// it's busy
+		while ((chip_readb(bios) & 0x80) == 0) ;
+	}
+
+	status = chip_readb(bios);
+
+	/* Reset to get a clean state */
+	chip_writeb(0xFF, bios);
+
+	return status;
+}
+
+int erase_82802ab_block(struct flashchip *flash, int offset)
+{
+	chipaddr bios = flash->virtual_memory + offset;
+	chipaddr wrprotect = flash->virtual_registers + offset + 2;
+	uint8_t status;
+
+	// clear status register
+	chip_writeb(0x50, bios);
+
+	// clear write protect
+	chip_writeb(0, wrprotect);
+
+	// now start it
+	chip_writeb(0x20, bios);
+	chip_writeb(0xd0, bios);
+	programmer_delay(10);
+
+	// now let's see what the register is
+	status = wait_82802ab(flash->virtual_memory);
+	print_82802ab_status(status);
+
+	if (check_erased_range(flash, offset, flash->page_size)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	printf("DONE BLOCK 0x%x\n", offset);
+
+	return 0;
+}
+
+int erase_82802ab(struct flashchip *flash)
+{
+	int i;
+	unsigned int total_size = flash->total_size * 1024;
+
+	printf("total_size is %d; flash->page_size is %d\n",
+	       total_size, flash->page_size);
+	for (i = 0; i < total_size; i += flash->page_size)
+		if (erase_82802ab_block(flash, i)) {
+			fprintf(stderr, "ERASE FAILED!\n");
+			return -1;
+		}
+	printf("DONE ERASE\n");
+
+	return 0;
+}
+
+void write_page_82802ab(chipaddr bios, uint8_t *src,
+			chipaddr dst, int page_size)
+{
+	int i;
+
+	for (i = 0; i < page_size; i++) {
+		/* transfer data from source to destination */
+		chip_writeb(0x40, dst);
+		chip_writeb(*src++, dst++);
+		wait_82802ab(bios);
+	}
+}
+
+int write_82802ab(struct flashchip *flash, uint8_t *buf)
+{
+	int i;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+	chipaddr bios = flash->virtual_memory;
+	uint8_t *tmpbuf = malloc(page_size);
+
+	if (!tmpbuf) {
+		printf("Could not allocate memory!\n");
+		exit(1);
+	}
+	printf("Programming page: \n");
+	for (i = 0; i < total_size / page_size; i++) {
+		printf
+		    ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+		printf("%04d at address: 0x%08x", i, i * page_size);
+
+		/* Auto Skip Blocks, which already contain the desired data
+		 * Faster, because we only write, what has changed
+		 * More secure, because blocks, which are excluded
+		 * (with the exclude or layout feature)
+		 * or not erased and rewritten; their data is retained also in
+		 * sudden power off situations
+		 */
+		chip_readn(tmpbuf, bios + i * page_size, page_size);
+		if (!memcmp((void *)(buf + i * page_size), tmpbuf, page_size)) {
+			printf("SKIPPED\n");
+			continue;
+		}
+
+		/* erase block by block and write block by block; this is the most secure way */
+		if (erase_82802ab_block(flash, i * page_size)) {
+			fprintf(stderr, "ERASE FAILED!\n");
+			return -1;
+		}
+		write_page_82802ab(bios, buf + i * page_size,
+				   bios + i * page_size, page_size);
+	}
+	printf("\n");
+	free(tmpbuf);
+
+	return 0;
+}
diff --git a/libflashrom/am29f040b.c b/libflashrom/am29f040b.c
new file mode 100644
index 0000000..46a5ef4
--- /dev/null
+++ b/libflashrom/am29f040b.c
@@ -0,0 +1,144 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+
+/* FIMXE: check that the 2 second delay is really needed.
+          Use erase_sector_jedec if not? */
+static int erase_sector_29f040b(struct flashchip *flash, unsigned long address)
+{
+	int page_size = flash->page_size;
+	chipaddr bios = flash->virtual_memory;
+
+	chip_writeb(0xAA, bios + 0x555);
+	chip_writeb(0x55, bios + 0x2AA);
+	chip_writeb(0x80, bios + 0x555);
+	chip_writeb(0xAA, bios + 0x555);
+	chip_writeb(0x55, bios + 0x2AA);
+	chip_writeb(0x30, bios + address);
+
+	programmer_delay(2 * 1000 * 1000);
+
+	/* wait for Toggle bit ready         */
+	toggle_ready_jedec(bios + address);
+
+	if (check_erased_range(flash, address, page_size)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+/* FIXME: use write_sector_jedec? */
+static int write_sector_29f040b(chipaddr bios, uint8_t *src, chipaddr dst,
+				unsigned int page_size)
+{
+	int i;
+
+	for (i = 0; i < page_size; i++) {
+		if ((i & 0xfff) == 0xfff)
+			printf("0x%08lx", dst - bios);
+
+		chip_writeb(0xAA, bios + 0x555);
+		chip_writeb(0x55, bios + 0x2AA);
+		chip_writeb(0xA0, bios + 0x555);
+		chip_writeb(*src++, dst++);
+
+		/* wait for Toggle bit ready */
+		toggle_ready_jedec(bios);
+
+		if ((i & 0xfff) == 0xfff)
+			printf("\b\b\b\b\b\b\b\b\b\b");
+	}
+
+	return 0;
+}
+
+int probe_29f040b(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+	uint8_t id1, id2;
+
+	chip_writeb(0xAA, bios + 0x555);
+	chip_writeb(0x55, bios + 0x2AA);
+	chip_writeb(0x90, bios + 0x555);
+
+	id1 = chip_readb(bios);
+	id2 = chip_readb(bios + 0x01);
+
+	chip_writeb(0xF0, bios);
+
+	programmer_delay(10);
+
+	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+	if (id1 == flash->manufacture_id && id2 == flash->model_id)
+		return 1;
+
+	return 0;
+}
+
+/* FIXME: use erase_chip_jedec? */
+int erase_29f040b(struct flashchip *flash)
+{
+	int total_size = flash->total_size * 1024;
+	chipaddr bios = flash->virtual_memory;
+
+	chip_writeb(0xAA, bios + 0x555);
+	chip_writeb(0x55, bios + 0x2AA);
+	chip_writeb(0x80, bios + 0x555);
+	chip_writeb(0xAA, bios + 0x555);
+	chip_writeb(0x55, bios + 0x2AA);
+	chip_writeb(0x10, bios + 0x555);
+
+	programmer_delay(10);
+	toggle_ready_jedec(bios);
+
+	if (check_erased_range(flash, 0, total_size)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+int write_29f040b(struct flashchip *flash, uint8_t *buf)
+{
+	int i;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+	chipaddr bios = flash->virtual_memory;
+
+	printf("Programming page ");
+	for (i = 0; i < total_size / page_size; i++) {
+		/* erase the page before programming */
+		if (erase_sector_29f040b(flash, i * page_size)) {
+			fprintf(stderr, "ERASE FAILED!\n");
+			return -1;
+		}
+
+		/* write to the sector */
+		printf("%04d at address: ", i);
+		write_sector_29f040b(bios, buf + i * page_size,
+				     bios + i * page_size, page_size);
+		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+	}
+	printf("\n");
+
+	return 0;
+}
diff --git a/libflashrom/bitbang_spi.c b/libflashrom/bitbang_spi.c
new file mode 100644
index 0000000..abf5530
--- /dev/null
+++ b/libflashrom/bitbang_spi.c
@@ -0,0 +1,164 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "flash.h"
+#include "spi.h"
+
+/* Length of half a clock period in usecs */
+int bitbang_spi_half_period = 0;
+
+enum bitbang_spi_master bitbang_spi_master = BITBANG_SPI_INVALID;
+
+const struct bitbang_spi_master_entry bitbang_spi_master_table[] = {
+	{}, /* This entry corresponds to BITBANG_SPI_INVALID. */
+};
+
+const int bitbang_spi_master_count = ARRAY_SIZE(bitbang_spi_master_table);
+
+void bitbang_spi_set_cs(int val)
+{
+	bitbang_spi_master_table[bitbang_spi_master].set_cs(val);
+}
+
+void bitbang_spi_set_sck(int val)
+{
+	bitbang_spi_master_table[bitbang_spi_master].set_sck(val);
+}
+
+void bitbang_spi_set_mosi(int val)
+{
+	bitbang_spi_master_table[bitbang_spi_master].set_mosi(val);
+}
+
+int bitbang_spi_get_miso(void)
+{
+	return bitbang_spi_master_table[bitbang_spi_master].get_miso();
+}
+
+int bitbang_spi_init(void)
+{
+	bitbang_spi_set_cs(1);
+	bitbang_spi_set_sck(0);
+	buses_supported = CHIP_BUSTYPE_SPI;
+	return 0;
+}
+
+uint8_t bitbang_spi_readwrite_byte(uint8_t val)
+{
+	uint8_t ret = 0;
+	int i;
+
+	for (i = 7; i >= 0; i--) {
+		bitbang_spi_set_mosi((val >> i) & 1);
+		programmer_delay(bitbang_spi_half_period);
+		bitbang_spi_set_sck(1);
+		ret <<= 1;
+		ret |= bitbang_spi_get_miso();
+		programmer_delay(bitbang_spi_half_period);
+		bitbang_spi_set_sck(0);
+	}
+	return ret;
+}
+
+int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		const unsigned char *writearr, unsigned char *readarr)
+{
+	static unsigned char *bufout = NULL;
+	static unsigned char *bufin = NULL;
+	static int oldbufsize = 0;
+	int bufsize;
+	int i;
+
+	/* Arbitrary size limitation here. We're only constrained by memory. */
+	if (writecnt > 65536 || readcnt > 65536)
+		return SPI_INVALID_LENGTH;
+
+	bufsize = max(writecnt + readcnt, 260);
+	/* Never shrink. realloc() calls are expensive. */
+	if (bufsize > oldbufsize) {
+		bufout = realloc(bufout, bufsize);
+		if (!bufout) {
+			fprintf(stderr, "Out of memory!\n");
+			if (bufin)
+				free(bufin);
+			exit(1);
+		}
+		bufin = realloc(bufout, bufsize);
+		if (!bufin) {
+			fprintf(stderr, "Out of memory!\n");
+			if (bufout)
+				free(bufout);
+			exit(1);
+		}
+		oldbufsize = bufsize;
+	}
+		
+	memcpy(bufout, writearr, writecnt);
+	/* Shift out 0x00 while reading data. */
+	memset(bufout + writecnt, 0x00, readcnt);
+	/* Make sure any non-read data is 0xff. */
+	memset(bufin + writecnt, 0xff, readcnt);
+
+	bitbang_spi_set_cs(0);
+	for (i = 0; i < readcnt + writecnt; i++) {
+		bufin[i] = bitbang_spi_readwrite_byte(bufout[i]);
+	}
+	programmer_delay(bitbang_spi_half_period);
+	bitbang_spi_set_cs(1);
+	programmer_delay(bitbang_spi_half_period);
+	memcpy(readarr, bufin + writecnt, readcnt);
+
+	return 0;
+}
+
+int bitbang_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
+{
+	/* Maximum read length is unlimited, use 64k bytes. */
+	return spi_read_chunked(flash, buf, start, len, 64 * 1024);
+}
+
+int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf)
+{
+	int total_size = 1024 * flash->total_size;
+	int i;
+
+	printf_debug("total_size is %d\n", total_size);
+	for (i = 0; i < total_size; i += 256) {
+		int l, r;
+		if (i + 256 <= total_size)
+			l = 256;
+		else
+			l = total_size - i;
+
+		if ((r = spi_nbyte_program(i, &buf[i], l))) {
+			fprintf(stderr, "%s: write fail %d\n", __func__, r);
+			return 1;
+		}
+		
+		while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+			/* loop */;
+	}
+
+	return 0;
+}
diff --git a/libflashrom/board_enable.c b/libflashrom/board_enable.c
new file mode 100644
index 0000000..769b402
--- /dev/null
+++ b/libflashrom/board_enable.c
@@ -0,0 +1,1326 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2005-2007 coresystems GmbH <stepan@coresystems.de>
+ * Copyright (C) 2006 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2007-2009 Luc Verhaegen <libv@skynet.be>
+ * Copyright (C) 2007 Carl-Daniel Hailfinger
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Contains the board specific flash enables.
+ */
+
+#include <string.h>
+#include <fcntl.h>
+#include "flash.h"
+
+/*
+ * Helper functions for many Winbond Super I/Os of the W836xx range.
+ */
+/* Enter extended functions */
+void w836xx_ext_enter(uint16_t port)
+{
+	OUTB(0x87, port);
+	OUTB(0x87, port);
+}
+
+/* Leave extended functions */
+void w836xx_ext_leave(uint16_t port)
+{
+	OUTB(0xAA, port);
+}
+
+/* Generic Super I/O helper functions */
+uint8_t sio_read(uint16_t port, uint8_t reg)
+{
+	OUTB(reg, port);
+	return INB(port + 1);
+}
+
+void sio_write(uint16_t port, uint8_t reg, uint8_t data)
+{
+	OUTB(reg, port);
+	OUTB(data, port + 1);
+}
+
+void sio_mask(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask)
+{
+	uint8_t tmp;
+
+	OUTB(reg, port);
+	tmp = INB(port + 1) & ~mask;
+	OUTB(tmp | (data & mask), port + 1);
+}
+
+/**
+ * Winbond W83627HF: Raise GPIO24.
+ *
+ * Suited for:
+ *  - Agami Aruma
+ *  - IWILL DK8-HTX
+ */
+static int w83627hf_gpio24_raise(uint16_t port, const char *name)
+{
+	w836xx_ext_enter(port);
+
+	/* Is this the W83627HF? */
+	if (sio_read(port, 0x20) != 0x52) {	/* Super I/O device ID reg. */
+		fprintf(stderr, "\nERROR: %s: W83627HF: Wrong ID: 0x%02X.\n",
+			name, sio_read(port, 0x20));
+		w836xx_ext_leave(port);
+		return -1;
+	}
+
+	/* PIN89S: WDTO/GP24 multiplex -> GPIO24 */
+	sio_mask(port, 0x2B, 0x10, 0x10);
+
+	/* Select logical device 8: GPIO port 2 */
+	sio_write(port, 0x07, 0x08);
+
+	sio_mask(port, 0x30, 0x01, 0x01);	/* Activate logical device. */
+	sio_mask(port, 0xF0, 0x00, 0x10);	/* GPIO24 -> output */
+	sio_mask(port, 0xF2, 0x00, 0x10);	/* Clear GPIO24 inversion */
+	sio_mask(port, 0xF1, 0x10, 0x10);	/* Raise GPIO24 */
+
+	w836xx_ext_leave(port);
+
+	return 0;
+}
+
+static int w83627hf_gpio24_raise_2e(const char *name)
+{
+	return w83627hf_gpio24_raise(0x2e, name);
+}
+
+/**
+ * Winbond W83627THF: GPIO 4, bit 4
+ *
+ * Suited for:
+ *  - MSI K8T Neo2-F
+ *  - MSI K8N-NEO3
+ */
+static int w83627thf_gpio4_4_raise(uint16_t port, const char *name)
+{
+	w836xx_ext_enter(port);
+
+	/* Is this the W83627THF? */
+	if (sio_read(port, 0x20) != 0x82) {	/* Super I/O device ID reg. */
+		fprintf(stderr, "\nERROR: %s: W83627THF: Wrong ID: 0x%02X.\n",
+			name, sio_read(port, 0x20));
+		w836xx_ext_leave(port);
+		return -1;
+	}
+
+	/* PINxxxxS: GPIO4/bit 4 multiplex -> GPIOXXX */
+
+	sio_write(port, 0x07, 0x09);      /* Select LDN 9: GPIO port 4 */
+	sio_mask(port, 0x30, 0x02, 0x02); /* Activate logical device. */
+	sio_mask(port, 0xF4, 0x00, 0x10); /* GPIO4 bit 4 -> output */
+	sio_mask(port, 0xF6, 0x00, 0x10); /* Clear GPIO4 bit 4 inversion */
+	sio_mask(port, 0xF5, 0x10, 0x10); /* Raise GPIO4 bit 4 */
+
+	w836xx_ext_leave(port);
+
+	return 0;
+}
+
+static int w83627thf_gpio4_4_raise_2e(const char *name)
+{
+	return w83627thf_gpio4_4_raise(0x2e, name);
+}
+
+static int w83627thf_gpio4_4_raise_4e(const char *name)
+{
+	return w83627thf_gpio4_4_raise(0x4e, name);
+}
+
+/**
+ * w83627: Enable MEMW# and set ROM size to max.
+ */
+static void w836xx_memw_enable(uint16_t port)
+{
+	w836xx_ext_enter(port);
+	if (!(sio_read(port, 0x24) & 0x02)) {	/* Flash ROM enabled? */
+		/* Enable MEMW# and set ROM size select to max. (4M). */
+		sio_mask(port, 0x24, 0x28, 0x28);
+	}
+	w836xx_ext_leave(port);
+}
+
+/**
+ * Common routine for several VT823x based boards.
+ */
+static void vt823x_set_all_writes_to_lpc(struct pci_dev *dev)
+{
+	uint8_t val;
+
+	/* All memory cycles, not just ROM ones, go to LPC. */
+	val = pci_read_byte(dev, 0x59);
+	val &= ~0x80;
+	pci_write_byte(dev, 0x59, val);
+}
+
+/**
+ * VT823x: Set one of the GPIO pins.
+ */
+static void vt823x_gpio_set(struct pci_dev *dev, uint8_t gpio, int raise)
+{
+	uint16_t base;
+	uint8_t val, bit, offset;
+
+	if ((gpio >= 12) && (gpio <= 15)) {
+		/* GPIO12-15 -> output */
+		val = pci_read_byte(dev, 0xE4);
+		val |= 0x10;
+		pci_write_byte(dev, 0xE4, val);
+	} else if (gpio == 9) {
+		/* GPIO9 -> Output */
+		val = pci_read_byte(dev, 0xE4);
+		val |= 0x20;
+		pci_write_byte(dev, 0xE4, val);
+	} else if (gpio == 5) {
+		val = pci_read_byte(dev, 0xE4);
+		val |= 0x01;
+		pci_write_byte(dev, 0xE4, val);
+	} else {
+		fprintf(stderr, "\nERROR: "
+			"VT823x GPIO%02d is not implemented.\n", gpio);
+		return;
+	}
+
+	/* We need the I/O Base Address for this board's flash enable. */
+	base = pci_read_word(dev, 0x88) & 0xff80;
+
+	offset = 0x4C + gpio / 8;
+	bit = 0x01 << (gpio % 8);
+
+	val = INB(base + offset);
+	if (raise)
+		val |= bit;
+	else
+		val &= ~bit;
+	OUTB(val, base + offset);
+}
+
+/**
+ * Suited for VIAs EPIA M and MII, and maybe other CLE266 based EPIAs.
+ *
+ * We don't need to do this when using coreboot, GPIO15 is never lowered there.
+ */
+static int board_via_epia_m(const char *name)
+{
+	struct pci_dev *dev;
+
+	dev = pci_dev_find(0x1106, 0x3177);	/* VT8235 ISA bridge */
+	if (!dev) {
+		fprintf(stderr, "\nERROR: VT8235 ISA bridge not found.\n");
+		return -1;
+	}
+
+	/* GPIO15 is connected to write protect. */
+	vt823x_gpio_set(dev, 15, 1);
+
+	return 0;
+}
+
+/**
+ * Suited for:
+ *   - ASUS A7V8X-MX SE and A7V400-MX: AMD K7 + VIA KM400A + VT8235
+ *   - Tyan S2498 (Tomcat K7M): AMD Geode NX + VIA KM400 + VT8237.
+ */
+static int board_asus_a7v8x_mx(const char *name)
+{
+	struct pci_dev *dev;
+
+	dev = pci_dev_find(0x1106, 0x3177);	/* VT8235 ISA bridge */
+	if (!dev)
+		dev = pci_dev_find(0x1106, 0x3227);	/* VT8237 ISA bridge */
+	if (!dev) {
+		fprintf(stderr, "\nERROR: VT823x ISA bridge not found.\n");
+		return -1;
+	}
+
+	vt823x_set_all_writes_to_lpc(dev);
+	w836xx_memw_enable(0x2E);
+
+	return 0;
+}
+
+/**
+ * Suited for VIAs EPIA SP and EPIA CN.
+ */
+static int board_via_epia_sp(const char *name)
+{
+	struct pci_dev *dev;
+
+	dev = pci_dev_find(0x1106, 0x3227);	/* VT8237R ISA bridge */
+	if (!dev) {
+		fprintf(stderr, "\nERROR: VT8237R ISA bridge not found.\n");
+		return -1;
+	}
+
+	vt823x_set_all_writes_to_lpc(dev);
+
+	return 0;
+}
+
+/**
+ * Suited for VIAs EPIA N & NL.
+ */
+static int board_via_epia_n(const char *name)
+{
+	struct pci_dev *dev;
+
+	dev = pci_dev_find(0x1106, 0x3227);	/* VT8237R ISA bridge */
+	if (!dev) {
+		fprintf(stderr, "\nERROR: VT8237R ISA bridge not found.\n");
+		return -1;
+	}
+
+	/* All memory cycles, not just ROM ones, go to LPC */
+	vt823x_set_all_writes_to_lpc(dev);
+
+	/* GPIO9 -> output */
+	vt823x_gpio_set(dev, 9, 1);
+
+	return 0;
+}
+
+/**
+ * Suited for:
+ *   - EPoX EP-8K5A2: VIA KT333 + VT8235.
+ *   - Albatron PM266A Pro: VIA P4M266A + VT8235.
+ *   - Shuttle AK31 (all versions): VIA KT266 + VT8233.
+ */
+static int w836xx_memw_enable_2e(const char *name)
+{
+	w836xx_memw_enable(0x2E);
+
+	return 0;
+}
+
+/**
+ * Suited for ASUS P5A.
+ *
+ * This is rather nasty code, but there's no way to do this cleanly.
+ * We're basically talking to some unknown device on SMBus, my guess
+ * is that it is the Winbond W83781D that lives near the DIP BIOS.
+ */
+static int board_asus_p5a(const char *name)
+{
+	uint8_t tmp;
+	int i;
+
+#define ASUSP5A_LOOP 5000
+
+	OUTB(0x00, 0xE807);
+	OUTB(0xEF, 0xE803);
+
+	OUTB(0xFF, 0xE800);
+
+	for (i = 0; i < ASUSP5A_LOOP; i++) {
+		OUTB(0xE1, 0xFF);
+		if (INB(0xE800) & 0x04)
+			break;
+	}
+
+	if (i == ASUSP5A_LOOP) {
+		printf("%s: Unable to contact device.\n", name);
+		return -1;
+	}
+
+	OUTB(0x20, 0xE801);
+	OUTB(0x20, 0xE1);
+
+	OUTB(0xFF, 0xE802);
+
+	for (i = 0; i < ASUSP5A_LOOP; i++) {
+		tmp = INB(0xE800);
+		if (tmp & 0x70)
+			break;
+	}
+
+	if ((i == ASUSP5A_LOOP) || !(tmp & 0x10)) {
+		printf("%s: failed to read device.\n", name);
+		return -1;
+	}
+
+	tmp = INB(0xE804);
+	tmp &= ~0x02;
+
+	OUTB(0x00, 0xE807);
+	OUTB(0xEE, 0xE803);
+
+	OUTB(tmp, 0xE804);
+
+	OUTB(0xFF, 0xE800);
+	OUTB(0xE1, 0xFF);
+
+	OUTB(0x20, 0xE801);
+	OUTB(0x20, 0xE1);
+
+	OUTB(0xFF, 0xE802);
+
+	for (i = 0; i < ASUSP5A_LOOP; i++) {
+		tmp = INB(0xE800);
+		if (tmp & 0x70)
+			break;
+	}
+
+	if ((i == ASUSP5A_LOOP) || !(tmp & 0x10)) {
+		printf("%s: failed to write to device.\n", name);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Set GPIO lines in the Broadcom HT-1000 southbridge.
+ *
+ *  It's not a Super I/O but it uses the same index/data port method.
+ */
+static int board_hp_dl145_g3_enable(const char *name)
+{
+	/* GPIO 0 reg from PM regs */
+	/* Set GPIO 2 and 5 high, connected to flash WP# and TBL# pins. */
+	sio_mask(0xcd6, 0x44, 0x24, 0x24);
+
+	return 0;
+}
+
+static int board_ibm_x3455(const char *name)
+{
+	/* raise gpio13 */
+	sio_mask(0xcd6, 0x45, 0x20, 0x20);
+
+	return 0;
+}
+
+/**
+ * Suited for Shuttle FN25 (SN25P): AMD S939 + Nvidia CK804 (nForce4).
+ */
+static int board_shuttle_fn25(const char *name)
+{
+	struct pci_dev *dev;
+
+	dev = pci_dev_find(0x10DE, 0x0050);	/* NVIDIA CK804 ISA Bridge. */
+	if (!dev) {
+		fprintf(stderr,
+			"\nERROR: NVIDIA nForce4 ISA bridge not found.\n");
+		return -1;
+	}
+
+	/* one of those bits seems to be connected to TBL#, but -ENOINFO. */
+	pci_write_byte(dev, 0x92, 0);
+
+	return 0;
+}
+
+/**
+ * Very similar to AMD 8111 IO Hub.
+ */
+static int nvidia_mcp_gpio_set(int gpio, int raise)
+{
+	struct pci_dev *dev;
+	uint16_t base;
+	uint8_t tmp;
+
+	if ((gpio < 0) || (gpio > 31)) {
+		fprintf(stderr, "\nERROR: unsupported GPIO: %d.\n", gpio);
+		return -1;
+	}
+
+	dev = pci_dev_find_vendorclass(0x10DE, 0x0C05);
+	switch (dev->device_id) {
+	case 0x0030: /* CK804 */
+	case 0x0050: /* MCP04 */
+	case 0x0060: /* MCP2 */
+		break;
+	default:
+		fprintf(stderr, "\nERROR: no nVidia SMBus controller found.\n");
+		return -1;
+	}
+
+	base = pci_read_long(dev, 0x64) & 0x0000FF00; /* System control area */
+	base += 0xC0;
+
+	tmp = INB(base + gpio);
+	tmp &= ~0x0F; /* null lower nibble */
+	tmp |= 0x04; /* gpio -> output. */
+	if (raise)
+		tmp |= 0x01;
+	OUTB(tmp, base + gpio);
+
+	return 0;
+}
+
+/**
+ * Suited for ASUS P5ND2-SLI Deluxe: LGA775 + nForce4 SLI + MCP04.
+ */
+static int nvidia_mcp_gpio10_raise(const char *name)
+{
+	return nvidia_mcp_gpio_set(0x10, 1);
+}
+
+/**
+ * Suited for the Gigabyte GA-K8N-SLI: CK804 southbridge.
+ */
+static int nvidia_mcp_gpio21_raise(const char *name)
+{
+	return nvidia_mcp_gpio_set(0x21, 0x01);
+}
+
+/**
+ * Suited for EPoX EP-8RDA3+: Socket A + nForce2 Ultra 400 + MCP2.
+ */
+static int nvidia_mcp_gpio31_raise(const char *name)
+{
+	return nvidia_mcp_gpio_set(0x31, 0x01);
+}
+
+/**
+ * Suited for EPoX EP-BX3, and maybe some other Intel 440BX based boards.
+ */
+static int board_epox_ep_bx3(const char *name)
+{
+	uint8_t tmp;
+
+	/* Raise GPIO22. */
+	tmp = INB(0x4036);
+	OUTB(tmp, 0xEB);
+
+	tmp |= 0x40;
+
+	OUTB(tmp, 0x4036);
+	OUTB(tmp, 0xEB);
+
+	return 0;
+}
+
+/**
+ * Suited for Artec Group DBE61 and DBE62.
+ */
+static int board_artecgroup_dbe6x(const char *name)
+{
+#define DBE6x_MSR_DIVIL_BALL_OPTS	0x51400015
+#define DBE6x_PRI_BOOT_LOC_SHIFT	(2)
+#define DBE6x_BOOT_OP_LATCHED_SHIFT	(8)
+#define DBE6x_SEC_BOOT_LOC_SHIFT	(10)
+#define DBE6x_PRI_BOOT_LOC		(3 << DBE6x_PRI_BOOT_LOC_SHIFT)
+#define DBE6x_BOOT_OP_LATCHED		(3 << DBE6x_BOOT_OP_LATCHED_SHIFT)
+#define DBE6x_SEC_BOOT_LOC		(3 << DBE6x_SEC_BOOT_LOC_SHIFT)
+#define DBE6x_BOOT_LOC_FLASH		(2)
+#define DBE6x_BOOT_LOC_FWHUB		(3)
+
+	msr_t msr;
+	unsigned long boot_loc;
+
+	/* Geode only has a single core */
+	if (setup_cpu_msr(0))
+		return -1;
+
+	msr = rdmsr(DBE6x_MSR_DIVIL_BALL_OPTS);
+
+	if ((msr.lo & (DBE6x_BOOT_OP_LATCHED)) ==
+	    (DBE6x_BOOT_LOC_FWHUB << DBE6x_BOOT_OP_LATCHED_SHIFT))
+		boot_loc = DBE6x_BOOT_LOC_FWHUB;
+	else
+		boot_loc = DBE6x_BOOT_LOC_FLASH;
+
+	msr.lo &= ~(DBE6x_PRI_BOOT_LOC | DBE6x_SEC_BOOT_LOC);
+	msr.lo |= ((boot_loc << DBE6x_PRI_BOOT_LOC_SHIFT) |
+		   (boot_loc << DBE6x_SEC_BOOT_LOC_SHIFT));
+
+	wrmsr(DBE6x_MSR_DIVIL_BALL_OPTS, msr);
+
+	cleanup_cpu_msr();
+
+	return 0;
+}
+
+/**
+ * Set a GPIO line on a given intel ICH LPC controller.
+ */
+static int intel_ich_gpio_set(int gpio, int raise)
+{
+	/* table mapping the different intel ICH LPC chipsets. */
+	static struct {
+		uint16_t id;
+		uint8_t base_reg;
+		uint32_t bank0;
+		uint32_t bank1;
+		uint32_t bank2;
+	} intel_ich_gpio_table[] = {
+		{0x2410, 0x58, 0x0FE30000,          0,          0}, /* 82801AA (ICH) */
+		{0x2420, 0x58, 0x0FE30000,          0,          0}, /* 82801AB (ICH0) */
+		{0x2440, 0x58, 0x1BFF391B,          0,          0}, /* 82801BA (ICH2) */
+		{0x244C, 0x58, 0x1A23399B,          0,          0}, /* 82801BAM (ICH2M) */
+		{0x2450, 0x58, 0x1BFF0000,          0,          0}, /* 82801E (C-ICH) */
+		{0x2480, 0x58, 0x1BFF0000, 0x00000FFF,          0}, /* 82801CA (ICH3-S) */
+		{0x248C, 0x58, 0x1A230000, 0x00000FFF,          0}, /* 82801CAM (ICH3-M) */
+		{0x24C0, 0x58, 0x1BFF0000, 0x00000FFF,          0}, /* 82801DB/DBL (ICH4/ICH4-L) */
+		{0x24CC, 0x58, 0x1A030000, 0x00000FFF,          0}, /* 82801DBM (ICH4-M) */
+		{0x24D0, 0x58, 0x1BFF0000, 0x00030305,          0}, /* 82801EB/ER (ICH5/ICH5R) */
+		{0x2640, 0x48, 0x1BFF0000, 0x00030307,          0}, /* 82801FB/FR (ICH6/ICH6R) */
+		{0x2641, 0x48, 0x1BFF0000, 0x00030307,          0}, /* 82801FBM (ICH6M) */
+		{0x27B8, 0x48, 0xFFFFFFFF, 0x000300FF,          0}, /* 82801GB/GR (ICH7 Family) */
+		{0x27B9, 0x48, 0xFFEBFFFE, 0x000300FE,          0}, /* 82801GBM (ICH7-M) */
+		{0x27BD, 0x48, 0xFFEBFFFE, 0x000300FE,          0}, /* 82801GHM (ICH7-M DH) */
+		{0x2810, 0x48, 0xFFFFFFFF, 0x00FF0FFF,          0}, /* 82801HB/HR (ICH8/R) */
+		{0x2811, 0x48, 0xFFFFFFFF, 0x00FF0FFF,          0}, /* 82801HBM (ICH8M-E) */
+		{0x2812, 0x48, 0xFFFFFFFF, 0x00FF0FFF,          0}, /* 82801HH (ICH8DH) */
+		{0x2814, 0x48, 0xFFFFFFFF, 0x00FF0FFF,          0}, /* 82801HO (ICH8DO) */
+		{0x2815, 0x48, 0xFFFFFFFF, 0x00FF0FFF,          0}, /* 82801HEM (ICH8M) */
+		{0x2912, 0x48, 0xFFFFFFFF, 0x00FFFFFF,          0}, /* 82801IH (ICH9DH) */
+		{0x2914, 0x48, 0xFFFFFFFF, 0x00FFFFFF,          0}, /* 82801IO (ICH9DO) */
+		{0x2916, 0x48, 0xFFFFFFFF, 0x00FFFFFF,          0}, /* 82801IR (ICH9R) */
+		{0x2917, 0x48, 0xFFFFFFFF, 0x00FFFFFF,          0}, /* 82801IEM (ICH9M-E) */
+		{0x2918, 0x48, 0xFFFFFFFF, 0x00FFFFFF,          0}, /* 82801IB (ICH9) */
+		{0x2919, 0x48, 0xFFFFFFFF, 0x00FFFFFF,          0}, /* 82801IBM (ICH9M) */
+		{0x3A14, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JDO (ICH10DO) */
+		{0x3A16, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JIR (ICH10R) */
+		{0x3A18, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JIB (ICH10) */
+		{0x3A1A, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JD (ICH10D) */
+		{0, 0, 0, 0, 0} /* end marker */
+	};
+
+	struct pci_dev *dev;
+	uint16_t base;
+	uint32_t tmp;
+	int i, allowed;
+
+	/* First, look for a known LPC bridge */
+	for (dev = pacc->devices; dev; dev = dev->next)
+		if ((dev->vendor_id == 0x8086) &&
+		    (dev->device_class == 0x0601)) { /* ISA Bridge */
+			/* Is this device in our list? */
+			for (i = 0; intel_ich_gpio_table[i].id; i++)
+				if (dev->device_id == intel_ich_gpio_table[i].id)
+					break;
+
+			if (intel_ich_gpio_table[i].id)
+				break;
+		}
+
+	if (!dev) {
+		fprintf(stderr, "\nERROR: No Known Intel LPC Bridge found.\n");
+		return -1;
+	}
+
+	/* According to the datasheets, all intel ICHs have the gpio bar 5:1
+	   strapped to zero. From some mobile ich9 version on, this becomes
+	   6:1. The mask below catches all. */
+	base = pci_read_word(dev, intel_ich_gpio_table[i].base_reg) & 0xFFC0;
+
+	/* check whether the line is allowed */
+	if (gpio < 32)
+		allowed = (intel_ich_gpio_table[i].bank0 >> gpio) & 0x01;
+	else if (gpio < 64)
+		allowed = (intel_ich_gpio_table[i].bank1 >> (gpio - 32)) & 0x01;
+	else
+		allowed = (intel_ich_gpio_table[i].bank2 >> (gpio - 64)) & 0x01;
+
+	if (!allowed) {
+		fprintf(stderr, "\nERROR: This Intel LPC Bridge does not allow"
+			" setting GPIO%02d\n", gpio);
+		return -1;
+	}
+
+	printf("\nIntel ICH LPC Bridge: %sing GPIO%02d.\n",
+	       raise ? "Rais" : "Dropp", gpio);
+
+	if (gpio < 32) {
+		/* Set line to GPIO */
+		tmp = INL(base);
+		/* ICH/ICH0 multiplexes 27/28 on the line set. */
+		if ((gpio == 28) &&
+		    ((dev->device_id == 0x2410) || (dev->device_id == 0x2420)))
+			tmp |= 1 << 27;
+		else
+			tmp |= 1 << gpio;
+		OUTL(tmp, base);
+
+		/* As soon as we are talking to ICH8 and above, this register
+		   decides whether we can set the gpio or not. */
+		if (dev->device_id > 0x2800) {
+			tmp = INL(base);
+			if (!(tmp & (1 << gpio))) {
+				fprintf(stderr, "\nERROR: This Intel LPC Bridge"
+					" does not allow setting GPIO%02d\n",
+					gpio);
+				return -1;
+			}
+		}
+
+		/* Set GPIO to OUTPUT */
+		tmp = INL(base + 0x04);
+		tmp &= ~(1 << gpio);
+		OUTL(tmp, base + 0x04);
+
+		/* Raise GPIO line */
+		tmp = INL(base + 0x0C);
+		if (raise)
+			tmp |= 1 << gpio;
+		else
+			tmp &= ~(1 << gpio);
+		OUTL(tmp, base + 0x0C);
+	} else if (gpio < 64) {
+		gpio -= 32;
+
+		/* Set line to GPIO */
+		tmp = INL(base + 0x30);
+		tmp |= 1 << gpio;
+		OUTL(tmp, base + 0x30);
+
+		/* As soon as we are talking to ICH8 and above, this register
+		   decides whether we can set the gpio or not. */
+		if (dev->device_id > 0x2800) {
+			tmp = INL(base + 30);
+			if (!(tmp & (1 << gpio))) {
+				fprintf(stderr, "\nERROR: This Intel LPC Bridge"
+					" does not allow setting GPIO%02d\n",
+					gpio + 32);
+				return -1;
+			}
+		}
+
+		/* Set GPIO to OUTPUT */
+		tmp = INL(base + 0x34);
+		tmp &= ~(1 << gpio);
+		OUTL(tmp, base + 0x34);
+
+		/* Raise GPIO line */
+		tmp = INL(base + 0x38);
+		if (raise)
+			tmp |= 1 << gpio;
+		else
+			tmp &= ~(1 << gpio);
+		OUTL(tmp, base + 0x38);
+	} else {
+		gpio -= 64;
+
+		/* Set line to GPIO */
+		tmp = INL(base + 0x40);
+		tmp |= 1 << gpio;
+		OUTL(tmp, base + 0x40);
+
+		tmp = INL(base + 40);
+		if (!(tmp & (1 << gpio))) {
+			fprintf(stderr, "\nERROR: This Intel LPC Bridge does "
+				"not allow setting GPIO%02d\n", gpio + 64);
+			return -1;
+		}
+
+		/* Set GPIO to OUTPUT */
+		tmp = INL(base + 0x44);
+		tmp &= ~(1 << gpio);
+		OUTL(tmp, base + 0x44);
+
+		/* Raise GPIO line */
+		tmp = INL(base + 0x48);
+		if (raise)
+			tmp |= 1 << gpio;
+		else
+			tmp &= ~(1 << gpio);
+		OUTL(tmp, base + 0x48);
+	}
+
+	return 0;
+}
+
+/**
+ * Suited for Abit IP35: Intel P35 + ICH9R.
+ */
+static int intel_ich_gpio16_raise(const char *name)
+{
+	return intel_ich_gpio_set(16, 1);
+}
+
+/**
+ * Suited for MSI MS-7046: LGA775 + 915P + ICH6.
+ */
+static int intel_ich_gpio19_raise(const char *name)
+{
+	return intel_ich_gpio_set(19, 1);
+}
+
+/**
+ * Suited for:
+ * - Asus P4B266LM (Sony Vaio PCV-RX650): socket478 + 845D + ICH2.
+ * - Asus P4P800-E Deluxe: Intel socket478 + 865PE + ICH5R.
+ */
+static int intel_ich_gpio21_raise(const char *name)
+{
+	return intel_ich_gpio_set(21, 1);
+}
+
+/**
+ * Suited for ASUS P4B266: socket478 + intel 845D + ICH2.
+ */
+static int intel_ich_gpio22_raise(const char *name)
+{
+	return intel_ich_gpio_set(22, 1);
+}
+
+/**
+ * Suited for:
+ * - Dell Poweredge 1850: Intel PPGA604 + E7520 + ICH5R.
+ * - ASRock P4i65GV: Intel Socket478 + 865GV + ICH5R.
+ */
+static int intel_ich_gpio23_raise(const char *name)
+{
+	return intel_ich_gpio_set(23, 1);
+}
+
+/**
+ * Suited for Acorp 6A815EPD: socket 370 + intel 815 + ICH2.
+ */
+static int board_acorp_6a815epd(const char *name)
+{
+	int ret;
+
+	/* Lower Blocks Lock -- pin 7 of PLCC32 */
+	ret = intel_ich_gpio_set(22, 1);
+	if (!ret) /* Top Block Lock -- pin 8 of PLCC32 */
+		ret = intel_ich_gpio_set(23, 1);
+
+	return ret;
+}
+
+/**
+ * Suited for Kontron 986LCD-M: socket478 + 915GM + ICH7R.
+ */
+static int board_kontron_986lcd_m(const char *name)
+{
+	int ret;
+
+	ret = intel_ich_gpio_set(34, 1); /* #TBL */
+	if (!ret)
+		ret = intel_ich_gpio_set(35, 1); /* #WP */
+
+	return ret;
+}
+
+/**
+ * Suited for:
+ *   - Biostar P4M80-M4: VIA P4M800 + VT8237 + IT8705AF
+ *   - GIGABYTE GA-7VT600: VIA KT600 + VT8237 + IT8705
+ *
+ * SIS950 superio probably requires the same flash write enable.
+ */
+static int it8705_rom_write_enable(const char *name)
+{
+	/* enter IT87xx conf mode */
+	enter_conf_mode_ite(0x2e);
+
+	/* select right flash chip */
+	sio_mask(0x2e, 0x22, 0x80, 0x80);
+
+	/* bit 3: flash chip write enable
+	 * bit 7: map flash chip at 1MB-128K (why though? ignoring this.)
+	 */
+	sio_mask(0x2e, 0x24, 0x04, 0x04);
+
+	/* exit IT87xx conf mode */
+	exit_conf_mode_ite(0x2e);
+
+	return 0;
+}
+
+/**
+ * Suited for AOpen vKM400Am-S: VIA KM400 + VT8237 + IT8705F.
+ */
+static int board_aopen_vkm400(const char *name)
+{
+	struct pci_dev *dev;
+
+	dev = pci_dev_find(0x1106, 0x3227);	/* VT8237 ISA bridge */
+	if (!dev) {
+		fprintf(stderr, "\nERROR: VT8237 ISA bridge not found.\n");
+		return -1;
+	}
+
+	vt823x_set_all_writes_to_lpc(dev);
+
+	return it8705_rom_write_enable(name);
+}
+
+/**
+ * Winbond W83697HF Super I/O + VIA VT8235 southbridge
+ *
+ * Suited for:
+ *   - MSI KT4V and KT4V-L: AMD K7 + VIA KT400 + VT8235
+ *   - MSI KT4 Ultra: AMD K7 + VIA KT400 + VT8235
+ */
+static int board_msi_kt4v(const char *name)
+{
+	struct pci_dev *dev;
+
+	dev = pci_dev_find(0x1106, 0x3177);	/* VT8235 ISA bridge */
+	if (!dev) {
+		fprintf(stderr, "\nERROR: VT823x ISA bridge not found.\n");
+		return -1;
+	}
+
+	vt823x_set_all_writes_to_lpc(dev);
+
+	vt823x_gpio_set(dev, 12, 1);
+	w836xx_memw_enable(0x2E);
+
+	return 0;
+}
+
+/**
+ * Suited for Soyo SY-7VCA: Pro133A + VT82C686.
+ */
+static int board_soyo_sy_7vca(const char *name)
+{
+    	struct pci_dev *dev;
+	uint32_t base;
+	uint8_t tmp;
+
+	/* VT82C686 Power management */
+	dev = pci_dev_find(0x1106, 0x3057);
+	if (!dev) {
+		fprintf(stderr, "\nERROR: VT82C686 PM device not found.\n");
+		return -1;
+	}
+
+	/* GPO0 output from PM IO base + 0x4C */
+	tmp = pci_read_byte(dev, 0x54);
+	tmp &= ~0x03;
+	pci_write_byte(dev, 0x54, tmp);
+
+	/* PM IO base */
+	base = pci_read_long(dev, 0x48) & 0x0000FF00;
+
+	/* Drop GPO0 */
+	tmp = INB(base + 0x4C);
+	tmp &= ~0x01;
+	OUTB(tmp, base + 0x4C);
+
+	return 0;
+}
+
+static int it8705f_write_enable(uint8_t port, const char *name)
+{
+	enter_conf_mode_ite(port);
+	sio_mask(port, 0x24, 0x04, 0x04); /* Flash ROM I/F Writes Enable */
+	exit_conf_mode_ite(port);
+
+	return 0;
+}
+
+/**
+ * Suited for:
+ *   - Shuttle AK38N: VIA KT333CF + VIA VT8235 + ITE IT8705F
+ *   - Elitegroup K7VTA3: VIA Apollo KT266/A/333 + VIA VT8235 + ITE IT8705F
+ */
+static int it8705f_write_enable_2e(const char *name)
+{
+	return it8705f_write_enable(0x2e, name);
+}
+
+/**
+ * Find the runtime registers of an SMSC Super I/O, after verifying its
+ * chip ID.
+ *
+ * Returns the base port of the runtime register block, or 0 on error.
+ */
+static uint16_t smsc_find_runtime(uint16_t sio_port, uint16_t chip_id,
+                                  uint8_t logical_device)
+{
+	uint16_t rt_port = 0;
+
+	/* Verify the chip ID. */
+	OUTB(0x55, sio_port);  /* Enable configuration. */
+	if (sio_read(sio_port, 0x20) != chip_id) {
+		fprintf(stderr, "\nERROR: SMSC Super I/O not found.\n");
+		goto out;
+	}
+
+	/* If the runtime block is active, get its address. */
+	sio_write(sio_port, 0x07, logical_device);
+	if (sio_read(sio_port, 0x30) & 1) {
+		rt_port = (sio_read(sio_port, 0x60) << 8)
+		          | sio_read(sio_port, 0x61);
+	}
+
+	if (rt_port == 0) {
+		fprintf(stderr, "\nERROR: "
+			"Super I/O runtime interface not available.\n");
+	}
+out:
+	OUTB(0xaa, sio_port);  /* Disable configuration. */
+	return rt_port;
+}
+
+/**
+ * Disable write protection on the Mitac 6513WU.  WP# on the FWH is
+ * connected to GP30 on the Super I/O, and TBL# is always high.
+ */
+static int board_mitac_6513wu(const char *name)
+{
+	struct pci_dev *dev;
+	uint16_t rt_port;
+	uint8_t val;
+
+	dev = pci_dev_find(0x8086, 0x2410);	/* Intel 82801AA ISA bridge */
+	if (!dev) {
+		fprintf(stderr, "\nERROR: Intel 82801AA ISA bridge not found.\n");
+		return -1;
+	}
+
+	rt_port = smsc_find_runtime(0x4e, 0x54 /* LPC47U33x */, 0xa);
+	if (rt_port == 0)
+		return -1;
+
+	/* Configure the GPIO pin. */
+	val = INB(rt_port + 0x33);  /* GP30 config */
+	val &= ~0x87;               /* Output, non-inverted, GPIO, push/pull */
+	OUTB(val, rt_port + 0x33);
+
+	/* Disable write protection. */
+	val = INB(rt_port + 0x4d);  /* GP3 values */
+	val |= 0x01;                /* Set GP30 high. */
+	OUTB(val, rt_port + 0x4d);
+
+	return 0;
+}
+
+/**
+ * Suited for Asus A7V8X: VIA KT400 + VT8235 + IT8703F-A
+ */
+static int board_asus_a7v8x(const char *name)
+{
+	uint16_t id, base;
+	uint8_t tmp;
+
+	/* find the IT8703F */
+	w836xx_ext_enter(0x2E);
+	id = (sio_read(0x2E, 0x20) << 8) | sio_read(0x2E, 0x21);
+	w836xx_ext_leave(0x2E);
+
+	if (id != 0x8701) {
+		fprintf(stderr, "\nERROR: IT8703F SuperIO not found.\n");
+		return -1;
+	}
+
+	/* Get the GP567 IO base */
+	w836xx_ext_enter(0x2E);
+	sio_write(0x2E, 0x07, 0x0C);
+	base = (sio_read(0x2E, 0x60) << 8) | sio_read(0x2E, 0x61);
+	w836xx_ext_leave(0x2E);
+
+	if (!base) {
+		fprintf(stderr, "\nERROR: Failed to read IT8703F SuperIO GPIO"
+			" Base.\n");
+		return -1;
+	}
+
+	/* Raise GP51. */
+	tmp = INB(base);
+	tmp |= 0x02;
+	OUTB(tmp, base);
+
+	return 0;
+}
+
+/*
+ * General routine for raising/dropping GPIO lines on the ITE IT8712F.
+ * There is only some limited checking on the port numbers.
+ */
+static int
+it8712f_gpio_set(unsigned int line, int raise)
+{
+	unsigned int port;
+	uint16_t id, base;
+	uint8_t tmp;
+
+	port = line / 10;
+	port--;
+	line %= 10;
+
+	/* Check line */
+	if ((port > 4) || /* also catches unsigned -1 */
+	    ((port < 4) && (line > 7)) || ((port == 4) && (line > 5))) {
+	    fprintf(stderr,
+		    "\nERROR: Unsupported IT8712F GPIO Line %02d.\n", line);
+	    return -1;
+	}
+
+	/* find the IT8712F */
+	enter_conf_mode_ite(0x2E);
+	id = (sio_read(0x2E, 0x20) << 8) | sio_read(0x2E, 0x21);
+	exit_conf_mode_ite(0x2E);
+
+	if (id != 0x8712) {
+		fprintf(stderr, "\nERROR: IT8712F SuperIO not found.\n");
+		return -1;
+	}
+
+	/* Get the GPIO base */
+	enter_conf_mode_ite(0x2E);
+	sio_write(0x2E, 0x07, 0x07);
+	base = (sio_read(0x2E, 0x62) << 8) | sio_read(0x2E, 0x63);
+	exit_conf_mode_ite(0x2E);
+
+	if (!base) {
+		fprintf(stderr, "\nERROR: Failed to read IT8712F SuperIO GPIO"
+			" Base.\n");
+		return -1;
+	}
+
+	/* set GPIO. */
+	tmp = INB(base + port);
+	if (raise)
+	    tmp |= 1 << line;
+	else
+	    tmp &= ~(1 << line);
+	OUTB(tmp, base + port);
+
+	return 0;
+}
+
+/**
+ * Suited for Asus A7V600-X: VIA KT600 + VT8237 + IT8712F
+ */
+static int board_asus_a7v600x(const char *name)
+{
+	return it8712f_gpio_set(32, 1);
+}
+
+/**
+ * Suited for Asus M2V-MX: VIA K8M890 + VT8237A + IT8716F
+ */
+static int board_asus_m2v_mx(const char *name)
+{
+	struct pci_dev *dev;
+
+	dev = pci_dev_find(0x1106, 0x3337);	/* VT8237A ISA bridge */
+	if (!dev) {
+		fprintf(stderr, "\nERROR: VT8237A ISA bridge not found.\n");
+		return -1;
+	}
+
+	/* GPO5 is connected to WP# and TBL#. */
+	vt823x_gpio_set(dev, 5, 1);
+
+	return 0;
+}
+
+
+/**
+ * Below is the list of boards which need a special "board enable" code in
+ * flashrom before their ROM chip can be accessed/written to.
+ *
+ * NOTE: Please add boards that _don't_ need such enables or don't work yet
+ *       to the respective tables in print.c. Thanks!
+ *
+ * We use 2 sets of IDs here, you're free to choose which is which. This
+ * is to provide a very high degree of certainty when matching a board on
+ * the basis of subsystem/card IDs. As not every vendor handles
+ * subsystem/card IDs in a sane manner.
+ *
+ * Keep the second set NULLed if it should be ignored. Keep the subsystem IDs
+ * NULLed if they don't identify the board fully. But please take care to
+ * provide an as complete set of pci ids as possible; autodetection is the
+ * preferred behaviour and we would like to make sure that matches are unique.
+ *
+ * The coreboot ids are used two fold. When running with a coreboot firmware,
+ * the ids uniquely matches the coreboot board identification string. When a
+ * legacy bios is installed and when autodetection is not possible, these ids
+ * can be used to identify the board through the -m command line argument.
+ *
+ * When a board is identified through its coreboot ids (in both cases), the
+ * main pci ids are still required to match, as a safeguard.
+ */
+
+/* Please keep this list alphabetically ordered by vendor/board name. */
+struct board_pciid_enable board_pciid_enables[] = {
+	/* first pci-id set [4],          second pci-id set [4],          coreboot id [2],             vendor name    board name            flash enable */
+	{0x8086, 0x2926, 0x147b, 0x1084,  0x11ab, 0x4364, 0x147b, 0x1084, NULL,         NULL,          "Abit",        "IP35",               intel_ich_gpio16_raise},
+	{0x105a, 0x0d30, 0x105a, 0x4d33,  0x8086, 0x1130, 0x8086,      0, NULL,         NULL,          "Acorp",       "6A815EPD",           board_acorp_6a815epd},
+	{0x8086, 0x24D4, 0x1849, 0x24D0,  0x8086, 0x24D5, 0x1849, 0x9739, NULL,         NULL,          "ASRock",      "P4i65GV",            intel_ich_gpio23_raise},
+	{0x1022, 0x746B,      0,      0,       0,      0,      0,      0, "AGAMI",      "ARUMA",       "agami",       "Aruma",              w83627hf_gpio24_raise_2e},
+	{0x1106, 0x3177, 0x17F2, 0x3177,  0x1106, 0x3148, 0x17F2, 0x3148, NULL,         NULL,          "Albatron",    "PM266A",             w836xx_memw_enable_2e},
+	{0x1106, 0x3205, 0x1106, 0x3205,  0x10EC, 0x8139, 0xA0A0, 0x0477, NULL,         NULL,          "AOpen",       "vKM400Am-S",         board_aopen_vkm400},
+	{0x1022, 0x2090,      0,      0,  0x1022, 0x2080,      0,      0, "artecgroup", "dbe61",       "Artec Group", "DBE61",              board_artecgroup_dbe6x},
+	{0x1022, 0x2090,      0,      0,  0x1022, 0x2080,      0,      0, "artecgroup", "dbe62",       "Artec Group", "DBE62",              board_artecgroup_dbe6x},
+	{0x1106, 0x3189, 0x1043, 0x807F,  0x1106, 0x3065, 0x1043, 0x80ED, NULL,         NULL,          "ASUS",        "A7V600-X",           board_asus_a7v600x},
+	{0x1106, 0x3189, 0x1043, 0x807F,  0x1106, 0x3177, 0x1043, 0x808C, NULL,         NULL,          "ASUS",        "A7V8X",              board_asus_a7v8x},
+	{0x1106, 0x3177, 0x1043, 0x80A1,  0x1106, 0x3205, 0x1043, 0x8118, NULL,         NULL,          "ASUS",        "A7V8X-MX SE",        board_asus_a7v8x_mx},
+	{0x1106, 0x1336, 0x1043, 0x80ed,  0x1106, 0x3288, 0x1043, 0x8249, NULL,         NULL,          "ASUS",        "M2V-MX",             board_asus_m2v_mx},
+	{0x8086, 0x1a30, 0x1043, 0x8070,  0x8086, 0x244b, 0x1043, 0x8028, NULL,         NULL,          "ASUS",        "P4B266",             intel_ich_gpio22_raise},
+	{0x8086, 0x1A30, 0x1043, 0x8025,  0x8086, 0x244B, 0x104D, 0x80F0, NULL,         NULL,          "ASUS",        "P4B266-LM",          intel_ich_gpio21_raise},
+	{0x8086, 0x2570, 0x1043, 0x80F2,  0x105A, 0x3373, 0x1043, 0x80F5, NULL,         NULL,          "ASUS",        "P4P800-E Deluxe",    intel_ich_gpio21_raise},
+	{0x10B9, 0x1541,      0,      0,  0x10B9, 0x1533,      0,      0, "asus",       "p5a",         "ASUS",        "P5A",                board_asus_p5a},
+	{0x10DE, 0x0030, 0x1043, 0x818a,  0x8086, 0x100E, 0x1043, 0x80EE, NULL,         NULL,          "ASUS",        "P5ND2-SLI Deluxe",   nvidia_mcp_gpio10_raise},
+	{0x1106, 0x3149, 0x1565, 0x3206,  0x1106, 0x3344, 0x1565, 0x1202, NULL,         NULL,          "Biostar",     "P4M80-M4",           it8705_rom_write_enable},
+	{0x8086, 0x3590, 0x1028, 0x016c,  0x1000, 0x0030, 0x1028, 0x016c, NULL,         NULL,          "Dell",        "PowerEdge 1850",     intel_ich_gpio23_raise},
+	{0x1106, 0x3038, 0x1019, 0x0996,  0x1106, 0x3177, 0x1019, 0x0996, NULL,         NULL,          "Elitegroup",  "K7VTA3",             it8705f_write_enable_2e},
+	{0x1106, 0x3177, 0x1106, 0x3177,  0x1106, 0x3059, 0x1695, 0x3005, NULL,         NULL,          "EPoX",        "EP-8K5A2",           w836xx_memw_enable_2e},
+	{0x10EC, 0x8139, 0x1695, 0x9001,  0x11C1, 0x5811, 0x1695, 0x9015, NULL,         NULL,          "EPoX",        "EP-8RDA3+",          nvidia_mcp_gpio31_raise},
+	{0x8086, 0x7110,      0,      0,  0x8086, 0x7190,      0,      0, "epox",       "ep-bx3",      "EPoX",        "EP-BX3",             board_epox_ep_bx3},
+	{0x1039, 0x0761,      0,      0,  0x10EC, 0x8168,      0,      0, "gigabyte",   "2761gxdk",    "GIGABYTE",    "GA-2761GXDK",        it87xx_probe_spi_flash},
+	{0x1106, 0x3227, 0x1458, 0x5001,  0x10ec, 0x8139, 0x1458, 0xe000, NULL,         NULL,          "GIGABYTE",    "GA-7VT600",          it8705_rom_write_enable},
+	{0x10DE, 0x0050, 0x1458, 0x0C11,  0x10DE, 0x005e, 0x1458, 0x5000, NULL,         NULL,          "GIGABYTE",    "GA-K8N-SLI",         nvidia_mcp_gpio21_raise},
+	{0x10DE, 0x0360, 0x1458, 0x0C11,  0x10DE, 0x0369, 0x1458, 0x5001, "gigabyte",   "m57sli",      "GIGABYTE",    "GA-M57SLI-S4",       it87xx_probe_spi_flash},
+	{0x10de, 0x03e0,      0,      0,  0x10DE, 0x03D0,      0,      0, NULL,         NULL,          "GIGABYTE",    "GA-M61P-S3",         it87xx_probe_spi_flash},
+	{0x1002, 0x4398, 0x1458, 0x5004,  0x1002, 0x4391, 0x1458, 0xb000, NULL,         NULL,          "GIGABYTE",    "GA-MA78G-DS3H",      it87xx_probe_spi_flash},
+	{0x1002, 0x4398, 0x1458, 0x5004,  0x1002, 0x4391, 0x1458, 0xb002, NULL,         NULL,          "GIGABYTE",    "GA-MA78GM-S2H",      it87xx_probe_spi_flash},
+	{0x1002, 0x438d, 0x1458, 0x5001,  0x1002, 0x5956, 0x1002, 0x5956, NULL,         NULL,          "GIGABYTE",    "GA-MA790FX-DQ6",     it87xx_probe_spi_flash},
+	{0x1166, 0x0223, 0x103c, 0x320d,  0x102b, 0x0522, 0x103c, 0x31fa, "hp",         "dl145_g3",    "HP",          "DL145 G3",           board_hp_dl145_g3_enable},
+	{0x1166, 0x0205, 0x1014, 0x0347,  0x1002, 0x515E, 0x1014, 0x0325, NULL,         NULL,          "IBM",         "x3455",              board_ibm_x3455},
+	{0x1039, 0x5513, 0x8086, 0xd61f,  0x1039, 0x6330, 0x8086, 0xd61f, NULL,         NULL,          "Intel",       "D201GLY",            wbsio_check_for_spi},
+	{0x1022, 0x7468,      0,      0,       0,      0,      0,      0, "iwill",      "dk8_htx",     "IWILL",       "DK8-HTX",            w83627hf_gpio24_raise_2e},
+	{0x8086, 0x27A0,      0,      0,  0x8086, 0x27b8,      0,      0, "kontron",    "986lcd-m",    "Kontron",     "986LCD-M",           board_kontron_986lcd_m},
+	{0x8086, 0x2411, 0x8086, 0x2411,  0x8086, 0x7125, 0x0e11, 0xb165, NULL,         NULL,          "Mitac",       "6513WU",             board_mitac_6513wu},
+	{0x13f6, 0x0111, 0x1462, 0x5900,  0x1106, 0x3177, 0x1106,      0, NULL,         NULL,          "MSI",         "MS-6590 (KT4 Ultra)",board_msi_kt4v},
+	{0x1106, 0x3149, 0x1462, 0x7094,  0x10ec, 0x8167, 0x1462, 0x094c, NULL,         NULL,          "MSI",         "MS-6702E (K8T Neo2-F)",w83627thf_gpio4_4_raise_2e},
+	{0x1106, 0x0571, 0x1462, 0x7120,  0x1106, 0x3065, 0x1462, 0x7120, NULL,         NULL,          "MSI",         "MS-6712 (KT4V)",     board_msi_kt4v},
+	{0x8086, 0x2658, 0x1462, 0x7046,  0x1106, 0x3044, 0x1462, 0x046d, NULL,         NULL,          "MSI",         "MS-7046",            intel_ich_gpio19_raise},
+	{0x10DE, 0x005E, 0x1462, 0x7135,  0x10DE, 0x0050, 0x1462, 0x7135, "msi",        "k8n-neo3",    "MSI",         "MS-7135 (K8N Neo3)", w83627thf_gpio4_4_raise_4e},
+	{0x1106, 0x3099,      0,      0,  0x1106, 0x3074,      0,      0, "shuttle",    "ak31",        "Shuttle",     "AK31",               w836xx_memw_enable_2e},
+	{0x1106, 0x3104, 0x1297, 0xa238,  0x1106, 0x3059, 0x1297, 0xc063, NULL,         NULL,          "Shuttle",     "AK38N",              it8705f_write_enable_2e},
+	{0x10DE, 0x0050, 0x1297, 0x5036,  0x1412, 0x1724, 0x1297, 0x5036, NULL,         NULL,          "Shuttle",     "FN25",               board_shuttle_fn25},
+	{0x1106, 0x3038, 0x0925, 0x1234,  0x1106, 0x3058, 0x15DD, 0x7609, NULL,         NULL,          "Soyo",        "SY-7VCA",            board_soyo_sy_7vca},
+	{0x8086, 0x1076, 0x8086, 0x1176,  0x1106, 0x3059, 0x10f1, 0x2498, NULL,         NULL,          "Tyan",        "S2498 (Tomcat K7M)", board_asus_a7v8x_mx},
+	{0x1106, 0x0314, 0x1106, 0xaa08,  0x1106, 0x3227, 0x1106, 0xAA08, NULL,         NULL,          "VIA",         "EPIA-CN",            board_via_epia_sp},
+	{0x1106, 0x3177, 0x1106, 0xAA01,  0x1106, 0x3123, 0x1106, 0xAA01, NULL,         NULL,          "VIA",         "EPIA M/MII/...",     board_via_epia_m},
+	{0x1106, 0x0259, 0x1106, 0x3227,  0x1106, 0x3065, 0x1106, 0x3149, NULL,         NULL,          "VIA",         "EPIA-N/NL",          board_via_epia_n},
+	{0x1106, 0x3227, 0x1106, 0xAA01,  0x1106, 0x0259, 0x1106, 0xAA01, NULL,         NULL,          "VIA",         "EPIA SP",            board_via_epia_sp},
+	{0x1106, 0x5337, 0x1458, 0xb003,  0x1106, 0x287e, 0x1106, 0x337e, NULL,         NULL,          "VIA",         "PC3500G",            it87xx_probe_spi_flash},
+
+	{     0,      0,      0,      0,       0,      0,      0,      0, NULL,         NULL,          NULL,          NULL,                 NULL}, /* end marker */
+};
+
+/**
+ * Match boards on coreboot table gathered vendor and part name.
+ * Require main PCI IDs to match too as extra safety.
+ */
+static struct board_pciid_enable *board_match_coreboot_name(const char *vendor,
+							    const char *part)
+{
+	struct board_pciid_enable *board = board_pciid_enables;
+	struct board_pciid_enable *partmatch = NULL;
+
+	for (; board->vendor_name; board++) {
+		if (vendor && (!board->lb_vendor
+			       || strcasecmp(board->lb_vendor, vendor)))
+			continue;
+
+		if (!board->lb_part || strcasecmp(board->lb_part, part))
+			continue;
+
+		if (!pci_dev_find(board->first_vendor, board->first_device))
+			continue;
+
+		if (board->second_vendor &&
+		    !pci_dev_find(board->second_vendor, board->second_device))
+			continue;
+
+		if (vendor)
+			return board;
+
+		if (partmatch) {
+			/* a second entry has a matching part name */
+			printf("AMBIGUOUS BOARD NAME: %s\n", part);
+			printf("At least vendors '%s' and '%s' match.\n",
+			       partmatch->lb_vendor, board->lb_vendor);
+			printf("Please use the full -m vendor:part syntax.\n");
+			return NULL;
+		}
+		partmatch = board;
+	}
+
+	if (partmatch)
+		return partmatch;
+
+	if (!partvendor_from_cbtable) {
+		/* Only warn if the mainboard type was not gathered from the
+		 * coreboot table. If it was, the coreboot implementor is
+		 * expected to fix flashrom, too.
+		 */
+		printf("\nUnknown vendor:board from -m option: %s:%s\n\n",
+		       vendor, part);
+	}
+	return NULL;
+}
+
+/**
+ * Match boards on PCI IDs and subsystem IDs.
+ * Second set of IDs can be main only or missing completely.
+ */
+static struct board_pciid_enable *board_match_pci_card_ids(void)
+{
+	struct board_pciid_enable *board = board_pciid_enables;
+
+	for (; board->vendor_name; board++) {
+		if (!board->first_card_vendor || !board->first_card_device)
+			continue;
+
+		if (!pci_card_find(board->first_vendor, board->first_device,
+				   board->first_card_vendor,
+				   board->first_card_device))
+			continue;
+
+		if (board->second_vendor) {
+			if (board->second_card_vendor) {
+				if (!pci_card_find(board->second_vendor,
+						   board->second_device,
+						   board->second_card_vendor,
+						   board->second_card_device))
+					continue;
+			} else {
+				if (!pci_dev_find(board->second_vendor,
+						  board->second_device))
+					continue;
+			}
+		}
+
+		return board;
+	}
+
+	return NULL;
+}
+
+int board_flash_enable(const char *vendor, const char *part)
+{
+	struct board_pciid_enable *board = NULL;
+	int ret = 0;
+
+	if (part)
+		board = board_match_coreboot_name(vendor, part);
+
+	if (!board)
+		board = board_match_pci_card_ids();
+
+	if (board) {
+		printf("Disabling flash write protection for board \"%s %s\"... ",
+		       board->vendor_name, board->board_name);
+
+		ret = board->enable(board->vendor_name);
+		if (ret)
+			printf("FAILED!\n");
+		else
+			printf("OK.\n");
+	}
+
+	return ret;
+}
diff --git a/libflashrom/buspirate_spi.c b/libflashrom/buspirate_spi.c
new file mode 100644
index 0000000..a1c8265
--- /dev/null
+++ b/libflashrom/buspirate_spi.c
@@ -0,0 +1,372 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include "flash.h"
+#include "spi.h"
+
+/* Change this to #define if you want to test without a serial implementation */
+#undef FAKE_COMMUNICATION
+
+#ifndef FAKE_COMMUNICATION
+int buspirate_serialport_setup(char *dev)
+{
+	/* 115200bps, 8 databits, no parity, 1 stopbit */
+	sp_fd = sp_openserport(dev, 115200);
+	return 0;
+}
+
+int buspirate_serialport_shutdown(void)
+{
+	close(sp_fd);
+	return 0;
+}
+
+int serialport_write(unsigned char *buf, unsigned int writecnt)
+{
+	int tmp = 0;
+
+	while (tmp != writecnt) {
+		tmp = write(sp_fd, buf + tmp, writecnt - tmp);
+		if (tmp == -1)
+			return 1;
+		if (!tmp)
+			printf_debug("Empty write\n");
+	}
+
+	return 0;
+}
+
+int serialport_read(unsigned char *buf, unsigned int readcnt)
+{
+	int tmp = 0;
+
+	while (tmp != readcnt) {
+		tmp = read(sp_fd, buf + tmp, readcnt - tmp);
+		if (tmp == -1)
+			return 1;
+		if (!tmp)
+			printf_debug("Empty read\n");
+	}
+
+	return 0;
+}
+
+int buspirate_discard_read(void)
+{
+	int flags;
+
+	printf_debug("%s\n", __func__);
+	flags = fcntl(sp_fd, F_GETFL);
+	flags |= O_NONBLOCK;
+	fcntl(sp_fd, F_SETFL, flags);
+	sp_flush_incoming();
+	flags &= ~O_NONBLOCK;
+	fcntl(sp_fd, F_SETFL, flags);
+
+	return 0;
+}
+#else
+#define buspirate_serialport_setup(...) 0
+#define buspirate_serialport_shutdown(...) 0
+#define serialport_write(...) 0
+#define serialport_read(...) 0
+#define buspirate_discard_read(...) 0
+#endif
+
+int buspirate_sendrecv(unsigned char *buf, unsigned int writecnt, unsigned int readcnt)
+{
+	int i, ret = 0;
+
+	printf_debug("%s: write %i, read %i\n", __func__, writecnt, readcnt);
+	if (!writecnt && !readcnt) {
+		fprintf(stderr, "Zero length command!\n");
+		return 1;
+	}
+	printf_debug("Sending");
+	for (i = 0; i < writecnt; i++)
+		printf_debug(" 0x%02x", buf[i]);
+#ifdef FAKE_COMMUNICATION
+	/* Placate the caller for now. */
+	if (readcnt) {
+		buf[0] = 0x01;
+		memset(buf + 1, 0xff, readcnt - 1);
+	}
+	ret = 0;
+#else
+	if (writecnt)
+		ret = serialport_write(buf, writecnt);
+	if (ret)
+		return ret;
+	if (readcnt)
+		ret = serialport_read(buf, readcnt);
+	if (ret)
+		return ret;
+#endif
+	printf_debug(", receiving");
+	for (i = 0; i < readcnt; i++)
+		printf_debug(" 0x%02x", buf[i]);
+	printf_debug("\n");
+	return 0;
+}
+
+static const struct buspirate_spispeeds spispeeds[] = {
+	{"30k",		0x0},
+	{"125k",	0x1},
+	{"250k",	0x2},
+	{"1M",		0x3},
+	{"2M",		0x4},
+	{"2.6M",	0x5},
+	{"4M",		0x6},
+	{"8M",		0x7},
+	{NULL,		0x0}
+};
+
+int buspirate_spi_init(void)
+{
+	unsigned char buf[512];
+	int ret = 0;
+	int i;
+	char *dev = NULL;
+	char *speed = NULL;
+	int spispeed = 0x7;
+
+	if (programmer_param && !strlen(programmer_param)) {
+		free(programmer_param);
+		programmer_param = NULL;
+	}
+	if (programmer_param) {
+		dev = extract_param(&programmer_param, "dev=", ",:");
+		speed = extract_param(&programmer_param, "spispeed=", ",:");
+		if (strlen(programmer_param))
+			fprintf(stderr, "Unhandled programmer parameters: %s\n",
+				programmer_param);
+		free(programmer_param);
+		programmer_param = NULL;
+	}
+	if (!dev) {
+		fprintf(stderr, "No serial device given. Use flashrom -p "
+			"buspiratespi:dev=/dev/ttyUSB0\n");
+		return 1;
+	}
+	if (speed) {
+		for (i = 0; spispeeds[i].name; i++)
+			if (!strncasecmp(spispeeds[i].name, speed,
+			    strlen(spispeeds[i].name))) {
+				spispeed = spispeeds[i].speed;
+				break;
+			}
+		if (!spispeeds[i].name)
+			fprintf(stderr, "Invalid SPI speed, using default.\n");
+	}
+	/* This works because speeds numbering starts at 0 and is contiguous. */
+	printf_debug("SPI speed is %sHz\n", spispeeds[spispeed].name);
+
+	ret = buspirate_serialport_setup(dev);
+	if (ret)
+		return ret;
+
+	/* This is the brute force version, but it should work. */
+	for (i = 0; i < 19; i++) {
+		/* Enter raw bitbang mode */
+		buf[0] = 0x00;
+		/* Send the command, don't read the response. */
+		ret = buspirate_sendrecv(buf, 1, 0);
+		if (ret)
+			return ret;
+		/* Read any response and discard it. */
+		ret = buspirate_discard_read();
+		if (ret)
+			return ret;
+	}
+	/* Enter raw bitbang mode */
+	buf[0] = 0x00;
+	ret = buspirate_sendrecv(buf, 1, 5);
+	if (ret)
+		return ret;
+	if (memcmp(buf, "BBIO", 4)) {
+		fprintf(stderr, "Entering raw bitbang mode failed!\n");
+		return 1;
+	}
+	printf_debug("Raw bitbang mode version %c\n", buf[4]);
+	if (buf[4] != '1') {
+		fprintf(stderr, "Can't handle raw bitbang mode version %c!\n",
+			buf[4]);
+		return 1;
+	}
+	/* Enter raw SPI mode */
+	buf[0] = 0x01;
+	ret = buspirate_sendrecv(buf, 1, 4);
+	if (memcmp(buf, "SPI", 3)) {
+		fprintf(stderr, "Entering raw SPI mode failed!\n");
+		return 1;
+	}
+	printf_debug("Raw SPI mode version %c\n", buf[3]);
+	if (buf[3] != '1') {
+		fprintf(stderr, "Can't handle raw SPI mode version %c!\n",
+			buf[3]);
+		return 1;
+	}
+
+	/* Initial setup (SPI peripherals config): Enable power, CS high, AUX */
+	buf[0] = 0x40 | 0xb;
+	ret = buspirate_sendrecv(buf, 1, 1);
+	if (ret)
+		return 1;
+	if (buf[0] != 0x01) {
+		fprintf(stderr, "Protocol error while setting power/CS/AUX!\n");
+		return 1;
+	}
+
+	/* Set SPI speed */
+	buf[0] = 0x60 | spispeed;
+	ret = buspirate_sendrecv(buf, 1, 1);
+	if (ret)
+		return 1;
+	if (buf[0] != 0x01) {
+		fprintf(stderr, "Protocol error while setting SPI speed!\n");
+		return 1;
+	}
+	
+	/* Set SPI config: output type, idle, clock edge, sample */
+	buf[0] = 0x80 | 0xa;
+	ret = buspirate_sendrecv(buf, 1, 1);
+	if (ret)
+		return 1;
+	if (buf[0] != 0x01) {
+		fprintf(stderr, "Protocol error while setting SPI config!\n");
+		return 1;
+	}
+
+	/* De-assert CS# */
+	buf[0] = 0x03;
+	ret = buspirate_sendrecv(buf, 1, 1);
+	if (ret)
+		return 1;
+	if (buf[0] != 0x01) {
+		fprintf(stderr, "Protocol error while raising CS#!\n");
+		return 1;
+	}
+
+	buses_supported = CHIP_BUSTYPE_SPI;
+	spi_controller = SPI_CONTROLLER_BUSPIRATE;
+
+	return 0;
+}
+
+int buspirate_spi_shutdown(void)
+{
+	unsigned char buf[5];
+	int ret = 0;
+
+	/* Exit raw SPI mode (enter raw bitbang mode) */
+	buf[0] = 0x00;
+	ret = buspirate_sendrecv(buf, 1, 5);
+	if (ret)
+		return ret;
+	if (memcmp(buf, "BBIO", 4)) {
+		fprintf(stderr, "Entering raw bitbang mode failed!\n");
+		return 1;
+	}
+	printf_debug("Raw bitbang mode version %c\n", buf[4]);
+	if (buf[4] != '1') {
+		fprintf(stderr, "Can't handle raw bitbang mode version %c!\n",
+			buf[4]);
+		return 1;
+	}
+	/* Reset Bus Pirate (return to user terminal) */
+	buf[0] = 0x0f;
+	ret = buspirate_sendrecv(buf, 1, 0);
+	if (ret)
+		return ret;
+
+	/* Shut down serial port communication */
+	ret = buspirate_serialport_shutdown();
+	if (ret)
+		return ret;
+	printf_debug("Bus Pirate shutdown completed.\n");
+
+	return 0;
+}
+
+int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		const unsigned char *writearr, unsigned char *readarr)
+{
+	static unsigned char *buf = NULL;
+	int i = 0, ret = 0;
+
+	if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
+		return SPI_INVALID_LENGTH;
+
+	/* +2 is pretty arbitrary. */
+	buf = realloc(buf, writecnt + readcnt + 2);
+	if (!buf) {
+		fprintf(stderr, "Out of memory!\n");
+		exit(1); // -1
+	}
+
+	/* Assert CS# */
+	buf[i++] = 0x02;
+	ret = buspirate_sendrecv(buf, 1, 1);
+	if (ret)
+		return SPI_GENERIC_ERROR;
+	if (buf[0] != 0x01) {
+		fprintf(stderr, "Protocol error while lowering CS#!\n");
+		return SPI_GENERIC_ERROR;
+	}
+
+	i = 0;
+	buf[i++] = 0x10 | (writecnt + readcnt - 1);
+	memcpy(buf + i, writearr, writecnt);
+	i += writecnt;
+	memset(buf + i, 0, readcnt);
+	ret = buspirate_sendrecv(buf, i + readcnt, i + readcnt);
+	if (ret)
+		return SPI_GENERIC_ERROR;
+	if (buf[0] != 0x01) {
+		fprintf(stderr, "Protocol error while reading/writing SPI!\n");
+		return SPI_GENERIC_ERROR;
+	}
+	memcpy(readarr, buf + i, readcnt);
+
+	i = 0;
+	/* De-assert CS# */
+	buf[i++] = 0x03;
+	ret = buspirate_sendrecv(buf, 1, 1);
+	if (ret)
+		return SPI_GENERIC_ERROR;
+	if (buf[0] != 0x01) {
+		fprintf(stderr, "Protocol error while raising CS#!\n");
+		return SPI_GENERIC_ERROR;
+	}
+
+	return ret;
+}
+
+int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
+{
+	return spi_read_chunked(flash, buf, start, len, 12);
+}
+
+/* We could do 12-byte writes, but for now we use the generic 1-byte code. */
diff --git a/libflashrom/chipset_enable.c b/libflashrom/chipset_enable.c
new file mode 100644
index 0000000..3bdd7d0
--- /dev/null
+++ b/libflashrom/chipset_enable.c
@@ -0,0 +1,1202 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2005-2009 coresystems GmbH
+ * Copyright (C) 2006 Uwe Hermann <uwe@hermann-uwe.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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Contains the chipset specific flash enables.
+ */
+
+#define _LARGEFILE64_SOURCE
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "flash.h"
+
+unsigned long flashbase = 0;
+
+/**
+ * flashrom defaults to Parallel/LPC/FWH flash devices. If a known host
+ * controller is found, the init routine sets the buses_supported bitfield to
+ * contain the supported buses for that controller.
+ */
+
+enum chipbustype buses_supported = CHIP_BUSTYPE_NONSPI;
+
+/**
+ * Programmers supporting multiple buses can have differing size limits on
+ * each bus. Store the limits for each bus in a common struct.
+ */
+struct decode_sizes max_rom_decode = {
+	.parallel	= 0xffffffff,
+	.lpc		= 0xffffffff,
+	.fwh		= 0xffffffff,
+	.spi		= 0xffffffff
+};
+
+extern int ichspi_lock;
+
+static int enable_flash_ali_m1533(struct pci_dev *dev, const char *name)
+{
+	uint8_t tmp;
+
+	/*
+	 * ROM Write enable, 0xFFFC0000-0xFFFDFFFF and
+	 * 0xFFFE0000-0xFFFFFFFF ROM select enable.
+	 */
+	tmp = pci_read_byte(dev, 0x47);
+	tmp |= 0x46;
+	pci_write_byte(dev, 0x47, tmp);
+
+	return 0;
+}
+
+static int enable_flash_sis85c496(struct pci_dev *dev, const char *name)
+{
+	uint8_t tmp;
+
+	tmp = pci_read_byte(dev, 0xd0);
+	tmp |= 0xf8;
+	pci_write_byte(dev, 0xd0, tmp);
+
+	return 0;
+}
+
+static int enable_flash_sis_mapping(struct pci_dev *dev, const char *name)
+{
+	uint8_t new, newer;
+
+	/* Extended BIOS enable = 1, Lower BIOS Enable = 1 */
+	/* This is 0xFFF8000~0xFFFF0000 decoding on SiS 540/630. */
+	new = pci_read_byte(dev, 0x40);
+	new &= (~0x04); /* No idea why we clear bit 2. */
+	new |= 0xb; /* 0x3 for some chipsets, bit 7 seems to be don't care. */
+	pci_write_byte(dev, 0x40, new);
+	newer = pci_read_byte(dev, 0x40);
+	if (newer != new) {
+		printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x40, new, name);
+		printf_debug("Stuck at 0x%x\n", newer);
+		return -1;
+	}
+	return 0;
+}
+
+static struct pci_dev *find_southbridge(uint16_t vendor, const char *name)
+{
+	struct pci_dev *sbdev;
+	
+	sbdev = pci_dev_find_vendorclass(vendor, 0x0601);
+	if (!sbdev)
+		sbdev = pci_dev_find_vendorclass(vendor, 0x0680);
+	if (!sbdev)
+		sbdev = pci_dev_find_vendorclass(vendor, 0x0000);
+	if (!sbdev)
+		fprintf(stderr, "No southbridge found for %s!\n", name);
+	if (sbdev)
+		printf_debug("Found southbridge %04x:%04x at %02x:%02x:%01x\n",
+			     sbdev->vendor_id, sbdev->device_id,
+			     sbdev->bus, sbdev->dev, sbdev->func);
+	return sbdev;
+}
+
+static int enable_flash_sis501(struct pci_dev *dev, const char *name)
+{
+	uint8_t tmp;
+	int ret = 0;
+	struct pci_dev *sbdev;
+
+	sbdev = find_southbridge(dev->vendor_id, name);
+	if (!sbdev)
+		return -1;
+
+	ret = enable_flash_sis_mapping(sbdev, name);
+
+	tmp = sio_read(0x22, 0x80);
+	tmp &= (~0x20);
+	tmp |= 0x4;
+	sio_write(0x22, 0x80, tmp);
+
+	tmp = sio_read(0x22, 0x70);
+	tmp &= (~0x20);
+	tmp |= 0x4;
+	sio_write(0x22, 0x70, tmp);
+	
+	return ret;
+}
+
+static int enable_flash_sis5511(struct pci_dev *dev, const char *name)
+{
+	uint8_t tmp;
+	int ret = 0;
+	struct pci_dev *sbdev;
+
+	sbdev = find_southbridge(dev->vendor_id, name);
+	if (!sbdev)
+		return -1;
+
+	ret = enable_flash_sis_mapping(sbdev, name);
+
+	tmp = sio_read(0x22, 0x50);
+	tmp &= (~0x20);
+	tmp |= 0x4;
+	sio_write(0x22, 0x50, tmp);
+
+	return ret;
+}
+
+static int enable_flash_sis5596(struct pci_dev *dev, const char *name)
+{
+	int ret;
+
+	ret = enable_flash_sis5511(dev, name);
+
+	/* FIXME: Needs same superio handling as enable_flash_sis630 */
+	return ret;
+}
+
+static int enable_flash_sis530(struct pci_dev *dev, const char *name)
+{
+	uint8_t new, newer;
+	int ret = 0;
+	struct pci_dev *sbdev;
+
+	sbdev = find_southbridge(dev->vendor_id, name);
+	if (!sbdev)
+		return -1;
+
+	ret = enable_flash_sis_mapping(sbdev, name);
+
+	new = pci_read_byte(sbdev, 0x45);
+	new &= (~0x20);
+	new |= 0x4;
+	pci_write_byte(sbdev, 0x45, new);
+	newer = pci_read_byte(dev, 0x45);
+	if (newer != new) {
+		printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x45, new, name);
+		printf_debug("Stuck at 0x%x\n", newer);
+		ret = -1;
+	}
+
+	return ret;
+}
+
+static int enable_flash_sis540(struct pci_dev *dev, const char *name)
+{
+	uint8_t new, newer;
+	int ret = 0;
+	struct pci_dev *sbdev;
+
+	sbdev = find_southbridge(dev->vendor_id, name);
+	if (!sbdev)
+		return -1;
+
+	ret = enable_flash_sis_mapping(sbdev, name);
+
+	new = pci_read_byte(sbdev, 0x45);
+	new &= (~0x80);
+	new |= 0x40;
+	pci_write_byte(sbdev, 0x45, new);
+	newer = pci_read_byte(dev, 0x45);
+	if (newer != new) {
+		printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x45, new, name);
+		printf_debug("Stuck at 0x%x\n", newer);
+		ret = -1;
+	}
+
+	return ret;
+}
+
+/* Datasheet:
+ *   - Name: 82371AB PCI-TO-ISA / IDE XCELERATOR (PIIX4)
+ *   - URL: http://www.intel.com/design/intarch/datashts/290562.htm
+ *   - PDF: http://www.intel.com/design/intarch/datashts/29056201.pdf
+ *   - Order Number: 290562-001
+ */
+static int enable_flash_piix4(struct pci_dev *dev, const char *name)
+{
+	uint16_t old, new;
+	uint16_t xbcs = 0x4e;	/* X-Bus Chip Select register. */
+
+	buses_supported = CHIP_BUSTYPE_PARALLEL;
+
+	old = pci_read_word(dev, xbcs);
+
+	/* Set bit 9: 1-Meg Extended BIOS Enable (PCI master accesses to
+	 *            FFF00000-FFF7FFFF are forwarded to ISA).
+	 *            Note: This bit is reserved on PIIX/PIIX3/MPIIX.
+	 * Set bit 7: Extended BIOS Enable (PCI master accesses to
+	 *            FFF80000-FFFDFFFF are forwarded to ISA).
+	 * Set bit 6: Lower BIOS Enable (PCI master, or ISA master accesses to
+	 *            the lower 64-Kbyte BIOS block (E0000-EFFFF) at the top
+	 *            of 1 Mbyte, or the aliases at the top of 4 Gbyte
+	 *            (FFFE0000-FFFEFFFF) result in the generation of BIOSCS#.
+	 * Note: Accesses to FFFF0000-FFFFFFFF are always forwarded to ISA.
+	 * Set bit 2: BIOSCS# Write Enable (1=enable, 0=disable).
+	 */
+	if (dev->device_id == 0x122e || dev->device_id == 0x7000
+	    || dev->device_id == 0x1234)
+		new = old | 0x00c4; /* PIIX/PIIX3/MPIIX: Bit 9 is reserved. */
+	else
+		new = old | 0x02c4;
+
+	if (new == old)
+		return 0;
+
+	pci_write_word(dev, xbcs, new);
+
+	if (pci_read_word(dev, xbcs) != new) {
+		printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", xbcs, new, name);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * See ie. page 375 of "Intel I/O Controller Hub 7 (ICH7) Family Datasheet"
+ * http://download.intel.com/design/chipsets/datashts/30701303.pdf
+ */
+static int enable_flash_ich(struct pci_dev *dev, const char *name,
+			    int bios_cntl)
+{
+	uint8_t old, new;
+
+	/*
+	 * Note: the ICH0-ICH5 BIOS_CNTL register is actually 16 bit wide, but
+	 * just treating it as 8 bit wide seems to work fine in practice.
+	 */
+	old = pci_read_byte(dev, bios_cntl);
+
+	printf_debug("\nBIOS Lock Enable: %sabled, ",
+		     (old & (1 << 1)) ? "en" : "dis");
+	printf_debug("BIOS Write Enable: %sabled, ",
+		     (old & (1 << 0)) ? "en" : "dis");
+	printf_debug("BIOS_CNTL is 0x%x\n", old);
+
+	new = old | 1;
+
+	if (new == old)
+		return 0;
+
+	pci_write_byte(dev, bios_cntl, new);
+
+	if (pci_read_byte(dev, bios_cntl) != new) {
+		printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", bios_cntl, new, name);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int enable_flash_ich_4e(struct pci_dev *dev, const char *name)
+{
+	/*
+	 * Note: ICH5 has registers similar to FWH_SEL1, FWH_SEL2 and
+	 * FWH_DEC_EN1, but they are called FB_SEL1, FB_SEL2, FB_DEC_EN1 and
+	 * FB_DEC_EN2.
+	 */
+	return enable_flash_ich(dev, name, 0x4e);
+}
+
+static int enable_flash_ich_dc(struct pci_dev *dev, const char *name)
+{
+	uint32_t fwh_conf;
+	int i;
+	char *idsel = NULL;
+
+	/* Ignore all legacy ranges below 1 MB. */
+	/* FWH_SEL1 */
+	fwh_conf = pci_read_long(dev, 0xd0);
+	for (i = 7; i >= 0; i--)
+		printf_debug("\n0x%08x/0x%08x FWH IDSEL: 0x%x",
+			     (0x1ff8 + i) * 0x80000,
+			     (0x1ff0 + i) * 0x80000,
+			     (fwh_conf >> (i * 4)) & 0xf);
+	/* FWH_SEL2 */
+	fwh_conf = pci_read_word(dev, 0xd4);
+	for (i = 3; i >= 0; i--)
+		printf_debug("\n0x%08x/0x%08x FWH IDSEL: 0x%x",
+			     (0xff4 + i) * 0x100000,
+			     (0xff0 + i) * 0x100000,
+			     (fwh_conf >> (i * 4)) & 0xf);
+	/* FWH_DEC_EN1 */
+	fwh_conf = pci_read_word(dev, 0xd8);
+	for (i = 7; i >= 0; i--)
+		printf_debug("\n0x%08x/0x%08x FWH decode %sabled",
+			     (0x1ff8 + i) * 0x80000,
+			     (0x1ff0 + i) * 0x80000,
+			     (fwh_conf >> (i + 0x8)) & 0x1 ? "en" : "dis");
+	for (i = 3; i >= 0; i--)
+		printf_debug("\n0x%08x/0x%08x FWH decode %sabled",
+			     (0xff4 + i) * 0x100000,
+			     (0xff0 + i) * 0x100000,
+			     (fwh_conf >> i) & 0x1 ? "en" : "dis");
+
+	if (programmer_param)
+		idsel = strstr(programmer_param, "fwh_idsel=");
+
+	if (idsel) {
+		idsel += strlen("fwh_idsel=");
+		fwh_conf = (uint32_t)strtoul(idsel, NULL, 0);
+
+		/* FIXME: Need to undo this on shutdown. */
+		printf("\nSetting IDSEL=0x%x for top 16 MB", fwh_conf);
+		pci_write_long(dev, 0xd0, fwh_conf);
+		pci_write_word(dev, 0xd4, fwh_conf);
+	}
+
+	return enable_flash_ich(dev, name, 0xdc);
+}
+
+#define ICH_STRAP_RSVD 0x00
+#define ICH_STRAP_SPI  0x01
+#define ICH_STRAP_PCI  0x02
+#define ICH_STRAP_LPC  0x03
+
+static int enable_flash_vt8237s_spi(struct pci_dev *dev, const char *name)
+{
+	uint32_t mmio_base;
+
+	mmio_base = (pci_read_long(dev, 0xbc)) << 8;
+	printf_debug("MMIO base at = 0x%x\n", mmio_base);
+	spibar = physmap("VT8237S MMIO registers", mmio_base, 0x70);
+
+	printf_debug("0x6c: 0x%04x     (CLOCK/DEBUG)\n",
+		     mmio_readw(spibar + 0x6c));
+
+	/* Not sure if it speaks all these bus protocols. */
+	buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI;
+	spi_controller = SPI_CONTROLLER_VIA;
+	ich_init_opcodes();
+
+	return 0;
+}
+
+static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name,
+				   int ich_generation)
+{
+	int ret, i;
+	uint8_t old, new, bbs, buc;
+	uint16_t spibar_offset, tmp2;
+	uint32_t tmp, gcs;
+	void *rcrb;
+	//TODO: These names are incorrect for EP80579. For that, the solution would look like the commented line
+	//static const char *straps_names[] = {"SPI", "reserved", "reserved", "LPC" };
+	static const char *straps_names[] = { "reserved", "SPI", "PCI", "LPC" };
+
+	/* Enable Flash Writes */
+	ret = enable_flash_ich_dc(dev, name);
+
+	/* Get physical address of Root Complex Register Block */
+	tmp = pci_read_long(dev, 0xf0) & 0xffffc000;
+	printf_debug("\nRoot Complex Register Block address = 0x%x\n", tmp);
+
+	/* Map RCBA to virtual memory */
+	rcrb = physmap("ICH RCRB", tmp, 0x4000);
+
+	gcs = mmio_readl(rcrb + 0x3410);
+	printf_debug("GCS = 0x%x: ", gcs);
+	printf_debug("BIOS Interface Lock-Down: %sabled, ",
+		     (gcs & 0x1) ? "en" : "dis");
+	bbs = (gcs >> 10) & 0x3;
+	printf_debug("BOOT BIOS Straps: 0x%x (%s)\n", bbs, straps_names[bbs]);
+
+	buc = mmio_readb(rcrb + 0x3414);
+	printf_debug("Top Swap : %s\n",
+		     (buc & 1) ? "enabled (A16 inverted)" : "not enabled");
+
+	/* It seems the ICH7 does not support SPI and LPC chips at the same
+	 * time. At least not with our current code. So we prevent searching
+	 * on ICH7 when the southbridge is strapped to LPC
+	 */
+
+	if (ich_generation == 7 && bbs == ICH_STRAP_LPC) {
+		/* Not sure if it speaks LPC as well. */
+		buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH;
+		/* No further SPI initialization required */
+		return ret;
+	}
+
+	switch (ich_generation) {
+	case 7:
+		buses_supported = CHIP_BUSTYPE_SPI;
+		spi_controller = SPI_CONTROLLER_ICH7;
+		spibar_offset = 0x3020;
+		break;
+	case 8:
+		/* Not sure if it speaks LPC as well. */
+		buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI;
+		spi_controller = SPI_CONTROLLER_ICH9;
+		spibar_offset = 0x3020;
+		break;
+	case 9:
+	case 10:
+	default:		/* Future version might behave the same */
+		/* Not sure if it speaks LPC as well. */
+		buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI;
+		spi_controller = SPI_CONTROLLER_ICH9;
+		spibar_offset = 0x3800;
+		break;
+	}
+
+	/* SPIBAR is at RCRB+0x3020 for ICH[78] and RCRB+0x3800 for ICH9. */
+	printf_debug("SPIBAR = 0x%x + 0x%04x\n", tmp, spibar_offset);
+
+	/* Assign Virtual Address */
+	spibar = rcrb + spibar_offset;
+
+	switch (spi_controller) {
+	case SPI_CONTROLLER_ICH7:
+		printf_debug("0x00: 0x%04x     (SPIS)\n",
+			     mmio_readw(spibar + 0));
+		printf_debug("0x02: 0x%04x     (SPIC)\n",
+			     mmio_readw(spibar + 2));
+		printf_debug("0x04: 0x%08x (SPIA)\n",
+			     mmio_readl(spibar + 4));
+		for (i = 0; i < 8; i++) {
+			int offs;
+			offs = 8 + (i * 8);
+			printf_debug("0x%02x: 0x%08x (SPID%d)\n", offs,
+				     mmio_readl(spibar + offs), i);
+			printf_debug("0x%02x: 0x%08x (SPID%d+4)\n", offs + 4,
+				     mmio_readl(spibar + offs + 4), i);
+		}
+		printf_debug("0x50: 0x%08x (BBAR)\n",
+			     mmio_readl(spibar + 0x50));
+		printf_debug("0x54: 0x%04x     (PREOP)\n",
+			     mmio_readw(spibar + 0x54));
+		printf_debug("0x56: 0x%04x     (OPTYPE)\n",
+			     mmio_readw(spibar + 0x56));
+		printf_debug("0x58: 0x%08x (OPMENU)\n",
+			     mmio_readl(spibar + 0x58));
+		printf_debug("0x5c: 0x%08x (OPMENU+4)\n",
+			     mmio_readl(spibar + 0x5c));
+		for (i = 0; i < 4; i++) {
+			int offs;
+			offs = 0x60 + (i * 4);
+			printf_debug("0x%02x: 0x%08x (PBR%d)\n", offs,
+				     mmio_readl(spibar + offs), i);
+		}
+		printf_debug("\n");
+		if (mmio_readw(spibar) & (1 << 15)) {
+			printf("WARNING: SPI Configuration Lockdown activated.\n");
+			ichspi_lock = 1;
+		}
+		ich_init_opcodes();
+		break;
+	case SPI_CONTROLLER_ICH9:
+		tmp2 = mmio_readw(spibar + 4);
+		printf_debug("0x04: 0x%04x (HSFS)\n", tmp2);
+		printf_debug("FLOCKDN %i, ", (tmp2 >> 15 & 1));
+		printf_debug("FDV %i, ", (tmp2 >> 14) & 1);
+		printf_debug("FDOPSS %i, ", (tmp2 >> 13) & 1);
+		printf_debug("SCIP %i, ", (tmp2 >> 5) & 1);
+		printf_debug("BERASE %i, ", (tmp2 >> 3) & 3);
+		printf_debug("AEL %i, ", (tmp2 >> 2) & 1);
+		printf_debug("FCERR %i, ", (tmp2 >> 1) & 1);
+		printf_debug("FDONE %i\n", (tmp2 >> 0) & 1);
+
+		tmp = mmio_readl(spibar + 0x50);
+		printf_debug("0x50: 0x%08x (FRAP)\n", tmp);
+		printf_debug("BMWAG %i, ", (tmp >> 24) & 0xff);
+		printf_debug("BMRAG %i, ", (tmp >> 16) & 0xff);
+		printf_debug("BRWA %i, ", (tmp >> 8) & 0xff);
+		printf_debug("BRRA %i\n", (tmp >> 0) & 0xff);
+
+		printf_debug("0x54: 0x%08x (FREG0)\n",
+			     mmio_readl(spibar + 0x54));
+		printf_debug("0x58: 0x%08x (FREG1)\n",
+			     mmio_readl(spibar + 0x58));
+		printf_debug("0x5C: 0x%08x (FREG2)\n",
+			     mmio_readl(spibar + 0x5C));
+		printf_debug("0x60: 0x%08x (FREG3)\n",
+			     mmio_readl(spibar + 0x60));
+		printf_debug("0x64: 0x%08x (FREG4)\n",
+			     mmio_readl(spibar + 0x64));
+		printf_debug("0x74: 0x%08x (PR0)\n",
+			     mmio_readl(spibar + 0x74));
+		printf_debug("0x78: 0x%08x (PR1)\n",
+			     mmio_readl(spibar + 0x78));
+		printf_debug("0x7C: 0x%08x (PR2)\n",
+			     mmio_readl(spibar + 0x7C));
+		printf_debug("0x80: 0x%08x (PR3)\n",
+			     mmio_readl(spibar + 0x80));
+		printf_debug("0x84: 0x%08x (PR4)\n",
+			     mmio_readl(spibar + 0x84));
+		printf_debug("0x90: 0x%08x (SSFS, SSFC)\n",
+			     mmio_readl(spibar + 0x90));
+		printf_debug("0x94: 0x%04x     (PREOP)\n",
+			     mmio_readw(spibar + 0x94));
+		printf_debug("0x96: 0x%04x     (OPTYPE)\n",
+			     mmio_readw(spibar + 0x96));
+		printf_debug("0x98: 0x%08x (OPMENU)\n",
+			     mmio_readl(spibar + 0x98));
+		printf_debug("0x9C: 0x%08x (OPMENU+4)\n",
+			     mmio_readl(spibar + 0x9C));
+		printf_debug("0xA0: 0x%08x (BBAR)\n",
+			     mmio_readl(spibar + 0xA0));
+		printf_debug("0xB0: 0x%08x (FDOC)\n",
+			     mmio_readl(spibar + 0xB0));
+		if (tmp2 & (1 << 15)) {
+			printf("WARNING: SPI Configuration Lockdown activated.\n");
+			ichspi_lock = 1;
+		}
+		ich_init_opcodes();
+		break;
+	default:
+		/* Nothing */
+		break;
+	}
+
+	old = pci_read_byte(dev, 0xdc);
+	printf_debug("SPI Read Configuration: ");
+	new = (old >> 2) & 0x3;
+	switch (new) {
+	case 0:
+	case 1:
+	case 2:
+		printf_debug("prefetching %sabled, caching %sabled, ",
+			     (new & 0x2) ? "en" : "dis",
+			     (new & 0x1) ? "dis" : "en");
+		break;
+	default:
+		printf_debug("invalid prefetching/caching settings, ");
+		break;
+	}
+
+	return ret;
+}
+
+static int enable_flash_ich7(struct pci_dev *dev, const char *name)
+{
+	return enable_flash_ich_dc_spi(dev, name, 7);
+}
+
+static int enable_flash_ich8(struct pci_dev *dev, const char *name)
+{
+	return enable_flash_ich_dc_spi(dev, name, 8);
+}
+
+static int enable_flash_ich9(struct pci_dev *dev, const char *name)
+{
+	return enable_flash_ich_dc_spi(dev, name, 9);
+}
+
+static int enable_flash_ich10(struct pci_dev *dev, const char *name)
+{
+	return enable_flash_ich_dc_spi(dev, name, 10);
+}
+
+static int enable_flash_vt823x(struct pci_dev *dev, const char *name)
+{
+	uint8_t val;
+
+	/* enable ROM decode range (1MB) FFC00000 - FFFFFFFF */
+	pci_write_byte(dev, 0x41, 0x7f);
+
+	/* ROM write enable */
+	val = pci_read_byte(dev, 0x40);
+	val |= 0x10;
+	pci_write_byte(dev, 0x40, val);
+
+	if (pci_read_byte(dev, 0x40) != val) {
+		printf("\nWARNING: Failed to enable flash write on \"%s\"\n",
+		       name);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int enable_flash_cs5530(struct pci_dev *dev, const char *name)
+{
+	uint8_t reg8;
+
+#define DECODE_CONTROL_REG2		0x5b	/* F0 index 0x5b */
+#define ROM_AT_LOGIC_CONTROL_REG	0x52	/* F0 index 0x52 */
+
+#define LOWER_ROM_ADDRESS_RANGE		(1 << 0)
+#define ROM_WRITE_ENABLE		(1 << 1)
+#define UPPER_ROM_ADDRESS_RANGE		(1 << 2)
+#define BIOS_ROM_POSITIVE_DECODE	(1 << 5)
+
+	/* Decode 0x000E0000-0x000FFFFF (128 KB), not just 64 KB, and
+	 * decode 0xFF000000-0xFFFFFFFF (16 MB), not just 256 KB.
+	 * Make the configured ROM areas writable.
+	 */
+	reg8 = pci_read_byte(dev, ROM_AT_LOGIC_CONTROL_REG);
+	reg8 |= LOWER_ROM_ADDRESS_RANGE;
+	reg8 |= UPPER_ROM_ADDRESS_RANGE;
+	reg8 |= ROM_WRITE_ENABLE;
+	pci_write_byte(dev, ROM_AT_LOGIC_CONTROL_REG, reg8);
+
+	/* Set positive decode on ROM. */
+	reg8 = pci_read_byte(dev, DECODE_CONTROL_REG2);
+	reg8 |= BIOS_ROM_POSITIVE_DECODE;
+	pci_write_byte(dev, DECODE_CONTROL_REG2, reg8);
+
+	return 0;
+}
+
+/**
+ * Geode systems write protect the BIOS via RCONFs (cache settings similar
+ * to MTRRs). To unlock, change MSR 0x1808 top byte to 0x22. 
+ *
+ * Geode systems also write protect the NOR flash chip itself via MSR_NORF_CTL.
+ * To enable write to NOR Boot flash for the benefit of systems that have such
+ * a setup, raise MSR 0x51400018 WE_CS3 (write enable Boot Flash Chip Select).
+ */
+static int enable_flash_cs5536(struct pci_dev *dev, const char *name)
+{
+#define MSR_RCONF_DEFAULT	0x1808
+#define MSR_NORF_CTL		0x51400018
+
+	msr_t msr;
+
+	/* Geode only has a single core */
+	if (setup_cpu_msr(0))
+		return -1;
+
+	msr = rdmsr(MSR_RCONF_DEFAULT);
+	if ((msr.hi >> 24) != 0x22) {
+		msr.hi &= 0xfbffffff;
+		wrmsr(MSR_RCONF_DEFAULT, msr);
+	}
+
+	msr = rdmsr(MSR_NORF_CTL);
+	/* Raise WE_CS3 bit. */
+	msr.lo |= 0x08;
+	wrmsr(MSR_NORF_CTL, msr);
+
+	cleanup_cpu_msr();
+
+#undef MSR_RCONF_DEFAULT
+#undef MSR_NORF_CTL
+	return 0;
+}
+
+static int enable_flash_sc1100(struct pci_dev *dev, const char *name)
+{
+	uint8_t new;
+
+	pci_write_byte(dev, 0x52, 0xee);
+
+	new = pci_read_byte(dev, 0x52);
+
+	if (new != 0xee) {
+		printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x52, new, name);
+		return -1;
+	}
+
+	return 0;
+}
+
+/* Works for AMD-8111, VIA VT82C586A/B, VIA VT82C686A/B. */
+static int enable_flash_amd8111(struct pci_dev *dev, const char *name)
+{
+	uint8_t old, new;
+
+	/* Enable decoding at 0xffb00000 to 0xffffffff. */
+	old = pci_read_byte(dev, 0x43);
+	new = old | 0xC0;
+	if (new != old) {
+		pci_write_byte(dev, 0x43, new);
+		if (pci_read_byte(dev, 0x43) != new) {
+			printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x43, new, name);
+		}
+	}
+
+	/* Enable 'ROM write' bit. */
+	old = pci_read_byte(dev, 0x40);
+	new = old | 0x01;
+	if (new == old)
+		return 0;
+	pci_write_byte(dev, 0x40, new);
+
+	if (pci_read_byte(dev, 0x40) != new) {
+		printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x40, new, name);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int enable_flash_sb600(struct pci_dev *dev, const char *name)
+{
+	uint32_t tmp, prot;
+	uint8_t reg;
+	struct pci_dev *smbus_dev;
+	int has_spi = 1;
+
+	/* Clear ROM protect 0-3. */
+	for (reg = 0x50; reg < 0x60; reg += 4) {
+		prot = pci_read_long(dev, reg);
+		/* No protection flags for this region?*/
+		if ((prot & 0x3) == 0)
+			continue;
+		printf_debug("SB600 %s%sprotected from %u to %u\n",
+			(prot & 0x1) ? "write " : "",
+			(prot & 0x2) ? "read " : "",
+			(prot & 0xfffffc00),
+			(prot & 0xfffffc00) + ((prot & 0x3ff) << 8));
+		prot &= 0xfffffffc;
+		pci_write_byte(dev, reg, prot);
+		prot = pci_read_long(dev, reg);
+		if (prot & 0x3)
+			printf("SB600 %s%sunprotect failed from %u to %u\n",
+				(prot & 0x1) ? "write " : "",
+				(prot & 0x2) ? "read " : "",
+				(prot & 0xfffffc00),
+				(prot & 0xfffffc00) + ((prot & 0x3ff) << 8));
+	}
+
+	/* Read SPI_BaseAddr */
+	tmp = pci_read_long(dev, 0xa0);
+	tmp &= 0xffffffe0;	/* remove bits 4-0 (reserved) */
+	printf_debug("SPI base address is at 0x%x\n", tmp);
+
+	/* If the BAR has address 0, it is unlikely SPI is used. */
+	if (!tmp)
+		has_spi = 0;
+
+	if (has_spi) {
+		/* Physical memory has to be mapped at page (4k) boundaries. */
+		sb600_spibar = physmap("SB600 SPI registers", tmp & 0xfffff000,
+				       0x1000);
+		/* The low bits of the SPI base address are used as offset into
+		 * the mapped page.
+		 */
+		sb600_spibar += tmp & 0xfff;
+
+		tmp = pci_read_long(dev, 0xa0);
+		printf_debug("AltSpiCSEnable=%i, SpiRomEnable=%i, "
+			     "AbortEnable=%i\n", tmp & 0x1, (tmp & 0x2) >> 1,
+			     (tmp & 0x4) >> 2);
+		tmp = (pci_read_byte(dev, 0xba) & 0x4) >> 2;
+		printf_debug("PrefetchEnSPIFromIMC=%i, ", tmp);
+
+		tmp = pci_read_byte(dev, 0xbb);
+		printf_debug("PrefetchEnSPIFromHost=%i, SpiOpEnInLpcMode=%i\n",
+			     tmp & 0x1, (tmp & 0x20) >> 5);
+		tmp = mmio_readl(sb600_spibar);
+		printf_debug("SpiArbEnable=%i, SpiAccessMacRomEn=%i, "
+			     "SpiHostAccessRomEn=%i, ArbWaitCount=%i, "
+			     "SpiBridgeDisable=%i, DropOneClkOnRd=%i\n",
+			     (tmp >> 19) & 0x1, (tmp >> 22) & 0x1,
+			     (tmp >> 23) & 0x1, (tmp >> 24) & 0x7,
+			     (tmp >> 27) & 0x1, (tmp >> 28) & 0x1);
+	}
+
+	/* Look for the SMBus device. */
+	smbus_dev = pci_dev_find(0x1002, 0x4385);
+
+	if (has_spi && !smbus_dev) {
+		fprintf(stderr, "ERROR: SMBus device not found. Not enabling SPI.\n");
+		has_spi = 0;
+	}
+	if (has_spi) {
+		/* Note about the bit tests below: If a bit is zero, the GPIO is SPI. */
+		/* GPIO11/SPI_DO and GPIO12/SPI_DI status */
+		reg = pci_read_byte(smbus_dev, 0xAB);
+		reg &= 0xC0;
+		printf_debug("GPIO11 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_DO");
+		printf_debug("GPIO12 used for %s\n", (reg & (1 << 7)) ? "GPIO" : "SPI_DI");
+		if (reg != 0x00)
+			has_spi = 0;
+		/* GPIO31/SPI_HOLD and GPIO32/SPI_CS status */
+		reg = pci_read_byte(smbus_dev, 0x83);
+		reg &= 0xC0;
+		printf_debug("GPIO31 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_HOLD");
+		printf_debug("GPIO32 used for %s\n", (reg & (1 << 7)) ? "GPIO" : "SPI_CS");
+		/* SPI_HOLD is not used on all boards, filter it out. */
+		if ((reg & 0x80) != 0x00)
+			has_spi = 0;
+		/* GPIO47/SPI_CLK status */
+		reg = pci_read_byte(smbus_dev, 0xA7);
+		reg &= 0x40;
+		printf_debug("GPIO47 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_CLK");
+		if (reg != 0x00)
+			has_spi = 0;
+	}
+
+	buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH;
+	if (has_spi) {
+		buses_supported |= CHIP_BUSTYPE_SPI;
+		spi_controller = SPI_CONTROLLER_SB600;
+	}
+
+	/* Read ROM strap override register. */
+	OUTB(0x8f, 0xcd6);
+	reg = INB(0xcd7);
+	reg &= 0x0e;
+	printf_debug("ROM strap override is %sactive", (reg & 0x02) ? "" : "not ");
+	if (reg & 0x02) {
+		switch ((reg & 0x0c) >> 2) {
+		case 0x00:
+			printf_debug(": LPC");
+			break;
+		case 0x01:
+			printf_debug(": PCI");
+			break;
+		case 0x02:
+			printf_debug(": FWH");
+			break;
+		case 0x03:
+			printf_debug(": SPI");
+			break;
+		}
+	}
+	printf_debug("\n");
+
+	/* Force enable SPI ROM in SB600 PM register.
+	 * If we enable SPI ROM here, we have to disable it after we leave.
+	 * But how can we know which ROM we are going to handle? So we have
+	 * to trade off. We only access LPC ROM if we boot via LPC ROM. And
+	 * only SPI ROM if we boot via SPI ROM. If you want to access SPI on
+	 * boards with LPC straps, you have to use the code below.
+	 */
+	/*
+	OUTB(0x8f, 0xcd6);
+	OUTB(0x0e, 0xcd7);
+	*/
+
+	return 0;
+}
+
+static int enable_flash_nvidia_nforce2(struct pci_dev *dev, const char *name)
+{
+	uint8_t tmp;
+
+	pci_write_byte(dev, 0x92, 0);
+
+	tmp = pci_read_byte(dev, 0x6d);
+	tmp |= 0x01;
+	pci_write_byte(dev, 0x6d, tmp);
+
+	return 0;
+}
+
+static int enable_flash_ck804(struct pci_dev *dev, const char *name)
+{
+	uint8_t old, new;
+
+	old = pci_read_byte(dev, 0x88);
+	new = old | 0xc0;
+	if (new != old) {
+		pci_write_byte(dev, 0x88, new);
+		if (pci_read_byte(dev, 0x88) != new) {
+			printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x88, new, name);
+		}
+	}
+
+	old = pci_read_byte(dev, 0x6d);
+	new = old | 0x01;
+	if (new == old)
+		return 0;
+	pci_write_byte(dev, 0x6d, new);
+
+	if (pci_read_byte(dev, 0x6d) != new) {
+		printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x6d, new, name);
+		return -1;
+	}
+
+	return 0;
+}
+
+/* ATI Technologies Inc IXP SB400 PCI-ISA Bridge (rev 80) */
+static int enable_flash_sb400(struct pci_dev *dev, const char *name)
+{
+	uint8_t tmp;
+	struct pci_dev *smbusdev;
+
+	/* Look for the SMBus device. */
+	smbusdev = pci_dev_find(0x1002, 0x4372);
+
+	if (!smbusdev) {
+		fprintf(stderr, "ERROR: SMBus device not found. Aborting.\n");
+		exit(1);
+	}
+
+	/* Enable some SMBus stuff. */
+	tmp = pci_read_byte(smbusdev, 0x79);
+	tmp |= 0x01;
+	pci_write_byte(smbusdev, 0x79, tmp);
+
+	/* Change southbridge. */
+	tmp = pci_read_byte(dev, 0x48);
+	tmp |= 0x21;
+	pci_write_byte(dev, 0x48, tmp);
+
+	/* Now become a bit silly. */
+	tmp = INB(0xc6f);
+	OUTB(tmp, 0xeb);
+	OUTB(tmp, 0xeb);
+	tmp |= 0x40;
+	OUTB(tmp, 0xc6f);
+	OUTB(tmp, 0xeb);
+	OUTB(tmp, 0xeb);
+
+	return 0;
+}
+
+static int enable_flash_mcp55(struct pci_dev *dev, const char *name)
+{
+	uint8_t old, new, byte;
+	uint16_t word;
+
+	/* Set the 0-16 MB enable bits. */
+	byte = pci_read_byte(dev, 0x88);
+	byte |= 0xff;		/* 256K */
+	pci_write_byte(dev, 0x88, byte);
+	byte = pci_read_byte(dev, 0x8c);
+	byte |= 0xff;		/* 1M */
+	pci_write_byte(dev, 0x8c, byte);
+	word = pci_read_word(dev, 0x90);
+	word |= 0x7fff;		/* 16M */
+	pci_write_word(dev, 0x90, word);
+
+	old = pci_read_byte(dev, 0x6d);
+	new = old | 0x01;
+	if (new == old)
+		return 0;
+	pci_write_byte(dev, 0x6d, new);
+
+	if (pci_read_byte(dev, 0x6d) != new) {
+		printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x6d, new, name);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int enable_flash_ht1000(struct pci_dev *dev, const char *name)
+{
+	uint8_t byte;
+
+	/* Set the 4MB enable bit. */
+	byte = pci_read_byte(dev, 0x41);
+	byte |= 0x0e;
+	pci_write_byte(dev, 0x41, byte);
+
+	byte = pci_read_byte(dev, 0x43);
+	byte |= (1 << 4);
+	pci_write_byte(dev, 0x43, byte);
+
+	return 0;
+}
+
+/**
+ * Usually on the x86 architectures (and on other PC-like platforms like some
+ * Alphas or Itanium) the system flash is mapped right below 4G. On the AMD
+ * Elan SC520 only a small piece of the system flash is mapped there, but the
+ * complete flash is mapped somewhere below 1G. The position can be determined
+ * by the BOOTCS PAR register.
+ */
+static int get_flashbase_sc520(struct pci_dev *dev, const char *name)
+{
+	int i, bootcs_found = 0;
+	uint32_t parx = 0;
+	void *mmcr;
+
+	/* 1. Map MMCR */
+	mmcr = physmap("Elan SC520 MMCR", 0xfffef000, getpagesize());
+
+	/* 2. Scan PAR0 (0x88) - PAR15 (0xc4) for
+	 *    BOOTCS region (PARx[31:29] = 100b)e
+	 */
+	for (i = 0x88; i <= 0xc4; i += 4) {
+		parx = mmio_readl(mmcr + i);
+		if ((parx >> 29) == 4) {
+			bootcs_found = 1;
+			break; /* BOOTCS found */
+		}
+	}
+
+	/* 3. PARx[25] = 1b --> flashbase[29:16] = PARx[13:0]
+	 *    PARx[25] = 0b --> flashbase[29:12] = PARx[17:0]
+	 */
+	if (bootcs_found) {
+		if (parx & (1 << 25)) {
+			parx &= (1 << 14) - 1; /* Mask [13:0] */
+			flashbase = parx << 16;
+		} else {
+			parx &= (1 << 18) - 1; /* Mask [17:0] */
+			flashbase = parx << 12;
+		}
+	} else {
+		printf("AMD Elan SC520 detected, but no BOOTCS. Assuming flash at 4G\n");
+	}
+
+	/* 4. Clean up */
+	physunmap(mmcr, getpagesize());
+	return 0;
+}
+
+/* Please keep this list alphabetically sorted by vendor/device. */
+const struct penable chipset_enables[] = {
+	{0x10B9, 0x1533, OK, "ALi", "M1533",		enable_flash_ali_m1533},
+	{0x1022, 0x7440, OK, "AMD", "AMD-768",		enable_flash_amd8111},
+	{0x1022, 0x7468, OK, "AMD", "AMD8111",		enable_flash_amd8111},
+	{0x1078, 0x0100, OK, "AMD", "CS5530(A)",	enable_flash_cs5530},
+	{0x1022, 0x2080, OK, "AMD", "CS5536",		enable_flash_cs5536},
+	{0x1022, 0x2090, OK, "AMD", "CS5536",		enable_flash_cs5536},
+	{0x1022, 0x3000, OK, "AMD", "Elan SC520",	get_flashbase_sc520},
+	{0x1002, 0x438D, OK, "AMD", "SB600",		enable_flash_sb600},
+	{0x1002, 0x439d, OK, "AMD", "SB700/SB710/SB750", enable_flash_sb600},
+	{0x100b, 0x0510, NT, "AMD", "SC1100",		enable_flash_sc1100},
+	{0x1002, 0x4377, OK, "ATI", "SB400",		enable_flash_sb400},
+	{0x1166, 0x0205, OK, "Broadcom", "HT-1000",	enable_flash_ht1000},
+	{0x8086, 0x3b00, NT, "Intel", "3400 Desktop",	enable_flash_ich10},
+	{0x8086, 0x3b01, NT, "Intel", "3400 Mobile",	enable_flash_ich10},
+	{0x8086, 0x3b0d, NT, "Intel", "3400 Mobile SFF", enable_flash_ich10},
+	{0x8086, 0x7198, OK, "Intel", "440MX",		enable_flash_piix4},
+	{0x8086, 0x25a1, OK, "Intel", "6300ESB",	enable_flash_ich_4e},
+	{0x8086, 0x2670, OK, "Intel", "631xESB/632xESB/3100", enable_flash_ich_dc},
+	{0x8086, 0x5031, OK, "Intel", "EP80579",	enable_flash_ich7},
+	{0x8086, 0x2420, OK, "Intel", "ICH0",		enable_flash_ich_4e},
+	{0x8086, 0x3a18, OK, "Intel", "ICH10",		enable_flash_ich10},
+	{0x8086, 0x3a1a, OK, "Intel", "ICH10D",		enable_flash_ich10},
+	{0x8086, 0x3a14, OK, "Intel", "ICH10DO",	enable_flash_ich10},
+	{0x8086, 0x3a16, OK, "Intel", "ICH10R",		enable_flash_ich10},
+	{0x8086, 0x2440, OK, "Intel", "ICH2",		enable_flash_ich_4e},
+	{0x8086, 0x244c, OK, "Intel", "ICH2-M",		enable_flash_ich_4e},
+	{0x8086, 0x248c, OK, "Intel", "ICH3-M",		enable_flash_ich_4e},
+	{0x8086, 0x2480, OK, "Intel", "ICH3-S",		enable_flash_ich_4e},
+	{0x8086, 0x24c0, OK, "Intel", "ICH4/ICH4-L",	enable_flash_ich_4e},
+	{0x8086, 0x24cc, OK, "Intel", "ICH4-M",		enable_flash_ich_4e},
+	{0x8086, 0x24d0, OK, "Intel", "ICH5/ICH5R",	enable_flash_ich_4e},
+	{0x8086, 0x2640, OK, "Intel", "ICH6/ICH6R",	enable_flash_ich_dc},
+	{0x8086, 0x2641, OK, "Intel", "ICH6-M",		enable_flash_ich_dc},
+	{0x8086, 0x27b0, OK, "Intel", "ICH7DH",		enable_flash_ich7},
+	{0x8086, 0x27b8, OK, "Intel", "ICH7/ICH7R",	enable_flash_ich7},
+	{0x8086, 0x27b9, OK, "Intel", "ICH7M",		enable_flash_ich7},
+	{0x8086, 0x27bd, OK, "Intel", "ICH7MDH",	enable_flash_ich7},
+	{0x8086, 0x2410, OK, "Intel", "ICH",		enable_flash_ich_4e},
+	{0x8086, 0x2812, OK, "Intel", "ICH8DH",		enable_flash_ich8},
+	{0x8086, 0x2814, OK, "Intel", "ICH8DO",		enable_flash_ich8},
+	{0x8086, 0x2810, OK, "Intel", "ICH8/ICH8R",	enable_flash_ich8},
+	{0x8086, 0x2815, OK, "Intel", "ICH8M",		enable_flash_ich8},
+	{0x8086, 0x2811, OK, "Intel", "ICH8M-E",	enable_flash_ich8},
+	{0x8086, 0x2918, OK, "Intel", "ICH9",		enable_flash_ich9},
+	{0x8086, 0x2912, OK, "Intel", "ICH9DH",		enable_flash_ich9},
+	{0x8086, 0x2914, OK, "Intel", "ICH9DO",		enable_flash_ich9},
+	{0x8086, 0x2919, OK, "Intel", "ICH9M",		enable_flash_ich9},
+	{0x8086, 0x2917, OK, "Intel", "ICH9M-E",	enable_flash_ich9},
+	{0x8086, 0x2916, OK, "Intel", "ICH9R",		enable_flash_ich9},
+	{0x8086, 0x2910, OK, "Intel", "ICH9 Engineering Sample", enable_flash_ich9},
+	{0x8086, 0x1234, NT, "Intel", "MPIIX",		enable_flash_piix4},
+	{0x8086, 0x7000, OK, "Intel", "PIIX3",		enable_flash_piix4},
+	{0x8086, 0x7110, OK, "Intel", "PIIX4/4E/4M",	enable_flash_piix4},
+	{0x8086, 0x122e, OK, "Intel", "PIIX",		enable_flash_piix4},
+	{0x10de, 0x0030, OK, "NVIDIA", "nForce4/MCP4",  enable_flash_nvidia_nforce2},
+	{0x10de, 0x0050, OK, "NVIDIA", "CK804",		enable_flash_ck804}, /* LPC */
+	{0x10de, 0x0051, OK, "NVIDIA", "CK804",		enable_flash_ck804}, /* Pro */
+	{0x10de, 0x0060, OK, "NVIDIA", "NForce2",       enable_flash_nvidia_nforce2},
+	/* Slave, should not be here, to fix known bug for A01. */
+	{0x10de, 0x00d3, OK, "NVIDIA", "CK804",		enable_flash_ck804},
+	{0x10de, 0x0260, NT, "NVIDIA", "MCP51",		enable_flash_ck804},
+	{0x10de, 0x0261, NT, "NVIDIA", "MCP51",		enable_flash_ck804},
+	{0x10de, 0x0262, NT, "NVIDIA", "MCP51",		enable_flash_ck804},
+	{0x10de, 0x0263, NT, "NVIDIA", "MCP51",		enable_flash_ck804},
+	{0x10de, 0x0360, OK, "NVIDIA", "MCP55",		enable_flash_mcp55}, /* M57SLI*/
+	{0x10de, 0x0361, OK, "NVIDIA", "MCP55",		enable_flash_mcp55}, /* LPC */
+	{0x10de, 0x0362, OK, "NVIDIA", "MCP55",		enable_flash_mcp55}, /* LPC */
+	{0x10de, 0x0363, OK, "NVIDIA", "MCP55",		enable_flash_mcp55}, /* LPC */
+	{0x10de, 0x0364, OK, "NVIDIA", "MCP55",		enable_flash_mcp55}, /* LPC */
+	{0x10de, 0x0365, OK, "NVIDIA", "MCP55",		enable_flash_mcp55}, /* LPC */
+	{0x10de, 0x0366, OK, "NVIDIA", "MCP55",		enable_flash_mcp55}, /* LPC */
+	{0x10de, 0x0367, OK, "NVIDIA", "MCP55",		enable_flash_mcp55}, /* Pro */
+	{0x10de, 0x0548, OK, "NVIDIA", "MCP67",		enable_flash_mcp55},
+	{0x1039, 0x0496, NT, "SiS", "85C496+497",	enable_flash_sis85c496},
+	{0x1039, 0x0406, NT, "SiS", "501/5101/5501",	enable_flash_sis501},
+	{0x1039, 0x5511, NT, "SiS", "5511",		enable_flash_sis5511},
+	{0x1039, 0x5596, NT, "SiS", "5596",		enable_flash_sis5596},
+	{0x1039, 0x5571, NT, "SiS", "5571",		enable_flash_sis530},
+	{0x1039, 0x5591, NT, "SiS", "5591/5592",	enable_flash_sis530},
+	{0x1039, 0x5597, NT, "SiS", "5597/5598/5581/5120", enable_flash_sis530},
+	{0x1039, 0x0530, NT, "SiS", "530",		enable_flash_sis530},
+	{0x1039, 0x5600, NT, "SiS", "600",		enable_flash_sis530},
+	{0x1039, 0x0620, NT, "SiS", "620",		enable_flash_sis530},
+	{0x1039, 0x0540, NT, "SiS", "540",		enable_flash_sis540},
+	{0x1039, 0x0630, NT, "SiS", "630",		enable_flash_sis540},
+	{0x1039, 0x0635, NT, "SiS", "635",		enable_flash_sis540},
+	{0x1039, 0x0640, NT, "SiS", "640",		enable_flash_sis540},
+	{0x1039, 0x0645, NT, "SiS", "645",		enable_flash_sis540},
+	{0x1039, 0x0646, NT, "SiS", "645DX",		enable_flash_sis540},
+	{0x1039, 0x0648, NT, "SiS", "648",		enable_flash_sis540},
+	{0x1039, 0x0650, NT, "SiS", "650",		enable_flash_sis540},
+	{0x1039, 0x0651, NT, "SiS", "651",		enable_flash_sis540},
+	{0x1039, 0x0655, NT, "SiS", "655",		enable_flash_sis540},
+	{0x1039, 0x0730, NT, "SiS", "730",		enable_flash_sis540},
+	{0x1039, 0x0733, NT, "SiS", "733",		enable_flash_sis540},
+	{0x1039, 0x0735, OK, "SiS", "735",		enable_flash_sis540},
+	{0x1039, 0x0740, NT, "SiS", "740",		enable_flash_sis540},
+	{0x1039, 0x0745, NT, "SiS", "745",		enable_flash_sis540},
+	{0x1039, 0x0746, NT, "SiS", "746",		enable_flash_sis540},
+	{0x1039, 0x0748, NT, "SiS", "748",		enable_flash_sis540},
+	{0x1039, 0x0755, NT, "SiS", "755",		enable_flash_sis540},
+	{0x1106, 0x8324, OK, "VIA", "CX700",		enable_flash_vt823x},
+	{0x1106, 0x8231, NT, "VIA", "VT8231",		enable_flash_vt823x},
+	{0x1106, 0x3074, NT, "VIA", "VT8233",		enable_flash_vt823x},
+	{0x1106, 0x3177, OK, "VIA", "VT8235",		enable_flash_vt823x},
+	{0x1106, 0x3227, OK, "VIA", "VT8237",		enable_flash_vt823x},
+	{0x1106, 0x3337, OK, "VIA", "VT8237A",		enable_flash_vt823x},
+	{0x1106, 0x3372, OK, "VIA", "VT8237S",		enable_flash_vt8237s_spi},
+	{0x1106, 0x8353, OK, "VIA", "VX800",		enable_flash_vt8237s_spi},
+	{0x1106, 0x0596, OK, "VIA", "VT82C596",		enable_flash_amd8111},
+	{0x1106, 0x0586, OK, "VIA", "VT82C586A/B",	enable_flash_amd8111},
+	{0x1106, 0x0686, NT, "VIA", "VT82C686A/B",	enable_flash_amd8111},
+
+	{},
+};
+
+int chipset_flash_enable(void)
+{
+	struct pci_dev *dev = 0;
+	int ret = -2;		/* Nothing! */
+	int i;
+
+	/* Now let's try to find the chipset we have... */
+	for (i = 0; chipset_enables[i].vendor_name != NULL; i++) {
+		dev = pci_dev_find(chipset_enables[i].vendor_id,
+				   chipset_enables[i].device_id);
+		if (dev)
+			break;
+	}
+
+	if (dev) {
+		printf("Found chipset \"%s %s\", enabling flash write... ",
+		       chipset_enables[i].vendor_name,
+		       chipset_enables[i].device_name);
+
+		ret = chipset_enables[i].doit(dev,
+					      chipset_enables[i].device_name);
+		if (ret)
+			printf("FAILED!\n");
+		else
+			printf("OK.\n");
+	}
+	printf("This chipset supports the following protocols: %s.\n",
+	       flashbuses_to_text(buses_supported));
+
+	return ret;
+}
diff --git a/libflashrom/drkaiser.c b/libflashrom/drkaiser.c
new file mode 100644
index 0000000..f13c13e
--- /dev/null
+++ b/libflashrom/drkaiser.c
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Joerg Fischer <turboj@web.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include "flash.h"
+
+#define PCI_VENDOR_ID_DRKAISER		0x1803
+
+#define PCI_MAGIC_DRKAISER_ADDR		0x50
+#define PCI_MAGIC_DRKAISER_VALUE	0xa971
+
+struct pcidev_status drkaiser_pcidev[] = {
+	{0x1803, 0x5057, PCI_OK, "Dr. Kaiser", "PC-Waechter (Actel FPGA)"},
+	{},
+};
+
+uint8_t *drkaiser_bar;
+
+int drkaiser_init(void)
+{
+	uint32_t addr;
+
+	get_io_perms();
+	pcidev_init(PCI_VENDOR_ID_DRKAISER, PCI_BASE_ADDRESS_2,
+		    drkaiser_pcidev, programmer_param);
+
+	/* Write magic register to enable flash write. */
+	pci_write_word(pcidev_dev, PCI_MAGIC_DRKAISER_ADDR,
+		       PCI_MAGIC_DRKAISER_VALUE);
+
+	/* TODO: Mask lower bits? How many? 3? 7? */
+	addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_2) & ~0x03;
+
+	/* Map 128KB flash memory window. */
+	drkaiser_bar = physmap("Dr. Kaiser PC-Waechter flash memory",
+			       addr, 128 * 1024);
+
+	buses_supported = CHIP_BUSTYPE_PARALLEL;
+	return 0;
+}
+
+int drkaiser_shutdown(void)
+{
+	/* Write protect the flash again. */
+	pci_write_word(pcidev_dev, PCI_MAGIC_DRKAISER_ADDR, 0);
+	free(programmer_param);
+	pci_cleanup(pacc);
+	release_io_perms();
+	return 0;
+};
+
+void drkaiser_chip_writeb(uint8_t val, chipaddr addr)
+{
+	mmio_writeb(val, drkaiser_bar + addr);
+}
+
+uint8_t drkaiser_chip_readb(const chipaddr addr)
+{
+	return mmio_readb(drkaiser_bar + addr);
+}
diff --git a/libflashrom/dummyflasher.c b/libflashrom/dummyflasher.c
new file mode 100644
index 0000000..903f88b
--- /dev/null
+++ b/libflashrom/dummyflasher.c
@@ -0,0 +1,158 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include "flash.h"
+
+int dummy_init(void)
+{
+	int i;
+	printf_debug("%s\n", __func__);
+
+	/* "all" is equivalent to specifying no type. */
+	if (programmer_param && (!strcmp(programmer_param, "all"))) {
+		free(programmer_param);
+		programmer_param = NULL;
+	}
+	if (!programmer_param)
+		programmer_param = strdup("parallel,lpc,fwh,spi");
+	/* Convert the parameters to lowercase. */
+	for (i = 0; programmer_param[i] != '\0'; i++)
+		programmer_param[i] = (char)tolower(programmer_param[i]);
+
+	buses_supported = CHIP_BUSTYPE_NONE;
+	if (strstr(programmer_param, "parallel")) {
+		buses_supported |= CHIP_BUSTYPE_PARALLEL;
+		printf_debug("Enabling support for %s flash.\n", "parallel");
+	}
+	if (strstr(programmer_param, "lpc")) {
+		buses_supported |= CHIP_BUSTYPE_LPC;
+		printf_debug("Enabling support for %s flash.\n", "LPC");
+	}
+	if (strstr(programmer_param, "fwh")) {
+		buses_supported |= CHIP_BUSTYPE_FWH;
+		printf_debug("Enabling support for %s flash.\n", "FWH");
+	}
+	if (strstr(programmer_param, "spi")) {
+		buses_supported |= CHIP_BUSTYPE_SPI;
+		spi_controller = SPI_CONTROLLER_DUMMY;
+		printf_debug("Enabling support for %s flash.\n", "SPI");
+	}
+	if (buses_supported == CHIP_BUSTYPE_NONE)
+		printf_debug("Support for all flash bus types disabled.\n");
+	free(programmer_param);
+	return 0;
+}
+
+int dummy_shutdown(void)
+{
+	printf_debug("%s\n", __func__);
+	return 0;
+}
+
+void *dummy_map(const char *descr, unsigned long phys_addr, size_t len)
+{
+	printf_debug("%s: Mapping %s, 0x%lx bytes at 0x%08lx\n",
+		__func__, descr, (unsigned long)len, phys_addr);
+	return (void *)phys_addr;
+}
+
+void dummy_unmap(void *virt_addr, size_t len)
+{
+	printf_debug("%s: Unmapping 0x%lx bytes at %p\n",
+		__func__, (unsigned long)len, virt_addr);
+}
+
+void dummy_chip_writeb(uint8_t val, chipaddr addr)
+{
+	printf_debug("%s: addr=0x%lx, val=0x%02x\n", __func__, addr, val);
+}
+
+void dummy_chip_writew(uint16_t val, chipaddr addr)
+{
+	printf_debug("%s: addr=0x%lx, val=0x%04x\n", __func__, addr, val);
+}
+
+void dummy_chip_writel(uint32_t val, chipaddr addr)
+{
+	printf_debug("%s: addr=0x%lx, val=0x%08x\n", __func__, addr, val);
+}
+
+void dummy_chip_writen(uint8_t *buf, chipaddr addr, size_t len)
+{
+	size_t i;
+	printf_debug("%s: addr=0x%lx, len=0x%08lx, writing data (hex):",
+		     __func__, addr, (unsigned long)len);
+	for (i = 0; i < len; i++) {
+		if ((i % 16) == 0)
+			printf_debug("\n");
+		printf_debug("%02x ", buf[i])
+	}
+}
+
+uint8_t dummy_chip_readb(const chipaddr addr)
+{
+	printf_debug("%s:  addr=0x%lx, returning 0xff\n", __func__, addr);
+	return 0xff;
+}
+
+uint16_t dummy_chip_readw(const chipaddr addr)
+{
+	printf_debug("%s:  addr=0x%lx, returning 0xffff\n", __func__, addr);
+	return 0xffff;
+}
+
+uint32_t dummy_chip_readl(const chipaddr addr)
+{
+	printf_debug("%s:  addr=0x%lx, returning 0xffffffff\n", __func__, addr);
+	return 0xffffffff;
+}
+
+void dummy_chip_readn(uint8_t *buf, const chipaddr addr, size_t len)
+{
+	printf_debug("%s:  addr=0x%lx, len=0x%lx, returning array of 0xff\n",
+		     __func__, addr, (unsigned long)len);
+	memset(buf, 0xff, len);
+	return;
+}
+
+int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		      const unsigned char *writearr, unsigned char *readarr)
+{
+	int i;
+
+	printf_debug("%s:", __func__);
+
+	printf_debug(" writing %u bytes:", writecnt);
+	for (i = 0; i < writecnt; i++)
+		printf_debug(" 0x%02x", writearr[i]);
+
+	printf_debug(" reading %u bytes:", readcnt);
+	for (i = 0; i < readcnt; i++) {
+		printf_debug(" 0xff");
+		readarr[i] = 0xff;
+	}
+
+	printf_debug("\n");
+	return 0;
+}
diff --git a/libflashrom/en29f002a.c b/libflashrom/en29f002a.c
new file mode 100644
index 0000000..020df32
--- /dev/null
+++ b/libflashrom/en29f002a.c
@@ -0,0 +1,89 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2007 Carl-Daniel Hailfinger
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * EN29F512 has 1C,21
+ * EN29F010 has 1C,20
+ * EN29F040A has 1C,04
+ * EN29LV010 has 1C,6E and uses short F0 reset sequence
+ * EN29LV040(A) has 1C,4F and uses short F0 reset sequence
+ */
+
+#include "flash.h"
+
+int probe_en29f512(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+	uint8_t id1, id2;
+
+	chip_writeb(0xAA, bios + 0x555);
+	chip_writeb(0x55, bios + 0x2AA);
+	chip_writeb(0x90, bios + 0x555);
+
+	programmer_delay(10);
+
+	id1 = chip_readb(bios + 0x100);
+	id2 = chip_readb(bios + 0x101);
+
+	/* exit by writing F0 anywhere? or the code below */
+	chip_writeb(0xAA, bios + 0x555);
+	chip_writeb(0x55, bios + 0x2AA);
+	chip_writeb(0xF0, bios + 0x555);
+
+	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+
+	if (id1 == flash->manufacture_id && id2 == flash->model_id)
+		return 1;
+
+	return 0;
+}
+
+/*
+ * EN29F002AT has 1C,92
+ * EN29F002AB has 1C,97
+ */
+
+/* This does not seem to function properly for EN29F002NT. */
+int probe_en29f002a(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+	uint8_t id1, id2;
+
+	chip_writeb(0xAA, bios + 0x555);
+	chip_writeb(0x55, bios + 0xAAA);
+	chip_writeb(0x90, bios + 0x555);
+
+	programmer_delay(10);
+
+	id1 = chip_readb(bios + 0x100);
+	id2 = chip_readb(bios + 0x101);
+
+	/* exit by writing F0 anywhere? or the code below */
+	chip_writeb(0xAA, bios + 0x555);
+	chip_writeb(0x55, bios + 0xAAA);
+	chip_writeb(0xF0, bios + 0x555);
+
+	printf_debug("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
+
+	if (id1 == flash->manufacture_id && id2 == flash->model_id)
+		return 1;
+
+	return 0;
+}
diff --git a/libflashrom/flash.h b/libflashrom/flash.h
new file mode 100644
index 0000000..4178d47
--- /dev/null
+++ b/libflashrom/flash.h
@@ -0,0 +1,763 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2000 Ronald G. Minnich <rminnich@gmail.com>
+ * Copyright (C) 2005-2009 coresystems GmbH
+ * Copyright (C) 2006-2009 Carl-Daniel Hailfinger
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef __FLASH_H__
+#define __FLASH_H__ 1
+
+#if defined(__GLIBC__)
+#include <sys/io.h>
+#endif
+#include <unistd.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <pci/pci.h>
+
+/* for iopl and outb under Solaris */
+#if defined (__sun) && (defined(__i386) || defined(__amd64))
+#include <strings.h>
+#include <sys/sysi86.h>
+#include <sys/psw.h>
+#include <asm/sunddi.h>
+#endif
+
+#if (defined(__MACH__) && defined(__APPLE__))
+#define __DARWIN__
+#endif
+
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+  #include <machine/cpufunc.h>
+  #define off64_t off_t
+  #define lseek64 lseek
+  #define OUTB(x, y) do { u_int tmp = (y); outb(tmp, (x)); } while (0)
+  #define OUTW(x, y) do { u_int tmp = (y); outw(tmp, (x)); } while (0)
+  #define OUTL(x, y) do { u_int tmp = (y); outl(tmp, (x)); } while (0)
+  #define INB(x) __extension__ ({ u_int tmp = (x); inb(tmp); })
+  #define INW(x) __extension__ ({ u_int tmp = (x); inw(tmp); })
+  #define INL(x) __extension__ ({ u_int tmp = (x); inl(tmp); })
+#else
+#if defined(__DARWIN__)
+    #include <DirectIO/darwinio.h>
+    #define off64_t off_t
+    #define lseek64 lseek
+#endif
+#if defined (__sun) && (defined(__i386) || defined(__amd64))
+  /* Note different order for outb */
+  #define OUTB(x,y) outb(y, x)
+  #define OUTW(x,y) outw(y, x)
+  #define OUTL(x,y) outl(y, x)
+  #define INB  inb
+  #define INW  inw
+  #define INL  inl
+#else
+  #define OUTB outb
+  #define OUTW outw
+  #define OUTL outl
+  #define INB  inb
+  #define INW  inw
+  #define INL  inl
+#endif
+#endif
+
+typedef unsigned long chipaddr;
+
+enum programmer {
+	PROGRAMMER_INTERNAL,
+#if DUMMY_SUPPORT == 1
+	PROGRAMMER_DUMMY,
+#endif
+#if NIC3COM_SUPPORT == 1
+	PROGRAMMER_NIC3COM,
+#endif
+#if GFXNVIDIA_SUPPORT == 1
+	PROGRAMMER_GFXNVIDIA,
+#endif
+#if DRKAISER_SUPPORT == 1
+	PROGRAMMER_DRKAISER,
+#endif
+#if SATASII_SUPPORT == 1
+	PROGRAMMER_SATASII,
+#endif
+	PROGRAMMER_IT87SPI,
+#if FT2232_SPI_SUPPORT == 1
+	PROGRAMMER_FT2232SPI,
+#endif
+#if SERPROG_SUPPORT == 1
+	PROGRAMMER_SERPROG,
+#endif
+#if BUSPIRATE_SPI_SUPPORT == 1
+	PROGRAMMER_BUSPIRATESPI,
+#endif
+	PROGRAMMER_INVALID /* This must always be the last entry. */
+};
+
+extern enum programmer programmer;
+
+struct programmer_entry {
+	const char *vendor;
+	const char *name;
+
+	int (*init) (void);
+	int (*shutdown) (void);
+
+	void * (*map_flash_region) (const char *descr, unsigned long phys_addr,
+				    size_t len);
+	void (*unmap_flash_region) (void *virt_addr, size_t len);
+
+	void (*chip_writeb) (uint8_t val, chipaddr addr);
+	void (*chip_writew) (uint16_t val, chipaddr addr);
+	void (*chip_writel) (uint32_t val, chipaddr addr);
+	void (*chip_writen) (uint8_t *buf, chipaddr addr, size_t len);
+	uint8_t (*chip_readb) (const chipaddr addr);
+	uint16_t (*chip_readw) (const chipaddr addr);
+	uint32_t (*chip_readl) (const chipaddr addr);
+	void (*chip_readn) (uint8_t *buf, const chipaddr addr, size_t len);
+	void (*delay) (int usecs);
+};
+
+extern const struct programmer_entry programmer_table[];
+
+int programmer_init(void);
+int programmer_shutdown(void);
+void *programmer_map_flash_region(const char *descr, unsigned long phys_addr,
+				  size_t len);
+void programmer_unmap_flash_region(void *virt_addr, size_t len);
+void chip_writeb(uint8_t val, chipaddr addr);
+void chip_writew(uint16_t val, chipaddr addr);
+void chip_writel(uint32_t val, chipaddr addr);
+void chip_writen(uint8_t *buf, chipaddr addr, size_t len);
+uint8_t chip_readb(const chipaddr addr);
+uint16_t chip_readw(const chipaddr addr);
+uint32_t chip_readl(const chipaddr addr);
+void chip_readn(uint8_t *buf, const chipaddr addr, size_t len);
+void programmer_delay(int usecs);
+
+enum bitbang_spi_master {
+	BITBANG_SPI_INVALID /* This must always be the last entry. */
+};
+
+extern const int bitbang_spi_master_count;
+
+extern enum bitbang_spi_master bitbang_spi_master;
+
+struct bitbang_spi_master_entry {
+	void (*set_cs) (int val);
+	void (*set_sck) (int val);
+	void (*set_mosi) (int val);
+	int (*get_miso) (void);
+};
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+enum chipbustype {
+	CHIP_BUSTYPE_NONE	= 0,
+	CHIP_BUSTYPE_PARALLEL	= 1 << 0,
+	CHIP_BUSTYPE_LPC	= 1 << 1,
+	CHIP_BUSTYPE_FWH	= 1 << 2,
+	CHIP_BUSTYPE_SPI	= 1 << 3,
+	CHIP_BUSTYPE_NONSPI	= CHIP_BUSTYPE_PARALLEL | CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH,
+	CHIP_BUSTYPE_UNKNOWN	= CHIP_BUSTYPE_PARALLEL | CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI,
+};
+
+/*
+ * How many different contiguous runs of erase blocks with one size each do
+ * we have for a given erase function?
+ */
+#define NUM_ERASEREGIONS 5
+
+/*
+ * How many different erase functions do we have per chip?
+ */
+#define NUM_ERASEFUNCTIONS 5
+
+struct flashchip {
+	const char *vendor;
+	const char *name;
+
+	enum chipbustype bustype;
+
+	/*
+	 * With 32bit manufacture_id and model_id we can cover IDs up to
+	 * (including) the 4th bank of JEDEC JEP106W Standard Manufacturer's
+	 * Identification code.
+	 */
+	uint32_t manufacture_id;
+	uint32_t model_id;
+
+	int total_size;
+	int page_size;
+
+	/*
+	 * Indicate if flashrom has been tested with this flash chip and if
+	 * everything worked correctly.
+	 */
+	uint32_t tested;
+
+	int (*probe) (struct flashchip *flash);
+
+	/* Delay after "enter/exit ID mode" commands in microseconds. */
+	int probe_timing;
+	int (*erase) (struct flashchip *flash);
+
+	/*
+	 * Erase blocks and associated erase function. The default entry is a
+	 * chip-sized virtual block together with the chip erase function.
+	 */
+	struct block_eraser {
+		struct eraseblock{
+			unsigned int size; /* Eraseblock size */
+			unsigned int count; /* Number of contiguous blocks with that size */
+		} eraseblocks[NUM_ERASEREGIONS];
+		int (*block_erase) (struct flashchip *flash, unsigned int blockaddr, unsigned int blocklen);
+	} block_erasers[NUM_ERASEFUNCTIONS];
+
+	int (*write) (struct flashchip *flash, uint8_t *buf);
+	int (*read) (struct flashchip *flash, uint8_t *buf, int start, int len);
+
+	/* Some flash devices have an additional register space. */
+	chipaddr virtual_memory;
+	chipaddr virtual_registers;
+};
+
+#define TEST_UNTESTED	0
+
+#define TEST_OK_PROBE	(1 << 0)
+#define TEST_OK_READ	(1 << 1)
+#define TEST_OK_ERASE	(1 << 2)
+#define TEST_OK_WRITE	(1 << 3)
+#define TEST_OK_PR	(TEST_OK_PROBE | TEST_OK_READ)
+#define TEST_OK_PRE	(TEST_OK_PROBE | TEST_OK_READ | TEST_OK_ERASE)
+#define TEST_OK_PRW	(TEST_OK_PROBE | TEST_OK_READ | TEST_OK_WRITE)
+#define TEST_OK_PREW	(TEST_OK_PROBE | TEST_OK_READ | TEST_OK_ERASE | TEST_OK_WRITE)
+#define TEST_OK_MASK	0x0f
+
+#define TEST_BAD_PROBE	(1 << 4)
+#define TEST_BAD_READ	(1 << 5)
+#define TEST_BAD_ERASE	(1 << 6)
+#define TEST_BAD_WRITE	(1 << 7)
+#define TEST_BAD_PREW	(TEST_BAD_PROBE | TEST_BAD_READ | TEST_BAD_ERASE | TEST_BAD_WRITE)
+#define TEST_BAD_MASK	0xf0
+
+/* Timing used in probe routines. ZERO is -2 to differentiate between an unset
+ * field and zero delay.
+ * 
+ * SPI devices will always have zero delay and ignore this field.
+ */
+#define TIMING_FIXME	-1
+/* this is intentionally same value as fixme */
+#define TIMING_IGNORED	-1
+#define TIMING_ZERO	-2
+
+extern struct flashchip flashchips[];
+
+struct penable {
+	uint16_t vendor_id;
+	uint16_t device_id;
+	int status;
+	const char *vendor_name;
+	const char *device_name;
+	int (*doit) (struct pci_dev *dev, const char *name);
+};
+
+extern const struct penable chipset_enables[];
+
+struct board_pciid_enable {
+	/* Any device, but make it sensible, like the ISA bridge. */
+	uint16_t first_vendor;
+	uint16_t first_device;
+	uint16_t first_card_vendor;
+	uint16_t first_card_device;
+
+	/* Any device, but make it sensible, like
+	 * the host bridge. May be NULL.
+	 */
+	uint16_t second_vendor;
+	uint16_t second_device;
+	uint16_t second_card_vendor;
+	uint16_t second_card_device;
+
+	/* The vendor / part name from the coreboot table. */
+	const char *lb_vendor;
+	const char *lb_part;
+
+	const char *vendor_name;
+	const char *board_name;
+
+	int (*enable) (const char *name);
+};
+
+extern struct board_pciid_enable board_pciid_enables[];
+
+struct board_info {
+	const char *vendor;
+	const char *name;
+};
+
+extern const struct board_info boards_ok[];
+extern const struct board_info boards_bad[];
+extern const struct board_info laptops_ok[];
+extern const struct board_info laptops_bad[];
+
+/* udelay.c */
+void myusec_delay(int usecs);
+void myusec_calibrate_delay(void);
+
+/* pcidev.c */
+#define PCI_OK 0
+#define PCI_NT 1    /* Not tested */
+
+extern uint32_t io_base_addr;
+extern struct pci_access *pacc;
+extern struct pci_filter filter;
+extern struct pci_dev *pcidev_dev;
+struct pcidev_status {
+	uint16_t vendor_id;
+	uint16_t device_id;
+	int status;
+	const char *vendor_name;
+	const char *device_name;
+};
+uint32_t pcidev_validate(struct pci_dev *dev, uint32_t bar, struct pcidev_status *devs);
+uint32_t pcidev_init(uint16_t vendor_id, uint32_t bar, struct pcidev_status *devs, char *pcidev_bdf);
+
+/* print.c */
+char *flashbuses_to_text(enum chipbustype bustype);
+void print_supported(void);
+void print_supported_pcidevs(struct pcidev_status *devs);
+void print_supported_wiki(void);
+
+/* board_enable.c */
+void w836xx_ext_enter(uint16_t port);
+void w836xx_ext_leave(uint16_t port);
+uint8_t sio_read(uint16_t port, uint8_t reg);
+void sio_write(uint16_t port, uint8_t reg, uint8_t data);
+void sio_mask(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask);
+int board_flash_enable(const char *vendor, const char *part);
+
+struct decode_sizes {
+	uint32_t parallel;
+	uint32_t lpc;
+	uint32_t fwh;
+	uint32_t spi;
+};
+
+/* chipset_enable.c */
+extern enum chipbustype buses_supported;
+int chipset_flash_enable(void);
+extern struct decode_sizes max_rom_decode;
+
+extern unsigned long flashbase;
+
+/* physmap.c */
+void *physmap(const char *descr, unsigned long phys_addr, size_t len);
+void physunmap(void *virt_addr, size_t len);
+int setup_cpu_msr(int cpu);
+void cleanup_cpu_msr(void);
+#if !defined(__DARWIN__) && !defined(__FreeBSD__) && !defined(__DragonFly__)
+typedef struct { uint32_t hi, lo; } msr_t;
+msr_t rdmsr(int addr);
+int wrmsr(int addr, msr_t msr);
+#endif
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+/* FreeBSD already has conflicting definitions for wrmsr/rdmsr. */
+#undef rdmsr
+#undef wrmsr
+#define rdmsr freebsd_rdmsr
+#define wrmsr freebsd_wrmsr
+typedef struct { uint32_t hi, lo; } msr_t;
+msr_t freebsd_rdmsr(int addr);
+int freebsd_wrmsr(int addr, msr_t msr);
+#endif
+
+/* internal.c */
+struct pci_dev *pci_dev_find_filter(struct pci_filter filter);
+struct pci_dev *pci_dev_find_vendorclass(uint16_t vendor, uint16_t class);
+struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device);
+struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device,
+			      uint16_t card_vendor, uint16_t card_device);
+void get_io_perms(void);
+void release_io_perms(void);
+int internal_init(void);
+int internal_shutdown(void);
+void internal_chip_writeb(uint8_t val, chipaddr addr);
+void internal_chip_writew(uint16_t val, chipaddr addr);
+void internal_chip_writel(uint32_t val, chipaddr addr);
+uint8_t internal_chip_readb(const chipaddr addr);
+uint16_t internal_chip_readw(const chipaddr addr);
+uint32_t internal_chip_readl(const chipaddr addr);
+void internal_chip_readn(uint8_t *buf, const chipaddr addr, size_t len);
+void mmio_writeb(uint8_t val, void *addr);
+void mmio_writew(uint16_t val, void *addr);
+void mmio_writel(uint32_t val, void *addr);
+uint8_t mmio_readb(void *addr);
+uint16_t mmio_readw(void *addr);
+uint32_t mmio_readl(void *addr);
+void internal_delay(int usecs);
+int noop_shutdown(void);
+void *fallback_map(const char *descr, unsigned long phys_addr, size_t len);
+void fallback_unmap(void *virt_addr, size_t len);
+uint8_t noop_chip_readb(const chipaddr addr);
+void noop_chip_writeb(uint8_t val, chipaddr addr);
+void fallback_chip_writew(uint16_t val, chipaddr addr);
+void fallback_chip_writel(uint32_t val, chipaddr addr);
+void fallback_chip_writen(uint8_t *buf, chipaddr addr, size_t len);
+uint16_t fallback_chip_readw(const chipaddr addr);
+uint32_t fallback_chip_readl(const chipaddr addr);
+void fallback_chip_readn(uint8_t *buf, const chipaddr addr, size_t len);
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+extern int io_fd;
+#endif
+
+/* dummyflasher.c */
+int dummy_init(void);
+int dummy_shutdown(void);
+void *dummy_map(const char *descr, unsigned long phys_addr, size_t len);
+void dummy_unmap(void *virt_addr, size_t len);
+void dummy_chip_writeb(uint8_t val, chipaddr addr);
+void dummy_chip_writew(uint16_t val, chipaddr addr);
+void dummy_chip_writel(uint32_t val, chipaddr addr);
+void dummy_chip_writen(uint8_t *buf, chipaddr addr, size_t len);
+uint8_t dummy_chip_readb(const chipaddr addr);
+uint16_t dummy_chip_readw(const chipaddr addr);
+uint32_t dummy_chip_readl(const chipaddr addr);
+void dummy_chip_readn(uint8_t *buf, const chipaddr addr, size_t len);
+int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		      const unsigned char *writearr, unsigned char *readarr);
+
+/* nic3com.c */
+int nic3com_init(void);
+int nic3com_shutdown(void);
+void nic3com_chip_writeb(uint8_t val, chipaddr addr);
+uint8_t nic3com_chip_readb(const chipaddr addr);
+extern struct pcidev_status nics_3com[];
+
+/* gfxnvidia.c */
+int gfxnvidia_init(void);
+int gfxnvidia_shutdown(void);
+void gfxnvidia_chip_writeb(uint8_t val, chipaddr addr);
+uint8_t gfxnvidia_chip_readb(const chipaddr addr);
+extern struct pcidev_status gfx_nvidia[];
+
+/* drkaiser.c */
+int drkaiser_init(void);
+int drkaiser_shutdown(void);
+void drkaiser_chip_writeb(uint8_t val, chipaddr addr);
+uint8_t drkaiser_chip_readb(const chipaddr addr);
+extern struct pcidev_status drkaiser_pcidev[];
+
+/* satasii.c */
+int satasii_init(void);
+int satasii_shutdown(void);
+void satasii_chip_writeb(uint8_t val, chipaddr addr);
+uint8_t satasii_chip_readb(const chipaddr addr);
+extern struct pcidev_status satas_sii[];
+
+/* ft2232_spi.c */
+#define FTDI_FT2232H 0x6010
+#define FTDI_FT4232H 0x6011
+int ft2232_spi_init(void);
+int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
+int ft2232_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
+int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf);
+
+/* bitbang_spi.c */
+extern int bitbang_spi_half_period;
+extern const struct bitbang_spi_master_entry bitbang_spi_master_table[];
+int bitbang_spi_init(void);
+int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
+int bitbang_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
+int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf);
+
+/* buspirate_spi.c */
+struct buspirate_spispeeds {
+	const char *name;
+	const int speed;
+};
+int buspirate_spi_init(void);
+int buspirate_spi_shutdown(void);
+int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
+int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
+
+/* flashrom.c */
+extern char *programmer_param;
+extern int verbose;
+extern const char *flashrom_version;
+#define printf_debug(x...) { if (verbose) printf(x); }
+void map_flash_registers(struct flashchip *flash);
+int read_memmapped(struct flashchip *flash, uint8_t *buf, int start, int len);
+int erase_flash(struct flashchip *flash);
+int min(int a, int b);
+int max(int a, int b);
+char *extract_param(char **haystack, char *needle, char *delim);
+int check_erased_range(struct flashchip *flash, int start, int len);
+int verify_range(struct flashchip *flash, uint8_t *cmpbuf, int start, int len, char *message);
+char *strcat_realloc(char *dest, const char *src);
+
+#define OK 0
+#define NT 1    /* Not tested */
+
+/* layout.c */
+int show_id(uint8_t *bios, int size, int force);
+int read_romlayout(char *name);
+int find_romentry(char *name);
+int handle_romentries(uint8_t *buffer, struct flashchip *flash);
+
+/* cbtable.c */
+int coreboot_init(void);
+extern char *lb_part, *lb_vendor;
+extern int partvendor_from_cbtable;
+
+/* spi.c */
+enum spi_controller {
+	SPI_CONTROLLER_NONE,
+	SPI_CONTROLLER_ICH7,
+	SPI_CONTROLLER_ICH9,
+	SPI_CONTROLLER_IT87XX,
+	SPI_CONTROLLER_SB600,
+	SPI_CONTROLLER_VIA,
+	SPI_CONTROLLER_WBSIO,
+#if FT2232_SPI_SUPPORT == 1
+	SPI_CONTROLLER_FT2232,
+#endif
+#if DUMMY_SUPPORT == 1
+	SPI_CONTROLLER_DUMMY,
+#endif
+#if BUSPIRATE_SPI_SUPPORT == 1
+	SPI_CONTROLLER_BUSPIRATE,
+#endif
+	SPI_CONTROLLER_INVALID /* This must always be the last entry. */
+};
+extern const int spi_programmer_count;
+struct spi_command {
+	unsigned int writecnt;
+	unsigned int readcnt;
+	const unsigned char *writearr;
+	unsigned char *readarr;
+};
+struct spi_programmer {
+	int (*command)(unsigned int writecnt, unsigned int readcnt,
+		   const unsigned char *writearr, unsigned char *readarr);
+	int (*multicommand)(struct spi_command *cmds);
+
+	/* Optimized functions for this programmer */
+	int (*read)(struct flashchip *flash, uint8_t *buf, int start, int len);
+	int (*write_256)(struct flashchip *flash, uint8_t *buf);
+};
+
+extern enum spi_controller spi_controller;
+extern const struct spi_programmer spi_programmer[];
+extern void *spibar;
+int probe_spi_rdid(struct flashchip *flash);
+int probe_spi_rdid4(struct flashchip *flash);
+int probe_spi_rems(struct flashchip *flash);
+int probe_spi_res(struct flashchip *flash);
+int spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		const unsigned char *writearr, unsigned char *readarr);
+int spi_send_multicommand(struct spi_command *cmds);
+int spi_write_enable(void);
+int spi_write_disable(void);
+int spi_chip_erase_60(struct flashchip *flash);
+int spi_chip_erase_c7(struct flashchip *flash);
+int spi_chip_erase_60_c7(struct flashchip *flash);
+int spi_chip_erase_d8(struct flashchip *flash);
+int spi_block_erase_20(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_52(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_d8(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_60(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_c7(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
+int spi_chip_write_1(struct flashchip *flash, uint8_t *buf);
+int spi_chip_write_256(struct flashchip *flash, uint8_t *buf);
+int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len);
+uint8_t spi_read_status_register(void);
+int spi_disable_blockprotect(void);
+int spi_byte_program(int addr, uint8_t byte);
+int spi_nbyte_program(int addr, uint8_t *bytes, int len);
+int spi_nbyte_read(int addr, uint8_t *bytes, int len);
+int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize);
+int spi_aai_write(struct flashchip *flash, uint8_t *buf);
+uint32_t spi_get_valid_read_addr(void);
+int default_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+			     const unsigned char *writearr, unsigned char *readarr);
+int default_spi_send_multicommand(struct spi_command *cmds);
+
+/* 82802ab.c */
+int probe_82802ab(struct flashchip *flash);
+int erase_82802ab(struct flashchip *flash);
+int write_82802ab(struct flashchip *flash, uint8_t *buf);
+
+/* am29f040b.c */
+int probe_29f040b(struct flashchip *flash);
+int erase_29f040b(struct flashchip *flash);
+int write_29f040b(struct flashchip *flash, uint8_t *buf);
+
+/* pm29f002.c */
+int write_pm29f002(struct flashchip *flash, uint8_t *buf);
+
+/* en29f002a.c */
+int probe_en29f002a(struct flashchip *flash);
+int erase_en29f002a(struct flashchip *flash);
+int write_en29f002a(struct flashchip *flash, uint8_t *buf);
+
+/* ichspi.c */
+int ich_init_opcodes(void);
+int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		    const unsigned char *writearr, unsigned char *readarr);
+int ich_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
+int ich_spi_write_256(struct flashchip *flash, uint8_t * buf);
+int ich_spi_send_multicommand(struct spi_command *cmds);
+
+/* it87spi.c */
+extern uint16_t it8716f_flashport;
+void enter_conf_mode_ite(uint16_t port);
+void exit_conf_mode_ite(uint16_t port);
+int it87spi_init(void);
+int it87xx_probe_spi_flash(const char *name);
+int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+			const unsigned char *writearr, unsigned char *readarr);
+int it8716f_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len);
+int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf);
+
+/* sb600spi.c */
+int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		      const unsigned char *writearr, unsigned char *readarr);
+int sb600_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
+int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf);
+extern uint8_t *sb600_spibar;
+
+/* jedec.c */
+uint8_t oddparity(uint8_t val);
+void toggle_ready_jedec(chipaddr dst);
+void data_polling_jedec(chipaddr dst, uint8_t data);
+void start_program_jedec(chipaddr bios);
+int write_byte_program_jedec(chipaddr bios, uint8_t *src,
+			     chipaddr dst);
+int probe_jedec(struct flashchip *flash);
+int erase_chip_jedec(struct flashchip *flash);
+int write_jedec(struct flashchip *flash, uint8_t *buf);
+int write_jedec_1(struct flashchip *flash, uint8_t *buf);
+int erase_sector_jedec(struct flashchip *flash, unsigned int page, unsigned int pagesize);
+int erase_block_jedec(struct flashchip *flash, unsigned int page, unsigned int blocksize);
+int write_sector_jedec(chipaddr bios, uint8_t *src,
+		       chipaddr dst, unsigned int page_size);
+
+/* m29f002.c */
+int erase_m29f002(struct flashchip *flash);
+int write_m29f002t(struct flashchip *flash, uint8_t *buf);
+int write_m29f002b(struct flashchip *flash, uint8_t *buf);
+
+/* m29f400bt.c */
+int probe_m29f400bt(struct flashchip *flash);
+int erase_m29f400bt(struct flashchip *flash);
+int block_erase_m29f400bt(struct flashchip *flash, int start, int len);
+int write_m29f400bt(struct flashchip *flash, uint8_t *buf);
+int write_coreboot_m29f400bt(struct flashchip *flash, uint8_t *buf);
+void toggle_ready_m29f400bt(chipaddr dst);
+void data_polling_m29f400bt(chipaddr dst, uint8_t data);
+void protect_m29f400bt(chipaddr bios);
+void write_page_m29f400bt(chipaddr bios, uint8_t *src,
+			  chipaddr dst, int page_size);
+
+/* mx29f002.c */
+int probe_29f002(struct flashchip *flash);
+int erase_29f002(struct flashchip *flash);
+int write_29f002(struct flashchip *flash, uint8_t *buf);
+
+/* pm49fl00x.c */
+int probe_49fl00x(struct flashchip *flash);
+int erase_49fl00x(struct flashchip *flash);
+int write_49fl00x(struct flashchip *flash, uint8_t *buf);
+
+/* sharplhf00l04.c */
+int probe_lhf00l04(struct flashchip *flash);
+int erase_lhf00l04(struct flashchip *flash);
+int write_lhf00l04(struct flashchip *flash, uint8_t *buf);
+void toggle_ready_lhf00l04(chipaddr dst);
+void data_polling_lhf00l04(chipaddr dst, uint8_t data);
+void protect_lhf00l04(chipaddr bios);
+
+/* sst28sf040.c */
+int probe_28sf040(struct flashchip *flash);
+int erase_28sf040(struct flashchip *flash);
+int write_28sf040(struct flashchip *flash, uint8_t *buf);
+
+/* sst39sf020.c */
+int probe_39sf020(struct flashchip *flash);
+int write_39sf020(struct flashchip *flash, uint8_t *buf);
+
+/* sst49lf040.c */
+int erase_49lf040(struct flashchip *flash);
+int write_49lf040(struct flashchip *flash, uint8_t *buf);
+
+/* sst49lfxxxc.c */
+int probe_49lfxxxc(struct flashchip *flash);
+int erase_49lfxxxc(struct flashchip *flash);
+int write_49lfxxxc(struct flashchip *flash, uint8_t *buf);
+
+/* sst_fwhub.c */
+int probe_sst_fwhub(struct flashchip *flash);
+int erase_sst_fwhub(struct flashchip *flash);
+int erase_sst_fwhub_block(struct flashchip *flash, unsigned int offset, unsigned int page_size);
+int write_sst_fwhub(struct flashchip *flash, uint8_t *buf);
+
+/* w39v040c.c */
+int probe_w39v040c(struct flashchip *flash);
+int erase_w39v040c(struct flashchip *flash);
+int write_w39v040c(struct flashchip *flash, uint8_t *buf);
+
+/* w39V080fa.c */
+int probe_winbond_fwhub(struct flashchip *flash);
+int erase_winbond_fwhub(struct flashchip *flash);
+int write_winbond_fwhub(struct flashchip *flash, uint8_t *buf);
+
+/* w29ee011.c */
+int probe_w29ee011(struct flashchip *flash);
+
+/* w49f002u.c */
+int write_49f002(struct flashchip *flash, uint8_t *buf);
+
+/* wbsio_spi.c */
+int wbsio_check_for_spi(const char *name);
+int wbsio_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		      const unsigned char *writearr, unsigned char *readarr);
+int wbsio_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
+int wbsio_spi_write_1(struct flashchip *flash, uint8_t *buf);
+
+/* stm50flw0x0x.c */
+int probe_stm50flw0x0x(struct flashchip *flash);
+int erase_stm50flw0x0x(struct flashchip *flash);
+int write_stm50flw0x0x(struct flashchip *flash, uint8_t *buf);
+
+/* serprog.c */
+int serprog_init(void);
+int serprog_shutdown(void);
+void serprog_chip_writeb(uint8_t val, chipaddr addr);
+uint8_t serprog_chip_readb(const chipaddr addr);
+void serprog_chip_readn(uint8_t *buf, const chipaddr addr, size_t len);
+void serprog_delay(int delay);
+
+/* serial.c */
+void sp_flush_incoming(void);
+int sp_openserport(char *dev, unsigned int baud);
+void __attribute__((noreturn)) sp_die(char *msg);
+extern int sp_fd;
+
+#endif				/* !__FLASH_H__ */
diff --git a/libflashrom/flashchips.c b/libflashrom/flashchips.c
new file mode 100644
index 0000000..5e74ccf
--- /dev/null
+++ b/libflashrom/flashchips.c
@@ -0,0 +1,3435 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2004 Tyan Corp
+ * Copyright (C) 2005-2008 coresystems GmbH <stepan@openbios.org>
+ * Copyright (C) 2006-2009 Carl-Daniel Hailfinger
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+#include "flashchips.h"
+
+/**
+ * List of supported flash chips.
+ *
+ * Please keep the list sorted by vendor name and chip name, so that
+ * the output of 'flashrom -L' is alphabetically sorted.
+ */
+struct flashchip flashchips[] = {
+
+	/*
+	 * .vendor		= Vendor name
+	 * .name		= Chip name
+	 * .bustype		= Supported flash bus types (Parallel, LPC...)
+	 * .manufacture_id	= Manufacturer chip ID
+	 * .model_id		= Model chip ID
+	 * .total_size		= Total size in (binary) kbytes
+	 * .page_size		= Page or eraseblock(?) size in bytes
+	 * .tested		= Test status
+	 * .probe		= Probe function
+	 * .probe_timing	= Probe function delay
+	 * .erase		= Chip erase function
+	 * .block_erasers[]	= Array of erase layouts and erase functions
+	 * {
+	 *	.eraseblocks[]	= Array of { blocksize, blockcount }
+	 *	.block_erase	= Block erase function
+	 * }
+	 * .write		= Chip write function
+	 * .read		= Chip read function
+	 */
+
+	{
+		.vendor		= "AMD",
+		.name		= "Am29F010A/B",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= AMD_ID,
+		.model_id	= AM_29F010B,	/* Same as Am29F010A */
+		.total_size	= 128,
+		.page_size	= 16 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_29f040b,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= erase_29f040b,
+		.write		= write_pm29f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "AMD",
+		.name		= "Am29F002(N)BB",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= AMD_ID,
+		.model_id	= AM_29F002BB,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "AMD",
+		.name		= "Am29F002(N)BT",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= AMD_ID,
+		.model_id	= AM_29F002BT,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_OK_PRE,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "AMD",
+		.name		= "Am29F016D",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= AMD_ID,
+		.model_id	= AM_29F016D,
+		.total_size	= 2048,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_29f040b,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */
+		.erase		= erase_29f040b,
+		.write		= write_29f040b,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "AMD",
+		.name		= "Am29F040B",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= AMD_ID,
+		.model_id	= AM_29F040B,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_29f040b,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */
+		.erase		= erase_29f040b,
+		.write		= write_29f040b,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "AMD",
+		.name		= "Am29F080B",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= AMD_ID,
+		.model_id	= AM_29F080B,
+		.total_size	= 1024,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= erase_29f040b,
+		.write		= write_29f040b,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "AMD",
+		.name		= "Am29LV040B",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= AMD_ID,
+		.model_id	= AM_29LV040B,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_29f040b,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */
+		.erase		= erase_29f040b,
+		.write		= write_29f040b,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "AMD",
+		.name		= "Am29LV081B",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= AMD_ID,
+		.model_id	= AM_29LV080B,
+		.total_size	= 1024,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_29f040b,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */
+		.erase		= erase_29f040b,
+		.write		= write_29f040b,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "ASD",
+		.name		= "AE49F2008",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= ASD_ID,
+		.model_id	= ASD_AE49F2008,
+		.total_size	= 256,
+		.page_size	= 128,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_FIXME, 
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT25DF021",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_25DF021,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT25DF041A",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_25DF041A,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT25DF081",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_25DF081,
+		.total_size	= 1024,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT25DF161",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_25DF161,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT25DF321",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_25DF321,
+		.total_size	= 4096,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT25DF321A",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_25DF321A,
+		.total_size	= 4096,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT25DF641",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_25DF641,
+		.total_size	= 8192,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT25F512B",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_25F512B,
+		.total_size	= 64,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT25FS010",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_25FS010,
+		.total_size	= 128,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT25FS040",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_25FS040,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT26DF041",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_26DF041,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL /* Incompatible Page write */,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT26DF081A",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_26DF081A,
+		.total_size	= 1024,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT26DF161",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_26DF161,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT26DF161A",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_26DF161A,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	/*The AT26DF321 has the same ID as the AT25DF321. */
+	/*{
+		.vendor		= "Atmel",
+		.name		= "AT26DF321",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_26DF321,
+		.total_size	= 4096,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	  },*/
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT26F004",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_26F004,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= NULL /* Incompatible Page write */,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT29C512",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_29C512,
+		.total_size	= 64,
+		.page_size	= 128,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec, 
+		.probe_timing	= 10000, /* 10mS, Enter=Exec */
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec,
+		.read		= read_memmapped,
+
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT29C010A",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_29C010A,
+		.total_size	= 128,
+		.page_size	= 128,
+		.tested		= TEST_OK_PRE,
+		.probe		= probe_jedec,
+		.probe_timing	= 10000, /* 10mS, Enter=Exec */
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec,	/* FIXME */
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT29C020",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_29C020,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 10000,			/* 10ms */ 
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT29C040A",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_29C040A,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= 10000,			/* 10 ms */
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45CS1282",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_45CS1282,
+		.total_size	= 16896 /* No power of two sizes */,
+		.page_size	= 1056 /* No power of two sizes */,
+		.tested		= TEST_BAD_READ,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL /* Incompatible Page write */,
+		.read		= NULL /* Incompatible read */,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45DB011D",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_45DB011D,
+		.total_size	= 128 /* Size can only be determined from status register */,
+		.page_size	= 256 /* Size can only be determined from status register */,
+		.tested		= TEST_BAD_READ,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= NULL,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45DB021D",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_45DB021D,
+		.total_size	= 256 /* Size can only be determined from status register */,
+		.page_size	= 256 /* Size can only be determined from status register */,
+		.tested		= TEST_BAD_READ,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= NULL,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45DB041D",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_45DB041D,
+		.total_size	= 512 /* Size can only be determined from status register */,
+		.page_size	= 256 /* Size can only be determined from status register */,
+		.tested		= TEST_BAD_READ,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= NULL,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45DB081D",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_45DB081D,
+		.total_size	= 1024 /* Size can only be determined from status register */,
+		.page_size	= 256 /* Size can only be determined from status register */,
+		.tested		= TEST_BAD_READ,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= NULL,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45DB161D",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_45DB161D,
+		.total_size	= 2048 /* Size can only be determined from status register */,
+		.page_size	= 512 /* Size can only be determined from status register */,
+		.tested		= TEST_BAD_READ,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= NULL,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45DB321C",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_45DB321C,
+		.total_size	= 4224 /* No power of two sizes */,
+		.page_size	= 528 /* No power of two sizes */,
+		.tested		= TEST_BAD_READ,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= NULL /* Incompatible read */,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45DB321D",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_45DB321D,
+		.total_size	= 4096 /* Size can only be determined from status register */,
+		.page_size	= 512 /* Size can only be determined from status register */,
+		.tested		= TEST_BAD_READ,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= NULL,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45DB642D",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_45DB642D,
+		.total_size	= 8192 /* Size can only be determined from status register */,
+		.page_size	= 1024 /* Size can only be determined from status register */,
+		.tested		= TEST_BAD_READ,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= NULL,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT49BV512",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_49BV512,
+		.total_size	= 64,
+		.page_size	= 64,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT49F002(N)",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_49F002N,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT49F002(N)T",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= AT_49F002NT,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "AMIC",
+		.name		= "A25L40P",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= AMIC_ID,
+		.model_id	= AMIC_A25L40P,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_spi_rdid4,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "AMIC",
+		.name		= "A29002B",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= AMIC_ID_NOPREFIX,
+		.model_id	= AMIC_A29002B,
+		.total_size	= 256,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_29f002,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */
+		.erase		= erase_29f002,
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "AMIC",
+		.name		= "A29002T",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= AMIC_ID_NOPREFIX,
+		.model_id	= AMIC_A29002T,
+		.total_size	= 256,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PRE,
+		.probe		= probe_29f002,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */
+		.erase		= erase_29f002,
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "AMIC",
+		.name		= "A29040B",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= AMIC_ID_NOPREFIX,
+		.model_id	= AMIC_A29040B,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PR,
+		.probe		= probe_29f040b,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */
+		.erase		= erase_29f040b,
+		.write		= write_29f040b,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "AMIC",
+		.name		= "A49LF040A",
+		.bustype	= CHIP_BUSTYPE_LPC,
+		.manufacture_id	= AMIC_ID_NOPREFIX,
+		.model_id	= AMIC_A49LF040A,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_49fl00x,
+		.probe_timing	= TIMING_ZERO,	/* routine is wrapper to probe_jedec (pm49fl00x.c) */
+		.erase		= erase_49fl00x,
+		.write		= write_49fl00x,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "EMST",
+		.name		= "F49B002UA",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= EMST_ID,
+		.model_id	= EMST_F49B002UA,
+		.total_size	= 256,
+		.page_size	= 4096,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25B05",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EN_25B05,
+		.total_size	= 64,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25B10",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EN_25B10,
+		.total_size	= 128,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25B20",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EN_25B20,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25B40",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EN_25B40,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25B80",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EN_25B80,
+		.total_size	= 1024,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25B16",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EN_25B16,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25B32",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EN_25B32,
+		.total_size	= 4096,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25B64",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EN_25B64,
+		.total_size	= 8192,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25D16",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EN_25D16,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25F05",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EN_25F05,
+		.total_size	= 64,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25F10",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EN_25F10,
+		.total_size	= 128,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25F20",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EN_25F20,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25F40",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EN_25F40,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_OK_PROBE,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25F80",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EN_25F80,
+		.total_size	= 1024,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25F16",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EN_25F16,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25F32",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EN_25F32,
+		.total_size	= 4096,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "EON",
+		.name		= "EN29F002(A)(N)B",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= EON_ID,
+		.model_id	= EN_29F002B,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "EON",
+		.name		= "EN29F002(A)(N)T",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= EON_ID,
+		.model_id	= EN_29F002T,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_OK_PRE,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Fujitsu",
+		.name		= "MBM29F004BC",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= FUJITSU_ID,
+		.model_id	= MBM29F004BC,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Fujitsu",
+		.name		= "MBM29F004TC",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= FUJITSU_ID,
+		.model_id	= MBM29F004TC,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Fujitsu",
+		.name		= "MBM29F400BC",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= FUJITSU_ID,
+		.model_id	= MBM29F400BC,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_m29f400bt,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (m29f400bt.c) */
+		.erase		= erase_m29f400bt,
+		.write		= write_coreboot_m29f400bt,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Fujitsu",
+		.name		= "MBM29F400TC",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= FUJITSU_ID,
+		.model_id	= MBM29F400TC,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_m29f400bt,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (m29f400bt.c) */
+		.erase		= erase_m29f400bt,
+		.write		= write_coreboot_m29f400bt,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Intel",
+		.name		= "28F001BX-B",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= INTEL_ID,
+		.model_id	= P28F001BXB,
+		.total_size	= 128,
+		.page_size	= 128 * 1024, /* 8k + 2x4k + 112k */
+		.tested		= TEST_BAD_ERASE|TEST_BAD_WRITE,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Intel",
+		.name		= "28F001BX-T",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= INTEL_ID,
+		.model_id	= P28F001BXT,
+		.total_size	= 128,
+		.page_size	= 128 * 1024, /* 112k + 2x4k + 8k */
+		.tested		= TEST_OK_PR|TEST_BAD_ERASE|TEST_BAD_WRITE,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Intel",
+		.name		= "82802AB",
+		.bustype	= CHIP_BUSTYPE_FWH,
+		.manufacture_id	= INTEL_ID,
+		.model_id	= I_82802AB,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_82802ab,
+		.probe_timing	= TIMING_IGNORED, /* routine does not use probe_timing (82802ab.c) */
+		.erase		= erase_82802ab,
+		.write		= write_82802ab,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Intel",
+		.name		= "82802AC",
+		.bustype	= CHIP_BUSTYPE_FWH,
+		.manufacture_id	= INTEL_ID,
+		.model_id	= I_82802AC,
+		.total_size	= 1024,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_82802ab,
+		.probe_timing	= TIMING_IGNORED, /* routine does not use probe_timing (82802ab.c) */
+		.erase		= erase_82802ab,
+		.write		= write_82802ab,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX25L512",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= MX_ID,
+		.model_id	= MX_25L512,
+		.total_size	= 64,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {4 * 1024, 16} },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { {64 * 1024, 1} },
+				.block_erase = spi_block_erase_52,
+			}, {
+				.eraseblocks = { {64 * 1024, 1} },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { {64 * 1024, 1} },
+				.block_erase = spi_block_erase_60,
+			}, {
+				.eraseblocks = { {64 * 1024, 1} },
+				.block_erase = spi_block_erase_c7,
+			},
+		},
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX25L1005",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= MX_ID,
+		.model_id	= MX_25L1005,
+		.total_size	= 128,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {4 * 1024, 32} },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { {64 * 1024, 2} },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { {128 * 1024, 1} },
+				.block_erase = spi_block_erase_60,
+			}, {
+				.eraseblocks = { {128 * 1024, 1} },
+				.block_erase = spi_block_erase_c7,
+			},
+		},
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX25L2005",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= MX_ID,
+		.model_id	= MX_25L2005,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {4 * 1024, 64} },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { {64 * 1024, 4} },
+				.block_erase = spi_block_erase_52,
+			}, {
+				.eraseblocks = { {64 * 1024, 4} },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { {256 * 1024, 1} },
+				.block_erase = spi_block_erase_60,
+			}, {
+				.eraseblocks = { {256 * 1024, 1} },
+				.block_erase = spi_block_erase_c7,
+			},
+		},
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX25L4005",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= MX_ID,
+		.model_id	= MX_25L4005,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_OK_PRW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {4 * 1024, 128} },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { {64 * 1024, 8} },
+				.block_erase = spi_block_erase_52,
+			}, {
+				.eraseblocks = { {64 * 1024, 8} },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { {512 * 1024, 1} },
+				.block_erase = spi_block_erase_60,
+			}, {
+				.eraseblocks = { {512 * 1024, 1} },
+				.block_erase = spi_block_erase_c7,
+			},
+		},
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX25L8005",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= MX_ID,
+		.model_id	= MX_25L8005,
+		.total_size	= 1024,
+		.page_size	= 256,
+		.tested		= TEST_OK_PRW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {4 * 1024, 256} },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { {64 * 1024, 16} },
+				.block_erase = spi_block_erase_52,
+			}, {
+				.eraseblocks = { {64 * 1024, 16} },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { {1024 * 1024, 1} },
+				.block_erase = spi_block_erase_60,
+			}, {
+				.eraseblocks = { {1024 * 1024, 1} },
+				.block_erase = spi_block_erase_c7,
+			},
+		},
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX25L1605",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= MX_ID,
+		.model_id	= MX_25L1605,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.tested		= TEST_OK_PRW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {4 * 1024, 512} },
+				.block_erase = spi_block_erase_20,	/* This erase function has 64k blocksize for eLiteFlash */
+			}, {
+				.eraseblocks = { {64 * 1024, 32} },	/* Not supported in MX25L1605 (eLiteFlash) and MX25L1605D */
+				.block_erase = spi_block_erase_52,
+			}, {
+				.eraseblocks = { {64 * 1024, 32} },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { {2 * 1024 * 1024, 1} },
+				.block_erase = spi_block_erase_60,
+			}, {
+				.eraseblocks = { {2 * 1024 * 1024, 1} },
+				.block_erase = spi_block_erase_c7,
+			},
+		},
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX25L1635D",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= MX_ID,
+		.model_id	= MX_25L1635D,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX25L3205",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= MX_ID,
+		.model_id	= MX_25L3205,
+		.total_size	= 4096,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX25L3235D",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= MX_ID,
+		.model_id	= MX_25L3235D,
+		.total_size	= 4096,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX25L6405",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= MX_ID,
+		.model_id	= MX_25L6405,
+		.total_size	= 8192,
+		.page_size	= 256,
+		.tested		= TEST_OK_PROBE,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX25L12805",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= MX_ID,
+		.model_id	= MX_25L12805,
+		.total_size	= 16384,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX29F001B",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= MX_ID,
+		.model_id	= MX_29F001B,
+		.total_size	= 128,
+		.page_size	= 32 * 1024,
+		.tested		= TEST_OK_PRE,
+		.probe		= probe_29f002,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */
+		.erase		= erase_29f002,
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX29F001T",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= MX_ID,
+		.model_id	= MX_29F001T,
+		.total_size	= 128,
+		.page_size	= 32 * 1024,
+		.tested		= TEST_OK_PRE,
+		.probe		= probe_29f002,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */
+		.erase		= erase_29f002,
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX29F002B",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= MX_ID,
+		.model_id	= MX_29F002B,
+		.total_size	= 256,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_29f002,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */
+		.erase		= erase_29f002,
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX29F002T",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= MX_ID,
+		.model_id	= MX_29F002T,
+		.total_size	= 256,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PRE,
+		.probe		= probe_29f002,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */
+		.erase		= erase_29f002,
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX29LV040",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= MX_ID,
+		.model_id	= MX_29LV040,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PR,
+		.probe		= probe_29f002,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */
+		.erase		= erase_29f002,
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Numonyx",
+		.name		= "M25PE10",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25PE10,
+		.total_size	= 128,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_d8,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Numonyx",
+		.name		= "M25PE20",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25PE20,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_d8,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Numonyx",
+		.name		= "M25PE40",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25PE40,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_d8,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Numonyx",
+		.name		= "M25PE80",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25PE80,
+		.total_size	= 1024,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_d8,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Numonyx",
+		.name		= "M25PE16",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25PE16,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_d8,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "PMC",
+		.name		= "Pm25LV010",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= PMC_ID,
+		.model_id	= PMC_25LV010,
+		.total_size	= 128,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "PMC",
+		.name		= "Pm25LV016B",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= PMC_ID,
+		.model_id	= PMC_25LV016B,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "PMC",
+		.name		= "Pm25LV020",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= PMC_ID,
+		.model_id	= PMC_25LV020,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "PMC",
+		.name		= "Pm25LV040",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= PMC_ID,
+		.model_id	= PMC_25LV040,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "PMC",
+		.name		= "Pm25LV080B",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= PMC_ID,
+		.model_id	= PMC_25LV080B,
+		.total_size	= 1024,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "PMC",
+		.name		= "Pm25LV512",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= PMC_ID,
+		.model_id	= PMC_25LV512,
+		.total_size	= 64,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "PMC",
+		.name		= "Pm29F0002T",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= PMC_ID_NOPREFIX,
+		.model_id	= PMC_29F002T,
+		.total_size	= 256,
+		.page_size	= 8192,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_29f040b,
+		.probe_timing	= TIMING_FIXME, 
+		.erase		= erase_29f040b,
+		.write		= write_pm29f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "PMC",
+		.name		= "Pm29F0002B",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= PMC_ID_NOPREFIX,
+		.model_id	= PMC_29F002B,
+		.total_size	= 256,
+		.page_size	= 8192,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_29f040b,
+		.probe_timing	= TIMING_FIXME, 
+		.erase		= erase_29f040b,
+		.write		= write_pm29f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "PMC",
+		.name		= "Pm39LV010",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= PMC_ID_NOPREFIX,
+		.model_id	= PMC_39F010,
+		.total_size	= 128,
+		.page_size	= 4096,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "PMC",
+		.name		= "Pm49FL002",
+		.bustype	= CHIP_BUSTYPE_LPC|CHIP_BUSTYPE_FWH, /* A/A Mux*/
+		.manufacture_id	= PMC_ID_NOPREFIX,
+		.model_id	= PMC_49FL002,
+		.total_size	= 256,
+		.page_size	= 16 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_49fl00x,
+		.probe_timing	= TIMING_ZERO,	/* routine is wrapper to probe_jedec (pm49fl00x.c) */
+		.erase		= erase_49fl00x,
+		.write		= write_49fl00x,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "PMC",
+		.name		= "Pm49FL004",
+		.bustype	= CHIP_BUSTYPE_LPC|CHIP_BUSTYPE_FWH, /* A/A Mux*/
+		.manufacture_id	= PMC_ID_NOPREFIX,
+		.model_id	= PMC_49FL004,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_49fl00x,
+		.probe_timing	= TIMING_ZERO,	/* routine is wrapper to probe_jedec (pm49fl00x.c) */
+		.erase		= erase_49fl00x,
+		.write		= write_49fl00x,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Sanyo",
+		.name		= "LF25FW203A",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= SANYO_ID,
+		.model_id	= SANYO_LE25FW203A,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Sharp",
+		.name		= "LHF00L04",
+		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
+		.manufacture_id	= SHARP_ID,
+		.model_id	= SHARP_LHF00L04,
+		.total_size	= 1024,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_lhf00l04,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (sharplhf00l04.c) */
+		.erase		= erase_lhf00l04,
+		.write		= write_lhf00l04,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Spansion",
+		.name		= "S25FL016A",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= SPANSION_ID,
+		.model_id	= SPANSION_S25FL016A,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST25VF016B",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_25VF016B,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_1,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST25VF032B",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_25VF032B,
+		.total_size	= 4096,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_1,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST25VF040B",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_25VF040B,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_1,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST25VF040.REMS",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_25VF040_REMS,
+		.total_size	= 512,
+		.page_size	= 64*1024,
+		.tested		= TEST_OK_PR,
+		.probe		= probe_spi_rems,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60,
+		.write		= spi_chip_write_1,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST25VF040B.REMS",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_25VF040B_REMS,
+		.total_size	= 512,
+		.page_size	= 64*1024,
+		.tested		= TEST_OK_PR,
+		.probe		= probe_spi_rems,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_1,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST25VF080B",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_25VF080B,
+		.total_size	= 1024,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_60_c7,
+		.write		= spi_chip_write_1,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST28SF040A",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_28SF040,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_28sf040,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (sst28sf040.c) */
+		.erase		= erase_28sf040,
+		.write		= write_28sf040,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST29EE010",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_29EE010,
+		.total_size	= 128,
+		.page_size	= 128,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 10, 
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST29LE010",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_29LE010,
+		.total_size	= 128,
+		.page_size	= 128,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= 10, 
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST29EE020A",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_29EE020A,
+		.total_size	= 256,
+		.page_size	= 128,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 10,
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST29LE020",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_29LE020,
+		.total_size	= 256,
+		.page_size	= 128,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= 10, 
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST39SF010A",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_39SF010,
+		.total_size	= 128,
+		.page_size	= 4096,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 1,			/* 150 ns */
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST39SF020A",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_39SF020,
+		.total_size	= 256,
+		.page_size	= 4096,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 1,			/* 150 ns */ 
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST39SF040",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_39SF040,
+		.total_size	= 512,
+		.page_size	= 4096,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 1,			/* 150 ns */ 
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST39VF512",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_39VF512,
+		.total_size	= 64,
+		.page_size	= 4096,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 1,			/* 150 ns*/ 
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST39VF010",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_39VF010,
+		.total_size	= 128,
+		.page_size	= 4096,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 1,			/* 150 ns */ 
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST39VF020",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_39VF020,
+		.total_size	= 256,
+		.page_size	= 4096,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 1,			/* 150 ns */ 
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST39VF040",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_39VF040,
+		.total_size	= 512,
+		.page_size	= 4096,
+		.tested		= TEST_OK_PROBE,
+		.probe		= probe_jedec,
+		.probe_timing	= 1,			/* 150 ns */ 
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST39VF080",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_39VF080,
+		.total_size	= 1024,
+		.page_size	= 4096,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= 1,			/* 150 ns */ 
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST49LF002A/B",
+		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_49LF002A,
+		.total_size	= 256,
+		.page_size	= 16 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_sst_fwhub,
+		.probe_timing	= 1,		/* 150 ns | routine is wrapper to probe_jedec (sst_fwhub.c) */
+		.erase		= erase_sst_fwhub,
+		.write		= write_sst_fwhub,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST49LF003A/B",
+		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_49LF003A,
+		.total_size	= 384,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PR,
+		.probe		= probe_sst_fwhub,
+		.probe_timing	= 1,		/* 150 ns | routine is wrapper to probe_jedec (sst_fwhub.c) */
+		.erase		= erase_sst_fwhub,
+		.write		= write_sst_fwhub,
+		.read		= read_memmapped,
+	},
+
+	{
+		/* Contrary to the data sheet, TBL# on the SST49LF004B affects the top 128kB (instead of 64kB)
+		 * and is only honored for 64k block erase, but not 4k sector erase.
+		 */
+		.vendor		= "SST",
+		.name		= "SST49LF004A/B",
+		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_49LF004A,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_sst_fwhub,
+		.probe_timing	= 1,		/* 150 ns | routine is wrapper to probe_jedec (sst_fwhub.c) */
+		.erase		= NULL,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {4 * 1024, 128} },
+				.block_erase = erase_sector_jedec, /* missing unlock */
+			}, {
+				.eraseblocks = { {64 * 1024, 8} },
+				.block_erase = erase_sst_fwhub_block, /* same as erase_block_jedec, but with unlock */
+			}, {
+				.eraseblocks = { {512 * 1024, 1} },
+				.block_erase = NULL, /* AA 55 80 AA 55 10, only in PP mode */
+			},
+		},
+		.write		= write_sst_fwhub,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST49LF004C",
+		.bustype	= CHIP_BUSTYPE_FWH,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_49LF004C,
+		.total_size	= 512,
+		.page_size	= 4 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_49lfxxxc,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */
+		.erase		= erase_49lfxxxc,
+		.write		= write_49lfxxxc,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST49LF008A",
+		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_49LF008A,
+		.total_size	= 1024,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_sst_fwhub,
+		.probe_timing	= 1,		/* 150 ns | routine is wrapper to probe_jedec (sst_fwhub.c) */
+		.erase		= erase_sst_fwhub,
+		.write		= write_sst_fwhub,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST49LF008C",
+		.bustype	= CHIP_BUSTYPE_FWH,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_49LF008C,
+		.total_size	= 1024,
+		.page_size	= 4 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_49lfxxxc,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */
+		.erase		= erase_49lfxxxc,
+		.write		= write_49lfxxxc,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST49LF016C",
+		.bustype	= CHIP_BUSTYPE_FWH,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_49LF016C,
+		.total_size	= 2048,
+		.page_size	= 4 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_49lfxxxc,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */
+		.erase		= erase_49lfxxxc,
+		.write		= write_49lfxxxc,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST49LF020",
+		.bustype	= CHIP_BUSTYPE_LPC,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_49LF020,
+		.total_size	= 256,
+		.page_size	= 16 * 1024,
+		.tested		= TEST_OK_PR,
+		.probe		= probe_jedec,
+		.probe_timing	= 1,			/* 150 ns */ 
+		.erase		= erase_49lf040,
+		.write		= write_49lf040,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST49LF020A",
+		.bustype	= CHIP_BUSTYPE_LPC,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_49LF020A,
+		.total_size	= 256,
+		.page_size	= 4 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 1,			/* 150 ns */ 
+		.erase		= erase_49lf040,
+		.write		= write_49lf040,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST49LF040",
+		.bustype	= CHIP_BUSTYPE_LPC,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_49LF040,
+		.total_size	= 512,
+		.page_size	= 4096,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 1,			/* 150 ns */ 
+		.erase		= erase_49lf040,
+		.write		= write_49lf040,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST49LF040B",
+		.bustype	= CHIP_BUSTYPE_LPC, /* A/A Mux */
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_49LF040B,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_sst_fwhub,
+		.probe_timing	= 1,		/* 150ns | routine is wrapper to probe_jedec (sst_fwhub.c) */
+		.erase		= erase_sst_fwhub,
+		.write		= write_sst_fwhub,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST49LF080A",
+		.bustype	= CHIP_BUSTYPE_LPC, /* A/A Mux */
+		.manufacture_id	= SST_ID,
+ 		.model_id	= SST_49LF080A,
+		.total_size	= 1024,
+		.page_size	= 4096,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_FIXME, 
+		.erase		= erase_49lf040,
+		.write		= write_49lf040,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "SST49LF160C",
+		.bustype	= CHIP_BUSTYPE_LPC,
+		.manufacture_id	= SST_ID,
+		.model_id	= SST_49LF160C,
+		.total_size	= 2048,
+		.page_size	= 4 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_49lfxxxc,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */
+		.erase		= erase_49lfxxxc,
+		.write		= write_49lfxxxc,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M25P05-A",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25P05A,
+		.total_size	= 64,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	/* The ST M25P05 is a bit of a problem. It has the same ID as the
+	 * ST M25P05-A in RES mode, but supports only 128 byte writes instead
+	 * of 256 byte writes. We rely heavily on the fact that probe_spi_res
+	 * only is successful if RDID does not work.
+	 */
+	{
+		.vendor		= "ST",
+		.name		= "M25P05.RES",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25P05_RES,
+		.total_size	= 64,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_res,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_1, /* 128 */
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M25P10-A",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25P10A,
+		.total_size	= 128,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	/* The ST M25P10 has the same problem as the M25P05. */
+	{
+		.vendor		= "ST",
+		.name		= "M25P10.RES",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25P10_RES,
+		.total_size	= 128,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_res,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_1, /* 128 */
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M25P20",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25P20,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M25P40",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25P40,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M25P40-old",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25P40_RES,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_res,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M25P80",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25P80,
+		.total_size	= 1024,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M25P16",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25P16,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M25P32",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25P32,
+		.total_size	= 4096,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M25P64",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25P64,
+		.total_size	= 8192,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M25P128",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M25P128,
+		.total_size	= 16384,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M29F002B",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M29F002B,
+		.total_size	= 256,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= erase_m29f002,
+		.write		= write_m29f002b,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M29F002T/NT",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M29F002T,
+		.total_size	= 256,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= erase_m29f002,
+		.write		= write_m29f002t,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M29F040B",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M29F040B,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_29f040b,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */
+		.erase		= erase_29f040b,
+		.write		= write_29f040b,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M29F400BT",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M29F400BT,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_m29f400bt,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (m29f400bt.c) */
+		.erase		= erase_m29f400bt,
+		.write		= write_coreboot_m29f400bt,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M29W010B",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M29W010B,
+		.total_size	= 128,
+		.page_size	= 16 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M29W040B",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M29W040B,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M50FLW040A",
+		.bustype	= CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M50FLW040A,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_stm50flw0x0x,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */
+		.erase		= erase_stm50flw0x0x,
+		.write		= write_stm50flw0x0x,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M50FLW040B",
+		.bustype	= CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M50FLW040B,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_stm50flw0x0x,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */
+		.erase		= erase_stm50flw0x0x,
+		.write		= write_stm50flw0x0x,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M50FLW080A",
+		.bustype	= CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M50FLW080A,
+		.total_size	= 1024,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_stm50flw0x0x,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */
+		.erase		= erase_stm50flw0x0x,
+		.write		= write_stm50flw0x0x,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M50FLW080B",
+		.bustype	= CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M50FLW080B,
+		.total_size	= 1024,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_stm50flw0x0x,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */
+		.erase		= erase_stm50flw0x0x,
+		.write		= write_stm50flw0x0x,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M50FW002",
+		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M50FW002,
+		.total_size	= 256,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_49lfxxxc,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M50FW016",
+		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M50FW016,
+		.total_size	= 2048,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_82802ab,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (82802ab.c) */
+		.erase		= erase_82802ab,
+		.write		= write_82802ab,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M50FW040",
+		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M50FW040,
+		.total_size	= 512,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_82802ab,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (82802ab.c) */
+		.erase		= erase_82802ab,
+		.write		= write_82802ab,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M50FW080",
+		.bustype	= CHIP_BUSTYPE_FWH, /* A/A Mux */
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M50FW080,
+		.total_size	= 1024,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_82802ab,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (82802ab.c) */
+		.erase		= erase_82802ab,
+		.write		= write_82802ab,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "M50LPW116",
+		.bustype	= CHIP_BUSTYPE_LPC, /* A/A Mux */
+		.manufacture_id	= ST_ID,
+		.model_id	= ST_M50LPW116,
+		.total_size	= 2048,
+		.page_size	= 64 * 1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SyncMOS",
+		.name		= "S29C31004T",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SYNCMOS_ID,
+		.model_id	= S29C31004T,
+		.total_size	= 512,
+		.page_size	= 128,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SyncMOS",
+		.name		= "S29C51001T",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SYNCMOS_ID,
+		.model_id	= S29C51001T,
+		.total_size	= 128,
+		.page_size	= 128,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SyncMOS",
+		.name		= "S29C51002T",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SYNCMOS_ID,
+		.model_id	= S29C51002T,
+		.total_size	= 256,
+		.page_size	= 128,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "SyncMOS",
+		.name		= "S29C51004T",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= SYNCMOS_ID,
+		.model_id	= S29C51004T,
+		.total_size	= 512,
+		.page_size	= 128,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "TI",
+		.name		= "TMS29F002RB",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= TI_OLD_ID,
+		.model_id	= TI_TMS29F002RB,
+		.total_size	= 256,
+		.page_size	= 16384, /* Non-uniform sectors */
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "TI",
+		.name		= "TMS29F002RT",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= TI_OLD_ID,
+		.model_id	= TI_TMS29F002RT,
+		.total_size	= 256,
+		.page_size	= 16384, /* Non-uniform sectors */
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W25x10",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= WINBOND_NEX_ID,
+		.model_id	= W_25X10,
+		.total_size	= 128,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W25x20",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= WINBOND_NEX_ID,
+		.model_id	= W_25X20,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W25x40",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= WINBOND_NEX_ID,
+		.model_id	= W_25X40,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W25x80",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= WINBOND_NEX_ID,
+		.model_id	= W_25X80,
+		.total_size	= 1024,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W25x16",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= WINBOND_NEX_ID,
+		.model_id	= W_25X16,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.tested		= TEST_OK_PR,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W25x32",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= WINBOND_NEX_ID,
+		.model_id	= W_25X32,
+		.total_size	= 4096,
+		.page_size	= 256,
+		.tested		= TEST_OK_PROBE,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W25x64",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= WINBOND_NEX_ID,
+		.model_id	= W_25X64,
+		.total_size	= 8192,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= spi_chip_erase_c7,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W29C011",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= WINBOND_ID,
+		.model_id	= W_29C011,
+		.total_size	= 128,
+		.page_size	= 128,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 10,		/* used datasheet for the W29C011A */
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W29C020C",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= WINBOND_ID,
+		.model_id	= W_29C020C,
+		.total_size	= 256,
+		.page_size	= 128,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 10, 
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W29C040P",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= WINBOND_ID,
+		.model_id	= W_29C040P,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 10, 
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W29EE011",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= WINBOND_ID,
+		.model_id	= W_29C011,
+		.total_size	= 128,
+		.page_size	= 128,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_w29ee011,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (w29ee011.c) */
+		.erase		= erase_chip_jedec,
+		.write		= write_jedec,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W39V040A",
+		.bustype	= CHIP_BUSTYPE_LPC,
+		.manufacture_id	= WINBOND_ID,
+		.model_id	= W_39V040A,
+		.total_size	= 512,
+		.page_size	= 64*1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 10, 
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W39V040B",
+		.bustype	= CHIP_BUSTYPE_LPC,
+		.manufacture_id	= WINBOND_ID,
+		.model_id	= W_39V040B,
+		.total_size	= 512,
+		.page_size	= 64*1024,
+		.tested		= TEST_OK_PR | TEST_BAD_ERASE | TEST_BAD_WRITE,
+		.probe		= probe_jedec,
+		.probe_timing	= 10, 
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W39V040C",
+		.bustype	= CHIP_BUSTYPE_LPC,
+		.manufacture_id	= WINBOND_ID,
+		.model_id	= W_39V040C,
+		.total_size	= 512,
+		.page_size	= 64*1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_w39v040c,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (w39v040c.c) */
+		.erase		= erase_w39v040c,
+		.write		= write_w39v040c,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W39V040FA",
+		.bustype	= CHIP_BUSTYPE_FWH,
+		.manufacture_id	= WINBOND_ID,
+		.model_id	= W_39V040FA,
+		.total_size	= 512,
+		.page_size	= 64*1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 10, 
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W39V080A",
+		.bustype	= CHIP_BUSTYPE_LPC,
+		.manufacture_id	= WINBOND_ID,
+		.model_id	= W_39V080A,
+		.total_size	= 1024,
+		.page_size	= 64*1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 10, 
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W49F002U",
+		.bustype	= CHIP_BUSTYPE_PARALLEL,
+		.manufacture_id	= WINBOND_ID,
+		.model_id	= W_49F002U,
+		.total_size	= 256,
+		.page_size	= 128,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 10,
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W49V002A",
+		.bustype	= CHIP_BUSTYPE_LPC,
+		.manufacture_id	= WINBOND_ID,
+		.model_id	= W_49V002A,
+		.total_size	= 256,
+		.page_size	= 128,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_jedec,
+		.probe_timing	= 10, 
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W49V002FA",
+		.bustype	= CHIP_BUSTYPE_FWH,
+		.manufacture_id	= WINBOND_ID,
+		.model_id	= W_49V002FA,
+		.total_size	= 256,
+		.page_size	= 128,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec,
+		.probe_timing	= 10,
+		.erase		= erase_chip_jedec,
+		.write		= write_49f002,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W39V080FA",
+		.bustype	= CHIP_BUSTYPE_FWH,
+		.manufacture_id	= WINBOND_ID,
+		.model_id	= W_39V080FA,
+		.total_size	= 1024,
+		.page_size	= 64*1024,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_winbond_fwhub,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (w39v080fa.c) */
+		.erase		= erase_winbond_fwhub,
+		.write		= write_winbond_fwhub,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W39V080FA (dual mode)",
+		.bustype	= CHIP_BUSTYPE_FWH,
+		.manufacture_id	= WINBOND_ID,
+		.model_id	= W_39V080FA_DM,
+		.total_size	= 512,
+		.page_size	= 64*1024,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_winbond_fwhub,
+		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (w39v080fa.c) */
+		.erase		= erase_winbond_fwhub,
+		.write		= write_winbond_fwhub,
+		.read		= read_memmapped,
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "unknown Atmel SPI chip",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ATMEL_ID,
+		.model_id	= GENERIC_DEVICE_ID,
+		.total_size	= 0,
+		.page_size	= 256,
+		.tested		= TEST_BAD_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= NULL,
+	},
+
+	{
+		.vendor		= "EON",
+		.name		= "unknown EON SPI chip",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= GENERIC_DEVICE_ID,
+		.total_size	= 0,
+		.page_size	= 256,
+		.tested		= TEST_BAD_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= NULL,
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "unknown Macronix SPI chip",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= MX_ID,
+		.model_id	= GENERIC_DEVICE_ID,
+		.total_size	= 0,
+		.page_size	= 256,
+		.tested		= TEST_BAD_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= NULL,
+	},
+
+	{
+		.vendor		= "PMC",
+		.name		= "unknown PMC SPI chip",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= PMC_ID,
+		.model_id	= GENERIC_DEVICE_ID,
+		.total_size	= 0,
+		.page_size	= 256,
+		.tested		= TEST_BAD_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= NULL,
+	},
+
+	{
+		.vendor		= "SST",
+		.name		= "unknown SST SPI chip",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= SST_ID,
+		.model_id	= GENERIC_DEVICE_ID,
+		.total_size	= 0,
+		.page_size	= 256,
+		.tested		= TEST_BAD_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= NULL,
+	},
+
+	{
+		.vendor		= "ST",
+		.name		= "unknown ST SPI chip",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= ST_ID,
+		.model_id	= GENERIC_DEVICE_ID,
+		.total_size	= 0,
+		.page_size	= 256,
+		.tested		= TEST_BAD_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= NULL,
+	},
+
+	{
+		.vendor		= "Sanyo",
+		.name		= "unknown Sanyo SPI chip",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= SANYO_ID,
+		.model_id	= GENERIC_DEVICE_ID,
+		.total_size	= 0,
+		.page_size	= 256,
+		.tested		= TEST_BAD_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.erase		= NULL,
+		.write		= NULL,
+		.read		= NULL,
+	},
+
+	{
+		.vendor		= "Generic",
+		.name		= "unknown SPI chip (RDID)",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= GENERIC_MANUF_ID,
+		.model_id	= GENERIC_DEVICE_ID,
+		.total_size	= 0,
+		.page_size	= 256,
+		.tested		= TEST_BAD_PREW,
+		.probe		= probe_spi_rdid,
+		.erase		= NULL,
+		.write		= NULL,
+	},
+	{
+		.vendor		= "Generic",
+		.name		= "unknown SPI chip (REMS)",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= GENERIC_MANUF_ID,
+		.model_id	= GENERIC_DEVICE_ID,
+		.total_size	= 0,
+		.page_size	= 256,
+		.tested		= TEST_BAD_PREW,
+		.probe		= probe_spi_rems,
+		.erase		= NULL,
+		.write		= NULL,
+	},
+
+	{ NULL 	}
+};
diff --git a/libflashrom/flashchips.h b/libflashrom/flashchips.h
new file mode 100644
index 0000000..684b8b9
--- /dev/null
+++ b/libflashrom/flashchips.h
@@ -0,0 +1,501 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2000 Ronald G. Minnich <rminnich@gmail.com>
+ * Copyright (C) 2005-2007 coresystems GmbH <stepan@coresystems.de>
+ * Copyright (C) 2006-2009 Carl-Daniel Hailfinger
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef __FLASHCHIPS_H__
+#define __FLASHCHIPS_H__ 1
+
+/*
+ * Please keep this list sorted alphabetically by manufacturer. The first
+ * entry of each section should be the manufacturer ID, followed by the
+ * list of devices from that manufacturer (sorted by device IDs).
+ *
+ * All LPC/FWH parts (parallel flash) have 8-bit device IDs if there is no
+ * continuation code.
+ * SPI parts have 16-bit device IDs if they support RDID.
+ */
+
+#define GENERIC_MANUF_ID	0xffff	/* Check if there is a vendor ID */
+#define GENERIC_DEVICE_ID	0xffff	/* Only match the vendor ID */
+
+#define ALLIANCE_ID		0x52	/* Alliance Semiconductor */
+
+#define AMD_ID			0x01	/* AMD */
+#define AM_29DL400BT		0x0C
+#define AM_29DL400BB		0x0F
+#define AM_29DL800BT		0x4A
+#define AM_29DL800BB		0xCB
+#define AM_29F002BB		0x34	/* Same as Am29F002NBB */
+#define AM_29F002BT		0xB0	/* Same as Am29F002NBT */
+#define AM_29F004BB		0x7B
+#define AM_29F004BT		0x77
+#define AM_29F016D		0xAD
+#define AM_29F010B		0x20	/* Same as Am29F010A */
+#define AM_29F040B		0xA4
+#define AM_29F080B		0xD5
+#define AM_29F200BB		0x57
+#define AM_29F200BT		0x51
+#define AM_29F400BB		0xAB
+#define AM_29F400BT		0x23
+#define AM_29F800BB		0x58
+#define AM_29F800BT		0xD6
+#define AM_29LV002BB		0xC2
+#define AM_29LV002BT		0x40
+#define AM_29LV004BB		0xB6
+#define AM_29LV004BT		0xB5
+#define AM_29LV008BB		0x37
+#define AM_29LV008BT		0x3E
+#define AM_29LV040B		0x4F
+#define AM_29LV080B		0x38	/* Same as Am29LV081B */
+#define AM_29LV200BB		0xBF
+#define AM_29LV200BT		0x3B
+#define AM_29LV800BB		0x5B	/* Same as Am29LV800DB */
+#define AM_29LV400BT		0xB9
+#define AM_29LV400BB		0xBA
+#define AM_29LV800BT		0xDA	/* Same as Am29LV800DT */
+
+#define AMIC_ID			0x7F37	/* AMIC */
+#define AMIC_ID_NOPREFIX	0x37	/* AMIC */
+#define AMIC_A25L40P		0x2013
+#define AMIC_A29002B		0x0d
+#define AMIC_A29002T		0x8C	/* Same as A290021T */
+#define AMIC_A29040B		0x86
+#define AMIC_A29400T		0xB0	/* Same as 294001T */
+#define AMIC_A29400U		0x31	/* Same as A294001U */
+#define AMIC_A29800T		0x0E
+#define AMIC_A29800U		0x8F
+#define AMIC_A29L004T		0x34	/* Same as A29L400T */
+#define AMIC_A29L004U		0xB5	/* Same as A29L400U */
+#define AMIC_A29L008T		0x1A	/* Same as A29L800T */
+#define AMIC_A29L008U		0x9B	/* Same as A29L800U */
+#define AMIC_A29L040		0x92
+#define AMIC_A49LF040A		0x9d
+
+/* This chip vendor/device ID is probably a misinterpreted LHA header. */
+#define ASD_ID			0x25	/* ASD, not listed in JEP106W */
+#define ASD_AE49F2008		0x52
+
+#define ATMEL_ID		0x1F	/* Atmel */
+#define AT_25DF021		0x4300
+#define AT_25DF041A		0x4401
+#define AT_25DF081		0x4502
+#define AT_25DF161		0x4602
+#define AT_25DF321		0x4700	/* Same as 26DF321 */
+#define AT_25DF321A		0x4701
+#define AT_25DF641		0x4800
+#define AT_25F512A		0x65 /* Needs special RDID. AT25F512A_RDID 15 1d */
+#define AT_25F512B		0x6500
+#define AT_25FS010		0x6601
+#define AT_25FS040		0x6604
+#define AT_26DF041		0x4400
+#define AT_26DF081		0x4500	/* guessed, no datasheet available */
+#define AT_26DF081A		0x4501
+#define AT_26DF161		0x4600
+#define AT_26DF161A		0x4601
+#define AT_26DF321		0x4700	/* Same as 25DF321 */
+#define AT_26F004		0x0400
+#define AT_29C040A		0xA4
+#define AT_29C010A		0xD5	
+#define AT_29C020		0xDA
+#define AT_29C512		0x5D	
+#define AT_45BR3214B		/* No ID available */
+#define AT_45CS1282		0x2920
+#define AT_45D011		/* No ID available */
+#define AT_45D021A		/* No ID available */
+#define AT_45D041A		/* No ID available */
+#define AT_45D081A		/* No ID available */
+#define AT_45D161		/* No ID available */
+#define AT_45DB011		/* No ID available */
+#define AT_45DB011B		/* No ID available */
+#define AT_45DB011D		0x2200
+#define AT_45DB021A		/* No ID available */
+#define AT_45DB021B		/* No ID available */
+#define AT_45DB021D		0x2300
+#define AT_45DB041A		/* No ID available */
+#define AT_45DB041D		0x2400
+#define AT_45DB081A		/* No ID available */
+#define AT_45DB081D		0x2500
+#define AT_45DB161		/* No ID available */
+#define AT_45DB161B		/* No ID available */
+#define AT_45DB161D		0x2600
+#define AT_45DB321		/* No ID available */
+#define AT_45DB321B		/* No ID available */
+#define AT_45DB321C		0x2700
+#define AT_45DB321D		0x2701 /* Buggy data sheet */
+#define AT_45DB642		/* No ID available */
+#define AT_45DB642D		0x2800
+#define AT_49BV512		0x03
+#define AT_49F002N		0x07	/* for AT49F002(N)  */
+#define AT_49F002NT		0x08	/* for AT49F002(N)T */
+
+#define CATALYST_ID		0x31	/* Catalyst */
+
+#define EMST_ID			0x8C	/* EMST / EFST Elite Flash Storage */
+#define EMST_F49B002UA		0x00
+
+/*
+ * EN25 chips are SPI, first byte of device ID is memory type,
+ * second byte of device ID is log(bitsize)-9.
+ * Vendor and device ID of EN29 series are both prefixed with 0x7F, which
+ * is the continuation code for IDs in bank 2.
+ * Vendor ID of EN25 series is NOT prefixed with 0x7F, this results in
+ * a collision with Mitsubishi. Mitsubishi once manufactured flash chips.
+ * Let's hope they are not manufacturing SPI flash chips as well.
+ */
+#define EON_ID			0x7F1C	/* EON Silicon Devices */
+#define EON_ID_NOPREFIX		0x1C	/* EON, missing 0x7F prefix */
+#define EN_25B05		0x2010	/* Same as P05, 2^19 kbit or 2^16 kByte */
+#define EN_25B10		0x2011	/* Same as P10 */
+#define EN_25B20		0x2012	/* Same as P20 */
+#define EN_25B40		0x2013	/* Same as P40 */
+#define EN_25B80		0x2014	/* Same as P80 */
+#define EN_25B16		0x2015	/* Same as P16 */
+#define EN_25B32		0x2016	/* Same as P32 */
+#define EN_25B64		0x2017	/* Same as P64 */
+#define EN_25D16		0x3015
+#define EN_25F05		0x3110
+#define EN_25F10		0x3111
+#define EN_25F20		0x3112
+#define EN_25F40		0x3113
+#define EN_25F80		0x3114
+#define EN_25F16		0x3115
+#define EN_25F32		0x3116
+#define EN_29F512		0x7F21
+#define EN_29F010		0x7F20
+#define EN_29F040A		0x7F04
+#define EN_29LV010		0x7F6E
+#define EN_29LV040A		0x7F4F	/* EN_29LV040(A) */
+#define EN_29F002T		0x7F92	/* Same as EN29F002A */
+#define EN_29F002B		0x7F97	/* Same as EN29F002AN */
+
+#define FUJITSU_ID		0x04	/* Fujitsu */
+#define MBM29DL400BC		0x0F
+#define MBM29DL400TC		0x0C
+#define MBM29DL800BA		0xCB
+#define MBM29DL800TA		0x4A
+#define MBM29F002BC		0x34
+#define MBM29F002TC		0xB0
+#define MBM29F004BC		0x7B
+#define MBM29F004TC		0x77
+#define MBM29F040C		0xA4
+#define MBM29F080A		0xD5
+#define MBM29F200BC		0x57
+#define MBM29F200TC		0x51
+#define MBM29F400BC		0xAB
+#define MBM29F400TC		0x23
+#define MBM29F800BA		0x58
+#define MBM29F800TA		0xD6
+#define MBM29LV002BC		0xC2
+#define MBM29LV002TC		0x40
+#define MBM29LV004BC		0xB6
+#define MBM29LV004TC		0xB5
+#define MBM29LV008BA		0x37
+#define MBM29LV008TA		0x3E
+#define MBM29LV080A		0x38
+#define MBM29LV200BC		0xBF
+#define MBM29LV200TC		0x3B
+#define MBM29LV400BC		0xBA
+#define MBM29LV400TC		0xB9
+#define MBM29LV800BA		0x5B	/* Same as MBM29LV800BE */
+#define MBM29LV800TA		0xDA	/* Same as MBM29LV800TE */
+
+#define HYUNDAI_ID		0xAD	/* Hyundai */
+#define HY_29F400T		0x23	/* Same as HY_29F400AT */
+#define HY_29F800B		0x58	/* Same as HY_29F800AB */
+#define HY_29LV800B		0x5B
+#define HY_29F040A		0xA4
+#define HY_29F400B		0xAB	/* Same as HY_29F400AB */
+#define HY_29F002		0xB0
+#define HY_29LV400T		0xB9
+#define HY_29LV400B		0xBA
+#define HY_29F080		0xD5
+#define HY_29F800T		0xD6	/* Same as HY_29F800AT */
+#define HY_29LV800T		0xDA
+
+#define IMT_ID			0x7F1F	/* Integrated Memory Technologies */
+#define IM_29F004B		0xAE
+#define IM_29F004T		0xAF
+
+#define INTEL_ID		0x89	/* Intel */
+#define I_82802AB		0xAD
+#define I_82802AC		0xAC
+#define P28F001BXT		0x94	/* 28F001BX-T */
+#define P28F001BXB		0x95	/* 28F001BX-B */
+#define SHARP_LH28F008SA	0xA2	/* Sharp chip, Intel Vendor ID */
+#define SHARP_LH28F008SC	0xA6	/* Sharp chip, Intel Vendor ID */
+
+#define ISSI_ID			0xD5	/* ISSI Integrated Silicon Solutions */
+
+/*
+ * MX25 chips are SPI, first byte of device ID is memory type,
+ * second byte of device ID is log(bitsize)-9.
+ * Generalplus SPI chips seem to be compatible with Macronix
+ * and use the same set of IDs.
+ */
+#define MX_ID			0xC2	/* Macronix (MX) */
+#define MX_25L512		0x2010	/* Same as MX25V512 */
+#define MX_25L1005		0x2011
+#define MX_25L2005		0x2012
+#define MX_25L4005		0x2013	/* MX25L4005{,A} */
+#define MX_25L8005		0x2014	/* Same as MX25V8005 */
+#define MX_25L1605		0x2015	/* MX25L1605{,A,D} */
+#define MX_25L3205		0x2016	/* MX25L3205{,A} */
+#define MX_25L6405		0x2017	/* MX25L3205{,D} */
+#define MX_25L12805		0x2018	/* MX25L12805 */
+#define MX_25L1635D		0x2415
+#define MX_25L3235D		0x5E16	/* MX25L3225D/MX25L3235D/MX25L3237D */
+#define MX_29F001B		0x19
+#define MX_29F001T		0x18
+#define MX_29F002B		0x34	/* Same as MX29F002NB */
+#define MX_29F002T		0xB0	/* Same as MX29F002NT */
+#define MX_29F004B		0x46
+#define MX_29F004T		0x45
+#define MX_29F022T		0x36	/* Same as MX29F022NT */
+#define MX_29F040		0xA4	/* Same as MX29F040C */
+#define MX_29F080		0xD5
+#define MX_29F200B		0x57	/* Same as MX29F200CB */
+#define MX_29F200T		0x51	/* Same as MX29F200CT */
+#define MX_29F400B		0xAB	/* Same as MX29F400CB */
+#define MX_29F400T		0x23	/* Same as MX29F400CT */
+#define MX_29F800B		0x58
+#define MX_29F800T		0xD6
+#define MX_29LV002CB		0x5A
+#define MX_29LV002CT		0x59
+#define MX_29LV004B		0xB6	/* Same as MX29LV004CB */
+#define MX_29LV004T		0xB5	/* Same as MX29LV004CT */
+#define MX_29LV008B		0x37	/* Same as MX29LV008CB */
+#define MX_29LV008T		0x3E	/* Same as MX29LV008CT */
+#define MX_29LV040		0x4F	/* Same as MX29LV040C */
+#define MX_29LV081		0x38
+#define MX_29LV128DB		0x7A
+#define MX_29LV128DT		0x7E
+#define MX_29LV160DB		0x49	/* Same as MX29LV161DB/MX29LV160CB */
+#define MX_29LV160DT		0xC4	/* Same as MX29LV161DT/MX29LV160CT */
+#define MX_29LV320DB		0xA8	/* Same as MX29LV321DB */
+#define MX_29LV320DT		0xA7	/* Same as MX29LV321DT */
+#define MX_29LV400B		0xBA	/* Same as MX29LV400CB */
+#define MX_29LV400T		0xB9	/* Same as MX29LV400CT */
+#define MX_29LV640DB		0xCB	/* Same as MX29LV640EB */
+#define MX_29LV640DT		0xC9	/* Same as MX29LV640ET */
+#define MX_29LV800B		0x5B	/* Same as MX29LV800CB */
+#define MX_29LV800T		0xDA	/* Same as MX29LV800CT */
+#define MX_29SL402CB		0xF1
+#define MX_29SL402CT		0x70
+#define MX_29SL800CB		0x6B	/* Same as MX29SL802CB */
+#define MX_29SL800CT		0xEA	/* Same as MX29SL802CT */
+
+/*
+ * Programmable Micro Corp is listed in JEP106W in bank 2, so it should
+ * have a 0x7F continuation code prefix.
+ */
+#define PMC_ID			0x7F9D	/* PMC */
+#define PMC_ID_NOPREFIX		0x9D	/* PMC, missing 0x7F prefix */
+#define PMC_25LV512		0x7B
+#define PMC_25LV010		0x7C
+#define PMC_25LV020		0x7D
+#define PMC_25LV040		0x7E
+#define PMC_25LV080B		0x13
+#define PMC_25LV016B		0x14
+#define PMC_29F002T		0x1D
+#define PMC_29F002B		0x2D
+#define PMC_39LV512		0x1B
+#define PMC_39F010		0x1C	/* Same as Pm39LV010 */
+#define PMC_39LV020		0x3D
+#define PMC_39LV040		0x3E
+#define PMC_39F020		0x4D
+#define PMC_39F040		0x4E
+#define PMC_49FL002		0x6D
+#define PMC_49FL004		0x6E
+
+/* 
+ * The Sanyo chip found so far uses SPI, first byte is manufacture code,
+ * second byte is the device code,
+ * third byte is a dummy byte.
+ */
+#define SANYO_ID		0x62
+#define SANYO_LE25FW203A	0x1600
+
+#define SHARP_ID		0xB0	/* Sharp */
+#define SHARP_LH28F008BJxxPT	0xEC
+#define SHARP_LH28F008BJxxPB	0xED
+#define SHARP_LH28F800BVxxBTL	0x4B
+#define SHARP_LH28F800BVxxBV	0x4D
+#define SHARP_LH28F800BVxxTV	0x4C
+#define SHARP_LHF00L02		0xC9	/* Same as LHF00L06/LHF00L07 */
+#define SHARP_LHF00L04		0xCF	/* Same as LHF00L03/LHF00L05 */
+
+/*
+ * Spansion was previously a joint venture of AMD and Fujitsu.
+ * S25 chips are SPI. The first device ID byte is memory type and
+ * the second device ID byte is memory capacity.
+ */
+#define SPANSION_ID		0x01	/* Spansion, same ID as AMD */
+#define SPANSION_S25FL016A	0x0214
+
+/*
+ * SST25 chips are SPI, first byte of device ID is memory type, second
+ * byte of device ID is related to log(bitsize) at least for some chips.
+ */
+#define SST_ID			0xBF	/* SST */
+#define SST_25WF512		0x2501
+#define SST_25WF010		0x2502
+#define SST_25WF020		0x2503
+#define SST_25WF040		0x2504
+#define SST_25VF512A_REMS	0x48	/* REMS or RES opcode */
+#define SST_25VF010_REMS	0x49	/* REMS or RES opcode */
+#define SST_25VF020_REMS	0x43	/* REMS or RES opcode */
+#define SST_25VF040_REMS	0x44	/* REMS or RES opcode */
+#define SST_25VF040B		0x258D
+#define SST_25VF040B_REMS	0x8D	/* REMS or RES opcode */
+#define SST_25VF080_REMS	0x80	/* REMS or RES opcode */
+#define SST_25VF080B		0x258E
+#define SST_25VF080B_REMS	0x8E	/* REMS or RES opcode */
+#define SST_25VF016B		0x2541
+#define SST_25VF032B		0x254A
+#define SST_25VF032B_REMS	0x4A	/* REMS or RES opcode */
+#define SST_26VF016		0x2601
+#define SST_26VF032		0x2602
+#define SST_27SF512		0xA4
+#define SST_27SF010		0xA5
+#define SST_27SF020		0xA6
+#define SST_27VF010		0xA9
+#define SST_27VF020		0xAA
+#define SST_28SF040		0x04
+#define SST_29EE512		0x5D
+#define SST_29EE010		0x07
+#define SST_29LE010		0x08	/* Same as SST29VE010 */
+#define SST_29EE020A		0x10	/* Same as SST29EE020 */
+#define SST_29LE020		0x12	/* Same as SST29VE020 */
+#define SST_29SF020		0x24
+#define SST_29VF020		0x25
+#define SST_29SF040		0x13
+#define SST_29VF040		0x14
+#define SST_39SF010		0xB5
+#define SST_39SF020		0xB6	/* Same as 39SF020A */
+#define SST_39SF040		0xB7
+#define SST_39VF512		0xD4
+#define SST_39VF010		0xD5
+#define SST_39VF020		0xD6	/* Same as 39LF020 */
+#define SST_39VF040		0xD7	/* Same as 39LF040 */
+#define SST_39VF080		0xD8	/* Same as 39LF080/39VF080/39VF088 */
+#define SST_49LF040B		0x50
+#define SST_49LF040		0x51
+#define SST_49LF020		0x61
+#define SST_49LF020A		0x52
+#define SST_49LF030A		0x1C
+#define SST_49LF080A		0x5B
+#define SST_49LF002A		0x57
+#define SST_49LF003A		0x1B
+#define SST_49LF004A		0x60	/* Same as 49LF004B */
+#define SST_49LF008A		0x5A
+#define SST_49LF004C		0x54
+#define SST_49LF008C		0x59
+#define SST_49LF016C		0x5C
+#define SST_49LF160C		0x4C
+
+/*
+ * ST25P chips are SPI, first byte of device ID is memory type, second
+ * byte of device ID is related to log(bitsize) at least for some chips.
+ */
+#define ST_ID			0x20	/* ST / SGS/Thomson */
+#define ST_M25P05A		0x2010
+#define ST_M25P05_RES		0x10	/* Same code as M25P10. */
+#define ST_M25P10A		0x2011
+#define ST_M25P10_RES		0x10	/* Same code as M25P05. */
+#define ST_M25P20		0x2012
+#define ST_M25P40		0x2013
+#define ST_M25P40_RES		0x12
+#define ST_M25P80		0x2014
+#define ST_M25P16		0x2015
+#define ST_M25P32		0x2016
+#define ST_M25P64		0x2017
+#define ST_M25P128		0x2018
+#define ST_M25PE10		0x8011
+#define ST_M25PE20		0x8012
+#define ST_M25PE40		0x8013
+#define ST_M25PE80		0x8014
+#define ST_M25PE16		0x8015
+#define ST_M50FLW040A		0x08
+#define ST_M50FLW040B		0x28
+#define ST_M50FLW080A		0x80
+#define ST_M50FLW080B		0x81
+#define ST_M50FW002		0x29
+#define ST_M50FW040		0x2C
+#define ST_M50FW080		0x2D
+#define ST_M50FW016		0x2E
+#define ST_M50LPW116		0x30
+#define ST_M29F002B		0x34	/* Same as M29F002BB */
+#define ST_M29F002T		0xB0	/* Same as M29F002BT/M29F002NT/M29F002BNT */
+#define ST_M29F040B		0xE2	/* Same as M29F040 */
+#define ST_M29F080		0xF1
+#define ST_M29F200BT		0xD3
+#define ST_M29F200BB		0xD4
+#define ST_M29F400BT		0xD5	/* Same as M29F400T */
+#define ST_M29F400BB		0xD6	/* Same as M29F400B */
+#define ST_M29F800DB		0x58
+#define ST_M29F800DT		0xEC
+#define ST_M29W010B		0x23
+#define ST_M29W040B		0xE3
+
+#define SYNCMOS_ID		0x40	/* SyncMOS and Mosel Vitelic */
+#define S29C51001T		0x01
+#define S29C51002T		0x02
+#define S29C51004T		0x03
+#define S29C31004T		0x63
+
+#define TI_ID			0x97	/* Texas Instruments */
+#define TI_OLD_ID		0x01	/* TI chips from last century */
+#define TI_TMS29F002RT		0xB0
+#define TI_TMS29F002RB		0x34
+
+/*
+ * W25X chips are SPI, first byte of device ID is memory type, second
+ * byte of device ID is related to log(bitsize).
+ */
+#define WINBOND_ID		0xDA	/* Winbond */
+#define WINBOND_NEX_ID		0xEF	/* Winbond (ex Nexcom) serial flashes */
+#define W_25X10			0x3011
+#define W_25X20			0x3012
+#define W_25X40			0x3013
+#define W_25X80			0x3014
+#define W_25X16			0x3015
+#define W_25X32			0x3016
+#define W_25X64			0x3017
+#define W_29C011		0xC1
+#define W_29C020C		0x45	/* Same as W29C020 and ASD AE29F2008 */
+#define W_29C040P		0x46	/* Same as W29C040 */
+#define W_29EE011		0xC1
+#define W_39L020		0xB5
+#define W_39L040		0xB6
+#define W_39V040FA		0x34
+#define W_39V040A		0x3D
+#define W_39V040B		0x54
+#define W_39V040C		0x50
+#define W_39V080A		0xD0
+#define W_39V080FA		0xD3
+#define W_39V080FA_DM		0x93
+#define W_49F002U		0x0B
+#define W_49F020		0x8C
+#define W_49V002A		0xB0
+#define W_49V002FA		0x32
+
+#endif /* !FLASHCHIPS_H */
diff --git a/libflashrom/ft2232_spi.c b/libflashrom/ft2232_spi.c
new file mode 100644
index 0000000..d565a6f
--- /dev/null
+++ b/libflashrom/ft2232_spi.c
@@ -0,0 +1,320 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Paul Fox <pgf@laptop.org>
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#if FT2232_SPI_SUPPORT == 1
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "flash.h"
+#include "spi.h"
+#include <ftdi.h>
+
+/*
+ * The 'H' chips can run internally at either 12MHz or 60MHz.
+ * The non-H chips can only run at 12MHz.
+ */
+#define CLOCK_5X 1
+
+/*
+ * In either case, the divisor is a simple integer clock divider.
+ * If CLOCK_5X is set, this divisor divides 30MHz, else it divides 6MHz.
+ */
+#define DIVIDE_BY 3  /* e.g. '3' will give either 10MHz or 2MHz SPI clock. */
+
+#define BITMODE_BITBANG_NORMAL	1
+#define BITMODE_BITBANG_SPI	2
+
+static struct ftdi_context ftdic_context;
+
+int send_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size)
+{
+	int r;
+	r = ftdi_write_data(ftdic, (unsigned char *) buf, size);
+	if (r < 0) {
+		fprintf(stderr, "ftdi_write_data: %d, %s\n", r,
+				ftdi_get_error_string(ftdic));
+		return 1;
+	}
+	return 0;
+}
+
+int get_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size)
+{
+	int r;
+	r = ftdi_read_data(ftdic, (unsigned char *) buf, size);
+	if (r < 0) {
+		fprintf(stderr, "ftdi_read_data: %d, %s\n", r,
+				ftdi_get_error_string(ftdic));
+		return 1;
+	}
+	return 0;
+}
+
+int ft2232_spi_init(void)
+{
+	int f;
+	struct ftdi_context *ftdic = &ftdic_context;
+	unsigned char buf[512];
+	char *portpos = NULL;
+	int ft2232_type = FTDI_FT4232H;
+	enum ftdi_interface ft2232_interface = INTERFACE_B;
+
+	if (ftdi_init(ftdic) < 0) {
+		fprintf(stderr, "ftdi_init failed\n");
+		return EXIT_FAILURE; // TODO
+	}
+
+	if (programmer_param && !strlen(programmer_param)) {
+		free(programmer_param);
+		programmer_param = NULL;
+	}
+	if (programmer_param) {
+		if (strstr(programmer_param, "2232"))
+			ft2232_type = FTDI_FT2232H;
+		if (strstr(programmer_param, "4232"))
+			ft2232_type = FTDI_FT4232H;
+		portpos = strstr(programmer_param, "port=");
+		if (portpos) {
+			portpos += 5;
+			switch (toupper(*portpos)) {
+			case 'A':
+				ft2232_interface = INTERFACE_A;
+				break;
+			case 'B':
+				ft2232_interface = INTERFACE_B;
+				break;
+			default:
+				fprintf(stderr, "Invalid interface specified, "
+					"using default.\n");
+			}
+		}
+		free(programmer_param);
+	}
+	printf_debug("Using device type %s ",
+		     (ft2232_type == FTDI_FT2232H) ? "2232H" : "4232H");
+	printf_debug("interface %s\n",
+		     (ft2232_interface == INTERFACE_A) ? "A" : "B");
+
+	f = ftdi_usb_open(ftdic, 0x0403, ft2232_type);
+
+	if (f < 0 && f != -5) {
+		fprintf(stderr, "Unable to open FTDI device: %d (%s)\n", f,
+				ftdi_get_error_string(ftdic));
+		exit(-1); // TODO
+	}
+
+	if (ftdi_set_interface(ftdic, ft2232_interface) < 0) {
+		fprintf(stderr, "Unable to select interface: %s\n",
+				ftdic->error_str);
+	}
+
+	if (ftdi_usb_reset(ftdic) < 0) {
+		fprintf(stderr, "Unable to reset FTDI device\n");
+	}
+
+	if (ftdi_set_latency_timer(ftdic, 2) < 0) {
+		fprintf(stderr, "Unable to set latency timer\n");
+	}
+
+	if (ftdi_write_data_set_chunksize(ftdic, 512)) {
+		fprintf(stderr, "Unable to set chunk size\n");
+	}
+
+	if (ftdi_set_bitmode(ftdic, 0x00, BITMODE_BITBANG_SPI) < 0) {
+		fprintf(stderr, "Unable to set bitmode to SPI\n");
+	}
+
+#if CLOCK_5X
+	printf_debug("Disable divide-by-5 front stage\n");
+	buf[0] = 0x8a;		/* Disable divide-by-5. */
+	if (send_buf(ftdic, buf, 1))
+		return -1;
+#define MPSSE_CLK 60.0
+
+#else
+
+#define MPSSE_CLK 12.0
+
+#endif
+	printf_debug("Set clock divisor\n");
+	buf[0] = 0x86;		/* command "set divisor" */
+	/* valueL/valueH are (desired_divisor - 1) */
+	buf[1] = (DIVIDE_BY - 1) & 0xff;
+	buf[2] = ((DIVIDE_BY - 1) >> 8) & 0xff;
+	if (send_buf(ftdic, buf, 3))
+		return -1;
+
+	printf("SPI clock is %fMHz\n",
+	       (double)(MPSSE_CLK / (((DIVIDE_BY - 1) + 1) * 2)));
+
+	/* Disconnect TDI/DO to TDO/DI for loopback. */
+	printf_debug("No loopback of TDI/DO TDO/DI\n");
+	buf[0] = 0x85;
+	if (send_buf(ftdic, buf, 1))
+		return -1;
+
+	printf_debug("Set data bits\n");
+	/* Set data bits low-byte command:
+	 *  value: 0x08  CS=high, DI=low, DO=low, SK=low
+	 *    dir: 0x0b  CS=output, DI=input, DO=output, SK=output
+	 */
+#define CS_BIT 0x08
+	buf[0] = SET_BITS_LOW;
+	buf[1] = CS_BIT;
+	buf[2] = 0x0b;
+	if (send_buf(ftdic, buf, 3))
+		return -1;
+
+	// printf_debug("\nft2232 chosen\n");
+
+	buses_supported = CHIP_BUSTYPE_SPI;
+	spi_controller = SPI_CONTROLLER_FT2232;
+
+	return 0;
+}
+
+int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		const unsigned char *writearr, unsigned char *readarr)
+{
+	struct ftdi_context *ftdic = &ftdic_context;
+	static unsigned char *buf = NULL;
+	/* failed is special. We use bitwise ops, but it is essentially bool. */
+	int i = 0, ret = 0, failed = 0;
+	int bufsize;
+	static int oldbufsize = 0;
+
+	if (writecnt > 65536 || readcnt > 65536)
+		return SPI_INVALID_LENGTH;
+
+	/* buf is not used for the response from the chip. */
+	bufsize = max(writecnt + 9, 260 + 9);
+	/* Never shrink. realloc() calls are expensive. */
+	if (bufsize > oldbufsize) {
+		buf = realloc(buf, bufsize);
+		if (!buf) {
+			fprintf(stderr, "Out of memory!\n");
+			exit(1);
+		}
+		oldbufsize = bufsize;
+	}
+
+	/*
+	 * Minimize USB transfers by packing as many commands as possible
+	 * together. If we're not expecting to read, we can assert CS#, write,
+	 * and deassert CS# all in one shot. If reading, we do three separate
+	 * operations.
+	 */
+	printf_debug("Assert CS#\n");
+	buf[i++] = SET_BITS_LOW;
+	buf[i++] = 0 & ~CS_BIT; /* assertive */
+	buf[i++] = 0x0b;
+
+	if (writecnt) {
+		buf[i++] = 0x11;
+		buf[i++] = (writecnt - 1) & 0xff;
+		buf[i++] = ((writecnt - 1) >> 8) & 0xff;
+		memcpy(buf + i, writearr, writecnt);
+		i += writecnt;
+	}
+
+	/*
+	 * Optionally terminate this batch of commands with a
+	 * read command, then do the fetch of the results.
+	 */
+	if (readcnt) {
+		buf[i++] = 0x20;
+		buf[i++] = (readcnt - 1) & 0xff;
+		buf[i++] = ((readcnt - 1) >> 8) & 0xff;
+		ret = send_buf(ftdic, buf, i);
+		failed = ret;
+		/* We can't abort here, we still have to deassert CS#. */
+		if (ret)
+			fprintf(stderr, "send_buf failed before read: %i\n",
+				ret);
+		i = 0;
+		if (ret == 0) {
+			/*
+			 * FIXME: This is unreliable. There's no guarantee that
+			 * we read the response directly after sending the read
+			 * command. We may be scheduled out etc.
+			 */
+			ret = get_buf(ftdic, readarr, readcnt);
+			failed |= ret;
+			/* We can't abort here either. */
+			if (ret)
+				fprintf(stderr, "get_buf failed: %i\n", ret);
+		}
+	}
+
+	printf_debug("De-assert CS#\n");
+	buf[i++] = SET_BITS_LOW;
+	buf[i++] = CS_BIT;
+	buf[i++] = 0x0b;
+	ret = send_buf(ftdic, buf, i);
+	failed |= ret;
+	if (ret)
+		fprintf(stderr, "send_buf failed at end: %i\n", ret);
+
+	return failed ? -1 : 0;
+}
+
+int ft2232_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
+{
+	/* Maximum read length is 64k bytes. */
+	return spi_read_chunked(flash, buf, start, len, 64 * 1024);
+}
+
+int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf)
+{
+	int total_size = 1024 * flash->total_size;
+	int i;
+
+	spi_disable_blockprotect();
+	/* Erase first. */
+	printf("Erasing flash before programming... ");
+	if (erase_flash(flash)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	printf("done.\n");
+	printf_debug("total_size is %d\n", total_size);
+	for (i = 0; i < total_size; i += 256) {
+		int l, r;
+		if (i + 256 <= total_size)
+			l = 256;
+		else
+			l = total_size - i;
+
+		if ((r = spi_nbyte_program(i, &buf[i], l))) {
+			fprintf(stderr, "%s: write fail %d\n", __func__, r);
+			return 1;
+		}
+
+		while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+			/* loop */;
+	}
+
+	return 0;
+}
+
+#endif
diff --git a/libflashrom/gfxnvidia.c b/libflashrom/gfxnvidia.c
new file mode 100644
index 0000000..1e9b679
--- /dev/null
+++ b/libflashrom/gfxnvidia.c
@@ -0,0 +1,104 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include "flash.h"
+
+#define PCI_VENDOR_ID_NVIDIA	0x10de
+
+uint8_t *nvidia_bar;
+
+struct pcidev_status gfx_nvidia[] = {
+	{0x10de, 0x0010, PCI_NT, "NVIDIA", "Mutara V08 [NV2]" },
+	{0x10de, 0x0018, PCI_NT, "NVIDIA", "RIVA 128" },
+	{0x10de, 0x0020, PCI_NT, "NVIDIA", "RIVA TNT" },
+	{0x10de, 0x0028, PCI_NT, "NVIDIA", "RIVA TNT2/TNT2 Pro" },
+	{0x10de, 0x0029, PCI_NT, "NVIDIA", "RIVA TNT2 Ultra" },
+	{0x10de, 0x002c, PCI_NT, "NVIDIA", "Vanta/Vanta LT" },
+	{0x10de, 0x002d, PCI_OK, "NVIDIA", "RIVA TNT2 Model 64/Model 64 Pro" },
+	{0x10de, 0x00a0, PCI_NT, "NVIDIA", "Aladdin TNT2" },
+	{0x10de, 0x0100, PCI_NT, "NVIDIA", "GeForce 256" },
+	{0x10de, 0x0101, PCI_NT, "NVIDIA", "GeForce DDR" },
+	{0x10de, 0x0103, PCI_NT, "NVIDIA", "Quadro" },
+	{0x10de, 0x0110, PCI_NT, "NVIDIA", "GeForce2 MX" },
+	{0x10de, 0x0111, PCI_NT, "NVIDIA", "GeForce2 MX" },
+	{0x10de, 0x0112, PCI_NT, "NVIDIA", "GeForce2 GO" },
+	{0x10de, 0x0113, PCI_NT, "NVIDIA", "Quadro2 MXR" },
+	{0x10de, 0x0150, PCI_NT, "NVIDIA", "GeForce2 GTS/Pro" },
+	{0x10de, 0x0151, PCI_NT, "NVIDIA", "GeForce2 GTS" },
+	{0x10de, 0x0152, PCI_NT, "NVIDIA", "GeForce2 Ultra" },
+	{0x10de, 0x0153, PCI_NT, "NVIDIA", "Quadro2 Pro" },
+	{0x10de, 0x0200, PCI_NT, "NVIDIA", "GeForce 3 nFX" },
+	{0x10de, 0x0201, PCI_NT, "NVIDIA", "GeForce 3 nFX" },
+	{0x10de, 0x0202, PCI_NT, "NVIDIA", "GeForce 3 nFX Ultra" },
+	{0x10de, 0x0203, PCI_NT, "NVIDIA", "Quadro 3 DDC" },
+
+	{},
+};
+
+int gfxnvidia_init(void)
+{
+	uint32_t reg32;
+
+	get_io_perms();
+
+	io_base_addr = pcidev_init(PCI_VENDOR_ID_NVIDIA, PCI_BASE_ADDRESS_0,
+				   gfx_nvidia, programmer_param);
+	io_base_addr += 0x300000;
+	printf("Detected NVIDIA I/O base address: 0x%x.\n", io_base_addr);
+
+	/* Allow access to flash interface (will disable screen). */
+	reg32 = pci_read_long(pcidev_dev, 0x50);
+	reg32 &= ~(1 << 0);
+	pci_write_long(pcidev_dev, 0x50, reg32);
+
+	nvidia_bar = physmap("NVIDIA", io_base_addr, 16 * 1024 * 1024);
+
+	buses_supported = CHIP_BUSTYPE_PARALLEL;
+
+	return 0;
+}
+
+int gfxnvidia_shutdown(void)
+{
+	uint32_t reg32;
+
+	/* Disallow access to flash interface (and re-enable screen). */
+	reg32 = pci_read_long(pcidev_dev, 0x50);
+	reg32 |= (1 << 0);
+	pci_write_long(pcidev_dev, 0x50, reg32);
+
+	free(programmer_param);
+	pci_cleanup(pacc);
+	release_io_perms();
+	return 0;
+}
+
+void gfxnvidia_chip_writeb(uint8_t val, chipaddr addr)
+{
+	mmio_writeb(val, nvidia_bar + addr);
+}
+
+uint8_t gfxnvidia_chip_readb(const chipaddr addr)
+{
+	return mmio_readb(nvidia_bar + addr);
+}
diff --git a/libflashrom/ichspi.c b/libflashrom/ichspi.c
new file mode 100644
index 0000000..cd02b96
--- /dev/null
+++ b/libflashrom/ichspi.c
@@ -0,0 +1,763 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2008 Stefan Wildemann <stefan.wildemann@kontron.com>
+ * Copyright (C) 2008 Claus Gindhart <claus.gindhart@kontron.com>
+ * Copyright (C) 2008 Dominik Geyer <dominik.geyer@kontron.com>
+ * Copyright (C) 2008 coresystems GmbH <info@coresystems.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * This module is designed for supporting the devices
+ * ST M25P40
+ * ST M25P80
+ * ST M25P16
+ * ST M25P32 already tested
+ * ST M25P64
+ * AT 25DF321 already tested
+ *
+ */
+
+#include <string.h>
+#include "flash.h"
+#include "spi.h"
+
+/* ICH9 controller register definition */
+#define ICH9_REG_FADDR         0x08	/* 32 Bits */
+#define ICH9_REG_FDATA0                0x10	/* 64 Bytes */
+
+#define ICH9_REG_SSFS          0x90	/* 08 Bits */
+#define SSFS_SCIP		0x00000001
+#define SSFS_CDS		0x00000004
+#define SSFS_FCERR		0x00000008
+#define SSFS_AEL		0x00000010
+
+#define ICH9_REG_SSFC          0x91	/* 24 Bits */
+#define SSFC_SCGO		0x00000200
+#define SSFC_ACS		0x00000400
+#define SSFC_SPOP		0x00000800
+#define SSFC_COP		0x00001000
+#define SSFC_DBC		0x00010000
+#define SSFC_DS			0x00400000
+#define SSFC_SME		0x00800000
+#define SSFC_SCF		0x01000000
+#define SSFC_SCF_20MHZ 0x00000000
+#define SSFC_SCF_33MHZ 0x01000000
+
+#define ICH9_REG_PREOP         0x94	/* 16 Bits */
+#define ICH9_REG_OPTYPE                0x96	/* 16 Bits */
+#define ICH9_REG_OPMENU                0x98	/* 64 Bits */
+
+// ICH9R SPI commands
+#define SPI_OPCODE_TYPE_READ_NO_ADDRESS     0
+#define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS    1
+#define SPI_OPCODE_TYPE_READ_WITH_ADDRESS   2
+#define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS  3
+
+// ICH7 registers
+#define ICH7_REG_SPIS          0x00	/* 16 Bits */
+#define SPIS_SCIP              0x00000001
+#define SPIS_CDS               0x00000004
+#define SPIS_FCERR             0x00000008
+
+/* VIA SPI is compatible with ICH7, but maxdata
+   to transfer is 16 bytes.
+
+   DATA byte count on ICH7 is 8:13, on VIA 8:11
+
+   bit 12 is port select CS0 CS1
+   bit 13 is FAST READ enable
+   bit 7  is used with fast read and one shot controls CS de-assert?
+*/
+
+#define ICH7_REG_SPIC          0x02	/* 16 Bits */
+#define SPIC_SCGO              0x0002
+#define SPIC_ACS               0x0004
+#define SPIC_SPOP              0x0008
+#define SPIC_DS                0x4000
+
+#define ICH7_REG_SPIA          0x04	/* 32 Bits */
+#define ICH7_REG_SPID0         0x08	/* 64 Bytes */
+#define ICH7_REG_PREOP         0x54	/* 16 Bits */
+#define ICH7_REG_OPTYPE                0x56	/* 16 Bits */
+#define ICH7_REG_OPMENU                0x58	/* 64 Bits */
+
+/* ICH SPI configuration lock-down. May be set during chipset enabling. */
+int ichspi_lock = 0;
+
+typedef struct _OPCODE {
+	uint8_t opcode;		//This commands spi opcode
+	uint8_t spi_type;	//This commands spi type
+	uint8_t atomic;		//Use preop: (0: none, 1: preop0, 2: preop1
+} OPCODE;
+
+/* Opcode definition:
+ * Preop 1: Write Enable
+ * Preop 2: Write Status register enable
+ *
+ * OP 0: Write address
+ * OP 1: Read Address
+ * OP 2: ERASE block
+ * OP 3: Read Status register
+ * OP 4: Read ID
+ * OP 5: Write Status register
+ * OP 6: chip private (read JDEC id)
+ * OP 7: Chip erase
+ */
+typedef struct _OPCODES {
+	uint8_t preop[2];
+	OPCODE opcode[8];
+} OPCODES;
+
+static OPCODES *curopcodes = NULL;
+
+/* HW access functions */
+static uint32_t REGREAD32(int X)
+{
+	return mmio_readl(spibar + X);
+}
+
+static uint16_t REGREAD16(int X)
+{
+	return mmio_readw(spibar + X);
+}
+
+#define REGWRITE32(X,Y) mmio_writel(Y, spibar+X)
+#define REGWRITE16(X,Y) mmio_writew(Y, spibar+X)
+#define REGWRITE8(X,Y)  mmio_writeb(Y, spibar+X)
+
+/* Common SPI functions */
+static int find_opcode(OPCODES *op, uint8_t opcode);
+static int find_preop(OPCODES *op, uint8_t preop);
+static int generate_opcodes(OPCODES * op);
+static int program_opcodes(OPCODES * op);
+static int run_opcode(OPCODE op, uint32_t offset,
+		      uint8_t datalength, uint8_t * data);
+static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes,
+			      int offset, int maxdata);
+
+/* for pairing opcodes with their required preop */
+struct preop_opcode_pair {
+	uint8_t preop;
+	uint8_t opcode;
+};
+
+struct preop_opcode_pair pops[] = {
+	{JEDEC_WREN, JEDEC_BYTE_PROGRAM},
+	{JEDEC_WREN, JEDEC_SE}, /* sector erase */
+	{JEDEC_WREN, JEDEC_BE_52}, /* block erase */
+	{JEDEC_WREN, JEDEC_BE_D8}, /* block erase */
+	{JEDEC_WREN, JEDEC_CE_60}, /* chip erase */
+	{JEDEC_WREN, JEDEC_CE_C7}, /* chip erase */
+	{JEDEC_EWSR, JEDEC_WRSR},
+	{0,}
+};
+
+OPCODES O_ST_M25P = {
+	{
+	 JEDEC_WREN,
+	 0},
+	{
+	 {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1},	// Write Byte
+	 {JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0},	// Read Data
+	 {JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1},	// Erase Sector
+	 {JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0},	// Read Device Status Reg
+	 {JEDEC_REMS, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0},	// Read Electronic Manufacturer Signature
+	 {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1},	// Write Status Register
+	 {JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0},	// Read JDEC ID
+	 {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1},	// Bulk erase
+	 }
+};
+
+OPCODES O_EXISTING = {};
+
+static int find_opcode(OPCODES *op, uint8_t opcode)
+{
+	int a;
+
+	for (a = 0; a < 8; a++) {
+		if (op->opcode[a].opcode == opcode)
+			return a;
+	}
+
+	return -1;
+}
+
+static int find_preop(OPCODES *op, uint8_t preop)
+{
+	int a;
+
+	for (a = 0; a < 2; a++) {
+		if (op->preop[a] == preop)
+			return a;
+	}
+
+	return -1;
+}
+
+static int generate_opcodes(OPCODES * op)
+{
+	int a, b, i;
+	uint16_t preop, optype;
+	uint32_t opmenu[2];
+
+	if (op == NULL) {
+		printf_debug("\n%s: null OPCODES pointer!\n", __func__);
+		return -1;
+	}
+
+	switch (spi_controller) {
+	case SPI_CONTROLLER_ICH7:
+	case SPI_CONTROLLER_VIA:
+		preop = REGREAD16(ICH7_REG_PREOP);
+		optype = REGREAD16(ICH7_REG_OPTYPE);
+		opmenu[0] = REGREAD32(ICH7_REG_OPMENU);
+		opmenu[1] = REGREAD32(ICH7_REG_OPMENU + 4);
+		break;
+	case SPI_CONTROLLER_ICH9:
+		preop = REGREAD16(ICH9_REG_PREOP);
+		optype = REGREAD16(ICH9_REG_OPTYPE);
+		opmenu[0] = REGREAD32(ICH9_REG_OPMENU);
+		opmenu[1] = REGREAD32(ICH9_REG_OPMENU + 4);
+		break;
+	default:
+		printf_debug("%s: unsupported chipset\n", __func__);
+		return -1;
+	}
+
+	op->preop[0] = (uint8_t) preop;
+	op->preop[1] = (uint8_t) (preop >> 8);
+
+	for (a = 0; a < 8; a++) {
+		op->opcode[a].spi_type = (uint8_t) (optype & 0x3);
+		optype >>= 2;
+	}
+
+	for (a = 0; a < 4; a++) {
+		op->opcode[a].opcode = (uint8_t) (opmenu[0] & 0xff);
+		opmenu[0] >>= 8;
+	}
+
+	for (a = 4; a < 8; a++) {
+		op->opcode[a].opcode = (uint8_t) (opmenu[1] & 0xff);
+		opmenu[1] >>= 8;
+	}
+
+	/* atomic (link opcode with required pre-op) */
+	for (a = 4; a < 8; a++)
+		op->opcode[a].atomic = 0;
+
+	for (i = 0; pops[i].opcode; i++) {
+		a = find_opcode(op, pops[i].opcode);
+		b = find_preop(op, pops[i].preop);
+		if ((a != -1) && (b != -1))
+			op->opcode[a].atomic = (uint8_t) ++b;
+	}
+
+	return 0;
+}
+
+int program_opcodes(OPCODES * op)
+{
+	uint8_t a;
+	uint16_t preop, optype;
+	uint32_t opmenu[2];
+
+	/* Program Prefix Opcodes */
+	/* 0:7 Prefix Opcode 1 */
+	preop = (op->preop[0]);
+	/* 8:16 Prefix Opcode 2 */
+	preop |= ((uint16_t) op->preop[1]) << 8;
+
+	/* Program Opcode Types 0 - 7 */
+	optype = 0;
+	for (a = 0; a < 8; a++) {
+		optype |= ((uint16_t) op->opcode[a].spi_type) << (a * 2);
+	}
+
+	/* Program Allowable Opcodes 0 - 3 */
+	opmenu[0] = 0;
+	for (a = 0; a < 4; a++) {
+		opmenu[0] |= ((uint32_t) op->opcode[a].opcode) << (a * 8);
+	}
+
+	/*Program Allowable Opcodes 4 - 7 */
+	opmenu[1] = 0;
+	for (a = 4; a < 8; a++) {
+		opmenu[1] |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8);
+	}
+
+	printf_debug("\n%s: preop=%04x optype=%04x opmenu=%08x%08x\n", __func__, preop, optype, opmenu[0], opmenu[1]);
+	switch (spi_controller) {
+	case SPI_CONTROLLER_ICH7:
+	case SPI_CONTROLLER_VIA:
+		REGWRITE16(ICH7_REG_PREOP, preop);
+		REGWRITE16(ICH7_REG_OPTYPE, optype);
+		REGWRITE32(ICH7_REG_OPMENU, opmenu[0]);
+		REGWRITE32(ICH7_REG_OPMENU + 4, opmenu[1]);
+		break;
+	case SPI_CONTROLLER_ICH9:
+		REGWRITE16(ICH9_REG_PREOP, preop);
+		REGWRITE16(ICH9_REG_OPTYPE, optype);
+		REGWRITE32(ICH9_REG_OPMENU, opmenu[0]);
+		REGWRITE32(ICH9_REG_OPMENU + 4, opmenu[1]);
+		break;
+	default:
+		printf_debug("%s: unsupported chipset\n", __func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+/* This function generates OPCODES from or programs OPCODES to ICH according to
+ * the chipset's SPI configuration lock.
+ *
+ * It should be called before ICH sends any spi command.
+ */
+int ich_init_opcodes(void)
+{
+	int rc = 0;
+	OPCODES *curopcodes_done;
+
+	if (curopcodes)
+		return 0;
+
+	if (ichspi_lock) {
+		printf_debug("Generating OPCODES... ");
+		curopcodes_done = &O_EXISTING;
+		rc = generate_opcodes(curopcodes_done);
+	} else {
+		printf_debug("Programming OPCODES... ");
+		curopcodes_done = &O_ST_M25P;
+		rc = program_opcodes(curopcodes_done);
+	}
+
+	if (rc) {
+		curopcodes = NULL;
+		printf_debug("failed\n");
+		return 1;
+	} else {
+		curopcodes = curopcodes_done;
+		printf_debug("done\n");
+		return 0;
+	}
+}
+
+static int ich7_run_opcode(OPCODE op, uint32_t offset,
+			   uint8_t datalength, uint8_t * data, int maxdata)
+{
+	int write_cmd = 0;
+	int timeout;
+	uint32_t temp32 = 0;
+	uint16_t temp16;
+	uint32_t a;
+	uint64_t opmenu;
+	int opcode_index;
+
+	/* Is it a write command? */
+	if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
+	    || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
+		write_cmd = 1;
+	}
+
+	/* Programm Offset in Flash into FADDR */
+	REGWRITE32(ICH7_REG_SPIA, (offset & 0x00FFFFFF));	/* SPI addresses are 24 BIT only */
+
+	/* Program data into FDATA0 to N */
+	if (write_cmd && (datalength != 0)) {
+		temp32 = 0;
+		for (a = 0; a < datalength; a++) {
+			if ((a % 4) == 0) {
+				temp32 = 0;
+			}
+
+			temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
+
+			if ((a % 4) == 3) {
+				REGWRITE32(ICH7_REG_SPID0 + (a - (a % 4)),
+					   temp32);
+			}
+		}
+		if (((a - 1) % 4) != 3) {
+			REGWRITE32(ICH7_REG_SPID0 +
+				   ((a - 1) - ((a - 1) % 4)), temp32);
+		}
+
+	}
+
+	/* Assemble SPIS */
+	temp16 = 0;
+	/* clear error status registers */
+	temp16 |= (SPIS_CDS + SPIS_FCERR);
+	REGWRITE16(ICH7_REG_SPIS, temp16);
+
+	/* Assemble SPIC */
+	temp16 = 0;
+
+	if (datalength != 0) {
+		temp16 |= SPIC_DS;
+		temp16 |= ((uint32_t) ((datalength - 1) & (maxdata - 1))) << 8;
+	}
+
+	/* Select opcode */
+	opmenu = REGREAD32(ICH7_REG_OPMENU);
+	opmenu |= ((uint64_t)REGREAD32(ICH7_REG_OPMENU + 4)) << 32;
+
+	for (opcode_index = 0; opcode_index < 8; opcode_index++) {
+		if ((opmenu & 0xff) == op.opcode) {
+			break;
+		}
+		opmenu >>= 8;
+	}
+	if (opcode_index == 8) {
+		printf_debug("Opcode %x not found.\n", op.opcode);
+		return 1;
+	}
+	temp16 |= ((uint16_t) (opcode_index & 0x07)) << 4;
+
+	/* Handle Atomic */
+	if (op.atomic != 0) {
+		/* Select atomic command */
+		temp16 |= SPIC_ACS;
+		/* Select prefix opcode */
+		if ((op.atomic - 1) == 1) {
+			/*Select prefix opcode 2 */
+			temp16 |= SPIC_SPOP;
+		}
+	}
+
+	/* Start */
+	temp16 |= SPIC_SCGO;
+
+	/* write it */
+	REGWRITE16(ICH7_REG_SPIC, temp16);
+
+	/* wait for cycle complete */
+	timeout = 100 * 1000 * 60;	// 60s is a looong timeout.
+	while (((REGREAD16(ICH7_REG_SPIS) & SPIS_CDS) == 0) && --timeout) {
+		programmer_delay(10);
+	}
+	if (!timeout) {
+		printf_debug("timeout\n");
+	}
+
+	if ((REGREAD16(ICH7_REG_SPIS) & SPIS_FCERR) != 0) {
+		printf_debug("Transaction error!\n");
+		return 1;
+	}
+
+	if ((!write_cmd) && (datalength != 0)) {
+		for (a = 0; a < datalength; a++) {
+			if ((a % 4) == 0) {
+				temp32 = REGREAD32(ICH7_REG_SPID0 + (a));
+			}
+
+			data[a] =
+			    (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8)))
+			    >> ((a % 4) * 8);
+		}
+	}
+
+	return 0;
+}
+
+static int ich9_run_opcode(OPCODE op, uint32_t offset,
+			   uint8_t datalength, uint8_t * data)
+{
+	int write_cmd = 0;
+	int timeout;
+	uint32_t temp32;
+	uint32_t a;
+	uint64_t opmenu;
+	int opcode_index;
+
+	/* Is it a write command? */
+	if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
+	    || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
+		write_cmd = 1;
+	}
+
+	/* Programm Offset in Flash into FADDR */
+	REGWRITE32(ICH9_REG_FADDR, (offset & 0x00FFFFFF));	/* SPI addresses are 24 BIT only */
+
+	/* Program data into FDATA0 to N */
+	if (write_cmd && (datalength != 0)) {
+		temp32 = 0;
+		for (a = 0; a < datalength; a++) {
+			if ((a % 4) == 0) {
+				temp32 = 0;
+			}
+
+			temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
+
+			if ((a % 4) == 3) {
+				REGWRITE32(ICH9_REG_FDATA0 + (a - (a % 4)),
+					   temp32);
+			}
+		}
+		if (((a - 1) % 4) != 3) {
+			REGWRITE32(ICH9_REG_FDATA0 +
+				   ((a - 1) - ((a - 1) % 4)), temp32);
+		}
+	}
+
+	/* Assemble SSFS + SSFC */
+	temp32 = 0;
+
+	/* clear error status registers */
+	temp32 |= (SSFS_CDS + SSFS_FCERR);
+	/* USE 20 MhZ */
+	temp32 |= SSFC_SCF_20MHZ;
+
+	if (datalength != 0) {
+		uint32_t datatemp;
+		temp32 |= SSFC_DS;
+		datatemp = ((uint32_t) ((datalength - 1) & 0x3f)) << (8 + 8);
+		temp32 |= datatemp;
+	}
+
+	/* Select opcode */
+	opmenu = REGREAD32(ICH9_REG_OPMENU);
+	opmenu |= ((uint64_t)REGREAD32(ICH9_REG_OPMENU + 4)) << 32;
+
+	for (opcode_index = 0; opcode_index < 8; opcode_index++) {
+		if ((opmenu & 0xff) == op.opcode) {
+			break;
+		}
+		opmenu >>= 8;
+	}
+	if (opcode_index == 8) {
+		printf_debug("Opcode %x not found.\n", op.opcode);
+		return 1;
+	}
+	temp32 |= ((uint32_t) (opcode_index & 0x07)) << (8 + 4);
+
+	/* Handle Atomic */
+	if (op.atomic != 0) {
+		/* Select atomic command */
+		temp32 |= SSFC_ACS;
+		/* Selct prefix opcode */
+		if ((op.atomic - 1) == 1) {
+			/*Select prefix opcode 2 */
+			temp32 |= SSFC_SPOP;
+		}
+	}
+
+	/* Start */
+	temp32 |= SSFC_SCGO;
+
+	/* write it */
+	REGWRITE32(ICH9_REG_SSFS, temp32);
+
+	/*wait for cycle complete */
+	timeout = 100 * 1000 * 60;	// 60s is a looong timeout.
+	while (((REGREAD32(ICH9_REG_SSFS) & SSFS_CDS) == 0) && --timeout) {
+		programmer_delay(10);
+	}
+	if (!timeout) {
+		printf_debug("timeout\n");
+	}
+
+	if ((REGREAD32(ICH9_REG_SSFS) & SSFS_FCERR) != 0) {
+		printf_debug("Transaction error!\n");
+		return 1;
+	}
+
+	if ((!write_cmd) && (datalength != 0)) {
+		for (a = 0; a < datalength; a++) {
+			if ((a % 4) == 0) {
+				temp32 = REGREAD32(ICH9_REG_FDATA0 + (a));
+			}
+
+			data[a] =
+			    (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8)))
+			    >> ((a % 4) * 8);
+		}
+	}
+
+	return 0;
+}
+
+static int run_opcode(OPCODE op, uint32_t offset,
+		      uint8_t datalength, uint8_t * data)
+{
+	switch (spi_controller) {
+	case SPI_CONTROLLER_VIA:
+		if (datalength > 16)
+			return SPI_INVALID_LENGTH;
+		return ich7_run_opcode(op, offset, datalength, data, 16);
+	case SPI_CONTROLLER_ICH7:
+		if (datalength > 64)
+			return SPI_INVALID_LENGTH;
+		return ich7_run_opcode(op, offset, datalength, data, 64);
+	case SPI_CONTROLLER_ICH9:
+		if (datalength > 64)
+			return SPI_INVALID_LENGTH;
+		return ich9_run_opcode(op, offset, datalength, data);
+	default:
+		printf_debug("%s: unsupported chipset\n", __func__);
+	}
+
+	/* If we ever get here, something really weird happened */
+	return -1;
+}
+
+static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes,
+			      int offset, int maxdata)
+{
+	int page_size = flash->page_size;
+	uint32_t remaining = page_size;
+	int towrite;
+
+	printf_debug("ich_spi_write_page: offset=%d, number=%d, buf=%p\n",
+		     offset, page_size, bytes);
+
+	for (; remaining > 0; remaining -= towrite) {
+		towrite = min(remaining, maxdata);
+		if (spi_nbyte_program(offset + (page_size - remaining),
+				      &bytes[page_size - remaining], towrite)) {
+			printf_debug("Error writing");
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+int ich_spi_read(struct flashchip *flash, uint8_t * buf, int start, int len)
+{
+	int maxdata = 64;
+
+	if (spi_controller == SPI_CONTROLLER_VIA)
+		maxdata = 16;
+
+	return spi_read_chunked(flash, buf, start, len, maxdata);
+}
+
+int ich_spi_write_256(struct flashchip *flash, uint8_t * buf)
+{
+	int i, j, rc = 0;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+	int erase_size = 64 * 1024;
+	int maxdata = 64;
+
+	spi_disable_blockprotect();
+	/* Erase first */
+	printf("Erasing flash before programming... ");
+	if (erase_flash(flash)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	printf("done.\n");
+
+	printf("Programming page: \n");
+	for (i = 0; i < total_size / erase_size; i++) {
+		if (spi_controller == SPI_CONTROLLER_VIA)
+			maxdata = 16;
+
+		for (j = 0; j < erase_size / page_size; j++) {
+			ich_spi_write_page(flash,
+			   (void *)(buf + (i * erase_size) + (j * page_size)),
+			   (i * erase_size) + (j * page_size), maxdata);
+		}
+	}
+
+	printf("\n");
+
+	return rc;
+}
+
+int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		    const unsigned char *writearr, unsigned char *readarr)
+{
+	int a;
+	int result;
+	int opcode_index = -1;
+	const unsigned char cmd = *writearr;
+	OPCODE *opcode;
+	uint32_t addr = 0;
+	uint8_t *data;
+	int count;
+
+	/* find cmd in opcodes-table */
+	for (a = 0; a < 8; a++) {
+		if ((curopcodes->opcode[a]).opcode == cmd) {
+			opcode_index = a;
+			break;
+		}
+	}
+
+	/* unknown / not programmed command */
+	if (opcode_index == -1) {
+		printf_debug("Invalid OPCODE 0x%02x\n", cmd);
+		return SPI_INVALID_OPCODE;
+	}
+
+	opcode = &(curopcodes->opcode[opcode_index]);
+
+	/* if opcode-type requires an address */
+	if (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS ||
+	    opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
+		addr = (writearr[1] << 16) |
+		    (writearr[2] << 8) | (writearr[3] << 0);
+	}
+
+	/* translate read/write array/count */
+	if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) {
+		data = (uint8_t *) (writearr + 1);
+		count = writecnt - 1;
+	} else if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
+		data = (uint8_t *) (writearr + 4);
+		count = writecnt - 4;
+	} else {
+		data = (uint8_t *) readarr;
+		count = readcnt;
+	}
+
+	result = run_opcode(*opcode, addr, count, data);
+	if (result) {
+		printf_debug("run OPCODE 0x%02x failed\n", opcode->opcode);
+	}
+
+	return result;
+}
+
+int ich_spi_send_multicommand(struct spi_command *cmds)
+{
+	int ret = 0;
+	int oppos, preoppos;
+	for (; (cmds->writecnt || cmds->readcnt) && !ret; cmds++) {
+		/* Is the next command valid or a terminator? */
+		if ((cmds + 1)->writecnt || (cmds + 1)->readcnt) {
+			preoppos = find_preop(curopcodes, cmds->writearr[0]);
+			oppos = find_opcode(curopcodes, (cmds + 1)->writearr[0]);
+			/* Is the opcode of the current command listed in the
+			 * ICH struct OPCODES as associated preopcode for the
+			 * opcode of the next command?
+			 */
+			if ((oppos != -1) && (preoppos != -1) &&
+			    ((curopcodes->opcode[oppos].atomic - 1) == preoppos))
+				continue;
+		}	
+			
+		ret = ich_spi_send_command(cmds->writecnt, cmds->readcnt,
+					   cmds->writearr, cmds->readarr);
+	}
+	return ret;
+}
diff --git a/libflashrom/internal.c b/libflashrom/internal.c
new file mode 100644
index 0000000..fc662c5
--- /dev/null
+++ b/libflashrom/internal.c
@@ -0,0 +1,320 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include "flash.h"
+
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+int io_fd;
+#endif
+
+struct pci_dev *pci_dev_find_filter(struct pci_filter filter)
+{
+	struct pci_dev *temp;
+
+	for (temp = pacc->devices; temp; temp = temp->next)
+		if (pci_filter_match(&filter, temp))
+			return temp;
+
+	return NULL;
+}
+
+struct pci_dev *pci_dev_find_vendorclass(uint16_t vendor, uint16_t class)
+{
+	struct pci_dev *temp;
+	struct pci_filter filter;
+	uint16_t tmp2;
+
+	pci_filter_init(NULL, &filter);
+	filter.vendor = vendor;
+
+	for (temp = pacc->devices; temp; temp = temp->next)
+		if (pci_filter_match(&filter, temp)) {
+			/* Read PCI class */
+			tmp2 = pci_read_word(temp, 0x0a);
+			if (tmp2 == class)
+				return temp;
+		}
+
+	return NULL;
+}
+
+struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device)
+{
+	struct pci_dev *temp;
+	struct pci_filter filter;
+
+	pci_filter_init(NULL, &filter);
+	filter.vendor = vendor;
+	filter.device = device;
+
+	for (temp = pacc->devices; temp; temp = temp->next)
+		if (pci_filter_match(&filter, temp))
+			return temp;
+
+	return NULL;
+}
+
+struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device,
+			      uint16_t card_vendor, uint16_t card_device)
+{
+	struct pci_dev *temp;
+	struct pci_filter filter;
+
+	pci_filter_init(NULL, &filter);
+	filter.vendor = vendor;
+	filter.device = device;
+
+	for (temp = pacc->devices; temp; temp = temp->next)
+		if (pci_filter_match(&filter, temp)) {
+			if ((card_vendor ==
+			     pci_read_word(temp, PCI_SUBSYSTEM_VENDOR_ID))
+			    && (card_device ==
+				pci_read_word(temp, PCI_SUBSYSTEM_ID)))
+				return temp;
+		}
+
+	return NULL;
+}
+
+void get_io_perms(void)
+{
+#if defined (__sun) && (defined(__i386) || defined(__amd64))
+	if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) {
+#elif defined(__FreeBSD__) || defined (__DragonFly__)
+	if ((io_fd = open("/dev/io", O_RDWR)) < 0) {
+#else
+	if (iopl(3) != 0) {
+#endif
+		fprintf(stderr, "ERROR: Could not get I/O privileges (%s).\n"
+			"You need to be root.\n", strerror(errno));
+		exit(1);
+	}
+}
+
+void release_io_perms(void)
+{
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+	close(io_fd);
+#endif
+}
+
+int internal_init(void)
+{
+	int ret = 0;
+
+	get_io_perms();
+
+	/* Initialize PCI access for flash enables */
+	pacc = pci_alloc();	/* Get the pci_access structure */
+	/* Set all options you want -- here we stick with the defaults */
+	pci_init(pacc);		/* Initialize the PCI library */
+	pci_scan_bus(pacc);	/* We want to get the list of devices */
+
+	/* We look at the lbtable first to see if we need a
+	 * mainboard specific flash enable sequence.
+	 */
+	coreboot_init();
+
+	/* try to enable it. Failure IS an option, since not all motherboards
+	 * really need this to be done, etc., etc.
+	 */
+	ret = chipset_flash_enable();
+	if (ret == -2) {
+		printf("WARNING: No chipset found. Flash detection "
+		       "will most likely fail.\n");
+	}
+
+	board_flash_enable(lb_vendor, lb_part);
+
+	/* Even if chipset init returns an error code, we don't want to abort.
+	 * The error code might have been a warning only.
+	 * Besides that, we don't check the board enable return code either.
+	 */
+	return 0; 
+}
+
+int internal_shutdown(void)
+{
+	release_io_perms();
+
+	return 0;
+}
+
+void internal_chip_writeb(uint8_t val, chipaddr addr)
+{
+	mmio_writeb(val, (void *) addr);
+}
+
+void internal_chip_writew(uint16_t val, chipaddr addr)
+{
+	mmio_writew(val, (void *) addr);
+}
+
+void internal_chip_writel(uint32_t val, chipaddr addr)
+{
+	mmio_writel(val, (void *) addr);
+}
+
+uint8_t internal_chip_readb(const chipaddr addr)
+{
+	return mmio_readb((void *) addr);
+}
+
+uint16_t internal_chip_readw(const chipaddr addr)
+{
+	return mmio_readw((void *) addr);
+}
+
+uint32_t internal_chip_readl(const chipaddr addr)
+{
+	return mmio_readl((void *) addr);
+}
+
+void internal_chip_readn(uint8_t *buf, const chipaddr addr, size_t len)
+{
+	memcpy(buf, (void *)addr, len);
+	return;
+}
+
+void mmio_writeb(uint8_t val, void *addr)
+{
+	*(volatile uint8_t *) addr = val;
+}
+
+void mmio_writew(uint16_t val, void *addr)
+{
+	*(volatile uint16_t *) addr = val;
+}
+
+void mmio_writel(uint32_t val, void *addr)
+{
+	*(volatile uint32_t *) addr = val;
+}
+
+uint8_t mmio_readb(void *addr)
+{
+	return *(volatile uint8_t *) addr;
+}
+
+uint16_t mmio_readw(void *addr)
+{
+	return *(volatile uint16_t *) addr;
+}
+
+uint32_t mmio_readl(void *addr)
+{
+	return *(volatile uint32_t *) addr;
+}
+
+void internal_delay(int usecs)
+{
+	/* If the delay is >1 s, use usleep because timing does not need to
+	 * be so precise.
+	 */
+	if (usecs > 1000000) {
+		usleep(usecs);
+	} else {
+		myusec_delay(usecs);
+	}
+}
+
+/* No-op shutdown() for programmers which don't need special handling */
+int noop_shutdown(void)
+{
+	return 0;
+}
+
+/* Fallback map() for programmers which don't need special handling */
+void *fallback_map(const char *descr, unsigned long phys_addr, size_t len)
+{
+	/* FIXME: Should return phys_addr. */
+	return 0;
+}
+
+/* No-op/fallback unmap() for programmers which don't need special handling */
+void fallback_unmap(void *virt_addr, size_t len)
+{
+}
+
+/* No-op chip_writeb() for drivers not supporting addr/data pair accesses */
+uint8_t noop_chip_readb(const chipaddr addr)
+{
+	return 0xff;
+}
+
+/* No-op chip_writeb() for drivers not supporting addr/data pair accesses */
+void noop_chip_writeb(uint8_t val, chipaddr addr)
+{
+}
+
+/* Little-endian fallback for drivers not supporting 16 bit accesses */
+void fallback_chip_writew(uint16_t val, chipaddr addr)
+{
+	chip_writeb(val & 0xff, addr);
+	chip_writeb((val >> 8) & 0xff, addr + 1);
+}
+
+/* Little-endian fallback for drivers not supporting 16 bit accesses */
+uint16_t fallback_chip_readw(const chipaddr addr)
+{
+	uint16_t val;
+	val = chip_readb(addr);
+	val |= chip_readb(addr + 1) << 8;
+	return val;
+}
+
+/* Little-endian fallback for drivers not supporting 32 bit accesses */
+void fallback_chip_writel(uint32_t val, chipaddr addr)
+{
+	chip_writew(val & 0xffff, addr);
+	chip_writew((val >> 16) & 0xffff, addr + 2);
+}
+
+/* Little-endian fallback for drivers not supporting 32 bit accesses */
+uint32_t fallback_chip_readl(const chipaddr addr)
+{
+	uint32_t val;
+	val = chip_readw(addr);
+	val |= chip_readw(addr + 2) << 16;
+	return val;
+}
+
+void fallback_chip_writen(uint8_t *buf, chipaddr addr, size_t len)
+{
+	size_t i;
+	for (i = 0; i < len; i++)
+		chip_writeb(buf[i], addr + i);
+	return;
+}
+
+void fallback_chip_readn(uint8_t *buf, chipaddr addr, size_t len)
+{
+	size_t i;
+	for (i = 0; i < len; i++)
+		buf[i] = chip_readb(addr + i);
+	return;
+}
diff --git a/libflashrom/it87spi.c b/libflashrom/it87spi.c
new file mode 100644
index 0000000..a5dc06e
--- /dev/null
+++ b/libflashrom/it87spi.c
@@ -0,0 +1,293 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2007, 2008, 2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2008 Ronald Hoogenboom <ronald@zonnet.nl>
+ * Copyright (C) 2008 coresystems GmbH
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Contains the ITE IT87* SPI specific routines
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "flash.h"
+#include "spi.h"
+
+#define ITE_SUPERIO_PORT1	0x2e
+#define ITE_SUPERIO_PORT2	0x4e
+
+uint16_t it8716f_flashport = 0;
+/* use fast 33MHz SPI (<>0) or slow 16MHz (0) */
+int fast_spi = 1;
+
+/* Helper functions for most recent ITE IT87xx Super I/O chips */
+#define CHIP_ID_BYTE1_REG	0x20
+#define CHIP_ID_BYTE2_REG	0x21
+void enter_conf_mode_ite(uint16_t port)
+{
+	OUTB(0x87, port);
+	OUTB(0x01, port);
+	OUTB(0x55, port);
+	if (port == ITE_SUPERIO_PORT1)
+		OUTB(0x55, port);
+	else
+		OUTB(0xaa, port);
+}
+
+void exit_conf_mode_ite(uint16_t port)
+{
+	sio_write(port, 0x02, 0x02);
+}
+
+static uint16_t find_ite_spi_flash_port(uint16_t port)
+{
+	uint8_t tmp = 0;
+	char *portpos = NULL;
+	uint16_t id, flashport = 0;
+
+	enter_conf_mode_ite(port);
+
+	id = sio_read(port, CHIP_ID_BYTE1_REG) << 8;
+	id |= sio_read(port, CHIP_ID_BYTE2_REG);
+
+	/* TODO: Handle more IT87xx if they support flash translation */
+	if (0x8716 == id || 0x8718 == id) {
+		/* NOLDN, reg 0x24, mask out lowest bit (suspend) */
+		tmp = sio_read(port, 0x24) & 0xFE;
+		printf("Serial flash segment 0x%08x-0x%08x %sabled\n",
+		       0xFFFE0000, 0xFFFFFFFF, (tmp & 1 << 1) ? "en" : "dis");
+		printf("Serial flash segment 0x%08x-0x%08x %sabled\n",
+		       0x000E0000, 0x000FFFFF, (tmp & 1 << 1) ? "en" : "dis");
+		printf("Serial flash segment 0x%08x-0x%08x %sabled\n",
+		       0xFFEE0000, 0xFFEFFFFF, (tmp & 1 << 2) ? "en" : "dis");
+		printf("Serial flash segment 0x%08x-0x%08x %sabled\n",
+		       0xFFF80000, 0xFFFEFFFF, (tmp & 1 << 3) ? "en" : "dis");
+		printf("LPC write to serial flash %sabled\n",
+		       (tmp & 1 << 4) ? "en" : "dis");
+		/* The LPC->SPI force write enable below only makes sense for
+		 * non-programmer mode.
+		 */
+		/* If any serial flash segment is enabled, enable writing. */
+		if ((tmp & 0xe) && (!(tmp & 1 << 4))) {
+			printf("Enabling LPC write to serial flash\n");
+			tmp |= 1 << 4;
+			sio_write(port, 0x24, tmp);
+		}
+		printf("Serial flash pin %i\n", (tmp & 1 << 5) ? 87 : 29);
+		/* LDN 0x7, reg 0x64/0x65 */
+		sio_write(port, 0x07, 0x7);
+		flashport = sio_read(port, 0x64) << 8;
+		flashport |= sio_read(port, 0x65);
+		printf("Serial flash port 0x%04x\n", flashport);
+		if (programmer_param && !strlen(programmer_param)) {
+			free(programmer_param);
+			programmer_param = NULL;
+		}
+		if (programmer_param && (portpos = strstr(programmer_param, "port="))) {
+			portpos += 5;
+			flashport = strtol(portpos, (char **)NULL, 0);
+			printf("Forcing serial flash port 0x%04x\n", flashport);
+			sio_write(port, 0x64, (flashport >> 8));
+			sio_write(port, 0x65, (flashport & 0xff));
+		}
+	}
+	exit_conf_mode_ite(port);
+	return flashport;
+}
+
+int it87spi_common_init(void)
+{
+	it8716f_flashport = find_ite_spi_flash_port(ITE_SUPERIO_PORT1);
+
+	if (!it8716f_flashport)
+		it8716f_flashport = find_ite_spi_flash_port(ITE_SUPERIO_PORT2);
+
+	if (it8716f_flashport)
+		spi_controller = SPI_CONTROLLER_IT87XX;
+
+	return (!it8716f_flashport);
+}
+
+
+int it87spi_init(void)
+{
+	int ret;
+
+	get_io_perms();
+	ret = it87spi_common_init();
+	if (!ret) {
+		buses_supported = CHIP_BUSTYPE_SPI;
+	} else {
+		buses_supported = CHIP_BUSTYPE_NONE;
+	}
+	return ret;
+}
+
+int it87xx_probe_spi_flash(const char *name)
+{
+	int ret;
+
+	ret = it87spi_common_init();
+	if (!ret)
+		buses_supported |= CHIP_BUSTYPE_SPI;
+	return ret;
+}
+
+/*
+ * The IT8716F only supports commands with length 1,2,4,5 bytes including
+ * command byte and can not read more than 3 bytes from the device.
+ *
+ * This function expects writearr[0] to be the first byte sent to the device,
+ * whereas the IT8716F splits commands internally into address and non-address
+ * commands with the address in inverse wire order. That's why the register
+ * ordering in case 4 and 5 may seem strange.
+ */
+int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+			const unsigned char *writearr, unsigned char *readarr)
+{
+	uint8_t busy, writeenc;
+	int i;
+
+	do {
+		busy = INB(it8716f_flashport) & 0x80;
+	} while (busy);
+	if (readcnt > 3) {
+		printf("%s called with unsupported readcnt %i.\n",
+		       __func__, readcnt);
+		return SPI_INVALID_LENGTH;
+	}
+	switch (writecnt) {
+	case 1:
+		OUTB(writearr[0], it8716f_flashport + 1);
+		writeenc = 0x0;
+		break;
+	case 2:
+		OUTB(writearr[0], it8716f_flashport + 1);
+		OUTB(writearr[1], it8716f_flashport + 7);
+		writeenc = 0x1;
+		break;
+	case 4:
+		OUTB(writearr[0], it8716f_flashport + 1);
+		OUTB(writearr[1], it8716f_flashport + 4);
+		OUTB(writearr[2], it8716f_flashport + 3);
+		OUTB(writearr[3], it8716f_flashport + 2);
+		writeenc = 0x2;
+		break;
+	case 5:
+		OUTB(writearr[0], it8716f_flashport + 1);
+		OUTB(writearr[1], it8716f_flashport + 4);
+		OUTB(writearr[2], it8716f_flashport + 3);
+		OUTB(writearr[3], it8716f_flashport + 2);
+		OUTB(writearr[4], it8716f_flashport + 7);
+		writeenc = 0x3;
+		break;
+	default:
+		printf("%s called with unsupported writecnt %i.\n",
+		       __func__, writecnt);
+		return SPI_INVALID_LENGTH;
+	}
+	/*
+	 * Start IO, 33 or 16 MHz, readcnt input bytes, writecnt output bytes.
+	 * Note:
+	 * We can't use writecnt directly, but have to use a strange encoding.
+	 */
+	OUTB(((0x4 + (fast_spi ? 1 : 0)) << 4)
+		| ((readcnt & 0x3) << 2) | (writeenc), it8716f_flashport);
+
+	if (readcnt > 0) {
+		do {
+			busy = INB(it8716f_flashport) & 0x80;
+		} while (busy);
+
+		for (i = 0; i < readcnt; i++)
+			readarr[i] = INB(it8716f_flashport + 5 + i);
+	}
+
+	return 0;
+}
+
+/* Page size is usually 256 bytes */
+static int it8716f_spi_page_program(struct flashchip *flash, int block, uint8_t *buf)
+{
+	int i;
+	int result;
+	chipaddr bios = flash->virtual_memory;
+
+	result = spi_write_enable();
+	if (result)
+		return result;
+	/* FIXME: The command below seems to be redundant or wrong. */
+	OUTB(0x06, it8716f_flashport + 1);
+	OUTB(((2 + (fast_spi ? 1 : 0)) << 4), it8716f_flashport);
+	for (i = 0; i < 256; i++) {
+		chip_writeb(buf[256 * block + i], bios + 256 * block + i);
+	}
+	OUTB(0, it8716f_flashport);
+	/* Wait until the Write-In-Progress bit is cleared.
+	 * This usually takes 1-10 ms, so wait in 1 ms steps.
+	 */
+	while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+		programmer_delay(1000);
+	return 0;
+}
+
+/*
+ * IT8716F only allows maximum of 512 kb SPI mapped to LPC memory cycles
+ * Need to read this big flash using firmware cycles 3 byte at a time.
+ */
+int it8716f_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len)
+{
+	int total_size = 1024 * flash->total_size;
+	fast_spi = 0;
+
+	if ((programmer == PROGRAMMER_IT87SPI) || (total_size > 512 * 1024)) {
+		spi_read_chunked(flash, buf, start, len, 3);
+	} else {
+		read_memmapped(flash, buf, start, len);
+	}
+
+	return 0;
+}
+
+int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf)
+{
+	int total_size = 1024 * flash->total_size;
+	int i;
+
+	/*
+	 * IT8716F only allows maximum of 512 kb SPI chip size for memory
+	 * mapped access.
+	 */
+	if ((programmer == PROGRAMMER_IT87SPI) || (total_size > 512 * 1024)) {
+		spi_chip_write_1(flash, buf);
+	} else {
+		spi_disable_blockprotect();
+		/* Erase first */
+		printf("Erasing flash before programming... ");
+		if (erase_flash(flash)) {
+			fprintf(stderr, "ERASE FAILED!\n");
+			return -1;
+		}
+		printf("done.\n");
+		for (i = 0; i < total_size / 256; i++) {
+			it8716f_spi_page_program(flash, i, buf);
+		}
+	}
+
+	return 0;
+}
diff --git a/libflashrom/jedec.c b/libflashrom/jedec.c
new file mode 100644
index 0000000..83a0b83
--- /dev/null
+++ b/libflashrom/jedec.c
@@ -0,0 +1,382 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2006 Giampiero Giancipoli <gianci@email.it>
+ * Copyright (C) 2006 coresystems GmbH <info@coresystems.de>
+ * Copyright (C) 2007 Carl-Daniel Hailfinger
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+
+#define MAX_REFLASH_TRIES 0x10
+
+/* Check one byte for odd parity */
+uint8_t oddparity(uint8_t val)
+{
+	val = (val ^ (val >> 4)) & 0xf;
+	val = (val ^ (val >> 2)) & 0x3;
+	return (val ^ (val >> 1)) & 0x1;
+}
+
+void toggle_ready_jedec(chipaddr dst)
+{
+	unsigned int i = 0;
+	uint8_t tmp1, tmp2;
+
+	tmp1 = chip_readb(dst) & 0x40;
+
+	while (i++ < 0xFFFFFFF) {
+		tmp2 = chip_readb(dst) & 0x40;
+		if (tmp1 == tmp2) {
+			break;
+		}
+		tmp1 = tmp2;
+	}
+}
+
+void data_polling_jedec(chipaddr dst, uint8_t data)
+{
+	unsigned int i = 0;
+	uint8_t tmp;
+
+	data &= 0x80;
+
+	while (i++ < 0xFFFFFFF) {
+		tmp = chip_readb(dst) & 0x80;
+		if (tmp == data) {
+			break;
+		}
+	}
+}
+
+void start_program_jedec(chipaddr bios)
+{
+	chip_writeb(0xAA, bios + 0x5555);
+	chip_writeb(0x55, bios + 0x2AAA);
+	chip_writeb(0xA0, bios + 0x5555);
+}
+
+int probe_jedec(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+	uint8_t id1, id2;
+	uint32_t largeid1, largeid2;
+	uint32_t flashcontent1, flashcontent2;
+	int probe_timing_enter, probe_timing_exit;
+
+	if (flash->probe_timing > 0) 
+		probe_timing_enter = probe_timing_exit = flash->probe_timing;
+	else if (flash->probe_timing == TIMING_ZERO) { /* No delay. */
+		probe_timing_enter = probe_timing_exit = 0;
+	} else if (flash->probe_timing == TIMING_FIXME) { /* == _IGNORED */
+		printf_debug("Chip lacks correct probe timing information, "
+			     "using default 10mS/40uS. ");
+		probe_timing_enter = 10000;
+		probe_timing_exit = 40;
+	} else {
+		printf("Chip has negative value in probe_timing, failing "
+		       "without chip access\n");
+		return 0;
+	}
+
+	/* Issue JEDEC Product ID Entry command */
+	chip_writeb(0xAA, bios + 0x5555);
+	programmer_delay(10);
+	chip_writeb(0x55, bios + 0x2AAA);
+	programmer_delay(10);
+	chip_writeb(0x90, bios + 0x5555);
+	programmer_delay(probe_timing_enter);
+
+	/* Read product ID */
+	id1 = chip_readb(bios);
+	id2 = chip_readb(bios + 0x01);
+	largeid1 = id1;
+	largeid2 = id2;
+
+	/* Check if it is a continuation ID, this should be a while loop. */
+	if (id1 == 0x7F) {
+		largeid1 <<= 8;
+		id1 = chip_readb(bios + 0x100);
+		largeid1 |= id1;
+	}
+	if (id2 == 0x7F) {
+		largeid2 <<= 8;
+		id2 = chip_readb(bios + 0x101);
+		largeid2 |= id2;
+	}
+
+	/* Issue JEDEC Product ID Exit command */
+	chip_writeb(0xAA, bios + 0x5555);
+	programmer_delay(10);
+	chip_writeb(0x55, bios + 0x2AAA);
+	programmer_delay(10);
+	chip_writeb(0xF0, bios + 0x5555);
+	programmer_delay(probe_timing_exit);
+
+	printf_debug("%s: id1 0x%02x, id2 0x%02x", __func__, largeid1, largeid2);
+	if (!oddparity(id1))
+		printf_debug(", id1 parity violation");
+
+	/* Read the product ID location again. We should now see normal flash contents. */
+	flashcontent1 = chip_readb(bios);
+	flashcontent2 = chip_readb(bios + 0x01);
+
+	/* Check if it is a continuation ID, this should be a while loop. */
+	if (flashcontent1 == 0x7F) {
+		flashcontent1 <<= 8;
+		flashcontent1 |= chip_readb(bios + 0x100);
+	}
+	if (flashcontent2 == 0x7F) {
+		flashcontent2 <<= 8;
+		flashcontent2 |= chip_readb(bios + 0x101);
+	}
+
+	if (largeid1 == flashcontent1)
+		printf_debug(", id1 is normal flash content");
+	if (largeid2 == flashcontent2)
+		printf_debug(", id2 is normal flash content");
+
+	printf_debug("\n");
+	if (largeid1 == flash->manufacture_id && largeid2 == flash->model_id)
+		return 1;
+
+	return 0;
+}
+
+int erase_sector_jedec(struct flashchip *flash, unsigned int page, unsigned int pagesize)
+{
+	chipaddr bios = flash->virtual_memory;
+
+	/*  Issue the Sector Erase command   */
+	chip_writeb(0xAA, bios + 0x5555);
+	programmer_delay(10);
+	chip_writeb(0x55, bios + 0x2AAA);
+	programmer_delay(10);
+	chip_writeb(0x80, bios + 0x5555);
+	programmer_delay(10);
+
+	chip_writeb(0xAA, bios + 0x5555);
+	programmer_delay(10);
+	chip_writeb(0x55, bios + 0x2AAA);
+	programmer_delay(10);
+	chip_writeb(0x30, bios + page);
+	programmer_delay(10);
+
+	/* wait for Toggle bit ready         */
+	toggle_ready_jedec(bios);
+
+	if (check_erased_range(flash, page, pagesize)) {
+		fprintf(stderr,"ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+int erase_block_jedec(struct flashchip *flash, unsigned int block, unsigned int blocksize)
+{
+	chipaddr bios = flash->virtual_memory;
+
+	/*  Issue the Sector Erase command   */
+	chip_writeb(0xAA, bios + 0x5555);
+	programmer_delay(10);
+	chip_writeb(0x55, bios + 0x2AAA);
+	programmer_delay(10);
+	chip_writeb(0x80, bios + 0x5555);
+	programmer_delay(10);
+
+	chip_writeb(0xAA, bios + 0x5555);
+	programmer_delay(10);
+	chip_writeb(0x55, bios + 0x2AAA);
+	programmer_delay(10);
+	chip_writeb(0x50, bios + block);
+	programmer_delay(10);
+
+	/* wait for Toggle bit ready         */
+	toggle_ready_jedec(bios);
+
+	if (check_erased_range(flash, block, blocksize)) {
+		fprintf(stderr,"ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+int erase_chip_jedec(struct flashchip *flash)
+{
+	int total_size = flash->total_size * 1024;
+	chipaddr bios = flash->virtual_memory;
+
+	/*  Issue the JEDEC Chip Erase command   */
+	chip_writeb(0xAA, bios + 0x5555);
+	programmer_delay(10);
+	chip_writeb(0x55, bios + 0x2AAA);
+	programmer_delay(10);
+	chip_writeb(0x80, bios + 0x5555);
+	programmer_delay(10);
+
+	chip_writeb(0xAA, bios + 0x5555);
+	programmer_delay(10);
+	chip_writeb(0x55, bios + 0x2AAA);
+	programmer_delay(10);
+	chip_writeb(0x10, bios + 0x5555);
+	programmer_delay(10);
+
+	toggle_ready_jedec(bios);
+
+	if (check_erased_range(flash, 0, total_size)) {
+		fprintf(stderr,"ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+int write_page_write_jedec(struct flashchip *flash, uint8_t *src,
+			   int start, int page_size)
+{
+	int i, tried = 0, failed;
+	uint8_t *s = src;
+	chipaddr bios = flash->virtual_memory;
+	chipaddr dst = bios + start;
+	chipaddr d = dst;
+
+retry:
+	/* Issue JEDEC Data Unprotect comand */
+	start_program_jedec(bios);
+
+	/* transfer data from source to destination */
+	for (i = 0; i < page_size; i++) {
+		/* If the data is 0xFF, don't program it */
+		if (*src != 0xFF)
+			chip_writeb(*src, dst);
+		dst++;
+		src++;
+	}
+
+	toggle_ready_jedec(dst - 1);
+
+	dst = d;
+	src = s;
+	failed = verify_range(flash, src, start, page_size, NULL);
+
+	if (failed && tried++ < MAX_REFLASH_TRIES) {
+		fprintf(stderr, "retrying.\n");
+		goto retry;
+	}
+	if (failed) {
+		fprintf(stderr, " page 0x%lx failed!\n",
+			(d - bios) / page_size);
+	}
+	return failed;
+}
+
+int write_byte_program_jedec(chipaddr bios, uint8_t *src,
+			     chipaddr dst)
+{
+	int tried = 0, failed = 0;
+
+	/* If the data is 0xFF, don't program it and don't complain. */
+	if (*src == 0xFF) {
+		return 0;
+	}
+
+retry:
+	/* Issue JEDEC Byte Program command */
+	start_program_jedec(bios);
+
+	/* transfer data from source to destination */
+	chip_writeb(*src, dst);
+	toggle_ready_jedec(bios);
+
+	if (chip_readb(dst) != *src && tried++ < MAX_REFLASH_TRIES) {
+		goto retry;
+	}
+
+	if (tried >= MAX_REFLASH_TRIES)
+		failed = 1;
+
+	return failed;
+}
+
+int write_sector_jedec(chipaddr bios, uint8_t *src,
+		       chipaddr dst, unsigned int page_size)
+{
+	int i, failed = 0;
+	chipaddr olddst;
+
+	olddst = dst;
+	for (i = 0; i < page_size; i++) {
+		if (write_byte_program_jedec(bios, src, dst))
+			failed = 1;
+		dst++, src++;
+	}
+	if (failed)
+		fprintf(stderr, " writing sector at 0x%lx failed!\n", olddst);
+
+	return failed;
+}
+
+int write_jedec(struct flashchip *flash, uint8_t *buf)
+{
+	int i, failed = 0;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+
+	if (erase_chip_jedec(flash)) {
+		fprintf(stderr,"ERASE FAILED!\n");
+		return -1;
+	}
+	
+	printf("Programming page: ");
+	for (i = 0; i < total_size / page_size; i++) {
+		printf("%04d at address: 0x%08x", i, i * page_size);
+		if (write_page_write_jedec(flash, buf + i * page_size,
+					   i * page_size, page_size))
+			failed = 1;
+		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+	}
+	printf("\n");
+
+	return failed;
+}
+
+int write_jedec_1(struct flashchip *flash, uint8_t * buf)
+{
+	int i;
+	chipaddr bios = flash->virtual_memory;
+	chipaddr dst = bios;
+
+	programmer_delay(10);
+	if (erase_flash(flash)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+
+	printf("Programming page: ");
+	for (i = 0; i < flash->total_size; i++) {
+		if ((i & 0x3) == 0)
+			printf("address: 0x%08lx", (unsigned long)i * 1024);
+
+                write_sector_jedec(bios, buf + i * 1024, dst + i * 1024, 1024);
+
+		if ((i & 0x3) == 0)
+			printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+	}
+
+	printf("\n");
+	return 0;
+}
diff --git a/libflashrom/m29f002.c b/libflashrom/m29f002.c
new file mode 100644
index 0000000..01a7a50
--- /dev/null
+++ b/libflashrom/m29f002.c
@@ -0,0 +1,128 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Peter Stuge <peter@stuge.se>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+
+int erase_m29f002(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+	chip_writeb(0xaa, bios + 0x555);
+	chip_writeb(0x55, bios + 0xaaa);
+	chip_writeb(0x80, bios + 0x555);
+	chip_writeb(0xaa, bios + 0x555);
+	chip_writeb(0x55, bios + 0xaaa);
+	chip_writeb(0x10, bios + 0x555);
+	programmer_delay(10);
+	toggle_ready_jedec(bios);
+	if (check_erased_range(flash, 0, flash->total_size * 1024)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int rewrite_block(struct flashchip *flash, uint8_t *src,
+			  unsigned long start, int size)
+{
+	chipaddr bios = flash->virtual_memory;
+	chipaddr dst = bios + start;
+
+	/* erase */
+	/* FIXME: use erase_sector_jedec? */
+	chip_writeb(0xaa, bios + 0x555);
+	chip_writeb(0x55, bios + 0xaaa);
+	chip_writeb(0x80, bios + 0x555);
+	chip_writeb(0xaa, bios + 0x555);
+	chip_writeb(0x55, bios + 0xaaa);
+	chip_writeb(0x30, dst);
+	programmer_delay(10);
+	toggle_ready_jedec(bios);
+	if (check_erased_range(flash, start, size)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+
+	/* program */
+	/* FIXME: use write_sector_jedec? */
+	while (size--) {
+		chip_writeb(0xaa, bios + 0x555);
+		chip_writeb(0x55, bios + 0xaaa);
+		chip_writeb(0xa0, bios + 0x555);
+		chip_writeb(*src, dst);
+		toggle_ready_jedec(dst);
+		dst++;
+		src++;
+	}
+	return 0;
+}
+
+static int do_block(struct flashchip *flash, uint8_t *src, int i,
+		     unsigned long start, int size)
+{
+	int ret;
+	printf("%d at address: 0x%08lx", i, start);
+	ret = rewrite_block(flash, src + start, start, size);
+	if (ret)
+		return ret;
+	printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+	return 0;
+}
+
+int write_m29f002t(struct flashchip *flash, uint8_t *buf)
+{
+	int i, page_size = flash->page_size;
+
+	/* M29F002(N)T has 7 blocks. From bottom to top their sizes are:
+	 * 64k 64k 64k 32k 8k 8k 16k
+	 * flash->page_size is set to 64k in flashchips.c
+	 */
+
+	printf("Programming block: ");
+	for (i = 0; i < 3; i++)
+		do_block(flash, buf, i, i * page_size, page_size);
+	do_block(flash, buf, i++, 0x30000, 32 * 1024);
+	do_block(flash, buf, i++, 0x38000, 8 * 1024);
+	do_block(flash, buf, i++, 0x3a000, 8 * 1024);
+	do_block(flash, buf, i, 0x3c000, 16 * 1024);
+
+	printf("\n");
+	return 0;
+}
+
+int write_m29f002b(struct flashchip *flash, uint8_t *buf)
+{
+	int i = 0, page_size = flash->page_size;
+
+	/* M29F002B has 7 blocks. From bottom to top their sizes are:
+	 * 16k 8k 8k 32k 64k 64k 64k
+	 * flash->page_size is set to 64k in flashchips.c
+	 */
+
+	printf("Programming block: ");
+	do_block(flash, buf, i++, 0x00000, 16 * 1024);
+	do_block(flash, buf, i++, 0x04000, 8 * 1024);
+	do_block(flash, buf, i++, 0x06000, 8 * 1024);
+	do_block(flash, buf, i++, 0x08000, 32 * 1024);
+	for (; i < 7; i++)
+		do_block(flash, buf, i, (i - 3) * page_size, page_size);
+
+	printf("\n");
+	return 0;
+}
diff --git a/libflashrom/m29f400bt.c b/libflashrom/m29f400bt.c
new file mode 100644
index 0000000..c327f44
--- /dev/null
+++ b/libflashrom/m29f400bt.c
@@ -0,0 +1,249 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+
+/* WARNING! 
+   This chip uses the standard JEDEC Addresses in 16-bit mode as word
+   addresses. In byte mode, 0xAAA has to be used instead of 0x555 and
+   0x555 instead of 0x2AA. Do *not* blindly replace with standard JEDEC
+   functions. */
+
+void write_page_m29f400bt(chipaddr bios, uint8_t *src,
+			  chipaddr dst, int page_size)
+{
+	int i;
+
+	for (i = 0; i < page_size; i++) {
+		chip_writeb(0xAA, bios + 0xAAA);
+		chip_writeb(0x55, bios + 0x555);
+		chip_writeb(0xA0, bios + 0xAAA);
+
+		/* transfer data from source to destination */
+		chip_writeb(*src, dst);
+		//chip_writeb(0xF0, bios);
+		//programmer_delay(5);
+		toggle_ready_jedec(dst);
+		printf
+		    ("Value in the flash at address 0x%lx = %#x, want %#x\n",
+		     (dst - bios), chip_readb(dst), *src);
+		dst++;
+		src++;
+	}
+}
+
+int probe_m29f400bt(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+	uint8_t id1, id2;
+
+	chip_writeb(0xAA, bios + 0xAAA);
+	chip_writeb(0x55, bios + 0x555);
+	chip_writeb(0x90, bios + 0xAAA);
+
+	programmer_delay(10);
+
+	id1 = chip_readb(bios);
+	/* The data sheet says id2 is at (bios + 0x01) and id2 listed in
+	 * flash.h does not match. It should be possible to use JEDEC probe.
+	 */
+	id2 = chip_readb(bios + 0x02);
+
+	chip_writeb(0xAA, bios + 0xAAA);
+	chip_writeb(0x55, bios + 0x555);
+	chip_writeb(0xF0, bios + 0xAAA);
+
+	programmer_delay(10);
+
+	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+
+	if (id1 == flash->manufacture_id && id2 == flash->model_id)
+		return 1;
+
+	return 0;
+}
+
+int erase_m29f400bt(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+
+	chip_writeb(0xAA, bios + 0xAAA);
+	chip_writeb(0x55, bios + 0x555);
+	chip_writeb(0x80, bios + 0xAAA);
+
+	chip_writeb(0xAA, bios + 0xAAA);
+	chip_writeb(0x55, bios + 0x555);
+	chip_writeb(0x10, bios + 0xAAA);
+
+	programmer_delay(10);
+	toggle_ready_jedec(bios);
+
+	if (check_erased_range(flash, 0, flash->total_size * 1024)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+int block_erase_m29f400bt(struct flashchip *flash, int start, int len)
+{
+	chipaddr bios = flash->virtual_memory;
+	chipaddr dst = bios + start;
+
+	chip_writeb(0xAA, bios + 0xAAA);
+	chip_writeb(0x55, bios + 0x555);
+	chip_writeb(0x80, bios + 0xAAA);
+
+	chip_writeb(0xAA, bios + 0xAAA);
+	chip_writeb(0x55, bios + 0x555);
+	//chip_writeb(0x10, bios + 0xAAA);
+	chip_writeb(0x30, dst);
+
+	programmer_delay(10);
+	toggle_ready_jedec(bios);
+
+	if (check_erased_range(flash, start, len)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+int write_m29f400bt(struct flashchip *flash, uint8_t *buf)
+{
+	int i;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+	chipaddr bios = flash->virtual_memory;
+
+	//erase_m29f400bt (flash);
+	printf("Programming page:\n ");
+	/*********************************
+	*Pages for M29F400BT:
+	* 16	0x7c000		0x7ffff		TOP
+	*  8 	0x7a000		0x7bfff
+	*  8 	0x78000		0x79fff
+	* 32	0x70000		0x77fff
+	* 64	0x60000		0x6ffff
+	* 64	0x50000		0x5ffff
+	* 64	0x40000		0x4ffff
+	*---------------------------------
+	* 64	0x30000		0x3ffff
+	* 64	0x20000		0x2ffff
+	* 64	0x10000		0x1ffff
+	* 64	0x00000		0x0ffff		BOTTOM
+	*********************************/
+	printf("total_size/page_size = %d\n", total_size / page_size);
+	for (i = 0; i < (total_size / page_size) - 1; i++) {
+		printf("%04d at address: 0x%08x\n", i, i * page_size);
+		if (block_erase_m29f400bt(flash, i * page_size, page_size)) {
+			fprintf(stderr, "ERASE FAILED!\n");
+			return -1;
+		}
+		write_page_m29f400bt(bios, buf + i * page_size,
+				     bios + i * page_size, page_size);
+		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+	}
+
+	printf("%04d at address: 0x%08x\n", 7, 0x70000);
+	if (block_erase_m29f400bt(flash, 0x70000, 32 * 1024)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	write_page_m29f400bt(bios, buf + 0x70000, bios + 0x70000, 32 * 1024);
+
+	printf("%04d at address: 0x%08x\n", 8, 0x78000);
+	if (block_erase_m29f400bt(flash, 0x78000, 8 * 1024)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	write_page_m29f400bt(bios, buf + 0x78000, bios + 0x78000, 8 * 1024);
+
+	printf("%04d at address: 0x%08x\n", 9, 0x7a000);
+	if (block_erase_m29f400bt(flash, 0x7a000, 8 * 1024)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	write_page_m29f400bt(bios, buf + 0x7a000, bios + 0x7a000, 8 * 1024);
+
+	printf("%04d at address: 0x%08x\n", 10, 0x7c000);
+	if (block_erase_m29f400bt(flash, 0x7c000, 16 * 1024)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	write_page_m29f400bt(bios, buf + 0x7c000, bios + 0x7c000, 16 * 1024);
+
+	printf("\n");
+
+	return 0;
+}
+
+int write_coreboot_m29f400bt(struct flashchip *flash, uint8_t *buf)
+{
+	chipaddr bios = flash->virtual_memory;
+
+	printf("Programming page:\n ");
+	/*********************************
+	*Pages for M29F400BT:
+	* 16	0x7c000		0x7ffff		TOP
+	*  8 	0x7a000		0x7bfff
+	*  8 	0x78000		0x79fff
+	* 32	0x70000		0x77fff
+	* 64	0x60000		0x6ffff
+	* 64	0x50000		0x5ffff
+	* 64	0x40000		0x4ffff
+	*---------------------------------
+	* 64	0x30000		0x3ffff
+	* 64	0x20000		0x2ffff
+	* 64	0x10000		0x1ffff
+	* 64	0x00000		0x0ffff		BOTTOM
+	*********************************/
+	printf("%04d at address: 0x%08x\n", 7, 0x00000);
+	if (block_erase_m29f400bt(flash, 0x00000, 64 * 1024)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	write_page_m29f400bt(bios, buf + 0x00000, bios + 0x00000, 64 * 1024);
+
+	printf("%04d at address: 0x%08x\n", 7, 0x10000);
+	if (block_erase_m29f400bt(flash, 0x10000, 64 * 1024)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	write_page_m29f400bt(bios, buf + 0x10000, bios + 0x10000, 64 * 1024);
+
+	printf("%04d at address: 0x%08x\n", 7, 0x20000);
+	if (block_erase_m29f400bt(flash, 0x20000, 64 * 1024)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	write_page_m29f400bt(bios, buf + 0x20000, bios + 0x20000, 64 * 1024);
+
+	printf("%04d at address: 0x%08x\n", 7, 0x30000);
+	if (block_erase_m29f400bt(flash, 0x30000, 64 * 1024)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	write_page_m29f400bt(bios, buf + 0x30000, bios + 0x30000, 64 * 1024);
+
+	printf("\n");
+
+	return 0;
+}
diff --git a/libflashrom/mx29f002.c b/libflashrom/mx29f002.c
new file mode 100644
index 0000000..7838c3d
--- /dev/null
+++ b/libflashrom/mx29f002.c
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+
+int probe_29f002(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+	uint8_t id1, id2;
+
+	chip_writeb(0xAA, bios + 0x5555);
+	chip_writeb(0x55, bios + 0x2AAA);
+	chip_writeb(0x90, bios + 0x5555);
+
+	id1 = chip_readb(bios);
+	id2 = chip_readb(bios + 0x01);
+
+	chip_writeb(0xF0, bios);
+
+	programmer_delay(10);
+
+	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+	if (id1 == flash->manufacture_id && id2 == flash->model_id)
+		return 1;
+
+	return 0;
+}
+
+/* FIXME: Use erase_chip_jedec?
+ * erase_29f002 uses shorter addresses, sends F0 (exit ID mode) and
+ * and has a bigger delay before polling the toggle bit */
+int erase_29f002(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+
+	chip_writeb(0xF0, bios + 0x555);
+	chip_writeb(0xAA, bios + 0x555);
+	chip_writeb(0x55, bios + 0x2AA);
+	chip_writeb(0x80, bios + 0x555);
+	chip_writeb(0xAA, bios + 0x555);
+	chip_writeb(0x55, bios + 0x2AA);
+	chip_writeb(0x10, bios + 0x555);
+
+	programmer_delay(100);
+	toggle_ready_jedec(bios);
+
+	if (check_erased_range(flash, 0, flash->total_size * 1024)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
diff --git a/libflashrom/nic3com.c b/libflashrom/nic3com.c
new file mode 100644
index 0000000..a4878d2
--- /dev/null
+++ b/libflashrom/nic3com.c
@@ -0,0 +1,114 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include "flash.h"
+
+#define BIOS_ROM_ADDR		0x04
+#define BIOS_ROM_DATA		0x08
+#define INT_STATUS		0x0e
+#define INTERNAL_CONFIG		0x00
+#define SELECT_REG_WINDOW	0x800
+
+#define PCI_VENDOR_ID_3COM	0x10b7
+
+uint32_t internal_conf;
+uint16_t id;
+
+struct pcidev_status nics_3com[] = {
+	/* 3C90xB */
+	{0x10b7, 0x9055, PCI_OK, "3COM", "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-TX"},
+	{0x10b7, 0x9001, PCI_NT, "3COM", "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-T4" },
+	{0x10b7, 0x9004, PCI_OK, "3COM", "3C90xB: PCI 10BASE-T (TPO)" },
+	{0x10b7, 0x9005, PCI_NT, "3COM", "3C90xB: PCI 10BASE-T/10BASE2/AUI (COMBO)" },
+	{0x10b7, 0x9006, PCI_NT, "3COM", "3C90xB: PCI 10BASE-T/10BASE2 (TPC)" },
+	{0x10b7, 0x900a, PCI_NT, "3COM", "3C90xB: PCI 10BASE-FL" },
+	{0x10b7, 0x905a, PCI_NT, "3COM", "3C90xB: PCI 10BASE-FX" },
+	{0x10b7, 0x9058, PCI_OK, "3COM", "3C905B: Cyclone 10/100/BNC" },
+
+	/* 3C905C */
+	{0x10b7, 0x9200, PCI_OK, "3COM", "3C905C: EtherLink 10/100 PCI (TX)" },
+
+	/* 3C980C */
+	{0x10b7, 0x9805, PCI_NT, "3COM", "3C980C: EtherLink Server 10/100 PCI (TX)" },
+
+	{},
+};
+
+int nic3com_init(void)
+{
+	get_io_perms();
+
+	io_base_addr = pcidev_init(PCI_VENDOR_ID_3COM, PCI_BASE_ADDRESS_0,
+				   nics_3com, programmer_param);
+	id = pcidev_dev->device_id;
+
+	/* 3COM 3C90xB cards need a special fixup. */
+	if (id == 0x9055 || id == 0x9001 || id == 0x9004 || id == 0x9005
+	    || id == 0x9006 || id == 0x900a || id == 0x905a || id == 0x9058) {
+		/* Select register window 3 and save the receiver status. */
+		OUTW(SELECT_REG_WINDOW + 3, io_base_addr + INT_STATUS);
+		internal_conf = INL(io_base_addr + INTERNAL_CONFIG);
+
+		/* Set receiver type to MII for full BIOS ROM access. */
+		OUTL((internal_conf & 0xf00fffff) | 0x00600000, io_base_addr);
+	}
+
+	/*
+	 * The lowest 16 bytes of the I/O mapped register space of (most) 3COM
+	 * cards form a 'register window' into one of multiple (usually 8)
+	 * register banks. For 3C90xB/3C90xC we need register window/bank 0.
+	 */
+	OUTW(SELECT_REG_WINDOW + 0, io_base_addr + INT_STATUS);
+
+	buses_supported = CHIP_BUSTYPE_PARALLEL;
+
+	return 0;
+}
+
+int nic3com_shutdown(void)
+{
+	/* 3COM 3C90xB cards need a special fixup. */
+	if (id == 0x9055 || id == 0x9001 || id == 0x9004 || id == 0x9005
+	    || id == 0x9006 || id == 0x900a || id == 0x905a || id == 0x9058) {
+		/* Select register window 3 and restore the receiver status. */
+		OUTW(SELECT_REG_WINDOW + 3, io_base_addr + INT_STATUS);
+		OUTL(internal_conf, io_base_addr + INTERNAL_CONFIG);
+	}
+
+	free(programmer_param);
+	pci_cleanup(pacc);
+	release_io_perms();
+	return 0;
+}
+
+void nic3com_chip_writeb(uint8_t val, chipaddr addr)
+{
+	OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR);
+	OUTB(val, io_base_addr + BIOS_ROM_DATA);
+}
+
+uint8_t nic3com_chip_readb(const chipaddr addr)
+{
+	OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR);
+	return INB(io_base_addr + BIOS_ROM_DATA);
+}
diff --git a/libflashrom/pcidev.c b/libflashrom/pcidev.c
new file mode 100644
index 0000000..6c92c0a
--- /dev/null
+++ b/libflashrom/pcidev.c
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include "flash.h"
+
+uint32_t io_base_addr;
+struct pci_access *pacc;
+struct pci_filter filter;
+struct pci_dev *pcidev_dev = NULL;
+
+uint32_t pcidev_validate(struct pci_dev *dev, uint32_t bar,
+			 struct pcidev_status *devs)
+{
+	int i;
+	uint32_t addr;
+
+	for (i = 0; devs[i].device_name != NULL; i++) {
+		if (dev->device_id != devs[i].device_id)
+			continue;
+
+		/*
+		 * Don't use dev->base_addr[x] (as value for 'bar'), won't
+		 * work on older libpci.
+		 */
+		addr = pci_read_long(dev, bar) & ~0x03;
+		
+		printf("Found \"%s %s\" (%04x:%04x, BDF %02x:%02x.%x).\n",
+		       devs[i].vendor_name, devs[i].device_name,
+		       dev->vendor_id, dev->device_id, dev->bus, dev->dev,
+		       dev->func);
+
+		if (devs[i].status == PCI_NT) {
+			printf("===\nThis PCI device is UNTESTED. Please "
+			       "report the 'flashrom -p xxxx' output \n"
+			       "to flashrom@flashrom.org if it works "
+			       "for you. Thank you for your help!\n===\n");
+		}
+
+		return addr;
+	}
+
+	return 0;
+}
+
+uint32_t pcidev_init(uint16_t vendor_id, uint32_t bar,
+		     struct pcidev_status *devs, char *pcidev_bdf)
+{
+	struct pci_dev *dev;
+	char *msg = NULL;
+	int found = 0;
+	uint32_t addr = 0, curaddr = 0;
+
+	pacc = pci_alloc();     /* Get the pci_access structure */
+	pci_init(pacc);         /* Initialize the PCI library */
+	pci_scan_bus(pacc);     /* We want to get the list of devices */
+	pci_filter_init(pacc, &filter);
+
+	/* Filter by vendor and also bb:dd.f (if supplied by the user). */
+	filter.vendor = vendor_id;
+	if (pcidev_bdf != NULL) {
+		if ((msg = pci_filter_parse_slot(&filter, pcidev_bdf))) {
+			fprintf(stderr, "Error: %s\n", msg);
+			exit(1);
+		}
+	}
+
+	for (dev = pacc->devices; dev; dev = dev->next) {
+		if (pci_filter_match(&filter, dev)) {
+			if ((addr = pcidev_validate(dev, bar, devs)) != 0) {
+				curaddr = addr;
+				pcidev_dev = dev;
+				found++;
+			}
+		}
+	}
+
+	/* Only continue if exactly one supported PCI dev has been found. */
+	if (found == 0) {
+		fprintf(stderr, "Error: No supported PCI device found.\n");
+		exit(1);
+	} else if (found > 1) {
+		fprintf(stderr, "Error: Multiple supported PCI devices found. "
+			"Use 'flashrom -p xxxx:bb:dd.f' \n"
+			"to explicitly select the card with the given BDF "
+			"(PCI bus, device, function).\n");
+		exit(1);
+	}
+
+	return curaddr;
+}
+
+void print_supported_pcidevs(struct pcidev_status *devs)
+{
+	int i;
+
+	for (i = 0; devs[i].vendor_name != NULL; i++) {
+		printf("%s %s [%02x:%02x]%s\n", devs[i].vendor_name,
+		       devs[i].device_name, devs[i].vendor_id,
+		       devs[i].device_id,
+		       (devs[i].status == PCI_NT) ? " (untested)" : "");
+	}
+}
diff --git a/libflashrom/pm29f002.c b/libflashrom/pm29f002.c
new file mode 100644
index 0000000..bf78d13
--- /dev/null
+++ b/libflashrom/pm29f002.c
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+
+/* if write_sector_jedec is used,
+   this is write_jedec_1 */
+int write_pm29f002(struct flashchip *flash, uint8_t *buf)
+{
+	int i, total_size = flash->total_size * 1024;
+	chipaddr bios = flash->virtual_memory;
+	chipaddr dst = bios;
+
+	if (erase_flash(flash)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+
+	/* FIXME: use write_sector_jedec? */
+	printf("Programming page: ");
+	for (i = 0; i < total_size; i++) {
+		if ((i & 0xfff) == 0)
+			printf("address: 0x%08lx", (unsigned long)i);
+
+		/* Pm29F002T/B only support byte-wise programming. */
+		chip_writeb(0xAA, bios + 0x555);
+		chip_writeb(0x55, bios + 0x2AA);
+		chip_writeb(0xA0, bios + 0x555);
+		chip_writeb(*buf++, dst++);
+
+		/* Wait for Toggle bit ready. */
+		toggle_ready_jedec(dst);
+
+		if ((i & 0xfff) == 0)
+			printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+	}
+
+	printf("\n");
+
+	return 0;
+}
diff --git a/libflashrom/pm49fl00x.c b/libflashrom/pm49fl00x.c
new file mode 100644
index 0000000..27a1163
--- /dev/null
+++ b/libflashrom/pm49fl00x.c
@@ -0,0 +1,116 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2004 Tyan Corporation
+ * Copyright (C) 2007 Nikolay Petukhov <nikolay.petukhov@gmail.com>
+ * Copyright (C) 2007 Reinder E.N. de Haan <lb_reha@mveas.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+
+void write_lockbits_49fl00x(chipaddr bios, int size,
+			    unsigned char bits, int block_size)
+{
+	int i, left = size;
+
+	for (i = 0; left >= block_size; i++, left -= block_size) {
+		/* pm49fl002 */
+		if (block_size == 16384 && i % 2)
+			continue;
+
+		chip_writeb(bits, bios + (i * block_size) + 2);
+	}
+}
+
+int probe_49fl00x(struct flashchip *flash)
+{
+	int ret = probe_jedec(flash);
+
+	if (ret == 1)
+		map_flash_registers(flash);
+
+	return ret;
+}
+
+int erase_49fl00x(struct flashchip *flash)
+{
+	int i;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+
+	/* unprotected */
+	write_lockbits_49fl00x(flash->virtual_registers,
+			       total_size, 0, page_size);
+
+	/*
+	 * erase_chip_jedec() will not work... Datasheet says
+	 * "Chip erase is available in A/A Mux Mode only".
+	 */
+	printf("Erasing page: ");
+	for (i = 0; i < total_size / page_size; i++) {
+		/* erase the page */
+		if (erase_block_jedec(flash, i * page_size, page_size)) {
+			fprintf(stderr, "ERASE FAILED!\n");
+			return -1;
+		}
+		printf("%04d at address: 0x%08x", i, i * page_size);
+		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+		fflush(stdout);
+	}
+	printf("\n");
+
+	/* protected */
+	write_lockbits_49fl00x(flash->virtual_registers,
+			       total_size, 1, page_size);
+
+	return 0;
+}
+
+int write_49fl00x(struct flashchip *flash, uint8_t *buf)
+{
+	int i;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+	chipaddr bios = flash->virtual_memory;
+
+	/* unprotected */
+	write_lockbits_49fl00x(flash->virtual_registers, total_size, 0,
+			       page_size);
+
+	printf("Programming page: ");
+	for (i = 0; i < total_size / page_size; i++) {
+		/* erase the page before programming */
+		if (erase_block_jedec(flash, i * page_size, page_size)) {
+			fprintf(stderr, "ERASE FAILED!\n");
+			return -1;
+		}
+
+		/* write to the sector */
+		printf("%04d at address: 0x%08x", i, i * page_size);
+		write_sector_jedec(bios, buf + i * page_size,
+				   bios + i * page_size, page_size);
+		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+		fflush(stdout);
+	}
+	printf("\n");
+
+	/* protected */
+	write_lockbits_49fl00x(flash->virtual_registers, total_size, 1,
+			       page_size);
+
+	return 0;
+}
diff --git a/libflashrom/satasii.c b/libflashrom/satasii.c
new file mode 100644
index 0000000..79d4325
--- /dev/null
+++ b/libflashrom/satasii.c
@@ -0,0 +1,113 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/* Datasheets can be found on http://www.siliconimage.com. Great thanks! */
+
+#include <stdlib.h>
+#include <string.h>
+#include "flash.h"
+
+#define PCI_VENDOR_ID_SII	0x1095
+
+uint8_t *sii_bar;
+uint16_t id;
+
+struct pcidev_status satas_sii[] = {
+	{0x1095, 0x0680, PCI_OK, "Silicon Image", "PCI0680 Ultra ATA-133 Host Ctrl"},
+	{0x1095, 0x3112, PCI_OK, "Silicon Image", "SiI 3112 [SATALink/SATARaid] SATA Ctrl"},
+	{0x1095, 0x3114, PCI_OK, "Silicon Image", "SiI 3114 [SATALink/SATARaid] SATA Ctrl"},
+	{0x1095, 0x3124, PCI_NT, "Silicon Image", "SiI 3124 PCI-X SATA Ctrl"},
+	{0x1095, 0x3132, PCI_OK, "Silicon Image", "SiI 3132 SATA Raid II Ctrl"},
+	{0x1095, 0x3512, PCI_NT, "Silicon Image", "SiI 3512 [SATALink/SATARaid] SATA Ctrl"},
+
+	{},
+};
+
+int satasii_init(void)
+{
+	uint32_t addr;
+	uint16_t reg_offset;
+
+	get_io_perms();
+
+	pcidev_init(PCI_VENDOR_ID_SII, PCI_BASE_ADDRESS_0, satas_sii,
+		    programmer_param);
+	id = pcidev_dev->device_id;
+
+	if ((id == 0x3132) || (id == 0x3124)) {
+		addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_0) & ~0x07;
+		reg_offset = 0x70;
+	} else {
+		addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_5) & ~0x07;
+		reg_offset = 0x50;
+	}
+
+	sii_bar = physmap("SATA SIL registers", addr, 0x100) + reg_offset;
+
+	/* Check if ROM cycle are OK. */
+	if ((id != 0x0680) && (!(mmio_readl(sii_bar) & (1 << 26))))
+		printf("Warning: Flash seems unconnected.\n");
+
+	buses_supported = CHIP_BUSTYPE_PARALLEL;
+
+	return 0;
+}
+
+int satasii_shutdown(void)
+{
+	free(programmer_param);
+	pci_cleanup(pacc);
+	release_io_perms();
+	return 0;
+}
+
+void satasii_chip_writeb(uint8_t val, chipaddr addr)
+{
+	uint32_t ctrl_reg, data_reg;
+
+	while ((ctrl_reg = mmio_readl(sii_bar)) & (1 << 25)) ;
+
+	/* Mask out unused/reserved bits, set writes and start transaction. */
+	ctrl_reg &= 0xfcf80000;
+	ctrl_reg |= (1 << 25) | (0 << 24) | ((uint32_t) addr & 0x7ffff);
+
+	data_reg = (mmio_readl((sii_bar + 4)) & ~0xff) | val;
+	mmio_writel(data_reg, (sii_bar + 4));
+	mmio_writel(ctrl_reg, sii_bar);
+
+	while (mmio_readl(sii_bar) & (1 << 25)) ;
+}
+
+uint8_t satasii_chip_readb(const chipaddr addr)
+{
+	uint32_t ctrl_reg;
+
+	while ((ctrl_reg = mmio_readl(sii_bar)) & (1 << 25)) ;
+
+	/* Mask out unused/reserved bits, set reads and start transaction. */
+	ctrl_reg &= 0xfcf80000;
+	ctrl_reg |= (1 << 25) | (1 << 24) | ((uint32_t) addr & 0x7ffff);
+
+	mmio_writel(ctrl_reg, sii_bar);
+
+	while (mmio_readl(sii_bar) & (1 << 25)) ;
+
+	return (mmio_readl(sii_bar + 4)) & 0xff;
+}
diff --git a/libflashrom/sb600spi.c b/libflashrom/sb600spi.c
new file mode 100644
index 0000000..87f1cc1
--- /dev/null
+++ b/libflashrom/sb600spi.c
@@ -0,0 +1,179 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2008 Wang Qingpei <Qingpei.Wang@amd.com>
+ * Copyright (C) 2008 Joe Bao <Zheng.Bao@amd.com>
+ * Copyright (C) 2008 Advanced Micro Devices, Inc.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <string.h>
+#include "flash.h"
+#include "spi.h"
+
+/* This struct is unused, but helps visualize the SB600 SPI BAR layout.
+ *struct sb600_spi_controller {
+ *	unsigned int spi_cntrl0;	/ * 00h * /
+ *	unsigned int restrictedcmd1;	/ * 04h * /
+ *	unsigned int restrictedcmd2;	/ * 08h * /
+ *	unsigned int spi_cntrl1;	/ * 0ch * /
+ *	unsigned int spi_cmdvalue0;	/ * 10h * /
+ *	unsigned int spi_cmdvalue1;	/ * 14h * /
+ *	unsigned int spi_cmdvalue2;	/ * 18h * /
+ *	unsigned int spi_fakeid;	/ * 1Ch * /
+ *};
+ */
+
+uint8_t *sb600_spibar = NULL;
+
+int sb600_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
+{
+	/* Maximum read length is 8 bytes. */
+	return spi_read_chunked(flash, buf, start, len, 8);
+}
+
+/* FIXME: SB600 can write 5 bytes per transaction. */
+int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf)
+{
+	int i;
+	int total_size = flash->total_size * 1024;
+	int result = 0;
+
+	spi_disable_blockprotect();
+	/* Erase first */
+	printf("Erasing flash before programming... ");
+	if (erase_flash(flash)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	printf("done.\n");
+
+	printf("Programming flash");
+	for (i = 0; i < total_size; i++, buf++) {
+		result = spi_nbyte_program(i, buf, 1);
+		if (result) {
+			fprintf(stderr, "Write error!\n");
+			return result;
+		}
+
+		/* wait program complete. */
+		if (i % 0x8000 == 0)
+			printf(".");
+		while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+			;
+	}
+	printf(" done.\n");
+	return result;
+}
+
+static void reset_internal_fifo_pointer(void)
+{
+	mmio_writeb(mmio_readb(sb600_spibar + 2) | 0x10, sb600_spibar + 2);
+
+	while (mmio_readb(sb600_spibar + 0xD) & 0x7)
+		printf("reset\n");
+}
+
+static void execute_command(void)
+{
+	mmio_writeb(mmio_readb(sb600_spibar + 2) | 1, sb600_spibar + 2);
+
+	while (mmio_readb(sb600_spibar + 2) & 1)
+		;
+}
+
+int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		      const unsigned char *writearr, unsigned char *readarr)
+{
+	int count;
+	/* First byte is cmd which can not being sent through FIFO. */
+	unsigned char cmd = *writearr++;
+	unsigned int readoffby1;
+
+	writecnt--;
+
+	printf_debug("%s, cmd=%x, writecnt=%x, readcnt=%x\n",
+		     __func__, cmd, writecnt, readcnt);
+
+	if (readcnt > 8) {
+		printf("%s, SB600 SPI controller can not receive %d bytes, "
+		       "it is limited to 8 bytes\n", __func__, readcnt);
+		return SPI_INVALID_LENGTH;
+	}
+
+	if (writecnt > 8) {
+		printf("%s, SB600 SPI controller can not send %d bytes, "
+		       "it is limited to 8 bytes\n", __func__, writecnt);
+		return SPI_INVALID_LENGTH;
+	}
+
+	/* This is a workaround for a bug in SB600 and SB700. If we only send
+	 * an opcode and no additional data/address, the SPI controller will
+	 * read one byte too few from the chip. Basically, the last byte of
+	 * the chip response is discarded and will not end up in the FIFO.
+	 * It is unclear if the CS# line is set high too early as well.
+	 */
+	readoffby1 = (writecnt) ? 0 : 1;
+	mmio_writeb((readcnt + readoffby1) << 4 | (writecnt), sb600_spibar + 1);
+	mmio_writeb(cmd, sb600_spibar + 0);
+
+	/* Before we use the FIFO, reset it first. */
+	reset_internal_fifo_pointer();
+
+	/* Send the write byte to FIFO. */
+	for (count = 0; count < writecnt; count++, writearr++) {
+		printf_debug(" [%x]", *writearr);
+		mmio_writeb(*writearr, sb600_spibar + 0xC);
+	}
+	printf_debug("\n");
+
+	/*
+	 * We should send the data by sequence, which means we need to reset
+	 * the FIFO pointer to the first byte we want to send.
+	 */
+	reset_internal_fifo_pointer();
+
+	execute_command();
+
+	/*
+	 * After the command executed, we should find out the index of the
+	 * received byte. Here we just reset the FIFO pointer and skip the
+	 * writecnt.
+	 * It would be possible to increase the FIFO pointer by one instead
+	 * of reading and discarding one byte from the FIFO.
+	 * The FIFO is implemented on top of an 8 byte ring buffer and the
+	 * buffer is never cleared. For every byte that is shifted out after
+	 * the opcode, the FIFO already stores the response from the chip.
+	 * Usually, the chip will respond with 0x00 or 0xff.
+	 */
+	reset_internal_fifo_pointer();
+
+	/* Skip the bytes we sent. */
+	for (count = 0; count < writecnt; count++) {
+		cmd = mmio_readb(sb600_spibar + 0xC);
+		printf_debug("[ %2x]", cmd);
+	}
+
+	printf_debug("The FIFO pointer after skipping is %d.\n",
+		     mmio_readb(sb600_spibar + 0xd) & 0x07);
+	for (count = 0; count < readcnt; count++, readarr++) {
+		*readarr = mmio_readb(sb600_spibar + 0xC);
+		printf_debug("[%02x]", *readarr);
+	}
+	printf_debug("\n");
+
+	return 0;
+}
diff --git a/libflashrom/serial.c b/libflashrom/serial.c
new file mode 100644
index 0000000..e22a8fa
--- /dev/null
+++ b/libflashrom/serial.c
@@ -0,0 +1,142 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Urja Rannikko <urjaman@gmail.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "flash.h"
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <termios.h>
+
+int sp_fd;
+
+void __attribute__((noreturn)) sp_die(char *msg)
+{
+	perror(msg);
+	exit(1);
+}
+
+struct baudentry {
+	int flag;
+	unsigned int baud;
+};
+
+/* I'd like if the C preprocessor could have directives in macros */
+#define BAUDENTRY(baud) { B##baud, baud },
+static const struct baudentry sp_baudtable[] = {
+	BAUDENTRY(9600)
+	BAUDENTRY(19200)
+	BAUDENTRY(38400)
+	BAUDENTRY(57600)
+	BAUDENTRY(115200)
+#ifdef B230400
+	BAUDENTRY(230400)
+#endif
+#ifdef B460800
+	BAUDENTRY(460800)
+#endif
+#ifdef B500000
+	BAUDENTRY(500000)
+#endif
+#ifdef B576000
+	BAUDENTRY(576000)
+#endif
+#ifdef B921600
+	BAUDENTRY(921600)
+#endif
+#ifdef B1000000
+	BAUDENTRY(1000000)
+#endif
+#ifdef B1152000
+	BAUDENTRY(1152000)
+#endif
+#ifdef B1500000
+	BAUDENTRY(1500000)
+#endif
+#ifdef B2000000
+	BAUDENTRY(2000000)
+#endif
+#ifdef B2500000
+	BAUDENTRY(2500000)
+#endif
+#ifdef B3000000
+	BAUDENTRY(3000000)
+#endif
+#ifdef B3500000
+	BAUDENTRY(3500000)
+#endif
+#ifdef B4000000
+	BAUDENTRY(4000000)
+#endif
+	{0, 0}			/* Terminator */
+};
+
+int sp_openserport(char *dev, unsigned int baud)
+{
+	struct termios options;
+	int fd, i;
+	fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY);
+	if (fd < 0)
+		sp_die("Error: cannot open serial port");
+	fcntl(fd, F_SETFL, 0);
+	tcgetattr(fd, &options);
+	for (i = 0;; i++) {
+		if (sp_baudtable[i].baud == 0) {
+			close(fd);
+			fprintf(stderr,
+				"Error: cannot configure for baudrate %d\n",
+				baud);
+			exit(1);
+		}
+		if (sp_baudtable[i].baud == baud) {
+			cfsetispeed(&options, sp_baudtable[i].flag);
+			cfsetospeed(&options, sp_baudtable[i].flag);
+			break;
+		}
+	}
+	options.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
+	options.c_cflag |= (CS8 | CLOCAL | CREAD);
+	options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
+	options.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | IGNCR | INLCR);
+	options.c_oflag &= ~OPOST;
+	tcsetattr(fd, TCSANOW, &options);
+	return fd;
+}
+
+void sp_flush_incoming(void)
+{
+	int i;
+	for (i=0;i<100;i++) { /* In case the device doesnt do EAGAIN, just read 0 */
+		unsigned char flush[16];
+		ssize_t rv;
+		rv = read(sp_fd, flush, sizeof(flush));
+		if ((rv == -1) && (errno == EAGAIN))
+			break;
+		if (rv == -1)
+			sp_die("flush read");
+	}
+	return;
+}
diff --git a/libflashrom/serprog-protocol.txt b/libflashrom/serprog-protocol.txt
new file mode 100644
index 0000000..0d389e6
--- /dev/null
+++ b/libflashrom/serprog-protocol.txt
@@ -0,0 +1,101 @@
+Serial Flasher Protocol Specification - version 1 (0x01 return value == 1)
+
+Command And Answer Sequence - all commands give an answer.
+PC: COMMAND(8bit) <parameters determined by opcode>
+DEV: ACK/NAK(8bit) <OPTIONAL RETURN BYTES (only if ACK)> / nothing
+Command 0x10 (SYNCNOP) has a special return of NAK+ACK for synchronization.
+
+ACK = 0x06
+NAK = 0x15
+
+All multibyte values are little-endian. Addresses and lengths are 24-bit.
+
+COMMAND	Description			Parameters			Return Value
+0x00	NOP				none				ACK
+0x01	Query programmer iface version	none				ACK + 16bit version (nonzero)
+0x02	Query supported commands bitmap	none				ACK + 32 bytes (256 bits) of supported cmds flags
+0x03	Query programmer name		none				ACK + 16 bytes string (null padding) / NAK
+0x04	Query serial buffer size	none				ACK + 16bit size / NAK
+0x05	Query supported bustypes	none				ACK + 8-bit flags (as per flashrom) / NAK
+0x06	Query connected address lines	none				ACK + 8bit line count / NAK
+0x07	Query operation buffer size	none				ACK + 16bit size / NAK
+0x08	Query write-n maximum data len	none				ACK + 24bit maximum length / NAK
+0x09	Read byte			24-bit addr			ACK + BYTE / NAK
+0x0A	Read n bytes			24-bit addr + 24-bit length	ACK + length bytes / NAK
+0x0B	Initialize operation buffer	none				ACK / NAK
+0x0C	Write to opbuf: Write byte	24-bit addr + 8-bit byte	ACK / NAK (NOTE: takes 5 bytes in opbuf)
+0x0D	Write to opbuf: Write n		24-bit length + 24-bit addr +	ACK / NAK (NOTE: takes 7+n bytes in opbuf)
+					 + length bytes of data
+0x0E	Write to opbuf: delay		32-bit usecs			ACK / NAK (NOTE: takes 5 bytes in opbuf)
+0x0F	Execute operation buffer	none				ACK / NAK
+0x10	Sync NOP			none				NAK + ACK (for synchronization)
+0x11	Query maximum read-n length	none				ACK + 24-bit length (0==2^24) / NAK
+0x12	Set used bustype		8-bit flags (as with 0x05)	ACK / NAK
+0x??	unimplemented command - invalid.
+
+
+Additional information of the above commands:
+	About unimplemented commands / startup sequence:
+		Only commands allowed to be used without checking anything are 0x00,0x10 and 0x01 (NOP,SYNCNOP,Q_IFACE).
+		If 0x01 doesn't return 1, dont do anything if you dont support a newer protocol.
+		Then, check support for any other opcode (except 0x02) by using 0x02 (Q_CMDMAP).
+	0x02 (Q_CMDMAP):
+		The map's bits are mapped as follows:
+		cmd 0 support: byte 0 bit 0
+		cmd 1 support: byte 0 bit 1
+		cmd 7 support: byte 0 bit 7
+		cmd 8 support: byte 1 bit 0, and so on.
+	0x04 (Q_SERBUF):
+		If the programmer has guaranteedly working flow control,
+		it should return a big bogus value - eg 0xFFFF.
+	0x05 (Q_BUSTYPE):
+		The bit's are defined as follows:
+		bit 0: PARALLEL, bit 1: LPC, bit 2: FWH, bit 3: SPI (if ever supported).
+	0x06 (Q_CHIPSIZE):
+		Only applicable to parallel programmers.
+		An LPC/FHW/SPI-programmer can report this as not supported in the command bitmap.
+	0x08 (Q_WRNMAXLEN):
+		If a programmer reports a bigger maximum write-n length than the serial buffer size,
+		it is assumed that the programmer can process the data fast enough to take in the
+		reported maximum write-n without problems.
+	0x0F (O_EXEC):
+		Execute operation buffer will also clear it, regardless of the return value.
+	0x11 (Q_RDNMAXLEN):
+		If this command is not supported, assume return of 0 (2^24).
+	0x12 (S_BUSTYPE):
+		Set's the used bustype if the programmer can support more than one flash protocol.
+		Sending a byte with more than 1 bit set will make the programmer decide among them
+		on it's own. Bit values as with Q_BUSTYPE.
+	About mandatory commands:
+		The only truly mandatory commands for any device are 0x00, 0x01, 0x02 and 0x10,
+		but one can't really do anything with these commands.
+		Support for the following commands is necessary for flashrom to operate properly:
+		S_CMD_Q_SERBUF, S_CMD_Q_OPBUF, S_CMD_Q_WRNMAXLEN, S_CMD_R_BYTE,
+		S_CMD_R_NBYTES, S_CMD_O_INIT, S_CMD_O_WRITEB, S_CMD_O_WRITEN,
+		S_CMD_O_DELAY, S_CMD_O_EXEC.
+		In addition, support for these commands is recommended:
+		S_CMD_Q_PGMNAME, S_CMD_Q_BUSTYPE, S_CMD_Q_CHIPSIZE (if parallel).
+
+
+This define listing should help C coders - (it's here to be the single source for copying - will be a .h someday i think)
+#define S_ACK 0x06
+#define S_NAK 0x15
+#define S_CMD_NOP		0x00            /* No operation                                 */
+#define S_CMD_Q_IFACE           0x01            /* Query interface version                      */
+#define S_CMD_Q_CMDMAP		0x02		/* Query supported commands bitmap		*/
+#define S_CMD_Q_PGMNAME         0x03            /* Query programmer name                        */
+#define S_CMD_Q_SERBUF          0x04            /* Query Serial Buffer Size                     */
+#define S_CMD_Q_BUSTYPE         0x05            /* Query supported bustypes                     */
+#define S_CMD_Q_CHIPSIZE        0x06            /* Query supported chipsize (2^n format)        */
+#define S_CMD_Q_OPBUF           0x07            /* Query operation buffer size                  */
+#define S_CMD_Q_WRNMAXLEN	0x08		/* Query Write to opbuf: Write-N maximum lenght */
+#define S_CMD_R_BYTE            0x09            /* Read a single byte                           */
+#define S_CMD_R_NBYTES          0x0A            /* Read n bytes                                 */
+#define S_CMD_O_INIT            0x0B            /* Initialize operation buffer                  */
+#define S_CMD_O_WRITEB          0x0C            /* Write opbuf: Write byte with address         */
+#define S_CMD_O_WRITEN		0x0D		/* Write to opbuf: Write-N			*/
+#define S_CMD_O_DELAY           0x0E            /* Write opbuf: udelay                          */
+#define S_CMD_O_EXEC            0x0F            /* Execute operation buffer                     */
+#define S_CMD_SYNCNOP		0x10		/* Special no-operation that returns NAK+ACK	*/
+#define S_CMD_Q_RDNMAXLEN	0x11		/* Query read-n maximum length			*/
+#define S_CMD_S_BUSTYPE		0x12		/* Set used bustype(s).				*/
diff --git a/libflashrom/serprog.c b/libflashrom/serprog.c
new file mode 100644
index 0000000..6544245
--- /dev/null
+++ b/libflashrom/serprog.c
@@ -0,0 +1,658 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Urja Rannikko <urjaman@gmail.com>
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "flash.h"
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <termios.h>
+
+#define MSGHEADER "serprog:"
+
+#define S_ACK 0x06
+#define S_NAK 0x15
+#define S_CMD_NOP		0x00	/* No operation                                 */
+#define S_CMD_Q_IFACE		0x01	/* Query interface version                      */
+#define S_CMD_Q_CMDMAP		0x02	/* Query supported commands bitmap              */
+#define S_CMD_Q_PGMNAME		0x03	/* Query programmer name                        */
+#define S_CMD_Q_SERBUF		0x04	/* Query Serial Buffer Size                     */
+#define S_CMD_Q_BUSTYPE		0x05	/* Query supported bustypes                     */
+#define S_CMD_Q_CHIPSIZE	0x06	/* Query supported chipsize (2^n format)        */
+#define S_CMD_Q_OPBUF		0x07	/* Query operation buffer size                  */
+#define S_CMD_Q_WRNMAXLEN	0x08	/* Query opbuf-write-N maximum lenght           */
+#define S_CMD_R_BYTE		0x09	/* Read a single byte                           */
+#define S_CMD_R_NBYTES		0x0A	/* Read n bytes                                 */
+#define S_CMD_O_INIT		0x0B	/* Initialize operation buffer                  */
+#define S_CMD_O_WRITEB		0x0C	/* Write opbuf: Write byte with address         */
+#define S_CMD_O_WRITEN		0x0D	/* Write to opbuf: Write-N                      */
+#define S_CMD_O_DELAY		0x0E	/* Write opbuf: udelay                          */
+#define S_CMD_O_EXEC		0x0F	/* Execute operation buffer                     */
+#define S_CMD_SYNCNOP		0x10	/* Special no-operation that returns NAK+ACK    */
+#define S_CMD_Q_RDNMAXLEN	0x11	/* Query read-n maximum length			*/
+#define S_CMD_S_BUSTYPE		0x12	/* Set used bustype(s).				*/
+
+static uint16_t sp_device_serbuf_size = 16;
+static uint16_t sp_device_opbuf_size = 300;
+/* Bitmap of supported commands */
+static uint8_t sp_cmdmap[32];
+
+/* sp_prev_was_write used to detect writes with continouous addresses
+	and combine them to write-n's */
+static int sp_prev_was_write = 0;
+/* sp_write_n_addr used as the starting addr of the currently
+	combined write-n operation */
+static uint32_t sp_write_n_addr;
+/* The maximum length of an write_n operation; 0 = write-n not supported */
+static uint32_t sp_max_write_n = 0;
+/* The maximum length of a read_n operation; 0 = 2^24 */
+static uint32_t sp_max_read_n = 0;
+
+/* A malloc'd buffer for combining the operation's data
+	and a counter that tells how much data is there. */
+static uint8_t *sp_write_n_buf;
+static uint32_t sp_write_n_bytes = 0;
+
+/* sp_streamed_* used for flow control checking */
+static int sp_streamed_transmit_ops = 0;
+static int sp_streamed_transmit_bytes = 0;
+
+/* sp_opbuf_usage used for counting the amount of
+	on-device operation buffer used */
+static int sp_opbuf_usage = 0;
+/* if true causes sp_docommand to automatically check
+	whether the command is supported before doing it */
+static int sp_check_avail_automatic = 0;
+
+static int sp_opensocket(char *ip, unsigned int port)
+{
+	int flag = 1;
+	struct hostent *hostPtr = NULL;
+	union { struct sockaddr_in si; struct sockaddr s; } sp = {};
+	int sock;
+	printf_debug(MSGHEADER "IP %s port %d\n", ip, port);
+	sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+	if (sock < 0)
+		sp_die("Error: serprog cannot open socket");
+	hostPtr = gethostbyname(ip);
+	if (NULL == hostPtr) {
+		hostPtr = gethostbyaddr(ip, strlen(ip), AF_INET);
+		if (NULL == hostPtr)
+			sp_die("Error: cannot resolve");
+	}
+	sp.si.sin_family = AF_INET;
+	sp.si.sin_port = htons(port);
+	(void)memcpy(&sp.si.sin_addr, hostPtr->h_addr, hostPtr->h_length);
+	if (connect(sock, &sp.s, sizeof(sp.si)) < 0) {
+		close(sock);
+		sp_die("Error: serprog cannot connect");
+	}
+	/* We are latency limited, and sometimes do write-write-read    *
+	 * (write-n) - so enable TCP_NODELAY.				*/
+	setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int));
+	return sock;
+}
+
+static int sp_sync_read_timeout(int loops)
+{
+	int i;
+	unsigned char c;
+	for (i = 0; i < loops; i++) {
+		ssize_t rv;
+		rv = read(sp_fd, &c, 1);
+		if (rv == 1)
+			return c;
+		if ((rv == -1) && (errno != EAGAIN))
+			sp_die("read");
+		usleep(10 * 1000);	/* 10ms units */
+	}
+	return -1;
+}
+
+/* Synchronize: a bit tricky algorhytm that tries to (and in my tests has *
+ * always succeeded in) bring the serial protocol to known waiting-for-   *
+ * command state - uses nonblocking read - rest of the driver uses	  *
+ * blocking read - TODO: add an alarm() timer for the rest of the app on  *
+ * serial operations, though not such a big issue as the first thing to   *
+ * do is synchronize (eg. check that device is alive).			  */
+static void sp_synchronize(void)
+{
+	int i;
+	int flags = fcntl(sp_fd, F_GETFL);
+	unsigned char buf[8];
+	flags |= O_NONBLOCK;
+	fcntl(sp_fd, F_SETFL, flags);
+	/* First sends 8 NOPs, then flushes the return data - should cause *
+	 * the device serial parser to get to a sane state, unless if it   *
+	 * is waiting for a real long write-n.                             */
+	memset(buf, S_CMD_NOP, 8);
+	if (write(sp_fd, buf, 8) != 8)
+		sp_die("flush write");
+	/* A second should be enough to get all the answers to the buffer */
+	usleep(1000 * 1000);
+	sp_flush_incoming();
+
+	/* Then try upto 8 times to send syncnop and get the correct special *
+	 * return of NAK+ACK. Timing note: upto 10 characters, 10*50ms =     *
+	 * upto 500ms per try, 8*0.5s = 4s; +1s (above) = upto 5s sync       *
+	 * attempt, ~1s if immediate success.                                */
+	for (i = 0; i < 8; i++) {
+		int n;
+		unsigned char c = S_CMD_SYNCNOP;
+		if (write(sp_fd, &c, 1) != 1)
+			sp_die("sync write");
+		printf_debug(".");
+		fflush(stdout);
+		for (n = 0; n < 10; n++) {
+			c = sp_sync_read_timeout(5);	/* wait upto 50ms */
+			if (c != S_NAK)
+				continue;
+			c = sp_sync_read_timeout(2);
+			if (c != S_ACK)
+				continue;
+			c = S_CMD_SYNCNOP;
+			if (write(sp_fd, &c, 1) != 1)
+				sp_die("sync write");
+			c = sp_sync_read_timeout(50);
+			if (c != S_NAK)
+				break;	/* fail */
+			c = sp_sync_read_timeout(10);
+			if (c != S_ACK)
+				break;	/* fail */
+			/* Ok, synchronized; back to blocking reads and return. */
+			flags &= ~O_NONBLOCK;
+			fcntl(sp_fd, F_SETFL, flags);
+			printf_debug("\n");
+			return;
+		}
+	}
+	fprintf(stderr,
+		"Error: cannot synchronize protocol\n"
+		"- check communications and reset device?\n");
+	exit(1);
+}
+
+static int sp_check_commandavail(uint8_t command)
+{
+	int byteoffs, bitoffs;
+	byteoffs = command / 8;
+	bitoffs = command % 8;
+	return (sp_cmdmap[byteoffs] & (1 << bitoffs)) ? 1 : 0;
+}
+
+static int sp_automatic_cmdcheck(uint8_t cmd)
+{
+	if ((sp_check_avail_automatic) && (sp_check_commandavail(cmd) == 0)) {
+		printf_debug ("Warning: Automatic command availability check"
+				" failed for cmd %d - wont execute cmd\n",cmd);
+		return 1;
+		}
+	return 0;
+}
+
+static int sp_docommand(uint8_t command, uint32_t parmlen,
+			     uint8_t * params, uint32_t retlen, void *retparms)
+{
+	unsigned char *sendpacket;
+	unsigned char c;
+	if (sp_automatic_cmdcheck(command))
+		return 1;
+	sendpacket = malloc(1 + parmlen);
+	if (!sendpacket)
+		sp_die("Error: cannot malloc command buffer");
+	sendpacket[0] = command;
+	memcpy(&(sendpacket[1]), params, parmlen);
+	if (write(sp_fd, sendpacket, 1 + parmlen) != (1 + parmlen)) {
+		sp_die("Error: cannot write command");
+	}
+	free(sendpacket);
+	if (read(sp_fd, &c, 1) != 1)
+		sp_die("Error: cannot read from device");
+	if (c == S_NAK) return 1;
+	if (c != S_ACK) {
+		fprintf(stderr,
+			"Error: invalid response 0x%02X from device\n",c);
+		exit(1);
+	}
+	if (retlen) {
+		int rd_bytes = 0;
+		do {
+			int r;
+			r = read(sp_fd, retparms + rd_bytes,
+				 retlen - rd_bytes);
+			if (r <= 0) sp_die
+				    ("Error: cannot read return parameters");
+			rd_bytes += r;
+		} while (rd_bytes != retlen);
+	}
+	return 0;
+}
+
+static void sp_flush_stream(void)
+{
+	if (sp_streamed_transmit_ops)
+		do {
+			unsigned char c;
+			if (read(sp_fd, &c, 1) != 1) {
+				sp_die
+				    ("Error: cannot read from device (flushing stream)");
+			}
+			if (c == S_NAK) {
+				fprintf(stderr,
+					"Error: NAK to a stream buffer operation\n");
+				exit(1);
+			}
+			if (c != S_ACK) {
+				fprintf(stderr,
+					"Error: Invalid reply 0x%02X from device\n",
+					c);
+				exit(1);
+			}
+		} while (--sp_streamed_transmit_ops);
+	sp_streamed_transmit_ops = 0;
+	sp_streamed_transmit_bytes = 0;
+}
+
+static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t * parms)
+{
+	uint8_t *sp;
+	if (sp_automatic_cmdcheck(cmd))
+		return 1;
+	sp = malloc(1 + parmlen);
+	if (!sp) sp_die("Error: cannot malloc command buffer");
+	sp[0] = cmd;
+	memcpy(&(sp[1]), parms, parmlen);
+	if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size))
+		sp_flush_stream();
+	if (write(sp_fd, sp, 1 + parmlen) != (1 + parmlen))
+		sp_die("Error: cannot write command");
+	free(sp);
+	sp_streamed_transmit_ops += 1;
+	sp_streamed_transmit_bytes += 1 + parmlen;
+	return 0;
+}
+
+int serprog_init(void)
+{
+	uint16_t iface;
+	int len;
+	unsigned char pgmname[17];
+	unsigned char rbuf[3];
+	unsigned char c;
+	char *num;
+	char *dev;
+	printf_debug("%s\n", __func__);
+	/* the parameter is either of format "/dev/device:baud" or "ip:port" */
+	if ((!programmer_param) || (!strlen(programmer_param))) {
+		nodevice:
+		fprintf(stderr,
+			"Error: No device/host given for the serial programmer driver.\n"
+			"Use flashrom -p serprog=/dev/device:baud or flashrom -p serprog=ip:port\n");
+		exit(1);
+	}
+	num = strstr(programmer_param, ":");
+	len = num - programmer_param;
+	if (!len) goto nodevice;
+	if (!num) {
+		fprintf(stderr,
+			"Error: No port or baudrate specified to serial programmer driver.\n"
+			"Use flashrom -p serprog=/dev/device:baud or flashrom -p serprog=ip:port\n");
+		exit(1);
+	}
+	len = num - programmer_param;
+	dev = malloc(len + 1);
+	if (!dev) sp_die("Error: memory allocation failure");
+	memcpy(dev, programmer_param, len);
+	dev[len] = 0;
+	num = strdup(num + 1);
+	if (!num) sp_die("Error: memory allocation failure");
+	free(programmer_param);
+	programmer_param = NULL;
+
+	if (dev[0] == '/') sp_fd = sp_openserport(dev, atoi(num));
+	else sp_fd = sp_opensocket(dev, atoi(num));
+
+	free(dev); dev = NULL;
+	free(num); num = NULL;
+
+	printf_debug(MSGHEADER "connected - attempting to synchronize\n");
+
+	sp_check_avail_automatic = 0;
+
+	sp_synchronize();
+
+	printf_debug(MSGHEADER "Synchronized\n");
+
+	if (sp_docommand(S_CMD_Q_IFACE, 0, NULL, 2, &iface)) {
+		fprintf(stderr, "Error: NAK to Query Interface version\n");
+		exit(1);
+	}
+
+	if (iface != 1) {
+		fprintf(stderr, "Error: Unknown interface version %d\n", iface);
+		exit(1);
+	}
+
+	printf_debug(MSGHEADER "Interface version ok.\n");
+
+	if (sp_docommand(S_CMD_Q_CMDMAP, 0, NULL, 32, sp_cmdmap)) {
+		fprintf(stderr, "Error: query command map not supported\n");
+		exit(1);
+	}
+
+	sp_check_avail_automatic = 1;
+
+	/* Check for the minimum operational set of commands */
+	if (sp_check_commandavail(S_CMD_R_BYTE) == 0) {
+		fprintf(stderr, "Error: Single byte read not supported\n");
+		exit(1);
+	}
+	/* This could be translated to single byte reads (if missing),	*
+	 * but now we dont support that.				*/
+	if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) {
+		fprintf(stderr, "Error: Read n bytes not supported\n");
+		exit(1);
+	}
+	/* In the future one could switch to read-only mode if these	*
+	 * are not available.						*/
+	if (sp_check_commandavail(S_CMD_O_INIT) == 0) {
+		fprintf(stderr,
+			"Error: Initialize operation buffer not supported\n");
+		exit(1);
+	}
+	if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) {
+		fprintf(stderr,
+			"Error: Write to opbuf: write byte not supported\n");
+		exit(1);
+	}
+	if (sp_check_commandavail(S_CMD_O_DELAY) == 0) {
+		fprintf(stderr, "Error: Write to opbuf: delay not supported\n");
+		exit(1);
+	}
+	if (sp_check_commandavail(S_CMD_O_EXEC) == 0) {
+		fprintf(stderr,
+			"Error: Execute operation buffer not supported\n");
+		exit(1);
+	}
+
+	if (sp_docommand(S_CMD_Q_PGMNAME, 0, NULL, 16, pgmname)) {
+		fprintf(stderr, "Warning: NAK to query programmer name\n");
+		strcpy((char *)pgmname, "(unknown)");
+	}
+	pgmname[16] = 0;
+	printf(MSGHEADER "Programmer name \"%s\"\n", pgmname);
+
+	if (sp_docommand(S_CMD_Q_SERBUF, 0, NULL, 2, &sp_device_serbuf_size)) {
+		fprintf(stderr, "Warning: NAK to query serial buffer size\n");
+	}
+	printf_debug(MSGHEADER "serial buffer size %d\n",
+		     sp_device_serbuf_size);
+
+	if (sp_docommand(S_CMD_Q_OPBUF, 0, NULL, 2, &sp_device_opbuf_size)) {
+		fprintf(stderr,
+			"Warning: NAK to query operation buffer size\n");
+	}
+	printf_debug(MSGHEADER "operation buffer size %d\n",
+		     sp_device_opbuf_size);
+
+	if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) {
+		fprintf(stderr, "Warning: NAK to query supported buses\n");
+		c = CHIP_BUSTYPE_NONSPI;	/* A reasonable default for now. */
+	}
+	buses_supported = c;
+
+	if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) {
+		fprintf(stderr, "Error: NAK to initialize operation buffer\n");
+		exit(1);
+	}
+
+	if (sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
+		printf_debug(MSGHEADER "Write-n not supported");
+		sp_max_write_n = 0;
+	} else {
+		sp_max_write_n = ((unsigned int)(rbuf[0]) << 0);
+		sp_max_write_n |= ((unsigned int)(rbuf[1]) << 8);
+		sp_max_write_n |= ((unsigned int)(rbuf[2]) << 16);
+		printf_debug(MSGHEADER "Maximum write-n length %d\n",
+			     sp_max_write_n);
+		sp_write_n_buf = malloc(sp_max_write_n);
+		if (!sp_write_n_buf) {
+			fprintf(stderr,
+				"Error: cannot allocate memory for Write-n buffer\n");
+			exit(1);
+		}
+		sp_write_n_bytes = 0;
+	}
+	
+	if ((sp_check_commandavail(S_CMD_Q_RDNMAXLEN))
+		&&((sp_docommand(S_CMD_Q_RDNMAXLEN,0,NULL, 3, rbuf) == 0))) {
+		sp_max_read_n = ((unsigned int)(rbuf[0]) << 0);
+		sp_max_read_n |= ((unsigned int)(rbuf[1]) << 8);
+		sp_max_read_n |= ((unsigned int)(rbuf[2]) << 16);
+		printf_debug(MSGHEADER "Maximum read-n length %d\n",
+			sp_max_read_n ? sp_max_read_n : (1<<24));
+	} else {
+		printf_debug(MSGHEADER "Maximum read-n length not reported\n");
+		sp_max_read_n = 0;
+	}
+
+	sp_prev_was_write = 0;
+	sp_streamed_transmit_ops = 0;
+	sp_streamed_transmit_bytes = 0;
+	sp_opbuf_usage = 0;
+	return 0;
+}
+
+/* Move an in flashrom buffer existing write-n operation to	*
+ * the on-device operation buffer.				*/
+static void sp_pass_writen(void)
+{
+	unsigned char header[7];
+	printf_debug(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n",
+		     sp_write_n_bytes, sp_write_n_addr);
+	if (sp_streamed_transmit_bytes >=
+	    (7 + sp_write_n_bytes + sp_device_serbuf_size))
+		sp_flush_stream();
+	/* In case it's just a single byte send it as a single write. */
+	if (sp_write_n_bytes == 1) {
+		sp_write_n_bytes = 0;
+		header[0] = (sp_write_n_addr >> 0) & 0xFF;
+		header[1] = (sp_write_n_addr >> 8) & 0xFF;
+		header[2] = (sp_write_n_addr >> 16) & 0xFF;
+		header[3] = sp_write_n_buf[0];
+		sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header);
+		sp_opbuf_usage += 5;
+		return;
+	}
+	header[0] = S_CMD_O_WRITEN;
+	header[1] = (sp_write_n_bytes >> 0) & 0xFF;
+	header[2] = (sp_write_n_bytes >> 8) & 0xFF;
+	header[3] = (sp_write_n_bytes >> 16) & 0xFF;
+	header[4] = (sp_write_n_addr >> 0) & 0xFF;
+	header[5] = (sp_write_n_addr >> 8) & 0xFF;
+	header[6] = (sp_write_n_addr >> 16) & 0xFF;
+	if (write(sp_fd, header, 7) != 7)
+		sp_die("Error: cannot write write-n command\n");
+	if (write(sp_fd, sp_write_n_buf, sp_write_n_bytes) !=
+	    sp_write_n_bytes)
+		sp_die("Error: cannot write write-n data");
+	sp_streamed_transmit_bytes += 7 + sp_write_n_bytes;
+	sp_streamed_transmit_ops += 1;
+	sp_opbuf_usage += 7 + sp_write_n_bytes;
+	sp_write_n_bytes = 0;
+	sp_prev_was_write = 0;
+}
+
+static void sp_execute_opbuf_noflush(void)
+{
+	if ((sp_max_write_n) && (sp_write_n_bytes))
+		sp_pass_writen();
+	sp_stream_buffer_op(S_CMD_O_EXEC, 0, 0);
+	printf_debug(MSGHEADER "Executed operation buffer of %d bytes\n",
+		     sp_opbuf_usage);
+	sp_opbuf_usage = 0;
+	sp_prev_was_write = 0;
+	return;
+}
+
+static void sp_execute_opbuf(void)
+{
+	sp_execute_opbuf_noflush();
+	sp_flush_stream();
+}
+
+int serprog_shutdown(void)
+{
+	printf_debug("%s\n", __func__);
+	if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
+		sp_execute_opbuf();
+	close(sp_fd);
+	if (sp_max_write_n)
+		free(sp_write_n_buf);
+	return 0;
+}
+
+static void sp_check_opbuf_usage(int bytes_to_be_added)
+{
+	if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) {
+		sp_execute_opbuf();
+		/* If this happens in the mid of an page load the page load *
+		 * will propably fail.					    */
+		printf_debug(MSGHEADER
+		"Warning: executed operation buffer due to size reasons\n");
+	}
+}
+
+void serprog_chip_writeb(uint8_t val, chipaddr addr)
+{
+	printf_debug("%s\n", __func__);
+	if (sp_max_write_n) {
+		if ((sp_prev_was_write)
+		    && (addr == (sp_write_n_addr + sp_write_n_bytes))) {
+			sp_write_n_buf[sp_write_n_bytes++] = val;
+		} else {
+			if ((sp_prev_was_write) && (sp_write_n_bytes))
+				sp_pass_writen();
+			sp_prev_was_write = 1;
+			sp_write_n_addr = addr;
+			sp_write_n_bytes = 1;
+			sp_write_n_buf[0] = val;
+		}
+		sp_check_opbuf_usage(7 + sp_write_n_bytes);
+		if (sp_write_n_bytes >= sp_max_write_n)
+			sp_pass_writen();
+	} else {
+		/* We will have to do single writeb ops. */
+		unsigned char writeb_parm[4];
+		sp_check_opbuf_usage(6);
+		writeb_parm[0] = (addr >> 0) & 0xFF;
+		writeb_parm[1] = (addr >> 8) & 0xFF;
+		writeb_parm[2] = (addr >> 16) & 0xFF;
+		writeb_parm[3] = val;
+		sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm);
+		sp_opbuf_usage += 5;
+	}
+}
+
+uint8_t serprog_chip_readb(const chipaddr addr)
+{
+	unsigned char c;
+	unsigned char buf[3];
+	/* Will stream the read operation - eg. add it to the stream buffer, *
+	 * then flush the buffer, then read the read answer.		     */
+	if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
+		sp_execute_opbuf_noflush();
+	buf[0] = ((addr >> 0) & 0xFF);
+	buf[1] = ((addr >> 8) & 0xFF);
+	buf[2] = ((addr >> 16) & 0xFF);
+	sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf);
+	sp_flush_stream();
+	if (read(sp_fd, &c, 1) != 1)
+		sp_die("readb byteread");
+	printf_debug("%s addr=0x%lx returning 0x%02X\n", __func__, addr, c);
+	return c;
+}
+
+/* Local version that really does the job, doesnt care of max_read_n. */
+static void sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len)
+{
+	int rd_bytes = 0;
+	unsigned char sbuf[6];
+	printf_debug("%s: addr=0x%lx len=%lu\n", __func__, addr, (unsigned long)len);
+	/* Stream the read-n -- as above. */
+	if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
+		sp_execute_opbuf_noflush();
+	sbuf[0] = ((addr >> 0) & 0xFF);
+	sbuf[1] = ((addr >> 8) & 0xFF);
+	sbuf[2] = ((addr >> 16) & 0xFF);
+	sbuf[3] = ((len >> 0) & 0xFF);
+	sbuf[4] = ((len >> 8) & 0xFF);
+	sbuf[5] = ((len >> 16) & 0xFF);
+	sp_stream_buffer_op(S_CMD_R_NBYTES, 6, sbuf);
+	sp_flush_stream();
+	do {
+		int r = read(sp_fd, buf + rd_bytes, len - rd_bytes);
+		if (r <= 0)
+			sp_die("Error: cannot read read-n data");
+		rd_bytes += r;
+	} while (rd_bytes != len);
+	return;
+}
+
+/* The externally called version that makes sure that max_read_n is obeyed. */
+void serprog_chip_readn(uint8_t * buf, const chipaddr addr, size_t len)
+{
+	size_t lenm = len;
+	chipaddr addrm = addr;
+	while ((sp_max_read_n)&&(lenm > sp_max_read_n)) {
+		sp_do_read_n(&(buf[addrm-addr]),addrm,sp_max_read_n);
+		addrm += sp_max_read_n;
+		lenm -= sp_max_read_n;
+	}
+	if (lenm) sp_do_read_n(&(buf[addrm-addr]),addrm,lenm);
+}
+
+void serprog_delay(int delay)
+{
+	unsigned char buf[4];
+	printf_debug("%s\n", __func__);
+	if ((sp_max_write_n) && (sp_write_n_bytes))
+		sp_pass_writen();
+	sp_check_opbuf_usage(5);
+	buf[0] = ((delay >> 0) & 0xFF);
+	buf[1] = ((delay >> 8) & 0xFF);
+	buf[2] = ((delay >> 16) & 0xFF);
+	buf[3] = ((delay >> 24) & 0xFF);
+	sp_stream_buffer_op(S_CMD_O_DELAY, 4, buf);
+	sp_opbuf_usage += 5;
+	sp_prev_was_write = 0;
+}
diff --git a/libflashrom/sharplhf00l04.c b/libflashrom/sharplhf00l04.c
new file mode 100644
index 0000000..1234ae4
--- /dev/null
+++ b/libflashrom/sharplhf00l04.c
@@ -0,0 +1,184 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include "flash.h"
+
+// I need that Berkeley bit-map printer
+void print_lhf00l04_status(uint8_t status)
+{
+	printf("%s", status & 0x80 ? "Ready:" : "Busy:");
+	printf("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:");
+	printf("%s", status & 0x20 ? "BE ERROR:" : "BE OK:");
+	printf("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:");
+	printf("%s", status & 0x8 ? "VP ERR:" : "VPP OK:");
+	printf("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:");
+	printf("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:");
+}
+
+int probe_lhf00l04(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+	uint8_t id1, id2;
+
+#if 0
+	/* Enter ID mode */
+	chip_writeb(0xAA, bios + 0x5555);
+	chip_writeb(0x55, bios + 0x2AAA);
+	chip_writeb(0x90, bios + 0x5555);
+#endif
+
+	chip_writeb(0xff, bios);
+	programmer_delay(10);
+	chip_writeb(0x90, bios);
+	programmer_delay(10);
+
+	id1 = chip_readb(bios);
+	id2 = chip_readb(bios + 0x01);
+
+	/* Leave ID mode */
+	chip_writeb(0xAA, bios + 0x5555);
+	chip_writeb(0x55, bios + 0x2AAA);
+	chip_writeb(0xF0, bios + 0x5555);
+
+	programmer_delay(10);
+
+	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+
+	if (id1 != flash->manufacture_id || id2 != flash->model_id)
+		return 0;
+
+	map_flash_registers(flash);
+
+	return 1;
+}
+
+uint8_t wait_lhf00l04(chipaddr bios)
+{
+	uint8_t status;
+
+	chip_writeb(0x70, bios);
+	if ((chip_readb(bios) & 0x80) == 0) {	// it's busy
+		while ((chip_readb(bios) & 0x80) == 0) ;
+	}
+
+	status = chip_readb(bios);
+
+	// put another command to get out of status register mode.
+
+	chip_writeb(0x90, bios);
+	programmer_delay(10);
+
+	chip_readb(bios);		// vendor ID
+	chip_readb(bios + 0x01);	// device ID
+
+	// this is needed to jam it out of "read id" mode
+	chip_writeb(0xAA, bios + 0x5555);
+	chip_writeb(0x55, bios + 0x2AAA);
+	chip_writeb(0xF0, bios + 0x5555);
+
+	return status;
+}
+
+int erase_lhf00l04_block(struct flashchip *flash, int offset)
+{
+	chipaddr bios = flash->virtual_memory + offset;
+	chipaddr wrprotect = flash->virtual_registers + offset + 2;
+	uint8_t status;
+
+	// clear status register
+	chip_writeb(0x50, bios);
+	printf("Erase at 0x%lx\n", bios);
+	status = wait_lhf00l04(flash->virtual_memory);
+	print_lhf00l04_status(status);
+	// clear write protect
+	printf("write protect is at 0x%lx\n", (wrprotect));
+	printf("write protect is 0x%x\n", chip_readb(wrprotect));
+	chip_writeb(0, wrprotect);
+	printf("write protect is 0x%x\n", chip_readb(wrprotect));
+
+	// now start it
+	chip_writeb(0x20, bios);
+	chip_writeb(0xd0, bios);
+	programmer_delay(10);
+	// now let's see what the register is
+	status = wait_lhf00l04(flash->virtual_memory);
+	print_lhf00l04_status(status);
+	printf("DONE BLOCK 0x%x\n", offset);
+
+	if (check_erased_range(flash, offset, flash->page_size)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+int erase_lhf00l04(struct flashchip *flash)
+{
+	int i;
+	unsigned int total_size = flash->total_size * 1024;
+
+	printf("total_size is %d; flash->page_size is %d\n",
+	       total_size, flash->page_size);
+	for (i = 0; i < total_size; i += flash->page_size)
+		if (erase_lhf00l04_block(flash, i)) {
+			fprintf(stderr, "ERASE FAILED!\n");
+			return -1;
+		}
+	printf("DONE ERASE\n");
+
+	return 0;
+}
+
+void write_page_lhf00l04(chipaddr bios, uint8_t *src,
+			 chipaddr dst, int page_size)
+{
+	int i;
+
+	for (i = 0; i < page_size; i++) {
+		/* transfer data from source to destination */
+		chip_writeb(0x40, dst);
+		chip_writeb(*src++, dst++);
+		wait_lhf00l04(bios);
+	}
+}
+
+int write_lhf00l04(struct flashchip *flash, uint8_t *buf)
+{
+	int i;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+	chipaddr bios = flash->virtual_memory;
+
+	if (erase_lhf00l04(flash)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	printf("Programming page: ");
+	for (i = 0; i < total_size / page_size; i++) {
+		printf("%04d at address: 0x%08x", i, i * page_size);
+		write_page_lhf00l04(bios, buf + i * page_size,
+				    bios + i * page_size, page_size);
+		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+	}
+	printf("\n");
+
+	return 0;
+}
diff --git a/libflashrom/spi.c b/libflashrom/spi.c
new file mode 100644
index 0000000..14beed7
--- /dev/null
+++ b/libflashrom/spi.c
@@ -0,0 +1,1071 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2007, 2008, 2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2008 coresystems GmbH
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Contains the generic SPI framework
+ */
+
+#include <string.h>
+#include "flash.h"
+#include "flashchips.h"
+#include "spi.h"
+
+enum spi_controller spi_controller = SPI_CONTROLLER_NONE;
+void *spibar = NULL;
+
+void spi_prettyprint_status_register(struct flashchip *flash);
+
+const struct spi_programmer spi_programmer[] = {
+	{ /* SPI_CONTROLLER_NONE */
+		.command = NULL,
+		.multicommand = NULL,
+		.read = NULL,
+		.write_256 = NULL,
+	},
+
+	{ /* SPI_CONTROLLER_ICH7 */
+		.command = ich_spi_send_command,
+		.multicommand = ich_spi_send_multicommand,
+		.read = ich_spi_read,
+		.write_256 = ich_spi_write_256,
+	},
+
+	{ /* SPI_CONTROLLER_ICH9 */
+		.command = ich_spi_send_command,
+		.multicommand = ich_spi_send_multicommand,
+		.read = ich_spi_read,
+		.write_256 = ich_spi_write_256,
+	},
+
+	{ /* SPI_CONTROLLER_IT87XX */
+		.command = it8716f_spi_send_command,
+		.multicommand = default_spi_send_multicommand,
+		.read = it8716f_spi_chip_read,
+		.write_256 = it8716f_spi_chip_write_256,
+	},
+
+	{ /* SPI_CONTROLLER_SB600 */
+		.command = sb600_spi_send_command,
+		.multicommand = default_spi_send_multicommand,
+		.read = sb600_spi_read,
+		.write_256 = sb600_spi_write_1,
+	},
+
+	{ /* SPI_CONTROLLER_VIA */
+		.command = ich_spi_send_command,
+		.multicommand = ich_spi_send_multicommand,
+		.read = ich_spi_read,
+		.write_256 = ich_spi_write_256,
+	},
+
+	{ /* SPI_CONTROLLER_WBSIO */
+		.command = wbsio_spi_send_command,
+		.multicommand = default_spi_send_multicommand,
+		.read = wbsio_spi_read,
+		.write_256 = wbsio_spi_write_1,
+	},
+
+#if FT2232_SPI_SUPPORT == 1
+	{ /* SPI_CONTROLLER_FT2232 */
+		.command = ft2232_spi_send_command,
+		.multicommand = default_spi_send_multicommand,
+		.read = ft2232_spi_read,
+		.write_256 = ft2232_spi_write_256,
+	},
+#endif
+
+#if DUMMY_SUPPORT == 1
+	{ /* SPI_CONTROLLER_DUMMY */
+		.command = dummy_spi_send_command,
+		.multicommand = default_spi_send_multicommand,
+		.read = NULL,
+		.write_256 = NULL,
+	},
+#endif
+
+#if BUSPIRATE_SPI_SUPPORT == 1
+	{ /* SPI_CONTROLLER_BUSPIRATE */
+		.command = buspirate_spi_send_command,
+		.multicommand = default_spi_send_multicommand,
+		.read = buspirate_spi_read,
+		.write_256 = spi_chip_write_1,
+	},
+#endif
+
+	{}, /* This entry corresponds to SPI_CONTROLLER_INVALID. */
+};
+
+const int spi_programmer_count = ARRAY_SIZE(spi_programmer);
+
+int spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		const unsigned char *writearr, unsigned char *readarr)
+{
+	if (!spi_programmer[spi_controller].command) {
+		fprintf(stderr, "%s called, but SPI is unsupported on this "
+			"hardware. Please report a bug.\n", __func__);
+		return 1;
+	}
+
+	return spi_programmer[spi_controller].command(writecnt, readcnt,
+						      writearr, readarr);
+}
+
+int spi_send_multicommand(struct spi_command *cmds)
+{
+	if (!spi_programmer[spi_controller].multicommand) {
+		fprintf(stderr, "%s called, but SPI is unsupported on this "
+			"hardware. Please report a bug.\n", __func__);
+		return 1;
+	}
+
+	return spi_programmer[spi_controller].multicommand(cmds);
+}
+
+int default_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+			     const unsigned char *writearr, unsigned char *readarr)
+{
+	struct spi_command cmd[] = {
+	{
+		.writecnt = writecnt,
+		.readcnt = readcnt,
+		.writearr = writearr,
+		.readarr = readarr,
+	}, {
+		.writecnt = 0,
+		.writearr = NULL,
+		.readcnt = 0,
+		.readarr = NULL,
+	}};
+
+	return spi_send_multicommand(cmd);
+}
+
+int default_spi_send_multicommand(struct spi_command *cmds)
+{
+	int result = 0;
+	for (; (cmds->writecnt || cmds->readcnt) && !result; cmds++) {
+		result = spi_send_command(cmds->writecnt, cmds->readcnt,
+					  cmds->writearr, cmds->readarr);
+	}
+	return result;
+}
+
+static int spi_rdid(unsigned char *readarr, int bytes)
+{
+	const unsigned char cmd[JEDEC_RDID_OUTSIZE] = { JEDEC_RDID };
+	int ret;
+	int i;
+
+	ret = spi_send_command(sizeof(cmd), bytes, cmd, readarr);
+	if (ret)
+		return ret;
+	printf_debug("RDID returned");
+	for (i = 0; i < bytes; i++)
+		printf_debug(" 0x%02x", readarr[i]);
+	printf_debug(". ");
+	return 0;
+}
+
+static int spi_rems(unsigned char *readarr)
+{
+	unsigned char cmd[JEDEC_REMS_OUTSIZE] = { JEDEC_REMS, 0, 0, 0 };
+	uint32_t readaddr;
+	int ret;
+
+	ret = spi_send_command(sizeof(cmd), JEDEC_REMS_INSIZE, cmd, readarr);
+	if (ret == SPI_INVALID_ADDRESS) {
+		/* Find the lowest even address allowed for reads. */
+		readaddr = (spi_get_valid_read_addr() + 1) & ~1;
+		cmd[1] = (readaddr >> 16) & 0xff,
+		cmd[2] = (readaddr >> 8) & 0xff,
+		cmd[3] = (readaddr >> 0) & 0xff,
+		ret = spi_send_command(sizeof(cmd), JEDEC_REMS_INSIZE, cmd, readarr);
+	}
+	if (ret)
+		return ret;
+	printf_debug("REMS returned %02x %02x. ", readarr[0], readarr[1]);
+	return 0;
+}
+
+static int spi_res(unsigned char *readarr)
+{
+	unsigned char cmd[JEDEC_RES_OUTSIZE] = { JEDEC_RES, 0, 0, 0 };
+	uint32_t readaddr;
+	int ret;
+
+	ret = spi_send_command(sizeof(cmd), JEDEC_RES_INSIZE, cmd, readarr);
+	if (ret == SPI_INVALID_ADDRESS) {
+		/* Find the lowest even address allowed for reads. */
+		readaddr = (spi_get_valid_read_addr() + 1) & ~1;
+		cmd[1] = (readaddr >> 16) & 0xff,
+		cmd[2] = (readaddr >> 8) & 0xff,
+		cmd[3] = (readaddr >> 0) & 0xff,
+		ret = spi_send_command(sizeof(cmd), JEDEC_RES_INSIZE, cmd, readarr);
+	}
+	if (ret)
+		return ret;
+	printf_debug("RES returned %02x. ", readarr[0]);
+	return 0;
+}
+
+int spi_write_enable(void)
+{
+	const unsigned char cmd[JEDEC_WREN_OUTSIZE] = { JEDEC_WREN };
+	int result;
+
+	/* Send WREN (Write Enable) */
+	result = spi_send_command(sizeof(cmd), 0, cmd, NULL);
+
+	if (result)
+		fprintf(stderr, "%s failed\n", __func__);
+
+	return result;
+}
+
+int spi_write_disable(void)
+{
+	const unsigned char cmd[JEDEC_WRDI_OUTSIZE] = { JEDEC_WRDI };
+
+	/* Send WRDI (Write Disable) */
+	return spi_send_command(sizeof(cmd), 0, cmd, NULL);
+}
+
+static int probe_spi_rdid_generic(struct flashchip *flash, int bytes)
+{
+	unsigned char readarr[4];
+	uint32_t id1;
+	uint32_t id2;
+
+	if (spi_rdid(readarr, bytes))
+		return 0;
+
+	if (!oddparity(readarr[0]))
+		printf_debug("RDID byte 0 parity violation. ");
+
+	/* Check if this is a continuation vendor ID */
+	if (readarr[0] == 0x7f) {
+		if (!oddparity(readarr[1]))
+			printf_debug("RDID byte 1 parity violation. ");
+		id1 = (readarr[0] << 8) | readarr[1];
+		id2 = readarr[2];
+		if (bytes > 3) {
+			id2 <<= 8;
+			id2 |= readarr[3];
+		}
+	} else {
+		id1 = readarr[0];
+		id2 = (readarr[1] << 8) | readarr[2];
+	}
+
+	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+
+	if (id1 == flash->manufacture_id && id2 == flash->model_id) {
+		/* Print the status register to tell the
+		 * user about possible write protection.
+		 */
+		spi_prettyprint_status_register(flash);
+
+		return 1;
+	}
+
+	/* Test if this is a pure vendor match. */
+	if (id1 == flash->manufacture_id &&
+	    GENERIC_DEVICE_ID == flash->model_id)
+		return 1;
+
+	/* Test if there is any vendor ID. */
+	if (GENERIC_MANUF_ID == flash->manufacture_id &&
+	    id1 != 0xff)
+		return 1;
+
+	return 0;
+}
+
+int probe_spi_rdid(struct flashchip *flash)
+{
+	return probe_spi_rdid_generic(flash, 3);
+}
+
+/* support 4 bytes flash ID */
+int probe_spi_rdid4(struct flashchip *flash)
+{
+	/* only some SPI chipsets support 4 bytes commands */
+	switch (spi_controller) {
+	case SPI_CONTROLLER_ICH7:
+	case SPI_CONTROLLER_ICH9:
+	case SPI_CONTROLLER_VIA:
+	case SPI_CONTROLLER_SB600:
+	case SPI_CONTROLLER_WBSIO:
+#if FT2232_SPI_SUPPORT == 1
+	case SPI_CONTROLLER_FT2232:
+#endif
+#if DUMMY_SUPPORT == 1
+	case SPI_CONTROLLER_DUMMY:
+#endif
+#if BUSPIRATE_SPI_SUPPORT == 1
+	case SPI_CONTROLLER_BUSPIRATE:
+#endif
+		return probe_spi_rdid_generic(flash, 4);
+	default:
+		printf_debug("4b ID not supported on this SPI controller\n");
+	}
+
+	return 0;
+}
+
+int probe_spi_rems(struct flashchip *flash)
+{
+	unsigned char readarr[JEDEC_REMS_INSIZE];
+	uint32_t id1, id2;
+
+	if (spi_rems(readarr))
+		return 0;
+
+	id1 = readarr[0];
+	id2 = readarr[1];
+
+	printf_debug("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
+
+	if (id1 == flash->manufacture_id && id2 == flash->model_id) {
+		/* Print the status register to tell the
+		 * user about possible write protection.
+		 */
+		spi_prettyprint_status_register(flash);
+
+		return 1;
+	}
+
+	/* Test if this is a pure vendor match. */
+	if (id1 == flash->manufacture_id &&
+	    GENERIC_DEVICE_ID == flash->model_id)
+		return 1;
+
+	/* Test if there is any vendor ID. */
+	if (GENERIC_MANUF_ID == flash->manufacture_id &&
+	    id1 != 0xff)
+		return 1;
+
+	return 0;
+}
+
+int probe_spi_res(struct flashchip *flash)
+{
+	unsigned char readarr[3];
+	uint32_t id2;
+
+	/* Check if RDID was successful and did not return 0xff 0xff 0xff.
+	 * In that case, RES is pointless.
+	 */
+	if (!spi_rdid(readarr, 3) && ((readarr[0] != 0xff) ||
+	    (readarr[1] != 0xff) || (readarr[2] != 0xff)))
+		return 0;
+
+	if (spi_res(readarr))
+		return 0;
+
+	id2 = readarr[0];
+	printf_debug("%s: id 0x%x\n", __func__, id2);
+	if (id2 != flash->model_id)
+		return 0;
+
+	/* Print the status register to tell the
+	 * user about possible write protection.
+	 */
+	spi_prettyprint_status_register(flash);
+	return 1;
+}
+
+uint8_t spi_read_status_register(void)
+{
+	const unsigned char cmd[JEDEC_RDSR_OUTSIZE] = { JEDEC_RDSR };
+	/* FIXME: No workarounds for driver/hardware bugs in generic code. */
+	unsigned char readarr[2]; /* JEDEC_RDSR_INSIZE=1 but wbsio needs 2 */
+	int ret;
+
+	/* Read Status Register */
+	ret = spi_send_command(sizeof(cmd), sizeof(readarr), cmd, readarr);
+	if (ret)
+		fprintf(stderr, "RDSR failed!\n");
+
+	return readarr[0];
+}
+
+/* Prettyprint the status register. Common definitions. */
+void spi_prettyprint_status_register_common(uint8_t status)
+{
+	printf_debug("Chip status register: Bit 5 / Block Protect 3 (BP3) is "
+		     "%sset\n", (status & (1 << 5)) ? "" : "not ");
+	printf_debug("Chip status register: Bit 4 / Block Protect 2 (BP2) is "
+		     "%sset\n", (status & (1 << 4)) ? "" : "not ");
+	printf_debug("Chip status register: Bit 3 / Block Protect 1 (BP1) is "
+		     "%sset\n", (status & (1 << 3)) ? "" : "not ");
+	printf_debug("Chip status register: Bit 2 / Block Protect 0 (BP0) is "
+		     "%sset\n", (status & (1 << 2)) ? "" : "not ");
+	printf_debug("Chip status register: Write Enable Latch (WEL) is "
+		     "%sset\n", (status & (1 << 1)) ? "" : "not ");
+	printf_debug("Chip status register: Write In Progress (WIP/BUSY) is "
+		     "%sset\n", (status & (1 << 0)) ? "" : "not ");
+}
+
+/* Prettyprint the status register. Works for
+ * ST M25P series
+ * MX MX25L series
+ */
+void spi_prettyprint_status_register_st_m25p(uint8_t status)
+{
+	printf_debug("Chip status register: Status Register Write Disable "
+		     "(SRWD) is %sset\n", (status & (1 << 7)) ? "" : "not ");
+	printf_debug("Chip status register: Bit 6 is "
+		     "%sset\n", (status & (1 << 6)) ? "" : "not ");
+	spi_prettyprint_status_register_common(status);
+}
+
+void spi_prettyprint_status_register_sst25(uint8_t status)
+{
+	printf_debug("Chip status register: Block Protect Write Disable "
+		     "(BPL) is %sset\n", (status & (1 << 7)) ? "" : "not ");
+	printf_debug("Chip status register: Auto Address Increment Programming "
+		     "(AAI) is %sset\n", (status & (1 << 6)) ? "" : "not ");
+	spi_prettyprint_status_register_common(status);
+}
+
+/* Prettyprint the status register. Works for
+ * SST 25VF016
+ */
+void spi_prettyprint_status_register_sst25vf016(uint8_t status)
+{
+	const char *bpt[] = {
+		"none",
+		"1F0000H-1FFFFFH",
+		"1E0000H-1FFFFFH",
+		"1C0000H-1FFFFFH",
+		"180000H-1FFFFFH",
+		"100000H-1FFFFFH",
+		"all", "all"
+	};
+	spi_prettyprint_status_register_sst25(status);
+	printf_debug("Resulting block protection : %s\n",
+		     bpt[(status & 0x1c) >> 2]);
+}
+
+void spi_prettyprint_status_register_sst25vf040b(uint8_t status)
+{
+	const char *bpt[] = {
+		"none",
+		"0x70000-0x7ffff",
+		"0x60000-0x7ffff",
+		"0x40000-0x7ffff",
+		"all blocks", "all blocks", "all blocks", "all blocks"
+	};
+	spi_prettyprint_status_register_sst25(status);
+	printf_debug("Resulting block protection : %s\n",
+		bpt[(status & 0x1c) >> 2]);
+}
+
+void spi_prettyprint_status_register(struct flashchip *flash)
+{
+	uint8_t status;
+
+	status = spi_read_status_register();
+	printf_debug("Chip status register is %02x\n", status);
+	switch (flash->manufacture_id) {
+	case ST_ID:
+		if (((flash->model_id & 0xff00) == 0x2000) ||
+		    ((flash->model_id & 0xff00) == 0x2500))
+			spi_prettyprint_status_register_st_m25p(status);
+		break;
+	case MX_ID:
+		if ((flash->model_id & 0xff00) == 0x2000)
+			spi_prettyprint_status_register_st_m25p(status);
+		break;
+	case SST_ID:
+		switch (flash->model_id) {
+		case 0x2541:
+			spi_prettyprint_status_register_sst25vf016(status);
+			break;
+		case 0x8d:
+		case 0x258d:
+			spi_prettyprint_status_register_sst25vf040b(status);
+			break;
+		default:
+			spi_prettyprint_status_register_sst25(status);
+			break;
+		}
+		break;
+	}
+}
+
+int spi_chip_erase_60(struct flashchip *flash)
+{
+	int result;
+	struct spi_command cmds[] = {
+	{
+		.writecnt	= JEDEC_WREN_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_WREN },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= JEDEC_CE_60_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_CE_60 },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= 0,
+		.writearr	= NULL,
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}};
+	
+	result = spi_disable_blockprotect();
+	if (result) {
+		fprintf(stderr, "spi_disable_blockprotect failed\n");
+		return result;
+	}
+	
+	result = spi_send_multicommand(cmds);
+	if (result) {
+		fprintf(stderr, "%s failed during command execution\n",
+			__func__);
+		return result;
+	}
+	/* Wait until the Write-In-Progress bit is cleared.
+	 * This usually takes 1-85 s, so wait in 1 s steps.
+	 */
+	/* FIXME: We assume spi_read_status_register will never fail. */
+	while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+		programmer_delay(1000 * 1000);
+	if (check_erased_range(flash, 0, flash->total_size * 1024)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+int spi_chip_erase_c7(struct flashchip *flash)
+{
+	int result;
+	struct spi_command cmds[] = {
+	{
+		.writecnt	= JEDEC_WREN_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_WREN },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= JEDEC_CE_C7_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_CE_C7 },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= 0,
+		.writearr	= NULL,
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}};
+
+	result = spi_disable_blockprotect();
+	if (result) {
+		fprintf(stderr, "spi_disable_blockprotect failed\n");
+		return result;
+	}
+
+	result = spi_send_multicommand(cmds);
+	if (result) {
+		fprintf(stderr, "%s failed during command execution\n", __func__);
+		return result;
+	}
+	/* Wait until the Write-In-Progress bit is cleared.
+	 * This usually takes 1-85 s, so wait in 1 s steps.
+	 */
+	/* FIXME: We assume spi_read_status_register will never fail. */
+	while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+		programmer_delay(1000 * 1000);
+	if (check_erased_range(flash, 0, flash->total_size * 1024)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+int spi_chip_erase_60_c7(struct flashchip *flash)
+{
+	int result;
+	result = spi_chip_erase_60(flash);
+	if (result) {
+		printf_debug("spi_chip_erase_60 failed, trying c7\n");
+		result = spi_chip_erase_c7(flash);
+	}
+	return result;
+}
+
+int spi_block_erase_52(struct flashchip *flash, unsigned int addr, unsigned int blocklen)
+{
+	int result;
+	struct spi_command cmds[] = {
+	{
+		.writecnt	= JEDEC_WREN_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_WREN },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= JEDEC_BE_52_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_BE_52, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff) },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= 0,
+		.writearr	= NULL,
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}};
+
+	result = spi_send_multicommand(cmds);
+	if (result) {
+		fprintf(stderr, "%s failed during command execution at address 0x%x\n",
+			__func__, addr);
+		return result;
+	}
+	/* Wait until the Write-In-Progress bit is cleared.
+	 * This usually takes 100-4000 ms, so wait in 100 ms steps.
+	 */
+	while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+		programmer_delay(100 * 1000);
+	if (check_erased_range(flash, addr, blocklen)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+/* Block size is usually
+ * 64k for Macronix
+ * 32k for SST
+ * 4-32k non-uniform for EON
+ */
+int spi_block_erase_d8(struct flashchip *flash, unsigned int addr, unsigned int blocklen)
+{
+	int result;
+	struct spi_command cmds[] = {
+	{
+		.writecnt	= JEDEC_WREN_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_WREN },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= JEDEC_BE_D8_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_BE_D8, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff) },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= 0,
+		.writearr	= NULL,
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}};
+
+	result = spi_send_multicommand(cmds);
+	if (result) {
+		fprintf(stderr, "%s failed during command execution at address 0x%x\n",
+			__func__, addr);
+		return result;
+	}
+	/* Wait until the Write-In-Progress bit is cleared.
+	 * This usually takes 100-4000 ms, so wait in 100 ms steps.
+	 */
+	while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+		programmer_delay(100 * 1000);
+	if (check_erased_range(flash, addr, blocklen)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+int spi_chip_erase_d8(struct flashchip *flash)
+{
+	int i, rc = 0;
+	int total_size = flash->total_size * 1024;
+	int erase_size = 64 * 1024;
+
+	spi_disable_blockprotect();
+
+	printf("Erasing chip: \n");
+
+	for (i = 0; i < total_size / erase_size; i++) {
+		rc = spi_block_erase_d8(flash, i * erase_size, erase_size);
+		if (rc) {
+			fprintf(stderr, "Error erasing block at 0x%x\n", i);
+			break;
+		}
+	}
+
+	printf("\n");
+
+	return rc;
+}
+
+/* Sector size is usually 4k, though Macronix eliteflash has 64k */
+int spi_block_erase_20(struct flashchip *flash, unsigned int addr, unsigned int blocklen)
+{
+	int result;
+	struct spi_command cmds[] = {
+	{
+		.writecnt	= JEDEC_WREN_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_WREN },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= JEDEC_SE_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_SE, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff) },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= 0,
+		.writearr	= NULL,
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}};
+
+	result = spi_send_multicommand(cmds);
+	if (result) {
+		fprintf(stderr, "%s failed during command execution at address 0x%x\n",
+			__func__, addr);
+		return result;
+	}
+	/* Wait until the Write-In-Progress bit is cleared.
+	 * This usually takes 15-800 ms, so wait in 10 ms steps.
+	 */
+	while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+		programmer_delay(10 * 1000);
+	if (check_erased_range(flash, addr, blocklen)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+int spi_block_erase_60(struct flashchip *flash, unsigned int addr, unsigned int blocklen)
+{
+	if ((addr != 0) || (blocklen != flash->total_size * 1024)) {
+		fprintf(stderr, "%s called with incorrect arguments\n",
+			__func__);
+		return -1;
+	}
+	return spi_chip_erase_60(flash);
+}
+
+int spi_block_erase_c7(struct flashchip *flash, unsigned int addr, unsigned int blocklen)
+{
+	if ((addr != 0) || (blocklen != flash->total_size * 1024)) {
+		fprintf(stderr, "%s called with incorrect arguments\n",
+			__func__);
+		return -1;
+	}
+	return spi_chip_erase_c7(flash);
+}
+
+int spi_write_status_enable(void)
+{
+	const unsigned char cmd[JEDEC_EWSR_OUTSIZE] = { JEDEC_EWSR };
+	int result;
+
+	/* Send EWSR (Enable Write Status Register). */
+	result = spi_send_command(sizeof(cmd), JEDEC_EWSR_INSIZE, cmd, NULL);
+
+	if (result)
+		fprintf(stderr, "%s failed\n", __func__);
+
+	return result;
+}
+
+/*
+ * This is according the SST25VF016 datasheet, who knows it is more
+ * generic that this...
+ */
+int spi_write_status_register(int status)
+{
+	int result;
+	struct spi_command cmds[] = {
+	{
+		.writecnt	= JEDEC_EWSR_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_EWSR },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= JEDEC_WRSR_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_WRSR, (unsigned char) status },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= 0,
+		.writearr	= NULL,
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}};
+
+	result = spi_send_multicommand(cmds);
+	if (result) {
+		fprintf(stderr, "%s failed during command execution\n",
+			__func__);
+	}
+	return result;
+}
+
+int spi_byte_program(int addr, uint8_t byte)
+{
+	int result;
+	struct spi_command cmds[] = {
+	{
+		.writecnt	= JEDEC_WREN_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_WREN },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= JEDEC_BYTE_PROGRAM_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_BYTE_PROGRAM, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff), byte },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= 0,
+		.writearr	= NULL,
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}};
+
+	result = spi_send_multicommand(cmds);
+	if (result) {
+		fprintf(stderr, "%s failed during command execution at address 0x%x\n",
+			__func__, addr);
+	}
+	return result;
+}
+
+int spi_nbyte_program(int addr, uint8_t *bytes, int len)
+{
+	int result;
+	/* FIXME: Switch to malloc based on len unless that kills speed. */
+	unsigned char cmd[JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + 256] = {
+		JEDEC_BYTE_PROGRAM,
+		(addr >> 16) & 0xff,
+		(addr >> 8) & 0xff,
+		(addr >> 0) & 0xff,
+	};
+	struct spi_command cmds[] = {
+	{
+		.writecnt	= JEDEC_WREN_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_WREN },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + len,
+		.writearr	= cmd,
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= 0,
+		.writearr	= NULL,
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}};
+
+	if (!len) {
+		fprintf(stderr, "%s called for zero-length write\n", __func__);
+		return 1;
+	}
+	if (len > 256) {
+		fprintf(stderr, "%s called for too long a write\n", __func__);
+		return 1;
+	}
+
+	memcpy(&cmd[4], bytes, len);
+
+	result = spi_send_multicommand(cmds);
+	if (result) {
+		fprintf(stderr, "%s failed during command execution at address 0x%x\n",
+			__func__, addr);
+	}
+	return result;
+}
+
+int spi_disable_blockprotect(void)
+{
+	uint8_t status;
+	int result;
+
+	status = spi_read_status_register();
+	/* If there is block protection in effect, unprotect it first. */
+	if ((status & 0x3c) != 0) {
+		printf_debug("Some block protection in effect, disabling\n");
+		result = spi_write_status_register(status & ~0x3c);
+		if (result) {
+			fprintf(stderr, "spi_write_status_register failed\n");
+			return result;
+		}
+	}
+	return 0;
+}
+
+int spi_nbyte_read(int address, uint8_t *bytes, int len)
+{
+	const unsigned char cmd[JEDEC_READ_OUTSIZE] = {
+		JEDEC_READ,
+		(address >> 16) & 0xff,
+		(address >> 8) & 0xff,
+		(address >> 0) & 0xff,
+	};
+
+	/* Send Read */
+	return spi_send_command(sizeof(cmd), len, cmd, bytes);
+}
+
+/*
+ * Read a complete flash chip.
+ * Each page is read separately in chunks with a maximum size of chunksize.
+ */
+int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize)
+{
+	int rc = 0;
+	int i, j, starthere, lenhere;
+	int page_size = flash->page_size;
+	int toread;
+
+	/* Warning: This loop has a very unusual condition and body.
+	 * The loop needs to go through each page with at least one affected
+	 * byte. The lowest page number is (start / page_size) since that
+	 * division rounds down. The highest page number we want is the page
+	 * where the last byte of the range lives. That last byte has the
+	 * address (start + len - 1), thus the highest page number is
+	 * (start + len - 1) / page_size. Since we want to include that last
+	 * page as well, the loop condition uses <=.
+	 */
+	for (i = start / page_size; i <= (start + len - 1) / page_size; i++) {
+		/* Byte position of the first byte in the range in this page. */
+		/* starthere is an offset to the base address of the chip. */
+		starthere = max(start, i * page_size);
+		/* Length of bytes in the range in this page. */
+		lenhere = min(start + len, (i + 1) * page_size) - starthere;
+		for (j = 0; j < lenhere; j += chunksize) {
+			toread = min(chunksize, lenhere - j);
+			rc = spi_nbyte_read(starthere + j, buf + starthere - start + j, toread);
+			if (rc)
+				break;
+		}
+		if (rc)
+			break;
+	}
+
+	return rc;
+}
+
+int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len)
+{
+	if (!spi_programmer[spi_controller].read) {
+		fprintf(stderr, "%s called, but SPI read is unsupported on this"
+			" hardware. Please report a bug.\n", __func__);
+		return 1;
+	}
+
+	return spi_programmer[spi_controller].read(flash, buf, start, len);
+}
+
+/*
+ * Program chip using byte programming. (SLOW!)
+ * This is for chips which can only handle one byte writes
+ * and for chips where memory mapped programming is impossible
+ * (e.g. due to size constraints in IT87* for over 512 kB)
+ */
+int spi_chip_write_1(struct flashchip *flash, uint8_t *buf)
+{
+	int total_size = 1024 * flash->total_size;
+	int i, result = 0;
+
+	spi_disable_blockprotect();
+	/* Erase first */
+	printf("Erasing flash before programming... ");
+	if (erase_flash(flash)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	printf("done.\n");
+	for (i = 0; i < total_size; i++) {
+		result = spi_byte_program(i, buf[i]);
+		if (result)
+			return 1;
+		while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+			programmer_delay(10);
+	}
+
+	return 0;
+}
+
+/*
+ * Program chip using page (256 bytes) programming.
+ * Some SPI masters can't do this, they use single byte programming instead.
+ */
+int spi_chip_write_256(struct flashchip *flash, uint8_t *buf)
+{
+	if (!spi_programmer[spi_controller].write_256) {
+		fprintf(stderr, "%s called, but SPI page write is unsupported "
+			" on this hardware. Please report a bug.\n", __func__);
+		return 1;
+	}
+
+	return spi_programmer[spi_controller].write_256(flash, buf);
+}
+
+uint32_t spi_get_valid_read_addr(void)
+{
+	/* Need to return BBAR for ICH chipsets. */
+	return 0;
+}
+
+int spi_aai_write(struct flashchip *flash, uint8_t *buf)
+{
+	uint32_t pos = 2, size = flash->total_size * 1024;
+	unsigned char w[6] = {0xad, 0, 0, 0, buf[0], buf[1]};
+	int result;
+
+	switch (spi_controller) {
+	case SPI_CONTROLLER_WBSIO:
+		fprintf(stderr, "%s: impossible with Winbond SPI masters,"
+				" degrading to byte program\n", __func__);
+		return spi_chip_write_1(flash, buf);
+	default:
+		break;
+	}
+	if (erase_flash(flash)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	result = spi_write_enable();
+	if (result)
+		return result;
+	spi_send_command(6, 0, w, NULL);
+	while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+		programmer_delay(5); /* SST25VF040B Tbp is max 10us */
+	while (pos < size) {
+		w[1] = buf[pos++];
+		w[2] = buf[pos++];
+		spi_send_command(3, 0, w, NULL);
+		while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+			programmer_delay(5); /* SST25VF040B Tbp is max 10us */
+	}
+	spi_write_disable();
+	return 0;
+}
diff --git a/libflashrom/spi.h b/libflashrom/spi.h
new file mode 100644
index 0000000..2fa7dcd
--- /dev/null
+++ b/libflashrom/spi.h
@@ -0,0 +1,114 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2007, 2008 Carl-Daniel Hailfinger
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef __SPI_H__
+#define __SPI_H__ 1
+
+/*
+ * Contains the generic SPI headers
+ */
+
+/* Read Electronic ID */
+#define JEDEC_RDID		0x9f
+#define JEDEC_RDID_OUTSIZE	0x01
+#define JEDEC_RDID_INSIZE	0x03
+
+/* AT25F512A has bit 3 as don't care bit in commands */
+#define AT25F512A_RDID		0x15
+#define AT25F512A_RDID_OUTSIZE	0x01
+#define AT25F512A_RDID_INSIZE	0x02
+
+/* Read Electronic Manufacturer Signature */
+#define JEDEC_REMS		0x90
+#define JEDEC_REMS_OUTSIZE	0x04
+#define JEDEC_REMS_INSIZE	0x02
+
+/* Read Electronic Signature */
+#define JEDEC_RES		0xab
+#define JEDEC_RES_OUTSIZE	0x04
+#define JEDEC_RES_INSIZE	0x01
+
+/* Write Enable */
+#define JEDEC_WREN		0x06
+#define JEDEC_WREN_OUTSIZE	0x01
+#define JEDEC_WREN_INSIZE	0x00
+
+/* Write Disable */
+#define JEDEC_WRDI		0x04
+#define JEDEC_WRDI_OUTSIZE	0x01
+#define JEDEC_WRDI_INSIZE	0x00
+
+/* Chip Erase 0x60 is supported by Macronix/SST chips. */
+#define JEDEC_CE_60		0x60
+#define JEDEC_CE_60_OUTSIZE	0x01
+#define JEDEC_CE_60_INSIZE	0x00
+
+/* Chip Erase 0xc7 is supported by SST/ST/EON/Macronix chips. */
+#define JEDEC_CE_C7		0xc7
+#define JEDEC_CE_C7_OUTSIZE	0x01
+#define JEDEC_CE_C7_INSIZE	0x00
+
+/* Block Erase 0x52 is supported by SST and old Atmel chips. */
+#define JEDEC_BE_52		0x52
+#define JEDEC_BE_52_OUTSIZE	0x04
+#define JEDEC_BE_52_INSIZE	0x00
+
+/* Block Erase 0xd8 is supported by EON/Macronix chips. */
+#define JEDEC_BE_D8		0xd8
+#define JEDEC_BE_D8_OUTSIZE	0x04
+#define JEDEC_BE_D8_INSIZE	0x00
+
+/* Sector Erase 0x20 is supported by Macronix/SST chips. */
+#define JEDEC_SE		0x20
+#define JEDEC_SE_OUTSIZE	0x04
+#define JEDEC_SE_INSIZE		0x00
+
+/* Read Status Register */
+#define JEDEC_RDSR		0x05
+#define JEDEC_RDSR_OUTSIZE	0x01
+#define JEDEC_RDSR_INSIZE	0x01
+#define JEDEC_RDSR_BIT_WIP	(0x01 << 0)
+
+/* Write Status Enable */
+#define JEDEC_EWSR		0x50
+#define JEDEC_EWSR_OUTSIZE	0x01
+#define JEDEC_EWSR_INSIZE	0x00
+
+/* Write Status Register */
+#define JEDEC_WRSR		0x01
+#define JEDEC_WRSR_OUTSIZE	0x02
+#define JEDEC_WRSR_INSIZE	0x00
+
+/* Read the memory */
+#define JEDEC_READ		0x03
+#define JEDEC_READ_OUTSIZE	0x04
+/*      JEDEC_READ_INSIZE : any length */
+
+/* Write memory byte */
+#define JEDEC_BYTE_PROGRAM	0x02
+#define JEDEC_BYTE_PROGRAM_OUTSIZE	0x05
+#define JEDEC_BYTE_PROGRAM_INSIZE	0x00
+
+/* Error codes */
+#define SPI_GENERIC_ERROR	-1
+#define SPI_INVALID_OPCODE	-2
+#define SPI_INVALID_ADDRESS	-3
+#define SPI_INVALID_LENGTH	-4
+
+#endif		/* !__SPI_H__ */
diff --git a/libflashrom/sst28sf040.c b/libflashrom/sst28sf040.c
new file mode 100644
index 0000000..930ad5b
--- /dev/null
+++ b/libflashrom/sst28sf040.c
@@ -0,0 +1,164 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2005 coresystems GmbH <stepan@openbios.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+
+#define AUTO_PG_ERASE1		0x20
+#define AUTO_PG_ERASE2		0xD0
+#define AUTO_PGRM		0x10
+#define CHIP_ERASE		0x30
+#define RESET			0xFF
+#define READ_ID			0x90
+
+static void protect_28sf040(chipaddr bios)
+{
+	chip_readb(bios + 0x1823);
+	chip_readb(bios + 0x1820);
+	chip_readb(bios + 0x1822);
+	chip_readb(bios + 0x0418);
+	chip_readb(bios + 0x041B);
+	chip_readb(bios + 0x0419);
+	chip_readb(bios + 0x040A);
+}
+
+static void unprotect_28sf040(chipaddr bios)
+{
+	chip_readb(bios + 0x1823);
+	chip_readb(bios + 0x1820);
+	chip_readb(bios + 0x1822);
+	chip_readb(bios + 0x0418);
+	chip_readb(bios + 0x041B);
+	chip_readb(bios + 0x0419);
+	chip_readb(bios + 0x041A);
+}
+
+static int erase_sector_28sf040(struct flashchip *flash, unsigned long address, int sector_size)
+{
+	chipaddr bios = flash->virtual_memory;
+
+	chip_writeb(AUTO_PG_ERASE1, bios);
+	chip_writeb(AUTO_PG_ERASE2, bios + address);
+
+	/* wait for Toggle bit ready         */
+	toggle_ready_jedec(bios);
+
+	if (check_erased_range(flash, address, sector_size)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int write_sector_28sf040(chipaddr bios, uint8_t *src, chipaddr dst,
+				unsigned int page_size)
+{
+	int i;
+
+	for (i = 0; i < page_size; i++) {
+		/* transfer data from source to destination */
+		if (*src == 0xFF) {
+			dst++, src++;
+			/* If the data is 0xFF, don't program it */
+			continue;
+		}
+		/*issue AUTO PROGRAM command */
+		chip_writeb(AUTO_PGRM, dst);
+		chip_writeb(*src++, dst++);
+
+		/* wait for Toggle bit ready */
+		toggle_ready_jedec(bios);
+	}
+
+	return 0;
+}
+
+int probe_28sf040(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+	uint8_t id1, id2;
+
+	chip_writeb(RESET, bios);
+	programmer_delay(10);
+
+	chip_writeb(READ_ID, bios);
+	programmer_delay(10);
+	id1 = chip_readb(bios);
+	programmer_delay(10);
+	id2 = chip_readb(bios + 0x01);
+
+	chip_writeb(RESET, bios);
+	programmer_delay(10);
+
+	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+	if (id1 == flash->manufacture_id && id2 == flash->model_id)
+		return 1;
+
+	return 0;
+}
+
+int erase_28sf040(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+
+	unprotect_28sf040(bios);
+	chip_writeb(CHIP_ERASE, bios);
+	chip_writeb(CHIP_ERASE, bios);
+	protect_28sf040(bios);
+
+	programmer_delay(10);
+	toggle_ready_jedec(bios);
+
+	if (check_erased_range(flash, 0, flash->total_size * 1024)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+int write_28sf040(struct flashchip *flash, uint8_t *buf)
+{
+	int i;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+	chipaddr bios = flash->virtual_memory;
+
+	unprotect_28sf040(bios);
+
+	printf("Programming page: ");
+	for (i = 0; i < total_size / page_size; i++) {
+		/* erase the page before programming */
+		if (erase_sector_28sf040(flash, i * page_size, page_size)) {
+			fprintf(stderr, "ERASE FAILED!\n");
+			return -1;
+		}
+
+		/* write to the sector */
+		printf("%04d at address: 0x%08x", i, i * page_size);
+		write_sector_28sf040(bios, buf + i * page_size,
+				     bios + i * page_size, page_size);
+		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+	}
+	printf("\n");
+
+	protect_28sf040(bios);
+
+	return 0;
+}
diff --git a/libflashrom/sst49lf040.c b/libflashrom/sst49lf040.c
new file mode 100644
index 0000000..ab1c918
--- /dev/null
+++ b/libflashrom/sst49lf040.c
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+
+int erase_49lf040(struct flashchip *flash)
+{
+	int i;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+
+	for (i = 0; i < total_size / page_size; i++) {
+		/* Chip erase only works in parallel programming mode
+		 * for the 49lf040. Use sector-erase instead */
+		if (erase_sector_jedec(flash, i * page_size, page_size)) {
+			fprintf(stderr, "ERASE FAILED!\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int write_49lf040(struct flashchip *flash, uint8_t *buf)
+{
+	int i;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+	chipaddr bios = flash->virtual_memory;
+
+	printf("Programming page: ");
+	for (i = 0; i < total_size / page_size; i++) {
+		/* erase the page before programming
+		 * Chip erase only works in parallel programming mode
+		 * for the 49lf040. Use sector-erase instead */
+		if (erase_sector_jedec(flash, i * page_size, page_size)) {
+			fprintf(stderr, "ERASE FAILED!\n");
+			return -1;
+		}
+
+		/* write to the sector */
+		if (i % 10 == 0)
+			printf("%04d at address: 0x%08x ", i, i * page_size);
+
+		write_sector_jedec(bios, buf + i * page_size,
+				   bios + i * page_size, page_size);
+
+		if (i % 10 == 0)
+			printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+		fflush(stdout);
+	}
+	printf("\n");
+
+	return 0;
+}
diff --git a/libflashrom/sst49lfxxxc.c b/libflashrom/sst49lfxxxc.c
new file mode 100644
index 0000000..a421acf
--- /dev/null
+++ b/libflashrom/sst49lfxxxc.c
@@ -0,0 +1,197 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2005-2007 coresystems GmbH
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include "flash.h"
+
+#define SECTOR_ERASE		0x30
+#define BLOCK_ERASE		0x20
+#define ERASE			0xD0
+#define AUTO_PGRM		0x10
+#define RESET			0xFF
+#define READ_ID			0x90
+#define READ_STATUS		0x70
+#define CLEAR_STATUS		0x50
+
+#define STATUS_BPS		(1 << 1)
+#define	STATUS_ESS		(1 << 6)
+#define	STATUS_WSMS		(1 << 7)
+
+static int write_lockbits_49lfxxxc(struct flashchip *flash, unsigned char bits)
+{
+	chipaddr registers = flash->virtual_registers;
+	int i, left = flash->total_size * 1024;
+	unsigned long address;
+
+	printf_debug("\nbios=0x%08lx\n", registers);
+	for (i = 0; left > 65536; i++, left -= 65536) {
+		printf_debug("lockbits at address=0x%08lx is 0x%01x\n",
+			     registers + (i * 65536) + 2,
+			     chip_readb(registers + (i * 65536) + 2));
+		chip_writeb(bits, registers + (i * 65536) + 2);
+	}
+	address = i * 65536;
+	printf_debug("lockbits at address=0x%08lx is 0x%01x\n",
+		     registers + address + 2,
+		     chip_readb(registers + address + 2));
+	chip_writeb(bits, registers + address + 2);
+	address += 32768;
+	printf_debug("lockbits at address=0x%08lx is 0x%01x\n",
+		     registers + address + 2,
+		     chip_readb(registers + address + 2));
+	chip_writeb(bits, registers + address + 2);
+	address += 8192;
+	printf_debug("lockbits at address=0x%08lx is 0x%01x\n",
+		     registers + address + 2,
+		     chip_readb(registers + address + 2));
+	chip_writeb(bits, registers + address + 2);
+	address += 8192;
+	printf_debug("lockbits at address=0x%08lx is 0x%01x\n",
+		     registers + address + 2,
+		     chip_readb(registers + address + 2));
+	chip_writeb(bits, registers + address + 2);
+
+	return 0;
+}
+
+static int erase_sector_49lfxxxc(struct flashchip *flash, unsigned long address, int sector_size)
+{
+	unsigned char status;
+	chipaddr bios = flash->virtual_memory;
+
+	chip_writeb(SECTOR_ERASE, bios);
+	chip_writeb(ERASE, bios + address);
+
+	do {
+		status = chip_readb(bios);
+		if (status & (STATUS_ESS | STATUS_BPS)) {
+			printf("sector erase FAILED at address=0x%08lx status=0x%01x\n", bios + address, status);
+			chip_writeb(CLEAR_STATUS, bios);
+			return (-1);
+		}
+	} while (!(status & STATUS_WSMS));
+	chip_writeb(RESET, bios);
+
+	if (check_erased_range(flash, address, sector_size)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int write_sector_49lfxxxc(chipaddr bios, uint8_t *src, chipaddr dst,
+				 unsigned int page_size)
+{
+	int i;
+	unsigned char status;
+
+	chip_writeb(CLEAR_STATUS, bios);
+	for (i = 0; i < page_size; i++) {
+		/* transfer data from source to destination */
+		if (*src == 0xFF) {
+			dst++, src++;
+			/* If the data is 0xFF, don't program it */
+			continue;
+		}
+		/*issue AUTO PROGRAM command */
+		chip_writeb(AUTO_PGRM, bios);
+		chip_writeb(*src++, dst++);
+
+		do {
+			status = chip_readb(bios);
+			if (status & (STATUS_ESS | STATUS_BPS)) {
+				printf("sector write FAILED at address=0x%08lx status=0x%01x\n", dst, status);
+				chip_writeb(CLEAR_STATUS, bios);
+				return (-1);
+			}
+		} while (!(status & STATUS_WSMS));
+	}
+
+	return 0;
+}
+
+int probe_49lfxxxc(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+	uint8_t id1, id2;
+
+	chip_writeb(RESET, bios);
+
+	chip_writeb(READ_ID, bios);
+	id1 = chip_readb(bios);
+	id2 = chip_readb(bios + 0x01);
+
+	chip_writeb(RESET, bios);
+
+	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+
+	if (!(id1 == flash->manufacture_id && id2 == flash->model_id))
+		return 0;
+
+	map_flash_registers(flash);
+
+	return 1;
+}
+
+int erase_49lfxxxc(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+	int i;
+	unsigned int total_size = flash->total_size * 1024;
+
+	write_lockbits_49lfxxxc(flash, 0);
+	for (i = 0; i < total_size; i += flash->page_size)
+		if (erase_sector_49lfxxxc(flash, i, flash->page_size))
+			return (-1);
+
+	chip_writeb(RESET, bios);
+
+	return 0;
+}
+
+int write_49lfxxxc(struct flashchip *flash, uint8_t *buf)
+{
+	int i;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+	chipaddr bios = flash->virtual_memory;
+
+	write_lockbits_49lfxxxc(flash, 0);
+	printf("Programming page: ");
+	for (i = 0; i < total_size / page_size; i++) {
+		/* erase the page before programming */
+		if (erase_sector_49lfxxxc(flash, i * page_size, flash->page_size)) {
+			fprintf(stderr, "ERASE FAILED!\n");
+			return -1;
+		}
+
+		/* write to the sector */
+		printf("%04d at address: 0x%08x", i, i * page_size);
+		write_sector_49lfxxxc(bios, buf + i * page_size,
+				      bios + i * page_size, page_size);
+		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+	}
+	printf("\n");
+
+	chip_writeb(RESET, bios);
+
+	return 0;
+}
diff --git a/libflashrom/sst_fwhub.c b/libflashrom/sst_fwhub.c
new file mode 100644
index 0000000..f09aa54
--- /dev/null
+++ b/libflashrom/sst_fwhub.c
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2009 Kontron Modular Computers
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/* Adapted from the Intel FW hub stuff for 82802ax parts. */
+
+#include <stdlib.h>
+#include <string.h>
+#include "flash.h"
+
+// I need that Berkeley bit-map printer
+void print_sst_fwhub_status(uint8_t status)
+{
+	printf("%s", status & 0x80 ? "Ready:" : "Busy:");
+	printf("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:");
+	printf("%s", status & 0x20 ? "BE ERROR:" : "BE OK:");
+	printf("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:");
+	printf("%s", status & 0x8 ? "VP ERR:" : "VPP OK:");
+	printf("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:");
+	printf("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:");
+}
+
+int check_sst_fwhub_block_lock(struct flashchip *flash, int offset)
+{
+	chipaddr registers = flash->virtual_registers;
+	uint8_t blockstatus;
+
+	blockstatus = chip_readb(registers + offset + 2);
+	printf_debug("Lock status for 0x%06x (size 0x%06x) is %02x, ",
+		     offset, flash->page_size, blockstatus);
+	switch (blockstatus & 0x3) {
+	case 0x0:
+		printf_debug("full access\n");
+		break;
+	case 0x1:
+		printf_debug("write locked\n");
+		break;
+	case 0x2:
+		printf_debug("locked open\n");
+		break;
+	case 0x3:
+		printf_debug("write locked down\n");
+		break;
+	}
+	/* Return content of the write_locked bit */
+	return blockstatus & 0x1;
+}
+
+int clear_sst_fwhub_block_lock(struct flashchip *flash, int offset)
+{
+	chipaddr registers = flash->virtual_registers;
+	uint8_t blockstatus;
+
+	blockstatus = check_sst_fwhub_block_lock(flash, offset);
+
+	if (blockstatus) {
+		printf_debug("Trying to clear lock for 0x%06x... ", offset)
+		chip_writeb(0, registers + offset + 2);
+
+		blockstatus = check_sst_fwhub_block_lock(flash, offset);
+		printf_debug("%s\n", (blockstatus) ? "failed" : "OK");
+	}
+
+	return blockstatus;
+}
+
+/* probe_jedec works fine for probing */
+int probe_sst_fwhub(struct flashchip *flash)
+{
+	int i;
+
+	if (probe_jedec(flash) == 0)
+		return 0;
+
+	map_flash_registers(flash);
+
+	for (i = 0; i < flash->total_size * 1024; i += flash->page_size)
+		check_sst_fwhub_block_lock(flash, i);
+
+	return 1;
+}
+
+int erase_sst_fwhub_block(struct flashchip *flash, unsigned int offset, unsigned int page_size)
+{
+	uint8_t blockstatus = clear_sst_fwhub_block_lock(flash, offset);
+
+	if (blockstatus) {
+		printf("Block lock clearing failed, not erasing block "
+			"at 0x%06x\n", offset);
+		return 1;
+	}
+
+	if (erase_block_jedec(flash, offset, page_size)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	toggle_ready_jedec(flash->virtual_memory);
+
+	return 0;
+}
+
+int erase_sst_fwhub(struct flashchip *flash)
+{
+	int i;
+	unsigned int total_size = flash->total_size * 1024;
+
+	for (i = 0; i < total_size; i += flash->page_size) {
+		if (erase_sst_fwhub_block(flash, i, flash->page_size)) {
+			fprintf(stderr, "ERASE FAILED!\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int write_sst_fwhub(struct flashchip *flash, uint8_t *buf)
+{
+	int i, rc;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+	chipaddr bios = flash->virtual_memory;
+	uint8_t *readbuf = malloc(page_size);
+	
+	printf("Programming page: ");
+	for (i = 0; i < total_size / page_size; i++) {
+		printf("%04d at address: 0x%08x", i, i * page_size);
+
+		/* Auto Skip Blocks, which already contain the desired data:
+		 * Faster, because we only write, what has changed
+		 * More secure, because blocks, which are excluded
+		 * (with the exclude or layout feature)
+		 * are not erased and rewritten; data is retained also
+		 * in sudden power off situations
+		 */
+		flash->read(flash, readbuf, i * page_size, page_size);
+		if (memcmp((void *)(buf + i * page_size),
+			   (void *)(readbuf), page_size)) {
+			rc = erase_sst_fwhub_block(flash, i * page_size,
+						   page_size);
+			if (rc)
+				return 1;
+			write_sector_jedec(bios, buf + i * page_size,
+					   bios + i * page_size, page_size);
+		}
+		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+	}
+	printf("\n");
+
+	return 0;
+}
diff --git a/libflashrom/stm50flw0x0x.c b/libflashrom/stm50flw0x0x.c
new file mode 100644
index 0000000..0ae6eb8
--- /dev/null
+++ b/libflashrom/stm50flw0x0x.c
@@ -0,0 +1,245 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2008 Claus Gindhart <claus.gindhart@kontron.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * This module is designed for supporting the devices
+ * ST M50FLW040A (not yet tested)
+ * ST M50FLW040B (not yet tested)
+ * ST M50FLW080A
+ * ST M50FLW080B (not yet tested)
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "flash.h"
+#include "flashchips.h"
+
+int probe_stm50flw0x0x(struct flashchip *flash)
+{
+	int result = probe_jedec(flash);
+
+	if (!result)
+		return result;
+
+	map_flash_registers(flash);
+
+	return 1;
+}
+
+static void wait_stm50flw0x0x(chipaddr bios)
+{
+	chip_writeb(0x70, bios);
+	if ((chip_readb(bios) & 0x80) == 0) {	// it's busy
+		while ((chip_readb(bios) & 0x80) == 0) ;
+	}
+
+	// put another command to get out of status register mode
+
+	chip_writeb(0x90, bios);
+	programmer_delay(10);
+
+	chip_readb(bios); // Read device ID (to make sure?)
+
+	// this is needed to jam it out of "read id" mode
+	chip_writeb(0xAA, bios + 0x5555);
+	chip_writeb(0x55, bios + 0x2AAA);
+	chip_writeb(0xF0, bios + 0x5555);
+}
+
+/*
+ * claus.gindhart@kontron.com
+ * The ST M50FLW080B and STM50FLW080B chips have to be unlocked,
+ * before you can erase them or write to them.
+ */
+int unlock_block_stm50flw0x0x(struct flashchip *flash, int offset)
+{
+	chipaddr wrprotect = flash->virtual_registers + 2;
+	const uint8_t unlock_sector = 0x00;
+	int j;
+
+	/*
+	 * These chips have to be unlocked before you can erase them or write
+	 * to them. The size of the locking sectors depends on the type
+	 * of chip.
+	 *
+	 * Sometimes, the BIOS does this for you; so you propably
+	 * don't need to worry about that.
+	 */
+
+	/* Check, if it's is a top/bottom-block with 4k-sectors. */
+	/* TODO: What about the other types? */
+	if ((offset == 0) ||
+	    (offset == (flash->model_id == ST_M50FLW080A ? 0xE0000 : 0x10000))
+	    || (offset == 0xF0000)) {
+
+		// unlock each 4k-sector
+		for (j = 0; j < 0x10000; j += 0x1000) {
+			printf_debug("unlocking at 0x%x\n", offset + j);
+			chip_writeb(unlock_sector, wrprotect + offset + j);
+			if (chip_readb(wrprotect + offset + j) != unlock_sector) {
+				printf("Cannot unlock sector @ 0x%x\n",
+				       offset + j);
+				return -1;
+			}
+		}
+	} else {
+		printf_debug("unlocking at 0x%x\n", offset);
+		chip_writeb(unlock_sector, wrprotect + offset);
+		if (chip_readb(wrprotect + offset) != unlock_sector) {
+			printf("Cannot unlock sector @ 0x%x\n", offset);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int erase_block_stm50flw0x0x(struct flashchip *flash, int offset)
+{
+	chipaddr bios = flash->virtual_memory + offset;
+
+	// clear status register
+	chip_writeb(0x50, bios);
+	printf_debug("Erase at 0x%lx\n", bios);
+	// now start it
+	chip_writeb(0x20, bios);
+	chip_writeb(0xd0, bios);
+	programmer_delay(10);
+
+	wait_stm50flw0x0x(flash->virtual_memory);
+
+	if (check_erased_range(flash, offset, flash->page_size)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	printf("DONE BLOCK 0x%x\n", offset);
+
+	return 0;
+}
+
+int write_page_stm50flw0x0x(chipaddr bios, uint8_t *src,
+			    chipaddr dst, int page_size)
+{
+	int i, rc = 0;
+	chipaddr d = dst;
+	uint8_t *s = src;
+
+	/* transfer data from source to destination */
+	for (i = 0; i < page_size; i++) {
+		chip_writeb(0x40, dst);
+		chip_writeb(*src++, dst++);
+		wait_stm50flw0x0x(bios);
+	}
+
+/* claus.gindhart@kontron.com
+ * TODO
+ * I think, that verification is not required, but
+ * i leave it in anyway
+ */
+	dst = d;
+	src = s;
+	for (i = 0; i < page_size; i++) {
+		if (chip_readb(dst) != *src) {
+			rc = -1;
+			break;
+		}
+		dst++;
+		src++;
+	}
+
+	if (rc) {
+		fprintf(stderr, " page 0x%lx failed!\n",
+			(d - bios) / page_size);
+	}
+
+	return rc;
+}
+
+/* I simply erase block by block
+ * I Chip This is not the fastest way, but it works
+ */
+int erase_stm50flw0x0x(struct flashchip *flash)
+{
+	int i;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+
+	printf("Erasing page:\n");
+	for (i = 0; i < total_size / page_size; i++) {
+		printf
+		    ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+		printf("%04d at address: 0x%08x ", i, i * page_size);
+		if (unlock_block_stm50flw0x0x(flash, i * page_size)) {
+			fprintf(stderr, "UNLOCK FAILED!\n");
+			return -1;
+		}
+		if (erase_block_stm50flw0x0x(flash, i * page_size)) {
+			fprintf(stderr, "ERASE FAILED!\n");
+			return -1;
+		}
+	}
+	printf("\n");
+
+	return 0;
+}
+
+int write_stm50flw0x0x(struct flashchip *flash, uint8_t * buf)
+{
+	int i, rc = 0;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+	chipaddr bios = flash->virtual_memory;
+	uint8_t *tmpbuf = malloc(page_size);
+
+	if (!tmpbuf) {
+		printf("Could not allocate memory!\n");
+		exit(1);
+	}
+	printf("Programming page: \n");
+	for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
+		printf
+		    ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+		printf("%04d at address: 0x%08x ", i, i * page_size);
+
+		/* Auto Skip Blocks, which already contain the desired data
+		 * Faster, because we only write, what has changed
+		 * More secure, because blocks, which are excluded
+		 * (with the exclude or layout feature)
+		 * are not erased and rewritten; data is retained also
+		 * in sudden power off situations
+		 */
+		chip_readn(tmpbuf, bios + i * page_size, page_size);
+		if (!memcmp((void *)(buf + i * page_size), tmpbuf, page_size)) {
+			printf("SKIPPED\n");
+			continue;
+		}
+
+		rc = unlock_block_stm50flw0x0x(flash, i * page_size);
+		if (!rc)
+			rc = erase_block_stm50flw0x0x(flash, i * page_size);
+		if (!rc)
+			write_page_stm50flw0x0x(bios, buf + i * page_size,
+					bios + i * page_size, page_size);
+	}
+	printf("\n");
+	free(tmpbuf);
+
+	return rc;
+}
diff --git a/libflashrom/w29ee011.c b/libflashrom/w29ee011.c
new file mode 100644
index 0000000..de9a547
--- /dev/null
+++ b/libflashrom/w29ee011.c
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2007 Markus Boas <ryven@ryven.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <string.h>
+#include "flash.h"
+
+int probe_w29ee011(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+	uint8_t id1, id2;
+	extern char *chip_to_probe;
+
+	if (!chip_to_probe || strcmp(chip_to_probe, "W29EE011")) {
+		printf_debug("Probing disabled for Winbond W29EE011 because "
+			     "the probing sequence puts the AMIC A49LF040A in "
+			     "a funky state. Use 'flashrom -c W29EE011' if you "
+			     "have a board with this chip.\n");
+		return 0;
+	}
+
+	/* Issue JEDEC Product ID Entry command */
+	chip_writeb(0xAA, bios + 0x5555);
+	programmer_delay(10);
+	chip_writeb(0x55, bios + 0x2AAA);
+	programmer_delay(10);
+	chip_writeb(0x80, bios + 0x5555);
+	programmer_delay(10);
+	chip_writeb(0xAA, bios + 0x5555);
+	programmer_delay(10);
+	chip_writeb(0x55, bios + 0x2AAA);
+	programmer_delay(10);
+	chip_writeb(0x60, bios + 0x5555);
+	programmer_delay(10);
+
+	/* Read product ID */
+	id1 = chip_readb(bios);
+	id2 = chip_readb(bios + 0x01);
+
+	/* Issue JEDEC Product ID Exit command */
+	chip_writeb(0xAA, bios + 0x5555);
+	programmer_delay(10);
+	chip_writeb(0x55, bios + 0x2AAA);
+	programmer_delay(10);
+	chip_writeb(0xF0, bios + 0x5555);
+	programmer_delay(10);
+
+	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+
+	if (id1 == flash->manufacture_id && id2 == flash->model_id)
+		return 1;
+
+	return 0;
+}
diff --git a/libflashrom/w39v040c.c b/libflashrom/w39v040c.c
new file mode 100644
index 0000000..722ae29
--- /dev/null
+++ b/libflashrom/w39v040c.c
@@ -0,0 +1,90 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2008 Peter Stuge <peter@stuge.se>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+
+int probe_w39v040c(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+	int result = probe_jedec(flash);
+	uint8_t lock;
+
+	if (!result)
+		return result;
+
+	chip_writeb(0xAA, bios + 0x5555);
+	programmer_delay(10);
+	chip_writeb(0x55, bios + 0x2AAA);
+	programmer_delay(10);
+	chip_writeb(0x90, bios + 0x5555);
+	programmer_delay(10);
+
+	lock = chip_readb(bios + 0xfff2);
+
+	chip_writeb(0xAA, bios + 0x5555);
+	programmer_delay(10);
+	chip_writeb(0x55, bios + 0x2AAA);
+	programmer_delay(10);
+	chip_writeb(0xF0, bios + 0x5555);
+	programmer_delay(40);
+
+	printf("%s: Boot block #TBL is %slocked, rest of chip #WP is %slocked.\n",
+		__func__, lock & 0x4 ? "" : "un", lock & 0x8 ? "" : "un");
+	return 1;
+}
+
+int erase_w39v040c(struct flashchip *flash)
+{
+	int i;
+	unsigned int total_size = flash->total_size * 1024;
+
+	for (i = 0; i < total_size; i += flash->page_size) {
+		if (erase_sector_jedec(flash, i, flash->page_size)) {
+			fprintf(stderr, "ERASE FAILED!\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int write_w39v040c(struct flashchip *flash, uint8_t *buf)
+{
+	int i;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+	chipaddr bios = flash->virtual_memory;
+
+	if (erase_flash(flash)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+
+	printf("Programming page: ");
+	for (i = 0; i < total_size / page_size; i++) {
+		printf("%04d at address: 0x%08x", i, i * page_size);
+		write_sector_jedec(bios, buf + i * page_size,
+				   bios + i * page_size, page_size);
+		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+	}
+	printf("\n");
+
+	return 0;
+}
diff --git a/libflashrom/w39v080fa.c b/libflashrom/w39v080fa.c
new file mode 100644
index 0000000..580657f
--- /dev/null
+++ b/libflashrom/w39v080fa.c
@@ -0,0 +1,190 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2008 coresystems GmbH
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+
+int probe_winbond_fwhub(struct flashchip *flash)
+{
+	int result = probe_jedec(flash);
+
+	if (!result)
+		return result;
+
+	map_flash_registers(flash);
+
+	return 1;
+}
+
+static int unlock_block_winbond_fwhub(struct flashchip *flash, int offset)
+{
+	chipaddr wrprotect = flash->virtual_registers + offset + 2;
+	uint8_t locking;
+
+	printf_debug("Trying to unlock block @0x%08x = 0x%02x\n", offset,
+		     chip_readb(wrprotect));
+
+	locking = chip_readb(wrprotect);
+	switch (locking & 0x7) {
+	case 0:
+		printf_debug("Full Access.\n");
+		return 0;
+	case 1:
+		printf_debug("Write Lock (Default State).\n");
+		chip_writeb(0, wrprotect);
+		return 0;
+	case 2:
+		printf_debug("Locked Open (Full Access, Lock Down).\n");
+		return 0;
+	case 3:
+		fprintf(stderr, "Error: Write Lock, Locked Down.\n");
+		return -1;
+	case 4:
+		printf_debug("Read Lock.\n");
+		chip_writeb(0, wrprotect);
+		return 0;
+	case 5:
+		printf_debug("Read/Write Lock.\n");
+		chip_writeb(0, wrprotect);
+		return 0;
+	case 6:
+		fprintf(stderr, "Error: Read Lock, Locked Down.\n");
+		return -1;
+	case 7:
+		fprintf(stderr, "Error: Read/Write Lock, Locked Down.\n");
+		return -1;
+	}
+
+	/* We will never reach this point, but GCC doesn't know */
+	return -1;
+}
+
+int unlock_winbond_fwhub(struct flashchip *flash)
+{
+	int i, total_size = flash->total_size * 1024;
+	chipaddr bios = flash->virtual_memory;
+	uint8_t locking;
+
+	/* Are there any hardware restrictions that we can't overcome? 
+	 * If flashrom fail here, someone's got to check all those GPIOs.
+	 */
+
+	/* Product Identification Entry */
+	chip_writeb(0xAA, bios + 0x5555);
+	chip_writeb(0x55, bios + 0x2AAA);
+	chip_writeb(0x90, bios + 0x5555);
+	programmer_delay(10);
+
+	/* Read Hardware Lock Bits */
+	locking = chip_readb(bios + 0xffff2);
+
+	/* Product Identification Exit */
+	chip_writeb(0xAA, bios + 0x5555);
+	chip_writeb(0x55, bios + 0x2AAA);
+	chip_writeb(0xF0, bios + 0x5555);
+	programmer_delay(10);
+
+	printf_debug("Lockout bits:\n");
+
+	if (locking & (1 << 2))
+		fprintf(stderr, "Error: hardware bootblock locking (#TBL).\n");
+	else
+		printf_debug("No hardware bootblock locking (good!)\n");
+
+	if (locking & (1 << 3))
+		fprintf(stderr, "Error: hardware block locking (#WP).\n");
+	else
+		printf_debug("No hardware block locking (good!)\n");
+
+	if (locking & ((1 << 2) | (1 << 3)))
+		return -1;
+
+	/* Unlock the complete chip */
+	for (i = 0; i < total_size; i += flash->page_size)
+		if (unlock_block_winbond_fwhub(flash, i))
+			return -1;
+
+	return 0;
+}
+
+static int erase_sector_winbond_fwhub(struct flashchip *flash,
+				      unsigned int sector)
+{
+	chipaddr bios = flash->virtual_memory;
+	/* Remember: too much sleep can waste your day. */
+
+	printf("0x%08x\b\b\b\b\b\b\b\b\b\b", sector);
+
+	/* Sector Erase */
+	chip_writeb(0xAA, bios + 0x5555);
+	chip_writeb(0x55, bios + 0x2AAA);
+	chip_writeb(0x80, bios + 0x5555);
+
+	chip_writeb(0xAA, bios + 0x5555);
+	chip_writeb(0x55, bios + 0x2AAA);
+	chip_writeb(0x30, bios + sector);
+
+	/* wait for Toggle bit ready */
+	toggle_ready_jedec(bios);
+
+	if (check_erased_range(flash, sector, flash->page_size)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+	return 0;
+}
+
+int erase_winbond_fwhub(struct flashchip *flash)
+{
+	int i, total_size = flash->total_size * 1024;
+
+	unlock_winbond_fwhub(flash);
+
+	printf("Erasing:     ");
+
+	for (i = 0; i < total_size; i += flash->page_size) {
+		if (erase_sector_winbond_fwhub(flash, i)) {
+			fprintf(stderr, "ERASE FAILED!\n");
+			return -1;
+		}
+	}
+
+	printf("\n");
+
+	return 0;
+}
+
+int write_winbond_fwhub(struct flashchip *flash, uint8_t *buf)
+{
+	int i;
+	int total_size = flash->total_size * 1024;
+	chipaddr bios = flash->virtual_memory;
+
+	if (erase_winbond_fwhub(flash))
+		return -1;
+
+	printf("Programming: ");
+	for (i = 0; i < total_size; i += flash->page_size) {
+		printf("0x%08x\b\b\b\b\b\b\b\b\b\b", i);
+		write_sector_jedec(bios, buf + i, bios + i, flash->page_size);
+	}
+	printf("\n");
+
+	return 0;
+}
diff --git a/libflashrom/w49f002u.c b/libflashrom/w49f002u.c
new file mode 100644
index 0000000..d12bc72
--- /dev/null
+++ b/libflashrom/w49f002u.c
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+
+int write_49f002(struct flashchip *flash, uint8_t *buf)
+{
+	int i;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+	chipaddr bios = flash->virtual_memory;
+
+	if (erase_chip_jedec(flash)) {
+		fprintf(stderr, "ERASE FAILED!\n");
+		return -1;
+	}
+
+	printf("Programming page: ");
+	for (i = 0; i < total_size / page_size; i++) {
+		printf("%04d at address: 0x%08x ", i, i * page_size);
+		/* Byte-wise writing of 'page_size' bytes. */
+		write_sector_jedec(bios, buf + i * page_size,
+				   bios + i * page_size, page_size);
+		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+		fflush(stdout);
+	}
+	printf("\n");
+
+	return 0;
+}
diff --git a/libflashrom/wbsio_spi.c b/libflashrom/wbsio_spi.c
new file mode 100644
index 0000000..6b9425f
--- /dev/null
+++ b/libflashrom/wbsio_spi.c
@@ -0,0 +1,199 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2008 Peter Stuge <peter@stuge.se>
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <string.h>
+#include "flash.h"
+#include "spi.h"
+
+#define WBSIO_PORT1	0x2e
+#define WBSIO_PORT2	0x4e
+
+static uint16_t wbsio_spibase = 0;
+
+static uint16_t wbsio_get_spibase(uint16_t port)
+{
+	uint8_t id;
+	uint16_t flashport = 0;
+
+	w836xx_ext_enter(port);
+	id = sio_read(port, 0x20);
+	if (id != 0xa0) {
+		fprintf(stderr, "\nW83627 not found at 0x%x, id=0x%02x want=0xa0.\n", port, id);
+		goto done;
+	}
+
+	if (0 == (sio_read(port, 0x24) & 2)) {
+		fprintf(stderr, "\nW83627 found at 0x%x, but SPI pins are not enabled. (CR[0x24] bit 1=0)\n", port);
+		goto done;
+	}
+
+	sio_write(port, 0x07, 0x06);
+	if (0 == (sio_read(port, 0x30) & 1)) {
+		fprintf(stderr, "\nW83627 found at 0x%x, but SPI is not enabled. (LDN6[0x30] bit 0=0)\n", port);
+		goto done;
+	}
+
+	flashport = (sio_read(port, 0x62) << 8) | sio_read(port, 0x63);
+
+done:
+	w836xx_ext_leave(port);
+	return flashport;
+}
+
+int wbsio_check_for_spi(const char *name)
+{
+	if (0 == (wbsio_spibase = wbsio_get_spibase(WBSIO_PORT1)))
+		if (0 == (wbsio_spibase = wbsio_get_spibase(WBSIO_PORT2)))
+			return 1;
+
+	printf_debug("\nwbsio_spibase = 0x%x\n", wbsio_spibase);
+
+	buses_supported |= CHIP_BUSTYPE_SPI;
+	spi_controller = SPI_CONTROLLER_WBSIO;
+
+	return 0;
+}
+
+/* W83627DHG has 11 command modes:
+ * 1=1 command only
+ * 2=1 command+1 data write
+ * 3=1 command+2 data read
+ * 4=1 command+3 address
+ * 5=1 command+3 address+1 data write
+ * 6=1 command+3 address+4 data write
+ * 7=1 command+3 address+1 dummy address inserted by wbsio+4 data read
+ * 8=1 command+3 address+1 data read
+ * 9=1 command+3 address+2 data read
+ * a=1 command+3 address+3 data read
+ * b=1 command+3 address+4 data read
+ *
+ * mode[7:4] holds the command mode
+ * mode[3:0] holds SPI address bits [19:16]
+ *
+ * The Winbond SPI master only supports 20 bit addresses on the SPI bus. :\
+ * Would one more byte of RAM in the chip (to get all 24 bits) really make
+ * such a big difference?
+ */
+int wbsio_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		      const unsigned char *writearr, unsigned char *readarr)
+{
+	int i;
+	uint8_t mode = 0;
+
+	printf_debug("%s:", __func__);
+
+	if (1 == writecnt && 0 == readcnt) {
+		mode = 0x10;
+	} else if (2 == writecnt && 0 == readcnt) {
+		OUTB(writearr[1], wbsio_spibase + 4);
+		printf_debug(" data=0x%02x", writearr[1]);
+		mode = 0x20;
+	} else if (1 == writecnt && 2 == readcnt) {
+		mode = 0x30;
+	} else if (4 == writecnt && 0 == readcnt) {
+		printf_debug(" addr=0x%02x", (writearr[1] & 0x0f));
+		for (i = 2; i < writecnt; i++) {
+			OUTB(writearr[i], wbsio_spibase + i);
+			printf_debug("%02x", writearr[i]);
+		}
+		mode = 0x40 | (writearr[1] & 0x0f);
+	} else if (5 == writecnt && 0 == readcnt) {
+		printf_debug(" addr=0x%02x", (writearr[1] & 0x0f));
+		for (i = 2; i < 4; i++) {
+			OUTB(writearr[i], wbsio_spibase + i);
+			printf_debug("%02x", writearr[i]);
+		}
+		OUTB(writearr[i], wbsio_spibase + i);
+		printf_debug(" data=0x%02x", writearr[i]);
+		mode = 0x50 | (writearr[1] & 0x0f);
+	} else if (8 == writecnt && 0 == readcnt) {
+		printf_debug(" addr=0x%02x", (writearr[1] & 0x0f));
+		for (i = 2; i < 4; i++) {
+			OUTB(writearr[i], wbsio_spibase + i);
+			printf_debug("%02x", writearr[i]);
+		}
+		printf_debug(" data=0x");
+		for (; i < writecnt; i++) {
+			OUTB(writearr[i], wbsio_spibase + i);
+			printf_debug("%02x", writearr[i]);
+		}
+		mode = 0x60 | (writearr[1] & 0x0f);
+	} else if (5 == writecnt && 4 == readcnt) {
+		/* XXX: TODO not supported by flashrom infrastructure!
+		 * This mode, 7, discards the fifth byte in writecnt,
+		 * but since we can not express that in flashrom, fail
+		 * the operation for now.
+		 */
+		;
+	} else if (4 == writecnt && readcnt >= 1 && readcnt <= 4) {
+		printf_debug(" addr=0x%02x", (writearr[1] & 0x0f));
+		for (i = 2; i < writecnt; i++) {
+			OUTB(writearr[i], wbsio_spibase + i);
+			printf_debug("%02x", writearr[i]);
+		}
+		mode = ((7 + readcnt) << 4) | (writearr[1] & 0x0f);
+	}
+	printf_debug(" cmd=%02x mode=%02x\n", writearr[0], mode);
+
+	if (!mode) {
+		fprintf(stderr, "%s: unsupported command type wr=%d rd=%d\n",
+			__func__, writecnt, readcnt);
+		/* Command type refers to the number of bytes read/written. */
+		return SPI_INVALID_LENGTH;
+	}
+
+	OUTB(writearr[0], wbsio_spibase);
+	OUTB(mode, wbsio_spibase + 1);
+	programmer_delay(10);
+
+	if (!readcnt)
+		return 0;
+
+	printf_debug("%s: returning data =", __func__);
+	for (i = 0; i < readcnt; i++) {
+		readarr[i] = INB(wbsio_spibase + 4 + i);
+		printf_debug(" 0x%02x", readarr[i]);
+	}
+	printf_debug("\n");
+	return 0;
+}
+
+int wbsio_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
+{
+	int size = flash->total_size * 1024;
+
+	if (size > 1024 * 1024) {
+		fprintf(stderr, "%s: Winbond saved on 4 register bits so max chip size is 1024 KB!\n", __func__);
+		return 1;
+	}
+
+	return read_memmapped(flash, buf, start, len);
+}
+
+int wbsio_spi_write_1(struct flashchip *flash, uint8_t *buf)
+{
+	int size = flash->total_size * 1024;
+
+	if (size > 1024 * 1024) {
+		fprintf(stderr, "%s: Winbond saved on 4 register bits so max chip size is 1024 KB!\n", __func__);
+		return 1;
+	}
+
+	return spi_chip_write_1(flash, buf);
+}
diff --git a/m29f002.c b/m29f002.c
deleted file mode 100644
index 01a7a50..0000000
--- a/m29f002.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Peter Stuge <peter@stuge.se>
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "flash.h"
-
-int erase_m29f002(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-	chip_writeb(0xaa, bios + 0x555);
-	chip_writeb(0x55, bios + 0xaaa);
-	chip_writeb(0x80, bios + 0x555);
-	chip_writeb(0xaa, bios + 0x555);
-	chip_writeb(0x55, bios + 0xaaa);
-	chip_writeb(0x10, bios + 0x555);
-	programmer_delay(10);
-	toggle_ready_jedec(bios);
-	if (check_erased_range(flash, 0, flash->total_size * 1024)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-static int rewrite_block(struct flashchip *flash, uint8_t *src,
-			  unsigned long start, int size)
-{
-	chipaddr bios = flash->virtual_memory;
-	chipaddr dst = bios + start;
-
-	/* erase */
-	/* FIXME: use erase_sector_jedec? */
-	chip_writeb(0xaa, bios + 0x555);
-	chip_writeb(0x55, bios + 0xaaa);
-	chip_writeb(0x80, bios + 0x555);
-	chip_writeb(0xaa, bios + 0x555);
-	chip_writeb(0x55, bios + 0xaaa);
-	chip_writeb(0x30, dst);
-	programmer_delay(10);
-	toggle_ready_jedec(bios);
-	if (check_erased_range(flash, start, size)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-
-	/* program */
-	/* FIXME: use write_sector_jedec? */
-	while (size--) {
-		chip_writeb(0xaa, bios + 0x555);
-		chip_writeb(0x55, bios + 0xaaa);
-		chip_writeb(0xa0, bios + 0x555);
-		chip_writeb(*src, dst);
-		toggle_ready_jedec(dst);
-		dst++;
-		src++;
-	}
-	return 0;
-}
-
-static int do_block(struct flashchip *flash, uint8_t *src, int i,
-		     unsigned long start, int size)
-{
-	int ret;
-	printf("%d at address: 0x%08lx", i, start);
-	ret = rewrite_block(flash, src + start, start, size);
-	if (ret)
-		return ret;
-	printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-	return 0;
-}
-
-int write_m29f002t(struct flashchip *flash, uint8_t *buf)
-{
-	int i, page_size = flash->page_size;
-
-	/* M29F002(N)T has 7 blocks. From bottom to top their sizes are:
-	 * 64k 64k 64k 32k 8k 8k 16k
-	 * flash->page_size is set to 64k in flashchips.c
-	 */
-
-	printf("Programming block: ");
-	for (i = 0; i < 3; i++)
-		do_block(flash, buf, i, i * page_size, page_size);
-	do_block(flash, buf, i++, 0x30000, 32 * 1024);
-	do_block(flash, buf, i++, 0x38000, 8 * 1024);
-	do_block(flash, buf, i++, 0x3a000, 8 * 1024);
-	do_block(flash, buf, i, 0x3c000, 16 * 1024);
-
-	printf("\n");
-	return 0;
-}
-
-int write_m29f002b(struct flashchip *flash, uint8_t *buf)
-{
-	int i = 0, page_size = flash->page_size;
-
-	/* M29F002B has 7 blocks. From bottom to top their sizes are:
-	 * 16k 8k 8k 32k 64k 64k 64k
-	 * flash->page_size is set to 64k in flashchips.c
-	 */
-
-	printf("Programming block: ");
-	do_block(flash, buf, i++, 0x00000, 16 * 1024);
-	do_block(flash, buf, i++, 0x04000, 8 * 1024);
-	do_block(flash, buf, i++, 0x06000, 8 * 1024);
-	do_block(flash, buf, i++, 0x08000, 32 * 1024);
-	for (; i < 7; i++)
-		do_block(flash, buf, i, (i - 3) * page_size, page_size);
-
-	printf("\n");
-	return 0;
-}
diff --git a/m29f400bt.c b/m29f400bt.c
deleted file mode 100644
index c327f44..0000000
--- a/m29f400bt.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "flash.h"
-
-/* WARNING! 
-   This chip uses the standard JEDEC Addresses in 16-bit mode as word
-   addresses. In byte mode, 0xAAA has to be used instead of 0x555 and
-   0x555 instead of 0x2AA. Do *not* blindly replace with standard JEDEC
-   functions. */
-
-void write_page_m29f400bt(chipaddr bios, uint8_t *src,
-			  chipaddr dst, int page_size)
-{
-	int i;
-
-	for (i = 0; i < page_size; i++) {
-		chip_writeb(0xAA, bios + 0xAAA);
-		chip_writeb(0x55, bios + 0x555);
-		chip_writeb(0xA0, bios + 0xAAA);
-
-		/* transfer data from source to destination */
-		chip_writeb(*src, dst);
-		//chip_writeb(0xF0, bios);
-		//programmer_delay(5);
-		toggle_ready_jedec(dst);
-		printf
-		    ("Value in the flash at address 0x%lx = %#x, want %#x\n",
-		     (dst - bios), chip_readb(dst), *src);
-		dst++;
-		src++;
-	}
-}
-
-int probe_m29f400bt(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-	uint8_t id1, id2;
-
-	chip_writeb(0xAA, bios + 0xAAA);
-	chip_writeb(0x55, bios + 0x555);
-	chip_writeb(0x90, bios + 0xAAA);
-
-	programmer_delay(10);
-
-	id1 = chip_readb(bios);
-	/* The data sheet says id2 is at (bios + 0x01) and id2 listed in
-	 * flash.h does not match. It should be possible to use JEDEC probe.
-	 */
-	id2 = chip_readb(bios + 0x02);
-
-	chip_writeb(0xAA, bios + 0xAAA);
-	chip_writeb(0x55, bios + 0x555);
-	chip_writeb(0xF0, bios + 0xAAA);
-
-	programmer_delay(10);
-
-	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
-
-	if (id1 == flash->manufacture_id && id2 == flash->model_id)
-		return 1;
-
-	return 0;
-}
-
-int erase_m29f400bt(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-
-	chip_writeb(0xAA, bios + 0xAAA);
-	chip_writeb(0x55, bios + 0x555);
-	chip_writeb(0x80, bios + 0xAAA);
-
-	chip_writeb(0xAA, bios + 0xAAA);
-	chip_writeb(0x55, bios + 0x555);
-	chip_writeb(0x10, bios + 0xAAA);
-
-	programmer_delay(10);
-	toggle_ready_jedec(bios);
-
-	if (check_erased_range(flash, 0, flash->total_size * 1024)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-int block_erase_m29f400bt(struct flashchip *flash, int start, int len)
-{
-	chipaddr bios = flash->virtual_memory;
-	chipaddr dst = bios + start;
-
-	chip_writeb(0xAA, bios + 0xAAA);
-	chip_writeb(0x55, bios + 0x555);
-	chip_writeb(0x80, bios + 0xAAA);
-
-	chip_writeb(0xAA, bios + 0xAAA);
-	chip_writeb(0x55, bios + 0x555);
-	//chip_writeb(0x10, bios + 0xAAA);
-	chip_writeb(0x30, dst);
-
-	programmer_delay(10);
-	toggle_ready_jedec(bios);
-
-	if (check_erased_range(flash, start, len)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-int write_m29f400bt(struct flashchip *flash, uint8_t *buf)
-{
-	int i;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-	chipaddr bios = flash->virtual_memory;
-
-	//erase_m29f400bt (flash);
-	printf("Programming page:\n ");
-	/*********************************
-	*Pages for M29F400BT:
-	* 16	0x7c000		0x7ffff		TOP
-	*  8 	0x7a000		0x7bfff
-	*  8 	0x78000		0x79fff
-	* 32	0x70000		0x77fff
-	* 64	0x60000		0x6ffff
-	* 64	0x50000		0x5ffff
-	* 64	0x40000		0x4ffff
-	*---------------------------------
-	* 64	0x30000		0x3ffff
-	* 64	0x20000		0x2ffff
-	* 64	0x10000		0x1ffff
-	* 64	0x00000		0x0ffff		BOTTOM
-	*********************************/
-	printf("total_size/page_size = %d\n", total_size / page_size);
-	for (i = 0; i < (total_size / page_size) - 1; i++) {
-		printf("%04d at address: 0x%08x\n", i, i * page_size);
-		if (block_erase_m29f400bt(flash, i * page_size, page_size)) {
-			fprintf(stderr, "ERASE FAILED!\n");
-			return -1;
-		}
-		write_page_m29f400bt(bios, buf + i * page_size,
-				     bios + i * page_size, page_size);
-		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-	}
-
-	printf("%04d at address: 0x%08x\n", 7, 0x70000);
-	if (block_erase_m29f400bt(flash, 0x70000, 32 * 1024)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	write_page_m29f400bt(bios, buf + 0x70000, bios + 0x70000, 32 * 1024);
-
-	printf("%04d at address: 0x%08x\n", 8, 0x78000);
-	if (block_erase_m29f400bt(flash, 0x78000, 8 * 1024)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	write_page_m29f400bt(bios, buf + 0x78000, bios + 0x78000, 8 * 1024);
-
-	printf("%04d at address: 0x%08x\n", 9, 0x7a000);
-	if (block_erase_m29f400bt(flash, 0x7a000, 8 * 1024)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	write_page_m29f400bt(bios, buf + 0x7a000, bios + 0x7a000, 8 * 1024);
-
-	printf("%04d at address: 0x%08x\n", 10, 0x7c000);
-	if (block_erase_m29f400bt(flash, 0x7c000, 16 * 1024)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	write_page_m29f400bt(bios, buf + 0x7c000, bios + 0x7c000, 16 * 1024);
-
-	printf("\n");
-
-	return 0;
-}
-
-int write_coreboot_m29f400bt(struct flashchip *flash, uint8_t *buf)
-{
-	chipaddr bios = flash->virtual_memory;
-
-	printf("Programming page:\n ");
-	/*********************************
-	*Pages for M29F400BT:
-	* 16	0x7c000		0x7ffff		TOP
-	*  8 	0x7a000		0x7bfff
-	*  8 	0x78000		0x79fff
-	* 32	0x70000		0x77fff
-	* 64	0x60000		0x6ffff
-	* 64	0x50000		0x5ffff
-	* 64	0x40000		0x4ffff
-	*---------------------------------
-	* 64	0x30000		0x3ffff
-	* 64	0x20000		0x2ffff
-	* 64	0x10000		0x1ffff
-	* 64	0x00000		0x0ffff		BOTTOM
-	*********************************/
-	printf("%04d at address: 0x%08x\n", 7, 0x00000);
-	if (block_erase_m29f400bt(flash, 0x00000, 64 * 1024)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	write_page_m29f400bt(bios, buf + 0x00000, bios + 0x00000, 64 * 1024);
-
-	printf("%04d at address: 0x%08x\n", 7, 0x10000);
-	if (block_erase_m29f400bt(flash, 0x10000, 64 * 1024)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	write_page_m29f400bt(bios, buf + 0x10000, bios + 0x10000, 64 * 1024);
-
-	printf("%04d at address: 0x%08x\n", 7, 0x20000);
-	if (block_erase_m29f400bt(flash, 0x20000, 64 * 1024)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	write_page_m29f400bt(bios, buf + 0x20000, bios + 0x20000, 64 * 1024);
-
-	printf("%04d at address: 0x%08x\n", 7, 0x30000);
-	if (block_erase_m29f400bt(flash, 0x30000, 64 * 1024)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	write_page_m29f400bt(bios, buf + 0x30000, bios + 0x30000, 64 * 1024);
-
-	printf("\n");
-
-	return 0;
-}
diff --git a/mx29f002.c b/mx29f002.c
deleted file mode 100644
index 7838c3d..0000000
--- a/mx29f002.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "flash.h"
-
-int probe_29f002(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-	uint8_t id1, id2;
-
-	chip_writeb(0xAA, bios + 0x5555);
-	chip_writeb(0x55, bios + 0x2AAA);
-	chip_writeb(0x90, bios + 0x5555);
-
-	id1 = chip_readb(bios);
-	id2 = chip_readb(bios + 0x01);
-
-	chip_writeb(0xF0, bios);
-
-	programmer_delay(10);
-
-	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
-	if (id1 == flash->manufacture_id && id2 == flash->model_id)
-		return 1;
-
-	return 0;
-}
-
-/* FIXME: Use erase_chip_jedec?
- * erase_29f002 uses shorter addresses, sends F0 (exit ID mode) and
- * and has a bigger delay before polling the toggle bit */
-int erase_29f002(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-
-	chip_writeb(0xF0, bios + 0x555);
-	chip_writeb(0xAA, bios + 0x555);
-	chip_writeb(0x55, bios + 0x2AA);
-	chip_writeb(0x80, bios + 0x555);
-	chip_writeb(0xAA, bios + 0x555);
-	chip_writeb(0x55, bios + 0x2AA);
-	chip_writeb(0x10, bios + 0x555);
-
-	programmer_delay(100);
-	toggle_ready_jedec(bios);
-
-	if (check_erased_range(flash, 0, flash->total_size * 1024)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
diff --git a/nic3com.c b/nic3com.c
deleted file mode 100644
index a4878d2..0000000
--- a/nic3com.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include "flash.h"
-
-#define BIOS_ROM_ADDR		0x04
-#define BIOS_ROM_DATA		0x08
-#define INT_STATUS		0x0e
-#define INTERNAL_CONFIG		0x00
-#define SELECT_REG_WINDOW	0x800
-
-#define PCI_VENDOR_ID_3COM	0x10b7
-
-uint32_t internal_conf;
-uint16_t id;
-
-struct pcidev_status nics_3com[] = {
-	/* 3C90xB */
-	{0x10b7, 0x9055, PCI_OK, "3COM", "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-TX"},
-	{0x10b7, 0x9001, PCI_NT, "3COM", "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-T4" },
-	{0x10b7, 0x9004, PCI_OK, "3COM", "3C90xB: PCI 10BASE-T (TPO)" },
-	{0x10b7, 0x9005, PCI_NT, "3COM", "3C90xB: PCI 10BASE-T/10BASE2/AUI (COMBO)" },
-	{0x10b7, 0x9006, PCI_NT, "3COM", "3C90xB: PCI 10BASE-T/10BASE2 (TPC)" },
-	{0x10b7, 0x900a, PCI_NT, "3COM", "3C90xB: PCI 10BASE-FL" },
-	{0x10b7, 0x905a, PCI_NT, "3COM", "3C90xB: PCI 10BASE-FX" },
-	{0x10b7, 0x9058, PCI_OK, "3COM", "3C905B: Cyclone 10/100/BNC" },
-
-	/* 3C905C */
-	{0x10b7, 0x9200, PCI_OK, "3COM", "3C905C: EtherLink 10/100 PCI (TX)" },
-
-	/* 3C980C */
-	{0x10b7, 0x9805, PCI_NT, "3COM", "3C980C: EtherLink Server 10/100 PCI (TX)" },
-
-	{},
-};
-
-int nic3com_init(void)
-{
-	get_io_perms();
-
-	io_base_addr = pcidev_init(PCI_VENDOR_ID_3COM, PCI_BASE_ADDRESS_0,
-				   nics_3com, programmer_param);
-	id = pcidev_dev->device_id;
-
-	/* 3COM 3C90xB cards need a special fixup. */
-	if (id == 0x9055 || id == 0x9001 || id == 0x9004 || id == 0x9005
-	    || id == 0x9006 || id == 0x900a || id == 0x905a || id == 0x9058) {
-		/* Select register window 3 and save the receiver status. */
-		OUTW(SELECT_REG_WINDOW + 3, io_base_addr + INT_STATUS);
-		internal_conf = INL(io_base_addr + INTERNAL_CONFIG);
-
-		/* Set receiver type to MII for full BIOS ROM access. */
-		OUTL((internal_conf & 0xf00fffff) | 0x00600000, io_base_addr);
-	}
-
-	/*
-	 * The lowest 16 bytes of the I/O mapped register space of (most) 3COM
-	 * cards form a 'register window' into one of multiple (usually 8)
-	 * register banks. For 3C90xB/3C90xC we need register window/bank 0.
-	 */
-	OUTW(SELECT_REG_WINDOW + 0, io_base_addr + INT_STATUS);
-
-	buses_supported = CHIP_BUSTYPE_PARALLEL;
-
-	return 0;
-}
-
-int nic3com_shutdown(void)
-{
-	/* 3COM 3C90xB cards need a special fixup. */
-	if (id == 0x9055 || id == 0x9001 || id == 0x9004 || id == 0x9005
-	    || id == 0x9006 || id == 0x900a || id == 0x905a || id == 0x9058) {
-		/* Select register window 3 and restore the receiver status. */
-		OUTW(SELECT_REG_WINDOW + 3, io_base_addr + INT_STATUS);
-		OUTL(internal_conf, io_base_addr + INTERNAL_CONFIG);
-	}
-
-	free(programmer_param);
-	pci_cleanup(pacc);
-	release_io_perms();
-	return 0;
-}
-
-void nic3com_chip_writeb(uint8_t val, chipaddr addr)
-{
-	OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR);
-	OUTB(val, io_base_addr + BIOS_ROM_DATA);
-}
-
-uint8_t nic3com_chip_readb(const chipaddr addr)
-{
-	OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR);
-	return INB(io_base_addr + BIOS_ROM_DATA);
-}
diff --git a/pcidev.c b/pcidev.c
deleted file mode 100644
index 6c92c0a..0000000
--- a/pcidev.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include "flash.h"
-
-uint32_t io_base_addr;
-struct pci_access *pacc;
-struct pci_filter filter;
-struct pci_dev *pcidev_dev = NULL;
-
-uint32_t pcidev_validate(struct pci_dev *dev, uint32_t bar,
-			 struct pcidev_status *devs)
-{
-	int i;
-	uint32_t addr;
-
-	for (i = 0; devs[i].device_name != NULL; i++) {
-		if (dev->device_id != devs[i].device_id)
-			continue;
-
-		/*
-		 * Don't use dev->base_addr[x] (as value for 'bar'), won't
-		 * work on older libpci.
-		 */
-		addr = pci_read_long(dev, bar) & ~0x03;
-		
-		printf("Found \"%s %s\" (%04x:%04x, BDF %02x:%02x.%x).\n",
-		       devs[i].vendor_name, devs[i].device_name,
-		       dev->vendor_id, dev->device_id, dev->bus, dev->dev,
-		       dev->func);
-
-		if (devs[i].status == PCI_NT) {
-			printf("===\nThis PCI device is UNTESTED. Please "
-			       "report the 'flashrom -p xxxx' output \n"
-			       "to flashrom@flashrom.org if it works "
-			       "for you. Thank you for your help!\n===\n");
-		}
-
-		return addr;
-	}
-
-	return 0;
-}
-
-uint32_t pcidev_init(uint16_t vendor_id, uint32_t bar,
-		     struct pcidev_status *devs, char *pcidev_bdf)
-{
-	struct pci_dev *dev;
-	char *msg = NULL;
-	int found = 0;
-	uint32_t addr = 0, curaddr = 0;
-
-	pacc = pci_alloc();     /* Get the pci_access structure */
-	pci_init(pacc);         /* Initialize the PCI library */
-	pci_scan_bus(pacc);     /* We want to get the list of devices */
-	pci_filter_init(pacc, &filter);
-
-	/* Filter by vendor and also bb:dd.f (if supplied by the user). */
-	filter.vendor = vendor_id;
-	if (pcidev_bdf != NULL) {
-		if ((msg = pci_filter_parse_slot(&filter, pcidev_bdf))) {
-			fprintf(stderr, "Error: %s\n", msg);
-			exit(1);
-		}
-	}
-
-	for (dev = pacc->devices; dev; dev = dev->next) {
-		if (pci_filter_match(&filter, dev)) {
-			if ((addr = pcidev_validate(dev, bar, devs)) != 0) {
-				curaddr = addr;
-				pcidev_dev = dev;
-				found++;
-			}
-		}
-	}
-
-	/* Only continue if exactly one supported PCI dev has been found. */
-	if (found == 0) {
-		fprintf(stderr, "Error: No supported PCI device found.\n");
-		exit(1);
-	} else if (found > 1) {
-		fprintf(stderr, "Error: Multiple supported PCI devices found. "
-			"Use 'flashrom -p xxxx:bb:dd.f' \n"
-			"to explicitly select the card with the given BDF "
-			"(PCI bus, device, function).\n");
-		exit(1);
-	}
-
-	return curaddr;
-}
-
-void print_supported_pcidevs(struct pcidev_status *devs)
-{
-	int i;
-
-	for (i = 0; devs[i].vendor_name != NULL; i++) {
-		printf("%s %s [%02x:%02x]%s\n", devs[i].vendor_name,
-		       devs[i].device_name, devs[i].vendor_id,
-		       devs[i].device_id,
-		       (devs[i].status == PCI_NT) ? " (untested)" : "");
-	}
-}
diff --git a/physmap.c b/physmap.c
deleted file mode 100644
index 3a003fe..0000000
--- a/physmap.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Peter Stuge <peter@stuge.se>
- * Copyright (C) 2009 coresystems GmbH
- *
- * 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; version 2 of the License.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include "flash.h"
-
-#ifdef __DARWIN__
-#include <DirectIO/darwinio.h>
-
-#define MEM_DEV "DirectIO"
-
-void *sys_physmap(unsigned long phys_addr, size_t len)
-{
-	return map_physical(phys_addr, len);
-}
-
-void physunmap(void *virt_addr, size_t len)
-{
-	unmap_physical(virt_addr, len);
-}
-
-#else
-#include <sys/mman.h>
-
-#if defined (__sun) && (defined(__i386) || defined(__amd64))
-#  define MEM_DEV "/dev/xsvc"
-#else
-#  define MEM_DEV "/dev/mem"
-#endif
-
-static int fd_mem = -1;
-
-void *sys_physmap(unsigned long phys_addr, size_t len)
-{
-	void *virt_addr;
-
-	if (-1 == fd_mem) {
-		/* Open the memory device UNCACHED. Important for MMIO. */
-		if (-1 == (fd_mem = open(MEM_DEV, O_RDWR | O_SYNC))) {
-			perror("Critical error: open(" MEM_DEV ")");
-			exit(2);
-		}
-	}
-
-	virt_addr = mmap(0, len, PROT_WRITE | PROT_READ, MAP_SHARED,
-			 fd_mem, (off_t)phys_addr);
-	return MAP_FAILED == virt_addr ? NULL : virt_addr;
-}
-
-void physunmap(void *virt_addr, size_t len)
-{
-	if (len == 0) {
-		printf_debug("Not unmapping zero size at %p\n", virt_addr);
-		return;
-	}
-		
-	munmap(virt_addr, len);
-}
-#endif
-
-void *physmap(const char *descr, unsigned long phys_addr, size_t len)
-{
-	void *virt_addr;
-
-	if (len == 0) {
-		printf_debug("Not mapping %s, zero size at 0x%08lx.\n",
-			     descr, phys_addr);
-		return NULL;
-	}
-		
-	if ((getpagesize() - 1) & len) {
-		fprintf(stderr, "Mapping %s at 0x%08lx, unaligned size 0x%lx.\n",
-			descr, phys_addr, (unsigned long)len);
-	}
-
-	if ((getpagesize() - 1) & phys_addr) {
-		fprintf(stderr, "Mapping %s, 0x%lx bytes at unaligned 0x%08lx.\n",
-			descr, (unsigned long)len, phys_addr);
-	}
-
-	virt_addr = sys_physmap(phys_addr, len);
-
-	if (NULL == virt_addr) {
-		if (NULL == descr)
-			descr = "memory";
-		fprintf(stderr, "Error accessing %s, 0x%lx bytes at 0x%08lx\n", descr, (unsigned long)len, phys_addr);
-		perror(MEM_DEV " mmap failed");
-		if (EINVAL == errno) {
-			fprintf(stderr, "In Linux this error can be caused by the CONFIG_NONPROMISC_DEVMEM (<2.6.27),\n");
-			fprintf(stderr, "CONFIG_STRICT_DEVMEM (>=2.6.27) and CONFIG_X86_PAT kernel options.\n");
-			fprintf(stderr, "Please check if either is enabled in your kernel before reporting a failure.\n");
-			fprintf(stderr, "You can override CONFIG_X86_PAT at boot with the nopat kernel parameter but\n");
-			fprintf(stderr, "disabling the other option unfortunately requires a kernel recompile. Sorry!\n");
-		}
-		exit(3);
-	}
-
-	return virt_addr;
-}
-
-#ifdef __linux__
-/*
- * Reading and writing to MSRs, however requires instructions rdmsr/wrmsr,
- * which are ring0 privileged instructions so only the kernel can do the
- * read/write.  This function, therefore, requires that the msr kernel module
- * be loaded to access these instructions from user space using device
- * /dev/cpu/0/msr.
- */
-
-static int fd_msr = -1;
-
-msr_t rdmsr(int addr)
-{
-	uint32_t buf[2];
-	msr_t msr = { 0xffffffff, 0xffffffff };
-
-	if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) {
-		perror("Could not lseek() to MSR");
-		close(fd_msr);
-		exit(1);
-	}
-
-	if (read(fd_msr, buf, 8) == 8) {
-		msr.lo = buf[0];
-		msr.hi = buf[1];
-
-		return msr;
-	}
-
-	if (errno != EIO) {
-		// A severe error.
-		perror("Could not read() MSR");
-		close(fd_msr);
-		exit(1);
-	}
-
-	return msr;
-}
-
-int wrmsr(int addr, msr_t msr)
-{
-	if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) {
-		perror("Could not lseek() to MSR");
-		close(fd_msr);
-		exit(1);
-	}
-
-	if (write(fd_msr, &msr, 8) != 8 && errno != EIO) {
-		perror("Could not write() MSR");
-		close(fd_msr);
-		exit(1);
-	}
-
-	/* some MSRs must not be written */
-	if (errno == EIO)
-		return -1;
-
-	return 0;
-}
-
-int setup_cpu_msr(int cpu)
-{
-	char msrfilename[64];
-	memset(msrfilename, 0, 64);
-	sprintf(msrfilename, "/dev/cpu/%d/msr", cpu);
-
-	if (fd_msr != -1) {
-		printf("MSR was already initialized\n");
-		return -1;
-	}
-
-	fd_msr = open(msrfilename, O_RDWR);
-
-	if (fd_msr < 0) {
-		perror("Error while opening /dev/cpu/0/msr");
-		printf("Did you run 'modprobe msr'?\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-void cleanup_cpu_msr(void)
-{
-	if (fd_msr == -1) {
-		printf("No MSR initialized.\n");
-		return;
-	}
-
-	close(fd_msr);
-
-	/* Clear MSR file descriptor */
-	fd_msr = -1;
-}
-#else
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-#include <sys/ioctl.h>
-
-typedef struct {
-	int msr;
-	uint64_t data;
-} cpu_msr_args_t;
-#define CPU_RDMSR _IOWR('c', 1, cpu_msr_args_t)
-#define CPU_WRMSR _IOWR('c', 2, cpu_msr_args_t)
-
-static int fd_msr = -1;
-
-msr_t rdmsr(int addr)
-{
-	cpu_msr_args_t args;
-
-	msr_t msr = { 0xffffffff, 0xffffffff };
-
-	args.msr = addr;
-
-	if (ioctl(fd_msr, CPU_RDMSR, &args) < 0) {
-		perror("CPU_RDMSR");
-		close(fd_msr);
-		exit(1);
-	}
-
-	msr.lo = args.data & 0xffffffff;
-	msr.hi = args.data >> 32;
-
-	return msr;
-}
-
-int wrmsr(int addr, msr_t msr)
-{
-	cpu_msr_args_t args;
-
-	args.msr = addr;
-	args.data = (((uint64_t)msr.hi) << 32) | msr.lo;
-
-	if (ioctl(fd_msr, CPU_WRMSR, &args) < 0) {
-		perror("CPU_WRMSR");
-		close(fd_msr);
-		exit(1);
-	}
-
-	return 0;
-}
-
-int setup_cpu_msr(int cpu)
-{
-	char msrfilename[64];
-	memset(msrfilename, 0, 64);
-	sprintf(msrfilename, "/dev/cpu%d", cpu);
-
-	if (fd_msr != -1) {
-		printf("MSR was already initialized\n");
-		return -1;
-	}
-
-	fd_msr = open(msrfilename, O_RDWR);
-
-	if (fd_msr < 0) {
-		perror("Error while opening /dev/cpu0");
-		printf("Did you install ports/sysutils/devcpu?\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-void cleanup_cpu_msr(void)
-{
-	if (fd_msr == -1) {
-		printf("No MSR initialized.\n");
-		return;
-	}
-
-	close(fd_msr);
-
-	/* Clear MSR file descriptor */
-	fd_msr = -1;
-}
-
-#else
-
-#ifdef __DARWIN__
-int setup_cpu_msr(int cpu)
-{
-	// Always succeed for now
-	return 0;
-}
-
-void cleanup_cpu_msr(void)
-{
-	// Nothing, yet.
-}
-#else
-msr_t rdmsr(int addr)
-{
-	msr_t ret = { 0xffffffff, 0xffffffff };
-
-	return ret;
-}
-
-int wrmsr(int addr, msr_t msr)
-{
-	return -1;
-}
-
-int setup_cpu_msr(int cpu)
-{
-	printf("No MSR support for your OS yet.\n");
-	return -1;
-}
-
-void cleanup_cpu_msr(void)
-{
-	// Nothing, yet.
-}
-#endif
-#endif
-#endif
-
diff --git a/pm29f002.c b/pm29f002.c
deleted file mode 100644
index bf78d13..0000000
--- a/pm29f002.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "flash.h"
-
-/* if write_sector_jedec is used,
-   this is write_jedec_1 */
-int write_pm29f002(struct flashchip *flash, uint8_t *buf)
-{
-	int i, total_size = flash->total_size * 1024;
-	chipaddr bios = flash->virtual_memory;
-	chipaddr dst = bios;
-
-	if (erase_flash(flash)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-
-	/* FIXME: use write_sector_jedec? */
-	printf("Programming page: ");
-	for (i = 0; i < total_size; i++) {
-		if ((i & 0xfff) == 0)
-			printf("address: 0x%08lx", (unsigned long)i);
-
-		/* Pm29F002T/B only support byte-wise programming. */
-		chip_writeb(0xAA, bios + 0x555);
-		chip_writeb(0x55, bios + 0x2AA);
-		chip_writeb(0xA0, bios + 0x555);
-		chip_writeb(*buf++, dst++);
-
-		/* Wait for Toggle bit ready. */
-		toggle_ready_jedec(dst);
-
-		if ((i & 0xfff) == 0)
-			printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-	}
-
-	printf("\n");
-
-	return 0;
-}
diff --git a/pm49fl00x.c b/pm49fl00x.c
deleted file mode 100644
index 27a1163..0000000
--- a/pm49fl00x.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2004 Tyan Corporation
- * Copyright (C) 2007 Nikolay Petukhov <nikolay.petukhov@gmail.com>
- * Copyright (C) 2007 Reinder E.N. de Haan <lb_reha@mveas.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "flash.h"
-
-void write_lockbits_49fl00x(chipaddr bios, int size,
-			    unsigned char bits, int block_size)
-{
-	int i, left = size;
-
-	for (i = 0; left >= block_size; i++, left -= block_size) {
-		/* pm49fl002 */
-		if (block_size == 16384 && i % 2)
-			continue;
-
-		chip_writeb(bits, bios + (i * block_size) + 2);
-	}
-}
-
-int probe_49fl00x(struct flashchip *flash)
-{
-	int ret = probe_jedec(flash);
-
-	if (ret == 1)
-		map_flash_registers(flash);
-
-	return ret;
-}
-
-int erase_49fl00x(struct flashchip *flash)
-{
-	int i;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-
-	/* unprotected */
-	write_lockbits_49fl00x(flash->virtual_registers,
-			       total_size, 0, page_size);
-
-	/*
-	 * erase_chip_jedec() will not work... Datasheet says
-	 * "Chip erase is available in A/A Mux Mode only".
-	 */
-	printf("Erasing page: ");
-	for (i = 0; i < total_size / page_size; i++) {
-		/* erase the page */
-		if (erase_block_jedec(flash, i * page_size, page_size)) {
-			fprintf(stderr, "ERASE FAILED!\n");
-			return -1;
-		}
-		printf("%04d at address: 0x%08x", i, i * page_size);
-		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-		fflush(stdout);
-	}
-	printf("\n");
-
-	/* protected */
-	write_lockbits_49fl00x(flash->virtual_registers,
-			       total_size, 1, page_size);
-
-	return 0;
-}
-
-int write_49fl00x(struct flashchip *flash, uint8_t *buf)
-{
-	int i;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-	chipaddr bios = flash->virtual_memory;
-
-	/* unprotected */
-	write_lockbits_49fl00x(flash->virtual_registers, total_size, 0,
-			       page_size);
-
-	printf("Programming page: ");
-	for (i = 0; i < total_size / page_size; i++) {
-		/* erase the page before programming */
-		if (erase_block_jedec(flash, i * page_size, page_size)) {
-			fprintf(stderr, "ERASE FAILED!\n");
-			return -1;
-		}
-
-		/* write to the sector */
-		printf("%04d at address: 0x%08x", i, i * page_size);
-		write_sector_jedec(bios, buf + i * page_size,
-				   bios + i * page_size, page_size);
-		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-		fflush(stdout);
-	}
-	printf("\n");
-
-	/* protected */
-	write_lockbits_49fl00x(flash->virtual_registers, total_size, 1,
-			       page_size);
-
-	return 0;
-}
diff --git a/print.c b/print.c
deleted file mode 100644
index a2a6c63..0000000
--- a/print.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
- * Copyright (C) 2009 Carl-Daniel Hailfinger
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <string.h>
-#include <stdlib.h>
-#include "flash.h"
-#include "flashchips.h"
-
-/*
- * Return a string corresponding to the bustype parameter.
- * Memory is obtained with malloc() and can be freed with free().
- */
-char *flashbuses_to_text(enum chipbustype bustype)
-{
-	char *ret = calloc(1, 1);
-	if (bustype == CHIP_BUSTYPE_UNKNOWN) {
-		ret = strcat_realloc(ret, "Unknown,");
-	/*
-	 * FIXME: Once all chipsets and flash chips have been updated, NONSPI
-	 * will cease to exist and should be eliminated here as well.
-	 */
-	} else if (bustype == CHIP_BUSTYPE_NONSPI) {
-		ret = strcat_realloc(ret, "Non-SPI,");
-	} else {
-		if (bustype & CHIP_BUSTYPE_PARALLEL)
-			ret = strcat_realloc(ret, "Parallel,");
-		if (bustype & CHIP_BUSTYPE_LPC)
-			ret = strcat_realloc(ret, "LPC,");
-		if (bustype & CHIP_BUSTYPE_FWH)
-			ret = strcat_realloc(ret, "FWH,");
-		if (bustype & CHIP_BUSTYPE_SPI)
-			ret = strcat_realloc(ret, "SPI,");
-		if (bustype == CHIP_BUSTYPE_NONE)
-			ret = strcat_realloc(ret, "None,");
-	}
-	/* Kill last comma. */
-	ret[strlen(ret) - 1] = '\0';
-	ret = realloc(ret, strlen(ret) + 1);
-	return ret;
-}
-
-#define POS_PRINT(x) do { pos += strlen(x); printf(x); } while (0)
-
-static int digits(int n)
-{
-	int i;
-
-	if (!n)
-		return 1;
-
-	for (i = 0; n; ++i)
-		n /= 10;
-
-	return i;
-}
-
-void print_supported_chips(void)
-{
-	int okcol = 0, pos = 0, i, chipcount = 0;
-	struct flashchip *f;
-
-	for (f = flashchips; f->name != NULL; f++) {
-		if (GENERIC_DEVICE_ID == f->model_id)
-			continue;
-		okcol = max(okcol, strlen(f->vendor) + 1 + strlen(f->name));
-	}
-	okcol = (okcol + 7) & ~7;
-
-	for (f = flashchips; f->name != NULL; f++)
-		chipcount++;
-
-	printf("\nSupported flash chips (total: %d):\n\n", chipcount);
-	POS_PRINT("Vendor:   Device:");
-	while (pos < okcol) {
-		printf("\t");
-		pos += 8 - (pos % 8);
-	}
-
-	printf("Tested OK:\tKnown BAD:  Size/KB:  Type:\n\n");
-	printf("(P = PROBE, R = READ, E = ERASE, W = WRITE)\n\n");
-
-	for (f = flashchips; f->name != NULL; f++) {
-		/* Don't print "unknown XXXX SPI chip" entries. */
-		if (!strncmp(f->name, "unknown", 7))
-			continue;
-
-		printf("%s", f->vendor);
-		for (i = 0; i < 10 - strlen(f->vendor); i++)
-			printf(" ");
-		printf("%s", f->name);
-
-		pos = 10 + strlen(f->name);
-		while (pos < okcol) {
-			printf("\t");
-			pos += 8 - (pos % 8);
-		}
-		if ((f->tested & TEST_OK_MASK)) {
-			if ((f->tested & TEST_OK_PROBE))
-				POS_PRINT("P ");
-			if ((f->tested & TEST_OK_READ))
-				POS_PRINT("R ");
-			if ((f->tested & TEST_OK_ERASE))
-				POS_PRINT("E ");
-			if ((f->tested & TEST_OK_WRITE))
-				POS_PRINT("W ");
-		}
-		while (pos < okcol + 9) {
-			printf("\t");
-			pos += 8 - (pos % 8);
-		}
-		if ((f->tested & TEST_BAD_MASK)) {
-			if ((f->tested & TEST_BAD_PROBE))
-				printf("P ");
-			if ((f->tested & TEST_BAD_READ))
-				printf("R ");
-			if ((f->tested & TEST_BAD_ERASE))
-				printf("E ");
-			if ((f->tested & TEST_BAD_WRITE))
-				printf("W ");
-		}
-
-		printf("\t    %d", f->total_size);
-		for (i = 0; i < 10 - digits(f->total_size); i++)
-			printf(" ");
-		printf("%s\n", flashbuses_to_text(f->bustype));
-	}
-}
-
-void print_supported_chipsets(void)
-{
-	int i, j, chipsetcount = 0;
-	const struct penable *c = chipset_enables;
-
-	for (i = 0; c[i].vendor_name != NULL; i++)
-		chipsetcount++;
-
-	printf("\nSupported chipsets (total: %d):\n\nVendor:                  "
-	       "Chipset:                 PCI IDs:\n\n", chipsetcount);
-
-	for (i = 0; c[i].vendor_name != NULL; i++) {
-		printf("%s", c[i].vendor_name);
-		for (j = 0; j < 25 - strlen(c[i].vendor_name); j++)
-			printf(" ");
-		printf("%s", c[i].device_name);
-		for (j = 0; j < 25 - strlen(c[i].device_name); j++)
-			printf(" ");
-		printf("%04x:%04x%s\n", c[i].vendor_id, c[i].device_id,
-		       (c[i].status == OK) ? "" : " (untested)");
-	}
-}
-
-void print_supported_boards_helper(const struct board_info *b, const char *msg)
-{
-	int i, j, boardcount = 0;
-
-	for (i = 0; b[i].vendor != NULL; i++)
-		boardcount++;
-
-	printf("\n%s (total: %d):\n\n", msg, boardcount);
-
-	for (i = 0; b[i].vendor != NULL; i++) {
-		printf("%s", b[i].vendor);
-		for (j = 0; j < 25 - strlen(b[i].vendor); j++)
-			printf(" ");
-		printf("%s", b[i].name);
-		for (j = 0; j < 28 - strlen(b[i].name); j++)
-			printf(" ");
-		printf("\n");
-	}
-}
-
-void print_supported_boards(void)
-{
-	int i, j, boardcount = 0;
-	struct board_pciid_enable *b = board_pciid_enables;
-
-	for (i = 0; b[i].vendor_name != NULL; i++)
-		boardcount++;
-
-	printf("\nSupported boards which need write-enable code (total: %d):"
-	       "\n\nVendor:                  Board:                        "
-	       "Required option:\n\n", boardcount);
-
-	for (i = 0; b[i].vendor_name != NULL; i++) {
-		printf("%s", b[i].vendor_name);
-		for (j = 0; j < 25 - strlen(b[i].vendor_name); j++)
-			printf(" ");
-		printf("%s", b[i].board_name);
-		for (j = 0; j < 30 - strlen(b[i].board_name); j++)
-			printf(" ");
-		if (b[i].lb_vendor != NULL)
-			printf("-m %s:%s\n", b[i].lb_vendor, b[i].lb_part);
-		else
-			printf("(none, board is autodetected)\n");
-	}
-
-	print_supported_boards_helper(boards_ok,
-		"Supported boards which don't need write-enable code");
-	print_supported_boards_helper(boards_bad,
-		"Boards which have been verified to NOT work yet");
-	print_supported_boards_helper(laptops_ok,
-		"Laptops which have been verified to work");
-	print_supported_boards_helper(laptops_bad,
-		"Laptops which have been verified to NOT work yet");
-}
-
-void print_supported(void)
-{
-		print_supported_chips();
-		print_supported_chipsets();
-		print_supported_boards();
-		printf("\nSupported PCI devices flashrom can use "
-		       "as programmer:\n\n");
-#if NIC3COM_SUPPORT == 1
-		print_supported_pcidevs(nics_3com);
-#endif
-#if GFXNVIDIA_SUPPORT == 1
-		print_supported_pcidevs(gfx_nvidia);
-#endif
-#if DRKAISER_SUPPORT == 1
-		print_supported_pcidevs(drkaiser_pcidev);
-#endif
-#if SATASII_SUPPORT == 1
-		print_supported_pcidevs(satas_sii);
-#endif
-}
-
-
-/* Please keep this list alphabetically ordered by vendor/board. */
-const struct board_info boards_ok[] = {
-	/* Verified working boards that don't need write-enables. */
-	{ "Abit",		"AX8", },
-	{ "Abit",		"Fatal1ty F-I90HD", },
-	{ "Advantech",		"PCM-5820", },
-	{ "ASI",		"MB-5BLMP", },
-	{ "ASRock",		"A770CrossFire", },
-	{ "ASRock",		"K8S8X", },
-	{ "ASUS",		"A7N8X Deluxe", },
-	{ "ASUS",		"A7N8X-E Deluxe", },
-	{ "ASUS",		"A7V400-MX", },
-	{ "ASUS",		"A7V8X-MX", },
-	{ "ASUS",		"A8N-E", },
-	{ "ASUS",		"A8NE-FM/S", },
-	{ "ASUS",		"A8N-SLI", },
-	{ "ASUS",		"A8N-SLI Premium", },
-	{ "ASUS",		"A8V Deluxe", },
-	{ "ASUS",		"A8V-E Deluxe", },
-	{ "ASUS",		"A8V-E SE", },
-	{ "ASUS",		"K8V", },
-	{ "ASUS",		"K8V SE Deluxe", },
-	{ "ASUS",		"K8V-X SE", },
-	{ "ASUS",		"M2A-MX", },
-	{ "ASUS",		"M2A-VM", },
-	{ "ASUS",		"M2N-E", },
-	{ "ASUS",		"M2V", },
-	{ "ASUS",		"M3A78-EM", },
-	{ "ASUS",		"P2B", },
-	{ "ASUS",		"P2B-D", },
-	{ "ASUS",		"P2B-DS", },
-	{ "ASUS",		"P2B-F", },
-	{ "ASUS",		"P2L97-S", },
-	{ "ASUS",		"P5B-Deluxe", },
-	{ "ASUS",		"P5KC", },
-	{ "ASUS",		"P5L-MX", },
-	{ "ASUS",		"P6T Deluxe V2", },
-	{ "A-Trend",		"ATC-6220", },
-	{ "BCOM",		"WinNET100", },
-	{ "DFI",		"Blood-Iron P35 T2RL", },
-	{ "Elitegroup",		"K7S5A", },
-	{ "Elitegroup",		"P6VAP-A+", },
-	{ "GIGABYTE",		"GA-6BXC", },
-	{ "GIGABYTE",		"GA-6BXDU", },
-	{ "GIGABYTE",		"GA-6ZMA", },
-	{ "GIGABYTE",		"GA-7ZM", },
-	{ "GIGABYTE",		"GA-EP35-DS3L", },
-	{ "GIGABYTE",		"GA-EX58-UD4P", },
-	{ "GIGABYTE",		"GA-MA78GPM-DS2H", },
-	{ "GIGABYTE",		"GA-MA790GP-DS4H", },
-	{ "GIGABYTE",		"GA-MA770T-UD3P", },
-	{ "Intel",		"EP80759", },
-	{ "Jetway",		"J7F4K1G5D-PB", },
-	{ "MSI",                "MS-6153", },
-	{ "MSI",                "MS-6156", },
-	{ "MSI",		"MS-6570 (K7N2)", },
-	{ "MSI",		"MS-7065", },
-	{ "MSI",		"MS-7168 (Orion)", },
-	{ "MSI",		"MS-7236 (945PL Neo3)", },
-	{ "MSI",		"MS-7255 (P4M890M)", },
-	{ "MSI",		"MS-7345 (P35 Neo2-FIR)", },
-	{ "MSI",		"MS-7368 (K9AG Neo2-Digital)", },
-	{ "NEC",		"PowerMate 2000", },
-	{ "PC Engines",		"Alix.1c", },
-	{ "PC Engines",		"Alix.2c2", },
-	{ "PC Engines",		"Alix.2c3", },
-	{ "PC Engines",		"Alix.3c3", },
-	{ "PC Engines",		"Alix.3d3", },
-	{ "RCA",		"RM4100", },
-	{ "Sun",		"Blade x6250", },
-	{ "Supermicro",		"H8QC8", },
-	{ "Thomson",		"IP1000", },
-	{ "TriGem",		"Lomita", },
-	{ "T-Online",		"S-100", },
-	{ "Tyan",		"iS5375-1U", },
-	{ "Tyan",		"S1846", },
-	{ "Tyan",		"S2466", },
-	{ "Tyan",		"S2881", },
-	{ "Tyan",		"S2882", },
-	{ "Tyan",		"S2882-D", },
-	{ "Tyan",		"S2891", },
-	{ "Tyan",		"S2892", },
-	{ "Tyan",		"S2895", },
-	{ "Tyan",		"S3095", },
-	{ "Tyan",		"S5180", },
-	{ "Tyan",		"S5191", },
-	{ "Tyan",		"S5197", },
-	{ "Tyan",		"S5211", },
-	{ "Tyan",		"S5211-1U", },
-	{ "Tyan",		"S5220", },
-	{ "Tyan",		"S5375", },
-	{ "Tyan",		"S5376G2NR/S5376WAG2NR", },
-	{ "Tyan",		"S5377", },
-	{ "Tyan",		"S5397", },
-	{ "VIA",		"EPIA-EX15000G", },
-	{ "VIA",		"EPIA-LN", },
-	{ "VIA",		"EPIA-M700", },
-	{ "VIA",		"EPIA-NX15000G", },
-	{ "VIA",		"NAB74X0", },
-	{ "VIA",		"pc2500e", },
-	{ "VIA",		"VB700X", },
-
-	{},
-};
-
-/* Please keep this list alphabetically ordered by vendor/board. */
-const struct board_info boards_bad[] = {
-	/* Verified non-working boards (for now). */
-	{ "Abit",		"IS-10", },
-	{ "ASRock",		"K7VT4A+", },
-	{ "ASUS",		"MEW-AM", },
-	{ "ASUS",		"MEW-VM", },
-	{ "ASUS",		"P3B-F", },
-	{ "ASUS",		"P5B", },
-	{ "ASUS",		"P5BV-M", },
-	{ "Biostar",		"M6TBA", },
-	{ "Boser",		"HS-6637", },
-	{ "DFI",		"855GME-MGF", },
-	{ "FIC",		"VA-502", },
-	{ "MSI",		"MS-6178", },
-	{ "MSI",		"MS-7260 (K9N Neo)", },
-	{ "Soyo",		"SY-5VD", },
-	{ "Sun",		"Fire x4150", },
-	{ "Sun",		"Fire x4200", },
-	{ "Sun",		"Fire x4540", },
-	{ "Sun",		"Fire x4600", },
-
-	{},
-};
-
-/* Please keep this list alphabetically ordered by vendor/board. */
-const struct board_info laptops_ok[] = {
-	/* Verified working laptops. */
-	{ "Lenovo",		"3000 V100 TF05Cxx", },
-
-	{},
-};
-
-/* Please keep this list alphabetically ordered by vendor/board. */
-const struct board_info laptops_bad[] = {
-	/* Verified non-working laptops (for now). */
-	{ "Acer",		"Aspire One", },
-	{ "ASUS",		"Eee PC 701 4G", },
-	{ "Dell",		"Latitude CPi A366XT", },
-	{ "HP/Compaq",		"nx9010", },
-	{ "IBM/Lenovo",		"Thinkpad T40p", },
-	{ "IBM/Lenovo",		"240", },
-
-	{},
-};
-
diff --git a/print_wiki.c b/print_wiki.c
deleted file mode 100644
index ce41ad4..0000000
--- a/print_wiki.c
+++ /dev/null
@@ -1,569 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
- * Copyright (C) 2009 Carl-Daniel Hailfinger
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <string.h>
-#include <stdlib.h>
-#include <time.h>
-#include "flash.h"
-#include "flashchips.h"
-
-struct board_info_url {
-	const char *vendor;
-	const char *name;
-	const char *url;
-};
-
-struct board_info_notes {
-	const char *vendor;
-	const char *name;
-	const char *note;
-};
-
-const char *wiki_header = "= Supported devices =\n\n\
-<div style=\"margin-top:0.5em; padding:0.5em 0.5em 0.5em 0.5em; \
-background-color:#eeeeee; align:right; border:1px solid #aabbcc;\"><small>\n\
-Please do '''not''' edit these tables in the wiki directly, they are \
-generated by pasting '''flashrom -z''' output.<br />\
-'''Last update:''' %s(generated by flashrom %s)\n</small></div>\n";
-
-const char *chipset_th = "{| border=\"0\" style=\"font-size: smaller\"\n\
-|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\
-! align=\"left\" | Southbridge\n! align=\"left\" | PCI IDs\n\
-! align=\"left\" | Status\n\n";
-
-const char *board_th = "{| border=\"0\" style=\"font-size: smaller\" \
-valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\
-! align=\"left\" | Mainboard\n! align=\"left\" | Status\n\n";
-
-const char *board_th2 = "{| border=\"0\" style=\"font-size: smaller\" \
-valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\
-! align=\"left\" | Mainboard\n! align=\"left\" | Required option\n\
-! align=\"left\" | Status\n\n";
-
-const char *board_intro = "\
-\n== Supported mainboards ==\n\n\
-In general, it is very likely that flashrom works out of the box even if your \
-mainboard is not listed below.\n\nThis is a list of mainboards where we have \
-verified that they either do or do not need any special initialization to \
-make flashrom work (given flashrom supports the respective chipset and flash \
-chip), or that they do not yet work at all. If they do not work, support may \
-or may not be added later.\n\n\
-Mainboards which don't appear in the list may or may not work (we don't \
-know, someone has to give it a try). Please report any further verified \
-mainboards on the [[Mailinglist|mailing list]].\n";
-
-const char *chip_th = "{| border=\"0\" style=\"font-size: smaller\" \
-valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\
-! align=\"left\" | Device\n! align=\"left\" | Size / KB\n\
-! align=\"left\" | Type\n! align=\"left\" colspan=\"4\" | Status\n\n\
-|- bgcolor=\"#6699ff\"\n| colspan=\"4\" | &nbsp;\n\
-| Probe\n| Read\n| Write\n| Erase\n\n";
-
-const char *programmer_section = "\
-\n== Supported programmers ==\n\nThis is a list \
-of supported PCI devices flashrom can use as programmer:\n\n{| border=\"0\" \
-valign=\"top\"\n| valign=\"top\"|\n\n{| border=\"0\" style=\"font-size: \
-smaller\" valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\
-! align=\"left\" | Device\n! align=\"left\" | PCI IDs\n\
-! align=\"left\" | Status\n\n";
-
-const char *laptop_intro = "\n== Supported laptops/notebooks ==\n\n\
-In general, flashing laptops is more difficult because laptops\n\n\
-* often use the flash chip for stuff besides the BIOS,\n\
-* often have special protection stuff which has to be handled by flashrom,\n\
-* often use flash translation circuits which need drivers in flashrom.\n\n\
-<div style=\"margin-top:0.5em; padding:0.5em 0.5em 0.5em 0.5em; \
-background-color:#ff6666; align:right; border:1px solid #000000;\">\n\
-'''IMPORTANT:''' At this point we recommend to '''not''' use flashrom on \
-untested laptops unless you have a means to recover from a flashing that goes \
-wrong (a working backup flash chip and/or good soldering skills).\n</div>\n";
-
-/* Please keep these lists alphabetically ordered by vendor/board. */
-const struct board_info_url boards_url[] = {
-	/* Verified working boards that don't need write-enables. */
-	{ "Abit",		"AX8",			"http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?DEFTITLE=Y&fMTYPE=Socket%20939&pMODEL_NAME=AX8" },
-	{ "Abit",		"Fatal1ty F-I90HD",	"http://www.abit.com.tw/page/de/motherboard/motherboard_detail.php?pMODEL_NAME=Fatal1ty+F-I90HD&fMTYPE=LGA775" },
-	{ "Advantech",		"PCM-5820", 		"http://www.emacinc.com/sbc_pc_compatible/pcm_5820.htm" },
-	{ "ASI",		"MB-5BLMP",		"http://www.hojerteknik.com/winnet.htm" },
-	{ "ASRock",		"A770CrossFire",	"http://www.asrock.com/mb/overview.asp?Model=A770CrossFire&s=AM2\%2b" },
-	{ "ASRock",		"K8S8X",		"http://www.asrock.com/mb/overview.asp?Model=K8S8X" },
-	{ "ASUS",		"A7N8X Deluxe",		"http://www.asus.com/Product.aspx?P_ID=wAsRYm41KTp78MFC" },
-	{ "ASUS",		"A7N8X-E Deluxe",	"http://www.asus.com/products.aspx?l1=3&l2=13&l3=56&l4=0&model=217&modelmenu=1" },
-	{ "ASUS",		"A7V400-MX",		"http://www.asus.com.tw/products.aspx?l1=3&l2=13&l3=63&l4=0&model=228&modelmenu=1" },
-	{ "ASUS",		"A7V8X-MX",		"http://www.asus.com.tw/products.aspx?l1=3&l2=13&l3=64&l4=0&model=229&modelmenu=1" },
-	{ "ASUS",		"A8N-E",		"http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=171&l4=0&model=455&modelmenu=2" },
-	{ "ASUS",		"A8NE-FM/S",		"http://www.hardwareschotte.de/hardware/preise/proid_1266090/preis_ASUS+A8NE-FM" },
-	{ "ASUS",		"A8N-SLI",		"http://asus.com/product.aspx?P_ID=J9FKa8z2xVId3pDK" },
-	{ "ASUS",		"A8N-SLI Premium",	"http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=148&l4=0&model=539&modelmenu=1" },
-	{ "ASUS",		"A8V Deluxe",		"http://www.asus.com/product.aspx?P_ID=tvpdgPNCPaABZRVU" },
-	{ "ASUS",		"A8V-E Deluxe",		"http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=143&l4=0&model=376&modelmenu=1" },
-	{ "ASUS",		"A8V-E SE",		"http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=143&l4=0&model=576&modelmenu=1" },
-	{ "ASUS",		"K8V",			"http://www.asus.com/product.aspx?P_ID=fG2KZOWF7v6MRFRm" },
-	{ "ASUS",		"K8V SE Deluxe",	"http://www.asus.com/product.aspx?P_ID=65HeDI8XM1u6Uy6o" },
-	{ "ASUS",		"K8V-X SE",		"http://asus.com/product.aspx?P_ID=lzDXlbBVHkdckHVr" },
-	{ "ASUS",		"M2A-MX",		"http://www.asus.com/products.aspx?l1=3&l2=101&l3=583&l4=0&model=1909&modelmenu=1" },
-	{ "ASUS",		"M2A-VM",		"http://www.asus.com.tw/products.aspx?l1=3&l2=101&l3=496&l4=0&model=1568&modelmenu=1" },
-	{ "ASUS",		"M2N-E",		"http://www.asus.com/products.aspx?l1=3&l2=101&l3=308&l4=0&model=1181&modelmenu=1" },
-	{ "ASUS",		"M2V",			"http://asus.com/Product.aspx?P_ID=OqYlEDFfF6ZqZGvp" },
-	{ "ASUS",		"M3A78-EM",		"http://www.asus.com/product.aspx?P_ID=KjpYqzmAd9vsTM2D" },
-	{ "ASUS",		"P2B",			"http://www.motherboard.cz/mb/asus/P2B.htm" },
-	{ "ASUS",		"P2B-D",		"ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-d/" },
-	{ "ASUS",		"P2B-DS",		"ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-ds/" },
-	{ "ASUS",		"P2B-F",		"http://www.motherboard.cz/mb/asus/P2B-F.htm" },
-	{ "ASUS",		"P2L97-S",		"http://www.motherboard.cz/mb/asus/P2L97-S.htm" },
-	{ "ASUS",		"P5B-Deluxe",		"ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B-Deluxe/" },
-	{ "ASUS",		"P5KC",			"http://www.asus.com/product.aspx?P_ID=fFZ8oUIGmLpwNMjj" },
-	{ "ASUS",		"P5L-MX",		"http://www.asus.com/product.aspx?P_ID=X70d3NCzH2DE9vWH" },
-	{ "ASUS",		"P6T Deluxe V2",	"http://www.asus.com/product.aspx?P_ID=iRlP8RG9han6saZx" },
-	{ "A-Trend",		"ATC-6220",		"http://www.motherboard.cz/mb/atrend/atc6220.htm" },
-	{ "BCOM",		"WinNET100",		"http://www.coreboot.org/BCOM_WINNET100" },
-	{ "DFI",		"Blood-Iron P35 T2RL",	"http://lp.lanparty.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?itemId=516&downloadFlag=false&action=1" },
-	{ "Elitegroup",		"K7S5A",		"http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=279&CategoryID=1&DetailName=Specification&MenuID=1&LanID=0" },
-	{ "Elitegroup",		"P6VAP-A+",		"http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=117&CategoryID=1&DetailName=Specification&MenuID=1&LanID=0" },
-	{ "GIGABYTE",		"GA-6BXC",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ClassValue=Motherboard&ProductID=1445&ProductName=GA-6BXC" },
-	{ "GIGABYTE",		"GA-6BXDU",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1429" },
-	{ "GIGABYTE",		"GA-6ZMA",		"http://www.gigabyte.de/Support/Motherboard/BIOS_Model.aspx?ProductID=3289" },
-	{ "GIGABYTE",		"GA-EX58-UD4P",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Overview.aspx?ProductID=2986" },
-	{ "GIGABYTE",		"GA-EP35-DS3L",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Overview.aspx?ProductID=2778" },
-	{ "GIGABYTE",		"GA-MA790GP-DS4H",	"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2887" },
-	{ "GIGABYTE",		"GA-MA78GPM-DS2H",	"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2859" },
-	{ "GIGABYTE",		"GA-MA770T-UD3P",	"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=3096" },
-	{ "Intel",		"EP80759",		NULL },
-	{ "Jetway",		"J7F4K1G5D-PB",		"http://www.jetway.com.tw/jetway/system/productshow2.asp?id=389&proname=J7F4K1G5D-P" },
-	{ "MSI",		"MS-6153",		"http://www.msi.com/index.php?func=proddesc&maincat_no=1&cat2_no=&cat3_no=&prod_no=336" },
-	{ "MSI",		"MS-6156",		"http://uk.ts.fujitsu.com/rl/servicesupport/techsupport/boards/Motherboards/MicroStar/Ms6156/MS6156.htm" },
-	{ "MSI",		"MS-6570 (K7N2)",	"http://www.msi-computer.de/index.php?func=proddesc&prod_no=519&maincat_no=1" },
-	{ "MSI",		"MS-7065",		"http://browse.geekbench.ca/geekbench2/view/53114" },
-	{ "MSI",		"MS-7168 (Orion)",	"http://support.packardbell.co.uk/uk/item/index.php?i=spec_orion&pi=platform_honeymoon_istart" },
-	{ "MSI",		"MS-7236 (945PL Neo3)",	"http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=1173" },
-	{ "MSI",		"MS-7255 (P4M890M)",	"http://www.tcsbahamas.com/P4M89.htm" },
-	{ "MSI",		"MS-7345 (P35 Neo2-FIR)","http://www.msi.com/index.php?func=prodcpusupport&maincat_no=1&cat2_no=170&cat3_no=&prod_no=1261" },
-	{ "MSI",		"MS-7368 (K9AG Neo2-Digital)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=1241" },
-	{ "NEC",		"PowerMate 2000",	"http://support.necam.com/mobilesolutions/hardware/Desktops/pm2000/celeron/" },
-	{ "PC Engines",		"Alix.1c",		"http://pcengines.ch/alix1c.htm" },
-	{ "PC Engines",		"Alix.2c2",		"http://pcengines.ch/alix2c2.htm" },
-	{ "PC Engines",		"Alix.2c3",		"http://pcengines.ch/alix2c3.htm" },
-	{ "PC Engines",		"Alix.3c3",		"http://pcengines.ch/alix3c3.htm" },
-	{ "PC Engines",		"Alix.3d3",		"http://pcengines.ch/alix3d3.htm" },
-	{ "RCA",		"RM4100",		"http://www.settoplinux.org/index.php?title=RCA_RM4100" },
-	{ "Sun",		"Blade x6250",		"http://www.sun.com/servers/blades/x6250/" },
-	{ "Supermicro",		"H8QC8",		"http://www.supermicro.com/Aplus/motherboard/Opteron/nforce/H8QC8.cfm" },
-	{ "Thomson",		"IP1000",		"http://www.settoplinux.org/index.php?title=Thomson_IP1000" },
-	{ "TriGem",		"Lomita",		"http://www.e4allupgraders.info/dir1/motherboards/socket370/lomita.shtml" },
-	{ "T-Online",		"S-100",		"http://wiki.freifunk-hannover.de/T-Online_S_100" },
-	{ "Tyan",		"iS5375-1U",		"http://www.tyan.com/product_board_detail.aspx?pid=610" },
-	{ "Tyan",		"S1846",		"http://www.tyan.com/archive/products/html/tsunamiatx.html" },
-	{ "Tyan",		"S2466",		"http://www.tyan.com/product_board_detail.aspx?pid=461" },
-	{ "Tyan",		"S2881",		"http://www.tyan.com/product_board_detail.aspx?pid=115" },
-	{ "Tyan",		"S2882",		"http://www.tyan.com/product_board_detail.aspx?pid=121" },
-	{ "Tyan",		"S2882-D",		"http://www.tyan.com/product_board_detail.aspx?pid=127" },
-	{ "Tyan",		"S2891",		"http://www.tyan.com/product_board_detail.aspx?pid=144" },
-	{ "Tyan",		"S2892",		"http://www.tyan.com/product_board_detail.aspx?pid=145" },
-	{ "Tyan",		"S2895",		"http://www.tyan.com/archive/products/html/thunderk8we.html" },
-	{ "Tyan",		"S3095",		"http://www.tyan.com/product_board_detail.aspx?pid=181" },
-	{ "Tyan",		"S5180",		"http://www.tyan.com/product_board_detail.aspx?pid=456" },
-	{ "Tyan",		"S5191",		"http://www.tyan.com/product_board_detail.aspx?pid=343" },
-	{ "Tyan",		"S5197",		"http://www.tyan.com/product_board_detail.aspx?pid=349" },
-	{ "Tyan",		"S5211",		"http://www.tyan.com/product_board_detail.aspx?pid=591" },
-	{ "Tyan",		"S5211-1U",		"http://www.tyan.com/product_board_detail.aspx?pid=593" },
-	{ "Tyan",		"S5220",		"http://www.tyan.com/product_board_detail.aspx?pid=597" },
-	{ "Tyan",		"S5375",		"http://www.tyan.com/product_board_detail.aspx?pid=566" },
-	{ "Tyan",		"S5376G2NR/S5376WAG2NR","http://www.tyan.com/product_board_detail.aspx?pid=605" },
-	{ "Tyan",		"S5377",		"http://www.tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=642&SKU=600000017" },
-	{ "Tyan",		"S5397",		"http://www.tyan.com/product_board_detail.aspx?pid=560" },
-	{ "VIA",		"EPIA-EX15000G",	"http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=450" },
-	{ "VIA",		"EPIA-LN",		"http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=473" },
-	{ "VIA",		"EPIA-M700",		"http://via.com.tw/servlet/downloadSvl?motherboard_id=670&download_file_id=3700" },
-	{ "VIA",		"EPIA-NX15000G",	"http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=470" },
-	{ "VIA",		"NAB74X0",		"http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=590" },
-	{ "VIA",		"pc2500e",		"http://www.via.com.tw/en/initiatives/empowered/pc2500_mainboard/index.jsp" },
-	{ "VIA",		"VB700X",		"http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=490" },
-
-	/* Verified working boards that DO need write-enables. */
-	{ "Abit",		"IP35",			"http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?fMTYPE=LGA775&pMODEL_NAME=IP35" },
-	{ "Acorp",		"6A815EPD",		"http://web.archive.org/web/20021206163652/www.acorp.com.tw/English/default.asp" },
-	{ "agami",		"Aruma",		"http://web.archive.org/web/20080212111524/http://www.agami.com/site/ais-6000-series" },
-	{ "Albatron",		"PM266A Pro",		"http://www.albatron.com.tw/English/Product/MB/pro_detail.asp?rlink=Overview&no=56" }, /* FIXME */
-	{ "AOpen",		"vKM400Am-S",		"http://usa.aopen.com/products_detail.aspx?Auno=824" },
-	{ "Artec Group",	"DBE61",		"http://wiki.thincan.org/DBE61" },
-	{ "Artec Group",	"DBE62",		"http://wiki.thincan.org/DBE62" },
-	{ "ASUS",		"A7V600-X",		"http://www.asus.com/product.aspx?P_ID=L2XYS0rmtCjeOr4k" },
-	{ "ASUS",		"A7V8X",		"http://www.asus.com/product.aspx?P_ID=qfpaGrAy2kLVo0f2" },
-	{ "ASUS",		"A7V8X-MX SE",		"http://www.asus.com/product.aspx?P_ID=1guVBT1qV5oqhHyZ" },
-	{ "ASUS",		"P4B266",		"http://www.ciao.co.uk/ASUS_Intel_845D_Chipset_P4B266__5409807#productdetail" },
-	{ "ASUS",		"P4P800-E Deluxe",	"http://www.asus.com/product.aspx?P_ID=INIJUvLlif7LHp3g" },
-	{ "ASUS",		"P5ND2-SLI Deluxe",	"http://www.asus.com/product.aspx?P_ID=WY7XroDuUImVbgp5" },
-	{ "ASUS",		"P5A",			"ftp://ftp.asus.com.tw/pub/ASUS/mb/sock7/ali/p5a/" },
-	{ "Biostar",		"P4M80-M4",		"http://www.biostar-usa.com/mbdetails.asp?model=p4m80-m4" },
-	{ "Dell",		"PowerEdge 1850",	"http://support.dell.com/support/edocs/systems/pe1850/en/index.htm" },
-	{ "Elitegroup",		"K7VTA3",		"http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=264&CategoryID=1&DetailName=Specification&MenuID=52&LanID=0" },
-	{ "EPoX",		"EP-8K5A2",		"http://www.epox.com/product.asp?ID=EP-8K5A2" },
-	{ "EPoX",		"EP-8RDA3+",		"http://www.epox.com/product.asp?ID=EP-8RDA3plus" },
-	{ "EPoX",		"EP-BX3",		"http://www.epox.com/product.asp?ID=EP-BX3" },
-	{ "GIGABYTE",		"GA-2761GXDK",		"http://www.computerbase.de/news/hardware/mainboards/amd-systeme/2007/mai/gigabyte_dtx-mainboard/" },
-	{ "GIGABYTE",		"GA-7VT600",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1666" },
-	{ "GIGABYTE",		"GA-7ZM",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1366" },
-	{ "GIGABYTE",		"GA-K8N-SLI",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1928" },
-	{ "GIGABYTE",		"GA-M57SLI-S4",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Overview.aspx?ProductID=2287&ModelName=GA-M57SLI-S4" },
-	{ "GIGABYTE",		"GA-M61P-S3",		"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2434" },
-	{ "GIGABYTE",		"GA-MA78G-DS3H",	"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2800" }, /* TODO: Rev 1.x or 2.x? */
-	{ "GIGABYTE",		"GA-MA78GM-S2H",	"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2758" }, /* TODO: Rev. 1.0, 1.1, or 2.x? */
-	{ "GIGABYTE",		"GA-MA790FX-DQ6",	"http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2690" },
-	{ "HP",			"DL145 G3",		"http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00816835&lang=en&cc=us&taskId=101&prodSeriesId=3219755&prodTypeId=15351" },
-	{ "IBM",		"x3455",		"http://www-03.ibm.com/systems/x/hardware/rack/x3455/index.html" },
-	{ "Intel",		"D201GLY",		"http://www.intel.com/support/motherboards/desktop/d201gly/index.htm" },
-	{ "IWILL",		"DK8-HTX",		"http://web.archive.org/web/20060507170150/http://www.iwill.net/product_2.asp?p_id=98" },
-	{ "Kontron",		"986LCD-M",		"http://de.kontron.com/products/boards+and+mezzanines/embedded+motherboards/miniitx+motherboards/986lcdmmitx.html" },
-	{ "Mitac",		"6513WU",		"http://web.archive.org/web/20050313054828/http://www.mitac.com/micweb/products/tyan/6513wu/6513wu.htm" },
-	{ "MSI",		"MS-6590 (KT4 Ultra)",	"http://www.msicomputer.com/product/p_spec.asp?model=KT4_Ultra&class=mb" },
-	{ "MSI",		"MS-6702E (K8T Neo2-F)","http://www.msicomputer.com/product/p_spec.asp?model=K8T_Neo2-F&class=mb" },
-	{ "MSI",		"MS-6712 (KT4V)",	"http://www.msi.com/index.php?func=proddesc&maincat_no=1&cat2_no=&cat3_no=&prod_no=505" },
-	{ "MSI",		"MS-7046",		"http://www.heimir.de/ms7046/" },
-	{ "MSI",		"MS-7135 (K8N Neo3)",	"http://www.msi-computer.de/index.php?func=proddesc&prod_no=170&maincat_no=1" },
-	{ "Shuttle",		"AK38N",		"http://eu.shuttle.com/en/desktopdefault.aspx/tabid-36/558_read-9889/" },
-	{ "Soyo",		"SY-7VCA",		"http://www.tomshardware.com/reviews/12-socket-370-motherboards,196-15.html" },
-	{ "Tyan",		"S2498 (Tomcat K7M)",	"http://www.tyan.com/archive/products/html/tomcatk7m.html" },
-	{ "VIA",		"EPIA-CN",		"http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=400" },
-	{ "VIA",		"EPIA M/MII/...",	"http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=202" }, /* EPIA-MII link for now */
-	{ "VIA",		"EPIA-N/NL",		"http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=221" }, /* EPIA-N link for now */
-	{ "VIA",		"EPIA SP",		"http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=261" },
-	{ "VIA",		"PC3500G",		"http://www.via.com.tw/en/initiatives/empowered/pc3500_mainboard/index.jsp" },
- 
-	/* Verified non-working boards (for now). */
-	{ "Abit",		"IS-10",		"http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?pMODEL_NAME=IS-10&fMTYPE=Socket+478" },
-	{ "ASRock",		"K7VT4A+",		"http://www.asrock.com/mb/overview.asp?Model=K7VT4A%%2b&s=" },
-	{ "ASUS",		"MEW-AM",		"ftp://ftp.asus.com.tw/pub/ASUS/mb/sock370/810/mew-am/" },
-	{ "ASUS",		"MEW-VM",		"http://www.elhvb.com/mboards/OEM/HP/manual/ASUS%20MEW-VM.htm" },
-	{ "ASUS",		"P3B-F",		"ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p3b-f/" },
-	{ "ASUS",		"P5B",			"ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B/" },
-	{ "ASUS",		"P5BV-M",		"ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B-VM/" },
-	{ "Biostar",		"M6TBA",		"ftp://ftp.biostar-usa.com/manuals/M6TBA/" },
-	{ "Boser",		"HS-6637",		"http://www.boser.com.tw/manual/HS-62376637v3.4.pdf" },
-	{ "DFI",		"855GME-MGF",		"http://www.dfi.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?action=e&downloadType=&windowstate=normal&mode=view&downloadFlag=false&itemId=433" },
-	{ "FIC",		"VA-502",		"ftp://ftp.fic.com.tw/motherboard/manual/socket7/va-502/" },
-	{ "MSI",		"MS-6178",		"http://www.msi-technology.de/index.php?func=proddesc&prod_no=343&maincat_no=1" },
-	{ "MSI",		"MS-7260 (K9N Neo)",	"http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=255" },
-	{ "Soyo",		"SY-5VD",		"http://www.soyo.com/content/Downloads/163/&c=80&p=464&l=English" },
-	{ "Sun",		"Fire x4540",		"http://www.sun.com/servers/x64/x4540/" },
-	{ "Sun",		"Fire x4150",		"http://www.sun.com/servers/x64/x4150/" },
-	{ "Sun",		"Fire x4200",		"http://www.sun.com/servers/entry/x4200/" },
-	{ "Sun",		"Fire x4600",		"http://www.sun.com/servers/x64/x4600/" },
-
-	/* Verified working laptops. */
-	{ "Lenovo",		"3000 V100 TF05Cxx",	"http://www5.pc.ibm.com/europe/products.nsf/products?openagent&brand=Lenovo3000Notebook&series=Lenovo+3000+V+Series#viewallmodelstop" },
-
-	/* Verified non-working laptops (for now). */
-	{ "Acer",		"Aspire One",		NULL },
-	{ "ASUS",		"Eee PC 701 4G",	"http://www.asus.com/product.aspx?P_ID=h6SPd3tEzLEsrEiS" },
-	{ "Dell",		"Latitude CPi A366XT",	"http://www.coreboot.org/Dell_Latitude_CPi_A366XT" },
-	{ "HP/Compaq",		"nx9010",		"http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?lang=en&cc=us&objectID=c00348514" },
-	{ "IBM/Lenovo",		"Thinkpad T40p",	"http://www.thinkwiki.org/wiki/Category:T40p" },
-	{ "IBM/Lenovo",		"240",			"http://www.stanford.edu/~bresnan//tp240.html" },
-
-	{ NULL,			NULL,			0 },
-};
-
-/* Please keep these lists alphabetically ordered by vendor/board. */
-const struct board_info_notes boards_notes[] = {
-	/* Verified working boards that don't need write-enables. */
-	{ "ASI",		"MB-5BLMP",		"Used in the IGEL WinNET III thin client." },
-	{ "ASRock",		"K8S8X",		"The Super I/O isn't found on this board. See http://www.flashrom.org/pipermail/flashrom/2009-November/000937.html." },
-	{ "ASUS",		"A8V-E SE",		"See http://www.coreboot.org/pipermail/coreboot/2007-October/026496.html." },
-	{ "ASUS",		"M2A-VM",		"See http://www.coreboot.org/pipermail/coreboot/2007-September/025281.html." },
-	{ "BCOM",		"WinNET100",		"Used in the IGEL-316 thin client." },
-	{ "GIGABYTE",		"GA-7ZM",		"Works fine if you remove jumper JP9 on the board and disable the flash protection BIOS option." },
-	{ "ASUS",		"M2N-E",		"If the machine doesn't come up again after flashing, try resetting the NVRAM(CMOS). The MAC address of the onboard network card will change to the value stored in the new image, so backup the old address first. See http://www.flashrom.org/pipermail/flashrom/2009-November/000879.html" },
-
-	/* Verified working boards that DO need write-enables. */
-	{ "Acer",		"Aspire One",		"See http://www.coreboot.org/pipermail/coreboot/2009-May/048041.html." },
-
-	/* Verified non-working boards (for now). */
-	{ "MSI",		"MS-6178",		"Immediately powers off if you try to hot-plug the chip. However, this does '''not''' happen if you use coreboot." },
-	{ "MSI",		"MS-7260 (K9N Neo)",	"Interestingly flashrom does not work when the vendor BIOS is booted, but it ''does'' work flawlessly when the machine is booted with coreboot." },
-
-	/* Verified working laptops. */
-	/* None which need comments, yet... */
-
-	/* Verified non-working laptops (for now). */
-	{ "Acer",		"Aspire One",		"http://www.coreboot.org/pipermail/coreboot/2009-May/048041.html" },
-	{ "ASUS",		"Eee PC 701 4G",	"It seems the chip (25X40VSIG) is behind some SPI flash translation layer (likely in the EC, the ENE KB3310)." },
-	{ "Dell",		"Latitude CPi A366XT",	"The laptop immediately powers off if you try to hot-swap the chip. It's not yet tested if write/erase would work on this laptop." },
-	{ "HP/Compaq",		"nx9010",		"Hangs upon '''flashrom -V''' (needs hard power-cycle then)." },
-	{ "IBM/Lenovo",		"Thinkpad T40p",	"Seems to (partially) work at first, but one block/sector cannot be written which then leaves you with a bricked laptop. Maybe this can be investigated and fixed in software later." },
-
-	{ NULL,			NULL,			0 },
-};
-
-static int url(const char *vendor, const char *board)
-{
-	int i;
-	const struct board_info_url *b = boards_url;
-
-        for (i = 0; b[i].vendor != NULL; i++) {
-		if (!strcmp(vendor, b[i].vendor) && !strcmp(board, b[i].name))
-			return i;
-	}
-
-	return -1;
-}
-
-static int note(const char *vendor, const char *board)
-{
-	int i;
-	const struct board_info_notes *n = boards_notes;
-
-        for (i = 0; n[i].vendor != NULL; i++) {
-		if (!strcmp(vendor, n[i].vendor) && !strcmp(board, n[i].name))
-			return i;
-	}
-
-	return -1;
-}
-
-void print_supported_chipsets_wiki(void)
-{
-	int i, j, enablescount = 0, color = 1;
-	const struct penable *e;
-
-	for (e = chipset_enables; e->vendor_name != NULL; e++)
-		enablescount++;
-
-	printf("\n== Supported chipsets ==\n\nTotal amount of supported "
-	       "chipsets: '''%d'''\n\n{| border=\"0\" valign=\"top\"\n| "
-	       "valign=\"top\"|\n\n%s", enablescount, chipset_th);
-
-	e = chipset_enables;
-	for (i = 0, j = 0; e[i].vendor_name != NULL; i++, j++) {
-		/* Alternate colors if the vendor changes. */
-		if (i > 0 && strcmp(e[i].vendor_name, e[i - 1].vendor_name))
-			color = !color;
-
-		printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s "
-		       "|| %04x:%04x || %s\n", (color) ? "eeeeee" : "dddddd",
-		       e[i].vendor_name, e[i].device_name,
-		       e[i].vendor_id, e[i].device_id,
-		       (e[i].status == OK) ? "{{OK}}" : "?");
-
-		/* Split table in three columns. */
-		if (j >= (enablescount / 3 + 1)) {
-			printf("\n|}\n\n| valign=\"top\"|\n\n%s", chipset_th);
-			j = 0;
-		}
-	}
-
-	printf("\n|}\n\n|}\n");
-}
-
-static void wiki_helper(const char *heading, const char *status,
-			int cols, const struct board_info boards[])
-{
-	int i, j, k, c, boardcount = 0, color = 1, num_notes = 0;
-	const struct board_info *b;
-	const struct board_info_url *u = boards_url;
-	char *notes = calloc(1, 1);
-	char tmp[900 + 1];
-
-	for (b = boards; b->vendor != NULL; b++)
-		boardcount++;
-
-	printf("\n'''%s'''\n\nTotal amount of boards: '''%d'''\n\n"
-	       "{| border=\"0\" valign=\"top\"\n| valign=\"top\"|\n\n%s",
-	       heading, boardcount, board_th);
-
-        for (i = 0, j = 0, b = boards; b[i].vendor != NULL; i++, j++) {
-		/* Alternate colors if the vendor changes. */
-		if (i > 0 && strcmp(b[i].vendor, b[i - 1].vendor))
-			color = !color;
-
-		k = url(b[i].vendor, b[i].name);
-		c = note(b[i].vendor, b[i].name);
-
-		printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s%s %s%s ||"
-		       " {{%s}}", (color) ? "eeeeee" : "dddddd", b[i].vendor,
-		       (k != -1 && u[k].url) ? "[" : "",
-		       (k != -1 && u[k].url) ? u[k].url : "",
-		       b[i].name, (k != -1 && u[k].url) ? "]" : "", status);
-
-		if (c != -1) {
-			printf("<sup>%d</sup>\n", num_notes + 1);
-			snprintf((char *)&tmp, 900, "<sup>%d</sup> %s<br />\n",
-				 1 + num_notes++, boards_notes[c].note);
-			notes = strcat_realloc(notes, (char *)&tmp);
-		} else {
-			printf("\n");
-		}
-
-		/* Split table in 'cols' columns. */
-		if (j >= (boardcount / cols + 1)) {
-			printf("\n|}\n\n| valign=\"top\"|\n\n%s", board_th);
-			j = 0;
-		}
-	}
-
-	printf("\n|}\n\n|}\n");
-
-	if (num_notes > 0)
-		printf("\n<small>\n%s</small>\n", notes);
-	free(notes);
-}
-
-static void wiki_helper2(const char *heading, int cols)
-{
-	int i, j, k, boardcount = 0, color = 1;
-	struct board_pciid_enable *b;
-	const struct board_info_url *u = boards_url;
-
-	for (b = board_pciid_enables; b->vendor_name != NULL; b++)
-		boardcount++;
-
-	printf("\n'''%s'''\n\nTotal amount of boards: '''%d'''\n\n"
-	       "{| border=\"0\" valign=\"top\"\n| valign=\"top\"|\n\n%s",
-	       heading, boardcount, board_th2);
-
-	b = board_pciid_enables;
-	for (i = 0, j = 0; b[i].vendor_name != NULL; i++, j++) {
-		/* Alternate colors if the vendor changes. */
-		if (i > 0 && strcmp(b[i].vendor_name, b[i - 1].vendor_name))
-			color = !color;
-
-		k = url(b[i].vendor_name, b[i].board_name);
-
-		printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s%s %s%s "
-		       "|| %s%s%s%s || {{OK}}\n", (color) ? "eeeeee" : "dddddd",
-		       b[i].vendor_name, (k != -1 && u[k].url) ? "[" : "",
-		       (k != -1 && u[k].url) ? u[k].url : "", b[i].board_name,
-		       (k != -1 && u[k].url) ? "]" : "",
-		       (b[i].lb_vendor) ? "-m " : "&mdash;",
-		       (b[i].lb_vendor) ? b[i].lb_vendor : "",
-		       (b[i].lb_vendor) ? ":" : "",
-		       (b[i].lb_vendor) ? b[i].lb_part : "");
-
-		/* Split table in three columns. */
-		if (j >= (boardcount / cols + 1)) {
-			printf("\n|}\n\n| valign=\"top\"|\n\n%s", board_th2);
-			j = 0;
-		}
-	}
-
-	printf("\n|}\n\n|}\n");
-}
-
-void print_supported_boards_wiki(void)
-{
-	printf("%s", board_intro);
-	wiki_helper("Known good (worked out of the box)", "OK", 3, boards_ok);
-	wiki_helper2("Known good (with write-enable code in flashrom)", 3);
-	wiki_helper("Not supported (yet)", "No", 3, boards_bad);
-
-	printf("%s", laptop_intro);
-	wiki_helper("Known good (worked out of the box)", "OK", 1, laptops_ok);
-	wiki_helper("Not supported (yet)", "No", 1, laptops_bad);
-}
-
-void print_supported_chips_wiki(void)
-{
-	int i = 0, c = 1, chipcount = 0;
-	struct flashchip *f, *old = NULL;
-	uint32_t t;
-
-	for (f = flashchips; f->name != NULL; f++)
-		chipcount++;
-
-	printf("\n== Supported chips ==\n\nTotal amount of supported "
-	       "chips: '''%d'''\n\n{| border=\"0\" valign=\"top\"\n"
-		"| valign=\"top\"|\n\n%s", chipcount, chip_th);
-
-	for (f = flashchips; f->name != NULL; f++, i++) {
-		/* Don't print "unknown XXXX SPI chip" entries. */
-		if (!strncmp(f->name, "unknown", 7))
-			continue;
-
-		/* Alternate colors if the vendor changes. */
-		if (old != NULL && strcmp(old->vendor, f->vendor))
-			c = !c;
-
-		t = f->tested;
-		printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s || %d "
-		       "|| %s || {{%s}} || {{%s}} || {{%s}} || {{%s}}\n",
-		       (c == 1) ? "eeeeee" : "dddddd", f->vendor, f->name,
-		       f->total_size, flashbuses_to_text(f->bustype),
-		       (t & TEST_OK_PROBE) ? "OK" :
-		       (t & TEST_BAD_PROBE) ? "No" : ((c) ? "?2" : "?"),
-		       (t & TEST_OK_READ) ? "OK" :
-		       (t & TEST_BAD_READ) ? "No" : ((c) ? "?2" : "?"),
-		       (t & TEST_OK_ERASE) ? "OK" :
-		       (t & TEST_BAD_ERASE) ? "No" : ((c) ? "?2" : "?"),
-		       (t & TEST_OK_WRITE) ? "OK" :
-		       (t & TEST_BAD_WRITE) ? "No" : ((c) ? "?2" : "?"));
-
-		/* Split table into three columns. */
-		if (i >= (chipcount / 3 + 1)) {
-			printf("\n|}\n\n| valign=\"top\"|\n\n%s", chip_th);
-			i = 0;
-		}
-
-		old = f;
-	}
-
-	printf("\n|}\n\n|}\n");
-}
-
-void print_supported_pcidevs_wiki(struct pcidev_status *devs)
-{
-	int i = 0;
-	static int c = 0;
-
-	/* Alternate colors if the vendor changes. */
-	c = !c;
-
-	for (i = 0; devs[i].vendor_name != NULL; i++) {
-		printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s || "
-		       "%04x:%04x || {{%s}}\n", (c) ? "eeeeee" : "dddddd",
-		       devs[i].vendor_name, devs[i].device_name,
-		       devs[i].vendor_id, devs[i].device_id,
-		       (devs[i].status == PCI_NT) ? (c) ? "?2" : "?" : "OK");
-	}
-}
-
-void print_supported_wiki(void)
-{
-	time_t t = time(NULL);
-
-	printf(wiki_header, ctime(&t), flashrom_version);
-	print_supported_chips_wiki();
-	print_supported_chipsets_wiki();
-	print_supported_boards_wiki();
-	printf("%s", programmer_section);
-#if NIC3COM_SUPPORT == 1
-	print_supported_pcidevs_wiki(nics_3com);
-#endif
-#if GFXNVIDIA_SUPPORT == 1
-	print_supported_pcidevs_wiki(gfx_nvidia);
-#endif
-#if DRKAISER_SUPPORT == 1
-	print_supported_pcidevs_wiki(drkaiser_pcidev);
-#endif
-#if SATASII_SUPPORT == 1
-	print_supported_pcidevs_wiki(satas_sii);
-#endif
-	printf("\n|}\n");
-}
-
diff --git a/satasii.c b/satasii.c
deleted file mode 100644
index 79d4325..0000000
--- a/satasii.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz>
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/* Datasheets can be found on http://www.siliconimage.com. Great thanks! */
-
-#include <stdlib.h>
-#include <string.h>
-#include "flash.h"
-
-#define PCI_VENDOR_ID_SII	0x1095
-
-uint8_t *sii_bar;
-uint16_t id;
-
-struct pcidev_status satas_sii[] = {
-	{0x1095, 0x0680, PCI_OK, "Silicon Image", "PCI0680 Ultra ATA-133 Host Ctrl"},
-	{0x1095, 0x3112, PCI_OK, "Silicon Image", "SiI 3112 [SATALink/SATARaid] SATA Ctrl"},
-	{0x1095, 0x3114, PCI_OK, "Silicon Image", "SiI 3114 [SATALink/SATARaid] SATA Ctrl"},
-	{0x1095, 0x3124, PCI_NT, "Silicon Image", "SiI 3124 PCI-X SATA Ctrl"},
-	{0x1095, 0x3132, PCI_OK, "Silicon Image", "SiI 3132 SATA Raid II Ctrl"},
-	{0x1095, 0x3512, PCI_NT, "Silicon Image", "SiI 3512 [SATALink/SATARaid] SATA Ctrl"},
-
-	{},
-};
-
-int satasii_init(void)
-{
-	uint32_t addr;
-	uint16_t reg_offset;
-
-	get_io_perms();
-
-	pcidev_init(PCI_VENDOR_ID_SII, PCI_BASE_ADDRESS_0, satas_sii,
-		    programmer_param);
-	id = pcidev_dev->device_id;
-
-	if ((id == 0x3132) || (id == 0x3124)) {
-		addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_0) & ~0x07;
-		reg_offset = 0x70;
-	} else {
-		addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_5) & ~0x07;
-		reg_offset = 0x50;
-	}
-
-	sii_bar = physmap("SATA SIL registers", addr, 0x100) + reg_offset;
-
-	/* Check if ROM cycle are OK. */
-	if ((id != 0x0680) && (!(mmio_readl(sii_bar) & (1 << 26))))
-		printf("Warning: Flash seems unconnected.\n");
-
-	buses_supported = CHIP_BUSTYPE_PARALLEL;
-
-	return 0;
-}
-
-int satasii_shutdown(void)
-{
-	free(programmer_param);
-	pci_cleanup(pacc);
-	release_io_perms();
-	return 0;
-}
-
-void satasii_chip_writeb(uint8_t val, chipaddr addr)
-{
-	uint32_t ctrl_reg, data_reg;
-
-	while ((ctrl_reg = mmio_readl(sii_bar)) & (1 << 25)) ;
-
-	/* Mask out unused/reserved bits, set writes and start transaction. */
-	ctrl_reg &= 0xfcf80000;
-	ctrl_reg |= (1 << 25) | (0 << 24) | ((uint32_t) addr & 0x7ffff);
-
-	data_reg = (mmio_readl((sii_bar + 4)) & ~0xff) | val;
-	mmio_writel(data_reg, (sii_bar + 4));
-	mmio_writel(ctrl_reg, sii_bar);
-
-	while (mmio_readl(sii_bar) & (1 << 25)) ;
-}
-
-uint8_t satasii_chip_readb(const chipaddr addr)
-{
-	uint32_t ctrl_reg;
-
-	while ((ctrl_reg = mmio_readl(sii_bar)) & (1 << 25)) ;
-
-	/* Mask out unused/reserved bits, set reads and start transaction. */
-	ctrl_reg &= 0xfcf80000;
-	ctrl_reg |= (1 << 25) | (1 << 24) | ((uint32_t) addr & 0x7ffff);
-
-	mmio_writel(ctrl_reg, sii_bar);
-
-	while (mmio_readl(sii_bar) & (1 << 25)) ;
-
-	return (mmio_readl(sii_bar + 4)) & 0xff;
-}
diff --git a/sb600spi.c b/sb600spi.c
deleted file mode 100644
index 87f1cc1..0000000
--- a/sb600spi.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2008 Wang Qingpei <Qingpei.Wang@amd.com>
- * Copyright (C) 2008 Joe Bao <Zheng.Bao@amd.com>
- * Copyright (C) 2008 Advanced Micro Devices, Inc.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <string.h>
-#include "flash.h"
-#include "spi.h"
-
-/* This struct is unused, but helps visualize the SB600 SPI BAR layout.
- *struct sb600_spi_controller {
- *	unsigned int spi_cntrl0;	/ * 00h * /
- *	unsigned int restrictedcmd1;	/ * 04h * /
- *	unsigned int restrictedcmd2;	/ * 08h * /
- *	unsigned int spi_cntrl1;	/ * 0ch * /
- *	unsigned int spi_cmdvalue0;	/ * 10h * /
- *	unsigned int spi_cmdvalue1;	/ * 14h * /
- *	unsigned int spi_cmdvalue2;	/ * 18h * /
- *	unsigned int spi_fakeid;	/ * 1Ch * /
- *};
- */
-
-uint8_t *sb600_spibar = NULL;
-
-int sb600_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
-{
-	/* Maximum read length is 8 bytes. */
-	return spi_read_chunked(flash, buf, start, len, 8);
-}
-
-/* FIXME: SB600 can write 5 bytes per transaction. */
-int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf)
-{
-	int i;
-	int total_size = flash->total_size * 1024;
-	int result = 0;
-
-	spi_disable_blockprotect();
-	/* Erase first */
-	printf("Erasing flash before programming... ");
-	if (erase_flash(flash)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	printf("done.\n");
-
-	printf("Programming flash");
-	for (i = 0; i < total_size; i++, buf++) {
-		result = spi_nbyte_program(i, buf, 1);
-		if (result) {
-			fprintf(stderr, "Write error!\n");
-			return result;
-		}
-
-		/* wait program complete. */
-		if (i % 0x8000 == 0)
-			printf(".");
-		while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
-			;
-	}
-	printf(" done.\n");
-	return result;
-}
-
-static void reset_internal_fifo_pointer(void)
-{
-	mmio_writeb(mmio_readb(sb600_spibar + 2) | 0x10, sb600_spibar + 2);
-
-	while (mmio_readb(sb600_spibar + 0xD) & 0x7)
-		printf("reset\n");
-}
-
-static void execute_command(void)
-{
-	mmio_writeb(mmio_readb(sb600_spibar + 2) | 1, sb600_spibar + 2);
-
-	while (mmio_readb(sb600_spibar + 2) & 1)
-		;
-}
-
-int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-		      const unsigned char *writearr, unsigned char *readarr)
-{
-	int count;
-	/* First byte is cmd which can not being sent through FIFO. */
-	unsigned char cmd = *writearr++;
-	unsigned int readoffby1;
-
-	writecnt--;
-
-	printf_debug("%s, cmd=%x, writecnt=%x, readcnt=%x\n",
-		     __func__, cmd, writecnt, readcnt);
-
-	if (readcnt > 8) {
-		printf("%s, SB600 SPI controller can not receive %d bytes, "
-		       "it is limited to 8 bytes\n", __func__, readcnt);
-		return SPI_INVALID_LENGTH;
-	}
-
-	if (writecnt > 8) {
-		printf("%s, SB600 SPI controller can not send %d bytes, "
-		       "it is limited to 8 bytes\n", __func__, writecnt);
-		return SPI_INVALID_LENGTH;
-	}
-
-	/* This is a workaround for a bug in SB600 and SB700. If we only send
-	 * an opcode and no additional data/address, the SPI controller will
-	 * read one byte too few from the chip. Basically, the last byte of
-	 * the chip response is discarded and will not end up in the FIFO.
-	 * It is unclear if the CS# line is set high too early as well.
-	 */
-	readoffby1 = (writecnt) ? 0 : 1;
-	mmio_writeb((readcnt + readoffby1) << 4 | (writecnt), sb600_spibar + 1);
-	mmio_writeb(cmd, sb600_spibar + 0);
-
-	/* Before we use the FIFO, reset it first. */
-	reset_internal_fifo_pointer();
-
-	/* Send the write byte to FIFO. */
-	for (count = 0; count < writecnt; count++, writearr++) {
-		printf_debug(" [%x]", *writearr);
-		mmio_writeb(*writearr, sb600_spibar + 0xC);
-	}
-	printf_debug("\n");
-
-	/*
-	 * We should send the data by sequence, which means we need to reset
-	 * the FIFO pointer to the first byte we want to send.
-	 */
-	reset_internal_fifo_pointer();
-
-	execute_command();
-
-	/*
-	 * After the command executed, we should find out the index of the
-	 * received byte. Here we just reset the FIFO pointer and skip the
-	 * writecnt.
-	 * It would be possible to increase the FIFO pointer by one instead
-	 * of reading and discarding one byte from the FIFO.
-	 * The FIFO is implemented on top of an 8 byte ring buffer and the
-	 * buffer is never cleared. For every byte that is shifted out after
-	 * the opcode, the FIFO already stores the response from the chip.
-	 * Usually, the chip will respond with 0x00 or 0xff.
-	 */
-	reset_internal_fifo_pointer();
-
-	/* Skip the bytes we sent. */
-	for (count = 0; count < writecnt; count++) {
-		cmd = mmio_readb(sb600_spibar + 0xC);
-		printf_debug("[ %2x]", cmd);
-	}
-
-	printf_debug("The FIFO pointer after skipping is %d.\n",
-		     mmio_readb(sb600_spibar + 0xd) & 0x07);
-	for (count = 0; count < readcnt; count++, readarr++) {
-		*readarr = mmio_readb(sb600_spibar + 0xC);
-		printf_debug("[%02x]", *readarr);
-	}
-	printf_debug("\n");
-
-	return 0;
-}
diff --git a/serial.c b/serial.c
deleted file mode 100644
index e22a8fa..0000000
--- a/serial.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Urja Rannikko <urjaman@gmail.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "flash.h"
-#include <string.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <termios.h>
-
-int sp_fd;
-
-void __attribute__((noreturn)) sp_die(char *msg)
-{
-	perror(msg);
-	exit(1);
-}
-
-struct baudentry {
-	int flag;
-	unsigned int baud;
-};
-
-/* I'd like if the C preprocessor could have directives in macros */
-#define BAUDENTRY(baud) { B##baud, baud },
-static const struct baudentry sp_baudtable[] = {
-	BAUDENTRY(9600)
-	BAUDENTRY(19200)
-	BAUDENTRY(38400)
-	BAUDENTRY(57600)
-	BAUDENTRY(115200)
-#ifdef B230400
-	BAUDENTRY(230400)
-#endif
-#ifdef B460800
-	BAUDENTRY(460800)
-#endif
-#ifdef B500000
-	BAUDENTRY(500000)
-#endif
-#ifdef B576000
-	BAUDENTRY(576000)
-#endif
-#ifdef B921600
-	BAUDENTRY(921600)
-#endif
-#ifdef B1000000
-	BAUDENTRY(1000000)
-#endif
-#ifdef B1152000
-	BAUDENTRY(1152000)
-#endif
-#ifdef B1500000
-	BAUDENTRY(1500000)
-#endif
-#ifdef B2000000
-	BAUDENTRY(2000000)
-#endif
-#ifdef B2500000
-	BAUDENTRY(2500000)
-#endif
-#ifdef B3000000
-	BAUDENTRY(3000000)
-#endif
-#ifdef B3500000
-	BAUDENTRY(3500000)
-#endif
-#ifdef B4000000
-	BAUDENTRY(4000000)
-#endif
-	{0, 0}			/* Terminator */
-};
-
-int sp_openserport(char *dev, unsigned int baud)
-{
-	struct termios options;
-	int fd, i;
-	fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY);
-	if (fd < 0)
-		sp_die("Error: cannot open serial port");
-	fcntl(fd, F_SETFL, 0);
-	tcgetattr(fd, &options);
-	for (i = 0;; i++) {
-		if (sp_baudtable[i].baud == 0) {
-			close(fd);
-			fprintf(stderr,
-				"Error: cannot configure for baudrate %d\n",
-				baud);
-			exit(1);
-		}
-		if (sp_baudtable[i].baud == baud) {
-			cfsetispeed(&options, sp_baudtable[i].flag);
-			cfsetospeed(&options, sp_baudtable[i].flag);
-			break;
-		}
-	}
-	options.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
-	options.c_cflag |= (CS8 | CLOCAL | CREAD);
-	options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
-	options.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | IGNCR | INLCR);
-	options.c_oflag &= ~OPOST;
-	tcsetattr(fd, TCSANOW, &options);
-	return fd;
-}
-
-void sp_flush_incoming(void)
-{
-	int i;
-	for (i=0;i<100;i++) { /* In case the device doesnt do EAGAIN, just read 0 */
-		unsigned char flush[16];
-		ssize_t rv;
-		rv = read(sp_fd, flush, sizeof(flush));
-		if ((rv == -1) && (errno == EAGAIN))
-			break;
-		if (rv == -1)
-			sp_die("flush read");
-	}
-	return;
-}
diff --git a/serprog-protocol.txt b/serprog-protocol.txt
deleted file mode 100644
index 0d389e6..0000000
--- a/serprog-protocol.txt
+++ /dev/null
@@ -1,101 +0,0 @@
-Serial Flasher Protocol Specification - version 1 (0x01 return value == 1)
-
-Command And Answer Sequence - all commands give an answer.
-PC: COMMAND(8bit) <parameters determined by opcode>
-DEV: ACK/NAK(8bit) <OPTIONAL RETURN BYTES (only if ACK)> / nothing
-Command 0x10 (SYNCNOP) has a special return of NAK+ACK for synchronization.
-
-ACK = 0x06
-NAK = 0x15
-
-All multibyte values are little-endian. Addresses and lengths are 24-bit.
-
-COMMAND	Description			Parameters			Return Value
-0x00	NOP				none				ACK
-0x01	Query programmer iface version	none				ACK + 16bit version (nonzero)
-0x02	Query supported commands bitmap	none				ACK + 32 bytes (256 bits) of supported cmds flags
-0x03	Query programmer name		none				ACK + 16 bytes string (null padding) / NAK
-0x04	Query serial buffer size	none				ACK + 16bit size / NAK
-0x05	Query supported bustypes	none				ACK + 8-bit flags (as per flashrom) / NAK
-0x06	Query connected address lines	none				ACK + 8bit line count / NAK
-0x07	Query operation buffer size	none				ACK + 16bit size / NAK
-0x08	Query write-n maximum data len	none				ACK + 24bit maximum length / NAK
-0x09	Read byte			24-bit addr			ACK + BYTE / NAK
-0x0A	Read n bytes			24-bit addr + 24-bit length	ACK + length bytes / NAK
-0x0B	Initialize operation buffer	none				ACK / NAK
-0x0C	Write to opbuf: Write byte	24-bit addr + 8-bit byte	ACK / NAK (NOTE: takes 5 bytes in opbuf)
-0x0D	Write to opbuf: Write n		24-bit length + 24-bit addr +	ACK / NAK (NOTE: takes 7+n bytes in opbuf)
-					 + length bytes of data
-0x0E	Write to opbuf: delay		32-bit usecs			ACK / NAK (NOTE: takes 5 bytes in opbuf)
-0x0F	Execute operation buffer	none				ACK / NAK
-0x10	Sync NOP			none				NAK + ACK (for synchronization)
-0x11	Query maximum read-n length	none				ACK + 24-bit length (0==2^24) / NAK
-0x12	Set used bustype		8-bit flags (as with 0x05)	ACK / NAK
-0x??	unimplemented command - invalid.
-
-
-Additional information of the above commands:
-	About unimplemented commands / startup sequence:
-		Only commands allowed to be used without checking anything are 0x00,0x10 and 0x01 (NOP,SYNCNOP,Q_IFACE).
-		If 0x01 doesn't return 1, dont do anything if you dont support a newer protocol.
-		Then, check support for any other opcode (except 0x02) by using 0x02 (Q_CMDMAP).
-	0x02 (Q_CMDMAP):
-		The map's bits are mapped as follows:
-		cmd 0 support: byte 0 bit 0
-		cmd 1 support: byte 0 bit 1
-		cmd 7 support: byte 0 bit 7
-		cmd 8 support: byte 1 bit 0, and so on.
-	0x04 (Q_SERBUF):
-		If the programmer has guaranteedly working flow control,
-		it should return a big bogus value - eg 0xFFFF.
-	0x05 (Q_BUSTYPE):
-		The bit's are defined as follows:
-		bit 0: PARALLEL, bit 1: LPC, bit 2: FWH, bit 3: SPI (if ever supported).
-	0x06 (Q_CHIPSIZE):
-		Only applicable to parallel programmers.
-		An LPC/FHW/SPI-programmer can report this as not supported in the command bitmap.
-	0x08 (Q_WRNMAXLEN):
-		If a programmer reports a bigger maximum write-n length than the serial buffer size,
-		it is assumed that the programmer can process the data fast enough to take in the
-		reported maximum write-n without problems.
-	0x0F (O_EXEC):
-		Execute operation buffer will also clear it, regardless of the return value.
-	0x11 (Q_RDNMAXLEN):
-		If this command is not supported, assume return of 0 (2^24).
-	0x12 (S_BUSTYPE):
-		Set's the used bustype if the programmer can support more than one flash protocol.
-		Sending a byte with more than 1 bit set will make the programmer decide among them
-		on it's own. Bit values as with Q_BUSTYPE.
-	About mandatory commands:
-		The only truly mandatory commands for any device are 0x00, 0x01, 0x02 and 0x10,
-		but one can't really do anything with these commands.
-		Support for the following commands is necessary for flashrom to operate properly:
-		S_CMD_Q_SERBUF, S_CMD_Q_OPBUF, S_CMD_Q_WRNMAXLEN, S_CMD_R_BYTE,
-		S_CMD_R_NBYTES, S_CMD_O_INIT, S_CMD_O_WRITEB, S_CMD_O_WRITEN,
-		S_CMD_O_DELAY, S_CMD_O_EXEC.
-		In addition, support for these commands is recommended:
-		S_CMD_Q_PGMNAME, S_CMD_Q_BUSTYPE, S_CMD_Q_CHIPSIZE (if parallel).
-
-
-This define listing should help C coders - (it's here to be the single source for copying - will be a .h someday i think)
-#define S_ACK 0x06
-#define S_NAK 0x15
-#define S_CMD_NOP		0x00            /* No operation                                 */
-#define S_CMD_Q_IFACE           0x01            /* Query interface version                      */
-#define S_CMD_Q_CMDMAP		0x02		/* Query supported commands bitmap		*/
-#define S_CMD_Q_PGMNAME         0x03            /* Query programmer name                        */
-#define S_CMD_Q_SERBUF          0x04            /* Query Serial Buffer Size                     */
-#define S_CMD_Q_BUSTYPE         0x05            /* Query supported bustypes                     */
-#define S_CMD_Q_CHIPSIZE        0x06            /* Query supported chipsize (2^n format)        */
-#define S_CMD_Q_OPBUF           0x07            /* Query operation buffer size                  */
-#define S_CMD_Q_WRNMAXLEN	0x08		/* Query Write to opbuf: Write-N maximum lenght */
-#define S_CMD_R_BYTE            0x09            /* Read a single byte                           */
-#define S_CMD_R_NBYTES          0x0A            /* Read n bytes                                 */
-#define S_CMD_O_INIT            0x0B            /* Initialize operation buffer                  */
-#define S_CMD_O_WRITEB          0x0C            /* Write opbuf: Write byte with address         */
-#define S_CMD_O_WRITEN		0x0D		/* Write to opbuf: Write-N			*/
-#define S_CMD_O_DELAY           0x0E            /* Write opbuf: udelay                          */
-#define S_CMD_O_EXEC            0x0F            /* Execute operation buffer                     */
-#define S_CMD_SYNCNOP		0x10		/* Special no-operation that returns NAK+ACK	*/
-#define S_CMD_Q_RDNMAXLEN	0x11		/* Query read-n maximum length			*/
-#define S_CMD_S_BUSTYPE		0x12		/* Set used bustype(s).				*/
diff --git a/serprog.c b/serprog.c
deleted file mode 100644
index 6544245..0000000
--- a/serprog.c
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Urja Rannikko <urjaman@gmail.com>
- * Copyright (C) 2009 Carl-Daniel Hailfinger
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "flash.h"
-#include <string.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <netdb.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <termios.h>
-
-#define MSGHEADER "serprog:"
-
-#define S_ACK 0x06
-#define S_NAK 0x15
-#define S_CMD_NOP		0x00	/* No operation                                 */
-#define S_CMD_Q_IFACE		0x01	/* Query interface version                      */
-#define S_CMD_Q_CMDMAP		0x02	/* Query supported commands bitmap              */
-#define S_CMD_Q_PGMNAME		0x03	/* Query programmer name                        */
-#define S_CMD_Q_SERBUF		0x04	/* Query Serial Buffer Size                     */
-#define S_CMD_Q_BUSTYPE		0x05	/* Query supported bustypes                     */
-#define S_CMD_Q_CHIPSIZE	0x06	/* Query supported chipsize (2^n format)        */
-#define S_CMD_Q_OPBUF		0x07	/* Query operation buffer size                  */
-#define S_CMD_Q_WRNMAXLEN	0x08	/* Query opbuf-write-N maximum lenght           */
-#define S_CMD_R_BYTE		0x09	/* Read a single byte                           */
-#define S_CMD_R_NBYTES		0x0A	/* Read n bytes                                 */
-#define S_CMD_O_INIT		0x0B	/* Initialize operation buffer                  */
-#define S_CMD_O_WRITEB		0x0C	/* Write opbuf: Write byte with address         */
-#define S_CMD_O_WRITEN		0x0D	/* Write to opbuf: Write-N                      */
-#define S_CMD_O_DELAY		0x0E	/* Write opbuf: udelay                          */
-#define S_CMD_O_EXEC		0x0F	/* Execute operation buffer                     */
-#define S_CMD_SYNCNOP		0x10	/* Special no-operation that returns NAK+ACK    */
-#define S_CMD_Q_RDNMAXLEN	0x11	/* Query read-n maximum length			*/
-#define S_CMD_S_BUSTYPE		0x12	/* Set used bustype(s).				*/
-
-static uint16_t sp_device_serbuf_size = 16;
-static uint16_t sp_device_opbuf_size = 300;
-/* Bitmap of supported commands */
-static uint8_t sp_cmdmap[32];
-
-/* sp_prev_was_write used to detect writes with continouous addresses
-	and combine them to write-n's */
-static int sp_prev_was_write = 0;
-/* sp_write_n_addr used as the starting addr of the currently
-	combined write-n operation */
-static uint32_t sp_write_n_addr;
-/* The maximum length of an write_n operation; 0 = write-n not supported */
-static uint32_t sp_max_write_n = 0;
-/* The maximum length of a read_n operation; 0 = 2^24 */
-static uint32_t sp_max_read_n = 0;
-
-/* A malloc'd buffer for combining the operation's data
-	and a counter that tells how much data is there. */
-static uint8_t *sp_write_n_buf;
-static uint32_t sp_write_n_bytes = 0;
-
-/* sp_streamed_* used for flow control checking */
-static int sp_streamed_transmit_ops = 0;
-static int sp_streamed_transmit_bytes = 0;
-
-/* sp_opbuf_usage used for counting the amount of
-	on-device operation buffer used */
-static int sp_opbuf_usage = 0;
-/* if true causes sp_docommand to automatically check
-	whether the command is supported before doing it */
-static int sp_check_avail_automatic = 0;
-
-static int sp_opensocket(char *ip, unsigned int port)
-{
-	int flag = 1;
-	struct hostent *hostPtr = NULL;
-	union { struct sockaddr_in si; struct sockaddr s; } sp = {};
-	int sock;
-	printf_debug(MSGHEADER "IP %s port %d\n", ip, port);
-	sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-	if (sock < 0)
-		sp_die("Error: serprog cannot open socket");
-	hostPtr = gethostbyname(ip);
-	if (NULL == hostPtr) {
-		hostPtr = gethostbyaddr(ip, strlen(ip), AF_INET);
-		if (NULL == hostPtr)
-			sp_die("Error: cannot resolve");
-	}
-	sp.si.sin_family = AF_INET;
-	sp.si.sin_port = htons(port);
-	(void)memcpy(&sp.si.sin_addr, hostPtr->h_addr, hostPtr->h_length);
-	if (connect(sock, &sp.s, sizeof(sp.si)) < 0) {
-		close(sock);
-		sp_die("Error: serprog cannot connect");
-	}
-	/* We are latency limited, and sometimes do write-write-read    *
-	 * (write-n) - so enable TCP_NODELAY.				*/
-	setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int));
-	return sock;
-}
-
-static int sp_sync_read_timeout(int loops)
-{
-	int i;
-	unsigned char c;
-	for (i = 0; i < loops; i++) {
-		ssize_t rv;
-		rv = read(sp_fd, &c, 1);
-		if (rv == 1)
-			return c;
-		if ((rv == -1) && (errno != EAGAIN))
-			sp_die("read");
-		usleep(10 * 1000);	/* 10ms units */
-	}
-	return -1;
-}
-
-/* Synchronize: a bit tricky algorhytm that tries to (and in my tests has *
- * always succeeded in) bring the serial protocol to known waiting-for-   *
- * command state - uses nonblocking read - rest of the driver uses	  *
- * blocking read - TODO: add an alarm() timer for the rest of the app on  *
- * serial operations, though not such a big issue as the first thing to   *
- * do is synchronize (eg. check that device is alive).			  */
-static void sp_synchronize(void)
-{
-	int i;
-	int flags = fcntl(sp_fd, F_GETFL);
-	unsigned char buf[8];
-	flags |= O_NONBLOCK;
-	fcntl(sp_fd, F_SETFL, flags);
-	/* First sends 8 NOPs, then flushes the return data - should cause *
-	 * the device serial parser to get to a sane state, unless if it   *
-	 * is waiting for a real long write-n.                             */
-	memset(buf, S_CMD_NOP, 8);
-	if (write(sp_fd, buf, 8) != 8)
-		sp_die("flush write");
-	/* A second should be enough to get all the answers to the buffer */
-	usleep(1000 * 1000);
-	sp_flush_incoming();
-
-	/* Then try upto 8 times to send syncnop and get the correct special *
-	 * return of NAK+ACK. Timing note: upto 10 characters, 10*50ms =     *
-	 * upto 500ms per try, 8*0.5s = 4s; +1s (above) = upto 5s sync       *
-	 * attempt, ~1s if immediate success.                                */
-	for (i = 0; i < 8; i++) {
-		int n;
-		unsigned char c = S_CMD_SYNCNOP;
-		if (write(sp_fd, &c, 1) != 1)
-			sp_die("sync write");
-		printf_debug(".");
-		fflush(stdout);
-		for (n = 0; n < 10; n++) {
-			c = sp_sync_read_timeout(5);	/* wait upto 50ms */
-			if (c != S_NAK)
-				continue;
-			c = sp_sync_read_timeout(2);
-			if (c != S_ACK)
-				continue;
-			c = S_CMD_SYNCNOP;
-			if (write(sp_fd, &c, 1) != 1)
-				sp_die("sync write");
-			c = sp_sync_read_timeout(50);
-			if (c != S_NAK)
-				break;	/* fail */
-			c = sp_sync_read_timeout(10);
-			if (c != S_ACK)
-				break;	/* fail */
-			/* Ok, synchronized; back to blocking reads and return. */
-			flags &= ~O_NONBLOCK;
-			fcntl(sp_fd, F_SETFL, flags);
-			printf_debug("\n");
-			return;
-		}
-	}
-	fprintf(stderr,
-		"Error: cannot synchronize protocol\n"
-		"- check communications and reset device?\n");
-	exit(1);
-}
-
-static int sp_check_commandavail(uint8_t command)
-{
-	int byteoffs, bitoffs;
-	byteoffs = command / 8;
-	bitoffs = command % 8;
-	return (sp_cmdmap[byteoffs] & (1 << bitoffs)) ? 1 : 0;
-}
-
-static int sp_automatic_cmdcheck(uint8_t cmd)
-{
-	if ((sp_check_avail_automatic) && (sp_check_commandavail(cmd) == 0)) {
-		printf_debug ("Warning: Automatic command availability check"
-				" failed for cmd %d - wont execute cmd\n",cmd);
-		return 1;
-		}
-	return 0;
-}
-
-static int sp_docommand(uint8_t command, uint32_t parmlen,
-			     uint8_t * params, uint32_t retlen, void *retparms)
-{
-	unsigned char *sendpacket;
-	unsigned char c;
-	if (sp_automatic_cmdcheck(command))
-		return 1;
-	sendpacket = malloc(1 + parmlen);
-	if (!sendpacket)
-		sp_die("Error: cannot malloc command buffer");
-	sendpacket[0] = command;
-	memcpy(&(sendpacket[1]), params, parmlen);
-	if (write(sp_fd, sendpacket, 1 + parmlen) != (1 + parmlen)) {
-		sp_die("Error: cannot write command");
-	}
-	free(sendpacket);
-	if (read(sp_fd, &c, 1) != 1)
-		sp_die("Error: cannot read from device");
-	if (c == S_NAK) return 1;
-	if (c != S_ACK) {
-		fprintf(stderr,
-			"Error: invalid response 0x%02X from device\n",c);
-		exit(1);
-	}
-	if (retlen) {
-		int rd_bytes = 0;
-		do {
-			int r;
-			r = read(sp_fd, retparms + rd_bytes,
-				 retlen - rd_bytes);
-			if (r <= 0) sp_die
-				    ("Error: cannot read return parameters");
-			rd_bytes += r;
-		} while (rd_bytes != retlen);
-	}
-	return 0;
-}
-
-static void sp_flush_stream(void)
-{
-	if (sp_streamed_transmit_ops)
-		do {
-			unsigned char c;
-			if (read(sp_fd, &c, 1) != 1) {
-				sp_die
-				    ("Error: cannot read from device (flushing stream)");
-			}
-			if (c == S_NAK) {
-				fprintf(stderr,
-					"Error: NAK to a stream buffer operation\n");
-				exit(1);
-			}
-			if (c != S_ACK) {
-				fprintf(stderr,
-					"Error: Invalid reply 0x%02X from device\n",
-					c);
-				exit(1);
-			}
-		} while (--sp_streamed_transmit_ops);
-	sp_streamed_transmit_ops = 0;
-	sp_streamed_transmit_bytes = 0;
-}
-
-static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t * parms)
-{
-	uint8_t *sp;
-	if (sp_automatic_cmdcheck(cmd))
-		return 1;
-	sp = malloc(1 + parmlen);
-	if (!sp) sp_die("Error: cannot malloc command buffer");
-	sp[0] = cmd;
-	memcpy(&(sp[1]), parms, parmlen);
-	if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size))
-		sp_flush_stream();
-	if (write(sp_fd, sp, 1 + parmlen) != (1 + parmlen))
-		sp_die("Error: cannot write command");
-	free(sp);
-	sp_streamed_transmit_ops += 1;
-	sp_streamed_transmit_bytes += 1 + parmlen;
-	return 0;
-}
-
-int serprog_init(void)
-{
-	uint16_t iface;
-	int len;
-	unsigned char pgmname[17];
-	unsigned char rbuf[3];
-	unsigned char c;
-	char *num;
-	char *dev;
-	printf_debug("%s\n", __func__);
-	/* the parameter is either of format "/dev/device:baud" or "ip:port" */
-	if ((!programmer_param) || (!strlen(programmer_param))) {
-		nodevice:
-		fprintf(stderr,
-			"Error: No device/host given for the serial programmer driver.\n"
-			"Use flashrom -p serprog=/dev/device:baud or flashrom -p serprog=ip:port\n");
-		exit(1);
-	}
-	num = strstr(programmer_param, ":");
-	len = num - programmer_param;
-	if (!len) goto nodevice;
-	if (!num) {
-		fprintf(stderr,
-			"Error: No port or baudrate specified to serial programmer driver.\n"
-			"Use flashrom -p serprog=/dev/device:baud or flashrom -p serprog=ip:port\n");
-		exit(1);
-	}
-	len = num - programmer_param;
-	dev = malloc(len + 1);
-	if (!dev) sp_die("Error: memory allocation failure");
-	memcpy(dev, programmer_param, len);
-	dev[len] = 0;
-	num = strdup(num + 1);
-	if (!num) sp_die("Error: memory allocation failure");
-	free(programmer_param);
-	programmer_param = NULL;
-
-	if (dev[0] == '/') sp_fd = sp_openserport(dev, atoi(num));
-	else sp_fd = sp_opensocket(dev, atoi(num));
-
-	free(dev); dev = NULL;
-	free(num); num = NULL;
-
-	printf_debug(MSGHEADER "connected - attempting to synchronize\n");
-
-	sp_check_avail_automatic = 0;
-
-	sp_synchronize();
-
-	printf_debug(MSGHEADER "Synchronized\n");
-
-	if (sp_docommand(S_CMD_Q_IFACE, 0, NULL, 2, &iface)) {
-		fprintf(stderr, "Error: NAK to Query Interface version\n");
-		exit(1);
-	}
-
-	if (iface != 1) {
-		fprintf(stderr, "Error: Unknown interface version %d\n", iface);
-		exit(1);
-	}
-
-	printf_debug(MSGHEADER "Interface version ok.\n");
-
-	if (sp_docommand(S_CMD_Q_CMDMAP, 0, NULL, 32, sp_cmdmap)) {
-		fprintf(stderr, "Error: query command map not supported\n");
-		exit(1);
-	}
-
-	sp_check_avail_automatic = 1;
-
-	/* Check for the minimum operational set of commands */
-	if (sp_check_commandavail(S_CMD_R_BYTE) == 0) {
-		fprintf(stderr, "Error: Single byte read not supported\n");
-		exit(1);
-	}
-	/* This could be translated to single byte reads (if missing),	*
-	 * but now we dont support that.				*/
-	if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) {
-		fprintf(stderr, "Error: Read n bytes not supported\n");
-		exit(1);
-	}
-	/* In the future one could switch to read-only mode if these	*
-	 * are not available.						*/
-	if (sp_check_commandavail(S_CMD_O_INIT) == 0) {
-		fprintf(stderr,
-			"Error: Initialize operation buffer not supported\n");
-		exit(1);
-	}
-	if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) {
-		fprintf(stderr,
-			"Error: Write to opbuf: write byte not supported\n");
-		exit(1);
-	}
-	if (sp_check_commandavail(S_CMD_O_DELAY) == 0) {
-		fprintf(stderr, "Error: Write to opbuf: delay not supported\n");
-		exit(1);
-	}
-	if (sp_check_commandavail(S_CMD_O_EXEC) == 0) {
-		fprintf(stderr,
-			"Error: Execute operation buffer not supported\n");
-		exit(1);
-	}
-
-	if (sp_docommand(S_CMD_Q_PGMNAME, 0, NULL, 16, pgmname)) {
-		fprintf(stderr, "Warning: NAK to query programmer name\n");
-		strcpy((char *)pgmname, "(unknown)");
-	}
-	pgmname[16] = 0;
-	printf(MSGHEADER "Programmer name \"%s\"\n", pgmname);
-
-	if (sp_docommand(S_CMD_Q_SERBUF, 0, NULL, 2, &sp_device_serbuf_size)) {
-		fprintf(stderr, "Warning: NAK to query serial buffer size\n");
-	}
-	printf_debug(MSGHEADER "serial buffer size %d\n",
-		     sp_device_serbuf_size);
-
-	if (sp_docommand(S_CMD_Q_OPBUF, 0, NULL, 2, &sp_device_opbuf_size)) {
-		fprintf(stderr,
-			"Warning: NAK to query operation buffer size\n");
-	}
-	printf_debug(MSGHEADER "operation buffer size %d\n",
-		     sp_device_opbuf_size);
-
-	if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) {
-		fprintf(stderr, "Warning: NAK to query supported buses\n");
-		c = CHIP_BUSTYPE_NONSPI;	/* A reasonable default for now. */
-	}
-	buses_supported = c;
-
-	if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) {
-		fprintf(stderr, "Error: NAK to initialize operation buffer\n");
-		exit(1);
-	}
-
-	if (sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
-		printf_debug(MSGHEADER "Write-n not supported");
-		sp_max_write_n = 0;
-	} else {
-		sp_max_write_n = ((unsigned int)(rbuf[0]) << 0);
-		sp_max_write_n |= ((unsigned int)(rbuf[1]) << 8);
-		sp_max_write_n |= ((unsigned int)(rbuf[2]) << 16);
-		printf_debug(MSGHEADER "Maximum write-n length %d\n",
-			     sp_max_write_n);
-		sp_write_n_buf = malloc(sp_max_write_n);
-		if (!sp_write_n_buf) {
-			fprintf(stderr,
-				"Error: cannot allocate memory for Write-n buffer\n");
-			exit(1);
-		}
-		sp_write_n_bytes = 0;
-	}
-	
-	if ((sp_check_commandavail(S_CMD_Q_RDNMAXLEN))
-		&&((sp_docommand(S_CMD_Q_RDNMAXLEN,0,NULL, 3, rbuf) == 0))) {
-		sp_max_read_n = ((unsigned int)(rbuf[0]) << 0);
-		sp_max_read_n |= ((unsigned int)(rbuf[1]) << 8);
-		sp_max_read_n |= ((unsigned int)(rbuf[2]) << 16);
-		printf_debug(MSGHEADER "Maximum read-n length %d\n",
-			sp_max_read_n ? sp_max_read_n : (1<<24));
-	} else {
-		printf_debug(MSGHEADER "Maximum read-n length not reported\n");
-		sp_max_read_n = 0;
-	}
-
-	sp_prev_was_write = 0;
-	sp_streamed_transmit_ops = 0;
-	sp_streamed_transmit_bytes = 0;
-	sp_opbuf_usage = 0;
-	return 0;
-}
-
-/* Move an in flashrom buffer existing write-n operation to	*
- * the on-device operation buffer.				*/
-static void sp_pass_writen(void)
-{
-	unsigned char header[7];
-	printf_debug(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n",
-		     sp_write_n_bytes, sp_write_n_addr);
-	if (sp_streamed_transmit_bytes >=
-	    (7 + sp_write_n_bytes + sp_device_serbuf_size))
-		sp_flush_stream();
-	/* In case it's just a single byte send it as a single write. */
-	if (sp_write_n_bytes == 1) {
-		sp_write_n_bytes = 0;
-		header[0] = (sp_write_n_addr >> 0) & 0xFF;
-		header[1] = (sp_write_n_addr >> 8) & 0xFF;
-		header[2] = (sp_write_n_addr >> 16) & 0xFF;
-		header[3] = sp_write_n_buf[0];
-		sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header);
-		sp_opbuf_usage += 5;
-		return;
-	}
-	header[0] = S_CMD_O_WRITEN;
-	header[1] = (sp_write_n_bytes >> 0) & 0xFF;
-	header[2] = (sp_write_n_bytes >> 8) & 0xFF;
-	header[3] = (sp_write_n_bytes >> 16) & 0xFF;
-	header[4] = (sp_write_n_addr >> 0) & 0xFF;
-	header[5] = (sp_write_n_addr >> 8) & 0xFF;
-	header[6] = (sp_write_n_addr >> 16) & 0xFF;
-	if (write(sp_fd, header, 7) != 7)
-		sp_die("Error: cannot write write-n command\n");
-	if (write(sp_fd, sp_write_n_buf, sp_write_n_bytes) !=
-	    sp_write_n_bytes)
-		sp_die("Error: cannot write write-n data");
-	sp_streamed_transmit_bytes += 7 + sp_write_n_bytes;
-	sp_streamed_transmit_ops += 1;
-	sp_opbuf_usage += 7 + sp_write_n_bytes;
-	sp_write_n_bytes = 0;
-	sp_prev_was_write = 0;
-}
-
-static void sp_execute_opbuf_noflush(void)
-{
-	if ((sp_max_write_n) && (sp_write_n_bytes))
-		sp_pass_writen();
-	sp_stream_buffer_op(S_CMD_O_EXEC, 0, 0);
-	printf_debug(MSGHEADER "Executed operation buffer of %d bytes\n",
-		     sp_opbuf_usage);
-	sp_opbuf_usage = 0;
-	sp_prev_was_write = 0;
-	return;
-}
-
-static void sp_execute_opbuf(void)
-{
-	sp_execute_opbuf_noflush();
-	sp_flush_stream();
-}
-
-int serprog_shutdown(void)
-{
-	printf_debug("%s\n", __func__);
-	if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
-		sp_execute_opbuf();
-	close(sp_fd);
-	if (sp_max_write_n)
-		free(sp_write_n_buf);
-	return 0;
-}
-
-static void sp_check_opbuf_usage(int bytes_to_be_added)
-{
-	if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) {
-		sp_execute_opbuf();
-		/* If this happens in the mid of an page load the page load *
-		 * will propably fail.					    */
-		printf_debug(MSGHEADER
-		"Warning: executed operation buffer due to size reasons\n");
-	}
-}
-
-void serprog_chip_writeb(uint8_t val, chipaddr addr)
-{
-	printf_debug("%s\n", __func__);
-	if (sp_max_write_n) {
-		if ((sp_prev_was_write)
-		    && (addr == (sp_write_n_addr + sp_write_n_bytes))) {
-			sp_write_n_buf[sp_write_n_bytes++] = val;
-		} else {
-			if ((sp_prev_was_write) && (sp_write_n_bytes))
-				sp_pass_writen();
-			sp_prev_was_write = 1;
-			sp_write_n_addr = addr;
-			sp_write_n_bytes = 1;
-			sp_write_n_buf[0] = val;
-		}
-		sp_check_opbuf_usage(7 + sp_write_n_bytes);
-		if (sp_write_n_bytes >= sp_max_write_n)
-			sp_pass_writen();
-	} else {
-		/* We will have to do single writeb ops. */
-		unsigned char writeb_parm[4];
-		sp_check_opbuf_usage(6);
-		writeb_parm[0] = (addr >> 0) & 0xFF;
-		writeb_parm[1] = (addr >> 8) & 0xFF;
-		writeb_parm[2] = (addr >> 16) & 0xFF;
-		writeb_parm[3] = val;
-		sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm);
-		sp_opbuf_usage += 5;
-	}
-}
-
-uint8_t serprog_chip_readb(const chipaddr addr)
-{
-	unsigned char c;
-	unsigned char buf[3];
-	/* Will stream the read operation - eg. add it to the stream buffer, *
-	 * then flush the buffer, then read the read answer.		     */
-	if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
-		sp_execute_opbuf_noflush();
-	buf[0] = ((addr >> 0) & 0xFF);
-	buf[1] = ((addr >> 8) & 0xFF);
-	buf[2] = ((addr >> 16) & 0xFF);
-	sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf);
-	sp_flush_stream();
-	if (read(sp_fd, &c, 1) != 1)
-		sp_die("readb byteread");
-	printf_debug("%s addr=0x%lx returning 0x%02X\n", __func__, addr, c);
-	return c;
-}
-
-/* Local version that really does the job, doesnt care of max_read_n. */
-static void sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len)
-{
-	int rd_bytes = 0;
-	unsigned char sbuf[6];
-	printf_debug("%s: addr=0x%lx len=%lu\n", __func__, addr, (unsigned long)len);
-	/* Stream the read-n -- as above. */
-	if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
-		sp_execute_opbuf_noflush();
-	sbuf[0] = ((addr >> 0) & 0xFF);
-	sbuf[1] = ((addr >> 8) & 0xFF);
-	sbuf[2] = ((addr >> 16) & 0xFF);
-	sbuf[3] = ((len >> 0) & 0xFF);
-	sbuf[4] = ((len >> 8) & 0xFF);
-	sbuf[5] = ((len >> 16) & 0xFF);
-	sp_stream_buffer_op(S_CMD_R_NBYTES, 6, sbuf);
-	sp_flush_stream();
-	do {
-		int r = read(sp_fd, buf + rd_bytes, len - rd_bytes);
-		if (r <= 0)
-			sp_die("Error: cannot read read-n data");
-		rd_bytes += r;
-	} while (rd_bytes != len);
-	return;
-}
-
-/* The externally called version that makes sure that max_read_n is obeyed. */
-void serprog_chip_readn(uint8_t * buf, const chipaddr addr, size_t len)
-{
-	size_t lenm = len;
-	chipaddr addrm = addr;
-	while ((sp_max_read_n)&&(lenm > sp_max_read_n)) {
-		sp_do_read_n(&(buf[addrm-addr]),addrm,sp_max_read_n);
-		addrm += sp_max_read_n;
-		lenm -= sp_max_read_n;
-	}
-	if (lenm) sp_do_read_n(&(buf[addrm-addr]),addrm,lenm);
-}
-
-void serprog_delay(int delay)
-{
-	unsigned char buf[4];
-	printf_debug("%s\n", __func__);
-	if ((sp_max_write_n) && (sp_write_n_bytes))
-		sp_pass_writen();
-	sp_check_opbuf_usage(5);
-	buf[0] = ((delay >> 0) & 0xFF);
-	buf[1] = ((delay >> 8) & 0xFF);
-	buf[2] = ((delay >> 16) & 0xFF);
-	buf[3] = ((delay >> 24) & 0xFF);
-	sp_stream_buffer_op(S_CMD_O_DELAY, 4, buf);
-	sp_opbuf_usage += 5;
-	sp_prev_was_write = 0;
-}
diff --git a/sharplhf00l04.c b/sharplhf00l04.c
deleted file mode 100644
index 1234ae4..0000000
--- a/sharplhf00l04.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdlib.h>
-#include "flash.h"
-
-// I need that Berkeley bit-map printer
-void print_lhf00l04_status(uint8_t status)
-{
-	printf("%s", status & 0x80 ? "Ready:" : "Busy:");
-	printf("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:");
-	printf("%s", status & 0x20 ? "BE ERROR:" : "BE OK:");
-	printf("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:");
-	printf("%s", status & 0x8 ? "VP ERR:" : "VPP OK:");
-	printf("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:");
-	printf("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:");
-}
-
-int probe_lhf00l04(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-	uint8_t id1, id2;
-
-#if 0
-	/* Enter ID mode */
-	chip_writeb(0xAA, bios + 0x5555);
-	chip_writeb(0x55, bios + 0x2AAA);
-	chip_writeb(0x90, bios + 0x5555);
-#endif
-
-	chip_writeb(0xff, bios);
-	programmer_delay(10);
-	chip_writeb(0x90, bios);
-	programmer_delay(10);
-
-	id1 = chip_readb(bios);
-	id2 = chip_readb(bios + 0x01);
-
-	/* Leave ID mode */
-	chip_writeb(0xAA, bios + 0x5555);
-	chip_writeb(0x55, bios + 0x2AAA);
-	chip_writeb(0xF0, bios + 0x5555);
-
-	programmer_delay(10);
-
-	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
-
-	if (id1 != flash->manufacture_id || id2 != flash->model_id)
-		return 0;
-
-	map_flash_registers(flash);
-
-	return 1;
-}
-
-uint8_t wait_lhf00l04(chipaddr bios)
-{
-	uint8_t status;
-
-	chip_writeb(0x70, bios);
-	if ((chip_readb(bios) & 0x80) == 0) {	// it's busy
-		while ((chip_readb(bios) & 0x80) == 0) ;
-	}
-
-	status = chip_readb(bios);
-
-	// put another command to get out of status register mode.
-
-	chip_writeb(0x90, bios);
-	programmer_delay(10);
-
-	chip_readb(bios);		// vendor ID
-	chip_readb(bios + 0x01);	// device ID
-
-	// this is needed to jam it out of "read id" mode
-	chip_writeb(0xAA, bios + 0x5555);
-	chip_writeb(0x55, bios + 0x2AAA);
-	chip_writeb(0xF0, bios + 0x5555);
-
-	return status;
-}
-
-int erase_lhf00l04_block(struct flashchip *flash, int offset)
-{
-	chipaddr bios = flash->virtual_memory + offset;
-	chipaddr wrprotect = flash->virtual_registers + offset + 2;
-	uint8_t status;
-
-	// clear status register
-	chip_writeb(0x50, bios);
-	printf("Erase at 0x%lx\n", bios);
-	status = wait_lhf00l04(flash->virtual_memory);
-	print_lhf00l04_status(status);
-	// clear write protect
-	printf("write protect is at 0x%lx\n", (wrprotect));
-	printf("write protect is 0x%x\n", chip_readb(wrprotect));
-	chip_writeb(0, wrprotect);
-	printf("write protect is 0x%x\n", chip_readb(wrprotect));
-
-	// now start it
-	chip_writeb(0x20, bios);
-	chip_writeb(0xd0, bios);
-	programmer_delay(10);
-	// now let's see what the register is
-	status = wait_lhf00l04(flash->virtual_memory);
-	print_lhf00l04_status(status);
-	printf("DONE BLOCK 0x%x\n", offset);
-
-	if (check_erased_range(flash, offset, flash->page_size)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-int erase_lhf00l04(struct flashchip *flash)
-{
-	int i;
-	unsigned int total_size = flash->total_size * 1024;
-
-	printf("total_size is %d; flash->page_size is %d\n",
-	       total_size, flash->page_size);
-	for (i = 0; i < total_size; i += flash->page_size)
-		if (erase_lhf00l04_block(flash, i)) {
-			fprintf(stderr, "ERASE FAILED!\n");
-			return -1;
-		}
-	printf("DONE ERASE\n");
-
-	return 0;
-}
-
-void write_page_lhf00l04(chipaddr bios, uint8_t *src,
-			 chipaddr dst, int page_size)
-{
-	int i;
-
-	for (i = 0; i < page_size; i++) {
-		/* transfer data from source to destination */
-		chip_writeb(0x40, dst);
-		chip_writeb(*src++, dst++);
-		wait_lhf00l04(bios);
-	}
-}
-
-int write_lhf00l04(struct flashchip *flash, uint8_t *buf)
-{
-	int i;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-	chipaddr bios = flash->virtual_memory;
-
-	if (erase_lhf00l04(flash)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	printf("Programming page: ");
-	for (i = 0; i < total_size / page_size; i++) {
-		printf("%04d at address: 0x%08x", i, i * page_size);
-		write_page_lhf00l04(bios, buf + i * page_size,
-				    bios + i * page_size, page_size);
-		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-	}
-	printf("\n");
-
-	return 0;
-}
diff --git a/spi.c b/spi.c
deleted file mode 100644
index 14beed7..0000000
--- a/spi.c
+++ /dev/null
@@ -1,1071 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2007, 2008, 2009 Carl-Daniel Hailfinger
- * Copyright (C) 2008 coresystems GmbH
- *
- * 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; version 2 of the License.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/*
- * Contains the generic SPI framework
- */
-
-#include <string.h>
-#include "flash.h"
-#include "flashchips.h"
-#include "spi.h"
-
-enum spi_controller spi_controller = SPI_CONTROLLER_NONE;
-void *spibar = NULL;
-
-void spi_prettyprint_status_register(struct flashchip *flash);
-
-const struct spi_programmer spi_programmer[] = {
-	{ /* SPI_CONTROLLER_NONE */
-		.command = NULL,
-		.multicommand = NULL,
-		.read = NULL,
-		.write_256 = NULL,
-	},
-
-	{ /* SPI_CONTROLLER_ICH7 */
-		.command = ich_spi_send_command,
-		.multicommand = ich_spi_send_multicommand,
-		.read = ich_spi_read,
-		.write_256 = ich_spi_write_256,
-	},
-
-	{ /* SPI_CONTROLLER_ICH9 */
-		.command = ich_spi_send_command,
-		.multicommand = ich_spi_send_multicommand,
-		.read = ich_spi_read,
-		.write_256 = ich_spi_write_256,
-	},
-
-	{ /* SPI_CONTROLLER_IT87XX */
-		.command = it8716f_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = it8716f_spi_chip_read,
-		.write_256 = it8716f_spi_chip_write_256,
-	},
-
-	{ /* SPI_CONTROLLER_SB600 */
-		.command = sb600_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = sb600_spi_read,
-		.write_256 = sb600_spi_write_1,
-	},
-
-	{ /* SPI_CONTROLLER_VIA */
-		.command = ich_spi_send_command,
-		.multicommand = ich_spi_send_multicommand,
-		.read = ich_spi_read,
-		.write_256 = ich_spi_write_256,
-	},
-
-	{ /* SPI_CONTROLLER_WBSIO */
-		.command = wbsio_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = wbsio_spi_read,
-		.write_256 = wbsio_spi_write_1,
-	},
-
-#if FT2232_SPI_SUPPORT == 1
-	{ /* SPI_CONTROLLER_FT2232 */
-		.command = ft2232_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = ft2232_spi_read,
-		.write_256 = ft2232_spi_write_256,
-	},
-#endif
-
-#if DUMMY_SUPPORT == 1
-	{ /* SPI_CONTROLLER_DUMMY */
-		.command = dummy_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = NULL,
-		.write_256 = NULL,
-	},
-#endif
-
-#if BUSPIRATE_SPI_SUPPORT == 1
-	{ /* SPI_CONTROLLER_BUSPIRATE */
-		.command = buspirate_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = buspirate_spi_read,
-		.write_256 = spi_chip_write_1,
-	},
-#endif
-
-	{}, /* This entry corresponds to SPI_CONTROLLER_INVALID. */
-};
-
-const int spi_programmer_count = ARRAY_SIZE(spi_programmer);
-
-int spi_send_command(unsigned int writecnt, unsigned int readcnt,
-		const unsigned char *writearr, unsigned char *readarr)
-{
-	if (!spi_programmer[spi_controller].command) {
-		fprintf(stderr, "%s called, but SPI is unsupported on this "
-			"hardware. Please report a bug.\n", __func__);
-		return 1;
-	}
-
-	return spi_programmer[spi_controller].command(writecnt, readcnt,
-						      writearr, readarr);
-}
-
-int spi_send_multicommand(struct spi_command *cmds)
-{
-	if (!spi_programmer[spi_controller].multicommand) {
-		fprintf(stderr, "%s called, but SPI is unsupported on this "
-			"hardware. Please report a bug.\n", __func__);
-		return 1;
-	}
-
-	return spi_programmer[spi_controller].multicommand(cmds);
-}
-
-int default_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-			     const unsigned char *writearr, unsigned char *readarr)
-{
-	struct spi_command cmd[] = {
-	{
-		.writecnt = writecnt,
-		.readcnt = readcnt,
-		.writearr = writearr,
-		.readarr = readarr,
-	}, {
-		.writecnt = 0,
-		.writearr = NULL,
-		.readcnt = 0,
-		.readarr = NULL,
-	}};
-
-	return spi_send_multicommand(cmd);
-}
-
-int default_spi_send_multicommand(struct spi_command *cmds)
-{
-	int result = 0;
-	for (; (cmds->writecnt || cmds->readcnt) && !result; cmds++) {
-		result = spi_send_command(cmds->writecnt, cmds->readcnt,
-					  cmds->writearr, cmds->readarr);
-	}
-	return result;
-}
-
-static int spi_rdid(unsigned char *readarr, int bytes)
-{
-	const unsigned char cmd[JEDEC_RDID_OUTSIZE] = { JEDEC_RDID };
-	int ret;
-	int i;
-
-	ret = spi_send_command(sizeof(cmd), bytes, cmd, readarr);
-	if (ret)
-		return ret;
-	printf_debug("RDID returned");
-	for (i = 0; i < bytes; i++)
-		printf_debug(" 0x%02x", readarr[i]);
-	printf_debug(". ");
-	return 0;
-}
-
-static int spi_rems(unsigned char *readarr)
-{
-	unsigned char cmd[JEDEC_REMS_OUTSIZE] = { JEDEC_REMS, 0, 0, 0 };
-	uint32_t readaddr;
-	int ret;
-
-	ret = spi_send_command(sizeof(cmd), JEDEC_REMS_INSIZE, cmd, readarr);
-	if (ret == SPI_INVALID_ADDRESS) {
-		/* Find the lowest even address allowed for reads. */
-		readaddr = (spi_get_valid_read_addr() + 1) & ~1;
-		cmd[1] = (readaddr >> 16) & 0xff,
-		cmd[2] = (readaddr >> 8) & 0xff,
-		cmd[3] = (readaddr >> 0) & 0xff,
-		ret = spi_send_command(sizeof(cmd), JEDEC_REMS_INSIZE, cmd, readarr);
-	}
-	if (ret)
-		return ret;
-	printf_debug("REMS returned %02x %02x. ", readarr[0], readarr[1]);
-	return 0;
-}
-
-static int spi_res(unsigned char *readarr)
-{
-	unsigned char cmd[JEDEC_RES_OUTSIZE] = { JEDEC_RES, 0, 0, 0 };
-	uint32_t readaddr;
-	int ret;
-
-	ret = spi_send_command(sizeof(cmd), JEDEC_RES_INSIZE, cmd, readarr);
-	if (ret == SPI_INVALID_ADDRESS) {
-		/* Find the lowest even address allowed for reads. */
-		readaddr = (spi_get_valid_read_addr() + 1) & ~1;
-		cmd[1] = (readaddr >> 16) & 0xff,
-		cmd[2] = (readaddr >> 8) & 0xff,
-		cmd[3] = (readaddr >> 0) & 0xff,
-		ret = spi_send_command(sizeof(cmd), JEDEC_RES_INSIZE, cmd, readarr);
-	}
-	if (ret)
-		return ret;
-	printf_debug("RES returned %02x. ", readarr[0]);
-	return 0;
-}
-
-int spi_write_enable(void)
-{
-	const unsigned char cmd[JEDEC_WREN_OUTSIZE] = { JEDEC_WREN };
-	int result;
-
-	/* Send WREN (Write Enable) */
-	result = spi_send_command(sizeof(cmd), 0, cmd, NULL);
-
-	if (result)
-		fprintf(stderr, "%s failed\n", __func__);
-
-	return result;
-}
-
-int spi_write_disable(void)
-{
-	const unsigned char cmd[JEDEC_WRDI_OUTSIZE] = { JEDEC_WRDI };
-
-	/* Send WRDI (Write Disable) */
-	return spi_send_command(sizeof(cmd), 0, cmd, NULL);
-}
-
-static int probe_spi_rdid_generic(struct flashchip *flash, int bytes)
-{
-	unsigned char readarr[4];
-	uint32_t id1;
-	uint32_t id2;
-
-	if (spi_rdid(readarr, bytes))
-		return 0;
-
-	if (!oddparity(readarr[0]))
-		printf_debug("RDID byte 0 parity violation. ");
-
-	/* Check if this is a continuation vendor ID */
-	if (readarr[0] == 0x7f) {
-		if (!oddparity(readarr[1]))
-			printf_debug("RDID byte 1 parity violation. ");
-		id1 = (readarr[0] << 8) | readarr[1];
-		id2 = readarr[2];
-		if (bytes > 3) {
-			id2 <<= 8;
-			id2 |= readarr[3];
-		}
-	} else {
-		id1 = readarr[0];
-		id2 = (readarr[1] << 8) | readarr[2];
-	}
-
-	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
-
-	if (id1 == flash->manufacture_id && id2 == flash->model_id) {
-		/* Print the status register to tell the
-		 * user about possible write protection.
-		 */
-		spi_prettyprint_status_register(flash);
-
-		return 1;
-	}
-
-	/* Test if this is a pure vendor match. */
-	if (id1 == flash->manufacture_id &&
-	    GENERIC_DEVICE_ID == flash->model_id)
-		return 1;
-
-	/* Test if there is any vendor ID. */
-	if (GENERIC_MANUF_ID == flash->manufacture_id &&
-	    id1 != 0xff)
-		return 1;
-
-	return 0;
-}
-
-int probe_spi_rdid(struct flashchip *flash)
-{
-	return probe_spi_rdid_generic(flash, 3);
-}
-
-/* support 4 bytes flash ID */
-int probe_spi_rdid4(struct flashchip *flash)
-{
-	/* only some SPI chipsets support 4 bytes commands */
-	switch (spi_controller) {
-	case SPI_CONTROLLER_ICH7:
-	case SPI_CONTROLLER_ICH9:
-	case SPI_CONTROLLER_VIA:
-	case SPI_CONTROLLER_SB600:
-	case SPI_CONTROLLER_WBSIO:
-#if FT2232_SPI_SUPPORT == 1
-	case SPI_CONTROLLER_FT2232:
-#endif
-#if DUMMY_SUPPORT == 1
-	case SPI_CONTROLLER_DUMMY:
-#endif
-#if BUSPIRATE_SPI_SUPPORT == 1
-	case SPI_CONTROLLER_BUSPIRATE:
-#endif
-		return probe_spi_rdid_generic(flash, 4);
-	default:
-		printf_debug("4b ID not supported on this SPI controller\n");
-	}
-
-	return 0;
-}
-
-int probe_spi_rems(struct flashchip *flash)
-{
-	unsigned char readarr[JEDEC_REMS_INSIZE];
-	uint32_t id1, id2;
-
-	if (spi_rems(readarr))
-		return 0;
-
-	id1 = readarr[0];
-	id2 = readarr[1];
-
-	printf_debug("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
-
-	if (id1 == flash->manufacture_id && id2 == flash->model_id) {
-		/* Print the status register to tell the
-		 * user about possible write protection.
-		 */
-		spi_prettyprint_status_register(flash);
-
-		return 1;
-	}
-
-	/* Test if this is a pure vendor match. */
-	if (id1 == flash->manufacture_id &&
-	    GENERIC_DEVICE_ID == flash->model_id)
-		return 1;
-
-	/* Test if there is any vendor ID. */
-	if (GENERIC_MANUF_ID == flash->manufacture_id &&
-	    id1 != 0xff)
-		return 1;
-
-	return 0;
-}
-
-int probe_spi_res(struct flashchip *flash)
-{
-	unsigned char readarr[3];
-	uint32_t id2;
-
-	/* Check if RDID was successful and did not return 0xff 0xff 0xff.
-	 * In that case, RES is pointless.
-	 */
-	if (!spi_rdid(readarr, 3) && ((readarr[0] != 0xff) ||
-	    (readarr[1] != 0xff) || (readarr[2] != 0xff)))
-		return 0;
-
-	if (spi_res(readarr))
-		return 0;
-
-	id2 = readarr[0];
-	printf_debug("%s: id 0x%x\n", __func__, id2);
-	if (id2 != flash->model_id)
-		return 0;
-
-	/* Print the status register to tell the
-	 * user about possible write protection.
-	 */
-	spi_prettyprint_status_register(flash);
-	return 1;
-}
-
-uint8_t spi_read_status_register(void)
-{
-	const unsigned char cmd[JEDEC_RDSR_OUTSIZE] = { JEDEC_RDSR };
-	/* FIXME: No workarounds for driver/hardware bugs in generic code. */
-	unsigned char readarr[2]; /* JEDEC_RDSR_INSIZE=1 but wbsio needs 2 */
-	int ret;
-
-	/* Read Status Register */
-	ret = spi_send_command(sizeof(cmd), sizeof(readarr), cmd, readarr);
-	if (ret)
-		fprintf(stderr, "RDSR failed!\n");
-
-	return readarr[0];
-}
-
-/* Prettyprint the status register. Common definitions. */
-void spi_prettyprint_status_register_common(uint8_t status)
-{
-	printf_debug("Chip status register: Bit 5 / Block Protect 3 (BP3) is "
-		     "%sset\n", (status & (1 << 5)) ? "" : "not ");
-	printf_debug("Chip status register: Bit 4 / Block Protect 2 (BP2) is "
-		     "%sset\n", (status & (1 << 4)) ? "" : "not ");
-	printf_debug("Chip status register: Bit 3 / Block Protect 1 (BP1) is "
-		     "%sset\n", (status & (1 << 3)) ? "" : "not ");
-	printf_debug("Chip status register: Bit 2 / Block Protect 0 (BP0) is "
-		     "%sset\n", (status & (1 << 2)) ? "" : "not ");
-	printf_debug("Chip status register: Write Enable Latch (WEL) is "
-		     "%sset\n", (status & (1 << 1)) ? "" : "not ");
-	printf_debug("Chip status register: Write In Progress (WIP/BUSY) is "
-		     "%sset\n", (status & (1 << 0)) ? "" : "not ");
-}
-
-/* Prettyprint the status register. Works for
- * ST M25P series
- * MX MX25L series
- */
-void spi_prettyprint_status_register_st_m25p(uint8_t status)
-{
-	printf_debug("Chip status register: Status Register Write Disable "
-		     "(SRWD) is %sset\n", (status & (1 << 7)) ? "" : "not ");
-	printf_debug("Chip status register: Bit 6 is "
-		     "%sset\n", (status & (1 << 6)) ? "" : "not ");
-	spi_prettyprint_status_register_common(status);
-}
-
-void spi_prettyprint_status_register_sst25(uint8_t status)
-{
-	printf_debug("Chip status register: Block Protect Write Disable "
-		     "(BPL) is %sset\n", (status & (1 << 7)) ? "" : "not ");
-	printf_debug("Chip status register: Auto Address Increment Programming "
-		     "(AAI) is %sset\n", (status & (1 << 6)) ? "" : "not ");
-	spi_prettyprint_status_register_common(status);
-}
-
-/* Prettyprint the status register. Works for
- * SST 25VF016
- */
-void spi_prettyprint_status_register_sst25vf016(uint8_t status)
-{
-	const char *bpt[] = {
-		"none",
-		"1F0000H-1FFFFFH",
-		"1E0000H-1FFFFFH",
-		"1C0000H-1FFFFFH",
-		"180000H-1FFFFFH",
-		"100000H-1FFFFFH",
-		"all", "all"
-	};
-	spi_prettyprint_status_register_sst25(status);
-	printf_debug("Resulting block protection : %s\n",
-		     bpt[(status & 0x1c) >> 2]);
-}
-
-void spi_prettyprint_status_register_sst25vf040b(uint8_t status)
-{
-	const char *bpt[] = {
-		"none",
-		"0x70000-0x7ffff",
-		"0x60000-0x7ffff",
-		"0x40000-0x7ffff",
-		"all blocks", "all blocks", "all blocks", "all blocks"
-	};
-	spi_prettyprint_status_register_sst25(status);
-	printf_debug("Resulting block protection : %s\n",
-		bpt[(status & 0x1c) >> 2]);
-}
-
-void spi_prettyprint_status_register(struct flashchip *flash)
-{
-	uint8_t status;
-
-	status = spi_read_status_register();
-	printf_debug("Chip status register is %02x\n", status);
-	switch (flash->manufacture_id) {
-	case ST_ID:
-		if (((flash->model_id & 0xff00) == 0x2000) ||
-		    ((flash->model_id & 0xff00) == 0x2500))
-			spi_prettyprint_status_register_st_m25p(status);
-		break;
-	case MX_ID:
-		if ((flash->model_id & 0xff00) == 0x2000)
-			spi_prettyprint_status_register_st_m25p(status);
-		break;
-	case SST_ID:
-		switch (flash->model_id) {
-		case 0x2541:
-			spi_prettyprint_status_register_sst25vf016(status);
-			break;
-		case 0x8d:
-		case 0x258d:
-			spi_prettyprint_status_register_sst25vf040b(status);
-			break;
-		default:
-			spi_prettyprint_status_register_sst25(status);
-			break;
-		}
-		break;
-	}
-}
-
-int spi_chip_erase_60(struct flashchip *flash)
-{
-	int result;
-	struct spi_command cmds[] = {
-	{
-		.writecnt	= JEDEC_WREN_OUTSIZE,
-		.writearr	= (const unsigned char[]){ JEDEC_WREN },
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}, {
-		.writecnt	= JEDEC_CE_60_OUTSIZE,
-		.writearr	= (const unsigned char[]){ JEDEC_CE_60 },
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}, {
-		.writecnt	= 0,
-		.writearr	= NULL,
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}};
-	
-	result = spi_disable_blockprotect();
-	if (result) {
-		fprintf(stderr, "spi_disable_blockprotect failed\n");
-		return result;
-	}
-	
-	result = spi_send_multicommand(cmds);
-	if (result) {
-		fprintf(stderr, "%s failed during command execution\n",
-			__func__);
-		return result;
-	}
-	/* Wait until the Write-In-Progress bit is cleared.
-	 * This usually takes 1-85 s, so wait in 1 s steps.
-	 */
-	/* FIXME: We assume spi_read_status_register will never fail. */
-	while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
-		programmer_delay(1000 * 1000);
-	if (check_erased_range(flash, 0, flash->total_size * 1024)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-int spi_chip_erase_c7(struct flashchip *flash)
-{
-	int result;
-	struct spi_command cmds[] = {
-	{
-		.writecnt	= JEDEC_WREN_OUTSIZE,
-		.writearr	= (const unsigned char[]){ JEDEC_WREN },
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}, {
-		.writecnt	= JEDEC_CE_C7_OUTSIZE,
-		.writearr	= (const unsigned char[]){ JEDEC_CE_C7 },
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}, {
-		.writecnt	= 0,
-		.writearr	= NULL,
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}};
-
-	result = spi_disable_blockprotect();
-	if (result) {
-		fprintf(stderr, "spi_disable_blockprotect failed\n");
-		return result;
-	}
-
-	result = spi_send_multicommand(cmds);
-	if (result) {
-		fprintf(stderr, "%s failed during command execution\n", __func__);
-		return result;
-	}
-	/* Wait until the Write-In-Progress bit is cleared.
-	 * This usually takes 1-85 s, so wait in 1 s steps.
-	 */
-	/* FIXME: We assume spi_read_status_register will never fail. */
-	while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
-		programmer_delay(1000 * 1000);
-	if (check_erased_range(flash, 0, flash->total_size * 1024)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-int spi_chip_erase_60_c7(struct flashchip *flash)
-{
-	int result;
-	result = spi_chip_erase_60(flash);
-	if (result) {
-		printf_debug("spi_chip_erase_60 failed, trying c7\n");
-		result = spi_chip_erase_c7(flash);
-	}
-	return result;
-}
-
-int spi_block_erase_52(struct flashchip *flash, unsigned int addr, unsigned int blocklen)
-{
-	int result;
-	struct spi_command cmds[] = {
-	{
-		.writecnt	= JEDEC_WREN_OUTSIZE,
-		.writearr	= (const unsigned char[]){ JEDEC_WREN },
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}, {
-		.writecnt	= JEDEC_BE_52_OUTSIZE,
-		.writearr	= (const unsigned char[]){ JEDEC_BE_52, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff) },
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}, {
-		.writecnt	= 0,
-		.writearr	= NULL,
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}};
-
-	result = spi_send_multicommand(cmds);
-	if (result) {
-		fprintf(stderr, "%s failed during command execution at address 0x%x\n",
-			__func__, addr);
-		return result;
-	}
-	/* Wait until the Write-In-Progress bit is cleared.
-	 * This usually takes 100-4000 ms, so wait in 100 ms steps.
-	 */
-	while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
-		programmer_delay(100 * 1000);
-	if (check_erased_range(flash, addr, blocklen)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-/* Block size is usually
- * 64k for Macronix
- * 32k for SST
- * 4-32k non-uniform for EON
- */
-int spi_block_erase_d8(struct flashchip *flash, unsigned int addr, unsigned int blocklen)
-{
-	int result;
-	struct spi_command cmds[] = {
-	{
-		.writecnt	= JEDEC_WREN_OUTSIZE,
-		.writearr	= (const unsigned char[]){ JEDEC_WREN },
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}, {
-		.writecnt	= JEDEC_BE_D8_OUTSIZE,
-		.writearr	= (const unsigned char[]){ JEDEC_BE_D8, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff) },
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}, {
-		.writecnt	= 0,
-		.writearr	= NULL,
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}};
-
-	result = spi_send_multicommand(cmds);
-	if (result) {
-		fprintf(stderr, "%s failed during command execution at address 0x%x\n",
-			__func__, addr);
-		return result;
-	}
-	/* Wait until the Write-In-Progress bit is cleared.
-	 * This usually takes 100-4000 ms, so wait in 100 ms steps.
-	 */
-	while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
-		programmer_delay(100 * 1000);
-	if (check_erased_range(flash, addr, blocklen)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-int spi_chip_erase_d8(struct flashchip *flash)
-{
-	int i, rc = 0;
-	int total_size = flash->total_size * 1024;
-	int erase_size = 64 * 1024;
-
-	spi_disable_blockprotect();
-
-	printf("Erasing chip: \n");
-
-	for (i = 0; i < total_size / erase_size; i++) {
-		rc = spi_block_erase_d8(flash, i * erase_size, erase_size);
-		if (rc) {
-			fprintf(stderr, "Error erasing block at 0x%x\n", i);
-			break;
-		}
-	}
-
-	printf("\n");
-
-	return rc;
-}
-
-/* Sector size is usually 4k, though Macronix eliteflash has 64k */
-int spi_block_erase_20(struct flashchip *flash, unsigned int addr, unsigned int blocklen)
-{
-	int result;
-	struct spi_command cmds[] = {
-	{
-		.writecnt	= JEDEC_WREN_OUTSIZE,
-		.writearr	= (const unsigned char[]){ JEDEC_WREN },
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}, {
-		.writecnt	= JEDEC_SE_OUTSIZE,
-		.writearr	= (const unsigned char[]){ JEDEC_SE, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff) },
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}, {
-		.writecnt	= 0,
-		.writearr	= NULL,
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}};
-
-	result = spi_send_multicommand(cmds);
-	if (result) {
-		fprintf(stderr, "%s failed during command execution at address 0x%x\n",
-			__func__, addr);
-		return result;
-	}
-	/* Wait until the Write-In-Progress bit is cleared.
-	 * This usually takes 15-800 ms, so wait in 10 ms steps.
-	 */
-	while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
-		programmer_delay(10 * 1000);
-	if (check_erased_range(flash, addr, blocklen)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-int spi_block_erase_60(struct flashchip *flash, unsigned int addr, unsigned int blocklen)
-{
-	if ((addr != 0) || (blocklen != flash->total_size * 1024)) {
-		fprintf(stderr, "%s called with incorrect arguments\n",
-			__func__);
-		return -1;
-	}
-	return spi_chip_erase_60(flash);
-}
-
-int spi_block_erase_c7(struct flashchip *flash, unsigned int addr, unsigned int blocklen)
-{
-	if ((addr != 0) || (blocklen != flash->total_size * 1024)) {
-		fprintf(stderr, "%s called with incorrect arguments\n",
-			__func__);
-		return -1;
-	}
-	return spi_chip_erase_c7(flash);
-}
-
-int spi_write_status_enable(void)
-{
-	const unsigned char cmd[JEDEC_EWSR_OUTSIZE] = { JEDEC_EWSR };
-	int result;
-
-	/* Send EWSR (Enable Write Status Register). */
-	result = spi_send_command(sizeof(cmd), JEDEC_EWSR_INSIZE, cmd, NULL);
-
-	if (result)
-		fprintf(stderr, "%s failed\n", __func__);
-
-	return result;
-}
-
-/*
- * This is according the SST25VF016 datasheet, who knows it is more
- * generic that this...
- */
-int spi_write_status_register(int status)
-{
-	int result;
-	struct spi_command cmds[] = {
-	{
-		.writecnt	= JEDEC_EWSR_OUTSIZE,
-		.writearr	= (const unsigned char[]){ JEDEC_EWSR },
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}, {
-		.writecnt	= JEDEC_WRSR_OUTSIZE,
-		.writearr	= (const unsigned char[]){ JEDEC_WRSR, (unsigned char) status },
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}, {
-		.writecnt	= 0,
-		.writearr	= NULL,
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}};
-
-	result = spi_send_multicommand(cmds);
-	if (result) {
-		fprintf(stderr, "%s failed during command execution\n",
-			__func__);
-	}
-	return result;
-}
-
-int spi_byte_program(int addr, uint8_t byte)
-{
-	int result;
-	struct spi_command cmds[] = {
-	{
-		.writecnt	= JEDEC_WREN_OUTSIZE,
-		.writearr	= (const unsigned char[]){ JEDEC_WREN },
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}, {
-		.writecnt	= JEDEC_BYTE_PROGRAM_OUTSIZE,
-		.writearr	= (const unsigned char[]){ JEDEC_BYTE_PROGRAM, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff), byte },
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}, {
-		.writecnt	= 0,
-		.writearr	= NULL,
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}};
-
-	result = spi_send_multicommand(cmds);
-	if (result) {
-		fprintf(stderr, "%s failed during command execution at address 0x%x\n",
-			__func__, addr);
-	}
-	return result;
-}
-
-int spi_nbyte_program(int addr, uint8_t *bytes, int len)
-{
-	int result;
-	/* FIXME: Switch to malloc based on len unless that kills speed. */
-	unsigned char cmd[JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + 256] = {
-		JEDEC_BYTE_PROGRAM,
-		(addr >> 16) & 0xff,
-		(addr >> 8) & 0xff,
-		(addr >> 0) & 0xff,
-	};
-	struct spi_command cmds[] = {
-	{
-		.writecnt	= JEDEC_WREN_OUTSIZE,
-		.writearr	= (const unsigned char[]){ JEDEC_WREN },
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}, {
-		.writecnt	= JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + len,
-		.writearr	= cmd,
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}, {
-		.writecnt	= 0,
-		.writearr	= NULL,
-		.readcnt	= 0,
-		.readarr	= NULL,
-	}};
-
-	if (!len) {
-		fprintf(stderr, "%s called for zero-length write\n", __func__);
-		return 1;
-	}
-	if (len > 256) {
-		fprintf(stderr, "%s called for too long a write\n", __func__);
-		return 1;
-	}
-
-	memcpy(&cmd[4], bytes, len);
-
-	result = spi_send_multicommand(cmds);
-	if (result) {
-		fprintf(stderr, "%s failed during command execution at address 0x%x\n",
-			__func__, addr);
-	}
-	return result;
-}
-
-int spi_disable_blockprotect(void)
-{
-	uint8_t status;
-	int result;
-
-	status = spi_read_status_register();
-	/* If there is block protection in effect, unprotect it first. */
-	if ((status & 0x3c) != 0) {
-		printf_debug("Some block protection in effect, disabling\n");
-		result = spi_write_status_register(status & ~0x3c);
-		if (result) {
-			fprintf(stderr, "spi_write_status_register failed\n");
-			return result;
-		}
-	}
-	return 0;
-}
-
-int spi_nbyte_read(int address, uint8_t *bytes, int len)
-{
-	const unsigned char cmd[JEDEC_READ_OUTSIZE] = {
-		JEDEC_READ,
-		(address >> 16) & 0xff,
-		(address >> 8) & 0xff,
-		(address >> 0) & 0xff,
-	};
-
-	/* Send Read */
-	return spi_send_command(sizeof(cmd), len, cmd, bytes);
-}
-
-/*
- * Read a complete flash chip.
- * Each page is read separately in chunks with a maximum size of chunksize.
- */
-int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize)
-{
-	int rc = 0;
-	int i, j, starthere, lenhere;
-	int page_size = flash->page_size;
-	int toread;
-
-	/* Warning: This loop has a very unusual condition and body.
-	 * The loop needs to go through each page with at least one affected
-	 * byte. The lowest page number is (start / page_size) since that
-	 * division rounds down. The highest page number we want is the page
-	 * where the last byte of the range lives. That last byte has the
-	 * address (start + len - 1), thus the highest page number is
-	 * (start + len - 1) / page_size. Since we want to include that last
-	 * page as well, the loop condition uses <=.
-	 */
-	for (i = start / page_size; i <= (start + len - 1) / page_size; i++) {
-		/* Byte position of the first byte in the range in this page. */
-		/* starthere is an offset to the base address of the chip. */
-		starthere = max(start, i * page_size);
-		/* Length of bytes in the range in this page. */
-		lenhere = min(start + len, (i + 1) * page_size) - starthere;
-		for (j = 0; j < lenhere; j += chunksize) {
-			toread = min(chunksize, lenhere - j);
-			rc = spi_nbyte_read(starthere + j, buf + starthere - start + j, toread);
-			if (rc)
-				break;
-		}
-		if (rc)
-			break;
-	}
-
-	return rc;
-}
-
-int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len)
-{
-	if (!spi_programmer[spi_controller].read) {
-		fprintf(stderr, "%s called, but SPI read is unsupported on this"
-			" hardware. Please report a bug.\n", __func__);
-		return 1;
-	}
-
-	return spi_programmer[spi_controller].read(flash, buf, start, len);
-}
-
-/*
- * Program chip using byte programming. (SLOW!)
- * This is for chips which can only handle one byte writes
- * and for chips where memory mapped programming is impossible
- * (e.g. due to size constraints in IT87* for over 512 kB)
- */
-int spi_chip_write_1(struct flashchip *flash, uint8_t *buf)
-{
-	int total_size = 1024 * flash->total_size;
-	int i, result = 0;
-
-	spi_disable_blockprotect();
-	/* Erase first */
-	printf("Erasing flash before programming... ");
-	if (erase_flash(flash)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	printf("done.\n");
-	for (i = 0; i < total_size; i++) {
-		result = spi_byte_program(i, buf[i]);
-		if (result)
-			return 1;
-		while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
-			programmer_delay(10);
-	}
-
-	return 0;
-}
-
-/*
- * Program chip using page (256 bytes) programming.
- * Some SPI masters can't do this, they use single byte programming instead.
- */
-int spi_chip_write_256(struct flashchip *flash, uint8_t *buf)
-{
-	if (!spi_programmer[spi_controller].write_256) {
-		fprintf(stderr, "%s called, but SPI page write is unsupported "
-			" on this hardware. Please report a bug.\n", __func__);
-		return 1;
-	}
-
-	return spi_programmer[spi_controller].write_256(flash, buf);
-}
-
-uint32_t spi_get_valid_read_addr(void)
-{
-	/* Need to return BBAR for ICH chipsets. */
-	return 0;
-}
-
-int spi_aai_write(struct flashchip *flash, uint8_t *buf)
-{
-	uint32_t pos = 2, size = flash->total_size * 1024;
-	unsigned char w[6] = {0xad, 0, 0, 0, buf[0], buf[1]};
-	int result;
-
-	switch (spi_controller) {
-	case SPI_CONTROLLER_WBSIO:
-		fprintf(stderr, "%s: impossible with Winbond SPI masters,"
-				" degrading to byte program\n", __func__);
-		return spi_chip_write_1(flash, buf);
-	default:
-		break;
-	}
-	if (erase_flash(flash)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	result = spi_write_enable();
-	if (result)
-		return result;
-	spi_send_command(6, 0, w, NULL);
-	while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
-		programmer_delay(5); /* SST25VF040B Tbp is max 10us */
-	while (pos < size) {
-		w[1] = buf[pos++];
-		w[2] = buf[pos++];
-		spi_send_command(3, 0, w, NULL);
-		while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
-			programmer_delay(5); /* SST25VF040B Tbp is max 10us */
-	}
-	spi_write_disable();
-	return 0;
-}
diff --git a/spi.h b/spi.h
deleted file mode 100644
index 2fa7dcd..0000000
--- a/spi.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2007, 2008 Carl-Daniel Hailfinger
- *
- * 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; version 2 of the License.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#ifndef __SPI_H__
-#define __SPI_H__ 1
-
-/*
- * Contains the generic SPI headers
- */
-
-/* Read Electronic ID */
-#define JEDEC_RDID		0x9f
-#define JEDEC_RDID_OUTSIZE	0x01
-#define JEDEC_RDID_INSIZE	0x03
-
-/* AT25F512A has bit 3 as don't care bit in commands */
-#define AT25F512A_RDID		0x15
-#define AT25F512A_RDID_OUTSIZE	0x01
-#define AT25F512A_RDID_INSIZE	0x02
-
-/* Read Electronic Manufacturer Signature */
-#define JEDEC_REMS		0x90
-#define JEDEC_REMS_OUTSIZE	0x04
-#define JEDEC_REMS_INSIZE	0x02
-
-/* Read Electronic Signature */
-#define JEDEC_RES		0xab
-#define JEDEC_RES_OUTSIZE	0x04
-#define JEDEC_RES_INSIZE	0x01
-
-/* Write Enable */
-#define JEDEC_WREN		0x06
-#define JEDEC_WREN_OUTSIZE	0x01
-#define JEDEC_WREN_INSIZE	0x00
-
-/* Write Disable */
-#define JEDEC_WRDI		0x04
-#define JEDEC_WRDI_OUTSIZE	0x01
-#define JEDEC_WRDI_INSIZE	0x00
-
-/* Chip Erase 0x60 is supported by Macronix/SST chips. */
-#define JEDEC_CE_60		0x60
-#define JEDEC_CE_60_OUTSIZE	0x01
-#define JEDEC_CE_60_INSIZE	0x00
-
-/* Chip Erase 0xc7 is supported by SST/ST/EON/Macronix chips. */
-#define JEDEC_CE_C7		0xc7
-#define JEDEC_CE_C7_OUTSIZE	0x01
-#define JEDEC_CE_C7_INSIZE	0x00
-
-/* Block Erase 0x52 is supported by SST and old Atmel chips. */
-#define JEDEC_BE_52		0x52
-#define JEDEC_BE_52_OUTSIZE	0x04
-#define JEDEC_BE_52_INSIZE	0x00
-
-/* Block Erase 0xd8 is supported by EON/Macronix chips. */
-#define JEDEC_BE_D8		0xd8
-#define JEDEC_BE_D8_OUTSIZE	0x04
-#define JEDEC_BE_D8_INSIZE	0x00
-
-/* Sector Erase 0x20 is supported by Macronix/SST chips. */
-#define JEDEC_SE		0x20
-#define JEDEC_SE_OUTSIZE	0x04
-#define JEDEC_SE_INSIZE		0x00
-
-/* Read Status Register */
-#define JEDEC_RDSR		0x05
-#define JEDEC_RDSR_OUTSIZE	0x01
-#define JEDEC_RDSR_INSIZE	0x01
-#define JEDEC_RDSR_BIT_WIP	(0x01 << 0)
-
-/* Write Status Enable */
-#define JEDEC_EWSR		0x50
-#define JEDEC_EWSR_OUTSIZE	0x01
-#define JEDEC_EWSR_INSIZE	0x00
-
-/* Write Status Register */
-#define JEDEC_WRSR		0x01
-#define JEDEC_WRSR_OUTSIZE	0x02
-#define JEDEC_WRSR_INSIZE	0x00
-
-/* Read the memory */
-#define JEDEC_READ		0x03
-#define JEDEC_READ_OUTSIZE	0x04
-/*      JEDEC_READ_INSIZE : any length */
-
-/* Write memory byte */
-#define JEDEC_BYTE_PROGRAM	0x02
-#define JEDEC_BYTE_PROGRAM_OUTSIZE	0x05
-#define JEDEC_BYTE_PROGRAM_INSIZE	0x00
-
-/* Error codes */
-#define SPI_GENERIC_ERROR	-1
-#define SPI_INVALID_OPCODE	-2
-#define SPI_INVALID_ADDRESS	-3
-#define SPI_INVALID_LENGTH	-4
-
-#endif		/* !__SPI_H__ */
diff --git a/sst28sf040.c b/sst28sf040.c
deleted file mode 100644
index 930ad5b..0000000
--- a/sst28sf040.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- * Copyright (C) 2005 coresystems GmbH <stepan@openbios.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "flash.h"
-
-#define AUTO_PG_ERASE1		0x20
-#define AUTO_PG_ERASE2		0xD0
-#define AUTO_PGRM		0x10
-#define CHIP_ERASE		0x30
-#define RESET			0xFF
-#define READ_ID			0x90
-
-static void protect_28sf040(chipaddr bios)
-{
-	chip_readb(bios + 0x1823);
-	chip_readb(bios + 0x1820);
-	chip_readb(bios + 0x1822);
-	chip_readb(bios + 0x0418);
-	chip_readb(bios + 0x041B);
-	chip_readb(bios + 0x0419);
-	chip_readb(bios + 0x040A);
-}
-
-static void unprotect_28sf040(chipaddr bios)
-{
-	chip_readb(bios + 0x1823);
-	chip_readb(bios + 0x1820);
-	chip_readb(bios + 0x1822);
-	chip_readb(bios + 0x0418);
-	chip_readb(bios + 0x041B);
-	chip_readb(bios + 0x0419);
-	chip_readb(bios + 0x041A);
-}
-
-static int erase_sector_28sf040(struct flashchip *flash, unsigned long address, int sector_size)
-{
-	chipaddr bios = flash->virtual_memory;
-
-	chip_writeb(AUTO_PG_ERASE1, bios);
-	chip_writeb(AUTO_PG_ERASE2, bios + address);
-
-	/* wait for Toggle bit ready         */
-	toggle_ready_jedec(bios);
-
-	if (check_erased_range(flash, address, sector_size)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-static int write_sector_28sf040(chipaddr bios, uint8_t *src, chipaddr dst,
-				unsigned int page_size)
-{
-	int i;
-
-	for (i = 0; i < page_size; i++) {
-		/* transfer data from source to destination */
-		if (*src == 0xFF) {
-			dst++, src++;
-			/* If the data is 0xFF, don't program it */
-			continue;
-		}
-		/*issue AUTO PROGRAM command */
-		chip_writeb(AUTO_PGRM, dst);
-		chip_writeb(*src++, dst++);
-
-		/* wait for Toggle bit ready */
-		toggle_ready_jedec(bios);
-	}
-
-	return 0;
-}
-
-int probe_28sf040(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-	uint8_t id1, id2;
-
-	chip_writeb(RESET, bios);
-	programmer_delay(10);
-
-	chip_writeb(READ_ID, bios);
-	programmer_delay(10);
-	id1 = chip_readb(bios);
-	programmer_delay(10);
-	id2 = chip_readb(bios + 0x01);
-
-	chip_writeb(RESET, bios);
-	programmer_delay(10);
-
-	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
-	if (id1 == flash->manufacture_id && id2 == flash->model_id)
-		return 1;
-
-	return 0;
-}
-
-int erase_28sf040(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-
-	unprotect_28sf040(bios);
-	chip_writeb(CHIP_ERASE, bios);
-	chip_writeb(CHIP_ERASE, bios);
-	protect_28sf040(bios);
-
-	programmer_delay(10);
-	toggle_ready_jedec(bios);
-
-	if (check_erased_range(flash, 0, flash->total_size * 1024)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-int write_28sf040(struct flashchip *flash, uint8_t *buf)
-{
-	int i;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-	chipaddr bios = flash->virtual_memory;
-
-	unprotect_28sf040(bios);
-
-	printf("Programming page: ");
-	for (i = 0; i < total_size / page_size; i++) {
-		/* erase the page before programming */
-		if (erase_sector_28sf040(flash, i * page_size, page_size)) {
-			fprintf(stderr, "ERASE FAILED!\n");
-			return -1;
-		}
-
-		/* write to the sector */
-		printf("%04d at address: 0x%08x", i, i * page_size);
-		write_sector_28sf040(bios, buf + i * page_size,
-				     bios + i * page_size, page_size);
-		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-	}
-	printf("\n");
-
-	protect_28sf040(bios);
-
-	return 0;
-}
diff --git a/sst49lf040.c b/sst49lf040.c
deleted file mode 100644
index ab1c918..0000000
--- a/sst49lf040.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "flash.h"
-
-int erase_49lf040(struct flashchip *flash)
-{
-	int i;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-
-	for (i = 0; i < total_size / page_size; i++) {
-		/* Chip erase only works in parallel programming mode
-		 * for the 49lf040. Use sector-erase instead */
-		if (erase_sector_jedec(flash, i * page_size, page_size)) {
-			fprintf(stderr, "ERASE FAILED!\n");
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-int write_49lf040(struct flashchip *flash, uint8_t *buf)
-{
-	int i;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-	chipaddr bios = flash->virtual_memory;
-
-	printf("Programming page: ");
-	for (i = 0; i < total_size / page_size; i++) {
-		/* erase the page before programming
-		 * Chip erase only works in parallel programming mode
-		 * for the 49lf040. Use sector-erase instead */
-		if (erase_sector_jedec(flash, i * page_size, page_size)) {
-			fprintf(stderr, "ERASE FAILED!\n");
-			return -1;
-		}
-
-		/* write to the sector */
-		if (i % 10 == 0)
-			printf("%04d at address: 0x%08x ", i, i * page_size);
-
-		write_sector_jedec(bios, buf + i * page_size,
-				   bios + i * page_size, page_size);
-
-		if (i % 10 == 0)
-			printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-		fflush(stdout);
-	}
-	printf("\n");
-
-	return 0;
-}
diff --git a/sst49lfxxxc.c b/sst49lfxxxc.c
deleted file mode 100644
index a421acf..0000000
--- a/sst49lfxxxc.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- * Copyright (C) 2005-2007 coresystems GmbH
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdlib.h>
-#include "flash.h"
-
-#define SECTOR_ERASE		0x30
-#define BLOCK_ERASE		0x20
-#define ERASE			0xD0
-#define AUTO_PGRM		0x10
-#define RESET			0xFF
-#define READ_ID			0x90
-#define READ_STATUS		0x70
-#define CLEAR_STATUS		0x50
-
-#define STATUS_BPS		(1 << 1)
-#define	STATUS_ESS		(1 << 6)
-#define	STATUS_WSMS		(1 << 7)
-
-static int write_lockbits_49lfxxxc(struct flashchip *flash, unsigned char bits)
-{
-	chipaddr registers = flash->virtual_registers;
-	int i, left = flash->total_size * 1024;
-	unsigned long address;
-
-	printf_debug("\nbios=0x%08lx\n", registers);
-	for (i = 0; left > 65536; i++, left -= 65536) {
-		printf_debug("lockbits at address=0x%08lx is 0x%01x\n",
-			     registers + (i * 65536) + 2,
-			     chip_readb(registers + (i * 65536) + 2));
-		chip_writeb(bits, registers + (i * 65536) + 2);
-	}
-	address = i * 65536;
-	printf_debug("lockbits at address=0x%08lx is 0x%01x\n",
-		     registers + address + 2,
-		     chip_readb(registers + address + 2));
-	chip_writeb(bits, registers + address + 2);
-	address += 32768;
-	printf_debug("lockbits at address=0x%08lx is 0x%01x\n",
-		     registers + address + 2,
-		     chip_readb(registers + address + 2));
-	chip_writeb(bits, registers + address + 2);
-	address += 8192;
-	printf_debug("lockbits at address=0x%08lx is 0x%01x\n",
-		     registers + address + 2,
-		     chip_readb(registers + address + 2));
-	chip_writeb(bits, registers + address + 2);
-	address += 8192;
-	printf_debug("lockbits at address=0x%08lx is 0x%01x\n",
-		     registers + address + 2,
-		     chip_readb(registers + address + 2));
-	chip_writeb(bits, registers + address + 2);
-
-	return 0;
-}
-
-static int erase_sector_49lfxxxc(struct flashchip *flash, unsigned long address, int sector_size)
-{
-	unsigned char status;
-	chipaddr bios = flash->virtual_memory;
-
-	chip_writeb(SECTOR_ERASE, bios);
-	chip_writeb(ERASE, bios + address);
-
-	do {
-		status = chip_readb(bios);
-		if (status & (STATUS_ESS | STATUS_BPS)) {
-			printf("sector erase FAILED at address=0x%08lx status=0x%01x\n", bios + address, status);
-			chip_writeb(CLEAR_STATUS, bios);
-			return (-1);
-		}
-	} while (!(status & STATUS_WSMS));
-	chip_writeb(RESET, bios);
-
-	if (check_erased_range(flash, address, sector_size)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-static int write_sector_49lfxxxc(chipaddr bios, uint8_t *src, chipaddr dst,
-				 unsigned int page_size)
-{
-	int i;
-	unsigned char status;
-
-	chip_writeb(CLEAR_STATUS, bios);
-	for (i = 0; i < page_size; i++) {
-		/* transfer data from source to destination */
-		if (*src == 0xFF) {
-			dst++, src++;
-			/* If the data is 0xFF, don't program it */
-			continue;
-		}
-		/*issue AUTO PROGRAM command */
-		chip_writeb(AUTO_PGRM, bios);
-		chip_writeb(*src++, dst++);
-
-		do {
-			status = chip_readb(bios);
-			if (status & (STATUS_ESS | STATUS_BPS)) {
-				printf("sector write FAILED at address=0x%08lx status=0x%01x\n", dst, status);
-				chip_writeb(CLEAR_STATUS, bios);
-				return (-1);
-			}
-		} while (!(status & STATUS_WSMS));
-	}
-
-	return 0;
-}
-
-int probe_49lfxxxc(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-	uint8_t id1, id2;
-
-	chip_writeb(RESET, bios);
-
-	chip_writeb(READ_ID, bios);
-	id1 = chip_readb(bios);
-	id2 = chip_readb(bios + 0x01);
-
-	chip_writeb(RESET, bios);
-
-	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
-
-	if (!(id1 == flash->manufacture_id && id2 == flash->model_id))
-		return 0;
-
-	map_flash_registers(flash);
-
-	return 1;
-}
-
-int erase_49lfxxxc(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-	int i;
-	unsigned int total_size = flash->total_size * 1024;
-
-	write_lockbits_49lfxxxc(flash, 0);
-	for (i = 0; i < total_size; i += flash->page_size)
-		if (erase_sector_49lfxxxc(flash, i, flash->page_size))
-			return (-1);
-
-	chip_writeb(RESET, bios);
-
-	return 0;
-}
-
-int write_49lfxxxc(struct flashchip *flash, uint8_t *buf)
-{
-	int i;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-	chipaddr bios = flash->virtual_memory;
-
-	write_lockbits_49lfxxxc(flash, 0);
-	printf("Programming page: ");
-	for (i = 0; i < total_size / page_size; i++) {
-		/* erase the page before programming */
-		if (erase_sector_49lfxxxc(flash, i * page_size, flash->page_size)) {
-			fprintf(stderr, "ERASE FAILED!\n");
-			return -1;
-		}
-
-		/* write to the sector */
-		printf("%04d at address: 0x%08x", i, i * page_size);
-		write_sector_49lfxxxc(bios, buf + i * page_size,
-				      bios + i * page_size, page_size);
-		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-	}
-	printf("\n");
-
-	chip_writeb(RESET, bios);
-
-	return 0;
-}
diff --git a/sst_fwhub.c b/sst_fwhub.c
deleted file mode 100644
index f09aa54..0000000
--- a/sst_fwhub.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- * Copyright (C) 2009 Kontron Modular Computers
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/* Adapted from the Intel FW hub stuff for 82802ax parts. */
-
-#include <stdlib.h>
-#include <string.h>
-#include "flash.h"
-
-// I need that Berkeley bit-map printer
-void print_sst_fwhub_status(uint8_t status)
-{
-	printf("%s", status & 0x80 ? "Ready:" : "Busy:");
-	printf("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:");
-	printf("%s", status & 0x20 ? "BE ERROR:" : "BE OK:");
-	printf("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:");
-	printf("%s", status & 0x8 ? "VP ERR:" : "VPP OK:");
-	printf("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:");
-	printf("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:");
-}
-
-int check_sst_fwhub_block_lock(struct flashchip *flash, int offset)
-{
-	chipaddr registers = flash->virtual_registers;
-	uint8_t blockstatus;
-
-	blockstatus = chip_readb(registers + offset + 2);
-	printf_debug("Lock status for 0x%06x (size 0x%06x) is %02x, ",
-		     offset, flash->page_size, blockstatus);
-	switch (blockstatus & 0x3) {
-	case 0x0:
-		printf_debug("full access\n");
-		break;
-	case 0x1:
-		printf_debug("write locked\n");
-		break;
-	case 0x2:
-		printf_debug("locked open\n");
-		break;
-	case 0x3:
-		printf_debug("write locked down\n");
-		break;
-	}
-	/* Return content of the write_locked bit */
-	return blockstatus & 0x1;
-}
-
-int clear_sst_fwhub_block_lock(struct flashchip *flash, int offset)
-{
-	chipaddr registers = flash->virtual_registers;
-	uint8_t blockstatus;
-
-	blockstatus = check_sst_fwhub_block_lock(flash, offset);
-
-	if (blockstatus) {
-		printf_debug("Trying to clear lock for 0x%06x... ", offset)
-		chip_writeb(0, registers + offset + 2);
-
-		blockstatus = check_sst_fwhub_block_lock(flash, offset);
-		printf_debug("%s\n", (blockstatus) ? "failed" : "OK");
-	}
-
-	return blockstatus;
-}
-
-/* probe_jedec works fine for probing */
-int probe_sst_fwhub(struct flashchip *flash)
-{
-	int i;
-
-	if (probe_jedec(flash) == 0)
-		return 0;
-
-	map_flash_registers(flash);
-
-	for (i = 0; i < flash->total_size * 1024; i += flash->page_size)
-		check_sst_fwhub_block_lock(flash, i);
-
-	return 1;
-}
-
-int erase_sst_fwhub_block(struct flashchip *flash, unsigned int offset, unsigned int page_size)
-{
-	uint8_t blockstatus = clear_sst_fwhub_block_lock(flash, offset);
-
-	if (blockstatus) {
-		printf("Block lock clearing failed, not erasing block "
-			"at 0x%06x\n", offset);
-		return 1;
-	}
-
-	if (erase_block_jedec(flash, offset, page_size)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	toggle_ready_jedec(flash->virtual_memory);
-
-	return 0;
-}
-
-int erase_sst_fwhub(struct flashchip *flash)
-{
-	int i;
-	unsigned int total_size = flash->total_size * 1024;
-
-	for (i = 0; i < total_size; i += flash->page_size) {
-		if (erase_sst_fwhub_block(flash, i, flash->page_size)) {
-			fprintf(stderr, "ERASE FAILED!\n");
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-int write_sst_fwhub(struct flashchip *flash, uint8_t *buf)
-{
-	int i, rc;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-	chipaddr bios = flash->virtual_memory;
-	uint8_t *readbuf = malloc(page_size);
-	
-	printf("Programming page: ");
-	for (i = 0; i < total_size / page_size; i++) {
-		printf("%04d at address: 0x%08x", i, i * page_size);
-
-		/* Auto Skip Blocks, which already contain the desired data:
-		 * Faster, because we only write, what has changed
-		 * More secure, because blocks, which are excluded
-		 * (with the exclude or layout feature)
-		 * are not erased and rewritten; data is retained also
-		 * in sudden power off situations
-		 */
-		flash->read(flash, readbuf, i * page_size, page_size);
-		if (memcmp((void *)(buf + i * page_size),
-			   (void *)(readbuf), page_size)) {
-			rc = erase_sst_fwhub_block(flash, i * page_size,
-						   page_size);
-			if (rc)
-				return 1;
-			write_sector_jedec(bios, buf + i * page_size,
-					   bios + i * page_size, page_size);
-		}
-		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-	}
-	printf("\n");
-
-	return 0;
-}
diff --git a/stm50flw0x0x.c b/stm50flw0x0x.c
deleted file mode 100644
index 0ae6eb8..0000000
--- a/stm50flw0x0x.c
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2008 Claus Gindhart <claus.gindhart@kontron.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/*
- * This module is designed for supporting the devices
- * ST M50FLW040A (not yet tested)
- * ST M50FLW040B (not yet tested)
- * ST M50FLW080A
- * ST M50FLW080B (not yet tested)
- */
-
-#include <string.h>
-#include <stdlib.h>
-#include "flash.h"
-#include "flashchips.h"
-
-int probe_stm50flw0x0x(struct flashchip *flash)
-{
-	int result = probe_jedec(flash);
-
-	if (!result)
-		return result;
-
-	map_flash_registers(flash);
-
-	return 1;
-}
-
-static void wait_stm50flw0x0x(chipaddr bios)
-{
-	chip_writeb(0x70, bios);
-	if ((chip_readb(bios) & 0x80) == 0) {	// it's busy
-		while ((chip_readb(bios) & 0x80) == 0) ;
-	}
-
-	// put another command to get out of status register mode
-
-	chip_writeb(0x90, bios);
-	programmer_delay(10);
-
-	chip_readb(bios); // Read device ID (to make sure?)
-
-	// this is needed to jam it out of "read id" mode
-	chip_writeb(0xAA, bios + 0x5555);
-	chip_writeb(0x55, bios + 0x2AAA);
-	chip_writeb(0xF0, bios + 0x5555);
-}
-
-/*
- * claus.gindhart@kontron.com
- * The ST M50FLW080B and STM50FLW080B chips have to be unlocked,
- * before you can erase them or write to them.
- */
-int unlock_block_stm50flw0x0x(struct flashchip *flash, int offset)
-{
-	chipaddr wrprotect = flash->virtual_registers + 2;
-	const uint8_t unlock_sector = 0x00;
-	int j;
-
-	/*
-	 * These chips have to be unlocked before you can erase them or write
-	 * to them. The size of the locking sectors depends on the type
-	 * of chip.
-	 *
-	 * Sometimes, the BIOS does this for you; so you propably
-	 * don't need to worry about that.
-	 */
-
-	/* Check, if it's is a top/bottom-block with 4k-sectors. */
-	/* TODO: What about the other types? */
-	if ((offset == 0) ||
-	    (offset == (flash->model_id == ST_M50FLW080A ? 0xE0000 : 0x10000))
-	    || (offset == 0xF0000)) {
-
-		// unlock each 4k-sector
-		for (j = 0; j < 0x10000; j += 0x1000) {
-			printf_debug("unlocking at 0x%x\n", offset + j);
-			chip_writeb(unlock_sector, wrprotect + offset + j);
-			if (chip_readb(wrprotect + offset + j) != unlock_sector) {
-				printf("Cannot unlock sector @ 0x%x\n",
-				       offset + j);
-				return -1;
-			}
-		}
-	} else {
-		printf_debug("unlocking at 0x%x\n", offset);
-		chip_writeb(unlock_sector, wrprotect + offset);
-		if (chip_readb(wrprotect + offset) != unlock_sector) {
-			printf("Cannot unlock sector @ 0x%x\n", offset);
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-int erase_block_stm50flw0x0x(struct flashchip *flash, int offset)
-{
-	chipaddr bios = flash->virtual_memory + offset;
-
-	// clear status register
-	chip_writeb(0x50, bios);
-	printf_debug("Erase at 0x%lx\n", bios);
-	// now start it
-	chip_writeb(0x20, bios);
-	chip_writeb(0xd0, bios);
-	programmer_delay(10);
-
-	wait_stm50flw0x0x(flash->virtual_memory);
-
-	if (check_erased_range(flash, offset, flash->page_size)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	printf("DONE BLOCK 0x%x\n", offset);
-
-	return 0;
-}
-
-int write_page_stm50flw0x0x(chipaddr bios, uint8_t *src,
-			    chipaddr dst, int page_size)
-{
-	int i, rc = 0;
-	chipaddr d = dst;
-	uint8_t *s = src;
-
-	/* transfer data from source to destination */
-	for (i = 0; i < page_size; i++) {
-		chip_writeb(0x40, dst);
-		chip_writeb(*src++, dst++);
-		wait_stm50flw0x0x(bios);
-	}
-
-/* claus.gindhart@kontron.com
- * TODO
- * I think, that verification is not required, but
- * i leave it in anyway
- */
-	dst = d;
-	src = s;
-	for (i = 0; i < page_size; i++) {
-		if (chip_readb(dst) != *src) {
-			rc = -1;
-			break;
-		}
-		dst++;
-		src++;
-	}
-
-	if (rc) {
-		fprintf(stderr, " page 0x%lx failed!\n",
-			(d - bios) / page_size);
-	}
-
-	return rc;
-}
-
-/* I simply erase block by block
- * I Chip This is not the fastest way, but it works
- */
-int erase_stm50flw0x0x(struct flashchip *flash)
-{
-	int i;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-
-	printf("Erasing page:\n");
-	for (i = 0; i < total_size / page_size; i++) {
-		printf
-		    ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-		printf("%04d at address: 0x%08x ", i, i * page_size);
-		if (unlock_block_stm50flw0x0x(flash, i * page_size)) {
-			fprintf(stderr, "UNLOCK FAILED!\n");
-			return -1;
-		}
-		if (erase_block_stm50flw0x0x(flash, i * page_size)) {
-			fprintf(stderr, "ERASE FAILED!\n");
-			return -1;
-		}
-	}
-	printf("\n");
-
-	return 0;
-}
-
-int write_stm50flw0x0x(struct flashchip *flash, uint8_t * buf)
-{
-	int i, rc = 0;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-	chipaddr bios = flash->virtual_memory;
-	uint8_t *tmpbuf = malloc(page_size);
-
-	if (!tmpbuf) {
-		printf("Could not allocate memory!\n");
-		exit(1);
-	}
-	printf("Programming page: \n");
-	for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
-		printf
-		    ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-		printf("%04d at address: 0x%08x ", i, i * page_size);
-
-		/* Auto Skip Blocks, which already contain the desired data
-		 * Faster, because we only write, what has changed
-		 * More secure, because blocks, which are excluded
-		 * (with the exclude or layout feature)
-		 * are not erased and rewritten; data is retained also
-		 * in sudden power off situations
-		 */
-		chip_readn(tmpbuf, bios + i * page_size, page_size);
-		if (!memcmp((void *)(buf + i * page_size), tmpbuf, page_size)) {
-			printf("SKIPPED\n");
-			continue;
-		}
-
-		rc = unlock_block_stm50flw0x0x(flash, i * page_size);
-		if (!rc)
-			rc = erase_block_stm50flw0x0x(flash, i * page_size);
-		if (!rc)
-			write_page_stm50flw0x0x(bios, buf + i * page_size,
-					bios + i * page_size, page_size);
-	}
-	printf("\n");
-	free(tmpbuf);
-
-	return rc;
-}
diff --git a/udelay.c b/udelay.c
deleted file mode 100644
index 9a0ab36..0000000
--- a/udelay.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <sys/time.h>
-#include "flash.h"
-
-// count to a billion. Time it. If it's < 1 sec, count to 10B, etc.
-unsigned long micro = 1;
-
-void myusec_delay(int usecs)
-{
-	volatile unsigned long i;
-	for (i = 0; i < usecs * micro; i++) ;
-}
-
-void myusec_calibrate_delay(void)
-{
-	int count = 1000;
-	unsigned long timeusec;
-	struct timeval start, end;
-	int ok = 0;
-
-	printf("Calibrating delay loop... ");
-
-	while (!ok) {
-		gettimeofday(&start, 0);
-		myusec_delay(count);
-		gettimeofday(&end, 0);
-		timeusec = 1000000 * (end.tv_sec - start.tv_sec) +
-		    (end.tv_usec - start.tv_usec);
-		count *= 2;
-		if (timeusec < 1000000 / 4)
-			continue;
-		ok = 1;
-	}
-
-	// compute one microsecond. That will be count / time
-	micro = count / timeusec;
-
-	gettimeofday(&start, 0);
-	myusec_delay(100);
-	gettimeofday(&end, 0);
-	timeusec = 1000000 * (end.tv_sec - start.tv_sec) +
-	    (end.tv_usec - start.tv_usec);
-	printf_debug("%ldM loops per second, 100 myus = %ld us. ",
-		     (unsigned long)micro, timeusec);
-	printf("OK.\n");
-}
diff --git a/w29ee011.c b/w29ee011.c
deleted file mode 100644
index de9a547..0000000
--- a/w29ee011.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2007 Markus Boas <ryven@ryven.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <string.h>
-#include "flash.h"
-
-int probe_w29ee011(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-	uint8_t id1, id2;
-	extern char *chip_to_probe;
-
-	if (!chip_to_probe || strcmp(chip_to_probe, "W29EE011")) {
-		printf_debug("Probing disabled for Winbond W29EE011 because "
-			     "the probing sequence puts the AMIC A49LF040A in "
-			     "a funky state. Use 'flashrom -c W29EE011' if you "
-			     "have a board with this chip.\n");
-		return 0;
-	}
-
-	/* Issue JEDEC Product ID Entry command */
-	chip_writeb(0xAA, bios + 0x5555);
-	programmer_delay(10);
-	chip_writeb(0x55, bios + 0x2AAA);
-	programmer_delay(10);
-	chip_writeb(0x80, bios + 0x5555);
-	programmer_delay(10);
-	chip_writeb(0xAA, bios + 0x5555);
-	programmer_delay(10);
-	chip_writeb(0x55, bios + 0x2AAA);
-	programmer_delay(10);
-	chip_writeb(0x60, bios + 0x5555);
-	programmer_delay(10);
-
-	/* Read product ID */
-	id1 = chip_readb(bios);
-	id2 = chip_readb(bios + 0x01);
-
-	/* Issue JEDEC Product ID Exit command */
-	chip_writeb(0xAA, bios + 0x5555);
-	programmer_delay(10);
-	chip_writeb(0x55, bios + 0x2AAA);
-	programmer_delay(10);
-	chip_writeb(0xF0, bios + 0x5555);
-	programmer_delay(10);
-
-	printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
-
-	if (id1 == flash->manufacture_id && id2 == flash->model_id)
-		return 1;
-
-	return 0;
-}
diff --git a/w39v040c.c b/w39v040c.c
deleted file mode 100644
index 722ae29..0000000
--- a/w39v040c.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2008 Peter Stuge <peter@stuge.se>
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "flash.h"
-
-int probe_w39v040c(struct flashchip *flash)
-{
-	chipaddr bios = flash->virtual_memory;
-	int result = probe_jedec(flash);
-	uint8_t lock;
-
-	if (!result)
-		return result;
-
-	chip_writeb(0xAA, bios + 0x5555);
-	programmer_delay(10);
-	chip_writeb(0x55, bios + 0x2AAA);
-	programmer_delay(10);
-	chip_writeb(0x90, bios + 0x5555);
-	programmer_delay(10);
-
-	lock = chip_readb(bios + 0xfff2);
-
-	chip_writeb(0xAA, bios + 0x5555);
-	programmer_delay(10);
-	chip_writeb(0x55, bios + 0x2AAA);
-	programmer_delay(10);
-	chip_writeb(0xF0, bios + 0x5555);
-	programmer_delay(40);
-
-	printf("%s: Boot block #TBL is %slocked, rest of chip #WP is %slocked.\n",
-		__func__, lock & 0x4 ? "" : "un", lock & 0x8 ? "" : "un");
-	return 1;
-}
-
-int erase_w39v040c(struct flashchip *flash)
-{
-	int i;
-	unsigned int total_size = flash->total_size * 1024;
-
-	for (i = 0; i < total_size; i += flash->page_size) {
-		if (erase_sector_jedec(flash, i, flash->page_size)) {
-			fprintf(stderr, "ERASE FAILED!\n");
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-int write_w39v040c(struct flashchip *flash, uint8_t *buf)
-{
-	int i;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-	chipaddr bios = flash->virtual_memory;
-
-	if (erase_flash(flash)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-
-	printf("Programming page: ");
-	for (i = 0; i < total_size / page_size; i++) {
-		printf("%04d at address: 0x%08x", i, i * page_size);
-		write_sector_jedec(bios, buf + i * page_size,
-				   bios + i * page_size, page_size);
-		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-	}
-	printf("\n");
-
-	return 0;
-}
diff --git a/w39v080fa.c b/w39v080fa.c
deleted file mode 100644
index 580657f..0000000
--- a/w39v080fa.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2008 coresystems GmbH
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "flash.h"
-
-int probe_winbond_fwhub(struct flashchip *flash)
-{
-	int result = probe_jedec(flash);
-
-	if (!result)
-		return result;
-
-	map_flash_registers(flash);
-
-	return 1;
-}
-
-static int unlock_block_winbond_fwhub(struct flashchip *flash, int offset)
-{
-	chipaddr wrprotect = flash->virtual_registers + offset + 2;
-	uint8_t locking;
-
-	printf_debug("Trying to unlock block @0x%08x = 0x%02x\n", offset,
-		     chip_readb(wrprotect));
-
-	locking = chip_readb(wrprotect);
-	switch (locking & 0x7) {
-	case 0:
-		printf_debug("Full Access.\n");
-		return 0;
-	case 1:
-		printf_debug("Write Lock (Default State).\n");
-		chip_writeb(0, wrprotect);
-		return 0;
-	case 2:
-		printf_debug("Locked Open (Full Access, Lock Down).\n");
-		return 0;
-	case 3:
-		fprintf(stderr, "Error: Write Lock, Locked Down.\n");
-		return -1;
-	case 4:
-		printf_debug("Read Lock.\n");
-		chip_writeb(0, wrprotect);
-		return 0;
-	case 5:
-		printf_debug("Read/Write Lock.\n");
-		chip_writeb(0, wrprotect);
-		return 0;
-	case 6:
-		fprintf(stderr, "Error: Read Lock, Locked Down.\n");
-		return -1;
-	case 7:
-		fprintf(stderr, "Error: Read/Write Lock, Locked Down.\n");
-		return -1;
-	}
-
-	/* We will never reach this point, but GCC doesn't know */
-	return -1;
-}
-
-int unlock_winbond_fwhub(struct flashchip *flash)
-{
-	int i, total_size = flash->total_size * 1024;
-	chipaddr bios = flash->virtual_memory;
-	uint8_t locking;
-
-	/* Are there any hardware restrictions that we can't overcome? 
-	 * If flashrom fail here, someone's got to check all those GPIOs.
-	 */
-
-	/* Product Identification Entry */
-	chip_writeb(0xAA, bios + 0x5555);
-	chip_writeb(0x55, bios + 0x2AAA);
-	chip_writeb(0x90, bios + 0x5555);
-	programmer_delay(10);
-
-	/* Read Hardware Lock Bits */
-	locking = chip_readb(bios + 0xffff2);
-
-	/* Product Identification Exit */
-	chip_writeb(0xAA, bios + 0x5555);
-	chip_writeb(0x55, bios + 0x2AAA);
-	chip_writeb(0xF0, bios + 0x5555);
-	programmer_delay(10);
-
-	printf_debug("Lockout bits:\n");
-
-	if (locking & (1 << 2))
-		fprintf(stderr, "Error: hardware bootblock locking (#TBL).\n");
-	else
-		printf_debug("No hardware bootblock locking (good!)\n");
-
-	if (locking & (1 << 3))
-		fprintf(stderr, "Error: hardware block locking (#WP).\n");
-	else
-		printf_debug("No hardware block locking (good!)\n");
-
-	if (locking & ((1 << 2) | (1 << 3)))
-		return -1;
-
-	/* Unlock the complete chip */
-	for (i = 0; i < total_size; i += flash->page_size)
-		if (unlock_block_winbond_fwhub(flash, i))
-			return -1;
-
-	return 0;
-}
-
-static int erase_sector_winbond_fwhub(struct flashchip *flash,
-				      unsigned int sector)
-{
-	chipaddr bios = flash->virtual_memory;
-	/* Remember: too much sleep can waste your day. */
-
-	printf("0x%08x\b\b\b\b\b\b\b\b\b\b", sector);
-
-	/* Sector Erase */
-	chip_writeb(0xAA, bios + 0x5555);
-	chip_writeb(0x55, bios + 0x2AAA);
-	chip_writeb(0x80, bios + 0x5555);
-
-	chip_writeb(0xAA, bios + 0x5555);
-	chip_writeb(0x55, bios + 0x2AAA);
-	chip_writeb(0x30, bios + sector);
-
-	/* wait for Toggle bit ready */
-	toggle_ready_jedec(bios);
-
-	if (check_erased_range(flash, sector, flash->page_size)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-	return 0;
-}
-
-int erase_winbond_fwhub(struct flashchip *flash)
-{
-	int i, total_size = flash->total_size * 1024;
-
-	unlock_winbond_fwhub(flash);
-
-	printf("Erasing:     ");
-
-	for (i = 0; i < total_size; i += flash->page_size) {
-		if (erase_sector_winbond_fwhub(flash, i)) {
-			fprintf(stderr, "ERASE FAILED!\n");
-			return -1;
-		}
-	}
-
-	printf("\n");
-
-	return 0;
-}
-
-int write_winbond_fwhub(struct flashchip *flash, uint8_t *buf)
-{
-	int i;
-	int total_size = flash->total_size * 1024;
-	chipaddr bios = flash->virtual_memory;
-
-	if (erase_winbond_fwhub(flash))
-		return -1;
-
-	printf("Programming: ");
-	for (i = 0; i < total_size; i += flash->page_size) {
-		printf("0x%08x\b\b\b\b\b\b\b\b\b\b", i);
-		write_sector_jedec(bios, buf + i, bios + i, flash->page_size);
-	}
-	printf("\n");
-
-	return 0;
-}
diff --git a/w49f002u.c b/w49f002u.c
deleted file mode 100644
index d12bc72..0000000
--- a/w49f002u.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "flash.h"
-
-int write_49f002(struct flashchip *flash, uint8_t *buf)
-{
-	int i;
-	int total_size = flash->total_size * 1024;
-	int page_size = flash->page_size;
-	chipaddr bios = flash->virtual_memory;
-
-	if (erase_chip_jedec(flash)) {
-		fprintf(stderr, "ERASE FAILED!\n");
-		return -1;
-	}
-
-	printf("Programming page: ");
-	for (i = 0; i < total_size / page_size; i++) {
-		printf("%04d at address: 0x%08x ", i, i * page_size);
-		/* Byte-wise writing of 'page_size' bytes. */
-		write_sector_jedec(bios, buf + i * page_size,
-				   bios + i * page_size, page_size);
-		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-		fflush(stdout);
-	}
-	printf("\n");
-
-	return 0;
-}
diff --git a/wbsio_spi.c b/wbsio_spi.c
deleted file mode 100644
index 6b9425f..0000000
--- a/wbsio_spi.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2008 Peter Stuge <peter@stuge.se>
- *
- * 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; version 2 of the License.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <string.h>
-#include "flash.h"
-#include "spi.h"
-
-#define WBSIO_PORT1	0x2e
-#define WBSIO_PORT2	0x4e
-
-static uint16_t wbsio_spibase = 0;
-
-static uint16_t wbsio_get_spibase(uint16_t port)
-{
-	uint8_t id;
-	uint16_t flashport = 0;
-
-	w836xx_ext_enter(port);
-	id = sio_read(port, 0x20);
-	if (id != 0xa0) {
-		fprintf(stderr, "\nW83627 not found at 0x%x, id=0x%02x want=0xa0.\n", port, id);
-		goto done;
-	}
-
-	if (0 == (sio_read(port, 0x24) & 2)) {
-		fprintf(stderr, "\nW83627 found at 0x%x, but SPI pins are not enabled. (CR[0x24] bit 1=0)\n", port);
-		goto done;
-	}
-
-	sio_write(port, 0x07, 0x06);
-	if (0 == (sio_read(port, 0x30) & 1)) {
-		fprintf(stderr, "\nW83627 found at 0x%x, but SPI is not enabled. (LDN6[0x30] bit 0=0)\n", port);
-		goto done;
-	}
-
-	flashport = (sio_read(port, 0x62) << 8) | sio_read(port, 0x63);
-
-done:
-	w836xx_ext_leave(port);
-	return flashport;
-}
-
-int wbsio_check_for_spi(const char *name)
-{
-	if (0 == (wbsio_spibase = wbsio_get_spibase(WBSIO_PORT1)))
-		if (0 == (wbsio_spibase = wbsio_get_spibase(WBSIO_PORT2)))
-			return 1;
-
-	printf_debug("\nwbsio_spibase = 0x%x\n", wbsio_spibase);
-
-	buses_supported |= CHIP_BUSTYPE_SPI;
-	spi_controller = SPI_CONTROLLER_WBSIO;
-
-	return 0;
-}
-
-/* W83627DHG has 11 command modes:
- * 1=1 command only
- * 2=1 command+1 data write
- * 3=1 command+2 data read
- * 4=1 command+3 address
- * 5=1 command+3 address+1 data write
- * 6=1 command+3 address+4 data write
- * 7=1 command+3 address+1 dummy address inserted by wbsio+4 data read
- * 8=1 command+3 address+1 data read
- * 9=1 command+3 address+2 data read
- * a=1 command+3 address+3 data read
- * b=1 command+3 address+4 data read
- *
- * mode[7:4] holds the command mode
- * mode[3:0] holds SPI address bits [19:16]
- *
- * The Winbond SPI master only supports 20 bit addresses on the SPI bus. :\
- * Would one more byte of RAM in the chip (to get all 24 bits) really make
- * such a big difference?
- */
-int wbsio_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-		      const unsigned char *writearr, unsigned char *readarr)
-{
-	int i;
-	uint8_t mode = 0;
-
-	printf_debug("%s:", __func__);
-
-	if (1 == writecnt && 0 == readcnt) {
-		mode = 0x10;
-	} else if (2 == writecnt && 0 == readcnt) {
-		OUTB(writearr[1], wbsio_spibase + 4);
-		printf_debug(" data=0x%02x", writearr[1]);
-		mode = 0x20;
-	} else if (1 == writecnt && 2 == readcnt) {
-		mode = 0x30;
-	} else if (4 == writecnt && 0 == readcnt) {
-		printf_debug(" addr=0x%02x", (writearr[1] & 0x0f));
-		for (i = 2; i < writecnt; i++) {
-			OUTB(writearr[i], wbsio_spibase + i);
-			printf_debug("%02x", writearr[i]);
-		}
-		mode = 0x40 | (writearr[1] & 0x0f);
-	} else if (5 == writecnt && 0 == readcnt) {
-		printf_debug(" addr=0x%02x", (writearr[1] & 0x0f));
-		for (i = 2; i < 4; i++) {
-			OUTB(writearr[i], wbsio_spibase + i);
-			printf_debug("%02x", writearr[i]);
-		}
-		OUTB(writearr[i], wbsio_spibase + i);
-		printf_debug(" data=0x%02x", writearr[i]);
-		mode = 0x50 | (writearr[1] & 0x0f);
-	} else if (8 == writecnt && 0 == readcnt) {
-		printf_debug(" addr=0x%02x", (writearr[1] & 0x0f));
-		for (i = 2; i < 4; i++) {
-			OUTB(writearr[i], wbsio_spibase + i);
-			printf_debug("%02x", writearr[i]);
-		}
-		printf_debug(" data=0x");
-		for (; i < writecnt; i++) {
-			OUTB(writearr[i], wbsio_spibase + i);
-			printf_debug("%02x", writearr[i]);
-		}
-		mode = 0x60 | (writearr[1] & 0x0f);
-	} else if (5 == writecnt && 4 == readcnt) {
-		/* XXX: TODO not supported by flashrom infrastructure!
-		 * This mode, 7, discards the fifth byte in writecnt,
-		 * but since we can not express that in flashrom, fail
-		 * the operation for now.
-		 */
-		;
-	} else if (4 == writecnt && readcnt >= 1 && readcnt <= 4) {
-		printf_debug(" addr=0x%02x", (writearr[1] & 0x0f));
-		for (i = 2; i < writecnt; i++) {
-			OUTB(writearr[i], wbsio_spibase + i);
-			printf_debug("%02x", writearr[i]);
-		}
-		mode = ((7 + readcnt) << 4) | (writearr[1] & 0x0f);
-	}
-	printf_debug(" cmd=%02x mode=%02x\n", writearr[0], mode);
-
-	if (!mode) {
-		fprintf(stderr, "%s: unsupported command type wr=%d rd=%d\n",
-			__func__, writecnt, readcnt);
-		/* Command type refers to the number of bytes read/written. */
-		return SPI_INVALID_LENGTH;
-	}
-
-	OUTB(writearr[0], wbsio_spibase);
-	OUTB(mode, wbsio_spibase + 1);
-	programmer_delay(10);
-
-	if (!readcnt)
-		return 0;
-
-	printf_debug("%s: returning data =", __func__);
-	for (i = 0; i < readcnt; i++) {
-		readarr[i] = INB(wbsio_spibase + 4 + i);
-		printf_debug(" 0x%02x", readarr[i]);
-	}
-	printf_debug("\n");
-	return 0;
-}
-
-int wbsio_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
-{
-	int size = flash->total_size * 1024;
-
-	if (size > 1024 * 1024) {
-		fprintf(stderr, "%s: Winbond saved on 4 register bits so max chip size is 1024 KB!\n", __func__);
-		return 1;
-	}
-
-	return read_memmapped(flash, buf, start, len);
-}
-
-int wbsio_spi_write_1(struct flashchip *flash, uint8_t *buf)
-{
-	int size = flash->total_size * 1024;
-
-	if (size > 1024 * 1024) {
-		fprintf(stderr, "%s: Winbond saved on 4 register bits so max chip size is 1024 KB!\n", __func__);
-		return 1;
-	}
-
-	return spi_chip_write_1(flash, buf);
-}
