[flashrom] [PATCH 4/4] Complete probing rewrite.

Stefan Tauner stefan.tauner at alumni.tuwien.ac.at
Mon Jun 16 02:50:09 CEST 2014


Some important facts:
- AT45 prober issues a 0xD7 opcode (without address) unconditionally.
- No prober weights yet - any chip matched by a single prober is
  presented to the user.

Signed-off-by: Stefan Tauner <stefan.tauner at alumni.tuwien.ac.at>
---
 82802ab.c     |   49 +-
 Makefile      |    2 +-
 at45db.c      |   48 +-
 chipdrivers.h |   36 +-
 cli_classic.c |  132 ++-
 en29lv640b.c  |   27 +-
 flash.h       |   54 +-
 flashchips.c  | 3624 +++++++++++++++++++++++++++++++++------------------------
 flashchips.h  |  888 +++++++-------
 flashrom.c    |  374 ++++--
 ichspi.c      |   52 +-
 jedec.c       |  122 +-
 m29f400bt.c   |   23 +-
 opaque.c      |   22 +-
 print.c       |   13 +-
 print_wiki.c  |   11 -
 programmer.c  |    2 +-
 programmer.h  |    5 +-
 sfdp.c        |  109 +-
 spi25.c       |  281 +----
 stm50.c       |    2 +-
 w29ee011.c    |   37 +-
 22 files changed, 3270 insertions(+), 2643 deletions(-)

diff --git a/82802ab.c b/82802ab.c
index d249c3a..5b376ce 100644
--- a/82802ab.c
+++ b/82802ab.c
@@ -40,10 +40,9 @@ void print_status_82802ab(uint8_t status)
 	msg_cdbg("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:");
 }
 
-static int probe_82802ab(struct flashctx *flash, bool shifted)
+static int probe_82802ab(struct flashctx *flash, struct probe_res *res, bool shifted)
 {
 	chipaddr bios = flash->virtual_memory;
-	uint8_t id1, id2, flashcontent1, flashcontent2;
 
 	/* Reset to get a clean state */
 	chip_writeb(flash, 0xFF, bios);
@@ -53,47 +52,37 @@ static int probe_82802ab(struct flashctx *flash, bool shifted)
 	chip_writeb(flash, 0x90, bios);
 	programmer_delay(10);
 
-	id1 = chip_readb(flash, bios + (0x00 << shifted));
-	id2 = chip_readb(flash, bios + (0x01 << shifted));
+#if (NUM_PROBE_BYTES < 2)
+#error probe_82802ab requires NUM_PROBE_BYTES to be at least 2.
+#endif
+	res->vals[0] = chip_readb(flash, bios + (0x00 << shifted));
+	res->vals[1] = chip_readb(flash, bios + (0x01 << shifted));
 
 	/* Leave ID mode */
 	chip_writeb(flash, 0xFF, bios);
 
 	programmer_delay(10);
 
-	msg_cdbg("%s: id1 0x%02x, id2 0x%02x", __func__, id1, id2);
-
-	if (!oddparity(id1))
-		msg_cdbg(", id1 parity violation");
-
-	/*
-	 * Read the product ID location again. We should now see normal
-	 * flash contents.
-	 */
-	flashcontent1 = chip_readb(flash, bios + (0x00 << shifted));
-	flashcontent2 = chip_readb(flash, bios + (0x01 << shifted));
-
-	if (id1 == flashcontent1)
-		msg_cdbg(", id1 is normal flash content");
-	if (id2 == flashcontent2)
-		msg_cdbg(", id2 is normal flash content");
-
-	msg_cdbg("\n");
-	if (id1 != flash->chip->manufacture_id || id2 != flash->chip->model_id)
+	uint8_t cont[2];
+	cont[0] = chip_readb(flash, bios + (0x00 << shifted));
+	cont[1] = chip_readb(flash, bios + (0x01 << shifted));
+	if (test_for_valid_ids(res->vals, cont, 2)) {
+		res->len = 2;
+		return 1;
+	} else {
+		res->len = 0;
 		return 0;
-
-
-	return 1;
+	}
 }
 
-int probe_82802ab_shifted(struct flashctx *flash)
+int probe_82802ab_shifted(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2)
 {
-	return probe_82802ab(flash, true);
+	return probe_82802ab(flash, res, true);
 }
 
-int probe_82802ab_unshifted(struct flashctx *flash)
+int probe_82802ab_unshifted(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2)
 {
-	return probe_82802ab(flash, false);
+	return probe_82802ab(flash, res, false);
 }
 
 /* FIXME: needs timeout */
diff --git a/Makefile b/Makefile
index 7a48889..4500b5e 100644
--- a/Makefile
+++ b/Makefile
@@ -35,7 +35,7 @@ INSTALL = install
 DIFF    = diff
 PREFIX  ?= /usr/local
 MANDIR  ?= $(PREFIX)/share/man
-CFLAGS  ?= -Os -Wall -Wshadow
+CFLAGS  ?= -Os -Wall -Wshadow -g
 EXPORTDIR ?= .
 AR      ?= ar
 RANLIB  ?= ranlib
diff --git a/at45db.c b/at45db.c
index 5396d7f..1150d3a 100644
--- a/at45db.c
+++ b/at45db.c
@@ -170,48 +170,26 @@ int spi_prettyprint_status_register_at45db(struct flashctx *flash)
 	return 0;
 }
 
-/* Probe function for AT45DB* chips that support multiple page sizes. */
-int probe_spi_at45db(struct flashctx *flash)
+/* Probe function for AT45DB* chips that support multiple page sizes. In order to tell which page size a chip
+ * has we need to read the status register and investigate bit #0. */
+int probe_spi_at45db(struct flashctx *flash, struct probe_res *res, unsigned int res_len, const struct probe *p)
 {
-	uint8_t status;
-	struct flashchip *chip = flash->chip;
+#if (NUM_PROBE_BYTES < 1)
+#error probe_spi_at45db requires NUM_PROBE_BYTES to be at least 1.
+#endif
 
-	if (!probe_spi_rdid(flash))
-		return 0;
+	if (res_len == 0)
+		return -1;
 
-	/* Some AT45DB* chips support two different page sizes each (e.g. 264 and 256 B). In order to tell which
-	 * page size this chip has we need to read the status register. */
+	uint8_t status;
 	if (at45db_read_status_register(flash, &status) != 0)
-		return 0;
-
-	/* We assume sane power-of-2 page sizes and adjust the chip attributes in case this is not the case. */
-	if ((status & AT45DB_POWEROF2) == 0) {
-		chip->total_size = (chip->total_size / 32) * 33;
-		chip->page_size = (chip->page_size / 32) * 33;
-
-		unsigned int i, j;
-		for (i = 0; i < NUM_ERASEFUNCTIONS; i++) {
-			struct block_eraser *eraser = &chip->block_erasers[i];
-			for (j = 0; j < NUM_ERASEREGIONS; j++) {
-				eraser->eraseblocks[j].size = (eraser->eraseblocks[j].size / 32) * 33;
-			}
-		}
-	}
+		return -1;
 
-	switch (chip->page_size) {
-	case 256: chip->gran = write_gran_256bytes; break;
-	case 264: chip->gran = write_gran_264bytes; break;
-	case 512: chip->gran = write_gran_512bytes; break;
-	case 528: chip->gran = write_gran_528bytes; break;
-	case 1024: chip->gran = write_gran_1024bytes; break;
-	case 1056: chip->gran = write_gran_1056bytes; break;
-	default:
-		msg_cerr("%s: unknown page size %d.\n", __func__, chip->page_size);
+	if (status == 0xFF || status == 0x00)
 		return 0;
-	}
-
-	msg_cdbg2("%s: total size %i kB, page size %i B\n", __func__, chip->total_size * 1024, chip->page_size);
 
+	res->vals[0] = status & AT45DB_POWEROF2;
+	res->len = 1;
 	return 1;
 }
 
diff --git a/chipdrivers.h b/chipdrivers.h
index 11a7191..668bd00 100644
--- a/chipdrivers.h
+++ b/chipdrivers.h
@@ -33,13 +33,10 @@ int spi_chip_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int
 int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start, int unsigned len);
 
 /* spi25.c */
-int probe_spi_rdid(struct flashctx *flash);
-int probe_spi_rdid4(struct flashctx *flash);
-int probe_spi_rems(struct flashctx *flash);
-int probe_spi_res1(struct flashctx *flash);
-int probe_spi_res2(struct flashctx *flash);
-int probe_spi_res3(struct flashctx *flash);
-int probe_spi_at25f(struct flashctx *flash);
+int probe_spi_rdid(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2);
+int probe_spi_rems(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2);
+int probe_spi_res(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2);
+int probe_spi_at25f(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2);
 int spi_write_enable(struct flashctx *flash);
 int spi_write_disable(struct flashctx *flash);
 int spi_block_erase_20(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
@@ -108,12 +105,12 @@ int probe_spi_sfdp(struct flashctx *flash);
 
 /* opaque.c */
 int probe_opaque(struct flashctx *flash);
-int read_opaque(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
-int write_opaque(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
-int erase_opaque(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen);
+
+/* flashrom.c */
+int probe_allsizes(struct flashctx *flash, struct probe_res *res, unsigned int res_len, const struct probe *p);
 
 /* at45db.c */
-int probe_spi_at45db(struct flashctx *flash);
+int probe_spi_at45db(struct flashctx *flash, struct probe_res *res, unsigned int res_len, const struct probe *p);
 int spi_prettyprint_status_register_at45db(struct flashctx *flash);
 int spi_disable_blockprotect_at45db(struct flashctx *flash);
 int spi_read_at45db(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
@@ -127,8 +124,8 @@ int spi_erase_at45cs_sector(struct flashctx *flash, unsigned int addr, unsigned
 
 /* 82802ab.c */
 uint8_t wait_82802ab(struct flashctx *flash);
-int probe_82802ab_shifted(struct flashctx *flash);
-int probe_82802ab_unshifted(struct flashctx *flash);
+int probe_82802ab_shifted(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2);
+int probe_82802ab_unshifted(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2);
 int erase_block_82802ab(struct flashctx *flash, unsigned int page, unsigned int pagesize);
 int write_82802ab(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
 void print_status_82802ab(uint8_t status);
@@ -138,9 +135,14 @@ int unlock_lh28f008bjt(struct flashctx *flash);
 
 /* jedec.c */
 uint8_t oddparity(uint8_t val);
+bool test_for_valid_ids(uint8_t *ids, uint8_t *content, unsigned int len);
 void toggle_ready_jedec(const struct flashctx *flash, chipaddr dst);
 void data_polling_jedec(const struct flashctx *flash, chipaddr dst, uint8_t data);
-int probe_jedec(struct flashctx *flash);
+int probe_jedec_longreset(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2);
+int probe_jedec_shortreset_full(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2);
+int probe_jedec_shortreset_full_384(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2);
+int probe_jedec_shortreset_aaa(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2);
+int probe_jedec_shortreset_2aa(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2);
 int write_jedec(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
 int write_jedec_1(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
 int erase_sector_jedec(struct flashctx *flash, unsigned int page, unsigned int pagesize);
@@ -148,7 +150,7 @@ int erase_block_jedec(struct flashctx *flash, unsigned int page, unsigned int bl
 int erase_chip_block_jedec(struct flashctx *flash, unsigned int page, unsigned int blocksize);
 
 /* m29f400bt.c */
-int probe_m29f400bt(struct flashctx *flash);
+int probe_m29f400bt(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2);
 int write_m29f400bt(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
 void protect_m29f400bt(struct flashctx *flash, chipaddr bios);
 
@@ -190,7 +192,7 @@ int unlock_w39v080fa(struct flashctx *flash);
 int printlock_at49f(struct flashctx *flash);
 
 /* w29ee011.c */
-int probe_w29ee011(struct flashctx *flash);
+int probe_w29ee011(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2);
 
 /* stm50.c */
 int erase_sector_stm50(struct flashctx *flash, unsigned int block, unsigned int blocksize);
@@ -198,7 +200,7 @@ int unlock_stm50_uniform(struct flashctx *flash);
 int unlock_stm50_nonuniform(struct flashctx *flash);
 
 /* en29lv640b.c */
-int probe_en29lv640b(struct flashctx *flash);
+int probe_en29lv640b(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2);
 int erase_block_shifted_jedec(struct flashctx *flash, unsigned int start, unsigned int len);
 int erase_chip_block_shifted_jedec(struct flashctx *flash, unsigned int start, unsigned int len);
 int write_en29lv640b(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
diff --git a/cli_classic.c b/cli_classic.c
index db76fbc..9068dc7 100644
--- a/cli_classic.c
+++ b/cli_classic.c
@@ -158,13 +158,9 @@ static void check_chip_supported(const struct flashchip *chip)
 
 int main(int argc, char *argv[])
 {
-	/* Probe for up to three flash chips. */
-	const struct flashchip *chip = NULL;
-	struct flashctx flashes[3] = {{0}};
-	struct flashctx *fill_flash;
 	const char *name;
-	int namelen, opt, i, j;
-	int startchip = -1, chipcount = 0, option_index = 0, force = 0;
+	int namelen, opt, i;
+	int option_index = 0, force = 0;
 #if CONFIG_PRINT_WIKI == 1
 	int list_supported_wiki = 0;
 #endif
@@ -445,6 +441,7 @@ int main(int argc, char *argv[])
 		ret = 1;
 		goto out;
 	}
+	const struct flashchip *chip = NULL;
 	/* Does a chip with the requested name exist in the flashchips array? */
 	if (chip_to_probe) {
 		for (chip = flashchips; chip && chip->name; chip++)
@@ -492,84 +489,91 @@ int main(int argc, char *argv[])
 	msg_pdbg("The following protocols are supported: %s.\n", tempstr);
 	free(tempstr);
 
-	for (j = 0; j < registered_programmer_count; j++) {
-		startchip = 0;
-		while (chipcount < ARRAY_SIZE(flashes)) {
-			startchip = probe_flash(&registered_programmers[j], startchip, &flashes[chipcount], 0);
-			if (startchip == -1)
-				break;
-			chipcount++;
-			startchip++;
-		}
+	/* Probe for up to three flash chips. */
+	struct flashctx *flashes = NULL;
+	int chipcount = probe_flash(&flashes, NULL);
+	if (chipcount < 0) {
+		msg_cerr("Error: Probing for flash chips failed.\n");
+		ret = 1;
+		goto out_free_flashes;
 	}
 
-	if (chipcount > 1) {
-		msg_cinfo("Multiple flash chip definitions match the detected chip(s): \"%s\"",
-			  flashes[0].chip->name);
-		for (i = 1; i < chipcount; i++)
-			msg_cinfo(", \"%s\"", flashes[i].chip->name);
-		msg_cinfo("\nPlease specify which chip definition to use with the -c <chipname> option.\n");
-		ret = 1;
-		goto out_shutdown;
-	} else if (!chipcount) {
+	struct flashctx *flash;
+	if (chipcount == 0) {
 		msg_cinfo("No EEPROM/flash device found.\n");
 		if (!force || !chip_to_probe) {
 			msg_cinfo("Note: flashrom can never write if the flash chip isn't found "
 				  "automatically.\n");
 		}
 		if (force && read_it && chip_to_probe) {
-			struct registered_programmer *pgm;
 			int compatible_programmers = 0;
 			msg_cinfo("Force read (-f -r -c) requested, pretending the chip is there:\n");
-			/* This loop just counts compatible controllers. */
+			flash = malloc(sizeof(struct flashctx));
+			if (flash == NULL) {
+				msg_cerr("Out of memory!\n");
+				ret = 1;
+				goto out_free_flashes;
+			}
+			/* chip is still set from the chip_to_probe check earlier in this function. */
+			flash->chip = chip;
+			unsigned int j;
 			for (j = 0; j < registered_programmer_count; j++) {
-				pgm = &registered_programmers[j];
-				/* chip is still set from the chip_to_probe earlier in this function. */
-				if (pgm->buses_supported & chip->bustype)
+				flash->pgm = &registered_programmers[j];
+				if (flash->pgm->buses_supported & chip->bustype)
 					compatible_programmers++;
 			}
 			if (!compatible_programmers) {
 				msg_cinfo("No compatible controller found for the requested flash chip.\n");
 				ret = 1;
-				goto out_shutdown;
+				goto out_free_flashes;
 			}
 			if (compatible_programmers > 1)
 				msg_cinfo("More than one compatible controller found for the requested flash "
 					  "chip, using the first one.\n");
-			for (j = 0; j < registered_programmer_count; j++) {
-				pgm = &registered_programmers[j];
-				startchip = probe_flash(pgm, 0, &flashes[0], 1);
-				if (startchip != -1)
-					break;
-			}
-			if (startchip == -1) {
-				// FIXME: This should never happen! Ask for a bug report?
-				msg_cinfo("Probing for flash chip '%s' failed.\n", chip_to_probe);
-				ret = 1;
-				goto out_shutdown;
-			}
 			msg_cinfo("Please note that forced reads most likely contain garbage.\n");
-			ret = read_flash_to_file(&flashes[0], filename);
-			free(flashes[0].chip);
-			goto out_shutdown;
+			ret = read_flash_to_file(flash, filename);
+			free(flash);
+			goto out_free_flashes;
+		} else {
+			ret = 1;
+			goto out_free_flashes;
 		}
-		ret = 1;
-		goto out_shutdown;
-	} else if (!chip_to_probe) {
-		/* repeat for convenience when looking at foreign logs */
-		tempstr = flashbuses_to_text(flashes[0].chip->bustype);
-		msg_gdbg("Found %s flash chip \"%s\" (%d kB, %s).\n",
-			 flashes[0].chip->vendor, flashes[0].chip->name, flashes[0].chip->total_size, tempstr);
-		free(tempstr);
-	}
+	} else if (chipcount == 1) {
+		flash = &flashes[0];
+	} else {
+		msg_cinfo("%d flash chip definitions match the genuine chip: ", chipcount);
 
-	fill_flash = &flashes[0];
+		msg_cinfo("\"%s\"", flashes[0].chip->name);
+		for (i = 1; i < chipcount; i++)
+			msg_cinfo(", \"%s\"", flashes[i].chip->name);
+
+		msg_cinfo("\n");
+		if (chip_to_probe == NULL) {
+			msg_cinfo("Please specify which chip definition to use with the "
+				  "--chip/-c <chipname> option.\n");
+			ret = 1;
+			goto out_free_flashes;
+		}
+		for (i = 0; i < chipcount; i++) {
+			if (strcmp(flashes[i].chip->name, chip_to_probe) == 0) {
+				flash = &flashes[i];
+				msg_cinfo("Using %s as requested.\n", flash->chip->name);
+				break;
+			}
+		}
+		if (flash == NULL) {
+			msg_cerr("The chip supplied with the --chip/-c option was not detected automatically.\n"
+				 "You can enforce using it with the --force/-f option.\n");
+			ret = 1;
+			goto out_free_flashes;
+		}
+	}
 
-	check_chip_supported(fill_flash->chip);
+	check_chip_supported(flash->chip);
 
-	unsigned int limitexceeded = count_max_decode_exceedings(fill_flash);
+	unsigned int limitexceeded = count_max_decode_exceedings(flash);
 	if (limitexceeded > 0 && !force) {
-		enum chipbustype commonbuses = fill_flash->pgm->buses_supported & fill_flash->chip->bustype;
+		enum chipbustype commonbuses = flash->pgm->buses_supported & flash->chip->bustype;
 
 		/* Sometimes chip and programmer have more than one bus in common,
 		 * and the limit is not exceeded on all buses. Tell the user. */
@@ -580,12 +584,12 @@ int main(int argc, char *argv[])
 		msg_cerr("This flash chip is too big for this programmer (--verbose/-V gives details).\n"
 			 "Use --force/-f to override at your own risk.\n");
 		ret = 1;
-		goto out_shutdown;
+		goto out_free_flashes;
 	}
 
 	if (!(read_it | write_it | verify_it | erase_it)) {
 		msg_ginfo("No operations were specified.\n");
-		goto out_shutdown;
+		goto out_free_flashes;
 	}
 
 	/* Always verify write operations unless -n is used. */
@@ -597,13 +601,15 @@ int main(int argc, char *argv[])
 	 * Give the chip time to settle.
 	 */
 	programmer_delay(100000);
-	ret |= doit(fill_flash, force, filename, read_it, write_it, erase_it, verify_it);
+	ret |= doit(flash, force, filename, read_it, write_it, erase_it, verify_it);
 
+out_free_flashes:
+	free(flashes);
 out_shutdown:
 	programmer_shutdown();
 out:
-	for (i = 0; i < chipcount; i++)
-		free(flashes[i].chip);
+	//for (i = 0; i < chipcount; i++)
+		//free(flashes[i]->chip);
 
 	layout_cleanup();
 	free(filename);
diff --git a/en29lv640b.c b/en29lv640b.c
index a274f62..47da1a1 100644
--- a/en29lv640b.c
+++ b/en29lv640b.c
@@ -58,10 +58,9 @@ int write_en29lv640b(struct flashctx *flash, const uint8_t *src, unsigned int st
 	return 0;
 }
 
-int probe_en29lv640b(struct flashctx *flash)
+int probe_en29lv640b(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2)
 {
 	chipaddr bios = flash->virtual_memory;
-	uint16_t id1, id2;
 
 	chip_writeb(flash, 0xAA, bios + 0xAAA);
 	chip_writeb(flash, 0x55, bios + 0x555);
@@ -69,21 +68,29 @@ int probe_en29lv640b(struct flashctx *flash)
 
 	programmer_delay(10);
 
-	id1 = chip_readb(flash, bios + 0x200);
-	id1 |= (chip_readb(flash, bios) << 8);
+#if (NUM_PROBE_BYTES < 3)
+#error probe_en29lv640b requires NUM_PROBE_BYTES to be at least 3.
+#endif
+	res->vals[0] = chip_readb(flash, bios + 0x200);
+	res->vals[1] = chip_readb(flash, bios);
 
-	id2 = chip_readb(flash, bios + 0x02);
+	res->vals[2] = chip_readb(flash, bios + 0x02);
 
 	chip_writeb(flash, 0xF0, bios + 0xAAA);
-
 	programmer_delay(10);
 
-	msg_cdbg("%s: id1 0x%04x, id2 0x%04x\n", __func__, id1, id2);
+	uint8_t cont[3];
+	cont[0] = chip_readb(flash, bios + 0x200);
+	cont[1] = chip_readb(flash, bios);
+	cont[2] = chip_readb(flash, bios + 0x02);
 
-	if (id1 == flash->chip->manufacture_id && id2 == flash->chip->model_id)
+	if (test_for_valid_ids(res->vals, cont, 3)) {
+		res->len = 3;
 		return 1;
-
-	return 0;
+	} else {
+		res->len = 0;
+		return 0;
+	}
 }
 
 static int erase_chip_shifted_jedec(struct flashctx *flash)
diff --git a/flash.h b/flash.h
index d26d90b..ed0aeeb 100644
--- a/flash.h
+++ b/flash.h
@@ -53,6 +53,7 @@ typedef uint32_t chipsize_t; /* Able to store the number of bytes of any support
 #define PRIxCHIPADDR "06"PRIx32
 #define PRIuCHIPSIZE PRIu32
 
+int shutdown_free(void *data);
 int register_shutdown(int (*function) (void *data), void *data);
 void *programmer_map_flash_region(const char *descr, uintptr_t phys_addr, size_t len);
 void programmer_unmap_flash_region(void *virt_addr, size_t len);
@@ -140,8 +141,36 @@ enum test_state {
 #define TEST_BAD_PRE	(struct tested){ .probe = BAD, .read = BAD, .erase = BAD, .write = NT }
 #define TEST_BAD_PREW	(struct tested){ .probe = BAD, .read = BAD, .erase = BAD, .write = BAD }
 
+
+#define NUM_PROBES 3
+#define NUM_PROBE_BYTES 5 /* Values below 2 will break code. */
+
 struct flashctx;
-typedef int (erasefunc_t)(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+struct registered_programmer; /* programmer.h */
+struct probe;
+struct probe_res;
+
+/* fixme  */
+typedef int (probefunc_t)(struct flashctx *flash, struct probe_res *res, unsigned int res_len, const struct probe *p);
+
+typedef struct probe_res {
+	uint8_t len;
+	uint8_t vals[NUM_PROBE_BYTES];
+	probefunc_t *probe_func;
+	unsigned int chip_size; /* in kB */
+} probe_res;
+
+typedef struct probe {
+	probefunc_t *probe_func;
+	enum chipbustype bustype;
+	const char *mnemonic;
+	uint16_t size_min;
+	uint16_t size_max;
+	uint8_t size_step;
+} probe;
+
+/* An erase function should try to erase one block of size 'len' at address 'addr' and return 0 on success. */
+typedef int (erasefunc_t)(struct flashctx *flash, unsigned int addr, unsigned int len);
 
 struct flashchip {
 	const char *vendor;
@@ -149,14 +178,6 @@ struct flashchip {
 
 	enum chipbustype bustype;
 
-	/*
-	 * With 32bit manufacture_id and model_id we can cover IDs up to
-	 * (including) the 4th bank of JEDEC JEP106W Standard Manufacturer's
-	 * Identification code.
-	 */
-	uint32_t manufacture_id;
-	uint32_t model_id;
-
 	/* Total chip size in kilobytes */
 	unsigned int total_size;
 	/* Chip page size in bytes */
@@ -171,7 +192,10 @@ struct flashchip {
 		enum test_state write;
 	} tested;
 
-	int (*probe) (struct flashctx *flash);
+	struct prober {
+		probefunc_t *func;
+		struct probe_res res;
+	} probers[NUM_PROBES];
 
 	/*
 	 * Erase blocks and associated erase function. Any chip erase function
@@ -185,9 +209,7 @@ struct flashchip {
 			unsigned int size; /* Eraseblock size in bytes */
 			unsigned int count; /* Number of contiguous blocks with that size */
 		} eraseblocks[NUM_ERASEREGIONS];
-		/* a block_erase function should try to erase one block of size
-		 * 'blocklen' at address 'blockaddr' and return 0 on success. */
-		int (*block_erase) (struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen);
+		erasefunc_t *block_erase;
 	} block_erasers[NUM_ERASEFUNCTIONS];
 
 	int (*printlock) (struct flashctx *flash);
@@ -202,7 +224,7 @@ struct flashchip {
 };
 
 struct flashctx {
-	struct flashchip *chip;
+	const struct flashchip *chip;
 	chipaddr virtual_memory;
 	/* Some flash devices have an additional register space. */
 	chipaddr virtual_registers;
@@ -241,7 +263,7 @@ extern const char flashrom_version[];
 extern const char *chip_to_probe;
 int read_memmapped(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
 int erase_flash(struct flashctx *flash);
-int probe_flash(struct registered_programmer *pgm, int startchip, struct flashctx *fill_flash, int force);
+int probe_flash(struct flashctx **flashes, const struct registered_programmer *pgm);
 int read_flash_to_file(struct flashctx *flash, const char *filename);
 char *extract_param(const char *const *haystack, const char *needle, const char *delim);
 int verify_range(struct flashctx *flash, const uint8_t *cmpbuf, unsigned int start, unsigned int len);
@@ -327,5 +349,7 @@ int spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int
 int spi_send_multicommand(struct flashctx *flash, struct spi_command *cmds);
 uint32_t spi_get_valid_read_addr(struct flashctx *flash);
 
+/* programmer.c */
 enum chipbustype get_buses_supported(void);
+
 #endif				/* !__FLASH_H__ */
diff --git a/flashchips.c b/flashchips.c
index 6e6b3a8..18637f5 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -60,13 +60,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMD",
 		.name		= "Am29F010A/B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AMD_AM29F010B,	/* Same as Am29F010A */
 		.total_size	= 128,
 		.page_size	= 16 * 1024,
-		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
+		.feature_bits	= FEATURE_ADDR_2AA,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, {  AMIC_ID, AMD_AM29F010B } } }, /* Same as Am29F010A */
+		},
 		.block_erasers	=
 		{
 			{
@@ -86,13 +87,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMD",
 		.name		= "Am29F002(N)BB",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AMD_AM29F002BB,
 		.total_size	= 256,
 		.page_size	= 256,
-		.feature_bits	= FEATURE_SHORT_RESET | FEATURE_ADDR_2AA,
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMD_ID, AMD_AM29F002BB } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -117,13 +119,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMD",
 		.name		= "Am29F002(N)BT",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AMD_AM29F002BT,
 		.total_size	= 256,
 		.page_size	= 256,
-		.feature_bits	= FEATURE_EITHER_RESET | FEATURE_ADDR_2AA,
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMD_ID, AMD_AM29F002BT } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -148,13 +151,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMD",
 		.name		= "Am29F016D",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AMD_AM29F016D,
-		.total_size	= 2 * 1024,
+		.total_size	= 2048,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMD_ID, AMD_AM29F016D } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -174,13 +178,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMD",
 		.name		= "Am29F040B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AMD_AM29F040B,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMD_ID, AMD_AM29F040B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -200,13 +205,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMD",
 		.name		= "Am29F080B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AMD_AM29F080B,
 		.total_size	= 1024,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMD_ID, AMD_AM29F080B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -226,13 +232,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMD",
 		.name		= "Am29LV001BB",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AMD_AM29LV001BB,
 		.total_size	= 128,
 		.page_size	= 64 * 1024, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMD_ID, AMD_AM29LV001BB } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -256,13 +263,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMD",
 		.name		= "Am29LV001BT",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AMD_AM29LV001BT,
 		.total_size	= 128,
 		.page_size	= 64 * 1024, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMD_ID, AMD_AM29LV001BT } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -286,13 +294,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMD",
 		.name		= "Am29LV002BB",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AMD_AM29LV002BB,
 		.total_size	= 256,
 		.page_size	= 64 * 1024, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMD_ID, AMD_AM29LV002BB } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -317,13 +326,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMD",
 		.name		= "Am29LV002BT",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AMD_AM29LV002BT,
 		.total_size	= 256,
 		.page_size	= 64 * 1024, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMD_ID, AMD_AM29LV002BT } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -348,13 +358,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMD",
 		.name		= "Am29LV004BB",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AMD_AM29LV004BB,
 		.total_size	= 512,
 		.page_size	= 64 * 1024, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMD_ID, AMD_AM29LV004BB } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -379,13 +390,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMD",
 		.name		= "Am29LV004BT",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AMD_AM29LV004BT,
 		.total_size	= 512,
 		.page_size	= 64 * 1024, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMD_ID, AMD_AM29LV004BT } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -410,13 +422,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMD",
 		.name		= "Am29LV008BB",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AMD_AM29LV008BB,
 		.total_size	= 1024,
 		.page_size	= 64 * 1024, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMD_ID, AMD_AM29LV008BB } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -441,13 +454,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMD",
 		.name		= "Am29LV008BT",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AMD_AM29LV008BT,
 		.total_size	= 1024,
 		.page_size	= 64 * 1024, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMD_ID, AMD_AM29LV008BT } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -472,13 +486,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMD",
 		.name		= "Am29LV040B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AMD_AM29LV040B,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMD_ID, AMD_AM29LV040B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -498,13 +513,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMD",
 		.name		= "Am29LV081B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMD_ID,
-		.model_id	= AMD_AM29LV080B,
 		.total_size	= 1024,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET, /* datasheet specifies address as don't care */
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMD_ID, AMD_AM29LV080B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -524,13 +540,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L05PT",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID,
-		.model_id	= AMIC_A25L05PT,
 		.total_size	= 64,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid4,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 4, {  AMIC_ID, AMIC_A25L05PT } } },
+			{ probe_spi_res,  { 1, { 0x05 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -557,13 +575,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L05PU",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID,
-		.model_id	= AMIC_A25L05PU,
 		.total_size	= 64,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid4,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 4, { AMIC_ID, AMIC_A25L05PU } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -590,13 +609,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L10PT",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID,
-		.model_id	= AMIC_A25L10PT,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid4,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 4, { AMIC_ID, AMIC_A25L10PT } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -624,13 +644,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L10PU",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID,
-		.model_id	= AMIC_A25L10PU,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid4,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 4, { AMIC_ID, AMIC_A25L10PU } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -658,13 +679,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L20PT",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID,
-		.model_id	= AMIC_A25L20PT,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid4,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 4, { AMIC_ID, AMIC_A25L20PT } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -692,13 +714,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L20PU",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID,
-		.model_id	= AMIC_A25L20PU,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid4,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 4, { AMIC_ID, AMIC_A25L20PU } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -731,13 +754,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L40PT",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID,
-		.model_id	= AMIC_A25L40PT,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_spi_rdid4,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 4, { AMIC_ID, AMIC_A25L40PT } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -765,13 +789,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L40PU",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID,
-		.model_id	= AMIC_A25L40PU,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_spi_rdid4,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 4, { AMIC_ID, AMIC_A25L40PU } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -799,13 +824,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L80P",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID,
-		.model_id	= AMIC_A25L80P,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_spi_rdid4,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 4, { AMIC_ID, AMIC_A25L80P } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -833,13 +859,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L16PT",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID,
-		.model_id	= AMIC_A25L16PT,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid4,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 4, { AMIC_ID, AMIC_A25L16PT } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -870,13 +897,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L16PU",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID,
-		.model_id	= AMIC_A25L16PU,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_spi_rdid4,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 4, { AMIC_ID, AMIC_A25L16PU } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -907,13 +935,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L512",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A25L512,
 		.total_size	= 64,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { AMIC_ID_NOPREFIX, AMIC_A25L512 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -938,13 +967,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L010",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A25L010,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { AMIC_ID_NOPREFIX, AMIC_A25L010 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -969,13 +999,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L020",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A25L020,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { AMIC_ID_NOPREFIX, AMIC_A25L020 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1000,13 +1031,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L040",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A25L040,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { AMIC_ID_NOPREFIX, AMIC_A25L040 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1031,13 +1063,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L080",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A25L080,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { AMIC_ID_NOPREFIX, AMIC_A25L080 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1062,13 +1095,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L016",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A25L016,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { AMIC_ID_NOPREFIX, AMIC_A25L016 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1093,14 +1127,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25L032",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A25L032,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* OTP: 64B total; read 0x4B, 0x48; write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { AMIC_ID_NOPREFIX, AMIC_A25L032 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1131,15 +1166,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25LQ16",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A25LQ16,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* supports SFDP */
 		/* OTP: 64B total; read 0x4B, 0x48; write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { AMIC_ID_NOPREFIX, AMIC_A25LQ16 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { { 4 * 1024, 512 } },
@@ -1169,15 +1205,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25LQ032/A25LQ32A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A25LQ032,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* A25LQ32A supports SFDP */
 		/* OTP: 64B total; read 0x4B, 0x48; write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { AMIC_ID_NOPREFIX, AMIC_A25LQ032 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1208,8 +1245,6 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A25LQ64",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A25LQ032,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* supports SFDP */
@@ -1217,7 +1252,10 @@ const struct flashchip flashchips[] = {
 		/* QPI enable 0x35, disable 0xF5 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { AMIC_ID_NOPREFIX, AMIC_A25LQ032 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1248,13 +1286,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A29002B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A29002B,
 		.total_size	= 256,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMIC_ID_NOPREFIX, AMIC_A29002B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1279,13 +1318,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A29002T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A29002T,
 		.total_size	= 256,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMIC_ID_NOPREFIX, AMIC_A29002T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1310,13 +1350,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A29040B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A29040B,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { AMIC_ID_NOPREFIX, AMIC_A29040B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1336,13 +1377,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "AMIC",
 		.name		= "A49LF040A",
 		.bustype	= BUS_LPC,
-		.manufacture_id	= AMIC_ID_NOPREFIX,
-		.model_id	= AMIC_A49LF040A,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { AMIC_ID_NOPREFIX, AMIC_A49LF040A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1363,14 +1405,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25DF021",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25DF021,
 		.total_size	= 256,
 		.page_size	= 256,
 		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT25DF021 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1401,13 +1444,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25DF041A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25DF041A,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT25DF041A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1438,13 +1482,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25DF081",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25DF081,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT25DF081 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1475,13 +1520,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25DF081A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25DF081A,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT25DF081A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1512,13 +1558,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25DF161",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25DF161,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PROBE,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT25DF161 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1549,13 +1596,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25DF321",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25DF321,
 		.total_size	= 4096,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT25DF321 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1586,14 +1634,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25DF321A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25DF321A,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT25DF321A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1624,13 +1673,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25DF641(A)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25DF641,
 		.total_size	= 8192,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT25DF641 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1661,14 +1711,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25DL081",
 		.bustype	= BUS_SPI,
-		.manufacture_id = ATMEL_ID,
-		.model_id	= ATMEL_AT25DF081,
 		.total_size	= 1024,
 		.page_size	= 256,
 		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT25DF081 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1699,14 +1750,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25DL161",
 		.bustype	= BUS_SPI,
-		.manufacture_id = ATMEL_ID,
-		.model_id	= ATMEL_AT25DL161,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT25DL161 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1737,14 +1789,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25DQ161",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25DQ161,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT25DQ161 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1775,13 +1828,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25F512",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25F512,
 		.total_size	= 64,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_at25f,
+		.probers	=
+		{
+			{ probe_spi_at25f, { 3, { ATMEL_ID, ATMEL_AT25F512 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1803,13 +1857,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25F512A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25F512A,
 		.total_size	= 64,
 		.page_size	= 128,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_at25f,
+		.probers	=
+		{
+			{ probe_spi_at25f, { 3, { ATMEL_ID, ATMEL_AT25F512A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1832,14 +1887,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25F512B",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25F512B,
 		.total_size	= 64,
 		.page_size	= 256,
 		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT25F512B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1875,13 +1931,14 @@ const struct flashchip flashchips[] = {
 		 * All other properties seem to be the same.*/
 		.name		= "AT25F1024(A)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25F1024,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_at25f,
+		.probers	=
+		{
+			{ probe_spi_at25f, { 3, { ATMEL_ID, ATMEL_AT25F1024 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1903,13 +1960,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25F2048",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25F2048,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_at25f,
+		.probers	=
+		{
+			{ probe_spi_at25f, { 3, { ATMEL_ID, ATMEL_AT25F2048 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1931,13 +1989,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25F4096",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25F4096,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_at25f,
+		.probers	=
+		{
+			{ probe_spi_at25f, { 3, { ATMEL_ID, ATMEL_AT25F4096 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -1960,13 +2019,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25FS010",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25FS010,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT25FS010 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -2000,13 +2060,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT25FS040",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT25FS040,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT25FS040 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -2037,13 +2098,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT26DF041",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT26DF041,
 		.total_size	= 512,
 		.page_size	= 256,
 		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT26DF041 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -2068,13 +2130,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT26DF081A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT26DF081A,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT26DF081A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -2105,13 +2168,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT26DF161",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT26DF161,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT26DF161 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -2142,13 +2206,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT26DF161A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT26DF161A,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT26DF161A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -2180,13 +2245,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT26DF321",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT26DF321,
 		.total_size	= 4096,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT26DF321 } } },
+		},
 		.printlock	= spi_prettyprint_status_register_at26df081a,
 		.unlock		= spi_disable_blockprotect,
 		.write		= spi_chip_write_256,
@@ -2197,13 +2263,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT26F004",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT26F004,
 		.total_size	= 512,
 		.page_size	= 256,
 		.tested		= {.probe = NT, .read = NT, .erase = NT, .write = BAD },
 		.feature_bits	= FEATURE_WRSR_WREN,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT26F004 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -2233,13 +2300,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT29C512",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT29C512,
 		.total_size	= 64,
 		.page_size	= 128,
-		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec, /* 10 ms, Enter=Exec */
+		.probers	=
+		{
+			{ probe_jedec_longreset, { 2, {  ATMEL_ID, ATMEL_AT29C512 } } }, /* 10 ms, Enter=Exec */
+		},
 		.block_erasers	=
 		{
 			{
@@ -2256,13 +2323,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT29C010A",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT29C010A,
 		.total_size	= 128,
 		.page_size	= 128,
-		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec, /* 10 ms, Enter=Exec */
+		.probers	=
+		{
+			{ probe_jedec_longreset, { 2, {  ATMEL_ID, ATMEL_AT29C010A } } }, /* 10 ms, Enter=Exec */
+		},
 		.block_erasers	=
 		{
 			{
@@ -2279,13 +2346,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT29C020",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT29C020,
 		.total_size	= 256,
 		.page_size	= 256,
-		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,			/* 10 ms */
+		.probers	=
+		{
+			{ probe_jedec_longreset, { 2, {  ATMEL_ID, ATMEL_AT29C020 } } }, /* 10 ms */
+		},
 		.block_erasers	=
 		{
 			{
@@ -2302,13 +2369,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT29C040A",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT29C040A,
 		.total_size	= 512,
 		.page_size	= 256,
-		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,			/* 10 ms */
+		.probers	=
+		{
+			{ probe_jedec_longreset, { 2, {  ATMEL_ID, ATMEL_AT29C040A } } }, /* 10 ms */
+		},
 		.block_erasers	=
 		{
 			{
@@ -2325,15 +2392,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT45CS1282",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT45CS1282,
 		.total_size	= 16896 /* No power of two sizes */,
 		.page_size	= 1056 /* No power of two sizes */,
 		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
 		/* OTP: 128B total, 64B pre-programmed; read 0x77 (4 dummy bytes); write 0x9A (via buffer) */
 		.feature_bits	= FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45CS1282 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -2354,24 +2422,26 @@ const struct flashchip flashchips[] = {
 
 	{
 		.vendor		= "Atmel",
-		.name		= "AT45DB011D",
+		.name		= "AT45DB011D (power-of-two)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT45DB011D,
-		.total_size	= 128 /* or 132, determined from status register */,
-		.page_size	= 256 /* or 264, determined from status register */,
+		.total_size	= 128,
+		.page_size	= 256,
 		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
 		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
 		.feature_bits	= FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_at45db,
+		.probers	=
+		{
+			{ probe_spi_at45db, { 1, { 0x01 } } },
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB011D } } },
+		},
 		.block_erasers	=
 		{
 			{
 				.eraseblocks = { {256, 512} },
 				.block_erase = spi_erase_at45db_page,
 			}, {
-				.eraseblocks = { {8 * 256, 512/8} },
+				.eraseblocks = { {8 * 256, 64} },
 				.block_erase = spi_erase_at45db_block,
 			}, {
 				.eraseblocks = {
@@ -2387,7 +2457,7 @@ const struct flashchip flashchips[] = {
 		},
 		.unlock		= spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
 		.printlock	= spi_prettyprint_status_register_at45db,
-		/* granularity will be set by the probing function. */
+		.gran		= write_gran_256bytes,
 		.write		= spi_write_at45db,
 		.read		= spi_read_at45db, /* Fast read (0x0B) supported */
 		.voltage	= {2700, 3600},
@@ -2395,40 +2465,42 @@ const struct flashchip flashchips[] = {
 
 	{
 		.vendor		= "Atmel",
-		.name		= "AT45DB021D",
+		.name		= "AT45DB011D (non-power-of-two)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT45DB021D,
-		.total_size	= 256 /* or 264, determined from status register */,
-		.page_size	= 256 /* or 264, determined from status register */,
+		.total_size	= (128 / 32) * 33,
+		.page_size	= (256 / 32) * 33,
 		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
 		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
 		.feature_bits	= FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_at45db,
+		.probers	=
+		{
+			{ probe_spi_at45db, { 1, { 0x00 } } },
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB011D } } },
+		},
 		.block_erasers	=
 		{
 			{
-				.eraseblocks = { {256, 1024} },
+				.eraseblocks = { {(256 / 32) * 33, 512} },
 				.block_erase = spi_erase_at45db_page,
 			}, {
-				.eraseblocks = { {8 * 256, 1024/8} },
+				.eraseblocks = { {(2048 / 32) * 33, 64} },
 				.block_erase = spi_erase_at45db_block,
 			}, {
 				.eraseblocks = {
-					{8 * 256, 1},
-					{120 * 256, 1},
-					{128 * 256, 7},
+					{8 * (256 / 32) * 33, 1},
+					{120 * (256 / 32) * 33, 1},
+					{128 * (256 / 32) * 33, 3},
 				},
 				.block_erase = spi_erase_at45db_sector
 			}, {
-				.eraseblocks = { {256 * 1024, 1} },
+				.eraseblocks = { {(128 / 32) * 33 * 1024, 1} },
 				.block_erase = spi_erase_at45db_chip,
 			}
 		},
 		.unlock		= spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
 		.printlock	= spi_prettyprint_status_register_at45db,
-		/* granularity will be set by the probing function. */
+		.gran		= write_gran_264bytes,
 		.write		= spi_write_at45db,
 		.read		= spi_read_at45db, /* Fast read (0x0B) supported */
 		.voltage	= {2700, 3600},
@@ -2436,205 +2508,213 @@ const struct flashchip flashchips[] = {
 
 	{
 		.vendor		= "Atmel",
-		.name		= "AT45DB041D",
+		.name		= "AT45DB021D (power-of-two)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT45DB041D,
-		.total_size	= 512 /* or 528, determined from status register */,
-		.page_size	= 256 /* or 264, determined from status register */,
+		.total_size	= 256,
+		.page_size	= 256,
 		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
 		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
 		.feature_bits	= FEATURE_OTP,
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_at45db,
+		.tested		= TEST_UNTESTED,
+		.probers	=
+		{
+			{ probe_spi_at45db, { 1, { 0x01 } } },
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB021D } } },
+		},
 		.block_erasers	=
 		{
 			{
-				.eraseblocks = { {256, 2048} },
+				.eraseblocks = { {256, 1024} },
 				.block_erase = spi_erase_at45db_page,
 			}, {
-				.eraseblocks = { {8 * 256, 2048/8} },
+				.eraseblocks = { {8 * 256, 1024/8} },
 				.block_erase = spi_erase_at45db_block,
 			}, {
 				.eraseblocks = {
 					{8 * 256, 1},
-					{248 * 256, 1},
-					{256 * 256, 7},
+					{120 * 256, 1},
+					{128 * 256, 7},
 				},
 				.block_erase = spi_erase_at45db_sector
 			}, {
-				.eraseblocks = { {512 * 1024, 1} },
+				.eraseblocks = { {256 * 1024, 1} },
 				.block_erase = spi_erase_at45db_chip,
 			}
 		},
 		.unlock		= spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
 		.printlock	= spi_prettyprint_status_register_at45db,
-		/* granularity will be set by the probing function. */
+		.gran		= write_gran_256bytes,
 		.write		= spi_write_at45db,
 		.read		= spi_read_at45db, /* Fast read (0x0B) supported */
-		.voltage	= {2700, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
+		.voltage	= {2700, 3600},
 	},
 
 	{
 		.vendor		= "Atmel",
-		.name		= "AT45DB081D",
+		.name		= "AT45DB021D (non-power-of-two)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT45DB081D,
-		.total_size	= 1024 /* or 1056, determined from status register */,
-		.page_size	= 256 /* or 264, determined from status register */,
+		.total_size	= (256 / 32) * 33,
+		.page_size	= (256 / 32) * 33,
 		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
 		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
 		.feature_bits	= FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_at45db,
+		.probers	=
+		{
+			{ probe_spi_at45db, { 1, { 0x00 } } },
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB021D } } },
+		},
 		.block_erasers	=
 		{
 			{
-				.eraseblocks = { {256, 4096} },
+				.eraseblocks = { {(256 / 32) * 33, 1024} },
 				.block_erase = spi_erase_at45db_page,
 			}, {
-				.eraseblocks = { {8 * 256, 4096/8} },
+				.eraseblocks = { {8 * (256 / 32) * 33, 1024/8} },
 				.block_erase = spi_erase_at45db_block,
 			}, {
 				.eraseblocks = {
-					{8 * 256, 1},
-					{248 * 256, 1},
-					{256 * 256, 15},
+					{8 * (256 / 32) * 33, 1},
+					{120 * (256 / 32) * 33, 1},
+					{128 * (256 / 32) * 33, 7},
 				},
 				.block_erase = spi_erase_at45db_sector
 			}, {
-				.eraseblocks = { {1024 * 1024, 1} },
+				.eraseblocks = { {(256 / 32) * 33 * 1024, 1} },
 				.block_erase = spi_erase_at45db_chip,
 			}
 		},
 		.unlock		= spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
 		.printlock	= spi_prettyprint_status_register_at45db,
-		/* granularity will be set by the probing function. */
+		.gran		= write_gran_264bytes,
 		.write		= spi_write_at45db,
 		.read		= spi_read_at45db, /* Fast read (0x0B) supported */
-		.voltage	= {2700, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
+		.voltage	= {2700, 3600},
 	},
 
 	{
 		.vendor		= "Atmel",
-		.name		= "AT45DB161D",
+		.name		= "AT45DB041D (power-of-two)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT45DB161D,
-		.total_size	= 2048 /* or 2112, determined from status register */,
-		.page_size	= 512 /* or 528, determined from status register */,
+		.total_size	= 512,
+		.page_size	= 256,
 		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
 		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
 		.feature_bits	= FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_at45db,
+		.probers	=
+		{
+			{ probe_spi_at45db, { 1, { 0x01 } } },
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB041D } } },
+		},
 		.block_erasers	=
 		{
 			{
-				.eraseblocks = { {512, 4096} },
+				.eraseblocks = { {256, 2048} },
 				.block_erase = spi_erase_at45db_page,
 			}, {
-				.eraseblocks = { {8 * 512, 4096/8} },
+				.eraseblocks = { {8 * 256, 2048/8} },
 				.block_erase = spi_erase_at45db_block,
 			}, {
 				.eraseblocks = {
-					{8 * 512, 1},
-					{248 * 512, 1},
-					{256 * 512, 15},
+					{8 * 256, 1},
+					{248 * 256, 1},
+					{256 * 256, 7},
 				},
 				.block_erase = spi_erase_at45db_sector
 			}, {
-				.eraseblocks = { {2048 * 1024, 1} },
+				.eraseblocks = { {512 * 1024, 1} },
 				.block_erase = spi_erase_at45db_chip,
 			}
 		},
 		.unlock		= spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
 		.printlock	= spi_prettyprint_status_register_at45db,
-		/* granularity will be set by the probing function. */
+		.gran		= write_gran_256bytes,
 		.write		= spi_write_at45db,
 		.read		= spi_read_at45db, /* Fast read (0x0B) supported */
 		.voltage	= {2700, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
 	},
-
 	{
 		.vendor		= "Atmel",
-		.name		= "AT45DB321C",
+		.name		= "AT45DB041D (non-power-of-two)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT45DB321C,
-		.total_size	= 4224 /* No power of two sizes */,
-		.page_size	= 528 /* No power of two sizes */,
+		.total_size	= (512 / 32) * 33,
+		.page_size	= (256 / 32) * 33,
 		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
-		/* OTP: 128B total, 64B pre-programmed; read 0x77 (4 dummy bytes); write 0x9A (via buffer) */
+		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
 		.feature_bits	= FEATURE_OTP,
-		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.tested		= TEST_OK_PREW,
+		.probers	=
+		{
+			{ probe_spi_at45db, { 1, { 0x00 } } },
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB041D, 0x00 } } },
+		},
 		.block_erasers	=
 		{
 			{
-				.eraseblocks = { {528, 8192} },
+				.eraseblocks = { {(256 / 32) * 33, 2048} },
 				.block_erase = spi_erase_at45db_page,
 			}, {
-				.eraseblocks = { {8 * 528, 8192/8} },
+				.eraseblocks = { {8 * (256 / 32) * 33, 2048/8} },
 				.block_erase = spi_erase_at45db_block,
-			}, /* Although the datasheets describes sectors (which can be write protected)
-			    * there seems to be no erase functions for them.
-			  {
+			}, {
 				.eraseblocks = {
-					{8 * 528, 1},
-					{120 * 528, 1},
-					{128 * 528, 63},
+					{8 * (256 / 32) * 33, 1},
+					{248 * (256 / 32) * 33, 1},
+					{256 * (256 / 32) * 33, 7},
 				},
 				.block_erase = spi_erase_at45db_sector
-			}, */ {
-				.eraseblocks = { {4224 * 1024, 1} },
+			}, {
+				.eraseblocks = { {(512 / 32) * 33 * 1024, 1} },
 				.block_erase = spi_erase_at45db_chip,
 			}
 		},
-		.printlock	= spi_prettyprint_status_register_at45db, /* Bit 0 is undefined, no lockdown */
-		.gran		= write_gran_528bytes,
+		.unlock		= spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
+		.printlock	= spi_prettyprint_status_register_at45db,
+		.gran		= write_gran_264bytes,
 		.write		= spi_write_at45db,
-		.read		= spi_read_at45db_e8, /* 3 address and 4 dummy bytes */
-		.voltage	= {2700, 3600},
+		.read		= spi_read_at45db, /* Fast read (0x0B) supported */
+		.voltage	= {2700, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
 	},
 
 	{
 		.vendor		= "Atmel",
-		.name		= "AT45DB321D",
+		.name		= "AT45DB081D (power-of-two)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT45DB321D,
-		.total_size	= 4096 /* or 4224, determined from status register */,
-		.page_size	= 512 /* or 528, determined from status register */,
+		.total_size	= 1024,
+		.page_size	= 256,
 		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
 		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
 		.feature_bits	= FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_at45db,
+		.probers	=
+		{
+			{ probe_spi_at45db, { 1, { 0x01 } } },
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB081D } } },
+		},
 		.block_erasers	=
 		{
 			{
-				.eraseblocks = { {512, 8192} },
+				.eraseblocks = { {256, 4096} },
 				.block_erase = spi_erase_at45db_page,
 			}, {
-				.eraseblocks = { {8 * 512, 8192/8} },
+				.eraseblocks = { {8 * 256, 4096/8} },
 				.block_erase = spi_erase_at45db_block,
 			}, {
 				.eraseblocks = {
-					{8 * 512, 1},
-					{120 * 512, 1},
-					{128 * 512, 63},
+					{8 * 256, 1},
+					{248 * 256, 1},
+					{256 * 256, 15},
 				},
 				.block_erase = spi_erase_at45db_sector
 			}, {
-				.eraseblocks = { {4096 * 1024, 1} },
+				.eraseblocks = { {1024 * 1024, 1} },
 				.block_erase = spi_erase_at45db_chip,
 			}
 		},
 		.unlock		= spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
 		.printlock	= spi_prettyprint_status_register_at45db,
-		/* granularity will be set by the probing function. */
+		.gran		= write_gran_256bytes,
 		.write		= spi_write_at45db,
 		.read		= spi_read_at45db, /* Fast read (0x0B) supported */
 		.voltage	= {2700, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
@@ -2642,81 +2722,428 @@ const struct flashchip flashchips[] = {
 
 	{
 		.vendor		= "Atmel",
-		.name		= "AT45DB321E",
+		.name		= "AT45DB081D (non-power-of-two)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT45DB321C,
-		.total_size	= 4096 /* or 4224, determined from status register */,
-		.page_size	= 512 /* or 528, determined from status register */,
+		.total_size	= (1024 / 32) * 33,
+		.page_size	= (256 / 32) * 33,
 		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
 		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
 		.feature_bits	= FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_at45db,
+		.probers	=
+		{
+			{ probe_spi_at45db, { 1, { 0x00 } } },
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB081D } } },
+		},
 		.block_erasers	=
 		{
 			{
-				.eraseblocks = { {512, 8192} },
+				.eraseblocks = { {(256 / 32) * 33, 4096} },
 				.block_erase = spi_erase_at45db_page,
 			}, {
-				.eraseblocks = { {8 * 512, 8192/8} },
+				.eraseblocks = { {8 * (256 / 32) * 33, 4096/8} },
 				.block_erase = spi_erase_at45db_block,
 			}, {
 				.eraseblocks = {
-					{8 * 512, 1},
-					{120 * 512, 1},
-					{128 * 512, 63},
+					{8 * (256 / 32) * 33, 1},
+					{248 * (256 / 32) * 33, 1},
+					{256 * (256 / 32) * 33, 15},
 				},
 				.block_erase = spi_erase_at45db_sector
 			}, {
-				.eraseblocks = { {4096 * 1024, 1} },
+				.eraseblocks = { {(1024 / 32) * 33 * 1024, 1} },
+				.block_erase = spi_erase_at45db_chip,
+			}
+		},
+		.unlock		= spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
+		.printlock	= spi_prettyprint_status_register_at45db,
+		.gran		= write_gran_264bytes,
+		.write		= spi_write_at45db,
+		.read		= spi_read_at45db, /* Fast read (0x0B) supported */
+		.voltage	= {2700, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45DB161D (power-of-two)",
+		.bustype	= BUS_SPI,
+		.total_size	= 2048,
+		.page_size	= 512,
+		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
+		.feature_bits	= FEATURE_OTP,
+		.tested		= TEST_OK_PREW,
+		.probers	=
+		{
+			{ probe_spi_at45db, { 1, { 0x01 } } },
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB161D } } },
+		},
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {512, 4096} },
+				.block_erase = spi_erase_at45db_page,
+			}, {
+				.eraseblocks = { {8 * 512, 4096/8} },
+				.block_erase = spi_erase_at45db_block,
+			}, {
+				.eraseblocks = {
+					{8 * 512, 1},
+					{248 * 512, 1},
+					{256 * 512, 15},
+				},
+				.block_erase = spi_erase_at45db_sector
+			}, {
+				.eraseblocks = { {2048 * 1024, 1} },
+				.block_erase = spi_erase_at45db_chip,
+			}
+		},
+		.unlock		= spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
+		.printlock	= spi_prettyprint_status_register_at45db,
+		.gran		= write_gran_512bytes,
+		.write		= spi_write_at45db,
+		.read		= spi_read_at45db, /* Fast read (0x0B) supported */
+		.voltage	= {2700, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45DB161D (non-power-of-two)",
+		.bustype	= BUS_SPI,
+		.total_size	= (2048 / 32) * 33,
+		.page_size	= (512 / 32) * 33,
+		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
+		.feature_bits	= FEATURE_OTP,
+		.tested		= TEST_OK_PREW,
+		.probers	=
+		{
+			{ probe_spi_at45db, { 1, { 0x00 } } },
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB161D } } },
+		},
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {(512 / 32) * 33, 4096} },
+				.block_erase = spi_erase_at45db_page,
+			}, {
+				.eraseblocks = { {8 * (512 / 32) * 33, 4096/8} },
+				.block_erase = spi_erase_at45db_block,
+			}, {
+				.eraseblocks = {
+					{8 * (512 / 32) * 33, 1},
+					{248 * (512 / 32) * 33, 1},
+					{256 * (512 / 32) * 33, 15},
+				},
+				.block_erase = spi_erase_at45db_sector
+			}, {
+				.eraseblocks = { {(2048 / 32) * 33 * 1024, 1} },
+				.block_erase = spi_erase_at45db_chip,
+			}
+		},
+		.unlock		= spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
+		.printlock	= spi_prettyprint_status_register_at45db,
+		.gran		= write_gran_528bytes,
+		.write		= spi_write_at45db,
+		.read		= spi_read_at45db, /* Fast read (0x0B) supported */
+		.voltage	= {2700, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45DB321C",
+		.bustype	= BUS_SPI,
+		.total_size	= 4224 /* No power of two sizes */,
+		.page_size	= 528 /* No power of two sizes */,
+		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+		/* OTP: 128B total, 64B pre-programmed; read 0x77 (4 dummy bytes); write 0x9A (via buffer) */
+		.feature_bits	= FEATURE_OTP,
+		.tested		= TEST_UNTESTED,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB321C } } },
+		},
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {528, 8192} },
+				.block_erase = spi_erase_at45db_page,
+			}, {
+				.eraseblocks = { {8 * 528, 8192/8} },
+				.block_erase = spi_erase_at45db_block,
+			}, /* Although the datasheets describes sectors (which can be write protected)
+			    * there seems to be no erase functions for them.
+			  {
+				.eraseblocks = {
+					{8 * 528, 1},
+					{120 * 528, 1},
+					{128 * 528, 63},
+				},
+				.block_erase = spi_erase_at45db_sector
+			}, */ {
+				.eraseblocks = { {4224 * 1024, 1} },
+				.block_erase = spi_erase_at45db_chip,
+			}
+		},
+		.printlock	= spi_prettyprint_status_register_at45db, /* Bit 0 is undefined, no lockdown */
+		.gran		= write_gran_528bytes,
+		.write		= spi_write_at45db,
+		.read		= spi_read_at45db_e8, /* 3 address and 4 dummy bytes */
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45DB321D (power-of-two)",
+		.bustype	= BUS_SPI,
+		.total_size	= 4096,
+		.page_size	= 512,
+		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
+		.feature_bits	= FEATURE_OTP,
+		.tested		= TEST_UNTESTED,
+		.probers	=
+		{
+			{ probe_spi_at45db, { 1, { 0x01 } } },
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB321D } } },
+		},
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {512, 8192} },
+				.block_erase = spi_erase_at45db_page,
+			}, {
+				.eraseblocks = { {8 * 512, 8192/8} },
+				.block_erase = spi_erase_at45db_block,
+			}, {
+				.eraseblocks = {
+					{8 * 512, 1},
+					{120 * 512, 1},
+					{128 * 512, 63},
+				},
+				.block_erase = spi_erase_at45db_sector
+			}, {
+				.eraseblocks = { {4096 * 1024, 1} },
+				.block_erase = spi_erase_at45db_chip,
+			}
+		},
+		.unlock		= spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
+		.printlock	= spi_prettyprint_status_register_at45db,
+		.gran		= write_gran_512bytes,
+		.write		= spi_write_at45db,
+		.read		= spi_read_at45db, /* Fast read (0x0B) supported */
+		.voltage	= {2700, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45DB321D (non-power-of-two)",
+		.bustype	= BUS_SPI,
+		.total_size	= (4096 / 32) * 33,
+		.page_size	= (512 / 32) * 33,
+		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
+		.feature_bits	= FEATURE_OTP,
+		.tested		= TEST_UNTESTED,
+		.probers	=
+		{
+			{ probe_spi_at45db, { 1, { 0x00 } } },
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB321D } } },
+		},
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {(512 / 32) * 33, 8192} },
+				.block_erase = spi_erase_at45db_page,
+			}, {
+				.eraseblocks = { {8 * (512 / 32) * 33, 8192/8} },
+				.block_erase = spi_erase_at45db_block,
+			}, {
+				.eraseblocks = {
+					{8 * (512 / 32) * 33, 1},
+					{120 * (512 / 32) * 33, 1},
+					{128 * (512 / 32) * 33, 63},
+				},
+				.block_erase = spi_erase_at45db_sector
+			}, {
+				.eraseblocks = { {(4096 / 32) * 33 * 1024, 1} },
+				.block_erase = spi_erase_at45db_chip,
+			}
+		},
+		.unlock		= spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
+		.printlock	= spi_prettyprint_status_register_at45db,
+		.gran		= write_gran_512bytes,
+		.write		= spi_write_at45db,
+		.read		= spi_read_at45db, /* Fast read (0x0B) supported */
+		.voltage	= {2700, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45DB321E (power-of-two)",
+		.bustype	= BUS_SPI,
+		.total_size	= 4096,
+		.page_size	= 512,
+		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
+		.feature_bits	= FEATURE_OTP,
+		.tested		= TEST_UNTESTED,
+		.probers	=
+		{
+			{ probe_spi_at45db, { 1, { 0x01 } } },
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB321C } } },
+		},
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {512, 8192} },
+				.block_erase = spi_erase_at45db_page,
+			}, {
+				.eraseblocks = { {8 * 512, 8192/8} },
+				.block_erase = spi_erase_at45db_block,
+			}, {
+				.eraseblocks = {
+					{8 * 512, 1},
+					{120 * 512, 1},
+					{128 * 512, 63},
+				},
+				.block_erase = spi_erase_at45db_sector
+			}, {
+				.eraseblocks = { {4096 * 1024, 1} },
 				.block_erase = spi_erase_at45db_chip,
 			}
 		},
 		.unlock		= spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
 		.printlock	= spi_prettyprint_status_register_at45db, /* has a 2nd status register */
-		/* granularity will be set by the probing function. */
+		.gran		= write_gran_512bytes,
+		.write		= spi_write_at45db,
+		.read		= spi_read_at45db, /* Fast read (0x0B) supported */
+		.voltage	= {2500, 3600}, /* 2.3-3.6V & 2.5-3.6V models available */
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45DB321E (non-power-of-two)",
+		.bustype	= BUS_SPI,
+		.total_size	= (4096 / 32) * 33,
+		.page_size	= (512 / 32) * 33,
+		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
+		.feature_bits	= FEATURE_OTP,
+		.tested		= TEST_UNTESTED,
+		.probers	=
+		{
+			{ probe_spi_at45db, { 1, { 0x00 } } },
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB321C } } },
+		},
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {(512 / 32) * 33, 8192} },
+				.block_erase = spi_erase_at45db_page,
+			}, {
+				.eraseblocks = { {8 * (512 / 32) * 33, 8192/8} },
+				.block_erase = spi_erase_at45db_block,
+			}, {
+				.eraseblocks = {
+					{8 * (512 / 32) * 33, 1},
+					{120 * (512 / 32) * 33, 1},
+					{128 * (512 / 32) * 33, 63},
+				},
+				.block_erase = spi_erase_at45db_sector
+			}, {
+				.eraseblocks = { {(4096 / 32) * 33 * 1024, 1} },
+				.block_erase = spi_erase_at45db_chip,
+			}
+		},
+		.unlock		= spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
+		.printlock	= spi_prettyprint_status_register_at45db, /* has a 2nd status register */
+		.gran		= write_gran_528bytes,
+		.write		= spi_write_at45db,
+		.read		= spi_read_at45db, /* Fast read (0x0B) supported */
+		.voltage	= {2500, 3600}, /* 2.3-3.6V & 2.5-3.6V models available */
+	},
+
+	{
+		.vendor		= "Atmel",
+		.name		= "AT45DB642D (power-of-two)",
+		.bustype	= BUS_SPI,
+		.total_size	= 8192,
+		.page_size	= 1024,
+		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
+		.feature_bits	= FEATURE_OTP,
+		.tested		= TEST_UNTESTED,
+		.probers	=
+		{
+			{ probe_spi_at45db, { 1, { 0x01 } } },
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB642D } } },
+		},
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {1024, 8192} },
+				.block_erase = spi_erase_at45db_page,
+			}, {
+				.eraseblocks = { {8 * 1024, 8192/8} },
+				.block_erase = spi_erase_at45db_block,
+			}, {
+				.eraseblocks = {
+					{8 * 1024, 1},
+					{248 * 1024, 1},
+					{256 * 1024, 31},
+				},
+				.block_erase = spi_erase_at45db_sector
+			}, {
+				.eraseblocks = { {8192 * 1024, 1} },
+				.block_erase = spi_erase_at45db_chip,
+			}
+		},
+		.unlock		= spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
+		.printlock	= spi_prettyprint_status_register_at45db,
+		.gran		= write_gran_1024bytes,
 		.write		= spi_write_at45db,
 		.read		= spi_read_at45db, /* Fast read (0x0B) supported */
-		.voltage	= {2500, 3600}, /* 2.3-3.6V & 2.5-3.6V models available */
+		.voltage	= {2700, 3600},
 	},
-
 	{
 		.vendor		= "Atmel",
-		.name		= "AT45DB642D",
+		.name		= "AT45DB642D (non-power-of-two)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT45DB642D,
-		.total_size	= 8192 /* or 8448, determined from status register */,
-		.page_size	= 1024 /* or 1056, determined from status register */,
+		.total_size	= (8192 / 32) * 33,
+		.page_size	= (1024 / 32) * 33,
 		/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
 		/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
 		.feature_bits	= FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_at45db,
+		.probers	=
+		{
+			{ probe_spi_at45db, { 1, { 0x00 } } },
+			{ probe_spi_rdid, { 3, { ATMEL_ID, ATMEL_AT45DB642D } } },
+		},
 		.block_erasers	=
 		{
 			{
-				.eraseblocks = { {1024, 8192} },
+				.eraseblocks = { {(1024 / 32) * 33, 8192} },
 				.block_erase = spi_erase_at45db_page,
 			}, {
-				.eraseblocks = { {8 * 1024, 8192/8} },
+				.eraseblocks = { {8 * (1024 / 32) * 33, 8192/8} },
 				.block_erase = spi_erase_at45db_block,
 			}, {
 				.eraseblocks = {
-					{8 * 1024, 1},
-					{248 * 1024, 1},
-					{256 * 1024, 31},
+					{8 * (1024 / 32) * 33, 1},
+					{248 * (1024 / 32) * 33, 1},
+					{256 * (1024 / 32) * 33, 31},
 				},
 				.block_erase = spi_erase_at45db_sector
 			}, {
-				.eraseblocks = { {8192 * 1024, 1} },
+				.eraseblocks = { {(8192 / 32) * 33 * 1024, 1} },
 				.block_erase = spi_erase_at45db_chip,
 			}
 		},
 		.unlock		= spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
 		.printlock	= spi_prettyprint_status_register_at45db,
-		/* granularity will be set by the probing function. */
+		.gran		= write_gran_1056bytes,
 		.write		= spi_write_at45db,
 		.read		= spi_read_at45db, /* Fast read (0x0B) supported */
 		.voltage	= {2700, 3600},
@@ -2726,13 +3153,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT49BV512",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT49BV512,
 		.total_size	= 64,
 		.page_size	= 64,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, {  ATMEL_ID, ATMEL_AT49BV512 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -2749,13 +3177,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT49F002(N)",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT49F002N,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { ATMEL_ID, ATMEL_AT49F002N } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -2780,13 +3209,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT49F002(N)T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT49F002NT,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { ATMEL_ID, ATMEL_AT49F002NT } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -2811,13 +3241,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT49(H)F010",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT49F010,
 		.total_size	= 128,
 		.page_size	= 0, /* unused */
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { ATMEL_ID, ATMEL_AT49F010 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -2835,13 +3266,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT49F020",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT49F020,
 		.total_size	= 256,
 		.page_size	= 0, /* unused */
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { ATMEL_ID, ATMEL_AT49F020 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -2865,13 +3297,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT49F040",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT49F040,
 		.total_size	= 512,
 		.page_size	= 0, /* unused */
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { ATMEL_ID, ATMEL_AT49F040 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -2895,13 +3328,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT49F080",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT49F080,
 		.total_size	= 1024,
 		.page_size	= 0, /* unused */
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { ATMEL_ID, ATMEL_AT49F080 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -2926,13 +3360,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT49F080T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT49F080T,
 		.total_size	= 1024,
 		.page_size	= 0, /* unused */
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { ATMEL_ID, ATMEL_AT49F080T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -2956,13 +3391,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Atmel",
 		.name		= "AT49LH002",
 		.bustype	= BUS_LPC | BUS_FWH, /* A/A Mux */
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= ATMEL_AT49LH002,
 		.total_size	= 256,
 		.page_size	= 0, /* unused */
 		.feature_bits	= FEATURE_REGISTERMAP, /* TODO: LPC OK too? */
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_unshifted, /* TODO: 0xff cmd not documented? */
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { ATMEL_ID, ATMEL_AT49LH002 } } }, /* TODO: 0xff cmd not documented? */
+		},
 		.block_erasers	=
 		{
 			{
@@ -2991,13 +3427,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Catalyst",
 		.name		= "CAT28F512",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= CATALYST_ID,
-		.model_id	= CATALYST_CAT28F512,
 		.total_size	= 64,
 		.page_size	= 0, /* unused */
 		.feature_bits	= 0,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_jedec, /* FIXME! */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { CATALYST_ID, CATALYST_CAT28F512 } } }, /* FIXME! */
+		},
 		.block_erasers	=
 		{
 			{
@@ -3014,13 +3451,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Bright",
 		.name		= "BM29F040",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= BRIGHT_ID,
-		.model_id	= BRIGHT_BM29F040,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { BRIGHT_ID, BRIGHT_BM29F040 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3040,13 +3478,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ESMT",
 		.name		= "F49B002UA",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ESMT_ID,
-		.model_id	= ESMT_F49B002UA,
 		.total_size	= 256,
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { ESMT_ID, ESMT_F49B002UA } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3071,13 +3510,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ESMT",
 		.name		= "F25L008A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ESMT_ID,
-		.model_id	= ESMT_F25L008A,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EITHER,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ESMT_ID, ESMT_F25L008A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3105,13 +3545,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ESMT",
 		.name		= "F25L32PA",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ESMT_ID,
-		.model_id	= ESMT_F25L32PA,
 		.total_size	= 4096,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EITHER | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ESMT_ID, ESMT_F25L32PA } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3139,13 +3580,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25B05",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25B05,
 		.total_size	= 64,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25B05 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3172,13 +3614,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25B05T",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25B05,
 		.total_size	= 64,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25B05 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3205,13 +3648,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25B10",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25B10,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25B10 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3238,13 +3682,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25B10T",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25B10,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25B10 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3271,13 +3716,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25B20",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25B20,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25B20 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3305,13 +3751,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25B20T",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25B20,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25B20 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3339,13 +3786,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25B40",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25B40,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25B40 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3373,13 +3821,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25B40T",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25B40,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25B40 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3407,13 +3856,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25B80",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25B80,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25B80 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3441,13 +3891,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25B80T",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25B80,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25B80 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3475,13 +3926,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25B16",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25B16,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25B16 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3509,13 +3961,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25B16T",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25B16,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25B16 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3543,13 +3996,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25B32",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25B32,
 		.total_size	= 4096,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25B32 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3577,13 +4031,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25B32T",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25B32,
 		.total_size	= 4096,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25B32 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3611,13 +4066,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25B64",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25B64,
 		.total_size	= 8192,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25B64 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3645,13 +4101,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25B64T",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25B64,
 		.total_size	= 8192,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25B64 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3679,13 +4136,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25F05",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25F05,
 		.total_size	= 64,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25F05 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3716,13 +4174,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25F10",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25F10,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25F10 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3753,13 +4212,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25F20",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25F20,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25F20 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3790,13 +4250,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25F40",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25F40,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PROBE,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25F40 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3824,13 +4285,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25F80",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25F80,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25F80 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3858,13 +4320,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25F16",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25F16,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25F16 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3892,13 +4355,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25F32",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25F32,
 		.total_size	= 4096,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25F32 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3926,13 +4390,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25F64",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25F64,
 		.total_size	= 8192,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25F64 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3960,14 +4425,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25Q40",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25Q40,
 		.total_size	= 512,
 		.page_size	= 256,
 		/* OTP: 256B total; enter 0x3A */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25Q40 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -3995,14 +4461,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25Q80(A)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25Q80,
 		.total_size	= 1024,
 		.page_size	= 256,
 		/* OTP: 256B total; enter 0x3A */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25Q80 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4032,14 +4499,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25Q16",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25Q16,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* OTP: D16 512B/Q16 128B total; enter 0x3A */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25Q16 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4071,14 +4539,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25Q32(A/B)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25Q32,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* OTP: 512B total; enter 0x3A */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25Q32 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4106,14 +4575,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25Q64",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25Q64,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* OTP: 512B total; enter 0x3A */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25Q64 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4141,14 +4611,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25Q128",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25Q128,
 		.total_size	= 16384,
 		.page_size	= 256,
 		/* OTP: 512B total; enter 0x3A */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25Q128 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4175,8 +4646,6 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25QH16",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25QH16,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* supports SFDP */
@@ -4184,7 +4653,10 @@ const struct flashchip flashchips[] = {
 		/* QPI enable 0x38, disable 0xFF */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25QH16 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4212,8 +4684,6 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25QH32",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25QH32,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* supports SFDP */
@@ -4221,7 +4691,10 @@ const struct flashchip flashchips[] = {
 		/* QPI enable 0x38, disable 0xFF */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25QH32 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4249,8 +4722,6 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25QH64",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25QH64,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* supports SFDP */
@@ -4258,7 +4729,10 @@ const struct flashchip flashchips[] = {
 		/* QPI enable 0x38, disable 0xFF */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25QH64 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 2048} },
@@ -4285,8 +4759,6 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25QH128",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25QH128,
 		.total_size	= 16384,
 		.page_size	= 256,
 		/* supports SFDP */
@@ -4294,7 +4766,10 @@ const struct flashchip flashchips[] = {
 		/* QPI enable 0x38, disable 0xFF */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25QH128 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 4096} },
@@ -4321,14 +4796,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25S10",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25S10,
 		.total_size	= 128,
 		.page_size	= 256,
 		/* OTP: 256B total; enter 0x3A */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25S10 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 32} },
@@ -4355,14 +4831,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25S20",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25S20,
 		.total_size	= 256,
 		.page_size	= 256,
 		/* OTP: 256B total; enter 0x3A */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25S20 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 64} },
@@ -4389,14 +4866,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25S40",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25S40,
 		.total_size	= 512,
 		.page_size	= 256,
 		/* OTP: 256B total; enter 0x3A */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25S40 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 128} },
@@ -4423,14 +4901,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25S80",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25S80,
 		.total_size	= 1024,
 		.page_size	= 256,
 		/* OTP: 256B total; enter 0x3A */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25S80 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 256} },
@@ -4457,14 +4936,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25S16",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25S16,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* OTP: 512B total; enter 0x3A */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25S16 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 512} },
@@ -4494,14 +4974,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25S32",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25S32,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* OTP: 512B total; enter 0x3A */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25S32 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 1024} },
@@ -4531,14 +5012,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN25S64",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= EON_EN25S64,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* OTP: 512B total; enter 0x3A */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { EON_ID_NOPREFIX, EON_EN25S64 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 2048} },
@@ -4565,13 +5047,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN29F010",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= EON_ID,
-		.model_id	= EON_EN29F010,
 		.total_size	= 128,
 		.page_size	= 128,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { EON_ID, EON_EN29F010 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4592,13 +5075,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN29F002(A)(N)B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= EON_ID,
-		.model_id	= EON_EN29F002B,
 		.total_size	= 256,
 		.page_size	= 256,
-		.feature_bits	= FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
+		.feature_bits	= FEATURE_ADDR_AAA,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_aaa, { 4, {  EON_ID, EON_EN29F002B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4623,13 +5107,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN29F002(A)(N)T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= EON_ID,
-		.model_id	= EON_EN29F002T,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_aaa, { 2, { EON_ID, EON_EN29F002T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4654,13 +5139,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Eon",
 		.name		= "EN29LV640B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= EON_ID,
-		.model_id	= EON_EN29LV640B,
 		.total_size	= 8192,
 		.page_size	= 8192,
 		.feature_bits	= 0,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_en29lv640b,
+		.probers	=
+		{
+			{ probe_en29lv640b, { 3, {  EON_ID, EON_EN29LV640B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4683,13 +5169,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Fujitsu",
 		.name		= "MBM29F004BC",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= FUJITSU_ID,
-		.model_id	= FUJITSU_MBM29F004BC,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { FUJITSU_ID, FUJITSU_MBM29F004BC } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4714,13 +5201,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Fujitsu",
 		.name		= "MBM29F004TC",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= FUJITSU_ID,
-		.model_id	= FUJITSU_MBM29F004TC,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { FUJITSU_ID, FUJITSU_MBM29F004TC } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4746,12 +5234,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Fujitsu",
 		.name		= "MBM29F400BC",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= FUJITSU_ID,
-		.model_id	= FUJITSU_MBM29F400BC,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_m29f400bt,
+		.probers	=
+		{
+			{ probe_m29f400bt, { 3, { FUJITSU_ID, FUJITSU_MBM29F400BC } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4776,12 +5265,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Fujitsu",
 		.name		= "MBM29F400TC",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= FUJITSU_ID,
-		.model_id	= FUJITSU_MBM29F400TC,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_m29f400bt,
+		.probers	=
+		{
+			{ probe_m29f400bt, { 3, { FUJITSU_ID, FUJITSU_MBM29F400TC } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4806,12 +5296,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Fujitsu",
 		.name		= "MBM29LV160BE",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= FUJITSU_ID,
-		.model_id	= FUJITSU_MBM29LV160BE,
-		.total_size	= 2 * 1024,
+		.total_size	= 2048,
 		.page_size	= 0,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_m29f400bt,
+		.probers	=
+		{
+			{ probe_m29f400bt, { 3, { FUJITSU_ID, FUJITSU_MBM29LV160BE } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4836,12 +5327,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Fujitsu",
 		.name		= "MBM29LV160TE",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= FUJITSU_ID,
-		.model_id	= FUJITSU_MBM29LV160TE,
-		.total_size	= 2 * 1024,
+		.total_size	= 2048,
 		.page_size	= 0,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_m29f400bt,
+		.probers	=
+		{
+			{ probe_m29f400bt, { 3, { FUJITSU_ID, FUJITSU_MBM29LV160TE } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4866,14 +5358,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "GigaDevice",
 		.name		= "GD25LQ32",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= GIGADEVICE_ID,
-		.model_id	= GIGADEVICE_GD25LQ32,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { GIGADEVICE_ID, GIGADEVICE_GD25LQ32 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -4904,13 +5397,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "GigaDevice",
 		.name		= "GD25Q512",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= GIGADEVICE_ID,
-		.model_id	= GIGADEVICE_GD25Q512,
 		.total_size	= 64,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { GIGADEVICE_ID, GIGADEVICE_GD25Q512 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 16} },
@@ -4937,13 +5431,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "GigaDevice",
 		.name		= "GD25Q10",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= GIGADEVICE_ID,
-		.model_id	= GIGADEVICE_GD25Q10,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { GIGADEVICE_ID, GIGADEVICE_GD25Q10 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 32} },
@@ -4973,13 +5468,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "GigaDevice",
 		.name		= "GD25Q20(B)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= GIGADEVICE_ID,
-		.model_id	= GIGADEVICE_GD25Q20,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { GIGADEVICE_ID, GIGADEVICE_GD25Q20 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5010,13 +5506,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "GigaDevice",
 		.name		= "GD25Q40(B)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= GIGADEVICE_ID,
-		.model_id	= GIGADEVICE_GD25Q40,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { GIGADEVICE_ID, GIGADEVICE_GD25Q40 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5047,14 +5544,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "GigaDevice",
 		.name		= "GD25Q80(B)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= GIGADEVICE_ID,
-		.model_id	= GIGADEVICE_GD25Q80,
 		.total_size	= 1024,
 		.page_size	= 256,
 		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 (B version only) */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { GIGADEVICE_ID, GIGADEVICE_GD25Q80 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5085,14 +5583,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "GigaDevice",
 		.name		= "GD25Q16(B)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= GIGADEVICE_ID,
-		.model_id	= GIGADEVICE_GD25Q16,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 (B version only) */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { GIGADEVICE_ID, GIGADEVICE_GD25Q16 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5123,14 +5622,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "GigaDevice",
 		.name		= "GD25Q32(B)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= GIGADEVICE_ID,
-		.model_id	= GIGADEVICE_GD25Q32,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { GIGADEVICE_ID, GIGADEVICE_GD25Q32 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5161,14 +5661,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "GigaDevice",
 		.name		= "GD25Q64(B)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= GIGADEVICE_ID,
-		.model_id	= GIGADEVICE_GD25Q64,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { GIGADEVICE_ID, GIGADEVICE_GD25Q64 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5199,14 +5700,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "GigaDevice",
 		.name		= "GD25Q128B",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= GIGADEVICE_ID,
-		.model_id	= GIGADEVICE_GD25Q128,
 		.total_size	= 16384,
 		.page_size	= 256,
 		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { GIGADEVICE_ID, GIGADEVICE_GD25Q128 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5237,14 +5739,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "GigaDevice",
 		.name		= "GD25T80",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= GIGADEVICE_ID,
-		.model_id	= GIGADEVICE_GD25T80,
 		.total_size	= 1024,
 		.page_size	= 256,
 		/* OTP: 256B total; enter 0x3A */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { GIGADEVICE_ID, GIGADEVICE_GD25T80 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 256} },
@@ -5274,13 +5777,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Hyundai",
 		.name		= "HY29F002T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= HYUNDAI_ID,
-		.model_id	= HYUNDAI_HY29F002T,
 		.total_size	= 256,
 		.page_size	= 256 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET, /* Some revisions may need FEATURE_ADDR_2AA */
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { HYUNDAI_ID, HYUNDAI_HY29F002T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5305,13 +5809,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Hyundai",
 		.name		= "HY29F002B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= HYUNDAI_ID,
-		.model_id	= HYUNDAI_HY29F002B,
 		.total_size	= 256,
 		.page_size	= 256 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET, /* Some revisions may need FEATURE_ADDR_2AA */
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { HYUNDAI_ID, HYUNDAI_HY29F002B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5336,13 +5841,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Hyundai",
 		.name		= "HY29F040A",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= HYUNDAI_ID,
-		.model_id	= HYUNDAI_HY29F040A,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { HYUNDAI_ID, HYUNDAI_HY29F040A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5362,14 +5868,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Intel",
 		.name		= "25F160S33B8",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= INTEL_25F160S33B8,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* OTP: 506B total (2x 8B, 30x 16B, 1x 10B); read 0x4B; write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { INTEL_ID, INTEL_25F160S33B8 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5378,7 +5885,7 @@ const struct flashchip flashchips[] = {
 				 * have no effect on the memory contents, but sets a flag in the SR.
 				.eraseblocks = {
 					{8 * 1024, 8},
-					{64 * 1024, 31} // inaccessible
+					{64 * 1024, 31}  inaccessible
 				},
 				.block_erase = spi_block_erase_40,
 			}, { */
@@ -5400,14 +5907,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Intel",
 		.name		= "25F160S33T8",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= INTEL_25F160S33T8,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* OTP: 506B total (2x 8B, 30x 16B, 1x 10B); read 0x4B; write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { INTEL_ID, INTEL_25F160S33T8 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5415,7 +5923,7 @@ const struct flashchip flashchips[] = {
 				 * opcode 0x40. Trying to access an address outside these 8 8kB blocks does
 				 * have no effect on the memory contents, but sets a flag in the SR.
 				.eraseblocks = {
-					{64 * 1024, 31}, // inaccessible
+					{64 * 1024, 31},  inaccessible
 					{8 * 1024, 8}
 				},
 				.block_erase = spi_block_erase_40,
@@ -5438,14 +5946,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Intel",
 		.name		= "25F320S33B8",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= INTEL_25F320S33B8,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* OTP: 506B total (2x 8B, 30x 16B, 1x 10B); read 0x4B; write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { INTEL_ID, INTEL_25F320S33B8 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5454,7 +5963,7 @@ const struct flashchip flashchips[] = {
 				 * have no effect on the memory contents, but sets a flag in the SR.
 				.eraseblocks = {
 					{8 * 1024, 8},
-					{64 * 1024, 63} // inaccessible
+					{64 * 1024, 63}  inaccessible
 				},
 				.block_erase = spi_block_erase_40,
 			}, { */
@@ -5476,14 +5985,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Intel",
 		.name		= "25F320S33T8",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= INTEL_25F320S33T8,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* OTP: 506B total (2x 8B, 30x 16B, 1x 10B); read 0x4B; write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { INTEL_ID, INTEL_25F320S33T8 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5491,7 +6001,7 @@ const struct flashchip flashchips[] = {
 				 * opcode 0x40. Trying to access an address outside these 8 8kB blocks does
 				 * have no effect on the memory contents, but sets a flag in the SR.
 				.eraseblocks = {
-					{64 * 1024, 63}, // inaccessible
+					{64 * 1024, 63},  inaccessible
 					{8 * 1024, 8}
 				},
 				.block_erase = spi_block_erase_40,
@@ -5514,14 +6024,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Intel",
 		.name		= "25F640S33B8",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= INTEL_25F640S33B8,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* OTP: 506B total (2x 8B, 30x 16B, 1x 10B); read 0x4B; write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { INTEL_ID, INTEL_25F640S33B8 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5530,7 +6041,7 @@ const struct flashchip flashchips[] = {
 				 * have no effect on the memory contents, but sets a flag in the SR.
 				.eraseblocks = {
 					{8 * 1024, 8},
-					{64 * 1024, 127} // inaccessible
+					{64 * 1024, 127}  inaccessible
 				},
 				.block_erase = spi_block_erase_40,
 			}, { */
@@ -5552,14 +6063,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Intel",
 		.name		= "25F640S33T8",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= INTEL_25F640S33T8,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* OTP: 506B total (2x 8B, 30x 16B, 1x 10B); read 0x4B; write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { INTEL_ID, INTEL_25F640S33T8 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5567,7 +6079,7 @@ const struct flashchip flashchips[] = {
 				 * opcode 0x40. Trying to access an address outside these 8 8kB blocks does
 				 * have no effect on the memory contents, but sets a flag in the SR.
 				.eraseblocks = {
-					{64 * 1024, 127}, // inaccessible
+					{64 * 1024, 127},  inaccessible
 					{8 * 1024, 8}
 				},
 				.block_erase = spi_block_erase_40,
@@ -5590,12 +6102,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Intel",
 		.name		= "28F001BN/BX-B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= INTEL_28F001B,
 		.total_size	= 128,
 		.page_size	= 128 * 1024, /* 8k + 2x4k + 112k */
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { INTEL_ID, INTEL_28F001B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5616,12 +6129,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Intel",
 		.name		= "28F001BN/BX-T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= INTEL_28F001T,
 		.total_size	= 128,
 		.page_size	= 128 * 1024, /* 112k + 2x4k + 8k */
 		.tested		= TEST_OK_PR,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { INTEL_ID, INTEL_28F001T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5642,12 +6156,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Intel",
 		.name		= "28F002BC/BL/BV/BX-T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= INTEL_28F002T,
 		.total_size	= 256,
 		.page_size	= 256 * 1024,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { INTEL_ID, INTEL_28F002T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5668,12 +6183,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Intel",
 		.name		= "28F008S3/S5/SC",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= INTEL_28F004S3,
 		.total_size	= 512,
 		.page_size	= 256,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { INTEL_ID, INTEL_28F004S3 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5690,12 +6206,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Intel",
 		.name		= "28F004B5/BE/BV/BX-B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= INTEL_28F004B,
 		.total_size	= 512,
 		.page_size	= 128 * 1024, /* maximal block size */
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { INTEL_ID, INTEL_28F004B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5716,12 +6233,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Intel",
 		.name		= "28F004B5/BE/BV/BX-T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= INTEL_28F004T,
 		.total_size	= 512,
 		.page_size	= 128 * 1024, /* maximal block size */
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { INTEL_ID, INTEL_28F004T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5742,12 +6260,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Intel",
 		.name		= "28F400BV/BX/CE/CV-B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= INTEL_28F400B,
 		.total_size	= 512,
 		.page_size	= 128 * 1024, /* maximal block size */
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_shifted,
+		.probers	=
+		{
+			{ probe_82802ab_shifted, { 3, { INTEL_ID, INTEL_28F400B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5768,12 +6287,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Intel",
 		.name		= "28F400BV/BX/CE/CV-T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= INTEL_28F400T,
 		.total_size	= 512,
 		.page_size	= 128 * 1024, /* maximal block size */
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_shifted,
+		.probers	=
+		{
+			{ probe_82802ab_shifted, { 3, { INTEL_ID, INTEL_28F400T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5794,13 +6314,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Intel",
 		.name		= "82802AB",
 		.bustype	= BUS_FWH,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= INTEL_82802AB,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { INTEL_ID, INTEL_82802AB } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5818,13 +6339,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Intel",
 		.name		= "82802AC",
 		.bustype	= BUS_FWH,
-		.manufacture_id	= INTEL_ID,
-		.model_id	= INTEL_82802AC,
 		.total_size	= 1024,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { INTEL_ID, INTEL_82802AC } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5842,12 +6364,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX23L3254",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX23L3254,
 		.total_size	= 4096,
 		.page_size	= 256,
 		.tested		= {.probe = OK, .read = OK, .erase = NA, .write = NA},
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX23L3254 } } },
+		},
 		.write		= NULL, /* MX23L3254 is a mask ROM, so it is read-only */
 		.read		= spi_chip_read, /* Fast read (0x0B) supported */
 		.voltage	= {3000, 3600},
@@ -5857,14 +6380,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L512(E)/MX25V512(C)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L512,
 		.total_size	= 64,
 		.page_size	= 256,
 		/* MX25L512E supports SFDP */
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L512 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5895,14 +6419,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L1005(C)/MX25L1006E",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L1005,
 		.total_size	= 128,
 		.page_size	= 256,
 		/* MX25L1006E supports SFDP */
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L1005 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5930,13 +6455,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L2005(C)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L2005,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L2005 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -5967,13 +6493,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L4005(A/C)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L4005,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L4005 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6004,13 +6531,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L8005/MX25V8005",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L8005,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L8005 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6041,13 +6569,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L1605",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L1605,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L1605 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6075,14 +6604,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L1605A/MX25L1606E",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L1605,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* OTP: 64B total; enter 0xB1, exit 0xC1 (MX25L1606E only) */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L1605 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6113,13 +6643,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L1605D/MX25L1608D/MX25L1673E",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L1605,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L1605 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6147,14 +6678,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L1635D",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L1635D,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* OTP: 64B total; enter 0xB1, exit 0xC1 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L1635D } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6182,14 +6714,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L1635E",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L1635E,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* OTP: 64B total; enter 0xB1, exit 0xC1 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L1635E } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6217,13 +6750,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L3205(A)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L3205,
 		.total_size	= 4096,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L3205 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6251,14 +6785,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L3205D/MX25L3208D",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L3205,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* OTP: 64B total; enter 0xB1, exit 0xC1 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L3205 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6286,14 +6821,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L3206E",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L3205,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* OTP: 64B total; enter 0xB1, exit 0xC1 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L3205 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6324,14 +6860,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L3273E",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L3205,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* OTP: 64B total; enter 0xB1, exit 0xC1 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L3205 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6362,14 +6899,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L3235D",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L3235D,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* OTP: 256B total; enter 0xB1, exit 0xC1 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L3235D } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6397,14 +6935,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L6405(D)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L6405,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* MX25L6405D has 64B of OTP; enter 0xB1, exit 0xC1 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L6405 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6432,14 +6971,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L6406E/MX25L6436E",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L6405,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* OTP: 06E 64B/36E 512B total; enter 0xB1, exit 0xC1 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L6405 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6467,15 +7007,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L6445E/MX25L6473E",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L6405,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* supports SFDP */
 		/* OTP: 512B total; enter 0xB1, exit 0xC1 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L6405 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6506,14 +7047,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25L12805(D)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25L12805,
 		.total_size	= 16384,
 		.page_size	= 256,
 		/* MX25L12805D has 64B of OTP; enter 0xB1, exit 0xC1 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25L12805 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6541,15 +7083,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25U1635E",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25U1635E,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* OTP: 512B total; enter 0xB1, exit 0xC1 */
 		/* QPI enable 0x35, disable 0xF5 (0xFF et al. work too) */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25U1635E } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6581,8 +7124,6 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25U3235E/F",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25U3235E,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* F model supports SFDP */
@@ -6590,7 +7131,10 @@ const struct flashchip flashchips[] = {
 		/* QPI enable 0x35, disable 0xF5 (0xFF et al. work too) */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25U3235E } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6622,8 +7166,6 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX25U6435E/F",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX25U6435E,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* F model supports SFDP */
@@ -6631,7 +7173,10 @@ const struct flashchip flashchips[] = {
 		/* QPI enable 0x35, disable 0xF5 (0xFF et al. work too) */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { MACRONIX_ID, MACRONIX_MX25U6435E } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6663,13 +7208,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX29F001B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX29F001B,
 		.total_size	= 128,
 		.page_size	= 32 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { MACRONIX_ID, MACRONIX_MX29F001B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6695,13 +7241,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX29F001T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX29F001T,
 		.total_size	= 128,
 		.page_size	= 32 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { MACRONIX_ID, MACRONIX_MX29F001T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6727,13 +7274,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX29F002(N)B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX29F002B,
 		.total_size	= 256,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { MACRONIX_ID, MACRONIX_MX29F002B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6758,13 +7306,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX29F002(N)T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX29F002T,
 		.total_size	= 256,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { MACRONIX_ID, MACRONIX_MX29F002T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6789,13 +7338,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX29F040",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX29F040,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { MACRONIX_ID, MACRONIX_MX29F040 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6815,13 +7365,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Macronix",
 		.name		= "MX29LV040",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= MACRONIX_MX29LV040,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { MACRONIX_ID, MACRONIX_MX29LV040 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6841,13 +7392,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25P05-A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P05A,
 		.total_size	= 64,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M25P05A } } },
+			{ probe_spi_res, { 1, { ST_M25P05A_RES } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6874,13 +7427,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25P05",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= 0, /* Not used. */
-		.model_id	= ST_M25P05_RES,
 		.total_size	= 64,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_res1,
+		.probers	=
+		{
+			{ probe_spi_res, { 1, { ST_M25P05_RES } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6902,13 +7456,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25P10-A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P10A,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, {ST_ID, ST_M25P10A } } },
+			{ probe_spi_res, { 1, { ST_M25P10_RES } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6931,13 +7487,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25P10",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= 0, /* Not used. */
-		.model_id	= ST_M25P10_RES,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_res1,
+		.probers	=
+		{
+			{ probe_spi_res, { 1, { ST_M25P10_RES } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6959,13 +7516,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST", /* Numonyx */
 		.name		= "M25P20",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P20,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, {ST_ID, ST_M25P20 } } },
+			{ probe_spi_res, { 1, {ST_ID, ST_M25P20_RES } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -6987,13 +7546,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25P20-old",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= 0, /* Not used. */
-		.model_id	= ST_M25P20_RES,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_res1,
+		.probers	=
+		{
+			{ probe_spi_res, { 1, {ST_ID, ST_M25P20 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7015,13 +7575,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST", /* Numonyx */
 		.name		= "M25P40",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P40,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, {ST_ID, ST_M25P40 } } },
+			{ probe_spi_res, { 1, {ST_ID, ST_M25P40_RES } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7043,13 +7605,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25P40-old",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= 0, /* Not used. */
-		.model_id	= ST_M25P40_RES,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_res1,
+		.probers	=
+		{
+			{ probe_spi_res, { 1, { ST_M25P40_RES } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7070,13 +7633,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25P80",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P80,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M25P80 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7098,13 +7662,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25P16",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P16,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M25P16 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7126,13 +7691,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25P32",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P32,
 		.total_size	= 4096,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M25P32 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7154,13 +7720,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25P64",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P64,
 		.total_size	= 8192,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M25P64 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7182,13 +7749,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25P128",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25P128,
 		.total_size	= 16384,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M25P128 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7210,13 +7778,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25PE10",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25PE10,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M25PE10 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7241,13 +7810,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25PE20",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25PE20,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M25PE20 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7272,13 +7842,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25PE40",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25PE40,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M25PE40 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7303,13 +7874,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25PE80",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25PE80,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M25PE80 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7334,13 +7906,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25PE16",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25PE16,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M25PE16 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7365,14 +7938,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25PX80",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25PX80,
 		.total_size	= 1024,
 		.page_size	= 256,
 		/* OTP: 64B total; read 0x4B, write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M25PX80 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { { 4 * 1024, 256 } },
@@ -7396,14 +7970,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25PX16",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25PX16,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* OTP: 64B total; read 0x4B; write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M25PX16 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7428,14 +8003,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25PX32",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25PX32,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* OTP: 64B total; read 0x4B; write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M25PX32 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7460,14 +8036,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M25PX64",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M25PX64,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* OTP: 64B total; read 0x4B; write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M25PX64 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7492,12 +8069,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M45PE10",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M45PE10,
 		.total_size	= 128,
 		.page_size	= 256,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M45PE10 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {256, 512} },
@@ -7518,12 +8096,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M45PE20",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M45PE20,
 		.total_size	= 256,
 		.page_size	= 256,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M45PE20 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {256, 1024} },
@@ -7544,12 +8123,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M45PE40",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M45PE40,
 		.total_size	= 512,
 		.page_size	= 256,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M45PE40 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {256, 2048} },
@@ -7570,12 +8150,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M45PE80",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M45PE80,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M45PE80 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {256, 4096} },
@@ -7596,12 +8177,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "M45PE16",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M45PE16,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_M45PE16 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {256, 8192} },
@@ -7622,15 +8204,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "N25Q016",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_N25Q016__1E,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* supports SFDP */
 		/* OTP: 64B total; read 0x4B, write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_N25Q016__1E } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7658,15 +8241,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "N25Q032..1E",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_N25Q032__1E,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* supports SFDP */
 		/* OTP: 64B total; read 0x4B, write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_N25Q032__1E } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7691,15 +8275,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "N25Q032..3E",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_N25Q032__3E,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* supports SFDP */
 		/* OTP: 64B total; read 0x4B, write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_N25Q032__3E } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7724,15 +8309,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "N25Q064..1E", /* ..1E = 1.8V, uniform 64KB/4KB blocks/sectors */
 		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_N25Q064__1E,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* supports SFDP */
 		/* OTP: 64B total; read 0x4B, write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_N25Q064__1E } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7757,15 +8343,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "N25Q064..3E", /* ..3E = 3V, uniform 64KB/4KB blocks/sectors */
 		.bustype	= BUS_SPI,
-		.manufacture_id = ST_ID,
-		.model_id	= ST_N25Q064__3E,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* supports SFDP */
 		/* OTP: 64B total; read 0x4B, write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_N25Q064__3E } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7790,15 +8377,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "N25Q128..1E", /* ..1E = 1.8V, uniform 64KB/4KB blocks/sectors */
 		.bustype	= BUS_SPI,
-		.manufacture_id = ST_ID,
-		.model_id	= ST_N25Q128__1E,
 		.total_size	= 16384,
 		.page_size	= 256,
 		/* supports SFDP */
 		/* OTP: 64B total; read 0x4B, write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_N25Q128__1E } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 4096 } },
@@ -7822,15 +8410,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Micron/Numonyx/ST",
 		.name		= "N25Q128..3E", /* ..3E = 3V, uniform 64KB/4KB blocks/sectors */
 		.bustype	= BUS_SPI,
-		.manufacture_id = ST_ID,
-		.model_id	= ST_N25Q128__3E,
 		.total_size	= 16384,
 		.page_size	= 256,
 		/* supports SFDP */
 		/* OTP: 64B total; read 0x4B, write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { ST_ID, ST_N25Q128__3E } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 4096 } },
@@ -7854,13 +8443,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "MoselVitelic",
 		.name		= "V29C51000B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SYNCMOS_MVC_ID,
-		.model_id	= MVC_V29C51000B,
 		.total_size	= 64,
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SYNCMOS_MVC_ID, MVC_V29C51000B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7880,13 +8470,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "MoselVitelic",
 		.name		= "V29C51000T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SYNCMOS_MVC_ID,
-		.model_id	= MVC_V29C51000T,
 		.total_size	= 64,
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SYNCMOS_MVC_ID, MVC_V29C51000T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7906,13 +8497,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "MoselVitelic",
 		.name		= "V29C51400B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SYNCMOS_MVC_ID,
-		.model_id	= MVC_V29C51400B,
 		.total_size	= 512,
 		.page_size	= 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SYNCMOS_MVC_ID, MVC_V29C51400B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7932,13 +8524,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "MoselVitelic",
 		.name		= "V29C51400T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SYNCMOS_MVC_ID,
-		.model_id	= MVC_V29C51400T,
 		.total_size	= 512,
 		.page_size	= 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SYNCMOS_MVC_ID, MVC_V29C51400T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7958,13 +8551,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "MoselVitelic",
 		.name		= "V29LC51000",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SYNCMOS_MVC_ID,
-		.model_id	= MVC_V29LC51000,
 		.total_size	= 64,
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SYNCMOS_MVC_ID, MVC_V29LC51000 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -7984,13 +8578,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "MoselVitelic",
 		.name		= "V29LC51001",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SYNCMOS_MVC_ID,
-		.model_id	= MVC_V29LC51001,
 		.total_size	= 128,
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SYNCMOS_MVC_ID, MVC_V29LC51001 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8010,13 +8605,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "MoselVitelic",
 		.name		= "V29LC51002",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SYNCMOS_MVC_ID,
-		.model_id	= MVC_V29LC51002,
 		.total_size	= 256,
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SYNCMOS_MVC_ID, MVC_V29LC51002 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8036,13 +8632,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Nantronics",
 		.name		= "N25S10",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= NANTRONICS_ID_NOPREFIX,
-		.model_id	= NANTRONICS_N25S10,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { NANTRONICS_ID_NOPREFIX, NANTRONICS_N25S10 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8076,13 +8673,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Nantronics",
 		.name		= "N25S20",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= NANTRONICS_ID_NOPREFIX,
-		.model_id	= NANTRONICS_N25S20,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { NANTRONICS_ID_NOPREFIX, NANTRONICS_N25S20 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8116,13 +8714,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Nantronics",
 		.name		= "N25S40",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= NANTRONICS_ID_NOPREFIX,
-		.model_id	= NANTRONICS_N25S40,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { NANTRONICS_ID_NOPREFIX, NANTRONICS_N25S40 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8156,13 +8755,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Nantronics",
 		.name		= "N25S80",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= NANTRONICS_ID_NOPREFIX,
-		.model_id	= NANTRONICS_N25S80,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { NANTRONICS_ID_NOPREFIX, NANTRONICS_N25S80 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8193,13 +8793,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Nantronics",
 		.name		= "N25S16",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= NANTRONICS_ID_NOPREFIX,
-		.model_id	= NANTRONICS_N25S16,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { NANTRONICS_ID_NOPREFIX, NANTRONICS_N25S16 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8227,13 +8828,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm25LD256C",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= PMC_PM25LD256C,
 		.total_size	= 32,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { PMC_ID, PMC_PM25LD256C } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8263,13 +8865,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm25LD512(C)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= PMC_PM25LD512,
 		.total_size	= 64,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { PMC_ID, PMC_PM25LD512 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8300,13 +8903,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm25LD010(C)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= PMC_PM25LD010,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { PMC_ID, PMC_PM25LD010 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8337,13 +8941,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm25LD020(C)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= PMC_PM25LD020,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { PMC_ID, PMC_PM25LD020 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8374,13 +8979,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm25LD040(C)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= PMC_PM25LV040,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { PMC_ID, PMC_PM25LV040 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8411,13 +9017,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm25LV512(A)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= PMC_ID_NOPREFIX,
-		.model_id	= PMC_PM25LV512,
 		.total_size	= 64,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_res2, /* The continuation code is transferred as the 3rd byte m( */
+		.probers	=
+		{
+			{ probe_spi_res, { 2, { PMC_ID_NOPREFIX, PMC_PM25LV512 } } }, /* The continuation code is transferred as the 3rd byte m( */
+		},
 		.block_erasers	=
 		{
 			{
@@ -8442,13 +9049,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm25LV010",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= PMC_ID_NOPREFIX,
-		.model_id	= PMC_PM25LV010,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_res2, /* The continuation code is transferred as the 3rd byte m( */
+		.probers	=
+		{
+			{ probe_spi_res, { 2, { PMC_ID_NOPREFIX, PMC_PM25LV010 } } }, /* The continuation code is transferred as the 3rd byte m( */
+		},
 		.block_erasers	=
 		{
 			{
@@ -8473,13 +9081,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm25LV010A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= PMC_PM25LV010,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { PMC_ID, PMC_PM25LV010 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8504,13 +9113,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm25LV020",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= PMC_PM25LV020,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { PMC_ID, PMC_PM25LV020 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8535,13 +9145,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm25LV040",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= PMC_PM25LV040,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { PMC_ID, PMC_PM25LV040 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8566,13 +9177,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm25LV080B",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= PMC_PM25LV080B,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { PMC_ID, PMC_PM25LV080B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8603,13 +9215,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm25LV016B",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= PMC_PM25LV016B,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { PMC_ID, PMC_PM25LV016B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8640,13 +9253,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm29F002T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= PMC_ID_NOPREFIX,
-		.model_id	= PMC_PM29F002T,
 		.total_size	= 256,
 		.page_size	= 8 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { PMC_ID_NOPREFIX, PMC_PM29F002T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8671,13 +9285,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm29F002B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= PMC_ID_NOPREFIX,
-		.model_id	= PMC_PM29F002B,
 		.total_size	= 256,
 		.page_size	= 8 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { PMC_ID_NOPREFIX, PMC_PM29F002B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8702,13 +9317,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm39LV010",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= PMC_ID_NOPREFIX,
-		.model_id	= PMC_PM39F010,	/* Pm39LV010 and Pm39F010 have identical IDs but different voltage */
 		.total_size	= 128,
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { PMC_ID_NOPREFIX, PMC_PM39F010 } } },	/* Pm39LV010 and Pm39F010 have identical IDs but different voltage */
+		},
 		.block_erasers	=
 		{
 			{
@@ -8731,13 +9347,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm39LV020",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= PMC_ID_NOPREFIX,
-		.model_id	= PMC_PM39LV020,
 		.total_size	= 256,
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { PMC_ID_NOPREFIX, PMC_PM39LV020 } } },
+		},
 		.block_erasers =
 		{
 			{
@@ -8760,13 +9377,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm39LV040",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= PMC_ID_NOPREFIX,
-		.model_id	= PMC_PM39LV040,
 		.total_size	= 512,
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { PMC_ID_NOPREFIX, PMC_PM39LV040 } } },
+		},
 		.block_erasers =
 		{
 			{
@@ -8789,13 +9407,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm39LV512",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= PMC_ID_NOPREFIX,
-		.model_id	= PMC_PM39LV512,
 		.total_size	= 64,
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { PMC_ID_NOPREFIX, PMC_PM39LV512 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8818,13 +9437,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm49FL002",
 		.bustype	= BUS_LPC | BUS_FWH, /* A/A Mux */
-		.manufacture_id	= PMC_ID_NOPREFIX,
-		.model_id	= PMC_PM49FL002,
 		.total_size	= 256,
 		.page_size	= 16 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { PMC_ID_NOPREFIX, PMC_PM49FL002 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8848,13 +9468,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "PMC",
 		.name		= "Pm49FL004",
 		.bustype	= BUS_LPC | BUS_FWH, /* A/A Mux */
-		.manufacture_id	= PMC_ID_NOPREFIX,
-		.model_id	= PMC_PM49FL004,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { PMC_ID_NOPREFIX, PMC_PM49FL004 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8878,13 +9499,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Sanyo",
 		.name		= "LE25FW106",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SANYO_ID,
-		.model_id	= SANYO_LE25FW106,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_res2,
+		.probers	=
+		{
+			{ probe_spi_res, { 2, { SANYO_ID, SANYO_LE25FW106 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {2 * 1024, 64} },
@@ -8908,13 +9530,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Sanyo",
 		.name		= "LE25FW406A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SANYO_ID,
-		.model_id	= SANYO_LE25FW406A,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_res2,
+		.probers	=
+		{
+			{ probe_spi_res, { 2, { SANYO_ID, SANYO_LE25FW406A } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 128} },
@@ -8938,13 +9561,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Sanyo",
 		.name		= "LE25FU406B",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SANYO_ID,
-		.model_id	= SANYO_LE25FU406B,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_res2,
+		.probers	=
+		{
+			{ probe_spi_res, { 2, { SANYO_ID, SANYO_LE25FU406B } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 128} },
@@ -8968,12 +9592,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Sanyo",
 		.name		= "LE25FW203A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SANYO_ID,
-		.model_id	= SANYO_LE25FW203A,
 		.total_size	= 256,
 		.page_size	= 256,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SANYO_ID, SANYO_LE25FW203A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -8998,12 +9623,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Sanyo",
 		.name		= "LE25FW403A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SANYO_ID,
-		.model_id	= SANYO_LE25FW403A,
 		.total_size	= 512,
 		.page_size	= 256,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SANYO_ID, SANYO_LE25FW403A } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {256, 2 * 1024} },
@@ -9027,13 +9653,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Sanyo",
 		.name		= "LE25FW418A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SANYO_ID,
-		.model_id	= SANYO_LE25FW418A,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_res2,
+		.probers	=
+		{
+			{ probe_spi_res, { 2, { SANYO_ID, SANYO_LE25FW418A } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 128} },
@@ -9057,13 +9684,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Sanyo",
 		.name		= "LE25FW806",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SANYO_ID,
-		.model_id	= SANYO_LE25FW806,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_res2,
+		.probers	=
+		{
+			{ probe_spi_res, { 2, { SANYO_ID, SANYO_LE25FW806 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 256} },
@@ -9090,13 +9718,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Sanyo",
 		.name		= "LE25FW808",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SANYO_ID,
-		.model_id	= SANYO_LE25FW808,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_res2,
+		.probers	=
+		{
+			{ probe_spi_res, { 2, { SANYO_ID, SANYO_LE25FW808 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {8 * 1024, 128} },
@@ -9120,12 +9749,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Sharp",
 		.name		= "LH28F008BJT-BTLZ1",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SHARP_ID,
-		.model_id	= SHARP_LH28F008BJ__PB,
 		.total_size	= 1024,
 		.page_size	= 64 * 1024,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { SHARP_ID, SHARP_LH28F008BJ__PB } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9149,13 +9779,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Sharp",
 		.name		= "LHF00L04",
 		.bustype	= BUS_FWH, /* A/A Mux */
-		.manufacture_id	= SHARP_ID,
-		.model_id	= SHARP_LHF00L04,
 		.total_size	= 1024,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { SHARP_ID, SHARP_LHF00L04 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9181,13 +9812,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Spansion",
 		.name		= "S25FL004A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SPANSION_ID,
-		.model_id	= SPANSION_S25FL004A,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SPANSION_ID, SPANSION_S25FL004A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9209,13 +9841,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Spansion",
 		.name		= "S25FL008A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SPANSION_ID,
-		.model_id	= SPANSION_S25FL008A,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SPANSION_ID, SPANSION_S25FL008A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9237,13 +9870,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Spansion",
 		.name		= "S25FL016A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SPANSION_ID,
-		.model_id	= SPANSION_S25FL016A,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SPANSION_ID, SPANSION_S25FL016A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9265,13 +9899,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Spansion",
 		.name		= "S25FL032A/P",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SPANSION_ID,
-		.model_id	= SPANSION_S25FL032A,
 		.total_size	= 4096,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SPANSION_ID, SPANSION_S25FL032A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9293,13 +9928,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Spansion",
 		.name		= "S25FL064A/P",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SPANSION_ID,
-		.model_id	= SPANSION_S25FL064A,
 		.total_size	= 8192,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SPANSION_ID, SPANSION_S25FL064A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9321,13 +9957,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Spansion",
 		.name		= "S25FL204K",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SPANSION_ID,
-		.model_id	= SPANSION_S25FL204,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SPANSION_ID, SPANSION_S25FL204 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 128} },
@@ -9354,13 +9991,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Spansion",
 		.name		= "S25FL208K",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SPANSION_ID,
-		.model_id	= SPANSION_S25FL208,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SPANSION_ID, SPANSION_S25FL208 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 256} },
@@ -9387,14 +10025,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Spansion",
 		.name		= "S25FL116K/S25FL216K",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SPANSION_ID,
-		.model_id	= SPANSION_S25FL216,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 (S25FL116K only) */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SPANSION_ID, SPANSION_S25FL216 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 512} },
@@ -9421,14 +10060,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Spansion",
 		.name		= "S25FL132K",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SPANSION_ID,
-		.model_id	= SPANSION_S25FL132K,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* OTP: 768B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SPANSION_ID, SPANSION_S25FL132K } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 1024} },
@@ -9455,14 +10095,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Spansion",
 		.name		= "S25FL164K",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SPANSION_ID,
-		.model_id	= SPANSION_S25FL164K,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SPANSION_ID, SPANSION_S25FL164K } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 2048} },
@@ -9489,15 +10130,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Spansion",
 		.name		= "S25FL128S......0", /* uniform 256kB sectors */
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SPANSION_ID,
-		.model_id	= SPANSION_S25FL128,
 		.total_size	= 16384,
 		.page_size	= 256,
 		/* supports 4B addressing */
 		/* OTP: 1024B total, 32B reserved; read 0x4B; write 0x42 */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SPANSION_ID, SPANSION_S25FL128 } } },
+		},
 		.block_erasers	= {
 			{
 				.eraseblocks = { {4 * 1024, 4096} },
@@ -9524,13 +10166,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25LF020A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25VF020_REMS,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EWSR,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rems,
+		.probers	=
+		{
+			{ probe_spi_rems, { 2, {  SST_ID, SST_SST25VF020_REMS } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9555,13 +10198,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25LF040A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25VF040_REMS,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EWSR,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_res2,
+		.probers	=
+		{
+			{ probe_spi_res, { 2, {  SST_ID, SST_SST25VF040_REMS } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9586,13 +10230,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25LF080(A)",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25VF080_REMS,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EITHER,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_res2,
+		.probers	=
+		{
+			{ probe_spi_res, { 2, { SST_ID, SST_SST25VF080_REMS } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9617,13 +10262,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25VF512A",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25VF512A_REMS,
 		.total_size	= 64,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EWSR,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rems,
+		.probers	=
+		{
+			{ probe_spi_rems, { 3, { SST_ID, SST_SST25VF512A_REMS } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9654,13 +10300,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25VF010",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25VF010_REMS,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EWSR,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rems,
+		.probers	=
+		{
+			{ probe_spi_rems, { 3, { SST_ID, SST_SST25VF010_REMS } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9691,13 +10338,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25VF020",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25VF020_REMS,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EWSR,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rems,
+		.probers	=
+		{
+			{ probe_spi_rems, { 3, { SST_ID, SST_SST25VF020_REMS } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9722,13 +10370,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25VF020B",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25VF020B,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EWSR,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SST_ID, SST_SST25VF020B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9759,13 +10408,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25VF040",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25VF040_REMS,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EWSR,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_spi_rems,
+		.probers	=
+		{
+			{ probe_spi_rems, { 3, { SST_ID, SST_SST25VF040_REMS } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9790,13 +10440,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25VF040B",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25VF040B,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EWSR,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SST_ID, SST_SST25VF040B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9827,13 +10478,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25VF040B.REMS",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25VF040B_REMS,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EWSR,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rems,
+		.probers	=
+		{
+			{ probe_spi_rems, { 3, { SST_ID, SST_SST25VF040B_REMS } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9864,13 +10516,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25VF080B",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25VF080B,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EWSR,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SST_ID, SST_SST25VF080B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9901,13 +10554,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25VF016B",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25VF016B,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EITHER,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SST_ID, SST_SST25VF016B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9938,13 +10592,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25VF032B",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25VF032B,
 		.total_size	= 4096,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EWSR,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SST_ID, SST_SST25VF032B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -9975,13 +10630,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25VF064C",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25VF064C,
 		.total_size	= 8192,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EWSR,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SST_ID, SST_SST25VF064C } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -10012,13 +10668,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25WF512",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25WF512,
 		.total_size	= 64,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EITHER,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SST_ID, SST_SST25WF512 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -10046,13 +10703,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25WF010",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25WF010,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EITHER,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SST_ID, SST_SST25WF010 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -10080,13 +10738,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25WF020",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25WF020,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EITHER,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SST_ID, SST_SST25WF020 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -10117,13 +10776,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25WF040",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25WF040,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EITHER,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SST_ID, SST_SST25WF040 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -10154,13 +10814,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST25WF080",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST25WF080,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_EITHER,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { SST_ID, SST_SST25WF080 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -10191,13 +10852,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST28SF040A",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST28SF040,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= 0,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { SST_ID, SST_SST28SF040 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -10218,13 +10880,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST29EE010",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST29EE010,
 		.total_size	= 128,
 		.page_size	= 128,
-		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_longreset, { 3, { SST_ID, SST_SST29EE010 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -10241,13 +10903,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST29LE010",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST29LE010,
 		.total_size	= 128,
 		.page_size	= 128,
-		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_longreset, { 3, { SST_ID, SST_SST29LE010 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -10264,13 +10926,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST29EE020A",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST29EE020A,
 		.total_size	= 256,
 		.page_size	= 128,
-		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_longreset, { 3, { SST_ID, SST_SST29EE020A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -10287,13 +10949,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST29LE020",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST29LE020,
 		.total_size	= 256,
 		.page_size	= 128,
-		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_longreset, { 3, { SST_ID, SST_SST29LE020 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -10310,13 +10972,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST39SF512",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST39SF512,
 		.total_size	= 64,
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST39SF512 } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10336,13 +10999,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST39SF010A",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST39SF010,
 		.total_size	= 128,
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST39SF010 } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10362,13 +11026,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST39SF020A",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST39SF020,
 		.total_size	= 256,
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST39SF020 } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10388,13 +11053,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST39SF040",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST39SF040,
 		.total_size	= 512,
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST39SF040 } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10414,13 +11080,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST39VF512",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST39VF512,
 		.total_size	= 64,
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST39VF512 } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10440,13 +11107,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST39VF010",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST39VF010,
 		.total_size	= 128,
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST39VF010 } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10466,13 +11134,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST39VF020",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST39VF020,
 		.total_size	= 256,
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST39VF020 } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10492,13 +11161,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST39VF040",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST39VF040,
 		.total_size	= 512,
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST39VF040 } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10518,13 +11188,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST39VF080",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST39VF080,
 		.total_size	= 1024,
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST39VF080 } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10547,13 +11218,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST49LF002A/B",
 		.bustype	= BUS_FWH, /* A/A Mux */
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST49LF002A,
 		.total_size	= 256,
 		.page_size	= 16 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST49LF002A } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10578,13 +11250,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST49LF003A/B",
 		.bustype	= BUS_FWH, /* A/A Mux */
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST49LF003A,
 		.total_size	= 384,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST49LF003A } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10612,13 +11285,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST49LF004A/B",
 		.bustype	= BUS_FWH, /* A/A Mux */
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST49LF004A,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST49LF004A } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10643,13 +11317,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST49LF004C",
 		.bustype	= BUS_FWH,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST49LF004C,
 		.total_size	= 512,
 		.page_size	= 4 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { SST_ID, SST_SST49LF004C } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -10675,13 +11350,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST49LF008A",
 		.bustype	= BUS_FWH, /* A/A Mux */
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST49LF008A,
 		.total_size	= 1024,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST49LF008A } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10706,13 +11382,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST49LF008C",
 		.bustype	= BUS_FWH,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST49LF008C,
 		.total_size	= 1024,
 		.page_size	= 4 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { SST_ID, SST_SST49LF008C } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -10738,13 +11415,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST49LF016C",
 		.bustype	= BUS_FWH,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST49LF016C,
 		.total_size	= 2048,
 		.page_size	= 4 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { SST_ID, SST_SST49LF016C } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -10770,13 +11448,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST49LF020",
 		.bustype	= BUS_LPC,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST49LF020,
 		.total_size	= 256,
 		.page_size	= 16 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, {  SST_ID, SST_SST49LF020 } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10799,13 +11478,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST49LF020A",
 		.bustype	= BUS_LPC,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST49LF020A,
 		.total_size	= 256,
 		.page_size	= 4 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST49LF020A } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10828,13 +11508,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST49LF040",
 		.bustype	= BUS_LPC,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST49LF040,
 		.total_size	= 512,
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST49LF040 } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10857,13 +11538,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST49LF040B",
 		.bustype	= BUS_LPC, /* A/A Mux */
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST49LF040B,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET | FEATURE_REGISTERMAP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec, /* 150 ns */
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST49LF040B } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10887,13 +11569,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST49LF080A",
 		.bustype	= BUS_LPC, /* A/A Mux */
-		.manufacture_id	= SST_ID,
- 		.model_id	= SST_SST49LF080A,
 		.total_size	= 1024,
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SST_ID, SST_SST49LF080A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -10916,13 +11599,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SST",
 		.name		= "SST49LF160C",
 		.bustype	= BUS_LPC,
-		.manufacture_id	= SST_ID,
-		.model_id	= SST_SST49LF160C,
 		.total_size	= 2048,
 		.page_size	= 4 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { SST_ID, SST_SST49LF160C } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -10948,13 +11632,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M29F002B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M29F002B,
 		.total_size	= 256,
 		.page_size	= 64 * 1024,
-		.feature_bits	= FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_aaa, { 2, {  ST_ID, ST_M29F002B } } }, /* 150 ns */
+		},
 		.block_erasers	=
 		{
 			{
@@ -10979,13 +11663,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M29F002T/NT",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M29F002T,
 		.total_size	= 256,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_aaa, { 2, { ST_ID, ST_M29F002T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11010,13 +11695,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M29F040B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M29F040B,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
-		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, {  ST_ID, ST_M29F040B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11037,12 +11722,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M29F400BB",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M29F400BB,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_m29f400bt,
+		.probers	=
+		{
+			{ probe_m29f400bt, { 3, { ST_ID, ST_M29F400BB } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11062,17 +11748,19 @@ const struct flashchip flashchips[] = {
 		.read		= read_memmapped,
 		.voltage	= {4500, 5500},
 	},
+
 	{
 		/* FIXME: this has WORD/BYTE sequences; 2AA for word, 555 for byte */
 		.vendor		= "ST",
 		.name		= "M29F400BT",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M29F400BT,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_m29f400bt,
+		.probers	=
+		{
+			{ probe_m29f400bt, { 2, {  ST_ID, ST_M29F400BT } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11097,13 +11785,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M29W010B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M29W010B,
 		.total_size	= 128,
 		.page_size	= 16 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { ST_ID, ST_M29W010B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11123,13 +11812,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M29W040B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M29W040B,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { ST_ID, ST_M29W040B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11149,13 +11839,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M29W512B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id = ST_ID,
-		.model_id	= ST_M29W512B,
 		.total_size	= 64,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { ST_ID, ST_M29W512B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11172,13 +11863,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M50FLW040A",
 		.bustype	= BUS_FWH | BUS_LPC, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50FLW040A,
 		.total_size	= 512,
 		.page_size	= 0,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { ST_ID, ST_M50FLW040A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11204,13 +11896,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M50FLW040B",
 		.bustype	= BUS_FWH | BUS_LPC, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50FLW040B,
 		.total_size	= 512,
 		.page_size	= 0,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { ST_ID, ST_M50FLW040B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11236,13 +11929,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M50FLW080A",
 		.bustype	= BUS_FWH | BUS_LPC, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50FLW080A,
 		.total_size	= 1024,
 		.page_size	= 0,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { ST_ID, ST_M50FLW080A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11268,13 +11962,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M50FLW080B",
 		.bustype	= BUS_FWH | BUS_LPC, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50FLW080B,
 		.total_size	= 1024,
 		.page_size	= 0,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { ST_ID, ST_M50FLW080B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11300,13 +11995,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M50FW002",
 		.bustype	= BUS_FWH, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50FW002,
 		.total_size	= 256,
 		.page_size	= 0,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { ST_ID, ST_M50FW002 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11329,13 +12025,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M50FW016",
 		.bustype	= BUS_FWH, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50FW016,
 		.total_size	= 2048,
 		.page_size	= 0,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { ST_ID, ST_M50FW016 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11353,13 +12050,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M50FW040",
 		.bustype	= BUS_FWH, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50FW040,
 		.total_size	= 512,
 		.page_size	= 0,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { ST_ID, ST_M50FW040 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11377,13 +12075,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M50FW080",
 		.bustype	= BUS_FWH, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50FW080,
 		.total_size	= 1024,
 		.page_size	= 0,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { ST_ID, ST_M50FW080 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11401,13 +12100,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M50LPW080",
 		.bustype	= BUS_LPC, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50LPW080,
 		.total_size	= 1024,
 		.page_size	= 0,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { ST_ID, ST_M50LPW080 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11425,13 +12125,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "ST",
 		.name		= "M50LPW116",
 		.bustype	= BUS_LPC, /* A/A Mux */
-		.manufacture_id	= ST_ID,
-		.model_id	= ST_M50LPW116,
 		.total_size	= 2048,
 		.page_size	= 0,
 		.feature_bits	= FEATURE_REGISTERMAP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_82802ab_unshifted,
+		.probers	=
+		{
+			{ probe_82802ab_unshifted, { 3, { ST_ID, ST_M50LPW116 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11455,13 +12156,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SyncMOS/MoselVitelic",
 		.name		= "{F,S,V}29C51001B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SYNCMOS_MVC_ID,
-		.model_id	= SM_MVC_29C51001B,
 		.total_size	= 128,
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SYNCMOS_MVC_ID, SM_MVC_29C51001B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11481,13 +12183,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SyncMOS/MoselVitelic",
 		.name		= "{F,S,V}29C51001T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SYNCMOS_MVC_ID,
-		.model_id	= SM_MVC_29C51001T,
 		.total_size	= 128,
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SYNCMOS_MVC_ID, SM_MVC_29C51001T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11507,13 +12210,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SyncMOS/MoselVitelic",
 		.name		= "{F,S,V}29C51002B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SYNCMOS_MVC_ID,
-		.model_id	= SM_MVC_29C51002B,
 		.total_size	= 256,
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SYNCMOS_MVC_ID, SM_MVC_29C51002B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11532,13 +12236,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SyncMOS/MoselVitelic",
 		.name		= "{F,S,V}29C51002T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SYNCMOS_MVC_ID,
-		.model_id	= SM_MVC_29C51002T,
 		.total_size	= 256,
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SYNCMOS_MVC_ID, SM_MVC_29C51002T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11557,13 +12262,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SyncMOS/MoselVitelic",
 		.name		= "{F,S,V}29C51004B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SYNCMOS_MVC_ID,
-		.model_id	= SM_MVC_29C51004B,
 		.total_size	= 512,
 		.page_size	= 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SYNCMOS_MVC_ID, SM_MVC_29C51004B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11583,13 +12289,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SyncMOS/MoselVitelic",
 		.name		= "{F,S,V}29C51004T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SYNCMOS_MVC_ID,
-		.model_id	= SM_MVC_29C51004T,
 		.total_size	= 512,
 		.page_size	= 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SYNCMOS_MVC_ID, SM_MVC_29C51004T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11609,13 +12316,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SyncMOS/MoselVitelic",
 		.name		= "{S,V}29C31004B",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SYNCMOS_MVC_ID,
-		.model_id	= SM_MVC_29C31004B,
 		.total_size	= 512,
 		.page_size	= 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SYNCMOS_MVC_ID, SM_MVC_29C31004B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11635,13 +12343,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "SyncMOS/MoselVitelic",
 		.name		= "{S,V}29C31004T",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= SYNCMOS_MVC_ID,
-		.model_id	= SM_MVC_29C31004T,
 		.total_size	= 512,
 		.page_size	= 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { SYNCMOS_MVC_ID, SM_MVC_29C31004T } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11661,13 +12370,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "TI",
 		.name		= "TMS29F002RB",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= TI_OLD_ID,
-		.model_id	= TI_TMS29F002RB,
 		.total_size	= 256,
 		.page_size	= 16384, /* Non-uniform sectors */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { TI_OLD_ID, TI_TMS29F002RB } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11692,13 +12402,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "TI",
 		.name		= "TMS29F002RT",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= TI_OLD_ID,
-		.model_id	= TI_TMS29F002RT,
 		.total_size	= 256,
 		.page_size	= 16384, /* Non-uniform sectors */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_2aa, { 2, { TI_OLD_ID, TI_TMS29F002RT } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11723,15 +12434,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25Q80.V",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25Q80_V,
 		.total_size	= 1024,
 		.page_size	= 256,
 		/* supports SFDP */
 		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { WINBOND_NEX_ID, WINBOND_NEX_W25Q80_V } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11762,15 +12474,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25Q16.V",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25Q16_V,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* supports SFDP */
 		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { WINBOND_NEX_ID, WINBOND_NEX_W25Q16_V } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11801,15 +12514,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25Q32.V",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25Q32_V,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* supports SFDP */
 		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { WINBOND_NEX_ID, WINBOND_NEX_W25Q32_V } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11840,15 +12554,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25Q64.V",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25Q64_V,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* supports SFDP */
 		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { WINBOND_NEX_ID, WINBOND_NEX_W25Q64_V } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11879,15 +12594,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25Q128.V",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25Q128_V,
 		.total_size	= 16384,
 		.page_size	= 256,
 		/* supports SFDP */
 		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { WINBOND_NEX_ID, WINBOND_NEX_W25Q128_V } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11918,14 +12634,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25Q20.W",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25Q20_W,
 		.total_size	= 256,
 		.page_size	= 256,
 		/* OTP: 256B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { WINBOND_NEX_ID, WINBOND_NEX_W25Q20_W } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11956,14 +12673,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25Q40.W",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25Q40_W,
 		.total_size	= 512,
 		.page_size	= 256,
 		/* OTP: 256B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { WINBOND_NEX_ID, WINBOND_NEX_W25Q40_W } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -11994,14 +12712,15 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25Q80.W",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25Q80_W,
 		.total_size	= 1024,
 		.page_size	= 256,
 		/* OTP: 256B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { WINBOND_NEX_ID, WINBOND_NEX_W25Q80_W } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12032,15 +12751,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25Q16.W",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25Q16_W,
 		.total_size	= 2048,
 		.page_size	= 256,
 		/* OTP: 256B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
 		/* QPI enable 0x38, disable 0xFF */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { WINBOND_NEX_ID, WINBOND_NEX_W25Q16_W } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12071,15 +12791,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25Q32.W",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25Q32_W,
 		.total_size	= 4096,
 		.page_size	= 256,
 		/* OTP: 256B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
 		/* QPI enable 0x38, disable 0xFF */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { WINBOND_NEX_ID, WINBOND_NEX_W25Q32_W } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12110,15 +12831,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25Q64.W",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25Q64_W,
 		.total_size	= 8192,
 		.page_size	= 256,
 		/* OTP: 256B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
 		/* QPI enable 0x38, disable 0xFF */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { WINBOND_NEX_ID, WINBOND_NEX_W25Q64_W } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12149,13 +12871,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25X10",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25X10,
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { WINBOND_NEX_ID, WINBOND_NEX_W25X10 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12180,13 +12903,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25X20",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25X20,
 		.total_size	= 256,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { WINBOND_NEX_ID, WINBOND_NEX_W25X20 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12211,13 +12935,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25X40",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25X40,
 		.total_size	= 512,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { WINBOND_NEX_ID, WINBOND_NEX_W25X40 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12242,13 +12967,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25X80",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25X80,
 		.total_size	= 1024,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, { WINBOND_NEX_ID, WINBOND_NEX_W25X80 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12273,13 +12999,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25X16",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25X16,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, {  WINBOND_NEX_ID, WINBOND_NEX_W25X16 } } },
+			{ probe_spi_res,  { 2, { WINBOND_NEX_ID, 0x14 } } },
+			{ probe_spi_rems, { 2, {  WINBOND_NEX_ID, 0x14 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12310,13 +13039,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25X32",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25X32,
 		.total_size	= 4096,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, {  WINBOND_NEX_ID, WINBOND_NEX_W25X32 } } },
+			{ probe_spi_res,  { 2, { WINBOND_NEX_ID, 0x15 } } },
+			{ probe_spi_rems, { 2, {  WINBOND_NEX_ID, 0x15 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12347,13 +13079,16 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W25X64",
 		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= WINBOND_NEX_W25X64,
 		.total_size	= 8192,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_OK_PROBE,
-		.probe		= probe_spi_rdid,
+		.probers	=
+		{
+			{ probe_spi_rdid, { 3, {  WINBOND_NEX_ID, WINBOND_NEX_W25X64 } } },
+			{ probe_spi_res,  { 2, { WINBOND_NEX_ID, 0x16 } } },
+			{ probe_spi_rems, { 2, {  WINBOND_NEX_ID, 0x16 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12384,12 +13119,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W29C010(M)/W29C011A/W29EE011/W29EE012-old",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W29C010,
 		.total_size	= 128,
 		.page_size	= 128,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_w29ee011,
+		.probers	=
+		{
+			{ probe_w29ee011, { 2, {  WINBOND_ID, WINBOND_W29C010 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12405,13 +13141,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W29C010(M)/W29C011A/W29EE011/W29EE012",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W29C010,
 		.total_size	= 128,
 		.page_size	= 128,
-		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,		/* used datasheet for the W29C011A */
+		.probers	=
+		{
+			{ probe_jedec_longreset, { 3, { WINBOND_ID, WINBOND_W29C010 } } },		/* used datasheet for the W29C011A */
+		},
 		.block_erasers	=
 		{
 			{
@@ -12427,13 +13163,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W29C020(C)/W29C022",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W29C020,
 		.total_size	= 256,
 		.page_size	= 128,
-		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_longreset, { 3, { WINBOND_ID, WINBOND_W29C020 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12450,13 +13186,13 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W29C040/P",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W29C040,
 		.total_size	= 512,
 		.page_size	= 256,
-		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_longreset, { 3, { WINBOND_ID, WINBOND_W29C040 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12473,13 +13209,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W39F010",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W39F010,
 		.total_size	= 128,
 		.page_size	= 4 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W39F010 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12500,13 +13237,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W39L010",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W39L010,
 		.total_size	= 128,
 		.page_size	= 4 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W39L010 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12527,13 +13265,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W39L020",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W39L020,
 		.total_size	= 256,
 		.page_size	= 4 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W39L020 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12557,13 +13296,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W39L040",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W39L040,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W39L040 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12587,13 +13327,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W39V040A",
 		.bustype	= BUS_LPC,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W39V040A,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W39V040A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12614,13 +13355,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W39V040B",
 		.bustype	= BUS_LPC,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W39V040B,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W39V040B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12641,13 +13383,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W39V040C",
 		.bustype	= BUS_LPC,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W39V040C,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W39V040C } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12668,13 +13411,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W39V040FA",
 		.bustype	= BUS_FWH,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W39V040FA,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W39V040FA } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12699,13 +13443,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W39V040FB",
 		.bustype	= BUS_FWH,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W39V040B,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W39V040B } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12727,13 +13472,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W39V040FC",
 		.bustype	= BUS_FWH,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W39V040C,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W39V040C } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12754,13 +13500,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W39V080A",
 		.bustype	= BUS_LPC,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W39V080A,
 		.total_size	= 1024,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W39V080A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12781,13 +13528,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W49F002U/N",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W49F002U,
 		.total_size	= 256,
 		.page_size	= 128,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W49F002U } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12812,13 +13560,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W49F020",
 		.bustype	= BUS_PARALLEL,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W49F020,
 		.total_size	= 256,
 		.page_size	= 128,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PROBE,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W49F020 } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12835,13 +13584,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W49V002A",
 		.bustype	= BUS_LPC,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W49V002A,
 		.total_size	= 256,
 		.page_size	= 128,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W49V002A } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12866,13 +13616,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W49V002FA",
 		.bustype	= BUS_FWH,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W49V002FA,
 		.total_size	= 256,
 		.page_size	= 128,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W49V002FA } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12897,13 +13648,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W39V080FA",
 		.bustype	= BUS_FWH,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W39V080FA,
 		.total_size	= 1024,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W39V080FA } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12925,13 +13677,14 @@ const struct flashchip flashchips[] = {
 		.vendor		= "Winbond",
 		.name		= "W39V080FA (dual mode)",
 		.bustype	= BUS_FWH,
-		.manufacture_id	= WINBOND_ID,
-		.model_id	= WINBOND_W39V080FA_DM,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probers	=
+		{
+			{ probe_jedec_shortreset_full, { 2, { WINBOND_ID, WINBOND_W39V080FA_DM } } },
+		},
 		.block_erasers	=
 		{
 			{
@@ -12947,203 +13700,6 @@ const struct flashchip flashchips[] = {
 		.read		= read_memmapped,
 		.voltage	= {3000, 3600}, /* Also has 12V fast program */
 	},
-	
-	{
-		.vendor		= "Unknown",
-		.name		= "SFDP-capable chip",
-		.bustype	= BUS_SPI,
-		.manufacture_id	= GENERIC_MANUF_ID,
-		.model_id	= SFDP_DEVICE_ID,
-		/* We present our own "report this" text hence we do not
-		 * want the default "This flash part has status UNTESTED..."
-		 * text to be printed. */
-		.tested		= TEST_OK_PREW,
-		.probe		= probe_spi_sfdp,
-		.unlock		= spi_disable_blockprotect, /* is this safe? */
-		.read		= spi_chip_read,
-		/* FIXME: some vendor extensions define this */
-		.voltage	= {0},
-		 /* Everything below will be set by the probing function. */
-		.write		= NULL,
-		.total_size	= 0,
-		.page_size	= 0,
-		.feature_bits	= 0,
-		.block_erasers	= {},
-	},
-
-	{
-		.vendor		= "Programmer",
-		.name		= "Opaque flash chip",
-		.bustype	= BUS_PROG,
-		.manufacture_id	= PROGMANUF_ID,
-		.model_id	= PROGDEV_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		/* probe is assumed to work, rest will be filled in by probe */
-		.tested		= TEST_OK_PROBE,
-		.probe		= probe_opaque,
-		/* eraseblock sizes will be set by the probing function */
-		.block_erasers	=
-		{
-			{
-				.block_erase = erase_opaque,
-			}
-		},
-		.write		= write_opaque,
-		.read		= read_opaque,
-	},
-
-	{
-		.vendor		= "AMIC",
-		.name		= "unknown AMIC SPI chip",
-		.bustype	= BUS_SPI,
-		.manufacture_id	= AMIC_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid4,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "Atmel",
-		.name		= "unknown Atmel SPI chip",
-		.bustype	= BUS_SPI,
-		.manufacture_id	= ATMEL_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "Eon",
-		.name		= "unknown Eon SPI chip",
-		.bustype	= BUS_SPI,
-		.manufacture_id	= EON_ID_NOPREFIX,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "Macronix",
-		.name		= "unknown Macronix SPI chip",
-		.bustype	= BUS_SPI,
-		.manufacture_id	= MACRONIX_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "PMC",
-		.name		= "unknown PMC SPI chip",
-		.bustype	= BUS_SPI,
-		.manufacture_id	= PMC_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "SST",
-		.name		= "unknown SST SPI chip",
-		.bustype	= BUS_SPI,
-		.manufacture_id	= SST_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "ST",
-		.name		= "unknown ST SPI chip",
-		.bustype	= BUS_SPI,
-		.manufacture_id	= ST_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "Sanyo",
-		.name		= "unknown Sanyo SPI chip",
-		.bustype	= BUS_SPI,
-		.manufacture_id	= SANYO_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "Winbond",
-		.name		= "unknown Winbond (ex Nexcom) SPI chip",
-		.bustype	= BUS_SPI,
-		.manufacture_id	= WINBOND_NEX_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.write		= NULL,
-		.read		= NULL,
-	},
-
-	{
-		.vendor		= "Generic",
-		.name		= "unknown SPI chip (RDID)",
-		.bustype	= BUS_SPI,
-		.manufacture_id	= GENERIC_MANUF_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rdid,
-		.write		= NULL,
-	},
-
-	{
-		.vendor		= "Generic",
-		.name		= "unknown SPI chip (REMS)",
-		.bustype	= BUS_SPI,
-		.manufacture_id	= GENERIC_MANUF_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 0,
-		.page_size	= 256,
-		.tested		= TEST_BAD_PREW,
-		.probe		= probe_spi_rems,
-		.write		= NULL,
-	},
 
 	{0}
 };
diff --git a/flashchips.h b/flashchips.h
index fb17981..5be232c 100644
--- a/flashchips.h
+++ b/flashchips.h
@@ -34,13 +34,7 @@
  * SPI parts have 16-bit device IDs if they support RDID.
  */
 
-#define GENERIC_MANUF_ID	0xFFFF	/* Check if there is a vendor ID */
-#define GENERIC_DEVICE_ID	0xFFFF	/* Only match the vendor ID */
-#define SFDP_DEVICE_ID		0xFFFE
-#define PROGMANUF_ID		0xFFFE	/* dummy ID for opaque chips behind a programmer */
-#define PROGDEV_ID		0x01	/* dummy ID for opaque chips behind a programmer */
-
-#define ALLIANCE_ID		0x52	/* Alliance Semiconductor */
+#define ALLIANCE_ID		0x52		/* Alliance Semiconductor */
 #define ALLIANCE_AS29F002B	0x34
 #define ALLIANCE_AS29F002T	0xB0
 #define ALLIANCE_AS29F010	0x04
@@ -54,17 +48,17 @@
 #define ALLIANCE_AS29LV800B	0x5B
 #define ALLIANCE_AS29LV800T	0xDA
 
-#define AMD_ID			0x01	/* AMD */
+#define AMD_ID			0x01		/* AMD */
 #define AMD_AM29DL400BT		0x0C
 #define AMD_AM29DL400BB		0x0F
 #define AMD_AM29DL800BT		0x4A
 #define AMD_AM29DL800BB		0xCB
-#define AMD_AM29F002BB		0x34	/* Same as Am29F002NBB */
-#define AMD_AM29F002BT		0xB0	/* Same as Am29F002NBT */
+#define AMD_AM29F002BB		0x34		/* Same as Am29F002NBB */
+#define AMD_AM29F002BT		0xB0		/* Same as Am29F002NBT */
 #define AMD_AM29F004BB		0x7B
 #define AMD_AM29F004BT		0x77
 #define AMD_AM29F016D		0xAD
-#define AMD_AM29F010B		0x20	/* Same as Am29F010A */
+#define AMD_AM29F010B		0x20		/* Same as Am29F010A */
 #define AMD_AM29F040B		0xA4
 #define AMD_AM29F080B		0xD5
 #define AMD_AM29F200BB		0x57
@@ -82,143 +76,144 @@
 #define AMD_AM29LV008BB		0x37
 #define AMD_AM29LV008BT		0x3E
 #define AMD_AM29LV040B		0x4F
-#define AMD_AM29LV080B		0x38	/* Same as Am29LV081B */
+#define AMD_AM29LV080B		0x38		/* Same as Am29LV081B */
 #define AMD_AM29LV200BB		0xBF
 #define AMD_AM29LV200BT		0x3B
-#define AMD_AM29LV800BB		0x5B	/* Same as Am29LV800DB */
+#define AMD_AM29LV800BB		0x5B		/* Same as Am29LV800DB */
 #define AMD_AM29LV400BT		0xB9
 #define AMD_AM29LV400BB		0xBA
-#define AMD_AM29LV800BT		0xDA	/* Same as Am29LV800DT */
-
-#define AMIC_ID			0x7F37	/* AMIC */
-#define AMIC_ID_NOPREFIX	0x37	/* AMIC */
-#define AMIC_A25L05PT		0x2020
-#define AMIC_A25L05PU		0x2010
-#define AMIC_A25L10PT		0x2021
-#define AMIC_A25L10PU		0x2011
-#define AMIC_A25L20PT		0x2022
-#define AMIC_A25L20PU		0x2012
-#define AMIC_A25L40PT		0x2013	/* Datasheet says T and U have
-					   same device ID. Confirmed by
-					   hardware testing. */
-#define AMIC_A25L40PU		0x2013
-#define AMIC_A25L80P		0x2014	/* Seems that no A25L80PT exists */
-#define AMIC_A25L16PT		0x2025
-#define AMIC_A25L16PU		0x2015
-#define AMIC_A25L512		0x3010
-#define AMIC_A25L010		0x3011
-#define AMIC_A25L020		0x3012
-#define AMIC_A25L040		0x3013
-#define AMIC_A25L080		0x3014
-#define AMIC_A25L016		0x3015
-#define AMIC_A25L032		0x3016
-#define AMIC_A25LQ16		0x4015
-#define AMIC_A25LQ032		0x4016	/* Same as A25LQ32A, but the latter supports SFDP */
-#define AMIC_A25LQ64		0x4017
+#define AMD_AM29LV800BT		0xDA		/* Same as Am29LV800DT */
+
+#define AMIC_ID			0x7F, 0x37	/* AMIC */
+#define AMIC_ID_NOPREFIX	0x37		/* AMIC, without prefix */
+#define AMIC_A25L05PT		0x20, 0x20
+#define AMIC_A25L05PU		0x20, 0x10
+#define AMIC_A25L10PT		0x20, 0x21
+#define AMIC_A25L10PU		0x20, 0x11
+#define AMIC_A25L20PT		0x20, 0x22
+#define AMIC_A25L20PU		0x20, 0x12
+#define AMIC_A25L40PT		0x20, 0x13	/* Datasheet says T and U have same device ID. Confirmed by
+						 * hardware testing. */
+#define AMIC_A25L40PU		0x20, 0x13
+#define AMIC_A25L80P		0x20, 0x14	/* Seems that no A25L80PT exists */
+#define AMIC_A25L16PT		0x20, 0x25
+#define AMIC_A25L16PU		0x20, 0x15
+#define AMIC_A25L512		0x30, 0x10
+#define AMIC_A25L010		0x30, 0x11
+#define AMIC_A25L020		0x30, 0x12
+#define AMIC_A25L040		0x30, 0x13
+#define AMIC_A25L080		0x30, 0x14
+#define AMIC_A25L016		0x30, 0x15
+#define AMIC_A25L032		0x30, 0x16
+#define AMIC_A25LQ16		0x40, 0x15
+#define AMIC_A25LQ032		0x40, 0x16	/* Same as A25LQ32A, but the latter supports SFDP */
+#define AMIC_A25LQ64		0x40, 0x17
 #define AMIC_A29002B		0x0d
-#define AMIC_A29002T		0x8C	/* Same as A290021T */
+#define AMIC_A29002T		0x8C		/* Same as A290021T */
 #define AMIC_A29040B		0x86
-#define AMIC_A29400T		0xB0	/* Same as 294001T */
-#define AMIC_A29400U		0x31	/* Same as A294001U */
+#define AMIC_A29400T		0xB0		/* Same as 294001T */
+#define AMIC_A29400U		0x31		/* Same as A294001U */
 #define AMIC_A29800T		0x0E
 #define AMIC_A29800U		0x8F
-#define AMIC_A29L004T		0x34	/* Same as A29L400T */
-#define AMIC_A29L004U		0xB5	/* Same as A29L400U */
-#define AMIC_A29L008T		0x1A	/* Same as A29L800T */
-#define AMIC_A29L008U		0x9B	/* Same as A29L800U */
+#define AMIC_A29L004T		0x34		/* Same as A29L400T */
+#define AMIC_A29L004U		0xB5		/* Same as A29L400U */
+#define AMIC_A29L008T		0x1A		/* Same as A29L800T */
+#define AMIC_A29L008U		0x9B		/* Same as A29L800U */
 #define AMIC_A29L040		0x92
 #define AMIC_A49LF040A		0x9d
 
-#define ATMEL_ID		0x1F	/* Atmel (now used by Adesto) */
-#define ATMEL_AT25DF021		0x4300
-#define ATMEL_AT25DF041A	0x4401
-#define ATMEL_AT25DF081		0x4502	/* EDI 0x00. AT25DL081 has same ID + EDI 0x0100 */
-#define ATMEL_AT25DF081A	0x4501	/* Yes, 81A has a lower number than 81 */
-#define ATMEL_AT25DF161		0x4602
-#define ATMEL_AT25DF321		0x4700	/* Same as 26DF321 */
-#define ATMEL_AT25DF321A	0x4701
-#define ATMEL_AT25DF641		0x4800
-#define ATMEL_AT25DL161		0x4603	/* EDI 0x0100 */
-#define ATMEL_AT25DQ161		0x8600	/* EDI 0x0100 */
-#define ATMEL_AT25DQ321		0x8700	/* EDI 0x0100 */
-#define ATMEL_AT25F512		0x60	/* Needs AT25F_RDID. ID from PCN and actual HW. Seems to be a relabeled AT25F1024. */
-#define ATMEL_AT25F512A		0x65	/* Needs AT25F_RDID */
-#define ATMEL_AT25F512B		0x6500
-#define ATMEL_AT25F1024		0x60	/* Needs AT25F_RDID */
-#define ATMEL_AT25F2048		0x63	/* Needs AT25F_RDID */
-#define ATMEL_AT25F4096		0x64	/* Needs AT25F_RDID */
-#define ATMEL_AT25FS010		0x6601
-#define ATMEL_AT25FS040		0x6604
-#define ATMEL_AT26DF041		0x4400
-#define ATMEL_AT26DF081		0x4500	/* guessed, no datasheet available */
-#define ATMEL_AT26DF081A	0x4501
-#define ATMEL_AT26DF161		0x4600
-#define ATMEL_AT26DF161A	0x4601
-#define ATMEL_AT26DF321		0x4700	/* Same as 25DF321 */
-#define ATMEL_AT26F004		0x0400
+#define ATMEL_ID		0x1F		/* Atmel (now used by Adesto) */
+#define ATMEL_AT25DF021		0x43, 0x00
+#define ATMEL_AT25DF041A	0x44, 0x01
+#define ATMEL_AT25DF081		0x45, 0x02	/* EDI 0x00. AT25DL081 has same ID + EDI 0x01, 0x00, */
+#define ATMEL_AT25DF081A	0x45, 0x01	/* Yes, 81A has a lower number than 81 */
+#define ATMEL_AT25DF161		0x46, 0x02
+#define ATMEL_AT25DF321		0x47, 0x00	/* Same as 26DF321 */
+#define ATMEL_AT25DF321A	0x47, 0x01
+#define ATMEL_AT25DF641		0x48, 0x00
+#define ATMEL_AT25DL161		0x46, 0x03	/* EDI 0x01, 0x00, */
+#define ATMEL_AT25DQ161		0x86, 0x00	/* EDI 0x01, 0x00, */
+#define ATMEL_AT25DQ321		0x87, 0x00	/* EDI 0x01, 0x00, */
+#define ATMEL_AT25F512		0x60		/* Needs AT25F_RDID. ID from PCN and actual HW. Seems to be a
+						 * relabeled AT25F1024. */
+#define ATMEL_AT25F512A		0x65		/* Needs AT25F_RDID */
+#define ATMEL_AT25F512B		0x65, 0x00
+#define ATMEL_AT25F1024		0x60		/* Needs AT25F_RDID */
+#define ATMEL_AT25F2048		0x63		/* Needs AT25F_RDID */
+#define ATMEL_AT25F4096		0x64		/* Needs AT25F_RDID */
+#define ATMEL_AT25FS010		0x66, 0x01
+#define ATMEL_AT25FS040		0x66, 0x04
+#define ATMEL_AT26DF041		0x44, 0x00
+#define ATMEL_AT26DF081		0x45, 0x00	/* guessed, no datasheet available */
+#define ATMEL_AT26DF081A	0x45, 0x01
+#define ATMEL_AT26DF161		0x46, 0x00
+#define ATMEL_AT26DF161A	0x46, 0x01
+#define ATMEL_AT26DF321		0x47, 0x00	/* Same as 25DF321 */
+#define ATMEL_AT26F004		0x04, 0x00
 #define ATMEL_AT29C040A		0xA4
 #define ATMEL_AT29C010A		0xD5
 #define ATMEL_AT29C020		0xDA
 #define ATMEL_AT29C512		0x5D
 #define ATMEL_AT45BR3214B	/* No ID available */
-#define ATMEL_AT45CS1282	0x2920
+#define ATMEL_AT45CS1282	0x29, 0x20
 #define ATMEL_AT45D011		/* No ID available */
 #define ATMEL_AT45D021A		/* No ID available */
 #define ATMEL_AT45D041A		/* No ID available */
 #define ATMEL_AT45D081A		/* No ID available */
 #define ATMEL_AT45D161		/* No ID available */
 #define ATMEL_AT45DB011		/* No ID (opcode) available for AT45DB011, AT45DB011B */
-#define ATMEL_AT45DB011D	0x2200
+#define ATMEL_AT45DB011D	0x22, 0x00
 #define ATMEL_AT45DB021		/* No ID (opcode) available for AT45DB021, AT45DB021A, AT45DB021B */
-#define ATMEL_AT45DB021D	0x2300
-#define ATMEL_AT45DB021E	/* same as above but with EDI 0x0100 */
+#define ATMEL_AT45DB021D	0x23, 0x00
+#define ATMEL_AT45DB021E	/* same as above but with EDI 0x01, 0x00, */
 #define ATMEL_AT45DB041		/* No ID (opcode) available for AT45DB041, AT45DB041A, AT45DB041B */
-#define ATMEL_AT45DB041D	0x2400
-#define ATMEL_AT45DB041E	/* same as above but with EDI 0x0100 */
+#define ATMEL_AT45DB041D	0x24, 0x00
+#define ATMEL_AT45DB041E	/* same as above but with EDI 0x01, 0x00, */
 #define ATMEL_AT45DB081		/* No ID (opcode) available for AT45DB081, AT45DB081A, AT45DB081B */
-#define ATMEL_AT45DB081D	0x2500
-#define ATMEL_AT45DB081E	/* same as above but with EDI 0x0100 */
+#define ATMEL_AT45DB081D	0x25, 0x00
+#define ATMEL_AT45DB081E	/* same as above but with EDI 0x01, 0x00, */
 #define ATMEL_AT45DB161		/* No ID (opcode) available for AT45DB161, AT45DB161B */
-#define ATMEL_AT45DB161D	0x2600
-#define ATMEL_AT45DB161E	/* same as above but with EDI 0x0100 */
+#define ATMEL_AT45DB161D	0x26, 0x00
+#define ATMEL_AT45DB161E	/* same as above but with EDI 0x01, 0x00, */
 #define ATMEL_AT45DB321		/* No ID (opcode) available for AT45DB321, AT45DB321B */
-#define ATMEL_AT45DB321C	0x2700
-#define ATMEL_AT45DB321E	/* same as above but with EDI 0x0100 */
-#define ATMEL_AT45DB321D	0x2701 /* Buggy data sheet */
+#define ATMEL_AT45DB321C	0x27, 0x00
+#define ATMEL_AT45DB321E	/* same as above but with EDI 0x01, 0x00, */
+#define ATMEL_AT45DB321D	0x27, 0x01 /* Buggy data sheet */
 #define ATMEL_AT45DB642		/* No ID (opcode) available for AT45DB642 */
-#define ATMEL_AT45DB642D	0x2800
+#define ATMEL_AT45DB642D	0x28, 0x00
 #define ATMEL_AT49BV512		0x03
-#define ATMEL_AT49F002N		0x07	/* for AT49F002(N)  */
+#define ATMEL_AT49F002N		0x07		/* for AT49F002(N)  */
 #define ATMEL_AT49LH002		0xE9
-#define ATMEL_AT49F002NT	0x08	/* for AT49F002(N)T */
-#define ATMEL_AT49F010		0x17	/* Same as AT49HF010 */
+#define ATMEL_AT49F002NT	0x08		/* for AT49F002(N)T */
+#define ATMEL_AT49F010		0x17		/* Same as AT49HF010 */
 #define ATMEL_AT49F020		0x0B
 #define ATMEL_AT49F040		0x13
 #define ATMEL_AT49F080		0x23
 #define ATMEL_AT49F080T		0x27
 
 /* Bright Microelectronics has the same manufacturer ID as Hyundai... */
-#define BRIGHT_ID		0xAD	/* Bright Microelectronics */
+#define BRIGHT_ID		0xAD		/* Bright Microelectronics */
 #define BRIGHT_BM29F040		0x40
 #define BRIGHT_BM29F400B	0xAB
 #define BRIGHT_BM29F400T	0xAD
 
-#define CATALYST_ID		0x31	/* Catalyst */
+#define CATALYST_ID		0x31		/* Catalyst */
 #define CATALYST_CAT28F512	0xB8
 
-#define ESMT_ID			0x8C	/* Elite Semiconductor Memory Technology (ESMT) / EFST Elite Flash Storage */
-#define ESMT_F25L008A		0x2014
-#define ESMT_F25L32PA		0x2016
-#define ESMT_F25D08QA		0x2534
-#define ESMT_F25L16QA2S		0x4015
-#define ESMT_F25L32QA		0x4016
-#define ESMT_F25L32QA2S		0x4116
-#define ESMT_F25L64QA		0x4117
-#define ESMT_F25L128QA		0x4118
+#define ESMT_ID			0x8C		/* Elite Semiconductor Memory Technology (ESMT) /
+						 * EFST Elite Flash Storage */
+#define ESMT_F25L008A		0x20, 0x14
+#define ESMT_F25L32PA		0x20, 0x16
+#define ESMT_F25D08QA		0x25, 0x34
+#define ESMT_F25L16QA2S		0x40, 0x15
+#define ESMT_F25L32QA		0x40, 0x16
+#define ESMT_F25L32QA2S		0x41, 0x16
+#define ESMT_F25L64QA		0x41, 0x17
+#define ESMT_F25L128QA		0x41, 0x18
 #define ESMT_F49B002UA		0x00
 
 /*
- * EN25 chips are SPI, first byte of device ID is memory type,
+ * EN25 chips are SPI, first byte of device ID is memory type
  * second byte of device ID is log(bitsize)-9.
  * Vendor and device ID of EN29 series are both prefixed with 0x7F, which
  * is the continuation code for IDs in bank 2.
@@ -226,85 +221,85 @@
  * a collision with Mitsubishi. Mitsubishi once manufactured flash chips.
  * Let's hope they are not manufacturing SPI flash chips as well.
  */
-#define EON_ID			0x7F1C	/* EON Silicon Devices */
-#define EON_ID_NOPREFIX		0x1C	/* EON, missing 0x7F prefix */
-#define EON_EN25B05		0x2010	/* Same as P05, 2^19 kbit or 2^16 kByte */
+#define EON_ID			0x7F, 0x1C	/* EON Silicon Devices */
+#define EON_ID_NOPREFIX		0x1C		/* EON, without prefix */
+#define EON_EN25B05		0x20, 0x10	/* Same as P05, 2^19 kbit or 2^16 kByte */
 #define EON_EN25B05T		0x25
 #define EON_EN25B05B		0x95
-#define EON_EN25B10		0x2011	/* Same as P10 */
+#define EON_EN25B10		0x20, 0x11	/* Same as P10 */
 #define EON_EN25B10T		0x40
 #define EON_EN25B10B		0x30
-#define EON_EN25B20		0x2012	/* Same as P20 */
+#define EON_EN25B20		0x20, 0x12	/* Same as P20 */
 #define EON_EN25B20T		0x41
 #define EON_EN25B20B		0x31
-#define EON_EN25B40		0x2013	/* Same as P40 */
+#define EON_EN25B40		0x20, 0x13	/* Same as P40 */
 #define EON_EN25B40T		0x42
 #define EON_EN25B40B		0x32
-#define EON_EN25B80		0x2014	/* Same as P80 */
+#define EON_EN25B80		0x20, 0x14	/* Same as P80 */
 #define EON_EN25B80T		0x43
 #define EON_EN25B80B		0x33
-#define EON_EN25B16		0x2015	/* Same as P16 */
+#define EON_EN25B16		0x20, 0x15	/* Same as P16 */
 #define EON_EN25B16T		0x44
 #define EON_EN25B16B		0x34
-#define EON_EN25B32		0x2016	/* Same as P32 */
+#define EON_EN25B32		0x20, 0x16	/* Same as P32 */
 #define EON_EN25B32T		0x45
 #define EON_EN25B32B		0x35
-#define EON_EN25B64		0x2017	/* Same as P64 */
+#define EON_EN25B64		0x20, 0x17	/* Same as P64 */
 #define EON_EN25B64T		0x46
 #define EON_EN25B64B		0x36
-#define EON_EN25F05		0x3110
-#define EON_EN25F10		0x3111
-#define EON_EN25F20		0x3112
-#define EON_EN25F40		0x3113
-#define EON_EN25F80		0x3114
-#define EON_EN25F16		0x3115
-#define EON_EN25F32		0x3116
-#define EON_EN25F64		0x3117	/* guessed */
-#define EON_EN25Q40		0x3013
-#define EON_EN25Q80		0x3014
-#define EON_EN25Q16		0x3015	/* Same as EN25D16 */
-#define EON_EN25Q32		0x3016	/* Same as EN25Q32A and EN25Q32B */
-#define EON_EN25Q64		0x3017
-#define EON_EN25Q128		0x3018
-#define EON_EN25QH16		0x7015
-#define EON_EN25QH32		0x7016
-#define EON_EN25QH64		0x7017
-#define EON_EN25QH128		0x7018
-#define EON_EN25QH256		0x7019
-#define EON_EN25S10		0x3811
-#define EON_EN25S20		0x3812
-#define EON_EN25S40		0x3813
-#define EON_EN25S80		0x3814
-#define EON_EN25S16		0x3815
-#define EON_EN25S32		0x3816
-#define EON_EN25S64		0x3817
-#define EON_EN25T80		0x5114
-#define EON_EN25T16		0x5115
-#define EON_EN29F512		0x7F21
+#define EON_EN25F05		0x31, 0x10
+#define EON_EN25F10		0x31, 0x11
+#define EON_EN25F20		0x31, 0x12
+#define EON_EN25F40		0x31, 0x13
+#define EON_EN25F80		0x31, 0x14
+#define EON_EN25F16		0x31, 0x15
+#define EON_EN25F32		0x31, 0x16
+#define EON_EN25F64		0x31, 0x17	/* guessed */
+#define EON_EN25Q40		0x30, 0x13
+#define EON_EN25Q80		0x30, 0x14
+#define EON_EN25Q16		0x30, 0x15	/* Same as EN25D16 */
+#define EON_EN25Q32		0x30, 0x16	/* Same as EN25Q32A and EN25Q32B */
+#define EON_EN25Q64		0x30, 0x17
+#define EON_EN25Q128		0x30, 0x18
+#define EON_EN25QH16		0x70, 0x15
+#define EON_EN25QH32		0x70, 0x16
+#define EON_EN25QH64		0x70, 0x17
+#define EON_EN25QH128		0x70, 0x18
+#define EON_EN25QH256		0x70, 0x19
+#define EON_EN25S10		0x38, 0x11
+#define EON_EN25S20		0x38, 0x12
+#define EON_EN25S40		0x38, 0x13
+#define EON_EN25S80		0x38, 0x14
+#define EON_EN25S16		0x38, 0x15
+#define EON_EN25S32		0x38, 0x16
+#define EON_EN25S64		0x38, 0x17
+#define EON_EN25T80		0x51, 0x14
+#define EON_EN25T16		0x51, 0x15
+#define EON_EN29F512		0x7F, 0x21
 #define EON_EN29F010		0x20
-#define EON_EN29F040A		0x7F04
-#define EON_EN29LV010		0x7F6E
-#define EON_EN29LV040A		0x7F4F	/* EN29LV040(A) */
+#define EON_EN29F040A		0x7F, 0x04
+#define EON_EN29LV010		0x7F, 0x6E
+#define EON_EN29LV040A		0x7F, 0x4F	/* EN29LV040(A) */
 #define EON_EN29LV640B		0xCB
-#define EON_EN29F002T		0x7F92	/* Same as EN29F002A */
-#define EON_EN29F002B		0x7F97	/* Same as EN29F002AN */
-
-#define EXCEL_ID		0x7F7F7F7F4A	/* Excel Semiconductor Inc. (ESI) resides in bank 5 */
-#define EXCEL_ID_NOPREFIX	0x4A	/* ESI, missing 0x7F prefix */
-#define EXCEL_ES25P40		0x2013
-#define EXCEL_ES25P80		0x2014
-#define EXCEL_ES25P16		0x2015
-
-#define FIDELIX_ID		0xF8	/* Fidelix */
-#define FIDELIX_FM25M16		0x4215
-#define FIDELIX_FM25M32		0x4216
-#define FIDELIX_FM25M64		0x4217
-#define FIDELIX_FM25Q08		0x3214
-#define FIDELIX_FM25Q16		0x3215	/* Same as FM25S16 (which is apparently single I/O only) */
-#define FIDELIX_FM25Q32		0x3216
-#define FIDELIX_FM25Q64		0x3217
-
-#define FUJITSU_ID		0x04	/* Fujitsu */
+#define EON_EN29F002T		0x7F, 0x92	/* Same as EN29F002A */
+#define EON_EN29F002B		0x7F, 0x97	/* Same as EN29F002AN */
+
+#define EXCEL_ID		0x7F, 0x7F, 0x7F, 0x7F, 0x4A	/* Excel Semiconductor Inc. (ESI), in bank 5 */
+#define EXCEL_ID_NOPREFIX	0x4A		/* ESI, without prefix */
+#define EXCEL_ES25P40		0x20, 0x13
+#define EXCEL_ES25P80		0x20, 0x14
+#define EXCEL_ES25P16		0x20, 0x15
+
+#define FIDELIX_ID		0xF8		/* Fidelix */
+#define FIDELIX_FM25M16		0x42, 0x15
+#define FIDELIX_FM25M32		0x42, 0x16
+#define FIDELIX_FM25M64		0x42, 0x17
+#define FIDELIX_FM25Q08		0x32, 0x14
+#define FIDELIX_FM25Q16		0x32, 0x15	/* Same as FM25S16 (which is apparently single I/O only) */
+#define FIDELIX_FM25Q32		0x32, 0x16
+#define FIDELIX_FM25Q64		0x32, 0x17
+
+#define FUJITSU_ID		0x04		/* Fujitsu */
 #define FUJITSU_MBM29DL400BC	0x0F
 #define FUJITSU_MBM29DL400TC	0x0C
 #define FUJITSU_MBM29DL800BA	0xCB
@@ -332,173 +327,173 @@
 #define FUJITSU_MBM29LV200TC	0x3B
 #define FUJITSU_MBM29LV400BC	0xBA
 #define FUJITSU_MBM29LV400TC	0xB9
-#define FUJITSU_MBM29LV800BA	0x5B	/* Same as MBM29LV800BE */
-#define FUJITSU_MBM29LV800TA	0xDA	/* Same as MBM29LV800TE */
-#define FUJITSU_MBM29LV160BE	0x49	/* 16 b mode 0x2249 */
-#define FUJITSU_MBM29LV160TE	0xC4	/* 16 b mode 0x22C4 */
-
-#define GIGADEVICE_ID		0xC8	/* GigaDevice */
-#define GIGADEVICE_GD25T80	0x3114
-#define GIGADEVICE_GD25Q512	0x4010
-#define GIGADEVICE_GD25Q10	0x4011
-#define GIGADEVICE_GD25Q20	0x4012	/* Same as GD25QB */
-#define GIGADEVICE_GD25Q40	0x4013	/* Same as GD25QB */
-#define GIGADEVICE_GD25Q80	0x4014	/* Same as GD25Q80B (which has OTP) */
-#define GIGADEVICE_GD25Q16	0x4015	/* Same as GD25Q16B (which has OTP) */
-#define GIGADEVICE_GD25Q32	0x4016	/* Same as GD25Q32B */
-#define GIGADEVICE_GD25Q64	0x4017	/* Same as GD25Q64B */
-#define GIGADEVICE_GD25Q128	0x4018	/* GD25Q128B only? */
-#define GIGADEVICE_GD25LQ40	0x6013
-#define GIGADEVICE_GD25LQ80	0x6014
-#define GIGADEVICE_GD25LQ16	0x6015
-#define GIGADEVICE_GD25LQ32	0x6016
-#define GIGADEVICE_GD25LQ64	0x6017	/* Same as GD25LQ64B (which is faster) */
-#define GIGADEVICE_GD25LQ128	0x6018
-
-#define HYUNDAI_ID		0xAD	/* Hyundai */
-#define HYUNDAI_HY29F400T	0x23	/* Same as HY29F400AT */
-#define HYUNDAI_HY29F800B	0x58	/* Same as HY29F800AB */
+#define FUJITSU_MBM29LV800BA	0x5B		/* Same as MBM29LV800BE */
+#define FUJITSU_MBM29LV800TA	0xDA		/* Same as MBM29LV800TE */
+#define FUJITSU_MBM29LV160BE	0x49		/* 16 b mode 0x22, 0x49, */
+#define FUJITSU_MBM29LV160TE	0xC4		/* 16 b mode 0x22, 0xC4, */
+
+#define GIGADEVICE_ID		0xC8		/* GigaDevice */
+#define GIGADEVICE_GD25T80	0x31, 0x14
+#define GIGADEVICE_GD25Q512	0x40, 0x10
+#define GIGADEVICE_GD25Q10	0x40, 0x11
+#define GIGADEVICE_GD25Q20	0x40, 0x12	/* Same as GD25QB */
+#define GIGADEVICE_GD25Q40	0x40, 0x13	/* Same as GD25QB */
+#define GIGADEVICE_GD25Q80	0x40, 0x14	/* Same as GD25Q80B (which has OTP) */
+#define GIGADEVICE_GD25Q16	0x40, 0x15	/* Same as GD25Q16B (which has OTP) */
+#define GIGADEVICE_GD25Q32	0x40, 0x16	/* Same as GD25Q32B */
+#define GIGADEVICE_GD25Q64	0x40, 0x17	/* Same as GD25Q64B */
+#define GIGADEVICE_GD25Q128	0x40, 0x18	/* GD25Q128B only? */
+#define GIGADEVICE_GD25LQ40	0x60, 0x13
+#define GIGADEVICE_GD25LQ80	0x60, 0x14
+#define GIGADEVICE_GD25LQ16	0x60, 0x15
+#define GIGADEVICE_GD25LQ32	0x60, 0x16
+#define GIGADEVICE_GD25LQ64	0x60, 0x17	/* Same as GD25LQ64B (which is faster) */
+#define GIGADEVICE_GD25LQ128	0x60, 0x18
+
+#define HYUNDAI_ID		0xAD		/* Hyundai */
+#define HYUNDAI_HY29F400T	0x23		/* Same as HY29F400AT */
+#define HYUNDAI_HY29F800B	0x58		/* Same as HY29F800AB */
 #define HYUNDAI_HY29LV800B	0x5B
 #define HYUNDAI_HY29F040A	0xA4
-#define HYUNDAI_HY29F400B	0xAB	/* Same as HY29F400AB */
+#define HYUNDAI_HY29F400B	0xAB		/* Same as HY29F400AB */
 #define HYUNDAI_HY29F002B	0x34
 #define HYUNDAI_HY29F002T	0xB0
 #define HYUNDAI_HY29LV400T	0xB9
 #define HYUNDAI_HY29LV400B	0xBA
 #define HYUNDAI_HY29F080	0xD5
-#define HYUNDAI_HY29F800T	0xD6	/* Same as HY29F800AT */
+#define HYUNDAI_HY29F800T	0xD6		/* Same as HY29F800AT */
 #define HYUNDAI_HY29LV800T	0xDA
 
-#define IMT_ID			0x7F1F	/* Integrated Memory Technologies */
+#define IMT_ID			0x7F, 0x1F	/* Integrated Memory Technologies */
 #define IMT_IM29F004B		0xAE
 #define IMT_IM29F004T		0xAF
 
-#define INTEL_ID		0x89	/* Intel */
+#define INTEL_ID		0x89		/* Intel */
 #define INTEL_28F320J5		0x14
 #define INTEL_28F640J5		0x15
 #define INTEL_28F320J3		0x16
 #define INTEL_28F640J3		0x17
 #define INTEL_28F128J3		0x18
 #define INTEL_28F256J3		0x1D
-#define INTEL_28F400T		0x70	/* 28F400BV/BX/CE/CV-T */
-#define INTEL_28F400B		0x71	/* 28F400BV/BX/CE/CV-B */
-#define INTEL_28F200T		0x74	/* 28F200BL/BV/BX/CV-T */
-#define INTEL_28F200B		0x75	/* 28F200BL/BV/BX/CV-B */
-#define INTEL_28F004T		0x78	/* 28F004B5/BE/BV/BX-T */
-#define INTEL_28F004B		0x79	/* 28F004B5/BE/BV/BX-B */
-#define INTEL_28F002T		0x7C	/* 28F002BC/BL/BV/BX-T */
-#define INTEL_28F002B		0x7D	/* 28F002BL/BV/BX-B */
-#define INTEL_28F001T		0x94	/* 28F001BN/BX-T */
-#define INTEL_28F001B		0x95	/* 28F001BN/BX-B */
-#define INTEL_28F008T		0x98	/* 28F008BE/BV-T */
-#define INTEL_28F008B		0x99	/* 28F008BE/BV-B */
-#define INTEL_28F800T		0x9C	/* 28F800B5/BV/CE/CV-T */
-#define INTEL_28F800B		0x9D	/* 28F800B5/BV/CE/CV-B */
-#define INTEL_28F016SV		0xA0	/* 28F016SA/SV */
+#define INTEL_28F400T		0x70		/* 28F400BV/BX/CE/CV-T */
+#define INTEL_28F400B		0x71		/* 28F400BV/BX/CE/CV-B */
+#define INTEL_28F200T		0x74		/* 28F200BL/BV/BX/CV-T */
+#define INTEL_28F200B		0x75		/* 28F200BL/BV/BX/CV-B */
+#define INTEL_28F004T		0x78		/* 28F004B5/BE/BV/BX-T */
+#define INTEL_28F004B		0x79		/* 28F004B5/BE/BV/BX-B */
+#define INTEL_28F002T		0x7C		/* 28F002BC/BL/BV/BX-T */
+#define INTEL_28F002B		0x7D		/* 28F002BL/BV/BX-B */
+#define INTEL_28F001T		0x94		/* 28F001BN/BX-T */
+#define INTEL_28F001B		0x95		/* 28F001BN/BX-B */
+#define INTEL_28F008T		0x98		/* 28F008BE/BV-T */
+#define INTEL_28F008B		0x99		/* 28F008BE/BV-B */
+#define INTEL_28F800T		0x9C		/* 28F800B5/BV/CE/CV-T */
+#define INTEL_28F800B		0x9D		/* 28F800B5/BV/CE/CV-B */
+#define INTEL_28F016SV		0xA0		/* 28F016SA/SV */
 #define INTEL_28F008SA		0xA2
-#define INTEL_28F008S3		0xA6	/* 28F008S3/S5/SC */
-#define INTEL_28F004S3		0xA7	/* 28F008S3/S5/SC */
+#define INTEL_28F008S3		0xA6		/* 28F008S3/S5/SC */
+#define INTEL_28F004S3		0xA7		/* 28F008S3/S5/SC */
 #define INTEL_28F016XS		0xA8
-#define INTEL_28F016S3		0xAA	/* 28F016S3/S5/SC */
+#define INTEL_28F016S3		0xAA		/* 28F016S3/S5/SC */
 #define INTEL_82802AC		0xAC
 #define INTEL_82802AB		0xAD
 #define INTEL_28F010		0xB4
 #define INTEL_28F512		0xB8
 #define INTEL_28F256A		0xB9
 #define INTEL_28F020		0xBD
-#define INTEL_28F016B3T		0xD0	/* 28F016B3-T */
-#define INTEL_28F016B3B		0xD1	/* 28F016B3-B */
-#define INTEL_28F008B3T		0xD2	/* 28F008B3-T */
-#define INTEL_28F008B3B		0xD3	/* 28F008B3-B */
-#define INTEL_28F004B3T		0xD4	/* 28F004B3-T */
-#define INTEL_28F004B3B		0xD5	/* 28F004B3-B */
-#define INTEL_25F160S33B8	0x8911	/* Same as 25F016S33B8 */
-#define INTEL_25F320S33B8	0x8912
-#define INTEL_25F640S33B8	0x8913
-#define INTEL_25F160S33T8	0x8915	/* Same as 25F016S33T8 */
-#define INTEL_25F320S33T8	0x8916
-#define INTEL_25F640S33T8	0x8917
-
-#define SHARP_LH28F008SA	0xA2	/* Sharp chip, Intel Vendor ID */
-#define SHARP_LH28F008SC	0xA6	/* Sharp chip, Intel Vendor ID */
-
-#define ISSI_ID			0xD5	/* ISSI Integrated Silicon Solutions */
-
-#define MACRONIX_ID		0xC2	/* Macronix (MX) */
+#define INTEL_28F016B3T		0xD0		/* 28F016B3-T */
+#define INTEL_28F016B3B		0xD1		/* 28F016B3-B */
+#define INTEL_28F008B3T		0xD2		/* 28F008B3-T */
+#define INTEL_28F008B3B		0xD3		/* 28F008B3-B */
+#define INTEL_28F004B3T		0xD4		/* 28F004B3-T */
+#define INTEL_28F004B3B		0xD5		/* 28F004B3-B */
+#define INTEL_25F160S33B8	0x89, 0x11	/* Same as 25F016S33B8 */
+#define INTEL_25F320S33B8	0x89, 0x12
+#define INTEL_25F640S33B8	0x89, 0x13
+#define INTEL_25F160S33T8	0x89, 0x15	/* Same as 25F016S33T8 */
+#define INTEL_25F320S33T8	0x89, 0x16
+#define INTEL_25F640S33T8	0x89, 0x17
+
+#define SHARP_LH28F008SA	0xA2		/* Sharp chip, Intel Vendor ID */
+#define SHARP_LH28F008SC	0xA6		/* Sharp chip, Intel Vendor ID */
+
+#define ISSI_ID			0xD5		/* ISSI Integrated Silicon Solutions */
+
+#define MACRONIX_ID		0xC2		/* Macronix (MX) */
 /* Mask ROMs */
-#define MACRONIX_MX23L3254	0x0516
-/* MX25 chips are SPI, first byte of device ID is memory type,
+#define MACRONIX_MX23L3254	0x05, 0x16
+/* MX25 chips are SPI, first byte of device ID is memory type
  * second byte of device ID is log(bitsize)-9.
  * Generalplus SPI chips seem to be compatible with Macronix
  * and use the same set of IDs. */
-#define MACRONIX_MX25L512	0x2010	/* Same as MX25L512E, MX25V512, MX25V512C */
-#define MACRONIX_MX25L1005	0x2011	/* Same as MX25L1005C, MX25L1006E */
-#define MACRONIX_MX25L2005	0x2012	/* Same as MX25L2005C */
-#define MACRONIX_MX25L4005	0x2013	/* Same as MX25L4005A, MX25L4005C */
-#define MACRONIX_MX25L8005	0x2014	/* Same as MX25V8005; FIXME: MX25L8073E (4k 0x20) */
-#define MACRONIX_MX25L1605	0x2015	/* MX25L1605 (64k 0x20); MX25L1605A/MX25L1606E (4k 0x20, 64k 0x52); MX25L1605D/MX25L1608D/MX25L1673E (4k 0x20) */
-#define MACRONIX_MX25L3205	0x2016	/* MX25L3205, MX25L3205A (64k 0x20); MX25L3205D/MX25L3208D (4k 0x20); MX25L3206E (4k 0x20, 64k 0x52); MX25L3273E (4k 0x20, 32k 0x52) */
-#define MACRONIX_MX25L6405	0x2017	/* MX25L6405, MX25L6405D (64k 0x20); MX25L6406E/MX25L6436E (4k 0x20); MX25L6445E/MX25L6473E (4k 0x20, 32k 0x52) */
-#define MACRONIX_MX25L12805	0x2018	/* Same as MX25L12805D, MX25L12835F, MX25L12845E (the latter two support completely new ID commands) */
-#define MACRONIX_MX25L25635F	0x2019	/* Same as MX25L25639F, but the latter seems to not support REMS */
-#define MACRONIX_MX25L1635D	0x2415
-#define MACRONIX_MX25L1635E	0x2515	/* MX25L1635{E} */
-#define MACRONIX_MX25U1635E	0x2535
-#define MACRONIX_MX25U3235E	0x2536	/* Same as MX25U6435F */
-#define MACRONIX_MX25U6435E	0x2537	/* Same as MX25U6435F */
-#define MACRONIX_MX25U12835E	0x2538	/* Same as MX25U12835F */
-#define MACRONIX_MX25U25635F	0x2539
-#define MACRONIX_MX25L3235D	0x5E16	/* MX25L3225D/MX25L3235D/MX25L3237D */
+#define MACRONIX_MX25L512	0x20, 0x10	/* Same as MX25L512E, MX25V512, MX25V512C */
+#define MACRONIX_MX25L1005	0x20, 0x11	/* Same as MX25L1005C, MX25L1006E */
+#define MACRONIX_MX25L2005	0x20, 0x12	/* Same as MX25L2005C */
+#define MACRONIX_MX25L4005	0x20, 0x13	/* Same as MX25L4005A, MX25L4005C */
+#define MACRONIX_MX25L8005	0x20, 0x14	/* Same as MX25V8005; FIXME: MX25L8073E (4k 0x20) */
+#define MACRONIX_MX25L1605	0x20, 0x15	/* MX25L1605 (64k 0x20); MX25L1605A/MX25L1606E (4k 0x20, 64k 0x52); MX25L1605D/MX25L1608D/MX25L1673E (4k 0x20) */
+#define MACRONIX_MX25L3205	0x20, 0x16	/* MX25L3205, MX25L3205A (64k 0x20); MX25L3205D/MX25L3208D (4k 0x20); MX25L3206E (4k 0x20, 64k 0x52); MX25L3273E (4k 0x20, 32k 0x52) */
+#define MACRONIX_MX25L6405	0x20, 0x17	/* MX25L6405, MX25L6405D (64k 0x20); MX25L6406E/MX25L6436E (4k 0x20); MX25L6445E/MX25L6473E (4k 0x20, 32k 0x52) */
+#define MACRONIX_MX25L12805	0x20, 0x18	/* Same as MX25L12805D, MX25L12835F, MX25L12845E (the latter two support completely new ID commands) */
+#define MACRONIX_MX25L25635F	0x20, 0x19	/* Same as MX25L25639F, but the latter seems to not support REMS */
+#define MACRONIX_MX25L1635D	0x24, 0x15
+#define MACRONIX_MX25L1635E	0x25, 0x15	/* MX25L1635{E} */
+#define MACRONIX_MX25U1635E	0x25, 0x35
+#define MACRONIX_MX25U3235E	0x25, 0x36	/* Same as MX25U6435F */
+#define MACRONIX_MX25U6435E	0x25, 0x37	/* Same as MX25U6435F */
+#define MACRONIX_MX25U12835E	0x25, 0x38	/* Same as MX25U12835F */
+#define MACRONIX_MX25U25635F	0x25, 0x39
+#define MACRONIX_MX25L3235D	0x5E, 0x16	/* MX25L3225D/MX25L3235D/MX25L3237D */
 
 #define MACRONIX_MX29F001B	0x19
 #define MACRONIX_MX29F001T	0x18
-#define MACRONIX_MX29F002B	0x34	/* Same as MX29F002NB; N has reset pin n/c. */
-#define MACRONIX_MX29F002T	0xB0	/* Same as MX29F002NT; N has reset pin n/c. */
+#define MACRONIX_MX29F002B	0x34		/* Same as MX29F002NB; N has reset pin n/c. */
+#define MACRONIX_MX29F002T	0xB0		/* Same as MX29F002NT; N has reset pin n/c. */
 #define MACRONIX_MX29F004B	0x46
 #define MACRONIX_MX29F004T	0x45
-#define MACRONIX_MX29F022T	0x36	/* Same as MX29F022NT */
-#define MACRONIX_MX29F040	0xA4	/* Same as MX29F040C */
+#define MACRONIX_MX29F022T	0x36		/* Same as MX29F022NT */
+#define MACRONIX_MX29F040	0xA4		/* Same as MX29F040C */
 #define MACRONIX_MX29F080	0xD5
-#define MACRONIX_MX29F200B	0x57	/* Same as MX29F200CB */
-#define MACRONIX_MX29F200T	0x51	/* Same as MX29F200CT */
-#define MACRONIX_MX29F400B	0xAB	/* Same as MX29F400CB */
-#define MACRONIX_MX29F400T	0x23	/* Same as MX29F400CT */
+#define MACRONIX_MX29F200B	0x57		/* Same as MX29F200CB */
+#define MACRONIX_MX29F200T	0x51		/* Same as MX29F200CT */
+#define MACRONIX_MX29F400B	0xAB		/* Same as MX29F400CB */
+#define MACRONIX_MX29F400T	0x23		/* Same as MX29F400CT */
 #define MACRONIX_MX29F800B	0x58
 #define MACRONIX_MX29F800T	0xD6
 #define MACRONIX_MX29LV002CB	0x5A
 #define MACRONIX_MX29LV002CT	0x59
-#define MACRONIX_MX29LV004B	0xB6	/* Same as MX29LV004CB */
-#define MACRONIX_MX29LV004T	0xB5	/* Same as MX29LV004CT */
-#define MACRONIX_MX29LV008B	0x37	/* Same as MX29LV008CB */
-#define MACRONIX_MX29LV008T	0x3E	/* Same as MX29LV008CT */
-#define MACRONIX_MX29LV040	0x4F	/* Same as MX29LV040C */
+#define MACRONIX_MX29LV004B	0xB6		/* Same as MX29LV004CB */
+#define MACRONIX_MX29LV004T	0xB5		/* Same as MX29LV004CT */
+#define MACRONIX_MX29LV008B	0x37		/* Same as MX29LV008CB */
+#define MACRONIX_MX29LV008T	0x3E		/* Same as MX29LV008CT */
+#define MACRONIX_MX29LV040	0x4F		/* Same as MX29LV040C */
 #define MACRONIX_MX29LV081	0x38
 #define MACRONIX_MX29LV128DB	0x7A
 #define MACRONIX_MX29LV128DT	0x7E
-#define MACRONIX_MX29LV160DB	0x49	/* Same as MX29LV161DB/MX29LV160CB */
-#define MACRONIX_MX29LV160DT	0xC4	/* Same as MX29LV161DT/MX29LV160CT */
-#define MACRONIX_MX29LV320DB	0xA8	/* Same as MX29LV321DB */
-#define MACRONIX_MX29LV320DT	0xA7	/* Same as MX29LV321DT */
-#define MACRONIX_MX29LV400B	0xBA	/* Same as MX29LV400CB */
-#define MACRONIX_MX29LV400T	0xB9	/* Same as MX29LV400CT */
-#define MACRONIX_MX29LV640DB	0xCB	/* Same as MX29LV640EB */
-#define MACRONIX_MX29LV640DT	0xC9	/* Same as MX29LV640ET */
-#define MACRONIX_MX29LV800B	0x5B	/* Same as MX29LV800CB */
-#define MACRONIX_MX29LV800T	0xDA	/* Same as MX29LV800CT */
+#define MACRONIX_MX29LV160DB	0x49		/* Same as MX29LV161DB/MX29LV160CB */
+#define MACRONIX_MX29LV160DT	0xC4		/* Same as MX29LV161DT/MX29LV160CT */
+#define MACRONIX_MX29LV320DB	0xA8		/* Same as MX29LV321DB */
+#define MACRONIX_MX29LV320DT	0xA7		/* Same as MX29LV321DT */
+#define MACRONIX_MX29LV400B	0xBA		/* Same as MX29LV400CB */
+#define MACRONIX_MX29LV400T	0xB9		/* Same as MX29LV400CT */
+#define MACRONIX_MX29LV640DB	0xCB		/* Same as MX29LV640EB */
+#define MACRONIX_MX29LV640DT	0xC9		/* Same as MX29LV640ET */
+#define MACRONIX_MX29LV800B	0x5B		/* Same as MX29LV800CB */
+#define MACRONIX_MX29LV800T	0xDA		/* Same as MX29LV800CT */
 #define MACRONIX_MX29SL402CB	0xF1
 #define MACRONIX_MX29SL402CT	0x70
-#define MACRONIX_MX29SL800CB	0x6B	/* Same as MX29SL802CB */
-#define MACRONIX_MX29SL800CT	0xEA	/* Same as MX29SL802CT */
+#define MACRONIX_MX29SL800CB	0x6B		/* Same as MX29SL802CB */
+#define MACRONIX_MX29SL800CT	0xEA		/* Same as MX29SL802CT */
 
 /* Nantronics Semiconductors is listed in JEP106AJ in bank 7, so it should have 6 continuation codes in front
  * of the manufacturer ID of 0xD5. http://www.nantronicssemi.com */
-#define NANTRONICS_ID			0x7F7F7F7F7F7FD5	/* Nantronics */
-#define NANTRONICS_ID_NOPREFIX		0xD5	/* Nantronics, missing prefix */
-#define NANTRONICS_N25S10		0x3011
-#define NANTRONICS_N25S20		0x3012
-#define NANTRONICS_N25S40		0x3013
-#define NANTRONICS_N25S80		0x3014
-#define NANTRONICS_N25S16		0x3015
+#define NANTRONICS_ID			0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0xD5	/* Nantronics */
+#define NANTRONICS_ID_NOPREFIX		0xD5		/* Nantronics, missing prefix */
+#define NANTRONICS_N25S10		0x30, 0x11
+#define NANTRONICS_N25S20		0x30, 0x12
+#define NANTRONICS_N25S40		0x30, 0x13
+#define NANTRONICS_N25S80		0x30, 0x14
+#define NANTRONICS_N25S16		0x30, 0x15
 
 /*
  * Programmable Micro Corp is listed in JEP106W in bank 2, so it should
@@ -506,102 +501,102 @@
  * Apparently this name is owned by "Chingis Technology Corporation" http://www.chingistek.com which is now a
  * subsidiary of ISSI. They continue to use the PMC manufacturer ID nevertheless.
  */
-#define PMC_ID			0x7F9D	/* PMC */
-#define PMC_ID_NOPREFIX		0x9D	/* PMC, missing 0x7F prefix */
+#define PMC_ID			0x7F, 0x9D	/* PMC */
+#define PMC_ID_NOPREFIX		0x9D		/* PMC, missing 0x7F prefix */
 #define PMC_PM25LD256C		0x2F
-#define PMC_PM25LD512		0x20	/* Same as Pm25LD512C, but the latter has more locking options. */
-#define PMC_PM25LD010		0x21	/* Same as Pm25LD010C, but the latter has more locking options. */
-#define PMC_PM25LD020		0x22	/* Same as Pm25LD020C, but the latter has more locking options. */
-#define PMC_PM25LV512		0x7B	/* Same as Pm25LV512A */
-#define PMC_PM25LV010		0x7C	/* Same as Pm25LV010A, but the former does not support RDID but RES3 only. */
+#define PMC_PM25LD512		0x20		/* Same as Pm25LD512C, but the latter has more locking options. */
+#define PMC_PM25LD010		0x21		/* Same as Pm25LD010C, but the latter has more locking options. */
+#define PMC_PM25LD020		0x22		/* Same as Pm25LD020C, but the latter has more locking options. */
+#define PMC_PM25LV512		0x7B		/* Same as Pm25LV512A */
+#define PMC_PM25LV010		0x7C		/* Same as Pm25LV010A, but the former does not support RDID but RES3 only. */
 #define PMC_PM25LV020		0x7D
-#define PMC_PM25LV040		0x7E	/* Same as PM25LD040(C), but the latter supports more features. */
+#define PMC_PM25LV040		0x7E		/* Same as PM25LD040(C), but the latter supports more features. */
 #define PMC_PM25LV080B		0x13
 #define PMC_PM25LV016B		0x14
 #define PMC_PM29F002T		0x1D
 #define PMC_PM29F002B		0x2D
-#define PMC_PM39LV512		0x1B	/* Same as IS39LV512 */
-#define PMC_PM39F010		0x1C	/* Same as Pm39LV010, IS39LV010 */
+#define PMC_PM39LV512		0x1B		/* Same as IS39LV512 */
+#define PMC_PM39F010		0x1C		/* Same as Pm39LV010, IS39LV010 */
 #define PMC_PM39LV020		0x3D
-#define PMC_PM39LV040		0x3E	/* Same as IS39LV040 */
+#define PMC_PM39LV040		0x3E		/* Same as IS39LV040 */
 #define PMC_PM39F020		0x4D
 #define PMC_PM39F040		0x4E
 #define PMC_PM49FL002		0x6D
 #define PMC_PM49FL004		0x6E
 
 /* 
- * The Sanyo chip found so far uses SPI, first byte is manufacture code,
- * second byte is the device code,
+ * The Sanyo chip found so far uses SPI, first byte is manufacture code
+ * second byte is the device code
  * third byte is a dummy byte.
  */
-#define SANYO_ID		0x62    /* Sanyo */
-#define SANYO_LE25FW203A	0x1600
-#define SANYO_LE25FW403A	0x1100
+#define SANYO_ID		0x62		/* Sanyo */
+#define SANYO_LE25FW203A	0x16, 0x00
+#define SANYO_LE25FW403A	0x11, 0x00
 #define SANYO_LE25FW106		0x15
-#define SANYO_LE25FW406		0x07	/* RES2 */
-#define SANYO_LE25FW418A	0x10	/* RES2 and some weird 1 byte RDID variant */
-#define SANYO_LE25FW406A	0x1A	/* RES2, no datasheet */
-#define SANYO_LE25FU406B	0x1E	/* LE25FW418A without HD_READ mode option variant */
-#define SANYO_LE25FW806		0x26	/* RES2 and some weird 1 byte RDID variant */
-#define SANYO_LE25FW808		0x20	/* RES2 and some weird 1 byte RDID variant */
-
-#define SHARP_ID		0xB0	/* Sharp */
+#define SANYO_LE25FW406		0x07		/* RES2 */
+#define SANYO_LE25FW418A	0x10		/* RES2 and some weird 1 byte RDID variant */
+#define SANYO_LE25FW406A	0x1A		/* RES2, no datasheet */
+#define SANYO_LE25FU406B	0x1E		/* LE25FW418A without HD_READ mode option variant */
+#define SANYO_LE25FW806		0x26		/* RES2 and some weird 1 byte RDID variant */
+#define SANYO_LE25FW808		0x20		/* RES2 and some weird 1 byte RDID variant */
+
+#define SHARP_ID		0xB0		/* Sharp */
 #define SHARP_LH28F008BJ__PT	0xEC
 #define SHARP_LH28F008BJ__PB	0xED
 #define SHARP_LH28F800BV__BTL	0x4B
 #define SHARP_LH28F800BV__BV	0x4D
 #define SHARP_LH28F800BV__TV	0x4C
-#define SHARP_LHF00L02		0xC9	/* Same as LHF00L06/LHF00L07 */
-#define SHARP_LHF00L04		0xCF	/* Same as LHF00L03/LHF00L05 */
+#define SHARP_LHF00L02		0xC9		/* Same as LHF00L06/LHF00L07 */
+#define SHARP_LHF00L04		0xCF		/* Same as LHF00L03/LHF00L05 */
 
 /*
  * Spansion was previously a joint venture of AMD and Fujitsu.
  * S25 chips are SPI. The first device ID byte is memory type and
  * the second device ID byte is memory capacity.
  */
-#define SPANSION_ID		0x01	/* Spansion, same ID as AMD */
-#define SPANSION_S25FL004A	0x0212
-#define SPANSION_S25FL008A	0x0213
-#define SPANSION_S25FL016A	0x0214
-#define SPANSION_S25FL032A	0x0215	/* Same as S25FL032P, but the latter supports EDI and CFI */
-#define SPANSION_S25FL064A	0x0216	/* Same as S25FL064P, but the latter supports EDI and CFI */
-#define SPANSION_S25FL128	0x2018
-#define SPANSION_S25FL256	0x0219
-#define SPANSION_S25FL512	0x0220
-#define SPANSION_S25FL204	0x4013
-#define SPANSION_S25FL208	0x4014
-#define SPANSION_S25FL216	0x4015	/* Same as S25FL216K, but the latter supports OTP, 3 status regs, quad I/O, SFDP etc. */
-#define SPANSION_S25FL132K	0x4016
-#define SPANSION_S25FL164K	0x4017
+#define SPANSION_ID		0x01		/* Spansion, same ID as AMD */
+#define SPANSION_S25FL004A	0x02, 0x12
+#define SPANSION_S25FL008A	0x02, 0x13
+#define SPANSION_S25FL016A	0x02, 0x14
+#define SPANSION_S25FL032A	0x02, 0x15	/* Same as S25FL032P, but the latter supports EDI and CFI */
+#define SPANSION_S25FL064A	0x02, 0x16	/* Same as S25FL064P, but the latter supports EDI and CFI */
+#define SPANSION_S25FL128	0x20, 0x18
+#define SPANSION_S25FL256	0x02, 0x19
+#define SPANSION_S25FL512	0x02, 0x20
+#define SPANSION_S25FL204	0x40, 0x13
+#define SPANSION_S25FL208	0x40, 0x14
+#define SPANSION_S25FL216	0x40, 0x15	/* Same as S25FL216K, but the latter supports OTP, 3 status regs, quad I/O, SFDP etc. */
+#define SPANSION_S25FL132K	0x40, 0x16
+#define SPANSION_S25FL164K	0x40, 0x17
 
 /*
  * SST25 chips are SPI, first byte of device ID is memory type, second
  * byte of device ID is related to log(bitsize) at least for some chips.
  */
-#define SST_ID			0xBF	/* SST */
-#define SST_SST25LF020_REMS	0x43	/* REMS or RES opcode */
-#define SST_SST25WF512		0x2501
-#define SST_SST25WF010		0x2502
-#define SST_SST25WF020		0x2503
-#define SST_SST25WF040		0x2504
-#define SST_SST25WF080		0x2505
-#define SST_SST25VF512A_REMS	0x48	/* REMS or RES opcode */
-#define SST_SST25VF010_REMS	0x49	/* REMS or RES opcode */
-#define SST_SST25VF020_REMS	0x43	/* REMS or RES opcode, same as SST25LF020A */
-#define SST_SST25VF020B		0x258C
-#define SST_SST25VF040_REMS	0x44	/* REMS or RES opcode, same as SST25LF040A */
-#define SST_SST25VF040B		0x258D
-#define SST_SST25VF040B_REMS	0x8D	/* REMS or RES opcode */
-#define SST_SST25VF080_REMS	0x80	/* REMS or RES opcode, same as SST25LF080A */
-#define SST_SST25VF080B		0x258E
-#define SST_SST25VF080B_REMS	0x8E	/* REMS or RES opcode */
-#define SST_SST25VF016B		0x2541
-#define SST_SST25VF032B		0x254A
-#define SST_SST25VF032B_REMS	0x4A	/* REMS or RES opcode */
-#define SST_SST25VF064C		0x254B
-#define SST_SST26VF016		0x2601
-#define SST_SST26VF032		0x2602
-#define SST_SST26VF064B		0x2643
+#define SST_ID			0xBF		/* SST */
+#define SST_SST25LF020_REMS	0x43		/* REMS or RES opcode */
+#define SST_SST25WF512		0x25, 0x01
+#define SST_SST25WF010		0x25, 0x02
+#define SST_SST25WF020		0x25, 0x03
+#define SST_SST25WF040		0x25, 0x04
+#define SST_SST25WF080		0x25, 0x05
+#define SST_SST25VF512A_REMS	0x48		/* REMS or RES opcode */
+#define SST_SST25VF010_REMS	0x49		/* REMS or RES opcode */
+#define SST_SST25VF020_REMS	0x43		/* REMS or RES opcode, same as SST25LF020A */
+#define SST_SST25VF020B		0x25, 0x8C
+#define SST_SST25VF040_REMS	0x44		/* REMS or RES opcode, same as SST25LF040A */
+#define SST_SST25VF040B		0x25, 0x8D
+#define SST_SST25VF040B_REMS	0x8D		/* REMS or RES opcode */
+#define SST_SST25VF080_REMS	0x80		/* REMS or RES opcode, same as SST25LF080A */
+#define SST_SST25VF080B		0x25, 0x8E
+#define SST_SST25VF080B_REMS	0x8E		/* REMS or RES opcode */
+#define SST_SST25VF016B		0x25, 0x41
+#define SST_SST25VF032B		0x25, 0x4A
+#define SST_SST25VF032B_REMS	0x4A		/* REMS or RES opcode */
+#define SST_SST25VF064C		0x25, 0x4B
+#define SST_SST26VF016		0x26, 0x01
+#define SST_SST26VF032		0x26, 0x02
+#define SST_SST26VF064B		0x26, 0x43
 #define SST_SST27SF512		0xA4
 #define SST_SST27SF010		0xA5
 #define SST_SST27SF020		0xA6
@@ -610,22 +605,22 @@
 #define SST_SST28SF040		0x04
 #define SST_SST29EE512		0x5D
 #define SST_SST29EE010		0x07
-#define SST_SST29LE010		0x08	/* Same as SST29VE010 */
-#define SST_SST29EE020A		0x10	/* Same as SST29EE020 */
-#define SST_SST29LE020		0x12	/* Same as SST29VE020 */
+#define SST_SST29LE010		0x08		/* Same as SST29VE010 */
+#define SST_SST29EE020A		0x10		/* Same as SST29EE020 */
+#define SST_SST29LE020		0x12		/* Same as SST29VE020 */
 #define SST_SST29SF020		0x24
 #define SST_SST29VF020		0x25
 #define SST_SST29SF040		0x13
 #define SST_SST29VF040		0x14
 #define SST_SST39SF512		0xB4
 #define SST_SST39SF010		0xB5
-#define SST_SST39SF020		0xB6	/* Same as 39SF020A */
+#define SST_SST39SF020		0xB6		/* Same as 39SF020A */
 #define SST_SST39SF040		0xB7
 #define SST_SST39VF512		0xD4
 #define SST_SST39VF010		0xD5
-#define SST_SST39VF020		0xD6	/* Same as 39LF020 */
-#define SST_SST39VF040		0xD7	/* Same as 39LF040 */
-#define SST_SST39VF080		0xD8	/* Same as 39LF080/39VF080/39VF088 */
+#define SST_SST39VF020		0xD6		/* Same as 39LF020 */
+#define SST_SST39VF040		0xD7		/* Same as 39LF040 */
+#define SST_SST39VF080		0xD8		/* Same as 39LF080/39VF080/39VF088 */
 #define SST_SST49LF040B		0x50
 #define SST_SST49LF040		0x51
 #define SST_SST49LF020		0x61
@@ -634,7 +629,7 @@
 #define SST_SST49LF080A		0x5B
 #define SST_SST49LF002A		0x57
 #define SST_SST49LF003A		0x1B
-#define SST_SST49LF004A		0x60	/* Same as 49LF004B */
+#define SST_SST49LF004A		0x60		/* Same as 49LF004B */
 #define SST_SST49LF008A		0x5A
 #define SST_SST49LF004C		0x54
 #define SST_SST49LF008C		0x59
@@ -645,34 +640,35 @@
  * ST25P chips are SPI, first byte of device ID is memory type, second
  * byte of device ID is related to log(bitsize) at least for some chips.
  */
-#define ST_ID			0x20	/* ST / SGS/Thomson / Numonyx (later acquired by Micron) */
-#define ST_M25P05A		0x2010
-#define ST_M25P05_RES		0x10	/* Same code as M25P10. */
-#define ST_M25P10A		0x2011
-#define ST_M25P10_RES		0x10	/* Same code as M25P05. */
-#define ST_M25P20		0x2012
+#define ST_ID			0x20		/* ST / SGS/Thomson / Numonyx (later acquired by Micron) */
+#define ST_M25P05A		0x20, 0x10
+#define ST_M25P05A_RES		0x05
+#define ST_M25P05_RES		0x10		/* Same code as M25P10. */
+#define ST_M25P10A		0x20, 0x11
+#define ST_M25P10_RES		0x10		/* Same code as M25P05. */
+#define ST_M25P20		0x20, 0x12, 0x10
 #define ST_M25P20_RES		0x11
-#define ST_M25P40		0x2013
+#define ST_M25P40		0x20, 0x13, 0x10
 #define ST_M25P40_RES		0x12
-#define ST_M25P80		0x2014
-#define ST_M25P16		0x2015
-#define ST_M25P32		0x2016
-#define ST_M25P64		0x2017
-#define ST_M25P128		0x2018
-#define ST_M45PE10		0x4011
-#define ST_M45PE20		0x4012
-#define ST_M45PE40		0x4013
-#define ST_M45PE80		0x4014
-#define ST_M45PE16		0x4015
-#define ST_M25PX80		0x7114
-#define ST_M25PX16		0x7115
-#define ST_M25PX32		0x7116
-#define ST_M25PX64		0x7117
-#define ST_M25PE10		0x8011
-#define ST_M25PE20		0x8012
-#define ST_M25PE40		0x8013
-#define ST_M25PE80		0x8014
-#define ST_M25PE16		0x8015
+#define ST_M25P80		0x20, 0x14, 0x10
+#define ST_M25P16		0x20, 0x15
+#define ST_M25P32		0x20, 0x16
+#define ST_M25P64		0x20, 0x17
+#define ST_M25P128		0x20, 0x18
+#define ST_M45PE10		0x40, 0x11
+#define ST_M45PE20		0x40, 0x12
+#define ST_M45PE40		0x40, 0x13
+#define ST_M45PE80		0x40, 0x14
+#define ST_M45PE16		0x40, 0x15
+#define ST_M25PX80		0x71, 0x14
+#define ST_M25PX16		0x71, 0x15
+#define ST_M25PX32		0x71, 0x16
+#define ST_M25PX64		0x71, 0x17
+#define ST_M25PE10		0x80, 0x11
+#define ST_M25PE20		0x80, 0x12
+#define ST_M25PE40		0x80, 0x13
+#define ST_M25PE80		0x80, 0x14
+#define ST_M25PE16		0x80, 0x15
 #define ST_M50FLW040A		0x08
 #define ST_M50FLW040B		0x28
 #define ST_M50FLW080A		0x80
@@ -683,33 +679,33 @@
 #define ST_M50FW016		0x2E
 #define ST_M50LPW080		0x2F
 #define ST_M50LPW116		0x30
-#define ST_M29F002B		0x34	/* Same as M29F002BB */
-#define ST_M29F002T		0xB0	/* Same as M29F002BT/M29F002NT/M29F002BNT */
-#define ST_M29F040B		0xE2	/* Same as M29F040 */
+#define ST_M29F002B		0x34		/* Same as M29F002BB */
+#define ST_M29F002T		0xB0		/* Same as M29F002BT/M29F002NT/M29F002BNT */
+#define ST_M29F040B		0xE2		/* Same as M29F040 */
 #define ST_M29F080		0xF1
 #define ST_M29F200BT		0xD3
 #define ST_M29F200BB		0xD4
-#define ST_M29F400BT		0xD5	/* Same as M29F400T */
-#define ST_M29F400BB		0xD6	/* Same as M29F400B */
+#define ST_M29F400BT		0xD5		/* Same as M29F400T */
+#define ST_M29F400BB		0xD6		/* Same as M29F400B */
 #define ST_M29F800DB		0x58
 #define ST_M29F800DT		0xEC
 #define ST_M29W010B		0x23
 #define ST_M29W040B		0xE3
 #define ST_M29W512B		0x27
-#define ST_N25Q016__1E		0xBB15	/* N25Q016, 1.8V, (uniform sectors expected) */
-#define ST_N25Q032__3E		0xBA16	/* N25Q032, 3.0V, (uniform sectors expected) */
-#define ST_N25Q032__1E		0xBB16	/* N25Q032, 1.8V, (uniform sectors expected) */
-#define ST_N25Q064__3E		0xBA17	/* N25Q064, 3.0V, (uniform sectors expected) */
-#define ST_N25Q064__1E		0xBB17	/* N25Q064, 1.8V, (uniform sectors expected) */
-#define ST_N25Q128__3E		0xBA18	/* N25Q128, 3.0V, (uniform sectors expected) */
-#define ST_N25Q128__1E		0xBB18	/* N25Q128, 1.8V, (uniform sectors expected) */
-#define ST_N25Q256__3E		0xBA19	/* N25Q256, 3.0V, (uniform sectors expected) */
-#define ST_N25Q256__1E		0xBB19	/* N25Q256, 1.8V, (uniform sectors expected) */
-#define ST_N25Q512__3E		0xBA20	/* N25Q512, 3.0V, (uniform sectors expected) */
-#define ST_N25Q512__1E		0xBB20	/* N25Q512, 1.8V, (uniform sectors expected) */
-#define ST_N25Q00A__3E		0xBA21	/* N25Q00A, 3.0V, (uniform sectors expected) */
-
-#define SYNCMOS_MVC_ID		0x40	/* SyncMOS (SM) and Mosel Vitelic Corporation (MVC) */
+#define ST_N25Q016__1E		0xBB, 0x15	/* N25Q016, 1.8V, (uniform sectors expected) */
+#define ST_N25Q032__3E		0xBA, 0x16	/* N25Q032, 3.0V, (uniform sectors expected) */
+#define ST_N25Q032__1E		0xBB, 0x16	/* N25Q032, 1.8V, (uniform sectors expected) */
+#define ST_N25Q064__3E		0xBA, 0x17	/* N25Q064, 3.0V, (uniform sectors expected) */
+#define ST_N25Q064__1E		0xBB, 0x17	/* N25Q064, 1.8V, (uniform sectors expected) */
+#define ST_N25Q128__3E		0xBA, 0x18	/* N25Q128, 3.0V, (uniform sectors expected) */
+#define ST_N25Q128__1E		0xBB, 0x18	/* N25Q128, 1.8V, (uniform sectors expected) */
+#define ST_N25Q256__3E		0xBA, 0x19	/* N25Q256, 3.0V, (uniform sectors expected) */
+#define ST_N25Q256__1E		0xBB, 0x19	/* N25Q256, 1.8V, (uniform sectors expected) */
+#define ST_N25Q512__3E		0xBA, 0x20	/* N25Q512, 3.0V, (uniform sectors expected) */
+#define ST_N25Q512__1E		0xBB, 0x20	/* N25Q512, 1.8V, (uniform sectors expected) */
+#define ST_N25Q00A__3E		0xBA, 0x21	/* N25Q00A, 3.0V, (uniform sectors expected) */
+
+#define SYNCMOS_MVC_ID		0x40		/* SyncMOS (SM) and Mosel Vitelic Corporation (MVC) */
 #define MVC_V29C51000T		0x00
 #define MVC_V29C51400T		0x13
 #define MVC_V29LC51000		0x20
@@ -717,17 +713,17 @@
 #define MVC_V29LC51002		0x82
 #define MVC_V29C51000B		0xA0
 #define MVC_V29C51400B		0xB3
-#define SM_MVC_29C51001T	0x01	/* Identical chips: {F,S,V}29C51001T */
-#define SM_MVC_29C51002T	0x02	/* Identical chips: {F,S,V}29C51002T */
-#define SM_MVC_29C51004T	0x03	/* Identical chips: {F,S,V}29C51004T */
-#define SM_MVC_29C31004T	0x63	/* Identical chips: {S,V}29C31004T */
-#define SM_MVC_29C31004B	0x73	/* Identical chips: {S,V}29C31004B */
-#define SM_MVC_29C51001B	0xA1	/* Identical chips: {F,S,V}29C51001B */
-#define SM_MVC_29C51002B	0xA2	/* Identical chips: {F,S,V}29C51002B */
-#define SM_MVC_29C51004B	0xA3	/* Identical chips: {F,S,V}29C51004B */
-
-#define TI_ID			0x97	/* Texas Instruments */
-#define TI_OLD_ID		0x01	/* TI chips from last century */
+#define SM_MVC_29C51001T	0x01		/* Identical chips: {F,S,V}29C51001T */
+#define SM_MVC_29C51002T	0x02		/* Identical chips: {F,S,V}29C51002T */
+#define SM_MVC_29C51004T	0x03		/* Identical chips: {F,S,V}29C51004T */
+#define SM_MVC_29C31004T	0x63		/* Identical chips: {S,V}29C31004T */
+#define SM_MVC_29C31004B	0x73		/* Identical chips: {S,V}29C31004B */
+#define SM_MVC_29C51001B	0xA1		/* Identical chips: {F,S,V}29C51001B */
+#define SM_MVC_29C51002B	0xA2		/* Identical chips: {F,S,V}29C51002B */
+#define SM_MVC_29C51004B	0xA3		/* Identical chips: {F,S,V}29C51004B */
+
+#define TI_ID			0x97		/* Texas Instruments */
+#define TI_OLD_ID		0x01		/* TI chips from last century */
 #define TI_TMS29F002RT		0xB0
 #define TI_TMS29F002RB		0x34
 
@@ -735,44 +731,44 @@
  * W25X chips are SPI, first byte of device ID is memory type, second
  * byte of device ID is related to log(bitsize).
  */
-#define WINBOND_NEX_ID		0xEF	/* Winbond (ex Nexcom) serial flashes */
-#define WINBOND_NEX_W25X10	0x3011
-#define WINBOND_NEX_W25X20	0x3012
-#define WINBOND_NEX_W25X40	0x3013
-#define WINBOND_NEX_W25X80	0x3014
-#define WINBOND_NEX_W25X16	0x3015
-#define WINBOND_NEX_W25X32	0x3016
-#define WINBOND_NEX_W25X64	0x3017
-#define WINBOND_NEX_W25Q40_V	0x4013	/* W25Q40BV; W25Q40BL (2.3-3.6V) */
-#define WINBOND_NEX_W25Q80_V	0x4014	/* W25Q80BV */
-#define WINBOND_NEX_W25Q16_V	0x4015	/* W25Q16CV; W25Q16DV */
-#define WINBOND_NEX_W25Q32_V	0x4016	/* W25Q32BV; W25Q32FV in SPI mode (default) */
-#define WINBOND_NEX_W25Q64_V	0x4017	/* W25Q64BV, W25Q64CV; W25Q64FV in SPI mode (default) */
-#define WINBOND_NEX_W25Q128_V	0x4018	/* W25Q128BV; W25Q128FV in SPI mode (default) */
-#define WINBOND_NEX_W25Q256_V	0x4019	/* W25Q256FV */
-#define WINBOND_NEX_W25Q20_W	0x5012	/* W25Q20BW */
-#define WINBOND_NEX_W25Q40_W	0x5013	/* W25Q40BW */
-#define WINBOND_NEX_W25Q80_W	0x5014	/* W25Q80BW */
-#define WINBOND_NEX_W25Q16_W	0x6015	/* W25Q16DW */
-#define WINBOND_NEX_W25Q32_W	0x6016	/* W25Q32DW; W25Q32FV in QPI mode */
-#define WINBOND_NEX_W25Q64_W	0x6017	/* W25Q64DW; W25Q64FV in QPI mode */
-#define WINBOND_NEX_W25Q128_W	0x6018	/* (No W version known) W25Q128FV in QPI mode */
-
-#define WINBOND_ID		0xDA	/* Winbond */
+#define WINBOND_NEX_ID		0xEF		/* Winbond (ex Nexcom) serial flashes */
+#define WINBOND_NEX_W25X10	0x30, 0x11
+#define WINBOND_NEX_W25X20	0x30, 0x12
+#define WINBOND_NEX_W25X40	0x30, 0x13
+#define WINBOND_NEX_W25X80	0x30, 0x14
+#define WINBOND_NEX_W25X16	0x30, 0x15
+#define WINBOND_NEX_W25X32	0x30, 0x16
+#define WINBOND_NEX_W25X64	0x30, 0x17
+#define WINBOND_NEX_W25Q40_V	0x40, 0x13	/* W25Q40BV; W25Q40BL (2.3-3.6V) */
+#define WINBOND_NEX_W25Q80_V	0x40, 0x14	/* W25Q80BV */
+#define WINBOND_NEX_W25Q16_V	0x40, 0x15	/* W25Q16CV; W25Q16DV */
+#define WINBOND_NEX_W25Q32_V	0x40, 0x16	/* W25Q32BV; W25Q32FV in SPI mode (default) */
+#define WINBOND_NEX_W25Q64_V	0x40, 0x17	/* W25Q64BV, W25Q64CV; W25Q64FV in SPI mode (default) */
+#define WINBOND_NEX_W25Q128_V	0x40, 0x18	/* W25Q128BV; W25Q128FV in SPI mode (default) */
+#define WINBOND_NEX_W25Q256_V	0x40, 0x19	/* W25Q256FV */
+#define WINBOND_NEX_W25Q20_W	0x50, 0x12	/* W25Q20BW */
+#define WINBOND_NEX_W25Q40_W	0x50, 0x13	/* W25Q40BW */
+#define WINBOND_NEX_W25Q80_W	0x50, 0x14	/* W25Q80BW */
+#define WINBOND_NEX_W25Q16_W	0x60, 0x15	/* W25Q16DW */
+#define WINBOND_NEX_W25Q32_W	0x60, 0x16	/* W25Q32DW; W25Q32FV in QPI mode */
+#define WINBOND_NEX_W25Q64_W	0x60, 0x17	/* W25Q64DW; W25Q64FV in QPI mode */
+#define WINBOND_NEX_W25Q128_W	0x60, 0x18	/* (No W version known) W25Q128FV in QPI mode */
+
+#define WINBOND_ID		0xDA		/* Winbond */
 #define WINBOND_W19B160BB	0x49
 #define WINBOND_W19B160BT	0xC4
-#define WINBOND_W19B320SB	0x2A    /* Same as W19L320SB */
-#define WINBOND_W19B320ST	0xBA    /* Same as W19L320ST */
+#define WINBOND_W19B320SB	0x2A		/* Same as W19L320SB */
+#define WINBOND_W19B320ST	0xBA		/* Same as W19L320ST */
 #define WINBOND_W19B322MB	0x92
 #define WINBOND_W19B322MT	0x10
 #define WINBOND_W19B323MB	0x94
 #define WINBOND_W19B323MT	0x13
 #define WINBOND_W19B324MB	0x97
 #define WINBOND_W19B324MT	0x16
-#define WINBOND_W29C010		0xC1    /* Same as W29C010M, W29C011A, W29EE011, W29EE012, and ASD AE29F1008 */
-#define WINBOND_W29C020		0x45    /* Same as W29C020C, W29C022 and ASD AE29F2008 */
-#define WINBOND_W29C040		0x46    /* Same as W29C040P */
-#define WINBOND_W29C512A	0xC8    /* Same as W29EE512 */
+#define WINBOND_W29C010		0xC1		/* Same as W29C010M, W29C011A, W29EE011, W29EE012, and ASD AE29F1008 */
+#define WINBOND_W29C020		0x45		/* Same as W29C020C, W29C022 and ASD AE29F2008 */
+#define WINBOND_W29C040		0x46		/* Same as W29C040P */
+#define WINBOND_W29C512A	0xC8		/* Same as W29EE512 */
 #define WINBOND_W39F010		0xA1
 #define WINBOND_W39L010		0x31
 #define WINBOND_W39L020		0xB5
@@ -781,13 +777,13 @@
 #define WINBOND_W39L512		0x38
 #define WINBOND_W39V040A	0x3D
 #define WINBOND_W39V040FA	0x34
-#define WINBOND_W39V040B	0x54    /* Same as W39V040FB */
-#define WINBOND_W39V040C	0x50    /* Same as W39V040FC */
+#define WINBOND_W39V040B	0x54		/* Same as W39V040FB */
+#define WINBOND_W39V040C	0x50		/* Same as W39V040FC */
 #define WINBOND_W39V080A	0xD0
 #define WINBOND_W39V080FA	0xD3
-#define WINBOND_W39V080FA_DM	0x93    /* W39V080FA dual mode */
-#define WINBOND_W49F002		0x25    /* Same as W49F002B */
-#define WINBOND_W49F002U	0x0B    /* Same as W49F002N and ASD AE49F2008 */
+#define WINBOND_W39V080FA_DM	0x93		/* W39V080FA dual mode */
+#define WINBOND_W49F002		0x25		/* Same as W49F002B */
+#define WINBOND_W49F002U	0x0B		/* Same as W49F002N and ASD AE49F2008 */
 #define WINBOND_W49F020		0x8C
 #define WINBOND_W49V002A	0xB0
 #define WINBOND_W49V002FA	0x32
diff --git a/flashrom.c b/flashrom.c
index e613768..e7c5781 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -36,7 +36,7 @@
 #include <sys/utsname.h>
 #endif
 #include "flash.h"
-#include "flashchips.h"
+#include "chipdrivers.h"
 #include "programmer.h"
 #include "hwaccess.h"
 
@@ -364,6 +364,12 @@ static bool all_skipped = true;
 
 static int check_block_eraser(const struct flashctx *flash, int k, int log);
 
+int shutdown_free(void *data)
+{
+	free(data);
+	return 0;
+}
+
 /* Register a function to be executed on programmer shutdown.
  * The advantage over atexit() is that you can supply a void pointer which will
  * be used as parameter to the registered function upon programmer shutdown.
@@ -1085,107 +1091,302 @@ int map_flash(struct flashctx *flash)
 	return 0;
 }
 
-int probe_flash(struct registered_programmer *pgm, int startchip, struct flashctx *flash, int force)
+static probe probes[] = {
+	{ &probe_spi_rdid,			BUS_SPI, "RDID"},
+	{ &probe_spi_res,			BUS_SPI, "RES"},
+	{ &probe_spi_rems,			BUS_SPI, "REMS"},
+	{ &probe_spi_at25f,			BUS_SPI, "AT25F"},
+	{ &probe_spi_at45db,			BUS_SPI, "AT45DB"},
+	{ &probe_jedec_longreset,		BUS_PARALLEL, "JEDEC long", 64, 512, 1},
+	{ &probe_jedec_shortreset_full,		BUS_PARALLEL | BUS_LPC | BUS_FWH, "JEDEC short full", 64, 1024, 1},
+	{ &probe_jedec_shortreset_full_384,	BUS_FWH, "JEDEC short full 384k", 384, 384}, // workaround for SST49LF003A/B
+	{ &probe_jedec_shortreset_aaa,		BUS_PARALLEL, "JEDEC short AAA", 256, 256},
+	{ &probe_jedec_shortreset_2aa,		BUS_PARALLEL, "JEDEC short 2AA", 64, 2048, 1},
+	{ &probe_82802ab_unshifted,		BUS_PARALLEL | BUS_LPC | BUS_FWH, "82802AB", 256, 2048, 1},
+	{ &probe_82802ab_shifted,		BUS_PARALLEL | BUS_LPC | BUS_FWH, "82802AB shifted", 256, 2048, 1},
+	{ &probe_w29ee011,			BUS_PARALLEL , "W29EE011", 128, 128},
+	{ &probe_en29lv640b,			BUS_PARALLEL , "EN29LV640B", 8192, 8192},
+	{ &probe_m29f400bt,			BUS_PARALLEL , "M29F400BT", 512, 2048, 2},
+};
+
+int probe_allsizes(struct flashctx *flash, struct probe_res *res, unsigned int res_len, const struct probe *p)
 {
-	const struct flashchip *chip;
-	uint32_t size;
-	enum chipbustype buses_common;
-	char *tmp;
+	uint16_t size_min = p->size_min;
+	uint16_t size_max = p->size_max;
+	uint16_t size_step = p->size_step;
+	if (res_len == 0 || size_min == 0)
+		return -1;
 
-	for (chip = flashchips + startchip; chip && chip->name; chip++) {
-		if (chip_to_probe && strcmp(chip->name, chip_to_probe) != 0)
-			continue;
-		buses_common = pgm->buses_supported & chip->bustype;
-		if (!buses_common)
+	if (size_step == 0) {
+		size_step = 1;
+		msg_cspew("%s: setting step size to 1.\n", __func__);
+	}
+
+	if (size_min > size_max) {
+		size_max = size_min;
+		msg_cspew("%s: setting max size to min size.\n", __func__);
+	}
+
+	/* Probe for chips of multiple sizes with one function (pointer) */
+	int res_cnt = 0;
+	unsigned int s;
+	for (s = size_min; s <= size_max; s <<= size_step) {
+		void *addr = programmer_map_flash_region("probe_allsizes", 0xffffffff - s * 1024 + 1, s * 1024);
+		if (addr == ERROR_PTR) {
+			msg_cwarn("%s: Could not map physical memory to probe for size %d kB.", __func__, s);
 			continue;
-		msg_gdbg("Probing for %s %s, %d kB: ", chip->vendor, chip->name, chip->total_size);
-		if (!chip->probe && !force) {
-			msg_gdbg("failed! flashrom has no probe function for this flash chip.\n");
+		}
+		flash->virtual_memory = (chipaddr)addr;
+		msg_cdbg("size %d... ", s);
+		int ret = p->probe_func(flash, res, res_len - res_cnt, p);
+		programmer_unmap_flash_region((void *)flash->virtual_memory, s * 1024);
+		if (ret >= 1) {
+			msg_cspew("%s: size %d returned %d result(s).\n", __func__, s, ret);
+			res->chip_size = s;
+			res += ret;
+			res_cnt += ret;
+			res_len -= ret;
+		} else if (ret <= 0)
+			res->len = 0;
+		if (res_len == 0) {
+			msg_cdbg("%s: Maximum number of results reached after probing for size %d kB. ",
+				 __func__, s);
+			break;
+		}
+	}
+	return res_cnt;
+}
+
+/* Probe for regular chips on a single programmer. */
+static unsigned int probe_flash_int(struct flashctx **flashes, unsigned int flashes_len, struct registered_programmer *pgm)
+{
+	unsigned int matches_prog = 0;
+	/* First, obtain results of all possible probe functions on this programmer. */
+	probe_res results[30] = {{0}}; //fixme
+	unsigned int results_cnt = 0;
+	unsigned int valid_results = 0;
+	unsigned int p_cnt;
+	for (p_cnt = 0; p_cnt < ARRAY_SIZE(probes); p_cnt++) {
+		if (results_cnt == ARRAY_SIZE(results)) {
+			msg_cwarn("%s: Maximum number of results (%ld) reached after %d probers. ",
+				 __func__, ARRAY_SIZE(results), p_cnt);
+			break;
+		}
+		probe *p = &probes[p_cnt];
+		probe_res *res = &results[results_cnt];
+		if ((p->bustype & pgm->buses_supported) == 0)
 			continue;
+		msg_gdbg("Probing with %s... ", p->mnemonic);
+		struct flashctx ctx = {.pgm = pgm};
+		int ret;
+		if (p->size_min != 0 || p->size_max != 0 || p->size_step != 0) {
+			ret = probe_allsizes(&ctx, res, ARRAY_SIZE(results) - results_cnt, p);
+		} else {
+			ret = p->probe_func(&ctx, res, ARRAY_SIZE(results) - results_cnt, p);
 		}
+		msg_gdbg("done: %d.\n", ret);
+
+		res->probe_func = p->probe_func;
+		if (ret > 0) {
+			unsigned int i, j;
+			for (i = 0; i < ret; i++) {
+				bool valid = false;
+				for (j = 0; j < res->len; j++) {
+					msg_cdbg(" 0x%02x", res->vals[j]);
+					/* All zeros or all ones is most probably not a valid result, but any
+					 * byte containing something else makes the response valid. */
+					if (res->vals[j] != 0x00 && res->vals[j] != 0xFF) {
+						valid = true;
+					}
+				}
+				if (valid)
+					valid_results++;
+				else
+					msg_cdbg(" Invalid result.");
 
-		/* Start filling in the dynamic data. */
-		flash->chip = calloc(1, sizeof(struct flashchip));
-		if (!flash->chip) {
-			msg_gerr("Out of memory!\n");
-			exit(1);
+				if (res->len > 0)
+					msg_cdbg("\n");
+
+				res++;
+			}
+			results_cnt += ret;
 		}
-		memcpy(flash->chip, chip, sizeof(struct flashchip));
-		flash->pgm = pgm;
+	}
 
-		if (map_flash(flash) != 0)
-			return -1;
+	if (valid_results == 0) {
+		char *busses = flashbuses_to_text(pgm->buses_supported);
+		msg_cdbg("No valid probing results received for %s.\n", busses);
+		free(busses);
+		return 0;
+	}
 
-		size = chip->total_size * 1024;
-		/* We handle a forced match like a real match, we just avoid probing. Note that probe_flash()
-		 * is only called with force=1 after normal probing failed.
-		 */
-		if (force)
-			break;
+	/* Try to find matching chips. For each chip in the flashchips array, compare its stored probers
+	 * with the results obtained above. */
+	const struct flashchip *chip;
+	for (chip = flashchips; chip->name; chip++) {
+		if ((chip->bustype & pgm->buses_supported) == 0)
+			continue;
+		msg_cdbg2("Matching %s... ", chip->name);
+		bool mismatch = false; // set if any received result does not match the saved values
+		bool match = false; // set if at least one result matches
+		unsigned int want_cnt;
+		for (want_cnt = 0; want_cnt < ARRAY_SIZE(chip->probers); want_cnt++) {
+			const struct prober *want = &chip->probers[want_cnt];
+			if (want->func == NULL)
+				break; /* If there is a prober w/o a func we are done for this chip. */
+
+			msg_cspew("\nComaring ID #%d: ", want_cnt);
+
+			/* Look for the matching probe function and compare its result to the chip. */
+			for (p_cnt = 0; p_cnt < ARRAY_SIZE(probes); p_cnt++) {
+				probe *p = &probes[p_cnt];
+				if (want->func != p->probe_func) {
+					msg_cspew("want->func != p->probe_func, ");
+					continue; // look further for the current probe function
+				}
 
-		if (flash->chip->probe(flash) != 1)
-			goto notfound;
+				probe_res *res = NULL;
+				unsigned int i;
+				for (i = 0; i < results_cnt; i++) {
+					if (results[i].probe_func == want->func &&
+					    (results[i].chip_size == 0 ||
+					     results[i].chip_size == chip->total_size)) {
+						res = &results[i];
+						// there should only be 1 result for any size, use first found
+						break;
+					}
+				}
+				if (res == NULL || res->len == 0) {
+					msg_cspew("no result for probe #%d, ", p_cnt);
+					break; // right function but there is no result -> next function
+				}
 
-		/* If this is the first chip found, accept it.
-		 * If this is not the first chip found, accept it only if it is
-		 * a non-generic match. SFDP and CFI are generic matches.
-		 * startchip==0 means this call to probe_flash() is the first
-		 * one for this programmer interface and thus no other chip has
-		 * been found on this interface.
-		 */
-		if (startchip == 0 && flash->chip->model_id == SFDP_DEVICE_ID) {
-			msg_cinfo("===\n"
-				  "SFDP has autodetected a flash chip which is "
-				  "not natively supported by flashrom yet.\n");
-			if (count_usable_erasers(flash) == 0)
-				msg_cinfo("The standard operations read and "
-					  "verify should work, but to support "
-					  "erase, write and all other "
-					  "possible features");
-			else
-				msg_cinfo("All standard operations (read, "
-					  "verify, erase and write) should "
-					  "work, but to support all possible "
-					  "features");
-
-			msg_cinfo(" we need to add them manually.\n"
-				  "You can help us by mailing us the output of the following command to "
-				  "flashrom at flashrom.org:\n"
-				  "'flashrom -VV [plus the -p/--programmer parameter]'\n"
-				  "Thanks for your help!\n"
-				  "===\n");
+				msg_cspew("comparing %d bytes of probe #%d... ",
+					  min(res->len, want->res.len), p_cnt);
+
+				bool seen_vendor = false;
+				for (i = 0; i < min(res->len, want->res.len); i++) {
+					if (!seen_vendor && res->vals[i] != 0x7F && res->vals[i] != 0x00 &&
+					    res->vals[i] != 0xFF) {
+						seen_vendor = true;
+						if (!oddparity(res->vals[i]))
+							msg_cdbg("%s byte %d parity violation.\n",
+								 p->mnemonic, i);
+					}
+					if (res->vals[i] != want->res.vals[i]) {
+						msg_cspew("byte #%d unexpected (0x%02x != 0x%02x), ",
+							  i, res->vals[i], want->res.vals[i]);
+						mismatch = true;
+						goto chip_done; // a single mismatch is enough to abort
+					}
+				}
+				msg_cspew("all match. ");
+				match = true; // remember that at least one prober has matched
+				break; // skip to next prober
+			}
+		}
+chip_done:
+		msg_cdbg2("%s does%s match.\n", chip->name, match && !mismatch ? "" : " not");
+		if (match && !mismatch) {
+			char *busses = flashbuses_to_text(chip->bustype);
+			msg_cinfo("Found %s flash chip \"%s\" (%d kB, %s).\n",
+				  chip->vendor, chip->name, chip->total_size, busses);
+			free(busses);
+			struct flashctx *tmp = realloc(*flashes, sizeof(struct flashctx) * (flashes_len + 1));
+			if (tmp == NULL) {
+				msg_gerr("Out of memory!\n");
+				free(*flashes);
+				*flashes = NULL;
+				return -1;
+			}
+			tmp[flashes_len].pgm = pgm;
+			tmp[flashes_len].chip = chip;
+			if (chip->printlock != NULL)
+				chip->printlock(&tmp[flashes_len]);
+			*flashes = tmp;
+			flashes_len++;
+			matches_prog++;
 		}
-
-		/* First flash chip detected on this bus. */
-		if (startchip == 0)
-			break;
-		/* Not the first flash chip detected on this bus, but not a generic match either. */
-		if ((flash->chip->model_id != GENERIC_DEVICE_ID) && (flash->chip->model_id != SFDP_DEVICE_ID))
-			break;
-		/* Not the first flash chip detected on this bus, and it's just a generic match. Ignore it. */
-notfound:
-		unmap_flash(flash);
-		free(flash->chip);
-		flash->chip = NULL;
 	}
+	return matches_prog;
+}
 
-	if (!flash->chip)
-		return -1;
+int probe_flash(struct flashctx **flashes, const struct registered_programmer *prog)
+{
+	unsigned int matches_total = 0;
+	unsigned int pgm_cnt;
+	for (pgm_cnt = 0; pgm_cnt < registered_programmer_count; pgm_cnt++) {
+		struct registered_programmer *pgm = &registered_programmers[pgm_cnt];
+		int matches_prog = probe_flash_int(flashes, matches_total, pgm);
+		if (matches_prog < 0) {
+			msg_cerr("%s: probe_flash_int for programmer #%d returned an error, aborting.",
+				  __func__, pgm_cnt);
+			free(*flashes);
+			return -1;
+		}
 
-	tmp = flashbuses_to_text(flash->chip->bustype);
-	msg_cinfo("%s %s flash chip \"%s\" (%d kB, %s).\n", force ? "Assuming" : "Found",
-		  flash->chip->vendor, flash->chip->name, flash->chip->total_size, tmp);
-	free(tmp);
+		matches_total += matches_prog;
 
-	/* Flash registers will not be mapped if the chip was forced. Lock info
-	 * may be stored in registers, so avoid lock info printing.
-	 */
-	if (!force)
-		if (flash->chip->printlock)
-			flash->chip->printlock(flash);
+		if (pgm->buses_supported & BUS_SPI) {
+			/* Try to detect SFDP only if there are no specific matches for this programmer. */
+			if (matches_prog == 0) {
+				struct flashctx *tmp = realloc(*flashes, sizeof(struct flashctx) * (matches_total + 1));
+				if (tmp == NULL) {
+					msg_gerr("Out of memory!\n");
+					free(*flashes);
+					return -1;
+				}
+				*flashes = tmp;
+				flashes[matches_total]->pgm = pgm;
+				if (probe_spi_sfdp(flashes[matches_total]) == 1) {
+					msg_cinfo("===\n"
+						  "SFDP has autodetected a flash chip which is "
+						  "not natively supported by flashrom yet.\n");
+					if (count_usable_erasers(flashes[matches_total]) == 0)
+						msg_cinfo("The standard operations read and "
+							  "verify should work, but to support "
+							  "erase, write and all other "
+							  "possible features");
+					else
+						msg_cinfo("All standard operations (read, "
+							  "verify, erase and write) should "
+							  "work, but to support all possible "
+							  "features");
+
+					msg_cinfo(" we need to add them manually.\n"
+						  "You can help us by mailing us the output of the following "
+						  "command to flashrom at flashrom.org:\n"
+						  "'flashrom -VV [plus the -p/--programmer parameters]'\n"
+						  "Thanks for your help!\n"
+						  "===\n");
+					matches_total++;
+				}
+			}
+		}
+	}
 
-	/* Return position of matching chip. */
-	return chip - flashchips;
+	/* Similar to SFDP above but here we check that there were no matches whatsoever at the very end of
+	 * probing so that everything else gets precedence. */
+	if (matches_total == 0) {
+		for (pgm_cnt = 0; pgm_cnt < registered_programmer_count; pgm_cnt++) {
+			struct registered_programmer *pgm = &registered_programmers[pgm_cnt];
+			if (pgm->buses_supported & BUS_PROG) {
+				struct flashctx *tmp = realloc(*flashes, sizeof(struct flashctx) * (matches_total + 1));
+				if (tmp == NULL) {
+					msg_gerr("Out of memory!\n");
+					free(*flashes);
+					return -1;
+				}
+				*flashes = tmp;
+				flashes[matches_total]->pgm = pgm;
+				if (pgm->opaque.probe(flashes[matches_total]) == 0) {
+					matches_total++;
+				}
+			}
+		}
+	}
+
+	return matches_total;
 }
 
 int read_buf_from_file(unsigned char *buf, unsigned long size,
@@ -1888,6 +2089,9 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it,
 		return 1;
 	}
 
+	if (map_flash(flash) != 0)
+		return 1;
+
 	/* Given the existence of read locks, we want to unlock for read,
 	 * erase and write.
 	 */
diff --git a/ichspi.c b/ichspi.c
index 190ad5a..c56f336 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -204,6 +204,7 @@ typedef struct _OPCODES {
 
 static OPCODES *curopcodes = NULL;
 
+
 /* HW access functions */
 static uint32_t REGREAD32(int X)
 {
@@ -1187,36 +1188,58 @@ static int ich_hwseq_wait_for_cycle_complete(unsigned int timeout,
 	return 0;
 }
 
+static int ich_hwseq_read(struct flashctx *flash, uint8_t *buf, unsigned int addr, unsigned int len);
+static int ich_hwseq_block_erase(struct flashctx *flash, unsigned int addr, unsigned int len);
+static int ich_hwseq_write(struct flashctx *flash, const uint8_t *buf, unsigned int addr, unsigned int len);
 static int ich_hwseq_probe(struct flashctx *flash)
 {
 	uint32_t total_size, boundary;
 	uint32_t erase_size_low, size_low, erase_size_high, size_high;
-	struct block_eraser *eraser;
 
 	total_size = hwseq_data.size_comp0 + hwseq_data.size_comp1;
-	msg_cdbg("Found %d attached SPI flash chip",
+	msg_cdbg("Hardware sequencing has found %d attached SPI flash chip",
 		 (hwseq_data.size_comp1 != 0) ? 2 : 1);
 	if (hwseq_data.size_comp1 != 0)
 		msg_cdbg("s with a combined");
 	else
 		msg_cdbg(" with a");
 	msg_cdbg(" density of %d kB.\n", total_size / 1024);
-	flash->chip->total_size = total_size / 1024;
 
-	eraser = &(flash->chip->block_erasers[0]);
+	struct flashchip *hwseq_chip = calloc(1, sizeof(struct flashchip));
+	if (hwseq_chip == NULL) {
+		msg_gerr("Out of memory!\n");
+		return -1;
+	}
+	if (register_shutdown(shutdown_free, (void *)hwseq_chip) != 0) {
+		msg_gerr("%s: Could not reqister shutdown function!\n", __func__);
+		free(hwseq_chip);
+		return -1;
+	}
+
+	hwseq_chip->vendor	= "Intel";
+	hwseq_chip->name	= "Flash chip(s) behind hardware sequencing";
+	hwseq_chip->bustype	= BUS_PROG;
+	hwseq_chip->page_size	= 256;
+	hwseq_chip->tested 	= TEST_OK_PREW;
+	hwseq_chip->block_erasers[0].block_erase = ich_hwseq_block_erase;
+	hwseq_chip->write	= ich_hwseq_write;
+	hwseq_chip->read	= ich_hwseq_read;
+	hwseq_chip->total_size = total_size / 1024;
+
+	struct block_eraser *eraser = &(hwseq_chip->block_erasers[0]);
 	boundary = (REGREAD32(ICH9_REG_FPB) & FPB_FPBA) << 12;
 	size_high = total_size - boundary;
 	erase_size_high = ich_hwseq_get_erase_block_size(boundary);
 
 	if (boundary == 0) {
-		msg_cdbg("There is only one partition containing the whole "
+		msg_cdbg2("There is only one partition containing the whole "
 			 "address space (0x%06x - 0x%06x).\n", 0, size_high-1);
 		eraser->eraseblocks[0].size = erase_size_high;
 		eraser->eraseblocks[0].count = size_high / erase_size_high;
-		msg_cdbg("There are %d erase blocks with %d B each.\n",
+		msg_cdbg2("There are %d erase blocks with %d B each.\n",
 			 size_high / erase_size_high, erase_size_high);
 	} else {
-		msg_cdbg("The flash address space (0x%06x - 0x%06x) is divided "
+		msg_cdbg2("The flash address space (0x%06x - 0x%06x) is divided "
 			 "at address 0x%06x in two partitions.\n",
 			 0, total_size-1, boundary);
 		size_low = total_size - size_high;
@@ -1224,20 +1247,20 @@ static int ich_hwseq_probe(struct flashctx *flash)
 
 		eraser->eraseblocks[0].size = erase_size_low;
 		eraser->eraseblocks[0].count = size_low / erase_size_low;
-		msg_cdbg("The first partition ranges from 0x%06x to 0x%06x.\n",
+		msg_cdbg2("The first partition ranges from 0x%06x to 0x%06x.\n",
 			 0, size_low-1);
-		msg_cdbg("In that range are %d erase blocks with %d B each.\n",
+		msg_cdbg2("In that range are %d erase blocks with %d B each.\n",
 			 size_low / erase_size_low, erase_size_low);
 
 		eraser->eraseblocks[1].size = erase_size_high;
 		eraser->eraseblocks[1].count = size_high / erase_size_high;
-		msg_cdbg("The second partition ranges from 0x%06x to 0x%06x.\n",
+		msg_cdbg2("The second partition ranges from 0x%06x to 0x%06x.\n",
 			 boundary, total_size-1);
-		msg_cdbg("In that range are %d erase blocks with %d B each.\n",
+		msg_cdbg2("In that range are %d erase blocks with %d B each.\n",
 			 size_high / erase_size_high, erase_size_high);
 	}
-	flash->chip->tested = TEST_OK_PREW;
-	return 1;
+	flash->chip = hwseq_chip;
+	return 0;
 }
 
 static int ich_hwseq_block_erase(struct flashctx *flash, unsigned int addr,
@@ -1547,9 +1570,6 @@ static const struct opaque_programmer opaque_programmer_ich_hwseq = {
 	.max_data_read = 64,
 	.max_data_write = 64,
 	.probe = ich_hwseq_probe,
-	.read = ich_hwseq_read,
-	.write = ich_hwseq_write,
-	.erase = ich_hwseq_block_erase,
 };
 
 int ich_init_spi(struct pci_dev *dev, void *spibar, enum ich_chipset ich_gen)
diff --git a/jedec.c b/jedec.c
index d8c3242..dbf3fd7 100644
--- a/jedec.c
+++ b/jedec.c
@@ -38,6 +38,30 @@ uint8_t oddparity(uint8_t val)
 	return (val ^ (val >> 1)) & 0x1;
 }
 
+/* Looks for values in a different from all zeroes and all ones. If b is non-null test_for_valid_ids
+ * additionally compares bytes in a and b respectively. Can be be used on values read before and after exiting
+ * ID mode: Unequal values indicate with high certainty that the write commands enabling and disabling ID mode
+ * were received and understood by the chip. */
+bool test_for_valid_ids(uint8_t *a, uint8_t *b, unsigned int len)
+{
+	unsigned int i;
+	bool equal = true;
+	bool valid = false;
+	for (i = 0; i < len; i++) {
+		if (b != NULL) {
+			if (a[i] != b[i])
+				equal = false;
+			else
+				msg_cspew("Byte #%d is equal (0x%02x).\n", i, a[i]);
+		}
+		if (a[i] != 0x00 && a[i] != 0xFF)
+			valid = true;
+	}
+	if (b != NULL && equal && valid)
+		msg_cdbg("IDs are equal to normal flash content.");
+	return valid;
+}
+
 static void toggle_ready_jedec_common(const struct flashctx *flash, chipaddr dst, unsigned int delay)
 {
 	unsigned int i = 0;
@@ -120,15 +144,10 @@ static void start_program_jedec_common(const struct flashctx *flash, unsigned in
 	chip_writeb(flash, 0xA0, bios + (0x5555 & mask));
 }
 
-int probe_jedec(struct flashctx *flash)
+static int probe_jedec(struct flashctx *flash, struct probe_res *res, unsigned int mask, bool long_reset)
 {
 	unsigned int delay = 10000;
 	chipaddr bios = flash->virtual_memory;
-	const struct flashchip *chip = flash->chip;
-	const unsigned int mask = getaddrmask(flash->chip);
-	uint8_t id1, id2;
-	uint32_t largeid1, largeid2;
-	uint32_t flashcontent1, flashcontent2;
 
 	/* Earlier probes might have been too fast for the chip to enter ID
 	 * mode completely. Allow the chip to finish this before seeing a
@@ -137,7 +156,7 @@ int probe_jedec(struct flashctx *flash)
 	if (delay)
 		programmer_delay(delay);
 	/* Reset chip to a clean slate */
-	if ((chip->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
+	if (long_reset)
 	{
 		chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
 		if (delay)
@@ -161,26 +180,25 @@ int probe_jedec(struct flashctx *flash)
 	if (delay)
 		programmer_delay(delay);
 
-	/* Read product ID */
-	id1 = chip_readb(flash, bios);
-	id2 = chip_readb(flash, bios + 0x01);
-	largeid1 = id1;
-	largeid2 = id2;
-
-	/* Check if it is a continuation ID, this should be a while loop. */
-	if (id1 == 0x7F) {
-		largeid1 <<= 8;
-		id1 = chip_readb(flash, bios + 0x100);
-		largeid1 |= id1;
+#if (NUM_PROBE_BYTES < 4)
+#error probe_jedec requires NUM_PROBE_BYTES to be at least 4.
+#endif
+	unsigned int idx = 0;
+	/* Read manufacturer ID */
+	res->vals[idx++] = chip_readb(flash, bios);
+	/* Check if it is a continuation ID, this (and the one below) should be a while loop. */
+	if (res->vals[idx] == 0x7F) {
+		res->vals[idx++] = chip_readb(flash, bios + 0x100);
 	}
-	if (id2 == 0x7F) {
-		largeid2 <<= 8;
-		id2 = chip_readb(flash, bios + 0x101);
-		largeid2 |= id2;
+
+	/* Read model ID */
+	res->vals[idx++] = chip_readb(flash, bios + 0x01);
+	if (res->vals[idx] == 0x7F) {
+		res->vals[idx++] = chip_readb(flash, bios + 0x101);
 	}
 
 	/* Issue JEDEC Product ID Exit command */
-	if ((chip->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
+	if (long_reset)
 	{
 		chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
 		if (delay)
@@ -193,36 +211,56 @@ int probe_jedec(struct flashctx *flash)
 	if (delay)
 		programmer_delay(delay);
 
-	msg_cdbg("%s: id1 0x%02x, id2 0x%02x", __func__, largeid1, largeid2);
-	if (!oddparity(id1))
-		msg_cdbg(", id1 parity violation");
-
+	uint8_t cont[idx];
+	unsigned cont_idx = 0;
 	/* Read the product ID location again. We should now see normal flash contents. */
-	flashcontent1 = chip_readb(flash, bios);
-	flashcontent2 = chip_readb(flash, bios + 0x01);
+	cont[cont_idx] = chip_readb(flash, bios);
 
 	/* Check if it is a continuation ID, this should be a while loop. */
-	if (flashcontent1 == 0x7F) {
-		flashcontent1 <<= 8;
-		flashcontent1 |= chip_readb(flash, bios + 0x100);
+	if (cont[cont_idx++] == 0x7F) {
+		cont[cont_idx++] = chip_readb(flash, bios + 0x100);
 	}
-	if (flashcontent2 == 0x7F) {
-		flashcontent2 <<= 8;
-		flashcontent2 |= chip_readb(flash, bios + 0x101);
+	cont[cont_idx] = chip_readb(flash, bios + 0x01);
+	if (cont[cont_idx++] == 0x7F) {
+		cont[cont_idx++] = chip_readb(flash, bios + 0x101);
 	}
 
-	if (largeid1 == flashcontent1)
-		msg_cdbg(", id1 is normal flash content");
-	if (largeid2 == flashcontent2)
-		msg_cdbg(", id2 is normal flash content");
-
-	msg_cdbg("\n");
-	if (largeid1 != chip->manufacture_id || largeid2 != chip->model_id)
+	if (test_for_valid_ids(res->vals, cont, idx)) {
+		res->len = idx;
+		return 1;
+	} else {
+		res->len = 0;
 		return 0;
+	}
 
 	return 1;
 }
 
+int probe_jedec_longreset(struct flashctx *flash, struct probe_res *res, unsigned int res_len, const struct probe *p)
+{
+	return probe_jedec(flash, res, MASK_FULL, true);
+}
+
+int probe_jedec_shortreset_full(struct flashctx *flash, struct probe_res *res, unsigned int res_len, const struct probe *p)
+{
+	return probe_jedec(flash, res, MASK_FULL, false);
+}
+
+int probe_jedec_shortreset_full_384(struct flashctx *flash, struct probe_res *res, unsigned int res_len, const struct probe *p)
+{
+	return probe_jedec(flash, res, MASK_FULL, false);
+}
+
+int probe_jedec_shortreset_2aa(struct flashctx *flash, struct probe_res *res, unsigned int res_len, const struct probe *p)
+{
+	return probe_jedec(flash, res, MASK_2AA, false);
+}
+
+int probe_jedec_shortreset_aaa(struct flashctx *flash, struct probe_res *res, unsigned int res_len, const struct probe *p)
+{
+	return probe_jedec(flash, res, MASK_AAA, false);
+}
+
 static int erase_sector_jedec_common(struct flashctx *flash, unsigned int page,
 				     unsigned int pagesize, unsigned int mask)
 {
diff --git a/m29f400bt.c b/m29f400bt.c
index 399a7e0..0a13076 100644
--- a/m29f400bt.c
+++ b/m29f400bt.c
@@ -55,10 +55,9 @@ int write_m29f400bt(struct flashctx *flash, const uint8_t *src, unsigned int sta
 	return 0;
 }
 
-int probe_m29f400bt(struct flashctx *flash)
+int probe_m29f400bt(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2)
 {
 	chipaddr bios = flash->virtual_memory;
-	uint8_t id1, id2;
 
 	chip_writeb(flash, 0xAA, bios + 0xAAA);
 	chip_writeb(flash, 0x55, bios + 0x555);
@@ -66,11 +65,14 @@ int probe_m29f400bt(struct flashctx *flash)
 
 	programmer_delay(10);
 
-	id1 = chip_readb(flash, bios);
+#if (NUM_PROBE_BYTES < 2)
+#error probe_m29f400bt requires NUM_PROBE_BYTES to be at least 2.
+#endif
+	res->vals[0] = chip_readb(flash, bios);
 	/* The data sheet says id2 is at (bios + 0x01) and id2 listed in
 	 * flash.h does not match. It should be possible to use JEDEC probe.
 	 */
-	id2 = chip_readb(flash, bios + 0x02);
+	res->vals[1] = chip_readb(flash, bios + 0x02);
 
 	chip_writeb(flash, 0xAA, bios + 0xAAA);
 	chip_writeb(flash, 0x55, bios + 0x555);
@@ -78,10 +80,15 @@ int probe_m29f400bt(struct flashctx *flash)
 
 	programmer_delay(10);
 
-	msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+	uint8_t cont[2];
+	cont[0] = chip_readb(flash, bios);
+	cont[1] = chip_readb(flash, bios + 0x02);
 
-	if (id1 == flash->chip->manufacture_id && id2 == flash->chip->model_id)
+	if (test_for_valid_ids(res->vals, cont, 2)) {
+		res->len = 2;
 		return 1;
-
-	return 0;
+	} else {
+		res->len = 0;
+		return 0;
+	}
 }
diff --git a/opaque.c b/opaque.c
index c63919f..3a9866c 100644
--- a/opaque.c
+++ b/opaque.c
@@ -30,31 +30,11 @@
 #include "chipdrivers.h"
 #include "programmer.h"
 
-int probe_opaque(struct flashctx *flash)
-{
-	return flash->pgm->opaque.probe(flash);
-}
-
-int read_opaque(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
-{
-	return flash->pgm->opaque.read(flash, buf, start, len);
-}
-
-int write_opaque(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
-{
-	return flash->pgm->opaque.write(flash, buf, start, len);
-}
-
-int erase_opaque(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen)
-{
-	return flash->pgm->opaque.erase(flash, blockaddr, blocklen);
-}
-
 int register_opaque_programmer(const struct opaque_programmer *pgm)
 {
 	struct registered_programmer rpgm;
 
-	if (!pgm->probe || !pgm->read || !pgm->write || !pgm->erase) {
+	if (!pgm->probe) {
 		msg_perr("%s called with incomplete programmer definition. "
 			 "Please report a bug at flashrom at flashrom.org\n",
 			 __func__);
diff --git a/print.c b/print.c
index efd834d..22d1d64 100644
--- a/print.c
+++ b/print.c
@@ -109,11 +109,6 @@ static int print_supported_chips(void)
 
 	/* calculate maximum column widths and by iterating over all chips */
 	for (chip = flashchips; chip->name != NULL; chip++) {
-		/* Ignore generic entries. */
-		if (!strncmp(chip->vendor, "Unknown", 7) ||
-		    !strncmp(chip->vendor, "Programmer", 10) ||
-		    !strncmp(chip->name, "unknown", 7))
-			continue;
 		chipcount++;
 
 		/* Find maximum vendor length (respecting line splitting). */
@@ -195,15 +190,9 @@ static int print_supported_chips(void)
 		msg_ginfo(" ");
 	msg_gdbg("range [V]");
 	msg_ginfo("\n\n");
-	msg_ginfo("(P = PROBE, R = READ, E = ERASE, W = WRITE)\n\n");
+	msg_ginfo("(P = PROBE, R = READ, E = ERASE, W = WRITE, - = N/A)\n\n");
 
 	for (chip = flashchips; chip->name != NULL; chip++) {
-		/* Don't print generic entries. */
-		if (!strncmp(chip->vendor, "Unknown", 7) ||
-		    !strncmp(chip->vendor, "Programmer", 10) ||
-		    !strncmp(chip->name, "unknown", 7))
-			continue;
-
 		/* support for multiline vendor names:
 		 * - make a copy of the original vendor name
 		 * - use strok to put the first token in tmpven
diff --git a/print_wiki.c b/print_wiki.c
index 2936dbf..8c64a80 100644
--- a/print_wiki.c
+++ b/print_wiki.c
@@ -292,11 +292,6 @@ static void print_supported_chips_wiki(int cols)
 	int i = 0, c = 1, chipcount = 0;
 
 	for (f = flashchips; f->name != NULL; f++) {
-		/* Don't count generic entries. */
-		if (!strncmp(f->vendor, "Unknown", 7) ||
-		    !strncmp(f->vendor, "Programmer", 10) ||
-		    !strncmp(f->name, "unknown", 7))
-			continue;
 		chipcount++;
 	}
 
@@ -308,12 +303,6 @@ static void print_supported_chips_wiki(int cols)
 	       "{| border=\"0\" valign=\"top\"\n", chipcount);
 
 	for (f = flashchips; f->name != NULL; f++) {
-		/* Don't print generic entries. */
-		if (!strncmp(f->vendor, "Unknown", 7) ||
-		    !strncmp(f->vendor, "Programmer", 10) ||
-		    !strncmp(f->name, "unknown", 7))
-			continue;
-
 		if ((i % lines_per_col) == 0)
 			printf("%s%s", th_start, chip_th);
 
diff --git a/programmer.c b/programmer.c
index 1874929..f677891 100644
--- a/programmer.c
+++ b/programmer.c
@@ -119,7 +119,7 @@ struct registered_programmer registered_programmers[PROGRAMMERS_MAX];
 int registered_programmer_count = 0;
 
 /* This function copies the struct registered_programmer parameter. */
-int register_programmer(struct registered_programmer *pgm)
+int register_programmer(const struct registered_programmer *pgm)
 {
 	if (registered_programmer_count >= PROGRAMMERS_MAX) {
 		msg_perr("Tried to register more than %i programmer "
diff --git a/programmer.h b/programmer.h
index 9b0227e..9ab7698 100644
--- a/programmer.h
+++ b/programmer.h
@@ -629,9 +629,6 @@ struct opaque_programmer {
 	int max_data_write;
 	/* Specific functions for this programmer */
 	int (*probe) (struct flashctx *flash);
-	int (*read) (struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
-	int (*write) (struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
-	int (*erase) (struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen);
 	const void *data;
 };
 int register_opaque_programmer(const struct opaque_programmer *pgm);
@@ -669,7 +666,7 @@ struct registered_programmer {
 };
 extern struct registered_programmer registered_programmers[];
 extern int registered_programmer_count;
-int register_programmer(struct registered_programmer *pgm);
+int register_programmer(const struct registered_programmer *pgm);
 
 /* serprog.c */
 #if CONFIG_SERPROG == 1
diff --git a/sfdp.c b/sfdp.c
index bc69dd0..488115d 100644
--- a/sfdp.c
+++ b/sfdp.c
@@ -256,51 +256,30 @@ static int sfdp_fill_flash(struct flashchip *chip, uint8_t *buf, uint16_t len)
 	}
 
 done:
+	chip->vendor	= "Unknown";
+	chip->name	= "SFDP-capable chip";
+	chip->bustype	= BUS_SPI;
+	/* We present our own "report this" text hence we do not
+	 * want the default "This flash part has status UNTESTED..."
+	 * text to be printed. */
+	chip->tested 	= TEST_OK_PREW;
+	chip->unlock	= spi_disable_blockprotect; /* is this safe? */
+	chip->read	= spi_chip_read;
+	/* FIXME: some vendor extensions define voltage ranges too. */
+
 	msg_cdbg("done.\n");
 	return 0;
 }
 
-int probe_spi_sfdp(struct flashctx *flash)
+static int sfdp_parse_headers(struct flashctx *flash, struct flashchip *sfdp_chip, uint8_t nph)
 {
-	int ret = 0;
-	uint8_t buf[8];
 	uint32_t tmp32;
-	uint8_t nph;
 	/* need to limit the table loop by comparing i to uint8_t nph hence: */
 	uint16_t i;
 	struct sfdp_tbl_hdr *hdrs;
 	uint8_t *hbuf;
 	uint8_t *tbuf;
-
-	if (spi_sfdp_read_sfdp(flash, 0x00, buf, 4)) {
-		msg_cdbg("Receiving SFDP signature failed.\n");
-		return 0;
-	}
-	tmp32 = buf[0];
-	tmp32 |= ((unsigned int)buf[1]) << 8;
-	tmp32 |= ((unsigned int)buf[2]) << 16;
-	tmp32 |= ((unsigned int)buf[3]) << 24;
-
-	if (tmp32 != 0x50444653) {
-		msg_cdbg2("Signature = 0x%08x (should be 0x50444653)\n", tmp32);
-		msg_cdbg("No SFDP signature found.\n");
-		return 0;
-	}
-
-	if (spi_sfdp_read_sfdp(flash, 0x04, buf, 3)) {
-		msg_cdbg("Receiving SFDP revision and number of parameter "
-			 "headers (NPH) failed. ");
-		return 0;
-	}
-	msg_cdbg2("SFDP revision = %d.%d\n", buf[1], buf[0]);
-	if (buf[1] != 0x01) {
-		msg_cdbg("The chip supports an unknown version of SFDP. "
-			  "Aborting SFDP probe!\n");
-		return 0;
-	}
-	nph = buf[2];
-	msg_cdbg2("SFDP number of parameter headers is %d (NPH = %d).\n",
-		  nph + 1, nph);
+	int ret = 1;
 
 	/* Fetch all parameter headers, even if we don't use them all (yet). */
 	hbuf = malloc((nph + 1) * 8);
@@ -381,8 +360,8 @@ int probe_spi_sfdp(struct flashctx *flash)
 				msg_cdbg("Length of the mandatory JEDEC SFDP "
 					 "parameter table is wrong (%d B), "
 					 "skipping it.\n", len);
-			} else if (sfdp_fill_flash(flash->chip, tbuf, len) == 0)
-				ret = 1;
+			} else
+				ret = sfdp_fill_flash(sfdp_chip, tbuf, len);
 		}
 		free(tbuf);
 	}
@@ -390,5 +369,63 @@ int probe_spi_sfdp(struct flashctx *flash)
 cleanup_hdrs:
 	free(hdrs);
 	free(hbuf);
+
+	return ret;
+}
+
+int probe_spi_sfdp(struct flashctx *flash)
+{
+	int ret = -1;
+	uint8_t buf[8];
+	uint32_t tmp32;
+
+	msg_cdbg("Looking for a SFDP-compatible chip... ");
+	if (spi_sfdp_read_sfdp(flash, 0x00, buf, 4)) {
+		msg_cdbg("Receiving SFDP signature failed.\n");
+		return -1;
+	}
+	tmp32 = buf[0];
+	tmp32 |= ((unsigned int)buf[1]) << 8;
+	tmp32 |= ((unsigned int)buf[2]) << 16;
+	tmp32 |= ((unsigned int)buf[3]) << 24;
+
+	if (tmp32 != 0x50444653) {
+		msg_cdbg2("Signature = 0x%08x (should be 0x50444653)\n", tmp32);
+		msg_cdbg("No SFDP signature found.\n");
+		return 0;
+	}
+
+	if (spi_sfdp_read_sfdp(flash, 0x04, buf, 3)) {
+		msg_cdbg("Receiving SFDP revision and number of parameter "
+			 "headers (NPH) failed. ");
+		return -1;
+	}
+	msg_cdbg2("SFDP revision = %d.%d\n", buf[1], buf[0]);
+	if (buf[1] != 0x01) {
+		msg_cdbg("The chip supports an unknown version of SFDP. "
+			  "Aborting SFDP probe!\n");
+		return 0;
+	}
+	msg_cdbg2("SFDP number of parameter headers is %d (NPH = %d).\n",
+		  buf[2] + 1, buf[2]);
+
+	struct flashchip *sfdp_chip = calloc(1, sizeof(struct flashchip));
+	if (sfdp_chip == NULL) {
+		msg_gerr("Out of memory!\n");
+		return -1;
+	}
+
+	ret = sfdp_parse_headers(flash, sfdp_chip, buf[2]);
+
+	if (ret == 0) {
+		if (register_shutdown(shutdown_free, (void *)sfdp_chip) != 0) {
+			msg_gerr("%s: Could not reqister shutdown function!\n", __func__);
+			free(sfdp_chip);
+			return -1;
+		}
+		flash->chip = sfdp_chip;
+	} else
+		free(sfdp_chip);
+
 	return ret;
 }
diff --git a/spi25.c b/spi25.c
index 9763c80..38846f9 100644
--- a/spi25.c
+++ b/spi25.c
@@ -29,68 +29,40 @@
 #include "programmer.h"
 #include "spi.h"
 
-static int spi_rdid(struct flashctx *flash, unsigned char *readarr, int bytes)
+static int spi_rdid(struct flashctx *flash, unsigned char *readarr, unsigned int bytes)
 {
-	static const unsigned char cmd[JEDEC_RDID_OUTSIZE] = { JEDEC_RDID };
-	int ret;
-	int i;
-
-	ret = spi_send_command(flash, sizeof(cmd), bytes, cmd, readarr);
-	if (ret)
-		return ret;
-	msg_cspew("RDID returned");
-	for (i = 0; i < bytes; i++)
-		msg_cspew(" 0x%02x", readarr[i]);
-	msg_cspew(". ");
-	return 0;
+	static const unsigned char cmd[] = { JEDEC_RDID };
+	if (spi_send_command(flash, sizeof(cmd), bytes, cmd, readarr) != 0)
+		return -1;
+	return test_for_valid_ids(readarr, NULL, bytes) ? 1 : 0;
 }
 
-static int spi_rems(struct flashctx *flash, unsigned char *readarr)
+static int probe_spi_res_rems(struct flashctx *flash, struct probe_res *res, uint8_t opcode)
 {
-	unsigned char cmd[JEDEC_REMS_OUTSIZE] = { JEDEC_REMS, 0, 0, 0 };
-	uint32_t readaddr;
-	int ret;
-
-	ret = spi_send_command(flash, sizeof(cmd), JEDEC_REMS_INSIZE, cmd,
-			       readarr);
+	unsigned char cmd[] = { opcode, 0, 0, 0 }; /* opcode + address */
+	res->len = ARRAY_SIZE(res->vals); // fill up to maximum if possible
+	int ret = spi_send_command(flash, sizeof(cmd), res->len, cmd, res->vals);
 	if (ret == SPI_INVALID_ADDRESS) {
 		/* Find the lowest even address allowed for reads. */
-		readaddr = (spi_get_valid_read_addr(flash) + 1) & ~1;
+		uint32_t readaddr = (spi_get_valid_read_addr(flash) + 1) & ~1;
 		cmd[1] = (readaddr >> 16) & 0xff,
 		cmd[2] = (readaddr >> 8) & 0xff,
 		cmd[3] = (readaddr >> 0) & 0xff,
-		ret = spi_send_command(flash, sizeof(cmd), JEDEC_REMS_INSIZE,
-				       cmd, readarr);
+		ret = spi_send_command(flash, sizeof(cmd), res->len, cmd, res->vals);
 	}
-	if (ret)
-		return ret;
-	msg_cspew("REMS returned 0x%02x 0x%02x. ", readarr[0], readarr[1]);
-	return 0;
+	if (ret != 0)
+		return -1;
+	return test_for_valid_ids(res->vals, NULL, res->len) ? 1 : 0;
 }
 
-static int spi_res(struct flashctx *flash, unsigned char *readarr, int bytes)
+int probe_spi_rems(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2)
 {
-	unsigned char cmd[JEDEC_RES_OUTSIZE] = { JEDEC_RES, 0, 0, 0 };
-	uint32_t readaddr;
-	int ret;
-	int i;
+	return probe_spi_res_rems(flash, res, JEDEC_REMS);
+}
 
-	ret = spi_send_command(flash, sizeof(cmd), bytes, cmd, readarr);
-	if (ret == SPI_INVALID_ADDRESS) {
-		/* Find the lowest even address allowed for reads. */
-		readaddr = (spi_get_valid_read_addr(flash) + 1) & ~1;
-		cmd[1] = (readaddr >> 16) & 0xff,
-		cmd[2] = (readaddr >> 8) & 0xff,
-		cmd[3] = (readaddr >> 0) & 0xff,
-		ret = spi_send_command(flash, sizeof(cmd), bytes, cmd, readarr);
-	}
-	if (ret)
-		return ret;
-	msg_cspew("RES returned");
-	for (i = 0; i < bytes; i++)
-		msg_cspew(" 0x%02x", readarr[i]);
-	msg_cspew(". ");
-	return 0;
+int probe_spi_res(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2)
+{
+	return probe_spi_res_rems(flash, res, JEDEC_RES);
 }
 
 int spi_write_enable(struct flashctx *flash)
@@ -115,210 +87,37 @@ int spi_write_disable(struct flashctx *flash)
 	return spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
 }
 
-static int probe_spi_rdid_generic(struct flashctx *flash, int bytes)
+int probe_spi_rdid(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2)
 {
-	const struct flashchip *chip = flash->chip;
-	unsigned char readarr[4];
-	uint32_t id1;
-	uint32_t id2;
-
-	if (spi_rdid(flash, readarr, bytes)) {
-		return 0;
-	}
-
-	if (!oddparity(readarr[0]))
-		msg_cdbg("RDID byte 0 parity violation. ");
-
-	/* Check if this is a continuation vendor ID.
-	 * FIXME: Handle continuation device IDs.
-	 */
-	if (readarr[0] == 0x7f) {
-		if (!oddparity(readarr[1]))
-			msg_cdbg("RDID byte 1 parity violation. ");
-		id1 = (readarr[0] << 8) | readarr[1];
-		id2 = readarr[2];
-		if (bytes > 3) {
-			id2 <<= 8;
-			id2 |= readarr[3];
-		}
-	} else {
-		id1 = readarr[0];
-		id2 = (readarr[1] << 8) | readarr[2];
-	}
-
-	msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
-
-	if (id1 == chip->manufacture_id && id2 == chip->model_id)
-		return 1;
-
-	/* Test if this is a pure vendor match. */
-	if (id1 == chip->manufacture_id && GENERIC_DEVICE_ID == chip->model_id)
-		return 1;
-
-	/* Test if there is any vendor ID. */
-	if (GENERIC_MANUF_ID == chip->manufacture_id && id1 != 0xff)
-		return 1;
-
-	return 0;
-}
-
-int probe_spi_rdid(struct flashctx *flash)
-{
-	return probe_spi_rdid_generic(flash, 3);
-}
-
-int probe_spi_rdid4(struct flashctx *flash)
-{
-	/* Some SPI controllers do not support commands with writecnt=1 and
-	 * readcnt=4.
-	 */
-	switch (flash->pgm->spi.type) {
+	res->len = ARRAY_SIZE(res->vals); // fill up to maximum if possible
+	/* Some SPI controllers do not support commands with writecnt=1 and readcnt=4. */
+	if (res->len != 3) { // FIXME
+		switch (flash->pgm->spi.type) {
 #if CONFIG_INTERNAL == 1
 #if defined(__i386__) || defined(__x86_64__)
-	case SPI_CONTROLLER_IT87XX:
-	case SPI_CONTROLLER_WBSIO:
-		msg_cinfo("4 byte RDID not supported on this SPI controller\n");
-		return 0;
-		break;
+		case SPI_CONTROLLER_IT87XX:
+		case SPI_CONTROLLER_WBSIO:
+			msg_cinfo("4 byte RDID not supported on this SPI controller\n");
+			return -1;
+			break;
 #endif
 #endif
-	default:
-		return probe_spi_rdid_generic(flash, 4);
-	}
-
-	return 0;
-}
-
-int probe_spi_rems(struct flashctx *flash)
-{
-	const struct flashchip *chip = flash->chip;
-	unsigned char readarr[JEDEC_REMS_INSIZE];
-	uint32_t id1, id2;
-
-	if (spi_rems(flash, readarr)) {
-		return 0;
-	}
-
-	id1 = readarr[0];
-	id2 = readarr[1];
-
-	msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
-
-	if (id1 == chip->manufacture_id && id2 == chip->model_id)
-		return 1;
-
-	/* Test if this is a pure vendor match. */
-	if (id1 == chip->manufacture_id && GENERIC_DEVICE_ID == chip->model_id)
-		return 1;
-
-	/* Test if there is any vendor ID. */
-	if (GENERIC_MANUF_ID == chip->manufacture_id && id1 != 0xff)
-		return 1;
-
-	return 0;
-}
-
-int probe_spi_res1(struct flashctx *flash)
-{
-	static const unsigned char allff[] = {0xff, 0xff, 0xff};
-	static const unsigned char all00[] = {0x00, 0x00, 0x00};
-	unsigned char readarr[3];
-	uint32_t id2;
-
-	/* We only want one-byte RES if RDID and REMS are unusable. */
-
-	/* Check if RDID is usable and does not return 0xff 0xff 0xff or
-	 * 0x00 0x00 0x00. In that case, RES is pointless.
-	 */
-	if (!spi_rdid(flash, readarr, 3) && memcmp(readarr, allff, 3) &&
-	    memcmp(readarr, all00, 3)) {
-		msg_cdbg("Ignoring RES in favour of RDID.\n");
-		return 0;
-	}
-	/* Check if REMS is usable and does not return 0xff 0xff or
-	 * 0x00 0x00. In that case, RES is pointless.
-	 */
-	if (!spi_rems(flash, readarr) &&
-	    memcmp(readarr, allff, JEDEC_REMS_INSIZE) &&
-	    memcmp(readarr, all00, JEDEC_REMS_INSIZE)) {
-		msg_cdbg("Ignoring RES in favour of REMS.\n");
-		return 0;
-	}
-
-	if (spi_res(flash, readarr, 1)) {
-		return 0;
-	}
-
-	id2 = readarr[0];
-
-	msg_cdbg("%s: id 0x%x\n", __func__, id2);
-
-	if (id2 != flash->chip->model_id)
-		return 0;
-
-	return 1;
-}
-
-int probe_spi_res2(struct flashctx *flash)
-{
-	unsigned char readarr[2];
-	uint32_t id1, id2;
-
-	if (spi_res(flash, readarr, 2)) {
-		return 0;
-	}
-
-	id1 = readarr[0];
-	id2 = readarr[1];
-
-	msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
-
-	if (id1 != flash->chip->manufacture_id || id2 != flash->chip->model_id)
-		return 0;
-
-	return 1;
-}
-
-int probe_spi_res3(struct flashctx *flash)
-{
-	unsigned char readarr[3];
-	uint32_t id1, id2;
-
-	if (spi_res(flash, readarr, 3)) {
-		return 0;
+		default:
+			;//return probe_spi_rdid_generic(flash, 4);
+		}
 	}
 
-	id1 = (readarr[0] << 8) | readarr[1];
-	id2 = readarr[2];
-
-	msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
-
-	if (id1 != flash->chip->manufacture_id || id2 != flash->chip->model_id)
-		return 0;
-
-	return 1;
+	return spi_rdid(flash, res->vals, res->len);
 }
 
 /* Only used for some Atmel chips. */
-int probe_spi_at25f(struct flashctx *flash)
+int probe_spi_at25f(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2)
 {
-	static const unsigned char cmd[AT25F_RDID_OUTSIZE] = { AT25F_RDID };
-	unsigned char readarr[AT25F_RDID_INSIZE];
-	uint32_t id1;
-	uint32_t id2;
-
-	if (spi_send_command(flash, sizeof(cmd), sizeof(readarr), cmd, readarr))
-		return 0;
-
-	id1 = readarr[0];
-	id2 = readarr[1];
-
-	msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
-
-	if (id1 == flash->chip->manufacture_id && id2 == flash->chip->model_id)
-		return 1;
-
-	return 0;
+	static const uint8_t cmd[AT25F_RDID_OUTSIZE] = { AT25F_RDID };
+	res->len = AT25F_RDID_INSIZE;
+	if (spi_send_command(flash, sizeof(cmd), res->len, cmd, res->vals) != 0)
+		return -1;
+	return test_for_valid_ids(res->vals, NULL, res->len) ? 1 : 0;
 }
 
 int spi_chip_erase_60(struct flashctx *flash)
diff --git a/stm50.c b/stm50.c
index edcfdd2..168a4a2 100644
--- a/stm50.c
+++ b/stm50.c
@@ -53,7 +53,7 @@ static int stm50_unlock_address(struct flashctx *flash, int offset)
 int unlock_stm50_nonuniform(struct flashctx *flash)
 {
 	int i;
-	struct eraseblock *eraseblocks = flash->chip->block_erasers[0].eraseblocks;
+	const struct eraseblock *eraseblocks = flash->chip->block_erasers[0].eraseblocks;
 	unsigned int done = 0;
 	for (i = 0; i < NUM_ERASEREGIONS && eraseblocks[i].count != 0; i++) {
 		unsigned int block_size = eraseblocks[i].size;
diff --git a/w29ee011.c b/w29ee011.c
index 4df4687..1dbbb35 100644
--- a/w29ee011.c
+++ b/w29ee011.c
@@ -20,23 +20,22 @@
 
 #include <string.h>
 #include "flash.h"
+#include "chipdrivers.h"
 
 /* According to the Winbond W29EE011, W29EE012, W29C010M, W29C011A
  * datasheets this is the only valid probe function for those chips.
  */
-int probe_w29ee011(struct flashctx *flash)
+int probe_w29ee011(struct flashctx *flash, struct probe_res *res, unsigned int ignored, const struct probe *ignored2)
 {
-	chipaddr bios = flash->virtual_memory;
-	uint8_t id1, id2;
-
-	if (!chip_to_probe || strcmp(chip_to_probe, flash->chip->name)) {
-		msg_cdbg("Old Winbond W29* probe method disabled because "
-			 "the probing sequence puts the AMIC A49LF040A in "
-			 "a funky state. Use 'flashrom -c %s' if you "
-			 "have a board with such a chip.\n", flash->chip->name);
+	static const char *w29ee011 = "W29C010(M)/W29C011A/W29EE011/W29EE012-old";
+	if (!chip_to_probe || (strcmp(chip_to_probe, w29ee011) != 0)) {
+		msg_cdbg("Old Winbond W29* probe method disabled because the probing sequence puts the\n"
+			 "AMIC A49LF040A in a funky state. Use 'flashrom -c \"%s\"' if you have a board\n"
+			 "with such a chip.\n", w29ee011);
 		return 0;
 	}
 
+	chipaddr bios = flash->virtual_memory;
 	/* Issue JEDEC Product ID Entry command */
 	chip_writeb(flash, 0xAA, bios + 0x5555);
 	programmer_delay(10);
@@ -51,9 +50,12 @@ int probe_w29ee011(struct flashctx *flash)
 	chip_writeb(flash, 0x60, bios + 0x5555);
 	programmer_delay(10);
 
+#if (NUM_PROBE_BYTES < 2)
+#error probe_w29ee011 requires NUM_PROBE_BYTES to be at least 2.
+#endif
 	/* Read product ID */
-	id1 = chip_readb(flash, bios);
-	id2 = chip_readb(flash, bios + 0x01);
+	res->vals[0] = chip_readb(flash, bios);
+	res->vals[1] = chip_readb(flash, bios + 0x01);
 
 	/* Issue JEDEC Product ID Exit command */
 	chip_writeb(flash, 0xAA, bios + 0x5555);
@@ -63,10 +65,17 @@ int probe_w29ee011(struct flashctx *flash)
 	chip_writeb(flash, 0xF0, bios + 0x5555);
 	programmer_delay(10);
 
-	msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+	uint8_t cont[2];
+	cont[0] = chip_readb(flash, bios);
+	cont[1] = chip_readb(flash, bios + 0x01);
 
-	if (id1 == flash->chip->manufacture_id && id2 == flash->chip->model_id)
+	if (test_for_valid_ids(res->vals, cont, 2)) {
+		res->len = 2;
 		return 1;
+	} else {
+		res->len = 0;
+		return 0;
+	}
 
-	return 0;
+	return 1;
 }
-- 
Kind regards, Stefan Tauner





More information about the flashrom mailing list