Add infrastructure to probe per bus

Add some infrastructure around per-bus probing functions.  Each function
is provided a private parameter, e.g. the expected length of an ID. This
will allow us to implement probing functions that are only called as of-
ten as necessary. The results will be stored in the `registered_master`
structure, to be compared to database entries later.

The probe_buses() wrapper can be used for chip entries, and allows us to
transition the existing probing functions one by one. Once all functions
have been ported, probe_flash() can be adapted as well and the wrapper
will become obsolete.

Change-Id: I6e82b6d61df50234096ac39acab58a4014203933
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/74899
diff --git a/flashprog.c b/flashprog.c
index 0ab20cb..cf697fb 100644
--- a/flashprog.c
+++ b/flashprog.c
@@ -180,6 +180,15 @@
 		int i = --shutdown_fn_count;
 		ret |= shutdown_fn[i].func(shutdown_fn[i].data);
 	}
+
+	int i;
+	for (i = 0; i < registered_master_count; ++i) {
+		struct found_id *found_id, *next;
+		for (found_id = registered_masters[i].found_ids; found_id; found_id = next) {
+			next = found_id->next;
+			free(found_id);
+		}
+	}
 	registered_master_count = 0;
 
 	return ret;
@@ -619,6 +628,88 @@
 	return 0;
 }
 
+static void probe_bus(struct registered_master *const mst, const enum id_type type)
+{
+	struct found_id **next_ptr;
+	unsigned int i;
+
+	if (mst->probed)
+		return;
+
+	next_ptr = &mst->found_ids;
+	for (i = 0; i < mst->probing.probe_count; ++i) {
+		if (type && type != mst->probing.probes[i].type)
+			continue;
+
+		*next_ptr = mst->probing.probes[i].run(&mst->probing.probes[i], &mst->common);
+
+		/* walk to end in case multiple IDs were found in a single call */
+		while (*next_ptr)
+			next_ptr = &(*next_ptr)->next;
+	}
+
+	mst->probed = true;
+}
+
+static bool chip_on_bus(struct registered_master *const mst, const struct flashprog_chip *const chip)
+{
+	static const char *const id_names[] = {
+		[ID_82802AB]	= "82802AB",
+		[ID_EN29LV640B]	= "EN29LV640B",
+		[ID_JEDEC]	= "JEDEC",
+		[ID_JEDEC_29GL]	= "JEDEC_29GL",
+		[ID_OPAQUE]	= "OPAQUE",
+		[ID_SPI_AT25F]	= "SPI_AT25F",
+		[ID_SPI_RDID]	= "SPI_RDID",
+		[ID_SPI_RDID4]	= "SPI_RDID4",
+		[ID_SPI_REMS]	= "SPI_REMS",
+		[ID_SPI_RES1]	= "SPI_RES1",
+		[ID_SPI_RES2]	= "SPI_RES2",
+		[ID_SPI_RES3]	= "SPI_RES3",
+		[ID_SPI_SFDP]	= "SPI_SFDP",
+		[ID_SPI_ST95]	= "SPI_ST95",
+		[ID_W29EE011]	= "W29EE011",
+		[ID_EDI]	= "EDI",
+	};
+
+	if (chip_to_probe) {
+		/* If we are looking for a particular chip,
+		   limit the probing functions to its type. */
+		probe_bus(mst, chip->id.type);
+	} else {
+		probe_bus(mst, 0);
+	}
+
+	struct found_id *found_id;
+	for (found_id = mst->found_ids; found_id; found_id = found_id->next) {
+		if (found_id->info.id.type != chip->id.type)
+			continue;
+
+		if (found_id->info.id.type < ARRAY_SIZE(id_names))
+			msg_cdbg("%s: id1 0x%02x, id2 0x%02x ",
+				 id_names[found_id->info.id.type],
+				 found_id->info.id.id1, found_id->info.id.id2);
+
+		if (mst->probing.match(chip, &found_id->info))
+			break;
+	}
+
+	msg_cdbg("\n");
+	return !!found_id;
+}
+
+/* wrapper that's used until all probing functions are ported to per-bus probing */
+int probe_buses(struct flashctx *const flash)
+{
+	int i;
+	for (i = 0; i < registered_master_count; ++i) {
+		if (flash->mst.common == &registered_masters[i].common &&
+		    chip_on_bus(&registered_masters[i], flash->chip))
+			return 1;
+	}
+	return 0;
+}
+
 int probe_flash(struct registered_master *mst, int startchip, struct flashctx *flash, int force)
 {
 	const struct flashchip *chip;
diff --git a/helpers.c b/helpers.c
index 5f2b02d..b892c20 100644
--- a/helpers.c
+++ b/helpers.c
@@ -20,6 +20,26 @@
 #include <string.h>
 #include "flash.h"
 
+/* Check if raw data is all 0 or all 1. */
+bool flashprog_no_data(const void *const raw_data, const size_t len)
+{
+	const uint8_t *const raw_end = (const uint8_t *)raw_data + len;
+	const uint8_t patterns[] = { 0x00, 0xff };
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(patterns); ++i) {
+		const uint8_t *raw_ptr;
+		for (raw_ptr = raw_data; raw_ptr < raw_end; ++raw_ptr) {
+			if (*raw_ptr != patterns[i])
+				break;
+		}
+		if (raw_ptr == raw_end)
+			return true;
+	}
+
+	return false;
+}
+
 int flashprog_read_chunked(struct flashctx *const flash, uint8_t *dst, unsigned int start, unsigned int len,
 			   unsigned int chunksize, readfunc_t *const read)
 {
diff --git a/include/chipdrivers/probing.h b/include/chipdrivers/probing.h
index 7563f74..fefca3c 100644
--- a/include/chipdrivers/probing.h
+++ b/include/chipdrivers/probing.h
@@ -17,6 +17,7 @@
 #ifndef __PROBING_H__
 #define __PROBING_H__ 1
 
+#include <stddef.h>
 #include <stdint.h>
 
 enum id_type {
@@ -47,9 +48,43 @@
  * Identification code.
  */
 struct id_info {
-	uint32_t manufacture;
-	uint32_t model;
+	union {
+		uint32_t manufacture;
+		uint32_t id1;
+	};
+	union {
+		uint32_t model;
+		uint32_t id2;
+	};
 	enum id_type type;
 };
 
+struct id_info_ext {
+	struct id_info id;
+	void *ext;
+};
+
+struct found_id {
+	struct found_id *next;
+	struct id_info_ext info;
+};
+
+struct flashprog_chip;
+struct master_common;
+
+struct bus_probe {
+	enum id_type type;
+	struct found_id *(*run)(const struct bus_probe *, const struct master_common *);
+	void *arg;
+};
+
+struct bus_probing {
+	unsigned int probe_count;
+	const struct bus_probe *probes;
+	bool (*match)(const struct flashprog_chip *, const struct id_info_ext *);
+};
+
+struct flashprog_flashctx;
+int probe_buses(struct flashprog_flashctx *);
+
 #endif /* !__PROBING_H__ */
diff --git a/include/flash.h b/include/flash.h
index 60e35d0..c4d9040 100644
--- a/include/flash.h
+++ b/include/flash.h
@@ -243,7 +243,8 @@
 	PREPARE_FULL,
 };
 
-struct flashchip {
+#define flashchip flashprog_chip
+struct flashprog_chip {
 	const char *vendor;
 	const char *name;
 
@@ -505,6 +506,7 @@
 void print_supported_wiki(void);
 
 /* helpers.c */
+bool flashprog_no_data(const void *raw_data, size_t);
 int flashprog_read_chunked(struct flashctx *, uint8_t *dst, unsigned int start, unsigned int len, unsigned int chunksize, readfunc_t *);
 uint32_t address_to_bits(uint32_t addr);
 unsigned int bitcount(unsigned long a);
diff --git a/include/programmer.h b/include/programmer.h
index 5cef491..46b50f1 100644
--- a/include/programmer.h
+++ b/include/programmer.h
@@ -474,6 +474,11 @@
 struct registered_master {
 	size_t max_rom_decode;
 	enum chipbustype buses_supported;
+
+	struct bus_probing probing;
+	struct found_id *found_ids;
+	bool probed;
+
 	union {
 		struct master_common common;
 		struct par_master par;
diff --git a/opaque.c b/opaque.c
index eacc09f..f03b70a 100644
--- a/opaque.c
+++ b/opaque.c
@@ -48,7 +48,7 @@
 
 int register_opaque_master(const struct opaque_master *mst, void *data)
 {
-	struct registered_master rmst;
+	struct registered_master rmst = { 0 };
 
 	if (mst->shutdown) {
 		if (register_shutdown(mst->shutdown, data)) {
diff --git a/parallel.c b/parallel.c
index abed345..5746862 100644
--- a/parallel.c
+++ b/parallel.c
@@ -66,7 +66,7 @@
 int register_par_master(const struct par_master *mst, const enum chipbustype buses,
 			const size_t max_rom_decode, void *data)
 {
-	struct registered_master rmst;
+	struct registered_master rmst = { 0 };
 
 	if (mst->shutdown) {
 		if (register_shutdown(mst->shutdown, data)) {
diff --git a/spi.c b/spi.c
index 9f8fb89..6f77e5c 100644
--- a/spi.c
+++ b/spi.c
@@ -163,7 +163,7 @@
 
 int register_spi_master(const struct spi_master *mst, size_t max_rom_decode, void *data)
 {
-	struct registered_master rmst;
+	struct registered_master rmst = { 0 };
 
 	if (mst->shutdown) {
 		if (register_shutdown(mst->shutdown, data)) {