libflashprog: Introduce new probing API flashprog_flash_probe_chip()
This new probing API acts about the same as the old one, except that
it accepts a `struct flashprog_chip *` handle instead of a chip name.
Under the hood, however, it uses our new bus probing directly.
We introduce a new function, flashprog_flash_prepare_context(), that
creates a flash context from a probed chip, and the bus it was found
on. This will be the single place that creates flash contexts in the
future.
Change-Id: I1a344aedf573d92f8f297e6eed8daadb511ebc10
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/484
diff --git a/libflashprog.c b/libflashprog.c
index 6cdb135..d32f9bd 100644
--- a/libflashprog.c
+++ b/libflashprog.c
@@ -4,6 +4,8 @@
* Copyright (C) 2012, 2016 secunet Security Networks AG
* (Written by Nico Huber <nico.huber@secunet.com> for secunet)
*
+ * Copyright (C) 2026 Nico Huber <nico.h@gmx.de>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -25,12 +27,15 @@
#include <string.h>
#include <stdarg.h>
+#define flashprog_chip flashchip /* For now, we use direct pointers */
+#include "libflashprog.h" /* to the internal struct flashchip. */
+
#include "flash.h"
#include "fmap.h"
#include "programmer.h"
#include "layout.h"
+#include "hwaccess_physmap.h"
#include "ich_descriptors.h"
-#include "libflashprog.h"
#include "writeprotect.h"
/**
@@ -239,6 +244,101 @@
return ret;
}
+/** @private */
+int flashprog_flash_prepare_context(struct flashprog_flashctx **flashctx,
+ const struct flashprog_programmer *flashprog,
+ const struct master_common *bus,
+ const struct flashchip *chip)
+{
+ if (bus->adapt_voltage) {
+ if (bus->adapt_voltage(bus, chip->voltage.min, chip->voltage.max))
+ return 4;
+ }
+
+ struct flashprog_flashctx *const flash = calloc(1, sizeof(*flash));
+ if (!flash) {
+ msg_gerr("Out of memory!\n");
+ return 1;
+ }
+
+ flash->chip = calloc(1, sizeof(*flash->chip));
+ if (!flash->chip) {
+ msg_gerr("Out of memory!\n");
+ free(flash);
+ return 1;
+ }
+
+ *flash->chip = *chip;
+ flash->mst.common = bus; /* `mst` is a union, so we need only one pointer */
+
+ if (chip->prepare_access && chip->prepare_access(flash, PREPARE_POST_PROBE))
+ goto free_flash;
+
+ /* Fill default layout covering the whole chip. */
+ if (flashprog_layout_new(&flash->default_layout) ||
+ flashprog_layout_add_region(flash->default_layout,
+ 0, flash->chip->total_size * 1024 - 1, "complete flash") ||
+ flashprog_layout_include_region(flash->default_layout, "complete flash"))
+ goto free_flash;
+
+ char *const tmp = flashbuses_to_text(flash->chip->bustype);
+ msg_cinfo("Using %s flash chip \"%s\" (%d kB, %s) ",
+ flash->chip->vendor, flash->chip->name, flash->chip->total_size, tmp);
+ free(tmp);
+ if (strcmp(flashprog->driver->name, "internal") == 0 && flash->physical_memory != 0)
+ msg_cinfo("mapped at physical address 0x%0*" PRIxPTR ".\n",
+ PRIxPTR_WIDTH, flash->physical_memory);
+ else
+ msg_cinfo("on %s.\n", flashprog->driver->name);
+
+ if (flash->chip->printlock)
+ flash->chip->printlock(flash);
+
+ if (flash->chip->finish_access)
+ flash->chip->finish_access(flash);
+
+ *flashctx = flash;
+ return 0;
+
+free_flash:
+ if (flash->chip && flash->chip->finish_access)
+ flash->chip->finish_access(flash);
+ free(flash->chip);
+ free(flash);
+ return 4;
+}
+
+/**
+ * @brief Probe for a specific flash chip.
+ *
+ * Probes for a flash chip and returns a flash context, that can be used
+ * later with flash chip and @ref flashprog-ops "image operations".
+ *
+ * @param[out] flashctx Points to a pointer of type struct flashprog_flashctx
+ * that will be set. *flashctx has to be freed by the
+ * caller with @ref flashprog_flash_release.
+ * @param[in] flashprog The flash programmer used to access the chip.
+ * @param[in] chip A reference to a chip structure that was previously
+ * fetched by @ref flashprog-chips "enumeration". Its
+ * contents will be copied, so the underlying chip
+ * enumeration can be released directly after the call.
+ * @return 0 on success,
+ * 4 if the chip was detected, but preparation failed,
+ * 3 if multiple chips were found,
+ * 2 if no chip was detected,
+ * or 1 on any other error.
+ */
+int flashprog_flash_probe_chip(struct flashprog_flashctx **flashctx,
+ const struct flashprog_programmer *flashprog,
+ const struct flashprog_chip *chip)
+{
+ const struct master_common *const bus = flashprog_chip_probe(flashprog, chip);
+ if (!bus)
+ return 2;
+
+ return flashprog_flash_prepare_context(flashctx, flashprog, bus, chip);
+}
+
/**
* @brief Returns the size of the specified flash chip in bytes.
*