Use bus probing for standard JEDEC and JEDEC_29GL

To keep things close to as they were, we still run the probing many
times, with a huge amount of different chip parameters and sizes.

This brings us down to 35 probing runs for 159 chips.  And there is
still room for improvement:  It's likely that chips respond already
when longer delays are used. Also, many chips actually ignore addi-
tional address bits when decoding commands (i.e. bits above a 0x555
pattern are simply ignored and we actually don't need the masking).
Many (if not all) parallel flash chips also don't care about higher
address bits when reading the identification, so we might only have
to probe for them with a single chip size.

For now, we keep the set of probing parameters close to what we did
before. For power-of-two chip sizes from 64KiB to 1MiB, we run with
the most common parameters. 7 more parameter sets are used for more
unusual cases. And the 29GL parts are probed for the three sizes we
have in our database: 4MiB, 8MiB, 16MiB.

A note on the 29GL probing: All the chips have status UNTESTED, and
most if not all are x16 parts that need the addresses shifted (what
we don't do ATM). Overall it looks like standard jedec probing with
a short reset sequence. However, continuations of the device ID are
always 2 bytes long, at a different offset (0x0E) and prefixed with
0x7E.

Change-Id: If6ece7edc2291cae4824e5bcc2f83fd8aaef296e
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/444
diff --git a/flashchips.c b/flashchips.c
index be57f0a..801cae2 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -73,7 +73,7 @@
 		.page_size	= 256,
 		.feature_bits	= FEATURE_SHORT_RESET | FEATURE_ADDR_2AA,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -108,7 +108,7 @@
 		.page_size	= 256,
 		.feature_bits	= FEATURE_EITHER_RESET | FEATURE_ADDR_2AA,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -143,7 +143,7 @@
 		.page_size	= 16 * 1024,
 		.feature_bits	= FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -173,7 +173,7 @@
 		.page_size	= 16 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -203,7 +203,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -233,7 +233,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -263,7 +263,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -293,7 +293,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -323,7 +323,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -353,7 +353,7 @@
 		.page_size	= 64 * 1024, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -387,7 +387,7 @@
 		.page_size	= 64 * 1024, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -421,7 +421,7 @@
 		.page_size	= 64 * 1024, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -456,7 +456,7 @@
 		.page_size	= 64 * 1024, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -491,7 +491,7 @@
 		.page_size	= 64 * 1024, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -526,7 +526,7 @@
 		.page_size	= 64 * 1024, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -561,7 +561,7 @@
 		.page_size	= 64 * 1024, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -596,7 +596,7 @@
 		.page_size	= 64 * 1024, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -631,7 +631,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -661,7 +661,7 @@
 		.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,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -1467,7 +1467,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -1502,7 +1502,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -1537,7 +1537,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -1567,7 +1567,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* routine is wrapper to probe_jedec (pm49fl00x.c) */
 		.block_erasers	=
 		{
@@ -2752,7 +2752,7 @@
 		.page_size	= 128,
 		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10000, /* 10mS, Enter=Exec */
 		.block_erasers	=
 		{
@@ -2779,7 +2779,7 @@
 		.page_size	= 256,
 		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10000,			/* 10ms */
 		.block_erasers	=
 		{
@@ -2806,7 +2806,7 @@
 		.page_size	= 256,
 		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10000,			/* 10 ms */
 		.block_erasers	=
 		{
@@ -2833,7 +2833,7 @@
 		.page_size	= 128,
 		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10000, /* 10mS, Enter=Exec */
 		.block_erasers	=
 		{
@@ -3289,7 +3289,7 @@
 		.page_size	= 0, /* unused */
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -3317,7 +3317,7 @@
 		.page_size	= 64,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -3344,7 +3344,7 @@
 		.page_size	= 256,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -3379,7 +3379,7 @@
 		.page_size	= 256,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -3414,7 +3414,7 @@
 		.page_size	= 0, /* unused */
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -3448,7 +3448,7 @@
 		.page_size	= 0, /* unused */
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,  /* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -3482,7 +3482,7 @@
 		.page_size	= 0, /* unused */
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,  /* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -3517,7 +3517,7 @@
 		.page_size	= 0, /* unused */
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,  /* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -4138,7 +4138,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -4168,7 +4168,7 @@
 		.page_size	= 0, /* unused */
 		.feature_bits	= 0,
 		.tested		= {.probe = OK, .read = OK, .erase = BAD, .write = BAD},
-		.probe		= probe_jedec, /* FIXME! */
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -4391,7 +4391,7 @@
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -6359,7 +6359,7 @@
 		.page_size	= 256,
 		.feature_bits	= FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -6394,7 +6394,7 @@
 		.page_size	= 256,
 		.feature_bits	= FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -6429,7 +6429,7 @@
 		.page_size	= 128,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -6460,7 +6460,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -6493,7 +6493,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -6526,7 +6526,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -6556,7 +6556,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -6585,7 +6585,7 @@
 		.total_size	= 512,
 		.page_size	= 4 * 1024,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -7266,7 +7266,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -7301,7 +7301,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -7337,7 +7337,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_SHIFTED | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10, // FIXME: check datasheet. Using the 10 us from probe_m29f400bt
 		.block_erasers	=
 		{
@@ -7372,7 +7372,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_SHIFTED | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10, // FIXME: check datasheet. Using the 10 us from probe_m29f400bt
 		.block_erasers	=
 		{
@@ -7407,7 +7407,7 @@
 		.page_size	= 0,
 		.feature_bits	= FEATURE_ADDR_SHIFTED | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10, // FIXME: check datasheet. Using the 10 us from probe_m29f400bt
 		.block_erasers	=
 		{
@@ -7442,7 +7442,7 @@
 		.page_size	= 0,
 		.feature_bits	= FEATURE_ADDR_SHIFTED | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10, // FIXME: check datasheet. Using the 10 us from probe_m29f400bt
 		.block_erasers	=
 		{
@@ -10281,7 +10281,7 @@
 		.page_size	= 256 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET, /* Some revisions may need FEATURE_ADDR_2AA */
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO, /* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -10316,7 +10316,7 @@
 		.page_size	= 256 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET, /* Some revisions may need FEATURE_ADDR_2AA */
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO, /* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -10351,7 +10351,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -10703,7 +10703,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -10736,7 +10736,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -10766,7 +10766,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -10799,7 +10799,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -11068,7 +11068,7 @@
 		.total_size	= 128,
 		.page_size	= 128 * 1024, /* 8k + 2x4k + 112k */
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -11098,7 +11098,7 @@
 		.total_size	= 128,
 		.page_size	= 128 * 1024, /* 112k + 2x4k + 8k */
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -12920,7 +12920,7 @@
 		.page_size	= 32 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -12956,7 +12956,7 @@
 		.page_size	= 32 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -12992,7 +12992,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -13027,7 +13027,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -13062,7 +13062,7 @@
 		.page_size	= 0, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -13097,7 +13097,7 @@
 		.page_size	= 0, /* unused */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -13132,7 +13132,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -13162,7 +13162,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -13192,7 +13192,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -13225,7 +13225,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -13255,7 +13255,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -13288,7 +13288,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -13321,7 +13321,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -13351,7 +13351,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -13384,7 +13384,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -15641,7 +15641,7 @@
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -15671,7 +15671,7 @@
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -15701,7 +15701,7 @@
 		.page_size	= 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -15731,7 +15731,7 @@
 		.page_size	= 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -15761,7 +15761,7 @@
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -15791,7 +15791,7 @@
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -15821,7 +15821,7 @@
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -16690,7 +16690,7 @@
 		.page_size	= 8 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_FIXME,
 		.block_erasers	=
 		{
@@ -16725,7 +16725,7 @@
 		.page_size	= 8 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_FIXME,
 		.block_erasers	=
 		{
@@ -16760,7 +16760,7 @@
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -16793,7 +16793,7 @@
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -16826,7 +16826,7 @@
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -16859,7 +16859,7 @@
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -16892,7 +16892,7 @@
 		.page_size	= 16 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* routine is wrapper to probe_jedec (pm49fl00x.c) */
 		.block_erasers	=
 		{
@@ -16926,7 +16926,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -19870,7 +19870,7 @@
 		.page_size	= 128,
 		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -19897,7 +19897,7 @@
 		.page_size	= 128,
 		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -19924,7 +19924,7 @@
 		.page_size	= 128,
 		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -19951,7 +19951,7 @@
 		.page_size	= 128,
 		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -19978,7 +19978,7 @@
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,			/* 150 ns */
 		.block_erasers	=
 		{
@@ -20008,7 +20008,7 @@
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,			/* 150 ns */
 		.block_erasers	=
 		{
@@ -20038,7 +20038,7 @@
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,			/* 150 ns */
 		.block_erasers	=
 		{
@@ -20068,7 +20068,7 @@
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,			/* 150 ns */
 		.block_erasers	=
 		{
@@ -20098,7 +20098,7 @@
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,			/* 150 ns */
 		.block_erasers	=
 		{
@@ -20128,7 +20128,7 @@
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,			/* 150 ns */
 		.block_erasers	=
 		{
@@ -20158,7 +20158,7 @@
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,			/* 150 ns */
 		.block_erasers	=
 		{
@@ -20188,7 +20188,7 @@
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,			/* 150 ns */
 		.block_erasers	=
 		{
@@ -20221,7 +20221,7 @@
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,			/* 150 ns */
 		.block_erasers	=
 		{
@@ -20251,7 +20251,7 @@
 		.page_size	= 16 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,		/* 150 ns */
 		.block_erasers	=
 		{
@@ -20286,7 +20286,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,		/* 150 ns */
 		.block_erasers	=
 		{
@@ -20324,7 +20324,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,		/* 150 ns */
 		.block_erasers	=
 		{
@@ -20395,7 +20395,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,		/* 150 ns */
 		.block_erasers	=
 		{
@@ -20502,7 +20502,7 @@
 		.page_size	= 16 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,			/* 150 ns */
 		.block_erasers	=
 		{
@@ -20535,7 +20535,7 @@
 		.page_size	= 4 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PRE,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,			/* 150 ns */
 		.block_erasers	=
 		{
@@ -20568,7 +20568,7 @@
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,			/* 150 ns */
 		.block_erasers	=
 		{
@@ -20601,7 +20601,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,		/* 150ns */
 		.block_erasers	=
 		{
@@ -20635,7 +20635,7 @@
 		.page_size	= 4096,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= {.probe = NT, .read = OK, .erase = OK, .write = OK},
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 1,		/* 150ns */
 		.block_erasers	=
 		{
@@ -20704,7 +20704,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -20739,7 +20739,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -20774,7 +20774,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO, /* datasheet specifies no timing */
 		.block_erasers	=
 		{
@@ -20805,7 +20805,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_SHIFTED | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10, // FIXME: check datasheet. Using the 10 us from probe_m29f400bt
 		.block_erasers	=
 		{
@@ -20841,7 +20841,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_SHIFTED | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10, // FIXME: check datasheet. Using the 10 us from probe_m29f400bt
 		.block_erasers	=
 		{
@@ -20876,7 +20876,7 @@
 		.page_size	= 16 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -20906,7 +20906,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -20936,7 +20936,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -22656,7 +22656,7 @@
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -22686,7 +22686,7 @@
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -22716,7 +22716,7 @@
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -22745,7 +22745,7 @@
 		.page_size	= 512,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -22774,7 +22774,7 @@
 		.page_size	= 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -22804,7 +22804,7 @@
 		.page_size	= 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -22834,7 +22834,7 @@
 		.page_size	= 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -22864,7 +22864,7 @@
 		.page_size	= 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -22894,7 +22894,7 @@
 		.page_size	= 16384, /* Non-uniform sectors */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -22929,7 +22929,7 @@
 		.page_size	= 16384, /* Non-uniform sectors */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
 		{
@@ -25343,7 +25343,7 @@
 		.page_size	= 128,
 		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,		/* used datasheet for the W29C011A */
 		.block_erasers	=
 		{
@@ -25395,7 +25395,7 @@
 		.page_size	= 128,
 		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -25422,7 +25422,7 @@
 		.page_size	= 256,
 		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -25449,7 +25449,7 @@
 		.page_size	= 128,
 		.feature_bits	= FEATURE_LONG_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -25476,7 +25476,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -25509,7 +25509,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -25539,7 +25539,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -25572,7 +25572,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -25605,7 +25605,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -25635,7 +25635,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -25668,7 +25668,7 @@
 		.page_size	= 128 * 1024, /* actual page size is 16 */
 		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec_29gl,
+		.probe		= probe_buses,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
@@ -25698,7 +25698,7 @@
 		.page_size	= 4 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -25729,7 +25729,7 @@
 		.page_size	= 4 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -25760,7 +25760,7 @@
 		.page_size	= 4 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -25794,7 +25794,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PR,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -25828,7 +25828,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -25859,7 +25859,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -25890,7 +25890,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -25921,7 +25921,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -25956,7 +25956,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -25988,7 +25988,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -26019,7 +26019,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -26050,7 +26050,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -26082,7 +26082,7 @@
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -26113,7 +26113,7 @@
 		.page_size	= 128,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -26148,7 +26148,7 @@
 		.page_size	= 128,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PROBE,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -26175,7 +26175,7 @@
 		.page_size	= 128,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
@@ -26210,7 +26210,7 @@
 		.page_size	= 128,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_OK_PREW,
-		.probe		= probe_jedec,
+		.probe		= probe_buses,
 		.probe_timing	= 10,
 		.block_erasers	=
 		{
diff --git a/include/chipdrivers/memory_bus.h b/include/chipdrivers/memory_bus.h
index 02794ee..6ffa367 100644
--- a/include/chipdrivers/memory_bus.h
+++ b/include/chipdrivers/memory_bus.h
@@ -33,11 +33,12 @@
 int unlock_lh28f008bjt(struct flashprog_flashctx *);
 
 /* jedec.c */
+struct found_id *probe_jedec(const struct bus_probe *, const struct master_common *, const struct flashchip *);
+struct found_id *probe_jedec_29gl(const struct bus_probe *, const struct master_common *, const struct flashchip *);
+
 uint8_t oddparity(uint8_t val);
 void toggle_ready_jedec(const struct flashprog_flashctx *, chipaddr dst);
 void data_polling_jedec(const struct flashprog_flashctx *, chipaddr dst, uint8_t data);
-int probe_jedec(struct flashprog_flashctx *);
-int probe_jedec_29gl(struct flashprog_flashctx *);
 int write_jedec(struct flashprog_flashctx *, const uint8_t *buf, unsigned int start, unsigned int len);
 int write_jedec_1(struct flashprog_flashctx *, const uint8_t *buf, unsigned int start, unsigned int len);
 int erase_sector_jedec(struct flashprog_flashctx *, unsigned int page, unsigned int pagesize);
@@ -96,6 +97,7 @@
 struct memory_chip_info {
 	chipsize_t chip_size;
 	feature_bits_t chip_features;
+	signed int probe_timing;
 };
 
 struct memory_found_id {
diff --git a/jedec.c b/jedec.c
index 7c8434f..3fbfd2b 100644
--- a/jedec.c
+++ b/jedec.c
@@ -20,6 +20,7 @@
  */
 
 #include "flash.h"
+#include "programmer.h"
 #include "chipdrivers/memory_bus.h"
 
 #define MAX_REFLASH_TRIES 0x10
@@ -90,9 +91,9 @@
 		msg_cdbg("%s: excessive loops, i=0x%x\n", __func__, i);
 }
 
-static unsigned int getaddrmask(const struct flashchip *chip)
+static unsigned int getaddrmask_from_features(feature_bits_t chip_features)
 {
-	switch (chip->feature_bits & FEATURE_ADDR_MASK) {
+	switch (chip_features & FEATURE_ADDR_MASK) {
 	case FEATURE_ADDR_FULL:
 		return MASK_FULL;
 		break;
@@ -109,6 +110,11 @@
 	}
 }
 
+static unsigned int getaddrmask(const struct flashprog_flashctx *flash)
+{
+	return getaddrmask_from_features(flash->chip->feature_bits);
+}
+
 static void start_program_jedec_common(const struct flashctx *flash, unsigned int mask)
 {
 	chipaddr bios = flash->virtual_memory;
@@ -119,39 +125,54 @@
 	chip_writeb(flash, 0xA0, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
 }
 
-int probe_jedec_29gl(struct flashctx *flash)
+static struct found_id *probe_jedec_29gl_generic(
+		const struct par_master *const par,
+		const chipsize_t chip_size, const feature_bits_t chip_features)
 {
-	unsigned int mask = getaddrmask(flash->chip);
-	chipaddr bios = flash->virtual_memory;
-	const struct flashchip *chip = flash->chip;
+	const unsigned int mask = getaddrmask_from_features(chip_features);
+	uint8_t raw[4];
+
+	const chipaddr bios = (chipaddr)programmer_map_flash_data(par, chip_size, "");
+	if (bios == (chipaddr)ERROR_PTR)
+		return NULL;
 
 	/* Reset chip to a clean slate */
-	chip_writeb(flash, 0xF0, bios + (0x5555 & mask));
+	par->chip_writeb(par, 0xF0, bios + (0x5555 & mask));
 
 	/* Issue JEDEC Product ID Entry command */
-	chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
-	chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
-	chip_writeb(flash, 0x90, bios + (0x5555 & mask));
+	par->chip_writeb(par, 0xAA, bios + (0x5555 & mask));
+	par->chip_writeb(par, 0x55, bios + (0x2AAA & mask));
+	par->chip_writeb(par, 0x90, bios + (0x5555 & mask));
 
 	/* Read product ID */
 	// FIXME: Continuation loop, second byte is at word 0x100/byte 0x200
-	uint32_t man_id = chip_readb(flash, bios + 0x00);
-	uint32_t dev_id = (chip_readb(flash, bios + 0x01) << 16) |
-			  (chip_readb(flash, bios + 0x0E) <<  8) |
-			  (chip_readb(flash, bios + 0x0F) <<  0);
+	raw[0] = par->chip_readb(par, bios + 0x00);
+	raw[1] = par->chip_readb(par, bios + 0x01);
+	raw[2] = par->chip_readb(par, bios + 0x0E);
+	raw[3] = par->chip_readb(par, bios + 0x0F);
 
 	/* Issue JEDEC Product ID Exit command */
-	chip_writeb(flash, 0xF0, bios + (0x5555 & mask));
+	par->chip_writeb(par, 0xF0, bios + (0x5555 & mask));
 
-	msg_cdbg("%s: man_id 0x%02x, dev_id 0x%06x", __func__, man_id, dev_id);
-	if (!oddparity(man_id))
-		msg_cdbg(", man_id parity violation");
+	const uint32_t man_id = raw[0];
+	const uint32_t dev_id = raw[1] << 16 | raw[2] << 8 | raw[3];
 
 	/* Read the product ID location again. We should now see normal flash contents. */
-	uint32_t flashcontent1 = chip_readb(flash, bios + 0x00); // FIXME: Continuation loop
-	uint32_t flashcontent2 = (chip_readb(flash, bios + 0x01) << 16) |
-				 (chip_readb(flash, bios + 0x0E) <<  8) |
-				 (chip_readb(flash, bios + 0x0F) <<  0);
+	uint32_t flashcontent1 = par->chip_readb(par, bios + 0x00); // FIXME: Continuation loop
+	uint32_t flashcontent2 = (par->chip_readb(par, bios + 0x01) << 16) |
+				 (par->chip_readb(par, bios + 0x0E) <<  8) |
+				 (par->chip_readb(par, bios + 0x0F) <<  0);
+
+	programmer_unmap_flash_region(par, (void *)bios, chip_size);
+
+	if (flashprog_no_data(raw, sizeof(raw)))
+		return NULL;
+
+	msg_cdbg("%s (%uKiB, features: 0x%02x): man_id 0x%02x, dev_id 0x%06x",
+		 __func__, chip_size / KiB, chip_features, man_id, dev_id);
+
+	if (!oddparity(man_id))
+		msg_cdbg(", man_id parity violation");
 
 	if (man_id == flashcontent1)
 		msg_cdbg(", man_id seems to be normal flash content");
@@ -159,33 +180,67 @@
 		msg_cdbg(", dev_id seems to be normal flash content");
 
 	msg_cdbg("\n");
-	if (man_id != chip->id.manufacture || dev_id != chip->id.model)
-		return 0;
 
-	return 1;
+	struct memory_found_id *const found = alloc_memory_found_id();
+	if (!found) {
+		msg_cerr("Out of memory!\n");
+		return NULL;
+	}
+
+	found->generic.info.id.manufacture	= man_id;
+	found->generic.info.id.model		= dev_id;
+	found->generic.info.id.type		= ID_JEDEC_29GL;
+	found->memory_info.chip_size		= chip_size;
+	found->memory_info.chip_features	= chip_features;
+
+	return &found->generic;
 }
 
-static int probe_jedec_common(struct flashctx *flash, unsigned int mask)
+struct found_id *probe_jedec_29gl(const struct bus_probe *probe,
+				  const struct master_common *mst,
+				  const struct flashchip *chip)
 {
-	chipaddr bios = flash->virtual_memory;
-	const struct flashchip *chip = flash->chip;
-	bool shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED);
-	uint8_t id1, id2;
+	const struct par_master *const par = (const struct par_master *)mst;
+	struct found_id *ids = NULL, **next_ptr = &ids;
+	chipsize_t chip_size;
+
+	if (chip)
+		return probe_jedec_29gl_generic(par, chip->total_size * KiB, chip->feature_bits);
+
+	/* XXX: Only limited sizes and single mask supported at this time: */
+	for (chip_size = 16*MiB; chip_size >= 4*MiB; chip_size /= 2) {
+		*next_ptr = probe_jedec_29gl_generic(par, chip_size, FEATURE_ADDR_2AA);
+		if (*next_ptr)
+			next_ptr = &(*next_ptr)->next;
+	}
+
+	return ids;
+}
+
+static struct found_id *probe_jedec_generic(
+		const struct par_master *const par, const chipsize_t chip_size,
+		const feature_bits_t chip_features, const signed int probe_timing)
+{
+	const unsigned int mask = getaddrmask_from_features(chip_features);
+	const bool shifted = (chip_features & FEATURE_ADDR_SHIFTED);
+
+	uint8_t raw[4];
+	unsigned int idx = 0;
 	uint32_t largeid1, largeid2;
 	uint32_t flashcontent1, flashcontent2;
 	unsigned int probe_timing_enter, probe_timing_exit;
 
-	if (chip->probe_timing > 0)
-		probe_timing_enter = probe_timing_exit = chip->probe_timing;
-	else if (chip->probe_timing == TIMING_ZERO) { /* No delay. */
-		probe_timing_enter = probe_timing_exit = 0;
-	} else if (chip->probe_timing == TIMING_FIXME) { /* == _IGNORED */
-		msg_cdbg("Chip lacks correct probe timing information, using default 10ms/40us. ");
+	const chipaddr bios = (chipaddr)programmer_map_flash_data(par, chip_size, "");
+	if (bios == (chipaddr)ERROR_PTR)
+		return NULL;
+
+	if (probe_timing == TIMING_FIXME) {
 		probe_timing_enter = 10000;
 		probe_timing_exit = 40;
+	} else if (probe_timing > 0) {
+		probe_timing_enter = probe_timing_exit = probe_timing;
 	} else {
-		msg_cerr("Chip has negative value in probe_timing, failing without chip access\n");
-		return 0;
+		probe_timing_enter = probe_timing_exit = 0;
 	}
 
 	/* Earlier probes might have been too fast for the chip to enter ID
@@ -195,90 +250,160 @@
 	if (probe_timing_enter)
 		programmer_delay(probe_timing_enter);
 	/* Reset chip to a clean slate */
-	if (chip->feature_bits & FEATURE_LONG_RESET)
+	if (chip_features & FEATURE_LONG_RESET)
 	{
-		chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
+		par->chip_writeb(par, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
 		if (probe_timing_exit)
 			programmer_delay(10);
-		chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
+		par->chip_writeb(par, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
 		if (probe_timing_exit)
 			programmer_delay(10);
 	}
-	chip_writeb(flash, 0xF0, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
+	par->chip_writeb(par, 0xF0, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
 	if (probe_timing_exit)
 		programmer_delay(probe_timing_exit);
 
 	/* Issue JEDEC Product ID Entry command */
-	chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
+	par->chip_writeb(par, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
 	if (probe_timing_enter)
 		programmer_delay(10);
-	chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
+	par->chip_writeb(par, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
 	if (probe_timing_enter)
 		programmer_delay(10);
-	chip_writeb(flash, 0x90, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
+	par->chip_writeb(par, 0x90, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
 	if (probe_timing_enter)
 		programmer_delay(probe_timing_enter);
 
 	/* Read product ID */
-	id1 = chip_readb(flash, bios + (0x00 << shifted));
-	id2 = chip_readb(flash, bios + (0x01 << shifted));
-	largeid1 = id1;
-	largeid2 = id2;
+	largeid1 = raw[idx++] = par->chip_readb(par, bios + (0x00 << shifted));
+	largeid2 = raw[idx++] = par->chip_readb(par, bios + (0x01 << shifted));
 
 	/* Check if it is a continuation ID, this should be a while loop. */
-	if (id1 == 0x7F) {
+	if (largeid1 == 0x7F) {
 		largeid1 <<= 8;
-		id1 = chip_readb(flash, bios + 0x100);
-		largeid1 |= id1;
+		largeid1 |= raw[idx++] = par->chip_readb(par, bios + 0x100);
 	}
-	if (id2 == 0x7F) {
+	if (largeid2 == 0x7F) {
 		largeid2 <<= 8;
-		id2 = chip_readb(flash, bios + 0x101);
-		largeid2 |= id2;
+		largeid2 |= raw[idx++] = par->chip_readb(par, bios + 0x101);
 	}
 
 	/* Issue JEDEC Product ID Exit command */
-	if (chip->feature_bits & FEATURE_LONG_RESET)
+	if (chip_features & FEATURE_LONG_RESET)
 	{
-		chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
+		par->chip_writeb(par, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
 		if (probe_timing_exit)
 			programmer_delay(10);
-		chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
+		par->chip_writeb(par, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
 		if (probe_timing_exit)
 			programmer_delay(10);
 	}
-	chip_writeb(flash, 0xF0, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
+	par->chip_writeb(par, 0xF0, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
 	if (probe_timing_exit)
 		programmer_delay(probe_timing_exit);
 
-	msg_cdbg("%s: id1 0x%02x, id2 0x%02x", __func__, largeid1, largeid2);
-	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));
+	flashcontent1 = par->chip_readb(par, bios + (0x00 << shifted));
+	flashcontent2 = par->chip_readb(par, bios + (0x01 << shifted));
 
 	/* Check if it is a continuation ID, this should be a while loop. */
 	if (flashcontent1 == 0x7F) {
 		flashcontent1 <<= 8;
-		flashcontent1 |= chip_readb(flash, bios + 0x100);
+		flashcontent1 |= par->chip_readb(par, bios + 0x100);
 	}
 	if (flashcontent2 == 0x7F) {
 		flashcontent2 <<= 8;
-		flashcontent2 |= chip_readb(flash, bios + 0x101);
+		flashcontent2 |= par->chip_readb(par, bios + 0x101);
 	}
 
+	programmer_unmap_flash_region(par, (void *)bios, chip_size);
+
+	if (flashprog_no_data(raw, idx))
+		return NULL;
+
+	msg_cdbg("%s (%uKiB, features: 0x%02x): id1 0x%02x, id2 0x%02x",
+		 __func__, chip_size / KiB, chip_features, largeid1, largeid2);
+
+	if (!oddparity(raw[0]))
+		msg_cdbg(", id1 parity violation");
+
 	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->id.manufacture || largeid2 != chip->id.model)
-		return 0;
 
-	return 1;
+	struct memory_found_id *const found = alloc_memory_found_id();
+	if (!found) {
+		msg_cerr("Out of memory!\n");
+		return NULL;
+	}
+
+	found->generic.info.id.manufacture	= largeid1;
+	found->generic.info.id.model		= largeid2;
+	found->generic.info.id.type		= ID_JEDEC;
+	found->memory_info.chip_size		= chip_size;
+	found->memory_info.chip_features	= chip_features;
+	found->memory_info.probe_timing		= probe_timing;
+
+	return &found->generic;
+}
+
+struct found_id *probe_jedec(const struct bus_probe *probe,
+			     const struct master_common *mst,
+			     const struct flashchip *chip)
+{
+	const struct par_master *const par = (const struct par_master *)mst;
+	struct found_id *ids = NULL, **next_ptr = &ids;
+	chipsize_t chip_size;
+	unsigned int set;
+
+	if (chip) {
+		return probe_jedec_generic(par,
+			chip->total_size * KiB, chip->feature_bits, chip->probe_timing);
+	}
+
+	static const struct {
+		feature_bits_t features;
+		signed int probe_timing;
+	} common_sets[] = {
+		{ FEATURE_SHORT_RESET | FEATURE_ADDR_2AA,	TIMING_ZERO },
+		{ FEATURE_LONG_RESET,				      10000 },
+		{ FEATURE_LONG_RESET,					 10 },
+		{ FEATURE_LONG_RESET,					  1 },
+		{ FEATURE_LONG_RESET,				TIMING_ZERO },
+	};
+	for (set = 0; set < ARRAY_SIZE(common_sets); ++set) {
+		for (chip_size = 1*MiB; chip_size >= 64*KiB; chip_size /= 2) {
+			*next_ptr = probe_jedec_generic(par, chip_size,
+				common_sets[set].features, common_sets[set].probe_timing);
+			if (*next_ptr)
+				next_ptr = &(*next_ptr)->next;
+		}
+	}
+
+	static const struct {
+		chipsize_t chip_size;
+		feature_bits_t features;
+		signed int probe_timing;
+	} additional_sets[] = {
+		{   2*MiB, FEATURE_SHORT_RESET,				 TIMING_ZERO },
+		{   2*MiB, FEATURE_LONG_RESET | FEATURE_ADDR_SHIFTED,		  10 },
+		{ 512*KiB, FEATURE_LONG_RESET | FEATURE_ADDR_SHIFTED,		  10 },
+		{ 384*KiB, FEATURE_LONG_RESET,					   1 },
+		{ 256*KiB, FEATURE_LONG_RESET | FEATURE_ADDR_2AA,	TIMING_FIXME },
+		{ 256*KiB, FEATURE_LONG_RESET | FEATURE_ADDR_AAA,	 TIMING_ZERO },
+		{ 128*KiB, FEATURE_SHORT_RESET,				 TIMING_ZERO },
+	};
+	for (set = 0; set < ARRAY_SIZE(additional_sets); ++set) {
+		*next_ptr = probe_jedec_generic(par, additional_sets[set].chip_size,
+			additional_sets[set].features, additional_sets[set].probe_timing);
+		if (*next_ptr)
+			next_ptr = &(*next_ptr)->next;
+	}
+
+	return ids;
 }
 
 static int erase_sector_jedec_common(struct flashctx *flash, unsigned int page,
@@ -414,7 +539,7 @@
 	chipaddr olddst;
 	unsigned int mask;
 
-	mask = getaddrmask(flash->chip);
+	mask = getaddrmask(flash);
 
 	olddst = dst;
 	for (i = 0; i < len; i++) {
@@ -440,7 +565,7 @@
 	chipaddr d = dst;
 	unsigned int mask;
 
-	mask = getaddrmask(flash->chip);
+	mask = getaddrmask(flash);
 
 retry:
 	/* Issue JEDEC Start Program command */
@@ -519,7 +644,7 @@
 {
 	unsigned int mask;
 
-	mask = getaddrmask(flash->chip);
+	mask = getaddrmask(flash);
 	if ((addr != 0) || (blocksize != flash->chip->total_size * 1024)) {
 		msg_cerr("%s called with incorrect arguments\n",
 			__func__);
@@ -528,20 +653,12 @@
 	return erase_chip_jedec_common(flash, mask);
 }
 
-int probe_jedec(struct flashctx *flash)
-{
-	unsigned int mask;
-
-	mask = getaddrmask(flash->chip);
-	return probe_jedec_common(flash, mask);
-}
-
 int erase_sector_jedec(struct flashctx *flash, unsigned int page,
 		       unsigned int size)
 {
 	unsigned int mask;
 
-	mask = getaddrmask(flash->chip);
+	mask = getaddrmask(flash);
 	return erase_sector_jedec_common(flash, page, size, mask);
 }
 
@@ -550,7 +667,7 @@
 {
 	unsigned int mask;
 
-	mask = getaddrmask(flash->chip);
+	mask = getaddrmask(flash);
 	return erase_block_jedec_common(flash, page, size, mask);
 }
 
diff --git a/parallel.c b/parallel.c
index e182394..699ce1a 100644
--- a/parallel.c
+++ b/parallel.c
@@ -78,6 +78,8 @@
 
 static const struct bus_probe memory_probes[] = {
     /* prio. type		function		function argument */
+	{ 0, ID_JEDEC,		probe_jedec,		NULL },
+	{ 0, ID_JEDEC_29GL,	probe_jedec_29gl,	NULL },
 	{ 0, ID_82802AB,	probe_82802ab,		NULL },
 	/* Old Winbond W29* probe method w/ low priority because the
 	   probing sequence puts the AMIC A49LF040A in a funky state. */
@@ -90,6 +92,7 @@
 
 	return	(memcmp(&found->id, &chip->id, sizeof(chip->id)) == 0) &&
 		(probe_info->chip_size == chip->total_size * KiB) &&
+		(!probe_info->probe_timing || probe_info->probe_timing == chip->probe_timing) &&
 		(probe_info->chip_features == (probe_info->chip_features & chip->feature_bits));
 }