Patchwork Preliminary general superio support.

login
register
about
Submitter Luc Verhaegen
Date 2010-01-20 15:14:42
Message ID <20100120151442.GH13604@skynet.be>
Download mbox | patch
Permalink /patch/822/
State Bitrotted
Headers show

Comments

Luc Verhaegen - 2010-01-20 15:14:42
Very untested and new. Sent in to show off what is being worked on and 
to get first impressions.

Last i tried it worked fine on:
* Winbond W83627EHF on MSI Fuzzy CN700 (nothing needed, just detection).
* Winbond W83697HF on Asus 7V8X-MX SE (needing superio rom write enable)

To be tested still:
* it8705F rom write enable (have shuttle board here that i should still 
test on).
* it87 spi code (have nonspi board here that i should still test on).

Luc Verhaegen.
Luc Verhaegen - 2010-01-20 22:02:31
On Wed, Jan 20, 2010 at 04:14:42PM +0100, Luc Verhaegen wrote:
> Very untested and new. Sent in to show off what is being worked on and 
> to get first impressions.
> 
> Last i tried it worked fine on:
> * Winbond W83627EHF on MSI Fuzzy CN700 (nothing needed, just detection).
> * Winbond W83697HF on Asus 7V8X-MX SE (needing superio rom write enable)
> 
> To be tested still:
> * it8705F rom write enable (have shuttle board here that i should still 
> test on).
> * it87 spi code (have nonspi board here that i should still test on).
> 
> Luc Verhaegen.

> >From f98cbb703f2bbbb918a87eebcd10c4cc1bd457f9 Mon Sep 17 00:00:00 2001
> From: Luc Verhaegen <libv@skynet.be>
> Date: Tue, 12 Jan 2010 13:57:21 +0100
> Subject: [PATCH] WIP.
> 
> ---
>  Makefile         |    2 +-
>  board_enable.c   |  411 +++++++------------------------------------------
>  chipset_enable.c |    1 +
>  flash.h          |   37 +----
>  flashrom.c       |   19 ---
>  internal.c       |   20 +--
>  it87spi.c        |  202 ++++--------------------
>  spi.c            |    1 +
>  superio.c        |  454 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  superio.h        |  107 +++++++++++++
>  wbsio_spi.c      |   48 ++-----
>  11 files changed, 676 insertions(+), 626 deletions(-)
>  create mode 100644 superio.c
>  create mode 100644 superio.h

> +/**
> + *
> + */
> +static struct superio superios[] = {
> +	{it87xx_detect, 0x8701, ITE_IT8703,   NULL,                 it8703_gpio_set},
> +	{it87xx_detect, 0x8705, ITE_IT8705,   it8705f_write_enable, NULL},
> +	{it87xx_detect, 0x8712, ITE_IT8712,   NULL,                 it8712f_gpio_set},
> +	{it87xx_detect, 0x8716, ITE_IT8716,   it8716_spi_init,      NULL},
> +	{it87xx_detect, 0x8718, ITE_IT8718,   it8716_spi_init,      NULL},
> +	{w836xx_detect, 0x3C,   VIA_VT1211,   NULL,                 NULL},
> +	{w836xx_detect, 0x52,   WB_W83627HF,  NULL,                 w83627hf_gpio_set},
> +	//{w836xx_detect, 0x60,   WB_W83697HF,  w83697hf_memw_enable, NULL},

Guess what i tested here :)

> +	{w836xx_detect, 0x82,   WB_W83627THF, NULL,                 w83627thf_gpio_set},
> +	{w836xx_detect, 0x88,   WB_W83627EHF, NULL,                 NULL},
> +	{w836xx_detect, 0xA0,   WB_W83627DHG, w83627dhg_spi_init,   NULL},
> +
> +	{NULL, 0, SIO_NONE, NULL, NULL}	/* end marker */
> +};

Table with the action.

> +int
> +superio_probe(void)
> +{
> +	struct superio_detect {
> +		uint16_t port;
> +		uint16_t (*detect) (uint16_t port);
> +		char *name;
> +	} superio_detects[] = {
> +		{0x2E, w836xx_detect, "Winbond W836xx"},
> +		{0x4E, w836xx_detect, "Winbond W836xx"},
> +		{0x2E, it87xx_detect, "ITE IT87xx"},
> +		{0x4E, it87xx_detect, "ITE IT87xx"},
> +
> +		{0, NULL} /* end marker */
> +	};
> +
> +	int i, j;
> +	uint16_t id;
> +
> +	for (i = 0; superio_detects[i].detect; i++) {
> +
> +		id = superio_detects[i].detect(superio_detects[i].port);
> +		if ((id == 0xFF) || (id == 0xFFFF))
> +		    continue;
> +
> +		msg_pdbg("Superio detection for \"%s\" on 0x%X"
> +			 " returned 0x%0X\n", superio_detects[i].name,
> +			 superio_detects[i].port, id);
> +
> +		for (j = 0; superios[j].detect; j++) {
> +			if ((superios[j].detect == superio_detects[i].detect) &&
> +			    (id == superios[j].id)) {
> +				superio = &superios[j];
> +				superio_port = superio_detects[i].port;
> +				break;
> +			}
> +		}
> +
> +		if (!superio)
> +			msg_perr("No matching superio found for \"%s\" (0x%X) :"
> +				 " 0x%0X\n", superio_detects[i].name,
> +				 superio_detects[i].port, id);
> +	}
> +
> +	if (superio)
> +		msg_pinfo("Superio \"%s\" detected on 0x%0X.\n",
> +			  superio_chip_name(superio->chip), superio_port);
> +	else
> +		msg_pdbg("No Superio chip detected.\n");
> +
> +	return 0;
> +}

Here we do the detection in a clean way with little noise.

> +++ b/superio.h
> @@ -0,0 +1,107 @@
> +/*
> + * This file is part of the flashrom project.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; 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 HAVE_SUPERIO_H
> +#define HAVE_SUPERIO_H 1
> +
> +/*
> + *
> + */
> +enum superio_chip {
> +	SIO_NONE = 0,
> +
> +	/* ITE */
> +	ITE_IT8703,
> +	ITE_IT8705,
> +	ITE_IT8708,
> +	ITE_IT8712,
> +	ITE_IT8716,
> +	ITE_IT8718,
> +
> +	/* A lonesome VIA superio */
> +	VIA_VT1211,
> +
> +	/* Winbond */
> +	WB_W83627DHG,
> +	WB_W83627EHF,
> +	WB_W83627HF,
> +	WB_W83627THF,
> +	WB_W83697HF,
> +
> +	SIO_UNKNOWN
> +};
> +
> +/*
> + *
> + */
> +struct superio {
> +	uint16_t (*detect) (uint16_t port);
> +	uint16_t id;
> +
> +	enum superio_chip chip;
> +
> +	int (*init) (uint16_t port);
> +	int (*gpio_set) (uint16_t port, int gpio, int raise);
> +};
> +
> +struct superio *superio;
> +uint16_t superio_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);
> +
> +void w836xx_ext_enter(uint16_t port);
> +void w836xx_ext_leave(uint16_t port);
> +
> +void ite_conf_mode_enter(uint16_t port);
> +void ite_conf_mode_exit(uint16_t port);
> +
> +/*
> + * High level calls.
> + */
> +int superio_probe(void);
> +int superio_init(void);
> +int superio_gpio_set(int gpio, int raise);
> +
> +/*
> + *
> + * Will someone please pour the programmer infrastructure in a struct with
> + * callbacks that gets created by the init functions below? This lack of
> + * abstraction now causes us to have to include horrible flash.h before
> + * this file.
> + *
> + */
> +
> +/*
> + * it87spi.c
> + */
> +int it8716_spi_init(uint16_t port);
> +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);
> +
> +/*
> + * wbsio_spi.c
> + */
> +int w83627dhg_spi_init(uint16_t port);
> +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);
> +
> +#endif /* HAVE_SUPERIO_H */

Anyway, here is an example of two test runs last weeks:

n the asus A7V8X-MX SE (which up until now required a board enable to init the superio).

With just superio_probe():

> /tmp/flashrom_superio# ./flashrom 
> flashrom v0.9.1-runknown
> No coreboot table found.
> Found chipset "VIA VT8235", enabling flash write... OK.
> This chipset supports the following protocols: Non-SPI.
> Superio "Winbond W83697HF" detected on 0x2E.
> Calibrating delay loop... OK.
> No EEPROM/flash device found.
> If you know which flash chip you have, and if this version of flashrom
> supports a similar flash chip, you can try to force read your chip. Run:
> flashrom -f -r -c similar_supported_flash_chip filename
>
> Note: flashrom can never write when the flash chip isn't found automatically.

After adding superio_init(), which runs the initialisation code, when a
superio has been identified and when the init callback is there:

> /tmp/flashrom_superio# ./flashrom 
> flashrom v0.9.1-runknown
> No coreboot table found.
> Found chipset "VIA VT8235", enabling flash write... OK.
> This chipset supports the following protocols: Non-SPI.
> Superio "Winbond W83697HF" detected on 0x2E.
> Initialising "Winbond W83697HF" superio
> Calibrating delay loop... OK.
> Found chip "SST SST39SF020A" (256 KB, Parallel) at physical address 0xfffc0000.
> No operations were specified.

SO with the above comment not there, we are already able to scrap 6 board enables!

Luc Verhaegen.
David Hendricks - 2010-01-29 23:14:20
The patch to board_enable.c needs to be updated to apply cleanly with the
new DMI identification stuff, but otherwise this patch applied cleanly for
me and I was able to add a superio entry to do some very basic testing -- My
superio isn't fully supported (yet), but I was able to run through the
probing steps successfully.

On Wed, Jan 20, 2010 at 2:02 PM, Luc Verhaegen <libv@skynet.be> wrote:

> > +/**
> > + *
> > + */
> > +static struct superio superios[] = {
> > +     {it87xx_detect, 0x8701, ITE_IT8703,   NULL,
> it8703_gpio_set},
> > +     {it87xx_detect, 0x8705, ITE_IT8705,   it8705f_write_enable, NULL},
> > +     {it87xx_detect, 0x8712, ITE_IT8712,   NULL,
> it8712f_gpio_set},
> > +     {it87xx_detect, 0x8716, ITE_IT8716,   it8716_spi_init,      NULL},
> > +     {it87xx_detect, 0x8718, ITE_IT8718,   it8716_spi_init,      NULL},
> > +     {w836xx_detect, 0x3C,   VIA_VT1211,   NULL,                 NULL},
> > +     {w836xx_detect, 0x52,   WB_W83627HF,  NULL,
> w83627hf_gpio_set},
> > +     //{w836xx_detect, 0x60,   WB_W83697HF,  w83697hf_memw_enable,
> NULL},
>
> Guess what i tested here :)
>
> > +     {w836xx_detect, 0x82,   WB_W83627THF, NULL,
> w83627thf_gpio_set},
> > +     {w836xx_detect, 0x88,   WB_W83627EHF, NULL,                 NULL},
> > +     {w836xx_detect, 0xA0,   WB_W83627DHG, w83627dhg_spi_init,   NULL},
> > +
> > +     {NULL, 0, SIO_NONE, NULL, NULL} /* end marker */
> > +};
>
> Table with the action.
>

There are three similar-but-different tables used in this file -- One in
superio_chip_name(), one in superio_probe(), and then the larger superios[]
table. Maybe we can find a way to use a single table to satisfy the needs of
all the helper functions?


>
> > +int
> > +superio_probe(void)
> > +{
> > +     struct superio_detect {
> > +             uint16_t port;
> > +             uint16_t (*detect) (uint16_t port);
> > +             char *name;
> > +     } superio_detects[] = {
> > +             {0x2E, w836xx_detect, "Winbond W836xx"},
> > +             {0x4E, w836xx_detect, "Winbond W836xx"},
> > +             {0x2E, it87xx_detect, "ITE IT87xx"},
> > +             {0x4E, it87xx_detect, "ITE IT87xx"},
> > +
> > +             {0, NULL} /* end marker */
> > +     };
> > +
> > +     int i, j;
> > +     uint16_t id;
> > +
> > +     for (i = 0; superio_detects[i].detect; i++) {
> > +
> > +             id = superio_detects[i].detect(superio_detects[i].port);
> > +             if ((id == 0xFF) || (id == 0xFFFF))
> > +                 continue;
> > +
> > +             msg_pdbg("Superio detection for \"%s\" on 0x%X"
> > +                      " returned 0x%0X\n", superio_detects[i].name,
> > +                      superio_detects[i].port, id);
> > +
> > +             for (j = 0; superios[j].detect; j++) {
> > +                     if ((superios[j].detect ==
> superio_detects[i].detect) &&
> > +                         (id == superios[j].id)) {
> > +                             superio = &superios[j];
> > +                             superio_port = superio_detects[i].port;
> > +                             break;
> > +                     }
> > +             }
> > +
> > +             if (!superio)
> > +                     msg_perr("No matching superio found for \"%s\"
> (0x%X) :"
> > +                              " 0x%0X\n", superio_detects[i].name,
> > +                              superio_detects[i].port, id);
> > +     }
> > +
> > +     if (superio)
> > +             msg_pinfo("Superio \"%s\" detected on 0x%0X.\n",
> > +                       superio_chip_name(superio->chip), superio_port);
> > +     else
> > +             msg_pdbg("No Superio chip detected.\n");
> > +
> > +     return 0;
> > +}
>
> Here we do the detection in a clean way with little noise.
>
> > +++ b/superio.h
> > @@ -0,0 +1,107 @@
> > +/*
> > + * This file is part of the flashrom project.
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; 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 HAVE_SUPERIO_H
> > +#define HAVE_SUPERIO_H 1
> > +
> > +/*
> > + *
> > + */
> > +enum superio_chip {
> > +     SIO_NONE = 0,
> > +
> > +     /* ITE */
> > +     ITE_IT8703,
> > +     ITE_IT8705,
> > +     ITE_IT8708,
> > +     ITE_IT8712,
> > +     ITE_IT8716,
> > +     ITE_IT8718,
> > +
> > +     /* A lonesome VIA superio */
> > +     VIA_VT1211,
> > +
> > +     /* Winbond */
> > +     WB_W83627DHG,
> > +     WB_W83627EHF,
> > +     WB_W83627HF,
> > +     WB_W83627THF,
> > +     WB_W83697HF,
> > +
> > +     SIO_UNKNOWN
> > +};
> > +
> > +/*
> > + *
> > + */
> > +struct superio {
> > +     uint16_t (*detect) (uint16_t port);
> > +     uint16_t id;
> > +
> > +     enum superio_chip chip;
> > +
> > +     int (*init) (uint16_t port);
> > +     int (*gpio_set) (uint16_t port, int gpio, int raise);
> > +};
> > +
> > +struct superio *superio;
> > +uint16_t superio_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);
> > +
> > +void w836xx_ext_enter(uint16_t port);
> > +void w836xx_ext_leave(uint16_t port);
> > +
> > +void ite_conf_mode_enter(uint16_t port);
> > +void ite_conf_mode_exit(uint16_t port);
> > +
> > +/*
> > + * High level calls.
> > + */
> > +int superio_probe(void);
> > +int superio_init(void);
> > +int superio_gpio_set(int gpio, int raise);
> > +
> > +/*
> > + *
> > + * Will someone please pour the programmer infrastructure in a struct
> with
> > + * callbacks that gets created by the init functions below? This lack of
> > + * abstraction now causes us to have to include horrible flash.h before
> > + * this file.
> > + *
> > + */
> > +
> > +/*
> > + * it87spi.c
> > + */
> > +int it8716_spi_init(uint16_t port);
> > +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);
> > +
> > +/*
> > + * wbsio_spi.c
> > + */
> > +int w83627dhg_spi_init(uint16_t port);
> > +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);
> > +
> > +#endif /* HAVE_SUPERIO_H */
>
> Anyway, here is an example of two test runs last weeks:
>
> n the asus A7V8X-MX SE (which up until now required a board enable to init
> the superio).
>
> With just superio_probe():
>
> > /tmp/flashrom_superio# ./flashrom
> > flashrom v0.9.1-runknown
> > No coreboot table found.
> > Found chipset "VIA VT8235", enabling flash write... OK.
> > This chipset supports the following protocols: Non-SPI.
> > Superio "Winbond W83697HF" detected on 0x2E.
> > Calibrating delay loop... OK.
> > No EEPROM/flash device found.
> > If you know which flash chip you have, and if this version of flashrom
> > supports a similar flash chip, you can try to force read your chip. Run:
> > flashrom -f -r -c similar_supported_flash_chip filename
> >
> > Note: flashrom can never write when the flash chip isn't found
> automatically.
>
> After adding superio_init(), which runs the initialisation code, when a
> superio has been identified and when the init callback is there:
>
> > /tmp/flashrom_superio# ./flashrom
> > flashrom v0.9.1-runknown
> > No coreboot table found.
> > Found chipset "VIA VT8235", enabling flash write... OK.
> > This chipset supports the following protocols: Non-SPI.
> > Superio "Winbond W83697HF" detected on 0x2E.
> > Initialising "Winbond W83697HF" superio
> > Calibrating delay loop... OK.
> > Found chip "SST SST39SF020A" (256 KB, Parallel) at physical address
> 0xfffc0000.
> > No operations were specified.
>
> SO with the above comment not there, we are already able to scrap 6 board
> enables!
>
> Luc Verhaegen.
>
>
> _______________________________________________
> flashrom mailing list
> flashrom@flashrom.org
> http://www.flashrom.org/mailman/listinfo/flashrom
>
Luc Verhaegen - 2010-01-30 00:47:56
On Fri, Jan 29, 2010 at 03:14:20PM -0800, David Hendricks wrote:
> The patch to board_enable.c needs to be updated to apply cleanly with the
> new DMI identification stuff, but otherwise this patch applied cleanly for
> me and I was able to add a superio entry to do some very basic testing -- My
> superio isn't fully supported (yet), but I was able to run through the
> probing steps successfully.

Yeah, but as you can see, it is already older code, as it is from 
december :) Aaeons in a project like flashrom :)

> There are three similar-but-different tables used in this file -- One in
> superio_chip_name(), one in superio_probe(), and then the larger superios[]
> table. Maybe we can find a way to use a single table to satisfy the needs of
> all the helper functions?

I want to get rid of the names table, and incorporate that directly in a 
wider and unrulier main table. The table for probing needs to stay. It 
contains the probe routines, and the probe addresses, and the order in 
which the probes happen.

I do not want the mess where one big table gets all probe routines 
called (even though 45% + 45% of it are the same two routines), like 
what you see with the flash chips.

I need a small table here, when an entry returns a result, the result, 
along with the pointer to the probe routine, will get matched in the 
main table.

Currently, with the superios in there atm, we run 4 probes:

WB@0x2E, WB@0x4E, ITE@0x2E, ITE@0x4E

Glad that someone is looking into this though :)

Luc Verhaegen.

Patch

From f98cbb703f2bbbb918a87eebcd10c4cc1bd457f9 Mon Sep 17 00:00:00 2001
From: Luc Verhaegen <libv@skynet.be>
Date: Tue, 12 Jan 2010 13:57:21 +0100
Subject: [PATCH] WIP.

---
 Makefile         |    2 +-
 board_enable.c   |  411 +++++++------------------------------------------
 chipset_enable.c |    1 +
 flash.h          |   37 +----
 flashrom.c       |   19 ---
 internal.c       |   20 +--
 it87spi.c        |  202 ++++--------------------
 spi.c            |    1 +
 superio.c        |  454 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 superio.h        |  107 +++++++++++++
 wbsio_spi.c      |   48 ++-----
 11 files changed, 676 insertions(+), 626 deletions(-)
 create mode 100644 superio.c
 create mode 100644 superio.h

diff --git a/Makefile b/Makefile
index 423e315..dfa6b66 100644
--- a/Makefile
+++ b/Makefile
@@ -101,7 +101,7 @@  CONFIG_PRINT_WIKI ?= no
 
 ifeq ($(CONFIG_INTERNAL), yes)
 FEATURE_CFLAGS += -D'INTERNAL_SUPPORT=1'
-PROGRAMMER_OBJS += chipset_enable.o board_enable.o cbtable.o it87spi.o ichspi.o sb600spi.o wbsio_spi.o
+PROGRAMMER_OBJS += chipset_enable.o board_enable.o cbtable.o it87spi.o ichspi.o sb600spi.o wbsio_spi.o superio.o
 NEED_PCI := yes
 endif
 
diff --git a/board_enable.c b/board_enable.c
index abe1d47..e5a620d 100644
--- a/board_enable.c
+++ b/board_enable.c
@@ -27,73 +27,7 @@ 
 #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);
-}
-
-/* Not used yet. */
-#if 0
-static int enable_flash_decode_superio(void)
-{
-	int ret;
-	uint8_t tmp;
-
-	switch (superio.vendor) {
-	case SUPERIO_VENDOR_NONE:
-		ret = -1;
-		break;
-	case SUPERIO_VENDOR_ITE:
-		enter_conf_mode_ite(superio.port);
-		/* Enable flash mapping. Works for most old ITE style SuperI/O. */
-		tmp = sio_read(superio.port, 0x24);
-		tmp |= 0xfc;
-		sio_write(superio.port, 0x24, tmp);
-		exit_conf_mode_ite(superio.port);
-		ret = 0;
-		break;
-	default:
-		printf_debug("Unhandled SuperI/O type!\n");
-		ret = -1;
-		break;
-	}
-	return ret;
-}
-#endif
+#include "superio.h"
 
 /**
  * Winbond W83627HF: Raise GPIO24.
@@ -102,37 +36,9 @@  static int enable_flash_decode_superio(void)
  *  - 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)
+static int w83627hf_gpio24_raise(const char *name)
 {
-	return w83627hf_gpio24_raise(0x2e, name);
+	return superio_gpio_set(24, 1);
 }
 
 /**
@@ -142,95 +48,9 @@  static int w83627hf_gpio24_raise_2e(const char *name)
  *  - 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);
-}
-
-/**
- * Suited for:
- *   - EPoX EP-8K5A2: VIA KT333 + VT8235.
- *   - Albatron PM266A Pro: VIA P4M266A + VT8235.
- *   - Shuttle AK31 (all versions): VIA KT266 + VT8233.
- *   - ASUS A7V8X-MX SE and A7V400-MX: AMD K7 + VIA KM400A + VT8235
- *   - Tyan S2498 (Tomcat K7M): AMD Geode NX + VIA KM400 + VT8237.
- */
-static int w836xx_memw_enable_2e(const char *name)
+static int w83627thf_gpio44_raise(const char *name)
 {
-	w836xx_memw_enable(0x2E);
-
-	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:
- *  - AOpen vKM400Am-S: VIA KM400 + VT8237 + IT8705F.
- *  - Biostar P4M80-M4: VIA P4M800 + VT8237 + IT8705AF
- *  - Elitegroup K7S6A: SiS745 + ITE IT8705F
- *  - Elitegroup K7VTA3: VIA Apollo KT266/A/333 + VIA VT8235 + ITE IT8705F
- *  - GIGABYTE GA-7VT600: VIA KT600 + VT8237 + IT8705
- *  - Shuttle AK38N: VIA KT333CF + VIA VT8235 + ITE IT8705F
- *
- * SIS950 superio probably requires the same flash write enable.
- */
-static int it8705f_write_enable_2e(const char *name)
-{
-	return it8705f_write_enable(0x2e, name);
+	return superio_gpio_set(44, 1);
 }
 
 /**
@@ -307,31 +127,24 @@  static int via_vt823x_gpio9_raise(const char *name)
 }
 
 /**
- * Suited for VIAs EPIA M and MII, and maybe other CLE266 based EPIAs.
- *
- * We don't need to do this for EPIA M when using coreboot, GPIO15 is never
- * lowered there.
+ * Suited for:
+ *   - MSI KT4V and KT4V-L: AMD K7 + VIA KT400 + VT8235 + W83697HF.
+ *   - MSI KT4 Ultra: AMD K7 + VIA KT400 + VT8235 + W83697HF.
  */
-static int via_vt823x_gpio15_raise(const char *name)
+static int via_vt823x_gpio12_raise(const char *name)
 {
-	return via_vt823x_gpio_set(15, 1);
+	return via_vt823x_gpio_set(12, 1);
 }
 
 /**
- * Winbond W83697HF Super I/O + VIA VT8235 southbridge
+ * Suited for VIAs EPIA M and MII, and maybe other CLE266 based EPIAs.
  *
- * Suited for:
- *   - MSI KT4V and KT4V-L: AMD K7 + VIA KT400 + VT8235
- *   - MSI KT4 Ultra: AMD K7 + VIA KT400 + VT8235
+ * We don't need to do this for EPIA M when using coreboot, GPIO15 is never
+ * lowered there.
  */
-static int board_msi_kt4v(const char *name)
+static int via_vt823x_gpio15_raise(const char *name)
 {
-	int ret;
-
-	ret = via_vt823x_gpio_set(12, 1);
-	w836xx_memw_enable(0x2E);
-
-	return ret;
+	return via_vt823x_gpio_set(15, 1);
 }
 
 /**
@@ -973,8 +786,6 @@  static int board_msi_651ml(const char *name)
 	temp |= (1 << 0);		/* Raise output? */
 	OUTW(temp, base + 0x64);
 
-	w836xx_memw_enable(0x2E);
-
 	return 0;
 }
 
@@ -1018,16 +829,9 @@  out:
  */
 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;
@@ -1050,93 +854,7 @@  static int board_mitac_6513wu(const char *name)
  */
 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;
+	return superio_gpio_set(51, 1);
 }
 
 /**
@@ -1144,7 +862,7 @@  it8712f_gpio_set(unsigned int line, int raise)
  */
 static int board_asus_a7v600x(const char *name)
 {
-	return it8712f_gpio_set(32, 1);
+	return superio_gpio_set(32, 1);
 }
 
 /**
@@ -1175,62 +893,45 @@  static int board_asus_a7v600x(const char *name)
 
 /* 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       max_rom_...  flash enable */
-	{0x8086, 0x2926, 0x147b, 0x1084,  0x11ab, 0x4364, 0x147b, 0x1084, NULL,         NULL,          "Abit",        "IP35",                  0,   intel_ich_gpio16_raise},
-	{0x105a, 0x0d30, 0x105a, 0x4d33,  0x8086, 0x1130, 0x8086,      0, NULL,         NULL,          "Acorp",       "6A815EPD",              0,   board_acorp_6a815epd},
-	{0x8086, 0x24D4, 0x1849, 0x24D0,  0x8086, 0x24D5, 0x1849, 0x9739, NULL,         NULL,          "ASRock",      "P4i65GV",               0,   intel_ich_gpio23_raise},
-	{0x1022, 0x746B,      0,      0,       0,      0,      0,      0, "AGAMI",      "ARUMA",       "agami",       "Aruma",                 0,   w83627hf_gpio24_raise_2e},
-	{0x1106, 0x3177, 0x17F2, 0x3177,  0x1106, 0x3148, 0x17F2, 0x3148, NULL,         NULL,          "Albatron",    "PM266A",                0,   w836xx_memw_enable_2e},
-	{0x1106, 0x3205, 0x1106, 0x3205,  0x10EC, 0x8139, 0xA0A0, 0x0477, NULL,         NULL,          "AOpen",       "vKM400Am-S",            0,   it8705f_write_enable_2e},
-	{0x1022, 0x2090,      0,      0,  0x1022, 0x2080,      0,      0, "artecgroup", "dbe61",       "Artec Group", "DBE61",                 0,   board_artecgroup_dbe6x},
-	{0x1022, 0x2090,      0,      0,  0x1022, 0x2080,      0,      0, "artecgroup", "dbe62",       "Artec Group", "DBE62",                 0,   board_artecgroup_dbe6x},
-	{0x1106, 0x3189, 0x1043, 0x807F,  0x1106, 0x3065, 0x1043, 0x80ED, NULL,         NULL,          "ASUS",        "A7V600-X",              0,   board_asus_a7v600x},
-	{0x1106, 0x3189, 0x1043, 0x807F,  0x1106, 0x3177, 0x1043, 0x808C, NULL,         NULL,          "ASUS",        "A7V8X",                 0,   board_asus_a7v8x},
-	{0x1106, 0x3177, 0x1043, 0x80A1,  0x1106, 0x3205, 0x1043, 0x8118, NULL,         NULL,          "ASUS",        "A7V8X-MX SE",           0,   w836xx_memw_enable_2e},
-	{0x1106, 0x1336, 0x1043, 0x80ed,  0x1106, 0x3288, 0x1043, 0x8249, NULL,         NULL,          "ASUS",        "M2V-MX",                0,   via_vt823x_gpio5_raise},
-	{0x8086, 0x1a30, 0x1043, 0x8070,  0x8086, 0x244b, 0x1043, 0x8028, NULL,         NULL,          "ASUS",        "P4B266",                0,   intel_ich_gpio22_raise},
-	{0x8086, 0x1A30, 0x1043, 0x8025,  0x8086, 0x244B, 0x104D, 0x80F0, NULL,         NULL,          "ASUS",        "P4B266-LM",             0,   intel_ich_gpio21_raise},
-	{0x8086, 0x2570, 0x1043, 0x80F2,  0x105A, 0x3373, 0x1043, 0x80F5, NULL,         NULL,          "ASUS",        "P4P800-E Deluxe",       0,   intel_ich_gpio21_raise},
-	{0x10B9, 0x1541,      0,      0,  0x10B9, 0x1533,      0,      0, "asus",       "p5a",         "ASUS",        "P5A",                   0,   board_asus_p5a},
-	{0x10DE, 0x0030, 0x1043, 0x818a,  0x8086, 0x100E, 0x1043, 0x80EE, NULL,         NULL,          "ASUS",        "P5ND2-SLI Deluxe",      0,   nvidia_mcp_gpio10_raise},
-	{0x1106, 0x3149, 0x1565, 0x3206,  0x1106, 0x3344, 0x1565, 0x1202, NULL,         NULL,          "Biostar",     "P4M80-M4",              0,   it8705f_write_enable_2e},
-	{0x8086, 0x3590, 0x1028, 0x016c,  0x1000, 0x0030, 0x1028, 0x016c, NULL,         NULL,          "Dell",        "PowerEdge 1850",        0,   intel_ich_gpio23_raise},
-	{0x1039, 0x5513, 0x1019, 0x0A41,  0x1039, 0x0018,      0,      0, NULL,         NULL,          "Elitegroup",  "K7S6A",                 0,   it8705f_write_enable_2e},
-	{0x1106, 0x3038, 0x1019, 0x0996,  0x1106, 0x3177, 0x1019, 0x0996, NULL,         NULL,          "Elitegroup",  "K7VTA3",                256, it8705f_write_enable_2e},
-	{0x1106, 0x3177, 0x1106, 0x3177,  0x1106, 0x3059, 0x1695, 0x3005, NULL,         NULL,          "EPoX",        "EP-8K5A2",              0,   w836xx_memw_enable_2e},
-	{0x10EC, 0x8139, 0x1695, 0x9001,  0x11C1, 0x5811, 0x1695, 0x9015, NULL,         NULL,          "EPoX",        "EP-8RDA3+",             0,   nvidia_mcp_gpio31_raise},
-	{0x8086, 0x7110,      0,      0,  0x8086, 0x7190,      0,      0, "epox",       "ep-bx3",      "EPoX",        "EP-BX3",                0,   board_epox_ep_bx3},
-	{0x1039, 0x0761,      0,      0,  0x10EC, 0x8168,      0,      0, "gigabyte",   "2761gxdk",    "GIGABYTE",    "GA-2761GXDK",           0,   it87xx_probe_spi_flash},
-	{0x1106, 0x3227, 0x1458, 0x5001,  0x10ec, 0x8139, 0x1458, 0xe000, NULL,         NULL,          "GIGABYTE",    "GA-7VT600",             0,   it8705f_write_enable_2e},
-	{0x10DE, 0x0050, 0x1458, 0x0C11,  0x10DE, 0x005e, 0x1458, 0x5000, NULL,         NULL,          "GIGABYTE",    "GA-K8N-SLI",            0,   nvidia_mcp_gpio21_raise},
-	{0x10DE, 0x0360, 0x1458, 0x0C11,  0x10DE, 0x0369, 0x1458, 0x5001, "gigabyte",   "m57sli",      "GIGABYTE",    "GA-M57SLI-S4",          0,   it87xx_probe_spi_flash},
-	{0x10de, 0x03e0,      0,      0,  0x10DE, 0x03D0,      0,      0, NULL,         NULL,          "GIGABYTE",    "GA-M61P-S3",            0,   it87xx_probe_spi_flash},
-	{0x1002, 0x4398, 0x1458, 0x5004,  0x1002, 0x4391, 0x1458, 0xb000, NULL,         NULL,          "GIGABYTE",    "GA-MA78G-DS3H",         0,   it87xx_probe_spi_flash},
-	{0x1002, 0x4398, 0x1458, 0x5004,  0x1002, 0x4391, 0x1458, 0xb002, NULL,         NULL,          "GIGABYTE",    "GA-MA78GM-S2H",         0,   it87xx_probe_spi_flash},
-	{0x1002, 0x438d, 0x1458, 0x5001,  0x1002, 0x5956, 0x1002, 0x5956, NULL,         NULL,          "GIGABYTE",    "GA-MA790FX-DQ6",        0,   it87xx_probe_spi_flash},
-	{0x1166, 0x0223, 0x103c, 0x320d,  0x102b, 0x0522, 0x103c, 0x31fa, "hp",         "dl145_g3",    "HP",          "DL145 G3",              0,   board_hp_dl145_g3_enable},
-	{0x1166, 0x0205, 0x1014, 0x0347,  0x1002, 0x515E, 0x1014, 0x0325, NULL,         NULL,          "IBM",         "x3455",                 0,   board_ibm_x3455},
-	{0x1039, 0x5513, 0x8086, 0xd61f,  0x1039, 0x6330, 0x8086, 0xd61f, NULL,         NULL,          "Intel",       "D201GLY",               0,   wbsio_check_for_spi},
-	{0x1022, 0x7468,      0,      0,       0,      0,      0,      0, "iwill",      "dk8_htx",     "IWILL",       "DK8-HTX",               0,   w83627hf_gpio24_raise_2e},
-	{0x8086, 0x27A0,      0,      0,  0x8086, 0x27b8,      0,      0, "kontron",    "986lcd-m",    "Kontron",     "986LCD-M",              0,   board_kontron_986lcd_m},
-	{0x8086, 0x2411, 0x8086, 0x2411,  0x8086, 0x7125, 0x0e11, 0xb165, NULL,         NULL,          "Mitac",       "6513WU",                0,   board_mitac_6513wu},
-	{0x13f6, 0x0111, 0x1462, 0x5900,  0x1106, 0x3177, 0x1106,      0, NULL,         NULL,          "MSI",         "MS-6590 (KT4 Ultra)",   0,   board_msi_kt4v},
-	{0x1106, 0x3149, 0x1462, 0x7094,  0x10ec, 0x8167, 0x1462, 0x094c, NULL,         NULL,          "MSI",         "MS-6702E (K8T Neo2-F)", 0,   w83627thf_gpio4_4_raise_2e},
-	{0x1106, 0x0571, 0x1462, 0x7120,  0x1106, 0x3065, 0x1462, 0x7120, NULL,         NULL,          "MSI",         "MS-6712 (KT4V)",        0,   board_msi_kt4v},
-	{0x1039, 0x7012, 0x1462, 0x0050,  0x1039, 0x6325, 0x1462, 0x0058, NULL,         NULL,          "MSI",         "MS-7005 (651M-L)",      0,   board_msi_651ml},
-	{0x8086, 0x2658, 0x1462, 0x7046,  0x1106, 0x3044, 0x1462, 0x046d, NULL,         NULL,          "MSI",         "MS-7046",               0,   intel_ich_gpio19_raise},
-	{0x10DE, 0x005E, 0x1462, 0x7135,  0x10DE, 0x0050, 0x1462, 0x7135, "msi",        "k8n-neo3",    "MSI",         "MS-7135 (K8N Neo3)",    0,   w83627thf_gpio4_4_raise_4e},
-	{0x10DE, 0x005E, 0x1462, 0x7125,  0x10DE, 0x0052, 0x1462, 0x7125, NULL,         NULL,          "MSI",         "K8N Neo4-F",            0,   nvidia_mcp_gpio2_raise},
-	{0x1106, 0x3099,      0,      0,  0x1106, 0x3074,      0,      0, "shuttle",    "ak31",        "Shuttle",     "AK31",                  0,   w836xx_memw_enable_2e},
-	{0x1106, 0x3104, 0x1297, 0xa238,  0x1106, 0x3059, 0x1297, 0xc063, NULL,         NULL,          "Shuttle",     "AK38N",                 256, it8705f_write_enable_2e},
-	{0x10DE, 0x0050, 0x1297, 0x5036,  0x1412, 0x1724, 0x1297, 0x5036, NULL,         NULL,          "Shuttle",     "FN25",                  0,   board_shuttle_fn25},
-	{0x1106, 0x3038, 0x0925, 0x1234,  0x1106, 0x3058, 0x15DD, 0x7609, NULL,         NULL,          "Soyo",        "SY-7VCA",               0,   board_soyo_sy_7vca},
-	{0x8086, 0x1076, 0x8086, 0x1176,  0x1106, 0x3059, 0x10f1, 0x2498, NULL,         NULL,          "Tyan",        "S2498 (Tomcat K7M)",    0,   w836xx_memw_enable_2e},
-	{0x1106, 0x3177, 0x1106, 0xAA01,  0x1106, 0x3123, 0x1106, 0xAA01, NULL,         NULL,          "VIA",         "EPIA M/MII/...",        0,   via_vt823x_gpio15_raise},
-	{0x1106, 0x0259, 0x1106, 0x3227,  0x1106, 0x3065, 0x1106, 0x3149, NULL,         NULL,          "VIA",         "EPIA-N/NL",             0,   via_vt823x_gpio9_raise},
-	{0x1106, 0x5337, 0x1458, 0xb003,  0x1106, 0x287e, 0x1106, 0x337e, NULL,         NULL,          "VIA",         "PC3500G",               0,   it87xx_probe_spi_flash},
-
-	{     0,      0,      0,      0,       0,      0,      0,      0, NULL,         NULL,          NULL,          NULL,                    0,   NULL}, /* end marker */
+	/* first pci-id set [4],          second pci-id set [4],           superio,      coreboot id [2],             vendor name    board name       max_rom_...  flash enable */
+	{0x8086, 0x2926, 0x147b, 0x1084,  0x11ab, 0x4364, 0x147b, 0x1084,  WB_W83627DHG, NULL,         NULL,          "Abit",        "IP35",                  0,   intel_ich_gpio16_raise},
+	{0x105a, 0x0d30, 0x105a, 0x4d33,  0x8086, 0x1130, 0x8086,      0,  WB_W83627HF,  NULL,         NULL,          "Acorp",       "6A815EPD",              0,   board_acorp_6a815epd},
+	{0x8086, 0x24D4, 0x1849, 0x24D0,  0x8086, 0x24D5, 0x1849, 0x9739,  WB_W83627HF,  NULL,         NULL,          "ASRock",      "P4i65GV",               0,   intel_ich_gpio23_raise},
+	{0x1022, 0x746B,      0,      0,       0,      0,      0,      0,  WB_W83627HF,  "AGAMI",      "ARUMA",       "agami",       "Aruma",                 0,   w83627hf_gpio24_raise},
+	{0x1022, 0x2090,      0,      0,  0x1022, 0x2080,      0,      0,  SIO_NONE,     "artecgroup", "dbe61",       "Artec Group", "DBE61",                 0,   board_artecgroup_dbe6x},
+	{0x1022, 0x2090,      0,      0,  0x1022, 0x2080,      0,      0,  SIO_NONE,     "artecgroup", "dbe62",       "Artec Group", "DBE62",                 0,   board_artecgroup_dbe6x},
+	{0x1106, 0x3189, 0x1043, 0x807F,  0x1106, 0x3065, 0x1043, 0x80ED,  ITE_IT8712,   NULL,         NULL,          "ASUS",        "A7V600-X",              0,   board_asus_a7v600x},
+	{0x1106, 0x3189, 0x1043, 0x807F,  0x1106, 0x3177, 0x1043, 0x808C,  ITE_IT8703,   NULL,         NULL,          "ASUS",        "A7V8X",                 0,   board_asus_a7v8x},
+	{0x1106, 0x1336, 0x1043, 0x80ed,  0x1106, 0x3288, 0x1043, 0x8249,  ITE_IT8716,   NULL,         NULL,          "ASUS",        "M2V-MX",                0,   via_vt823x_gpio5_raise},
+	{0x8086, 0x1a30, 0x1043, 0x8070,  0x8086, 0x244b, 0x1043, 0x8028,  ITE_IT8708,   NULL,         NULL,          "ASUS",        "P4B266",                0,   intel_ich_gpio22_raise},
+	{0x8086, 0x1A30, 0x1043, 0x8025,  0x8086, 0x244B, 0x104D, 0x80F0,  SIO_UNKNOWN,  NULL,         NULL,          "ASUS",        "P4B266-LM",             0,   intel_ich_gpio21_raise},
+	{0x8086, 0x2570, 0x1043, 0x80F2,  0x105A, 0x3373, 0x1043, 0x80F5,  WB_W83627THF, NULL,         NULL,          "ASUS",        "P4P800-E Deluxe",       0,   intel_ich_gpio21_raise},
+	{0x10B9, 0x1541,      0,      0,  0x10B9, 0x1533,      0,      0,  SIO_UNKNOWN,  "asus",       "p5a",         "ASUS",        "P5A",                   0,   board_asus_p5a},
+	{0x10DE, 0x0030, 0x1043, 0x818a,  0x8086, 0x100E, 0x1043, 0x80EE,  SIO_UNKNOWN,  NULL,         NULL,          "ASUS",        "P5ND2-SLI Deluxe",      0,   nvidia_mcp_gpio10_raise},
+	{0x8086, 0x3590, 0x1028, 0x016c,  0x1000, 0x0030, 0x1028, 0x016c,  SIO_UNKNOWN,  NULL,         NULL,          "Dell",        "PowerEdge 1850",        0,   intel_ich_gpio23_raise},
+	{0x1106, 0x3038, 0x1019, 0x0996,  0x1106, 0x3177, 0x1019, 0x0996,  SIO_UNKNOWN,  NULL,         NULL,          "Elitegroup",  "K7VTA3",                256, NULL},
+	{0x10EC, 0x8139, 0x1695, 0x9001,  0x11C1, 0x5811, 0x1695, 0x9015,  SIO_UNKNOWN,  NULL,         NULL,          "EPoX",        "EP-8RDA3+",             0,   nvidia_mcp_gpio31_raise},
+	{0x8086, 0x7110,      0,      0,  0x8086, 0x7190,      0,      0,  SIO_UNKNOWN,  "epox",       "ep-bx3",      "EPoX",        "EP-BX3",                0,   board_epox_ep_bx3},
+	{0x10DE, 0x0050, 0x1458, 0x0C11,  0x10DE, 0x005e, 0x1458, 0x5000,  SIO_UNKNOWN,  NULL,         NULL,          "GIGABYTE",    "GA-K8N-SLI",            0,   nvidia_mcp_gpio21_raise},
+	{0x1166, 0x0223, 0x103c, 0x320d,  0x102b, 0x0522, 0x103c, 0x31fa,  SIO_UNKNOWN,  "hp",         "dl145_g3",    "HP",          "DL145 G3",              0,   board_hp_dl145_g3_enable},
+	{0x1166, 0x0205, 0x1014, 0x0347,  0x1002, 0x515E, 0x1014, 0x0325,  SIO_UNKNOWN,  NULL,         NULL,          "IBM",         "x3455",                 0,   board_ibm_x3455},
+	{0x1022, 0x7468,      0,      0,       0,      0,      0,      0,  WB_W83627HF,  "iwill",      "dk8_htx",     "IWILL",       "DK8-HTX",               0,   w83627hf_gpio24_raise},
+	{0x8086, 0x27A0,      0,      0,  0x8086, 0x27b8,      0,      0,  SIO_UNKNOWN,  "kontron",    "986lcd-m",    "Kontron",     "986LCD-M",              0,   board_kontron_986lcd_m},
+	{0x8086, 0x2411, 0x8086, 0x2411,  0x8086, 0x7125, 0x0e11, 0xb165,  SIO_UNKNOWN,  NULL,         NULL,          "Mitac",       "6513WU",                0,   board_mitac_6513wu},
+	{0x13f6, 0x0111, 0x1462, 0x5900,  0x1106, 0x3177, 0x1106,      0,  WB_W83697HF,  NULL,         NULL,          "MSI",         "MS-6590 (KT4 Ultra)",   0,   via_vt823x_gpio12_raise},
+	{0x1106, 0x3149, 0x1462, 0x7094,  0x10ec, 0x8167, 0x1462, 0x094c,  WB_W83627THF, NULL,         NULL,          "MSI",         "MS-6702E (K8T Neo2-F)", 0,   w83627thf_gpio44_raise},
+	{0x1106, 0x0571, 0x1462, 0x7120,  0x1106, 0x3065, 0x1462, 0x7120,  WB_W83697HF,  NULL,         NULL,          "MSI",         "MS-6712 (KT4V)",        0,   via_vt823x_gpio12_raise},
+	{0x1039, 0x7012, 0x1462, 0x0050,  0x1039, 0x6325, 0x1462, 0x0058,  WB_W83697HF,  NULL,         NULL,          "MSI",         "MS-7005 (651M-L)",      0,   board_msi_651ml},
+	{0x8086, 0x2658, 0x1462, 0x7046,  0x1106, 0x3044, 0x1462, 0x046d,  SIO_UNKNOWN,  NULL,         NULL,          "MSI",         "MS-7046",               0,   intel_ich_gpio19_raise},
+	{0x10DE, 0x005E, 0x1462, 0x7135,  0x10DE, 0x0050, 0x1462, 0x7135,  WB_W83627THF, "msi",        "k8n-neo3",    "MSI",         "MS-7135 (K8N Neo3)",    0,   w83627thf_gpio44_raise},
+	{0x10DE, 0x005E, 0x1462, 0x7125,  0x10DE, 0x0052, 0x1462, 0x7125,  SIO_UNKNOWN,  NULL,         NULL,          "MSI",         "K8N Neo4-F",            0,   nvidia_mcp_gpio2_raise},
+	{0x1106, 0x3104, 0x1297, 0xa238,  0x1106, 0x3059, 0x1297, 0xc063,  SIO_UNKNOWN,  NULL,         NULL,          "Shuttle",     "AK38N",                 256, NULL},
+	{0x10DE, 0x0050, 0x1297, 0x5036,  0x1412, 0x1724, 0x1297, 0x5036,  SIO_UNKNOWN,  NULL,         NULL,          "Shuttle",     "FN25",                  0,   board_shuttle_fn25},
+	{0x1106, 0x3038, 0x0925, 0x1234,  0x1106, 0x3058, 0x15DD, 0x7609,  SIO_UNKNOWN,  NULL,         NULL,          "Soyo",        "SY-7VCA",               0,   board_soyo_sy_7vca},
+	{0x1106, 0x3177, 0x1106, 0xAA01,  0x1106, 0x3123, 0x1106, 0xAA01,  VIA_VT1211,   NULL,         NULL,          "VIA",         "EPIA M/MII/...",        0,   via_vt823x_gpio15_raise},
+	{0x1106, 0x0259, 0x1106, 0x3227,  0x1106, 0x3065, 0x1106, 0x3149,  SIO_UNKNOWN,  NULL,         NULL,          "VIA",         "EPIA-N/NL",             0,   via_vt823x_gpio9_raise},
+
+	{     0,      0,      0,      0,       0,      0,      0,      0,  0,            NULL,         NULL,          NULL,          NULL,                    0,   NULL}, /* end marker */
 };
 
 /**
diff --git a/chipset_enable.c b/chipset_enable.c
index f106f96..e06562a 100644
--- a/chipset_enable.c
+++ b/chipset_enable.c
@@ -33,6 +33,7 @@ 
 #include <sys/stat.h>
 #include <fcntl.h>
 #include "flash.h"
+#include "superio.h"
 
 extern int ichspi_lock;
 
diff --git a/flash.h b/flash.h
index 75a84b0..1b1eb72 100644
--- a/flash.h
+++ b/flash.h
@@ -55,9 +55,6 @@  enum programmer {
 #if SATASII_SUPPORT == 1
 	PROGRAMMER_SATASII,
 #endif
-#if INTERNAL_SUPPORT == 1
-	PROGRAMMER_IT87SPI,
-#endif
 #if FT2232_SPI_SUPPORT == 1
 	PROGRAMMER_FT2232SPI,
 #endif
@@ -262,6 +259,8 @@  struct board_pciid_enable {
 	uint16_t second_card_vendor;
 	uint16_t second_card_device;
 
+	int superio; /* enum superio_chip */
+
 	/* The vendor / part name from the coreboot table. */
 	const char *lb_vendor;
 	const char *lb_part;
@@ -319,12 +318,16 @@  void print_supported_pcidevs(struct pcidev_status *devs);
 #endif
 void print_supported_wiki(void);
 
+#if 0
 /* 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);
+#endif
+
+/* board enable.c */
 int board_flash_enable(const char *vendor, const char *part);
 
 /* chipset_enable.c */
@@ -344,14 +347,6 @@  extern int partvendor_from_cbtable;
 
 /* internal.c */
 #if NEED_PCI == 1
-struct superio {
-	uint16_t vendor;
-	uint16_t port;
-	uint16_t model;
-};
-extern struct superio superio;
-#define SUPERIO_VENDOR_NONE	0x0
-#define SUPERIO_VENDOR_ITE	0x1
 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);
@@ -361,7 +356,6 @@  struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device,
 void get_io_perms(void);
 void release_io_perms(void);
 #if INTERNAL_SUPPORT == 1
-void probe_superio(void);
 int internal_init(void);
 int internal_shutdown(void);
 void internal_chip_writeb(uint8_t val, chipaddr addr);
@@ -593,18 +587,6 @@  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);
-struct superio probe_superio_ite(void);
-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);
@@ -612,13 +594,6 @@  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;
 
-/* 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);
-
 /* serprog.c */
 int serprog_init(void);
 int serprog_shutdown(void);
diff --git a/flashrom.c b/flashrom.c
index db44c2f..1f8979b 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -207,25 +207,6 @@  const struct programmer_entry programmer_table[] = {
 	},
 #endif
 
-#if INTERNAL_SUPPORT == 1
-	{
-		.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,
-	},
-#endif
-
 #if FT2232_SPI_SUPPORT == 1
 	{
 		.name			= "ft2232spi",
diff --git a/internal.c b/internal.c
index acb99b7..a545892 100644
--- a/internal.c
+++ b/internal.c
@@ -27,6 +27,8 @@ 
 #include <errno.h>
 #include "flash.h"
 
+#include "superio.h"
+
 #if defined(__FreeBSD__) || defined(__DragonFly__)
 int io_fd;
 #endif
@@ -125,17 +127,6 @@  void release_io_perms(void)
 }
 
 #if INTERNAL_SUPPORT == 1
-struct superio superio = {};
-
-void probe_superio(void)
-{
-	superio = probe_superio_ite();
-#if 0	/* Winbond SuperI/O code is not yet available. */
-	if (superio.vendor == SUPERIO_VENDOR_NONE)
-		superio = probe_superio_winbond();
-#endif
-}
-
 int internal_init(void)
 {
 	int ret = 0;
@@ -153,9 +144,6 @@  int internal_init(void)
 	 */
 	coreboot_init();
 
-	/* Probe for the SuperI/O chip and fill global struct superio. */
-	probe_superio();
-
 	/* try to enable it. Failure IS an option, since not all motherboards
 	 * really need this to be done, etc., etc.
 	 */
@@ -165,6 +153,10 @@  int internal_init(void)
 		       "will most likely fail.\n");
 	}
 
+	/* Probe for the SuperI/O chip and fill global struct superio. */
+	superio_probe();
+	superio_init();
+
 	board_flash_enable(lb_vendor, lb_part);
 
 	/* Even if chipset init returns an error code, we don't want to abort.
diff --git a/it87spi.c b/it87spi.c
index fcbf086..c8a8fc6 100644
--- a/it87spi.c
+++ b/it87spi.c
@@ -27,167 +27,29 @@ 
 #include <stdlib.h>
 #include "flash.h"
 #include "spi.h"
+#include "superio.h"
 
-#define ITE_SUPERIO_PORT1	0x2e
-#define ITE_SUPERIO_PORT2	0x4e
-
-uint16_t it8716f_flashport = 0;
+static uint16_t 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);
-}
+static int fast_spi = 1;
 
-void exit_conf_mode_ite(uint16_t port)
+int it8716_spi_init(uint16_t port)
 {
-	sio_write(port, 0x02, 0x02);
-}
+	ite_conf_mode_enter(port);
 
-uint16_t probe_id_ite(uint16_t port)
-{
-	uint16_t id;
-
-	enter_conf_mode_ite(port);
-	id = sio_read(port, CHIP_ID_BYTE1_REG) << 8;
-	id |= sio_read(port, CHIP_ID_BYTE2_REG);
-	exit_conf_mode_ite(port);
-
-	return id;
-}
-
-struct superio probe_superio_ite(void)
-{
-	struct superio ret = {};
-	uint16_t ite_ports[] = {ITE_SUPERIO_PORT1, ITE_SUPERIO_PORT2, 0};
-	uint16_t *i = ite_ports;
-
-	ret.vendor = SUPERIO_VENDOR_ITE;
-	for (; *i; i++) {
-		ret.port = *i;
-		ret.model = probe_id_ite(ret.port);
-		switch (ret.model >> 8) {
-		case 0x82:
-		case 0x86:
-		case 0x87:
-			msg_pinfo("Found ITE SuperI/O, id %04hx\n",
-				     ret.model);
-			return ret;
-		}
-	}
-
-	/* No good ID found. */
-	ret.vendor = SUPERIO_VENDOR_NONE;
-	ret.port = 0;
-	ret.model = 0;
-	return ret;
-}
-
-static uint16_t find_ite_spi_flash_port(uint16_t port, uint16_t id)
-{
-	uint8_t tmp = 0;
-	char *portpos = NULL;
-	uint16_t flashport = 0;
-
-	switch (id) {
-	case 0x8716:
-	case 0x8718:
-		enter_conf_mode_ite(port);
-		/* NOLDN, reg 0x24, mask out lowest bit (suspend) */
-		tmp = sio_read(port, 0x24) & 0xFE;
-		msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n",
-		       0xFFFE0000, 0xFFFFFFFF, (tmp & 1 << 1) ? "en" : "dis");
-		msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n",
-		       0x000E0000, 0x000FFFFF, (tmp & 1 << 1) ? "en" : "dis");
-		msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n",
-		       0xFFEE0000, 0xFFEFFFFF, (tmp & 1 << 2) ? "en" : "dis");
-		msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n",
-		       0xFFF80000, 0xFFFEFFFF, (tmp & 1 << 3) ? "en" : "dis");
-		msg_pdbg("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))) {
-			msg_pdbg("Enabling LPC write to serial flash\n");
-			tmp |= 1 << 4;
-			sio_write(port, 0x24, tmp);
-		}
-		msg_pdbg("Serial flash pin %i\n", (tmp & 1 << 5) ? 87 : 29);
+	if (sio_read(port, 0x24) & 0x10) {
 		/* LDN 0x7, reg 0x64/0x65 */
 		sio_write(port, 0x07, 0x7);
 		flashport = sio_read(port, 0x64) << 8;
 		flashport |= sio_read(port, 0x65);
-		msg_pdbg("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);
-			msg_pinfo("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);
-		break;
-	/* TODO: Handle more IT87xx if they support flash translation */
-	default:
-		msg_pinfo("SuperI/O ID %04hx is not on the controller list.\n", id);
-	}
-	return flashport;
-}
-
-int it87spi_common_init(void)
-{
-	if (superio.vendor != SUPERIO_VENDOR_ITE)
-		return 1;
-
-	it8716f_flashport = find_ite_spi_flash_port(superio.port, superio.model);
-
-	if (it8716f_flashport)
-		spi_controller = SPI_CONTROLLER_IT87XX;
-
-	return (!it8716f_flashport);
-}
-
 
-int it87spi_init(void)
-{
-	int ret;
-
-	get_io_perms();
-	/* Probe for the SuperI/O chip and fill global struct superio. */
-	probe_superio();
-	ret = it87spi_common_init();
-	if (!ret) {
-		buses_supported = CHIP_BUSTYPE_SPI;
-	} else {
-		buses_supported = CHIP_BUSTYPE_NONE;
+		if (flashport) {
+			spi_controller = SPI_CONTROLLER_IT87XX;
+			buses_supported = CHIP_BUSTYPE_SPI;
+		}
 	}
-	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;
+	return 0;
 }
 
 /*
@@ -206,7 +68,7 @@  int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt,
 	int i;
 
 	do {
-		busy = INB(it8716f_flashport) & 0x80;
+		busy = INB(flashport) & 0x80;
 	} while (busy);
 	if (readcnt > 3) {
 		msg_pinfo("%s called with unsupported readcnt %i.\n",
@@ -215,27 +77,27 @@  int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt,
 	}
 	switch (writecnt) {
 	case 1:
-		OUTB(writearr[0], it8716f_flashport + 1);
+		OUTB(writearr[0], flashport + 1);
 		writeenc = 0x0;
 		break;
 	case 2:
-		OUTB(writearr[0], it8716f_flashport + 1);
-		OUTB(writearr[1], it8716f_flashport + 7);
+		OUTB(writearr[0], flashport + 1);
+		OUTB(writearr[1], 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);
+		OUTB(writearr[0], flashport + 1);
+		OUTB(writearr[1], flashport + 4);
+		OUTB(writearr[2], flashport + 3);
+		OUTB(writearr[3], 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);
+		OUTB(writearr[0], flashport + 1);
+		OUTB(writearr[1], flashport + 4);
+		OUTB(writearr[2], flashport + 3);
+		OUTB(writearr[3], flashport + 2);
+		OUTB(writearr[4], flashport + 7);
 		writeenc = 0x3;
 		break;
 	default:
@@ -249,15 +111,15 @@  int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt,
 	 * 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);
+		| ((readcnt & 0x3) << 2) | (writeenc), flashport);
 
 	if (readcnt > 0) {
 		do {
-			busy = INB(it8716f_flashport) & 0x80;
+			busy = INB(flashport) & 0x80;
 		} while (busy);
 
 		for (i = 0; i < readcnt; i++)
-			readarr[i] = INB(it8716f_flashport + 5 + i);
+			readarr[i] = INB(flashport + 5 + i);
 	}
 
 	return 0;
@@ -274,12 +136,12 @@  static int it8716f_spi_page_program(struct flashchip *flash, int block, uint8_t
 	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);
+	OUTB(0x06, flashport + 1);
+	OUTB(((2 + (fast_spi ? 1 : 0)) << 4), flashport);
 	for (i = 0; i < 256; i++) {
 		chip_writeb(buf[256 * block + i], bios + 256 * block + i);
 	}
-	OUTB(0, it8716f_flashport);
+	OUTB(0, flashport);
 	/* Wait until the Write-In-Progress bit is cleared.
 	 * This usually takes 1-10 ms, so wait in 1 ms steps.
 	 */
@@ -297,7 +159,7 @@  int it8716f_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int
 	int total_size = 1024 * flash->total_size;
 	fast_spi = 0;
 
-	if ((programmer == PROGRAMMER_IT87SPI) || (total_size > 512 * 1024)) {
+	if (total_size > 512 * 1024) {
 		spi_read_chunked(flash, buf, start, len, 3);
 	} else {
 		read_memmapped(flash, buf, start, len);
@@ -315,7 +177,7 @@  int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf)
 	 * IT8716F only allows maximum of 512 kb SPI chip size for memory
 	 * mapped access.
 	 */
-	if ((programmer == PROGRAMMER_IT87SPI) || (total_size > 512 * 1024)) {
+	if (total_size > 512 * 1024) {
 		spi_chip_write_1(flash, buf);
 	} else {
 		spi_disable_blockprotect();
diff --git a/spi.c b/spi.c
index 43dc4bf..d85fc14 100644
--- a/spi.c
+++ b/spi.c
@@ -26,6 +26,7 @@ 
 #include "flash.h"
 #include "flashchips.h"
 #include "spi.h"
+#include "superio.h" /* for it87spi and wbsio */
 
 enum spi_controller spi_controller = SPI_CONTROLLER_NONE;
 void *spibar = NULL;
diff --git a/superio.c b/superio.c
new file mode 100644
index 0000000..4647321
--- /dev/null
+++ b/superio.c
@@ -0,0 +1,454 @@ 
+/*
+ * This file is part of the flashrom project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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 <stdint.h>
+
+
+#include "hwaccess.h"
+
+#include "flash.h" /* GRR! */
+
+#include "superio.h"
+
+/* Preset global variables. */
+struct superio *superio = NULL;
+uint16_t superio_port = 0;
+
+#include "flash.h"
+
+/**
+ *
+ */
+char *superio_chip_name(enum superio_chip chip)
+{
+	struct {
+		enum superio_chip chip;
+		char *name;
+	} superio_chip_name[] = {
+		{ITE_IT8703,   "ITE IT8703"},
+		{ITE_IT8705,   "ITE IT8705"},
+		{ITE_IT8712,   "ITE IT8712"},
+		{ITE_IT8716,   "ITE IT8716"},
+		{ITE_IT8718,   "ITE IT8718"},
+		{VIA_VT1211,   "VIA VT1211"},
+		{WB_W83627DHG, "Winbond W83627DHG"},
+		{WB_W83627EHF, "Winbond W83627EHF/EF/EHG/EG"},
+		{WB_W83627HF,  "Winbond W83627HF"},
+		{WB_W83627THF, "Winbond W83627THF"},
+		{WB_W83697HF,  "Winbond W83697HF"},
+		{SIO_NONE, NULL},
+	};
+	int i;
+
+	for (i = 0; superio_chip_name[i].name; i++)
+		if (superio_chip_name[i].chip == chip)
+			return superio_chip_name[i].name;
+
+	return "Unknown";
+}
+
+/* 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);
+}
+
+/*
+ * 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);
+}
+
+/**
+ *
+ */
+static uint16_t
+w836xx_detect(uint16_t port)
+{
+	uint16_t id;
+
+	w836xx_ext_enter(port);
+	id = sio_read(port, 0x20);
+	w836xx_ext_leave(port);
+
+	return id;
+}
+
+/**
+ * Only sets gpio24 for now.
+ */
+static int
+w83627hf_gpio_set(uint16_t port, int gpio, int raise)
+{
+	if (gpio != 24) {
+		fprintf(stderr, "\nERROR: Only gpio24 is supported.\n");
+		return 1;
+	}
+
+
+	w836xx_ext_enter(port);
+
+	/* 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 */
+
+	if (raise)
+		sio_mask(port, 0xF1, 0x10, 0x10);
+	else
+		sio_mask(port, 0xF1, 0, 0x10);
+
+	w836xx_ext_leave(port);
+
+	return 0;
+}
+
+/**
+ * Only raises gpio44 for now.
+ */
+static int
+w83627thf_gpio_set(uint16_t port, int gpio, int raise)
+{
+	if (gpio != 44) {
+		fprintf(stderr, "\nERROR: Only gpio44 is supported.\n");
+		return 1;
+	}
+
+	w836xx_ext_enter(port);
+
+	/* 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;
+}
+
+#if 0
+/**
+ * w83697hf: Enable MEMW# and set ROM size to max.
+ */
+static int
+w83697hf_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);
+
+	return 0;
+}
+#endif
+
+/*
+ *
+ * ITE functions.
+ *
+ */
+
+/**
+ *
+ */
+void
+ite_conf_mode_enter(uint16_t port)
+{
+	OUTB(0x87, port);
+	OUTB(0x01, port);
+	OUTB(0x55, port);
+	if (port == 0x2E)
+		OUTB(0x55, port);
+	else
+		OUTB(0xaa, port);
+}
+
+/**
+ *
+ */
+void
+ite_conf_mode_exit(uint16_t port)
+{
+	sio_write(port, 0x02, 0x02);
+}
+
+/**
+ *
+ */
+static uint16_t
+it87xx_detect(uint16_t port)
+{
+	uint16_t id;
+
+	ite_conf_mode_enter(port);
+	id = (sio_read(port, 0x20) << 8) | sio_read(port, 0x21);
+	ite_conf_mode_exit(port);
+
+	return id;
+}
+
+/**
+ *
+ */
+static int
+it8705f_write_enable(uint16_t port)
+{
+	ite_conf_mode_enter(port);
+	sio_mask(port, 0x24, 0x04, 0x04); /* Flash ROM I/F Writes Enable */
+	ite_conf_mode_exit(port);
+
+	return 0;
+}
+
+/**
+ * Only raises gpio51 for now.
+ */
+static int
+it8703_gpio_set(uint16_t port, int gpio, int raise)
+{
+	uint16_t base;
+	uint8_t tmp;
+
+	if (gpio != 51) {
+		fprintf(stderr, "\nERROR: Only gpio51 is supported.\n");
+		return -1;
+	}
+
+	/* Get the GP567 IO base */
+	w836xx_ext_enter(port);
+	sio_write(port, 0x07, 0x0C);
+	base = (sio_read(port, 0x60) << 8) | sio_read(port, 0x61);
+	w836xx_ext_leave(port);
+
+	if (!base) {
+		fprintf(stderr, "\nERROR: Failed to read IT8703F SuperIO GPIO"
+			" Base.\n");
+		return -1;
+	}
+
+	/* Raise GP51. */
+	tmp = INB(base);
+	if (raise)
+		tmp |= 0x02;
+	else
+		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(uint16_t port, int gpio, int raise)
+{
+	unsigned int block;
+	uint16_t base;
+	uint8_t tmp;
+
+	block = gpio / 10;
+	block--;
+	gpio %= 10;
+
+	/* Check gpio */
+	if ((block > 4) || /* also catches unsigned -1 */
+	    ((block < 4) && (gpio > 7)) || ((block == 4) && (gpio > 5))) {
+	    fprintf(stderr,
+		    "\nERROR: Unsupported IT8712F GPIO %02d.\n", gpio);
+	    return -1;
+	}
+
+	/* Get the GPIO base */
+	ite_conf_mode_enter(port);
+	sio_write(port, 0x07, 0x07);
+	base = (sio_read(port, 0x62) << 8) | sio_read(port, 0x63);
+	ite_conf_mode_exit(port);
+
+	if (!base) {
+		fprintf(stderr, "\nERROR: Failed to read IT8712F SuperIO GPIO"
+			" Base.\n");
+		return -1;
+	}
+
+	/* set GPIO. */
+	tmp = INB(base + block);
+	if (raise)
+	    tmp |= 1 << gpio;
+	else
+	    tmp &= ~(1 << gpio);
+	OUTB(tmp, base + block);
+
+	return 0;
+}
+
+/**
+ *
+ */
+static struct superio superios[] = {
+	{it87xx_detect, 0x8701, ITE_IT8703,   NULL,                 it8703_gpio_set},
+	{it87xx_detect, 0x8705, ITE_IT8705,   it8705f_write_enable, NULL},
+	{it87xx_detect, 0x8712, ITE_IT8712,   NULL,                 it8712f_gpio_set},
+	{it87xx_detect, 0x8716, ITE_IT8716,   it8716_spi_init,      NULL},
+	{it87xx_detect, 0x8718, ITE_IT8718,   it8716_spi_init,      NULL},
+	{w836xx_detect, 0x3C,   VIA_VT1211,   NULL,                 NULL},
+	{w836xx_detect, 0x52,   WB_W83627HF,  NULL,                 w83627hf_gpio_set},
+	//{w836xx_detect, 0x60,   WB_W83697HF,  w83697hf_memw_enable, NULL},
+	{w836xx_detect, 0x82,   WB_W83627THF, NULL,                 w83627thf_gpio_set},
+	{w836xx_detect, 0x88,   WB_W83627EHF, NULL,                 NULL},
+	{w836xx_detect, 0xA0,   WB_W83627DHG, w83627dhg_spi_init,   NULL},
+
+	{NULL, 0, SIO_NONE, NULL, NULL}	/* end marker */
+};
+
+/*
+ *
+ * High level routines.
+ *
+ */
+
+/*
+ *
+ */
+int
+superio_probe(void)
+{
+	struct superio_detect {
+		uint16_t port;
+		uint16_t (*detect) (uint16_t port);
+		char *name;
+	} superio_detects[] = {
+		{0x2E, w836xx_detect, "Winbond W836xx"},
+		{0x4E, w836xx_detect, "Winbond W836xx"},
+		{0x2E, it87xx_detect, "ITE IT87xx"},
+		{0x4E, it87xx_detect, "ITE IT87xx"},
+
+		{0, NULL} /* end marker */
+	};
+
+	int i, j;
+	uint16_t id;
+
+	for (i = 0; superio_detects[i].detect; i++) {
+
+		id = superio_detects[i].detect(superio_detects[i].port);
+		if ((id == 0xFF) || (id == 0xFFFF))
+		    continue;
+
+		msg_pdbg("Superio detection for \"%s\" on 0x%X"
+			 " returned 0x%0X\n", superio_detects[i].name,
+			 superio_detects[i].port, id);
+
+		for (j = 0; superios[j].detect; j++) {
+			if ((superios[j].detect == superio_detects[i].detect) &&
+			    (id == superios[j].id)) {
+				superio = &superios[j];
+				superio_port = superio_detects[i].port;
+				break;
+			}
+		}
+
+		if (!superio)
+			msg_perr("No matching superio found for \"%s\" (0x%X) :"
+				 " 0x%0X\n", superio_detects[i].name,
+				 superio_detects[i].port, id);
+	}
+
+	if (superio)
+		msg_pinfo("Superio \"%s\" detected on 0x%0X.\n",
+			  superio_chip_name(superio->chip), superio_port);
+	else
+		msg_pdbg("No Superio chip detected.\n");
+
+	return 0;
+}
+
+/*
+ *
+ */
+int
+superio_init(void)
+{
+	if (!superio || !superio->init)
+		return 0; /* not an error */
+
+	printf("Initialising \"%s\" superio.\n",
+	       superio_chip_name(superio->chip));
+
+	return superio->init(superio_port);
+}
+
+/*
+ *
+ */
+int
+superio_gpio_set(int gpio, int raise)
+{
+	if (!superio || !superio->gpio_set) {
+		printf("Error: Unable to set gpio line on superio.\n");
+		return 1;
+	}
+
+	printf("Setting GPIO%d(%X) on superio \"%s\" to %s\n",
+	       gpio, gpio, superio_chip_name(superio->chip),
+	       raise ? "high" : "low");
+
+	return superio->gpio_set(superio_port, gpio, raise);
+}
diff --git a/superio.h b/superio.h
new file mode 100644
index 0000000..cc1c9ba
--- /dev/null
+++ b/superio.h
@@ -0,0 +1,107 @@ 
+/*
+ * This file is part of the flashrom project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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 HAVE_SUPERIO_H
+#define HAVE_SUPERIO_H 1
+
+/*
+ *
+ */
+enum superio_chip {
+	SIO_NONE = 0,
+
+	/* ITE */
+	ITE_IT8703,
+	ITE_IT8705,
+	ITE_IT8708,
+	ITE_IT8712,
+	ITE_IT8716,
+	ITE_IT8718,
+
+	/* A lonesome VIA superio */
+	VIA_VT1211,
+
+	/* Winbond */
+	WB_W83627DHG,
+	WB_W83627EHF,
+	WB_W83627HF,
+	WB_W83627THF,
+	WB_W83697HF,
+
+	SIO_UNKNOWN
+};
+
+/*
+ *
+ */
+struct superio {
+	uint16_t (*detect) (uint16_t port);
+	uint16_t id;
+
+	enum superio_chip chip;
+
+	int (*init) (uint16_t port);
+	int (*gpio_set) (uint16_t port, int gpio, int raise);
+};
+
+struct superio *superio;
+uint16_t superio_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);
+
+void w836xx_ext_enter(uint16_t port);
+void w836xx_ext_leave(uint16_t port);
+
+void ite_conf_mode_enter(uint16_t port);
+void ite_conf_mode_exit(uint16_t port);
+
+/*
+ * High level calls.
+ */
+int superio_probe(void);
+int superio_init(void);
+int superio_gpio_set(int gpio, int raise);
+
+/*
+ *
+ * Will someone please pour the programmer infrastructure in a struct with
+ * callbacks that gets created by the init functions below? This lack of
+ * abstraction now causes us to have to include horrible flash.h before
+ * this file.
+ *
+ */
+
+/*
+ * it87spi.c
+ */
+int it8716_spi_init(uint16_t port);
+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);
+
+/*
+ * wbsio_spi.c
+ */
+int w83627dhg_spi_init(uint16_t port);
+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);
+
+#endif /* HAVE_SUPERIO_H */
diff --git a/wbsio_spi.c b/wbsio_spi.c
index 922aff1..ac95bdd 100644
--- a/wbsio_spi.c
+++ b/wbsio_spi.c
@@ -21,52 +21,28 @@ 
 #include <string.h>
 #include "flash.h"
 #include "spi.h"
-
-#define WBSIO_PORT1	0x2e
-#define WBSIO_PORT2	0x4e
+#include "superio.h"
 
 static uint16_t wbsio_spibase = 0;
 
-static uint16_t wbsio_get_spibase(uint16_t port)
+int w83627dhg_spi_init(uint16_t port)
 {
-	uint8_t id;
-	uint16_t flashport = 0;
-
 	w836xx_ext_enter(port);
-	id = sio_read(port, 0x20);
-	if (id != 0xa0) {
-		msg_perr("\nW83627 not found at 0x%x, id=0x%02x want=0xa0.\n", port, id);
-		goto done;
-	}
 
-	if (0 == (sio_read(port, 0x24) & 2)) {
-		msg_perr("\nW83627 found at 0x%x, but SPI pins are not enabled. (CR[0x24] bit 1=0)\n", port);
-		goto done;
-	}
+	if (sio_read(port, 0x24) & 0x02) { /* Are SPI pins enabled? */
+		sio_write(port, 0x07, 0x06); /* LDN 6 */
+		if (sio_read(port, 0x30) & 0x01) { /* SPI enabled? */
+			wbsio_spibase = (sio_read(port, 0x62) << 8) |
+				sio_read(port, 0x63);
 
-	sio_write(port, 0x07, 0x06);
-	if (0 == (sio_read(port, 0x30) & 1)) {
-		msg_perr("\nW83627 found at 0x%x, but SPI is not enabled. (LDN6[0x30] bit 0=0)\n", port);
-		goto done;
-	}
+			msg_pspew("\nwbsio_spibase = 0x%x\n", wbsio_spibase);
 
-	flashport = (sio_read(port, 0x62) << 8) | sio_read(port, 0x63);
+			buses_supported |= CHIP_BUSTYPE_SPI;
+			spi_controller = SPI_CONTROLLER_WBSIO;
+		}
+	}
 
-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;
-
-	msg_pspew("\nwbsio_spibase = 0x%x\n", wbsio_spibase);
-
-	buses_supported |= CHIP_BUSTYPE_SPI;
-	spi_controller = SPI_CONTROLLER_WBSIO;
 
 	return 0;
 }
-- 
1.6.0.2