Kill central list of SPI programmers

Remove the array spi_programmer, replace it by dynamic registration
instead. Also initially start with no busses supported, and switch to
the default non-SPI only for the internal programmer.

Also this patch changes the initialization for the buses_supported variable
from "everything-except-SPI" to "nothing". All programmers have to set the
bus type on their own, and this enables register_spi_programmer to just add
the SPI both for on-board SPI interfaces (where the internal programmer
already detected the other bus types), as well as for external programmers
(where we have the default "none").

Corresponding to flashrom svn r1299.

Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
diff --git a/bitbang_spi.c b/bitbang_spi.c
index d63c769..3c718af 100644
--- a/bitbang_spi.c
+++ b/bitbang_spi.c
@@ -64,6 +64,19 @@
 		bitbang_spi_master->release_bus();
 }
 
+static int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		const unsigned char *writearr, unsigned char *readarr);
+
+static const struct spi_programmer spi_programmer_bitbang = {
+	.type = SPI_CONTROLLER_BITBANG,
+	.max_data_read = MAX_DATA_READ_UNLIMITED,
+	.max_data_write = MAX_DATA_WRITE_UNLIMITED,
+	.command = bitbang_spi_send_command,
+	.multicommand = default_spi_send_multicommand,
+	.read = default_spi_read,
+	.write_256 = default_spi_write_256,
+};
+
 int bitbang_spi_init(const struct bitbang_spi_master *master, int halfperiod)
 {
 	/* BITBANG_SPI_INVALID is 0, so if someone forgot to initialize ->type,
@@ -85,6 +98,8 @@
 	bitbang_spi_master = master;
 	bitbang_spi_half_period = halfperiod;
 
+	register_spi_programmer(&spi_programmer_bitbang);
+
 	/* FIXME: Run bitbang_spi_request_bus here or in programmer init? */
 	bitbang_spi_set_cs(1);
 	bitbang_spi_set_sck(0);
@@ -127,7 +142,7 @@
 	return ret;
 }
 
-int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+static int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt,
 		const unsigned char *writearr, unsigned char *readarr)
 {
 	int i;
diff --git a/buspirate_spi.c b/buspirate_spi.c
index e7a7a10..0a9e952 100644
--- a/buspirate_spi.c
+++ b/buspirate_spi.c
@@ -81,6 +81,19 @@
 	return 0;
 }
 
+static int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		const unsigned char *writearr, unsigned char *readarr);
+
+static const struct spi_programmer spi_programmer_buspirate = {
+	.type = SPI_CONTROLLER_BUSPIRATE,
+	.max_data_read = 12,
+	.max_data_write = 12,
+	.command = buspirate_spi_send_command,
+	.multicommand = default_spi_send_multicommand,
+	.read = default_spi_read,
+	.write_256 = default_spi_write_256,
+};
+
 static const struct buspirate_spispeeds spispeeds[] = {
 	{"30k",		0x0},
 	{"125k",	0x1},
@@ -230,8 +243,7 @@
 		return 1;
 	}
 
-	buses_supported = CHIP_BUSTYPE_SPI;
-	spi_controller = SPI_CONTROLLER_BUSPIRATE;
+	register_spi_programmer(&spi_programmer_buspirate);
 
 	return 0;
 }
@@ -271,7 +283,7 @@
 	return 0;
 }
 
-int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+static int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt,
 		const unsigned char *writearr, unsigned char *readarr)
 {
 	static unsigned char *buf = NULL;
diff --git a/dediprog.c b/dediprog.c
index 989306a..1c54c66 100644
--- a/dediprog.c
+++ b/dediprog.c
@@ -248,7 +248,7 @@
 	return 0;
 }
 
-int dediprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
+static int dediprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
 {
 	int ret;
 	/* chunksize must be 512, other sizes will NOT work at all. */
@@ -293,7 +293,7 @@
 	return 0;
 }
 
-int dediprog_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len)
+static int dediprog_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len)
 {
 	int ret;
 
@@ -310,7 +310,7 @@
 	return ret;
 }
 
-int dediprog_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+static int dediprog_spi_send_command(unsigned int writecnt, unsigned int readcnt,
 			const unsigned char *writearr, unsigned char *readarr)
 {
 	int ret;
@@ -526,6 +526,16 @@
 	return millivolt;
 }
 
+static const struct spi_programmer spi_programmer_dediprog = {
+	.type = SPI_CONTROLLER_DEDIPROG,
+	.max_data_read = MAX_DATA_UNSPECIFIED,
+	.max_data_write = MAX_DATA_UNSPECIFIED,
+	.command = dediprog_spi_send_command,
+	.multicommand = default_spi_send_multicommand,
+	.read = dediprog_spi_read,
+	.write_256 = dediprog_spi_write_256,
+};
+
 /* URB numbers refer to the first log ever captured. */
 int dediprog_init(void)
 {
@@ -606,8 +616,7 @@
 		return 1;
 	}
 
-	buses_supported = CHIP_BUSTYPE_SPI;
-	spi_controller = SPI_CONTROLLER_DEDIPROG;
+	register_spi_programmer(&spi_programmer_dediprog);
 
 	/* RE leftover, leave in until the driver is complete. */
 #if 0
diff --git a/dummyflasher.c b/dummyflasher.c
index b6e67db..fdb4f2a 100644
--- a/dummyflasher.c
+++ b/dummyflasher.c
@@ -60,6 +60,19 @@
 
 static int spi_write_256_chunksize = 256;
 
+static int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		      const unsigned char *writearr, unsigned char *readarr);
+static int dummy_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len);
+
+static const struct spi_programmer spi_programmer_dummyflasher = {
+	.type = SPI_CONTROLLER_DUMMY,
+	.max_data_read = MAX_DATA_READ_UNLIMITED,
+	.max_data_write = MAX_DATA_UNSPECIFIED,
+	.command = dummy_spi_send_command,
+	.multicommand = default_spi_send_multicommand,
+	.read = default_spi_read,
+	.write_256 = dummy_spi_write_256,
+};
 int dummy_init(void)
 {
 	char *bustext = NULL;
@@ -91,8 +104,7 @@
 		msg_pdbg("Enabling support for %s flash.\n", "FWH");
 	}
 	if (strstr(bustext, "spi")) {
-		buses_supported |= CHIP_BUSTYPE_SPI;
-		spi_controller = SPI_CONTROLLER_DUMMY;
+		register_spi_programmer(&spi_programmer_dummyflasher);
 		msg_pdbg("Enabling support for %s flash.\n", "SPI");
 	}
 	if (buses_supported == CHIP_BUSTYPE_NONE)
@@ -471,7 +483,7 @@
 }
 #endif
 
-int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+static int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt,
 		      const unsigned char *writearr, unsigned char *readarr)
 {
 	int i;
@@ -507,7 +519,7 @@
 	return 0;
 }
 
-int dummy_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len)
+static int dummy_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len)
 {
 	return spi_write_chunked(flash, buf, start, len,
 				 spi_write_256_chunksize);
diff --git a/flashrom.c b/flashrom.c
index f18828c..0e9433b 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -521,10 +521,7 @@
 		.fwh		= 0xffffffff,
 		.spi		= 0xffffffff
 	};
-	/* Default to Parallel/LPC/FWH flash devices. If a known host controller
-	 * is found, the init routine sets the buses_supported bitfield.
-	 */
-	buses_supported = CHIP_BUSTYPE_NONSPI;
+	buses_supported = CHIP_BUSTYPE_NONE;
 	/* Default to top aligned flash at 4 GB. */
 	flashbase = 0;
 	/* Registering shutdown functions is now allowed. */
@@ -1712,10 +1709,6 @@
 		msg_gerr("Programmer table miscompilation!\n");
 		ret = 1;
 	}
-	if (spi_programmer_count - 1 != SPI_CONTROLLER_INVALID) {
-		msg_gerr("SPI programmer table miscompilation!\n");
-		ret = 1;
-	}
 	for (flash = flashchips; flash && flash->name; flash++)
 		if (selfcheck_eraseblocks(flash))
 			ret = 1;
diff --git a/ft2232_spi.c b/ft2232_spi.c
index 7ff1d81..f37a698 100644
--- a/ft2232_spi.c
+++ b/ft2232_spi.c
@@ -128,6 +128,19 @@
 	return 0;
 }
 
+static int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		const unsigned char *writearr, unsigned char *readarr);
+
+static const struct spi_programmer spi_programmer_ft2232 = {
+	.type = SPI_CONTROLLER_FT2232,
+	.max_data_read = 64 * 1024,
+	.max_data_write = 256,
+	.command = ft2232_spi_send_command,
+	.multicommand = default_spi_send_multicommand,
+	.read = default_spi_read,
+	.write_256 = default_spi_write_256,
+};
+
 int ft2232_spi_init(void)
 {
 	int f;
@@ -261,13 +274,12 @@
 
 	// msg_pdbg("\nft2232 chosen\n");
 
-	buses_supported = CHIP_BUSTYPE_SPI;
-	spi_controller = SPI_CONTROLLER_FT2232;
+	register_spi_programmer(&spi_programmer_ft2232);
 
 	return 0;
 }
 
-int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+static int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt,
 		const unsigned char *writearr, unsigned char *readarr)
 {
 	struct ftdi_context *ftdic = &ftdic_context;
diff --git a/ichspi.c b/ichspi.c
index 4315e78..ddd14d3 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -313,7 +313,7 @@
 		return -1;
 	}
 
-	switch (spi_controller) {
+	switch (spi_programmer->type) {
 	case SPI_CONTROLLER_ICH7:
 	case SPI_CONTROLLER_VIA:
 		preop = REGREAD16(ICH7_REG_PREOP);
@@ -388,7 +388,7 @@
 	}
 
 	msg_pdbg("\n%s: preop=%04x optype=%04x opmenu=%08x%08x\n", __func__, preop, optype, opmenu[0], opmenu[1]);
-	switch (spi_controller) {
+	switch (spi_programmer->type) {
 	case SPI_CONTROLLER_ICH7:
 	case SPI_CONTROLLER_VIA:
 		/* Register undo only for enable_undo=1, i.e. first call. */
@@ -432,7 +432,7 @@
 {
 #define BBAR_MASK	0x00ffff00
 	minaddr &= BBAR_MASK;
-	switch (spi_controller) {
+	switch (spi_programmer->type) {
 	case SPI_CONTROLLER_ICH7:
 	case SPI_CONTROLLER_VIA:
 		ichspi_bbar = mmio_readl(ich_spibar + 0x50) & ~BBAR_MASK;
@@ -801,7 +801,7 @@
 static int run_opcode(OPCODE op, uint32_t offset,
 		      uint8_t datalength, uint8_t * data)
 {
-	switch (spi_controller) {
+	switch (spi_programmer->type) {
 	case SPI_CONTROLLER_VIA:
 		if (datalength > 16) {
 			msg_perr("%s: Internal command size error for "
@@ -834,7 +834,7 @@
 	return -1;
 }
 
-int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+static int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt,
 		    const unsigned char *writearr, unsigned char *readarr)
 {
 	int result;
@@ -900,7 +900,7 @@
 	    opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
 		addr = (writearr[1] << 16) |
 		    (writearr[2] << 8) | (writearr[3] << 0);
-		switch (spi_controller) {
+		switch (spi_programmer->type) {
 		case SPI_CONTROLLER_ICH7:
 		case SPI_CONTROLLER_VIA:
 		case SPI_CONTROLLER_ICH9:
@@ -953,7 +953,7 @@
 	return result;
 }
 
-int ich_spi_send_multicommand(struct spi_command *cmds)
+static int ich_spi_send_multicommand(struct spi_command *cmds)
 {
 	int ret = 0;
 	int i;
@@ -1051,6 +1051,26 @@
 		    access_names[rwperms]);
 }
 
+static const struct spi_programmer spi_programmer_ich7 = {
+	.type = SPI_CONTROLLER_ICH7,
+	.max_data_read = 64,
+	.max_data_write = 64,
+	.command = ich_spi_send_command,
+	.multicommand = ich_spi_send_multicommand,
+	.read = default_spi_read,
+	.write_256 = default_spi_write_256,
+};
+
+static const struct spi_programmer spi_programmer_ich9 = {
+	.type = SPI_CONTROLLER_ICH9,
+	.max_data_read = 64,
+	.max_data_write = 64,
+	.command = ich_spi_send_command,
+	.multicommand = ich_spi_send_multicommand,
+	.read = default_spi_read,
+	.write_256 = default_spi_write_256,
+};
+
 int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
 			int ich_generation)
 {
@@ -1059,20 +1079,19 @@
 	uint16_t spibar_offset, tmp2;
 	uint32_t tmp;
 
-	buses_supported |= CHIP_BUSTYPE_SPI;
 	switch (ich_generation) {
 	case 7:
-		spi_controller = SPI_CONTROLLER_ICH7;
+		register_spi_programmer(&spi_programmer_ich7);
 		spibar_offset = 0x3020;
 		break;
 	case 8:
-		spi_controller = SPI_CONTROLLER_ICH9;
+		register_spi_programmer(&spi_programmer_ich9);
 		spibar_offset = 0x3020;
 		break;
 	case 9:
 	case 10:
 	default:		/* Future version might behave the same */
-		spi_controller = SPI_CONTROLLER_ICH9;
+		register_spi_programmer(&spi_programmer_ich9);
 		spibar_offset = 0x3800;
 		break;
 	}
@@ -1083,7 +1102,7 @@
 	/* Assign Virtual Address */
 	ich_spibar = rcrb + spibar_offset;
 
-	switch (spi_controller) {
+	switch (spi_programmer->type) {
 	case SPI_CONTROLLER_ICH7:
 		msg_pdbg("0x00: 0x%04x     (SPIS)\n",
 			     mmio_readw(ich_spibar + 0));
@@ -1211,6 +1230,16 @@
 	return 0;
 }
 
+static const struct spi_programmer spi_programmer_via = {
+	.type = SPI_CONTROLLER_VIA,
+	.max_data_read = 16,
+	.max_data_write = 16,
+	.command = ich_spi_send_command,
+	.multicommand = ich_spi_send_multicommand,
+	.read = default_spi_read,
+	.write_256 = default_spi_write_256,
+};
+
 int via_init_spi(struct pci_dev *dev)
 {
 	uint32_t mmio_base;
@@ -1221,8 +1250,8 @@
 	ich_spibar = physmap("VT8237S MMIO registers", mmio_base, 0x70);
 
 	/* 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;
+	buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH;
+	register_spi_programmer(&spi_programmer_via);
 
 	msg_pdbg("0x00: 0x%04x     (SPIS)\n", mmio_readw(ich_spibar + 0));
 	msg_pdbg("0x02: 0x%04x     (SPIC)\n", mmio_readw(ich_spibar + 2));
diff --git a/internal.c b/internal.c
index 33a4150..c9f62c1 100644
--- a/internal.c
+++ b/internal.c
@@ -179,6 +179,11 @@
 
 	get_io_perms();
 
+	/* Default to Parallel/LPC/FWH flash devices. If a known host controller
+	 * is found, the init routine sets the buses_supported bitfield.
+	 */
+	buses_supported = CHIP_BUSTYPE_NONSPI;
+
 	/* 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 */
diff --git a/it85spi.c b/it85spi.c
index a388d10..c6c945b 100644
--- a/it85spi.c
+++ b/it85spi.c
@@ -262,12 +262,22 @@
 	ce_low = (unsigned char*)(base + 0xD00);  /* 0xFFFFFD00 */
 #endif
 
-	/* Set this as spi controller. */
-	spi_controller = SPI_CONTROLLER_IT85XX;
-
 	return 0;
 }
 
+static int it85xx_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+			const unsigned char *writearr, unsigned char *readarr);
+
+static const struct spi_programmer spi_programmer_it85xx = {
+	.type = SPI_CONTROLLER_IT85XX,
+	.max_data_read = 64,
+	.max_data_write = 64,
+	.command = it85xx_spi_send_command,
+	.multicommand = default_spi_send_multicommand,
+	.read = default_spi_read,
+	.write_256 = default_spi_write_256,
+};
+
 int it85xx_spi_init(struct superio s)
 {
 	int ret;
@@ -284,7 +294,8 @@
 		if (buses_supported & CHIP_BUSTYPE_FWH)
 			msg_pdbg("Overriding chipset SPI with IT85 FWH|SPI.\n");
 		/* Really leave FWH enabled? */
-		buses_supported |= CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI;
+		/* Set this as spi controller. */
+		register_spi_programmer(&spi_programmer_it85xx);
 	}
 	return ret;
 }
@@ -303,7 +314,7 @@
  *   3. read date from LPC/FWH address 0xffff_fdxxh (drive CE# low and get
  *      data from MISO)
  */
-int it85xx_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+static int it85xx_spi_send_command(unsigned int writecnt, unsigned int readcnt,
 			const unsigned char *writearr, unsigned char *readarr)
 {
 	int i;
diff --git a/it87spi.c b/it87spi.c
index 2b09d64..54f41fa 100644
--- a/it87spi.c
+++ b/it87spi.c
@@ -104,6 +104,21 @@
 	return;
 }
 
+static int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+			const unsigned char *writearr, unsigned char *readarr);
+static int it8716f_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len);
+static int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf, int start, int len);
+
+static const struct spi_programmer spi_programmer_it87xx = {
+	.type = SPI_CONTROLLER_IT87XX,
+	.max_data_read = MAX_DATA_UNSPECIFIED,
+	.max_data_write = MAX_DATA_UNSPECIFIED,
+	.command = it8716f_spi_send_command,
+	.multicommand = default_spi_send_multicommand,
+	.read = it8716f_spi_chip_read,
+	.write_256 = it8716f_spi_chip_write_256,
+};
+
 static uint16_t it87spi_probe(uint16_t port)
 {
 	uint8_t tmp = 0;
@@ -180,9 +195,8 @@
 	it8716f_flashport = flashport;
 	if (buses_supported & CHIP_BUSTYPE_SPI)
 		msg_pdbg("Overriding chipset SPI with IT87 SPI.\n");
-	spi_controller = SPI_CONTROLLER_IT87XX;
 	/* FIXME: Add the SPI bus or replace the other buses with it? */
-	buses_supported |= CHIP_BUSTYPE_SPI;
+	register_spi_programmer(&spi_programmer_it87xx);
 	return 0;
 }
 
@@ -234,7 +248,7 @@
  * 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,
+static int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt,
 			const unsigned char *writearr, unsigned char *readarr)
 {
 	uint8_t busy, writeenc;
@@ -327,7 +341,7 @@
  * 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)
+static int it8716f_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len)
 {
 	fast_spi = 0;
 
@@ -344,7 +358,7 @@
 	return 0;
 }
 
-int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf, int start, int len)
+static int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf, int start, int len)
 {
 	/*
 	 * IT8716F only allows maximum of 512 kb SPI chip size for memory
diff --git a/mcp6x_spi.c b/mcp6x_spi.c
index 0e0d311..d2c31be 100644
--- a/mcp6x_spi.c
+++ b/mcp6x_spi.c
@@ -166,9 +166,6 @@
 		return 1;
 	}
 
-	buses_supported |= CHIP_BUSTYPE_SPI;
-	spi_controller = SPI_CONTROLLER_MCP6X_BITBANG;
-
 	return 0;
 }
 
diff --git a/nicintel_spi.c b/nicintel_spi.c
index 28d332e..ee7046c 100644
--- a/nicintel_spi.c
+++ b/nicintel_spi.c
@@ -162,9 +162,6 @@
 	if (bitbang_spi_init(&bitbang_spi_master_nicintel, 1))
 		return 1;
 
-	buses_supported = CHIP_BUSTYPE_SPI;
-	spi_controller = SPI_CONTROLLER_NICINTEL;
-
 	return 0;
 }
 
diff --git a/ogp_spi.c b/ogp_spi.c
index 6932f06..2916ae1 100644
--- a/ogp_spi.c
+++ b/ogp_spi.c
@@ -128,9 +128,6 @@
 	if (bitbang_spi_init(&bitbang_spi_master_ogp, 0))
 		return 1;
 
-	buses_supported = CHIP_BUSTYPE_SPI;
-	spi_controller = SPI_CONTROLLER_OGP;
-
 	return 0;
 }
 
diff --git a/programmer.h b/programmer.h
index 6ade8ed..b68aa88 100644
--- a/programmer.h
+++ b/programmer.h
@@ -372,9 +372,6 @@
 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);
-int dummy_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len);
 #endif
 
 /* nic3com.c */
@@ -485,7 +482,6 @@
 	const char *device_name;
 };
 int ft2232_spi_init(void);
-int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
 extern const struct usbdev_status devs_ft2232spi[];
 void print_supported_usbdevs(const struct usbdev_status *devs);
 #endif
@@ -505,7 +501,6 @@
 /* bitbang_spi.c */
 int bitbang_spi_init(const struct bitbang_spi_master *master, int halfperiod);
 int bitbang_spi_shutdown(const struct bitbang_spi_master *master);
-int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
 
 /* buspirate_spi.c */
 struct buspirate_spispeeds {
@@ -514,14 +509,10 @@
 };
 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);
 
 /* dediprog.c */
 int dediprog_init(void);
 int dediprog_shutdown(void);
-int dediprog_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
-int dediprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
-int dediprog_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len);
 
 /* flashrom.c */
 struct decode_sizes {
@@ -552,7 +543,6 @@
 	SPI_CONTROLLER_SB600,
 	SPI_CONTROLLER_VIA,
 	SPI_CONTROLLER_WBSIO,
-	SPI_CONTROLLER_MCP6X_BITBANG,
 #endif
 #endif
 #if CONFIG_FT2232_SPI == 1
@@ -567,16 +557,9 @@
 #if CONFIG_DEDIPROG == 1
 	SPI_CONTROLLER_DEDIPROG,
 #endif
-#if CONFIG_RAYER_SPI == 1
-	SPI_CONTROLLER_RAYER,
+#if CONFIG_OGP_SPI == 1 || CONFIG_NICINTEL_SPI == 1 || CONFIG_RAYER_SPI == 1 || (CONFIG_INTERNAL == 1 && (defined(__i386__) || defined(__x86_64__)))
+	SPI_CONTROLLER_BITBANG,
 #endif
-#if CONFIG_NICINTEL_SPI == 1
-	SPI_CONTROLLER_NICINTEL,
-#endif
-#if CONFIG_OGP_SPI == 1
-	SPI_CONTROLLER_OGP,
-#endif
-	SPI_CONTROLLER_INVALID /* This must always be the last entry. */
 };
 extern const int spi_programmer_count;
 
@@ -584,6 +567,7 @@
 #define MAX_DATA_READ_UNLIMITED 64 * 1024
 #define MAX_DATA_WRITE_UNLIMITED 256
 struct spi_programmer {
+	enum spi_controller type;
 	int max_data_read;
 	int max_data_write;
 	int (*command)(unsigned int writecnt, unsigned int readcnt,
@@ -595,13 +579,13 @@
 	int (*write_256)(struct flashchip *flash, uint8_t *buf, int start, int len);
 };
 
-extern enum spi_controller spi_controller;
-extern const struct spi_programmer spi_programmer[];
+extern const struct spi_programmer *spi_programmer;
 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);
 int default_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
 int default_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len);
+void register_spi_programmer(const struct spi_programmer *programmer);
 
 /* ichspi.c */
 #if CONFIG_INTERNAL == 1
@@ -609,40 +593,26 @@
 int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
 		    int ich_generation);
 int via_init_spi(struct pci_dev *dev);
-int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-		    const unsigned char *writearr, unsigned char *readarr);
-int ich_spi_send_multicommand(struct spi_command *cmds);
 #endif
 
 /* it85spi.c */
 int it85xx_spi_init(struct superio s);
 int it85xx_shutdown(void);
-int it85xx_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-			const unsigned char *writearr, unsigned char *readarr);
 
 /* it87spi.c */
 void enter_conf_mode_ite(uint16_t port);
 void exit_conf_mode_ite(uint16_t port);
 void probe_superio_ite(void);
 int init_superio_ite(void);
-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, int start, int len);
 
 /* sb600spi.c */
 #if CONFIG_INTERNAL == 1
 int sb600_probe_spi(struct pci_dev *dev);
-int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt,
-		      const unsigned char *writearr, unsigned char *readarr);
 #endif
 
 /* wbsio_spi.c */
 #if CONFIG_INTERNAL == 1
 int wbsio_check_for_spi(void);
-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);
 #endif
 
 /* serprog.c */
diff --git a/rayer_spi.c b/rayer_spi.c
index a01ee80..0807487 100644
--- a/rayer_spi.c
+++ b/rayer_spi.c
@@ -134,9 +134,6 @@
 	if (bitbang_spi_init(&bitbang_spi_master_rayer, 0))
 		return 1;
 
-	buses_supported = CHIP_BUSTYPE_SPI;
-	spi_controller = SPI_CONTROLLER_RAYER;
-
 	return 0;
 }
 
diff --git a/sb600spi.c b/sb600spi.c
index 269af8a..37aac3b 100644
--- a/sb600spi.c
+++ b/sb600spi.c
@@ -89,7 +89,7 @@
 		;
 }
 
-int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+static int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt,
 		      const unsigned char *writearr, unsigned char *readarr)
 {
 	int count;
@@ -192,6 +192,16 @@
 	return 0;
 }
 
+static const struct spi_programmer spi_programmer_sb600 = {
+	.type = SPI_CONTROLLER_SB600,
+	.max_data_read = 8,
+	.max_data_write = 5,
+	.command = sb600_spi_send_command,
+	.multicommand = default_spi_send_multicommand,
+	.read = default_spi_read,
+	.write_256 = default_spi_write_256,
+};
+
 int sb600_probe_spi(struct pci_dev *dev)
 {
 	struct pci_dev *smbus_dev;
@@ -304,8 +314,7 @@
 	/* Bring the FIFO to a clean state. */
 	reset_internal_fifo_pointer();
 
-	buses_supported |= CHIP_BUSTYPE_SPI;
-	spi_controller = SPI_CONTROLLER_SB600;
+	register_spi_programmer(&spi_programmer_sb600);
 	return 0;
 }
 
diff --git a/spi.c b/spi.c
index 5857fda..4610102 100644
--- a/spi.c
+++ b/spi.c
@@ -30,200 +30,42 @@
 #include "programmer.h"
 #include "spi.h"
 
-enum spi_controller spi_controller = SPI_CONTROLLER_NONE;
-
-const struct spi_programmer spi_programmer[] = {
-	{ /* SPI_CONTROLLER_NONE */
-		.max_data_read = MAX_DATA_UNSPECIFIED,
-		.max_data_write = MAX_DATA_UNSPECIFIED,
-		.command = NULL,
-		.multicommand = NULL,
-		.read = NULL,
-		.write_256 = NULL,
-	},
-
-#if CONFIG_INTERNAL == 1
-#if defined(__i386__) || defined(__x86_64__)
-	{ /* SPI_CONTROLLER_ICH7 */
-		.max_data_read = 64,
-		.max_data_write = 64,
-		.command = ich_spi_send_command,
-		.multicommand = ich_spi_send_multicommand,
-		.read = default_spi_read,
-		.write_256 = default_spi_write_256,
-	},
-
-	{ /* SPI_CONTROLLER_ICH9 */
-		.max_data_read = 64,
-		.max_data_write = 64,
-		.command = ich_spi_send_command,
-		.multicommand = ich_spi_send_multicommand,
-		.read = default_spi_read,
-		.write_256 = default_spi_write_256,
-	},
-
-	{ /* SPI_CONTROLLER_IT85XX */
-		.max_data_read = 64,
-		.max_data_write = 64,
-		.command = it85xx_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = default_spi_read,
-		.write_256 = default_spi_write_256,
-	},
-
-	{ /* SPI_CONTROLLER_IT87XX */
-		.max_data_read = MAX_DATA_UNSPECIFIED,
-		.max_data_write = MAX_DATA_UNSPECIFIED,
-		.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 */
-		.max_data_read = 8,
-		.max_data_write = 5,
-		.command = sb600_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = default_spi_read,
-		.write_256 = default_spi_write_256,
-	},
-
-	{ /* SPI_CONTROLLER_VIA */
-		.max_data_read = 16,
-		.max_data_write = 16,
-		.command = ich_spi_send_command,
-		.multicommand = ich_spi_send_multicommand,
-		.read = default_spi_read,
-		.write_256 = default_spi_write_256,
-	},
-
-	{ /* SPI_CONTROLLER_WBSIO */
-		.max_data_read = MAX_DATA_UNSPECIFIED,
-		.max_data_write = MAX_DATA_UNSPECIFIED,
-		.command = wbsio_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = wbsio_spi_read,
-		.write_256 = spi_chip_write_1,
-	},
-
-	{ /* SPI_CONTROLLER_MCP6X_BITBANG */
-		.max_data_read = MAX_DATA_READ_UNLIMITED,
-		.max_data_write = MAX_DATA_WRITE_UNLIMITED,
-		.command = bitbang_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = default_spi_read,
-		.write_256 = default_spi_write_256,
-	},
-#endif
-#endif
-
-#if CONFIG_FT2232_SPI == 1
-	{ /* SPI_CONTROLLER_FT2232 */
-		.max_data_read = 64 * 1024,
-		.max_data_write = 256,
-		.command = ft2232_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = default_spi_read,
-		.write_256 = default_spi_write_256,
-	},
-#endif
-
-#if CONFIG_DUMMY == 1
-	{ /* SPI_CONTROLLER_DUMMY */
-		.max_data_read = MAX_DATA_READ_UNLIMITED,
-		.max_data_write = MAX_DATA_UNSPECIFIED,
-		.command = dummy_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = default_spi_read,
-		.write_256 = dummy_spi_write_256,
-	},
-#endif
-
-#if CONFIG_BUSPIRATE_SPI == 1
-	{ /* SPI_CONTROLLER_BUSPIRATE */
-		.max_data_read = 12,
-		.max_data_write = 12,
-		.command = buspirate_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = default_spi_read,
-		.write_256 = default_spi_write_256,
-	},
-#endif
-
-#if CONFIG_DEDIPROG == 1
-	{ /* SPI_CONTROLLER_DEDIPROG */
-		.max_data_read = MAX_DATA_UNSPECIFIED,
-		.max_data_write = MAX_DATA_UNSPECIFIED,
-		.command = dediprog_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = dediprog_spi_read,
-		.write_256 = dediprog_spi_write_256,
-	},
-#endif
-
-#if CONFIG_RAYER_SPI == 1
-	{ /* SPI_CONTROLLER_RAYER */
-		.max_data_read = MAX_DATA_READ_UNLIMITED,
-		.max_data_write = MAX_DATA_WRITE_UNLIMITED,
-		.command = bitbang_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = default_spi_read,
-		.write_256 = default_spi_write_256,
-	},
-#endif
-
-#if CONFIG_NICINTEL_SPI == 1
-	{ /* SPI_CONTROLLER_NICINTEL */
-		.max_data_read = MAX_DATA_READ_UNLIMITED,
-		.max_data_write = MAX_DATA_WRITE_UNLIMITED,
-		.command = bitbang_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = default_spi_read,
-		.write_256 = default_spi_write_256,
-	},
-#endif
-
-#if CONFIG_OGP_SPI == 1
-	{ /* SPI_CONTROLLER_OGP */
-		.max_data_read = MAX_DATA_READ_UNLIMITED,
-		.max_data_write = MAX_DATA_WRITE_UNLIMITED,
-		.command = bitbang_spi_send_command,
-		.multicommand = default_spi_send_multicommand,
-		.read = default_spi_read,
-		.write_256 = default_spi_write_256,
-	},
-#endif
-
-	{}, /* This entry corresponds to SPI_CONTROLLER_INVALID. */
+const struct spi_programmer spi_programmer_none = {
+	.type = SPI_CONTROLLER_NONE,
+	.max_data_read = MAX_DATA_UNSPECIFIED,
+	.max_data_write = MAX_DATA_UNSPECIFIED,
+	.command = NULL,
+	.multicommand = NULL,
+	.read = NULL,
+	.write_256 = NULL,
 };
 
-const int spi_programmer_count = ARRAY_SIZE(spi_programmer);
+const struct spi_programmer *spi_programmer = &spi_programmer_none;
 
 int spi_send_command(unsigned int writecnt, unsigned int readcnt,
 		const unsigned char *writearr, unsigned char *readarr)
 {
-	if (!spi_programmer[spi_controller].command) {
+	if (!spi_programmer->command) {
 		msg_perr("%s called, but SPI is unsupported on this "
 			 "hardware. Please report a bug at "
 			 "flashrom@flashrom.org\n", __func__);
 		return 1;
 	}
 
-	return spi_programmer[spi_controller].command(writecnt, readcnt,
+	return spi_programmer->command(writecnt, readcnt,
 						      writearr, readarr);
 }
 
 int spi_send_multicommand(struct spi_command *cmds)
 {
-	if (!spi_programmer[spi_controller].multicommand) {
+	if (!spi_programmer->multicommand) {
 		msg_perr("%s called, but SPI is unsupported on this "
 			 "hardware. Please report a bug at "
 			 "flashrom@flashrom.org\n", __func__);
 		return 1;
 	}
 
-	return spi_programmer[spi_controller].multicommand(cmds);
+	return spi_programmer->multicommand(cmds);
 }
 
 int default_spi_send_command(unsigned int writecnt, unsigned int readcnt,
@@ -257,7 +99,7 @@
 
 int default_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
 {
-	int max_data = spi_programmer[spi_controller].max_data_read;
+	int max_data = spi_programmer->max_data_read;
 	if (max_data == MAX_DATA_UNSPECIFIED) {
 		msg_perr("%s called, but SPI read chunk size not defined "
 			 "on this hardware. Please report a bug at "
@@ -269,7 +111,7 @@
 
 int default_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len)
 {
-	int max_data = spi_programmer[spi_controller].max_data_write;
+	int max_data = spi_programmer->max_data_write;
 	if (max_data == MAX_DATA_UNSPECIFIED) {
 		msg_perr("%s called, but SPI write chunk size not defined "
 			 "on this hardware. Please report a bug at "
@@ -282,7 +124,7 @@
 int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len)
 {
 	int addrbase = 0;
-	if (!spi_programmer[spi_controller].read) {
+	if (!spi_programmer->read) {
 		msg_perr("%s called, but SPI read is unsupported on this "
 			 "hardware. Please report a bug at "
 			 "flashrom@flashrom.org\n", __func__);
@@ -308,7 +150,7 @@
 			 "access window.\n");
 		msg_perr("Read will probably return garbage.\n");
 	}
-	return spi_programmer[spi_controller].read(flash, buf, addrbase + start, len);
+	return spi_programmer->read(flash, buf, addrbase + start, len);
 }
 
 /*
@@ -320,14 +162,14 @@
 /* real chunksize is up to 256, logical chunksize is 256 */
 int spi_chip_write_256(struct flashchip *flash, uint8_t *buf, int start, int len)
 {
-	if (!spi_programmer[spi_controller].write_256) {
+	if (!spi_programmer->write_256) {
 		msg_perr("%s called, but SPI page write is unsupported on this "
 			 "hardware. Please report a bug at "
 			 "flashrom@flashrom.org\n", __func__);
 		return 1;
 	}
 
-	return spi_programmer[spi_controller].write_256(flash, buf, start, len);
+	return spi_programmer->write_256(flash, buf, start, len);
 }
 
 /*
@@ -337,7 +179,7 @@
  */
 uint32_t spi_get_valid_read_addr(void)
 {
-	switch (spi_controller) {
+	switch (spi_programmer->type) {
 #if CONFIG_INTERNAL == 1
 #if defined(__i386__) || defined(__x86_64__)
 	case SPI_CONTROLLER_ICH7:
@@ -349,3 +191,9 @@
 		return 0;
 	}
 }
+
+void register_spi_programmer(const struct spi_programmer *pgm)
+{
+	spi_programmer = pgm;
+	buses_supported |= CHIP_BUSTYPE_SPI;
+}
\ No newline at end of file
diff --git a/spi25.c b/spi25.c
index c9e1ebf..b3bd7a1 100644
--- a/spi25.c
+++ b/spi25.c
@@ -178,7 +178,7 @@
 	/* Some SPI controllers do not support commands with writecnt=1 and
 	 * readcnt=4.
 	 */
-	switch (spi_controller) {
+	switch (spi_programmer->type) {
 #if CONFIG_INTERNAL == 1
 #if defined(__i386__) || defined(__x86_64__)
 	case SPI_CONTROLLER_IT87XX:
@@ -1351,7 +1351,7 @@
 		.readarr	= NULL,
 	}};
 
-	switch (spi_controller) {
+	switch (spi_programmer->type) {
 #if CONFIG_INTERNAL == 1
 #if defined(__i386__) || defined(__x86_64__)
 	case SPI_CONTROLLER_IT87XX:
diff --git a/wbsio_spi.c b/wbsio_spi.c
index acf9cb2..7889f91 100644
--- a/wbsio_spi.c
+++ b/wbsio_spi.c
@@ -60,6 +60,20 @@
 	return flashport;
 }
 
+static int wbsio_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		      const unsigned char *writearr, unsigned char *readarr);
+static int wbsio_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
+
+static const struct spi_programmer spi_programmer_wbsio = {
+	.type = SPI_CONTROLLER_WBSIO,
+	.max_data_read = MAX_DATA_UNSPECIFIED,
+	.max_data_write = MAX_DATA_UNSPECIFIED,
+	.command = wbsio_spi_send_command,
+	.multicommand = default_spi_send_multicommand,
+	.read = wbsio_spi_read,
+	.write_256 = spi_chip_write_1,
+};
+
 int wbsio_check_for_spi(void)
 {
 	if (0 == (wbsio_spibase = wbsio_get_spibase(WBSIO_PORT1)))
@@ -68,8 +82,7 @@
 
 	msg_pspew("\nwbsio_spibase = 0x%x\n", wbsio_spibase);
 
-	buses_supported |= CHIP_BUSTYPE_SPI;
-	spi_controller = SPI_CONTROLLER_WBSIO;
+	register_spi_programmer(&spi_programmer_wbsio);
 	msg_pdbg("%s: Winbond saved on 4 register bits so max chip size is "
 		 "1024 KB!\n", __func__);
 	max_rom_decode.spi = 1024 * 1024;
@@ -97,7 +110,7 @@
  * 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,
+static int wbsio_spi_send_command(unsigned int writecnt, unsigned int readcnt,
 		      const unsigned char *writearr, unsigned char *readarr)
 {
 	int i;
@@ -181,7 +194,7 @@
 	return 0;
 }
 
-int wbsio_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
+static int wbsio_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
 {
 	return read_memmapped(flash, buf, start, len);
 }