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/Doxyfile b/Doxyfile
index 5fdf5e8..c0c3528 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -780,8 +780,9 @@
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
-INPUT = libflashprog.c \
- libflashprog.h \
+INPUT = include/libflashprog.h \
+ libflashprog.c \
+ libflashprog/ \
flashprog.c \
layout.c \
@@ -808,7 +809,7 @@
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
-FILE_PATTERNS =
+FILE_PATTERNS = *.c
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
diff --git a/Makefile b/Makefile
index 11eb07b..7d6e668 100644
--- a/Makefile
+++ b/Makefile
@@ -400,8 +400,10 @@
###############################################################################
# Library code.
-LIB_OBJS = libflashprog.o layout.o flashprog.o udelay.o parallel.o programmer.o programmer_table.o \
- helpers.o helpers_fileio.o ich_descriptors.o fmap.o platform/endian_$(ENDIAN).o platform/memaccess.o
+LIB_OBJS = libflashprog.o libflashprog/chips.o layout.o flashprog.o udelay.o \
+ parallel.o programmer.o programmer_table.o \
+ helpers.o helpers_fileio.o ich_descriptors.o fmap.o \
+ platform/endian_$(ENDIAN).o platform/memaccess.o
###############################################################################
diff --git a/include/libflashprog.h b/include/libflashprog.h
index e1d4d80..1f46be1 100644
--- a/include/libflashprog.h
+++ b/include/libflashprog.h
@@ -45,6 +45,25 @@
int flashprog_programmer_init(struct flashprog_programmer **, const char *prog_name, const char *prog_params);
int flashprog_programmer_shutdown(struct flashprog_programmer *);
+struct flashprog_chips;
+__attribute__((nonnull))
+int flashprog_chips_all(struct flashprog_chips **);
+__attribute__((nonnull))
+unsigned int flashprog_chips_count(const struct flashprog_chips *);
+void flashprog_chips_release(struct flashprog_chips *);
+
+struct flashprog_chip;
+__attribute__((nonnull))
+const struct flashprog_chip *flashprog_chip_first(const struct flashprog_chips *);
+__attribute__((nonnull))
+const struct flashprog_chip *flashprog_chip_next(const struct flashprog_chip *);
+__attribute__((nonnull))
+const char *flashprog_chip_vendor(const struct flashprog_chip *);
+__attribute__((nonnull))
+const char *flashprog_chip_name(const struct flashprog_chip *);
+__attribute__((nonnull))
+size_t flashprog_chip_size(const struct flashprog_chip *);
+
struct flashprog_flashctx;
int flashprog_flash_probe(struct flashprog_flashctx **, const struct flashprog_programmer *, const char *chip_name);
size_t flashprog_flash_getsize(const struct flashprog_flashctx *);
diff --git a/libflashprog.c b/libflashprog.c
index 9c28eff..7e2cea1 100644
--- a/libflashprog.c
+++ b/libflashprog.c
@@ -100,17 +100,6 @@
/**
- * @defgroup flashprog-query Querying
- * @{
- */
-
-/* TBD */
-
-/** @} */ /* end flashprog-query */
-
-
-
-/**
* @defgroup flashprog-prog Programmers
* @{
*/
diff --git a/libflashprog.map b/libflashprog.map
index a0dd125..c13f7e4 100644
--- a/libflashprog.map
+++ b/libflashprog.map
@@ -1,5 +1,13 @@
LIBFLASHPROG_1.0 {
global:
+ flashprog_chip_first;
+ flashprog_chip_name;
+ flashprog_chip_next;
+ flashprog_chip_size;
+ flashprog_chip_vendor;
+ flashprog_chips_all;
+ flashprog_chips_count;
+ flashprog_chips_release;
flashprog_flag_get;
flashprog_flag_set;
flashprog_flash_erase;
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 */
diff --git a/meson.build b/meson.build
index 9e996e9..2b40d52 100644
--- a/meson.build
+++ b/meson.build
@@ -60,6 +60,7 @@
'jedec.c',
'layout.c',
'libflashprog.c',
+ 'libflashprog/chips.c',
'm28f.c',
'memory_bus.c',
'opaque.c',