libflashprog: Allow to query bus types, voltage, and test status

This is mostly an export of the long stable internal structures. We do
some renames, though,  and provide the voltage range as floating point
numbers. While we are at it, also rename:
* flashprog_test_status.wp      => .block_protection,
* BUS_PROG                      => BUS_OPAQUE,
* BUS_NONSPI                    => BUS_PRESPI.
The last one is a pseudonym for the older, memory-mapped buses, and
doesn't include BUS_OPAQUE.

Also try to name the captured test state consistently, either `tested`
or `status`.

Change-Id: Ibefb923fa5f566daa804651aa1a9bfe5602ca364
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/482
diff --git a/amd_rom3read.c b/amd_rom3read.c
index ad03fb7..98ba5d2 100644
--- a/amd_rom3read.c
+++ b/amd_rom3read.c
@@ -71,8 +71,8 @@
 
 	flash->chip->total_size = flash_size / KiB;
 	flash->chip->feature_bits |= FEATURE_NO_ERASE;
-	flash->chip->tested =
-		(struct tested){ .probe = OK, .read = OK, .erase = NA, .write = NA, .wp = NA };
+	flash->chip->tested = (struct flashprog_test_status)
+		{ .probe = OK, .read = OK, .erase = NA, .write = NA, .block_protection = NA };
 
 	return !!flash->chip->total_size;
 }
diff --git a/chipset_enable.c b/chipset_enable.c
index 6e8d723..2953c4b 100644
--- a/chipset_enable.c
+++ b/chipset_enable.c
@@ -1517,7 +1517,7 @@
 		return ERROR_FATAL;
 
 	/* Our best guess */
-	internal_buses_supported &= ~BUS_NONSPI;
+	internal_buses_supported &= ~BUS_PRESPI;
 	/* Suppress unknown laptop warning with non-SPI buses disabled. */
 	laptop_ok = true;
 
@@ -1554,7 +1554,7 @@
 	const bool spirom_enable = spibar & BIT(1);
 	if (spirom_enable) {
 		/* If SPI ROM is memory mapped, nothing else can be */
-		internal_buses_supported &= ~BUS_NONSPI;
+		internal_buses_supported &= ~BUS_PRESPI;
 		/* Suppress unknown laptop warning with non-SPI buses disabled. */
 		laptop_ok = true;
 	}
@@ -1907,8 +1907,8 @@
 #define ANY_REV	false, 0x00
 
 #define B_P	(BUS_PARALLEL)
-#define B_PFL	(BUS_NONSPI)
-#define B_PFLS	(BUS_NONSPI | BUS_SPI)
+#define B_PFL	(BUS_PRESPI)
+#define B_PFLS	(BUS_PRESPI | BUS_SPI)
 #define B_FL	(BUS_FWH | BUS_LPC)
 #define B_FLS	(BUS_FWH | BUS_LPC | BUS_SPI)
 #define B_FS	(BUS_FWH | BUS_SPI)
diff --git a/dummyflasher.c b/dummyflasher.c
index b9357ea..ca2a6a8 100644
--- a/dummyflasher.c
+++ b/dummyflasher.c
@@ -516,9 +516,9 @@
 		free(data);
 		return 1;
 	}
-	if (dummy_buses_supported & BUS_NONSPI)
+	if (dummy_buses_supported & BUS_PRESPI)
 		ret |= register_par_master(&par_master_dummyflasher,
-					   dummy_buses_supported & BUS_NONSPI,
+					   dummy_buses_supported & BUS_PRESPI,
 					   0, 0, data);
 	if (dummy_buses_supported & BUS_SPI)
 		ret |= register_spi_master(&spi_master_dummyflasher, 0, data);
diff --git a/flashchips.c b/flashchips.c
index 6987de8..e38f5e4 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -26750,7 +26750,7 @@
 	{
 		.vendor		= "Programmer",
 		.name		= "Opaque flash chip",
-		.bustype	= BUS_PROG,
+		.bustype	= BUS_OPAQUE,
 		.id.type	= ID_OPAQUE,
 		.id.manufacture	= PROGMANUF_ID,
 		.id.model	= PROGDEV_ID,
diff --git a/flashprog.c b/flashprog.c
index 2c27eb5..d042c58 100644
--- a/flashprog.c
+++ b/flashprog.c
@@ -584,7 +584,7 @@
 	 * FIXME: Once all chipsets and flash chips have been updated, NONSPI
 	 * will cease to exist and should be eliminated here as well.
 	 */
-	if (bustype == BUS_NONSPI) {
+	if (bustype == BUS_PRESPI) {
 		ret = strcat_realloc(ret, "Non-SPI, ");
 	} else {
 		if (bustype & BUS_PARALLEL)
@@ -595,7 +595,7 @@
 			ret = strcat_realloc(ret, "FWH, ");
 		if (bustype & BUS_SPI)
 			ret = strcat_realloc(ret, "SPI, ");
-		if (bustype & BUS_PROG)
+		if (bustype & BUS_OPAQUE)
 			ret = strcat_realloc(ret, "Programmer-specific, ");
 		if (bustype == BUS_NONE)
 			ret = strcat_realloc(ret, "None, ");
diff --git a/include/flash.h b/include/flash.h
index 75c0250..3ad9d1f 100644
--- a/include/flash.h
+++ b/include/flash.h
@@ -61,15 +61,14 @@
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
-enum chipbustype {
-	BUS_NONE	= 0,
-	BUS_PARALLEL	= 1 << 0,
-	BUS_LPC		= 1 << 1,
-	BUS_FWH		= 1 << 2,
-	BUS_SPI		= 1 << 3,
-	BUS_PROG	= 1 << 4,
-	BUS_NONSPI	= BUS_PARALLEL | BUS_LPC | BUS_FWH,
-};
+#define chipbustype	flashprog_bus_type
+#define BUS_NONE	0
+#define BUS_PARALLEL	FLASHPROG_BUS_PARALLEL
+#define BUS_LPC		FLASHPROG_BUS_LPC
+#define BUS_FWH		FLASHPROG_BUS_FWH
+#define BUS_SPI		FLASHPROG_BUS_SPI
+#define BUS_OPAQUE	FLASHPROG_BUS_OPAQUE
+#define BUS_PRESPI	(BUS_PARALLEL | BUS_LPC | BUS_FWH)
 
 /*
  * The following enum defines possible write granularities of flash chips. These tend to reflect the properties
@@ -181,27 +180,36 @@
 
 #define ERASED_VALUE(flash)	(((flash)->chip->feature_bits & FEATURE_ERASED_ZERO) ? 0x00 : 0xff)
 
-enum test_state {
-	OK = 0,
-	NT = 1,	/* Not tested */
-	BAD,	/* Known to not work */
-	DEP,	/* Support depends on configuration (e.g. Intel flash descriptor) */
-	NA,	/* Not applicable (e.g. write support on ROM chips) */
-};
+#define OK   FLASHPROG_TEST_OK
+#define NT   FLASHPROG_TEST_NT
+#define BAD  FLASHPROG_TEST_BAD
+#define DEP  FLASHPROG_TEST_DEP
+#define NA   FLASHPROG_TEST_NA
 
-#define TEST_UNTESTED	(struct tested){ .probe = NT, .read = NT, .erase = NT, .write = NT, .wp = NT }
+#define TEST_UNTESTED	(struct flashprog_test_status) \
+			{ .probe = NT, .read = NT, .erase = NT, .write = NT, .block_protection = NT }
 
-#define TEST_OK_PROBE	(struct tested){ .probe = OK, .read = NT, .erase = NT, .write = NT, .wp = NT }
-#define TEST_OK_PR	(struct tested){ .probe = OK, .read = OK, .erase = NT, .write = NT, .wp = NT }
-#define TEST_OK_PRE	(struct tested){ .probe = OK, .read = OK, .erase = OK, .write = NT, .wp = NT }
-#define TEST_OK_PREW	(struct tested){ .probe = OK, .read = OK, .erase = OK, .write = OK, .wp = NT }
-#define TEST_OK_PREWB	(struct tested){ .probe = OK, .read = OK, .erase = OK, .write = OK, .wp = OK }
+#define TEST_OK_PROBE	(struct flashprog_test_status) \
+			{ .probe = OK, .read = NT, .erase = NT, .write = NT, .block_protection = NT }
+#define TEST_OK_PR	(struct flashprog_test_status) \
+			{ .probe = OK, .read = OK, .erase = NT, .write = NT, .block_protection = NT }
+#define TEST_OK_PRE	(struct flashprog_test_status) \
+			{ .probe = OK, .read = OK, .erase = OK, .write = NT, .block_protection = NT }
+#define TEST_OK_PREW	(struct flashprog_test_status) \
+			{ .probe = OK, .read = OK, .erase = OK, .write = OK, .block_protection = NT }
+#define TEST_OK_PREWB	(struct flashprog_test_status) \
+			{ .probe = OK, .read = OK, .erase = OK, .write = OK, .block_protection = OK }
 
-#define TEST_BAD_PROBE	(struct tested){ .probe = BAD, .read = NT, .erase = NT, .write = NT, .wp = NT }
-#define TEST_BAD_PR	(struct tested){ .probe = BAD, .read = BAD, .erase = NT, .write = NT, .wp = NT }
-#define TEST_BAD_PRE	(struct tested){ .probe = BAD, .read = BAD, .erase = BAD, .write = NT, .wp = NT }
-#define TEST_BAD_PREW	(struct tested){ .probe = BAD, .read = BAD, .erase = BAD, .write = BAD, .wp = NT }
-#define TEST_BAD_PREWB	(struct tested){ .probe = BAD, .read = BAD, .erase = BAD, .write = BAD, .wp = BAD }
+#define TEST_BAD_PROBE	(struct flashprog_test_status) \
+			{ .probe = BAD, .read = NT, .erase = NT, .write = NT, .block_protection = NT }
+#define TEST_BAD_PR	(struct flashprog_test_status) \
+			{ .probe = BAD, .read = BAD, .erase = NT, .write = NT, .block_protection = NT }
+#define TEST_BAD_PRE	(struct flashprog_test_status) \
+			{ .probe = BAD, .read = BAD, .erase = BAD, .write = NT, .block_protection = NT }
+#define TEST_BAD_PREW	(struct flashprog_test_status) \
+			{ .probe = BAD, .read = BAD, .erase = BAD, .write = BAD, .block_protection = NT }
+#define TEST_BAD_PREWB	(struct flashprog_test_status) \
+			{ .probe = BAD, .read = BAD, .erase = BAD, .write = BAD, .block_protection = BAD }
 
 struct flashprog_flashctx;
 #define flashctx flashprog_flashctx /* TODO: Agree on a name and convert all occurrences. */
@@ -258,13 +266,7 @@
 	feature_bits_t feature_bits;
 
 	/* Indicate how well flashprog supports different operations of this flash chip. */
-	struct tested {
-		enum test_state probe;
-		enum test_state read;
-		enum test_state erase;
-		enum test_state write;
-		enum test_state wp;
-	} tested;
+	struct flashprog_test_status tested;
 
 	/*
 	 * Group chips that have common command sets. This should ensure that
diff --git a/include/libflashprog.h b/include/libflashprog.h
index 1f46be1..eec69ee 100644
--- a/include/libflashprog.h
+++ b/include/libflashprog.h
@@ -64,6 +64,60 @@
 __attribute__((nonnull))
 size_t flashprog_chip_size(const struct flashprog_chip *);
 
+/**
+ * @brief Bit masks that represent supported bus types.
+ * @ingroup flashprog-chip
+ */
+enum flashprog_bus_type {
+	FLASHPROG_BUS_PARALLEL	= 1 << 0, /**< Parallel flash chip */
+	FLASHPROG_BUS_LPC	= 1 << 1, /**< Low Pin Count (LPC) flash */
+	FLASHPROG_BUS_FWH	= 1 << 2, /**< Firmware Hub (FWH) flash */
+	FLASHPROG_BUS_SPI	= 1 << 3, /**< Serial Peripheral Interface (SPI) flash */
+	FLASHPROG_BUS_OPAQUE	= 1 << 4, /**< Chip behind an opaque bus interface */
+};
+__attribute__((nonnull))
+enum flashprog_bus_type flashprog_chip_buses(const struct flashprog_chip *);
+__attribute__((nonnull))
+char *flashprog_chip_bus_names(const struct flashprog_chip *);
+
+/**
+ * @brief Documents the minimal and maximal operating voltage for a chip.
+ * @ingroup flashprog-chip
+ */
+struct flashprog_voltage_range {
+	float min; /**< Lowest operating voltage */
+	float max; /**< Highest operating voltage */
+};
+__attribute__((nonnull))
+struct flashprog_voltage_range flashprog_chip_voltage_range(const struct flashprog_chip *);
+
+/**
+ * @brief Documents the test status of a chip operation.
+ * @ingroup flashprog-chip
+ */
+enum flashprog_test_state {
+	FLASHPROG_TEST_OK = 0,	/**< Tested positively */
+	FLASHPROG_TEST_NT = 1,	/**< Not tested */
+	FLASHPROG_TEST_BAD,	/**< Known to not work */
+	FLASHPROG_TEST_DEP,	/**< Support depends on configuration (e.g. Intel flash descriptor) */
+	FLASHPROG_TEST_NA,	/**< Not applicable (e.g. write support on ROM chips) */
+};
+/**
+ * @brief Documents the test status of various chip operations.
+ * @ingroup flashprog-chip
+ */
+struct flashprog_test_status {
+	enum flashprog_test_state probe:3;		/**< Test status for probing. */
+	enum flashprog_test_state read:3;		/**< Test status for reading. */
+	enum flashprog_test_state erase:3;		/**< Test status for erasing. */
+	enum flashprog_test_state write:3;		/**< Test status for writing. */
+	enum flashprog_test_state block_protection:3;	/**< Test status for block-protection configuration. */
+	enum flashprog_test_state :3, :3, :3, :3, :3, :3, :3, :3, :3, :3, reserved:3;
+	/* XXX: Used as return value. Consider ABI compatibility when extending. */
+};
+__attribute__((nonnull))
+struct flashprog_test_status flashprog_chip_test_status(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/include/programmer.h b/include/programmer.h
index 88a7047..31c95f7 100644
--- a/include/programmer.h
+++ b/include/programmer.h
@@ -36,7 +36,7 @@
 struct dev_entry {
 	uint16_t vendor_id;
 	uint16_t device_id;
-	const enum test_state status;
+	const enum flashprog_test_state status;
 	const char *vendor_name;
 	const char *device_name;
 };
@@ -142,7 +142,7 @@
 	bool match_revision;
 	uint8_t revision_id;
 	enum chipbustype buses;
-	const enum test_state status;
+	const enum flashprog_test_state status;
 	const char *vendor_name;
 	const char *device_name;
 	int (*doit) (struct flashprog_programmer *, struct pci_dev *, const char *name);
@@ -184,7 +184,7 @@
 	const char *board_name;
 
 	int max_rom_decode_parallel;
-	const enum test_state status;
+	const enum flashprog_test_state status;
 	int (*enable) (struct flashprog_programmer *); /* May be NULL. */
 };
 
@@ -193,7 +193,7 @@
 struct board_info {
 	const char *vendor;
 	const char *name;
-	const enum test_state working;
+	const enum flashprog_test_state working;
 #ifdef CONFIG_PRINT_WIKI
 	const char *url;
 	const char *note;
diff --git a/internal.c b/internal.c
index 7f9713a..4c2a28b 100644
--- a/internal.c
+++ b/internal.c
@@ -187,7 +187,7 @@
 	 * is found, the host controller init routine sets the
 	 * internal_buses_supported bitfield.
 	 */
-	internal_buses_supported = BUS_NONSPI;
+	internal_buses_supported = BUS_PRESPI;
 
 	if (try_mtd(prog) == 0) {
 		ret = 0;
@@ -277,7 +277,7 @@
 	}
 #endif
 
-	if (internal_buses_supported & BUS_NONSPI) {
+	if (internal_buses_supported & BUS_PRESPI) {
 		register_par_master(&par_master_internal, internal_buses_supported,
 				    internal->rom_base, internal->max_rom_decode, NULL);
 	}
diff --git a/libflashprog.map b/libflashprog.map
index c13f7e4..709db87 100644
--- a/libflashprog.map
+++ b/libflashprog.map
@@ -1,10 +1,14 @@
 LIBFLASHPROG_1.0 {
   global:
+    flashprog_chip_bus_names;
+    flashprog_chip_buses;
     flashprog_chip_first;
     flashprog_chip_name;
     flashprog_chip_next;
     flashprog_chip_size;
+    flashprog_chip_test_status;
     flashprog_chip_vendor;
+    flashprog_chip_voltage_range;
     flashprog_chips_all;
     flashprog_chips_count;
     flashprog_chips_release;
diff --git a/libflashprog/chips.c b/libflashprog/chips.c
index ec4adbc..0b43e6f 100644
--- a/libflashprog/chips.c
+++ b/libflashprog/chips.c
@@ -165,4 +165,50 @@
 	return chip->total_size * KiB;
 }
 
+/**
+ * @brief Get a bit mask of the supported bus types.
+ *
+ * @param chip reference to query.
+ * @return bit mask of supported bus types.
+ */
+enum flashprog_bus_type flashprog_chip_buses(const struct flashprog_chip *chip) {
+	return chip->bustype;
+}
+
+/**
+ * @brief Get a string that lists the supported bus types.
+ *
+ * The resulting string needs to be freed with free().
+ *
+ * @param chip reference to query.
+ * @return comma-separated string of supported bus types.
+ */
+char *flashprog_chip_bus_names(const struct flashprog_chip *chip) {
+	return flashbuses_to_text(chip->bustype);
+}
+
+/**
+ * @brief Get the supported operating voltage range.
+ *
+ * @param chip reference to query.
+ * @return supported operating voltage range.
+ */
+struct flashprog_voltage_range flashprog_chip_voltage_range(const struct flashprog_chip *chip)
+{
+	return (struct flashprog_voltage_range) {
+		.min = chip->voltage.min / 1000.f,
+		.max = chip->voltage.max / 1000.f,
+	};
+}
+
+/**
+ * @brief Get the test status of a chip's standard features.
+ *
+ * @param chip reference to query.
+ * @return struct with the test status of the chip's standard features.
+ */
+struct flashprog_test_status flashprog_chip_test_status(const struct flashprog_chip *chip) {
+	return chip->tested;
+}
+
 /** @} */ /* end flashprog-chip */
diff --git a/opaque.c b/opaque.c
index 7a11b90..6db03cc 100644
--- a/opaque.c
+++ b/opaque.c
@@ -96,7 +96,7 @@
 			 __func__);
 		return ERROR_FLASHPROG_BUG;
 	}
-	rmst.buses_supported = BUS_PROG;
+	rmst.buses_supported = BUS_OPAQUE;
 	rmst.probing.probe_count = ARRAY_SIZE(opaque_probes);
 	rmst.probing.probes = opaque_probes;
 	rmst.probing.match = opaque_probe_match;
diff --git a/print.c b/print.c
index 79d585b..cee7ab5 100644
--- a/print.c
+++ b/print.c
@@ -113,7 +113,7 @@
 	msg_ginfo("\n");
 }
 
-static const char *test_state_to_text(enum test_state test_state)
+static const char *test_state_to_text(enum flashprog_test_state test_state)
 {
 	switch (test_state) {
 	case OK: return "OK";
diff --git a/print_wiki.c b/print_wiki.c
index 5c36588..52536a8 100644
--- a/print_wiki.c
+++ b/print_wiki.c
@@ -115,8 +115,8 @@
 
 /* The output of this module relies on MediaWiki templates to select special formatting styles for table cells
  * reflecting the test status of the respective hardware. This functions returns the correct template name for
- * the supplied enum test_state. */
-static const char *test_state_to_template(enum test_state test_state)
+ * the supplied enum flashprog_test_state. */
+static const char *test_state_to_template(enum flashprog_test_state test_state)
 {
 	switch (test_state) {
 	case OK: return "OK";
diff --git a/rayer_spi.c b/rayer_spi.c
index 30577ac..718c53d 100644
--- a/rayer_spi.c
+++ b/rayer_spi.c
@@ -38,7 +38,7 @@
 
 struct rayer_programmer {
 	const char *type;
-	const enum test_state status;
+	const enum flashprog_test_state status;
 	const char *description;
 	const void *dev_data;
 };
diff --git a/serprog.c b/serprog.c
index a596966..674d029 100644
--- a/serprog.c
+++ b/serprog.c
@@ -518,7 +518,7 @@
 	 */
 	if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) {
 		msg_pwarn("Warning: NAK to query supported buses\n");
-		c = BUS_NONSPI;	/* A reasonable default for now. */
+		c = BUS_PRESPI;	/* A reasonable default for now. */
 	}
 	serprog_buses_supported = c;
 
@@ -639,7 +639,7 @@
 			goto init_err_cleanup_exit;
 	}
 
-	if (serprog_buses_supported & BUS_NONSPI) {
+	if (serprog_buses_supported & BUS_PRESPI) {
 		if (sp_check_commandavail(S_CMD_O_INIT) == 0) {
 			msg_perr("Error: Initialize operation buffer "
 				 "not supported\n");
@@ -760,8 +760,8 @@
 		goto init_err_cleanup_exit;
 	if (serprog_buses_supported & BUS_SPI)
 		register_spi_master(&spi_master_serprog, 0, NULL);
-	if (serprog_buses_supported & BUS_NONSPI)
-		register_par_master(&par_master_serprog, serprog_buses_supported & BUS_NONSPI, 0, 0, NULL);
+	if (serprog_buses_supported & BUS_PRESPI)
+		register_par_master(&par_master_serprog, serprog_buses_supported & BUS_PRESPI, 0, 0, NULL);
 	return 0;
 
 init_err_cleanup_exit: