libflashprog: Start a new API for chip enumeration
For now, allow to query all chips, their vendor, name and size.
There's a tricky optimization coming up: We don't want to allocate
additional memory when enumerating the chip database. But, we also
want to use the same API interface to access information about de-
tected chips, which requires dynamic memory. So we have to handle
these distinct cases explicitly. Where `struct flashprog_chips *`
is used, we set it to the special value `FLASHCHIPS_DB` to denote
the flash database. For `struct flashprog_chip *` pointers, we add
chip_from_db(), which tells us whether the given pointer is within
the database range.
Change-Id: I7ecc12e1b74ca11f2be1b3472d6e470da44bfef1
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/481
diff --git a/libflashprog/chips.c b/libflashprog/chips.c
new file mode 100644
index 0000000..ec4adbc
--- /dev/null
+++ b/libflashprog/chips.c
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the flashprog project.
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdlib.h>
+
+#define flashprog_chip flashchip /* For now, we use direct pointers */
+#include "libflashprog.h" /* to the internal struct flashchip. */
+
+#include "flash.h"
+#include "flashchips.h"
+
+/**
+ * @defgroup flashprog-chips Chip Enumeration
+ * @{
+ */
+
+/* Magic pointer that represents our built in database. */
+#define FLASHCHIPS_DB (struct flashprog_chips *)(uintptr_t)-1
+
+static bool chip_from_db(const struct flashprog_chip *chip) {
+ return flashchips <= chip && chip < flashchips + flashchips_size;
+}
+
+/**
+ * @brief Enumerate the internal chips database.
+ *
+ * @param[out] chips Points to a struct flashprog_chips pointer that gets
+ * set if the enumeration is successful. *chips has to be
+ * freed by the caller with @ref flashprog_chips_release.
+ * @return 0 on success
+ */
+int flashprog_chips_all(struct flashprog_chips **chips) {
+ *chips = FLASHCHIPS_DB;
+ return 0;
+}
+
+/**
+ * @brief Count the chips in an enumeration.
+ *
+ * @return The number of chips.
+ */
+unsigned int flashprog_chips_count(const struct flashprog_chips *chips)
+{
+ unsigned int count = 0;
+ const struct flashprog_chip *chip;
+ for (chip = flashprog_chip_first(chips); chip; chip = flashprog_chip_next(chip))
+ ++count;
+ return count;
+}
+
+/**
+ * @brief Free a set of enumerated chips.
+ *
+ * This also invalidates all references that were acquired via
+ * @ref flashprog_chip_first or @ref flashprog_chip_next from
+ * the given set.
+ *
+ * @param chips Chip enumeration to free.
+ */
+void flashprog_chips_release(struct flashprog_chips *chips)
+{
+ if (chips == FLASHCHIPS_DB)
+ return;
+
+ free(chips);
+}
+
+/**
+ * @brief Starts an iteration over a given set of enumerated chips.
+ *
+ * The referenced chip structure will stay valid until either the iteration
+ * is advanced (@ref flashprog_chip_next) or the provided chips enumeration
+ * is released. Note, each call may allocated additional resources that are
+ * only freed by walking the iteration to its end, or releasing the entire
+ * chips set.
+ *
+ * @param chips A set of enumerated chips.
+ * @return A pointer to the structure of the first chip or NULL if the set is empty.
+ */
+const struct flashprog_chip *flashprog_chip_first(const struct flashprog_chips *chips)
+{
+ if (chips == FLASHCHIPS_DB)
+ return flashchips;
+
+ return NULL;
+}
+
+/**
+ * @brief Iterates to the next chip structure in a set of enumerated chips.
+ *
+ * The referenced chip structure will stay valid until either the iteration
+ * is advanced further or the original chips enumeration is released (cf.
+ * @ref flashprog_chip_first).
+ *
+ * @param chip The previous chip in the enumeration. The referenced
+ * structure will be invalidated by the call.
+ * @return A pointer to the structure of the next chip or NULL if there is none.
+ */
+const struct flashprog_chip *flashprog_chip_next(const struct flashprog_chip *chip)
+{
+ if (chip_from_db(chip)) {
+ for (++chip; chip->name; ++chip) {
+ if (chip->id.manufacture == PROGMANUF_ID)
+ continue;
+ if (chip->id.manufacture == GENERIC_MANUF_ID)
+ continue;
+ if (chip->id.model == GENERIC_DEVICE_ID)
+ continue;
+ return chip;
+ }
+ return NULL;
+ }
+
+ return NULL;
+}
+
+/** @} */ /* end flashprog-chips */
+
+
+/**
+ * @defgroup flashprog-chip Chip Information
+ * @{
+ */
+
+/**
+ * @brief Get the vendor string of a given chip structure.
+ *
+ * @param chip reference to query.
+ * @return Vendor string.
+ */
+const char *flashprog_chip_vendor(const struct flashprog_chip *chip) {
+ return chip->vendor;
+}
+
+/**
+ * @brief Get the name string of a given chip structure.
+ *
+ * @param chip reference to query.
+ * @return Name string.
+ */
+const char *flashprog_chip_name(const struct flashprog_chip *chip) {
+ return chip->name;
+}
+
+/**
+ * @brief Get the size of a given chip in bytes.
+ *
+ * @param chip reference to query.
+ * @return Size in bytes.
+ */
+size_t flashprog_chip_size(const struct flashprog_chip *chip) {
+ return chip->total_size * KiB;
+}
+
+/** @} */ /* end flashprog-chip */