Migrate flashprog_bus_probe() into libflashprog/chip.c

Also move the cleanup of `found_id` structures into a new
flashprog_bus_probe_cleanup(). We clean up locally, right
after matching the IDs against chip entries. This way, we
save us the state tracking in `registered_master`.

Change-Id: Idcd837bd16c743a245a14a6c8f2a7dfca5fe5b42
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/491
diff --git a/libflashprog/chips.c b/libflashprog/chips.c
index 12b4197..018d447 100644
--- a/libflashprog/chips.c
+++ b/libflashprog/chips.c
@@ -58,25 +58,68 @@
 	return 0;
 }
 
-static bool flashprog_bus_match_chip(struct registered_master *bus, const struct flashprog_chip *chip)
+static struct found_id *flashprog_bus_probe(struct registered_master *bus, const struct flashprog_chip *chip)
 {
-	struct found_id *found_id;
-	for (found_id = bus->found_ids; found_id; found_id = found_id->next) {
-		if (found_id->info.id.type != chip->id.type)
-			continue;
+	struct found_id *found_ids = NULL, **next_ptr = &found_ids;
+	unsigned int least_priority, priority, i;
 
-		if (bus->probing.match(chip, &found_id->info))
+	for (i = 0, least_priority = 0; i < bus->probing.probe_count; ++i) {
+		if (least_priority < bus->probing.probes[i].priority)
+			least_priority = bus->probing.probes[i].priority;
+	}
+
+	for (priority = 0; priority <= least_priority; ++priority) {
+		for (i = 0; i < bus->probing.probe_count; ++i) {
+			if (bus->probing.probes[i].priority != priority)
+				continue;
+
+			if (chip && chip->id.type != bus->probing.probes[i].type)
+				continue;
+
+			*next_ptr = bus->probing.probes[i].run(&bus->probing.probes[i], &bus->common, chip);
+
+			/* walk to end in case multiple IDs were found in a single call */
+			while (*next_ptr)
+				next_ptr = &(*next_ptr)->next;
+		}
+
+		/* Skip lower-priority probing if any chip replied. */
+		if (found_ids)
 			break;
 	}
-	return !!found_id;
+
+	return found_ids;
+}
+
+static void flashprog_bus_probe_cleanup(struct found_id *found_ids)
+{
+	struct found_id *next;
+	for (; found_ids; found_ids = next) {
+		next = found_ids->next;
+		free(found_ids);
+	}
+}
+
+static bool flashprog_bus_match_chip(struct registered_master *bus,
+				     const struct found_id *found_ids,
+				     const struct flashprog_chip *chip)
+{
+	for (; found_ids; found_ids = found_ids->next) {
+		if (found_ids->info.id.type != chip->id.type)
+			continue;
+
+		if (bus->probing.match(chip, &found_ids->info))
+			break;
+	}
+	return !!found_ids;
 }
 
 static int flashprog_chips_probe_bus(struct flashprog_chips *chips,
 				     struct registered_master *bus)
 {
-	flashprog_bus_probe(bus, NULL);
+	struct found_id *const found_ids = flashprog_bus_probe(bus, NULL);
+	int chip, ret = 0;
 
-	int chip;
 	for (chip = 0; flashchips[chip].name; ++chip) {
 		/* Ignore generic entries if we already have a match. */
 		if (chips->entries &&
@@ -84,13 +127,14 @@
 		     (flashchips[chip].id.model == GENERIC_DEVICE_ID)))
 			continue;
 
-		if (!flashprog_bus_match_chip(bus, &flashchips[chip]))
+		if (!flashprog_bus_match_chip(bus, found_ids, &flashchips[chip]))
 			continue;
 
 		struct chip_entry *const entry = malloc(sizeof(*entry));
 		if (!entry) {
 			msg_cerr("Out of memory!\n");
-			return 1;
+			ret = 1;
+			break;
 		}
 
 		entry->chip = flashchips[chip];
@@ -100,7 +144,8 @@
 		chips->entries = entry;
 	}
 
-	return 0;
+	flashprog_bus_probe_cleanup(found_ids);
+	return ret;
 }
 
 /** @private */
@@ -128,8 +173,11 @@
 		    bus->common.adapt_voltage(&bus->common, chip->voltage.min, chip->voltage.max))
 			return NULL;
 
-		flashprog_bus_probe(bus, chip);
-		if (flashprog_bus_match_chip(bus, chip))
+		struct found_id *const found_ids = flashprog_bus_probe(bus, chip);
+		const bool match = flashprog_bus_match_chip(bus, found_ids, chip);
+		flashprog_bus_probe_cleanup(found_ids);
+
+		if (match)
 			return &bus->common;
 	}