blob: ac5cdc21cbfa7c0a315e969aeb6a67959ebd9a49 [file] [log] [blame]
Nico Huber48d4a042026-03-08 16:07:28 +01001/*
2 * This file is part of the flashprog project.
3 *
4 * Copyright (C) 2026 Nico Huber <nico.h@gmx.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <stdlib.h>
18
19#define flashprog_chip flashchip /* For now, we use direct pointers */
20#include "libflashprog.h" /* to the internal struct flashchip. */
21
22#include "flash.h"
23#include "flashchips.h"
Nico Huberd9301142026-03-08 21:19:27 +010024#include "programmer.h"
Nico Huber48d4a042026-03-08 16:07:28 +010025
26/**
27 * @defgroup flashprog-chips Chip Enumeration
28 * @{
29 */
30
31/* Magic pointer that represents our built in database. */
32#define FLASHCHIPS_DB (struct flashprog_chips *)(uintptr_t)-1
33
Nico Huberd9301142026-03-08 21:19:27 +010034/** @private */
35struct flashprog_chips {
36 /** @private */
37 struct chip_entry {
38 struct flashprog_chip chip;
39 const struct master_common *bus;
40 struct chip_entry *next;
41 } *entries;
42};
43
Nico Huber48d4a042026-03-08 16:07:28 +010044static bool chip_from_db(const struct flashprog_chip *chip) {
45 return flashchips <= chip && chip < flashchips + flashchips_size;
46}
47
48/**
49 * @brief Enumerate the internal chips database.
50 *
51 * @param[out] chips Points to a struct flashprog_chips pointer that gets
52 * set if the enumeration is successful. *chips has to be
53 * freed by the caller with @ref flashprog_chips_release.
54 * @return 0 on success
55 */
56int flashprog_chips_all(struct flashprog_chips **chips) {
57 *chips = FLASHCHIPS_DB;
58 return 0;
59}
60
Nico Huberd9301142026-03-08 21:19:27 +010061static int flashprog_chips_probe_bus(struct flashprog_chips *chips,
62 struct registered_master *bus)
63{
64 flashprog_bus_probe(bus, NULL);
65
66 int chip;
67 for (chip = 0; flashchips[chip].name; ++chip) {
68 /* Ignore generic entries if we already have a match. */
69 if (chips->entries &&
70 ((flashchips[chip].id.model == SFDP_DEVICE_ID) ||
71 (flashchips[chip].id.model == GENERIC_DEVICE_ID)))
72 continue;
73
74 if (!flashprog_chip_match(bus, &flashchips[chip]))
75 continue;
76
77 struct chip_entry *const entry = malloc(sizeof(*entry));
78 if (!entry) {
79 msg_cerr("Out of memory!\n");
80 return 1;
81 }
82
83 entry->chip = flashchips[chip];
84 entry->bus = &bus->common;
85 entry->next = chips->entries;
86
87 chips->entries = entry;
88 }
89
90 return 0;
91}
92
Nico Huberd4926fe2026-03-08 21:37:52 +010093/** @private */
94const struct master_common *flashprog_chip_probe(
95 const struct flashprog_programmer *flashprog,
96 const struct flashchip *chip)
97{
98 if (!chip_from_db(chip))
99 /* If not in the DB, it must be a probed `chip_entry`. */
100 return ((const struct chip_entry *)chip)->bus;
101
102 int i;
103 for (i = 0; i < registered_master_count; ++i) {
104 struct registered_master *const bus = &registered_masters[i];
105
106 if (!(bus->buses_supported & chip->bustype))
107 continue;
108
109 /* If it can't be probed, assume it's there. */
110 if (chip->id.type == ID_NONE)
111 return &bus->common;
112
113 /* We probe for a specific chip, so we can adapt the voltage early. */
114 if (bus->common.adapt_voltage &&
115 bus->common.adapt_voltage(&bus->common, chip->voltage.min, chip->voltage.max))
116 return NULL;
117
118 flashprog_bus_probe(bus, chip);
119 if (flashprog_chip_match(bus, chip))
120 return &bus->common;
121 }
122
123 return NULL;
124}
125
Nico Huberd9301142026-03-08 21:19:27 +0100126/**
127 * @brief Probe for flash chips.
128 *
129 * Probes for flash chips on a given programmer. Can return multiple
130 * matches in case of ambiguous IDs or when the programmer features
131 * multiple buses.
132 *
133 * @param[out] chips Points to a struct flashprog_chips pointer that gets
134 * set if probing is successful. *chips has to be freed
135 * by the caller with @ref flashprog_chips_release after
136 * successful calls.
137 * @param[in] flashprog The flash programmer used to access the chip.
138 * @return 0 on success
139 */
140int flashprog_chips_probe(struct flashprog_chips **chips, const struct flashprog_programmer *flashprog)
141{
142 struct flashprog_chips *const matched_chips = calloc(1, sizeof(*matched_chips));
143 if (!matched_chips) {
144 msg_gerr("Out of memory!\n");
145 return 1;
146 }
147
148 int bus_index;
149 for (bus_index = 0; bus_index < registered_master_count; bus_index++) {
150 if (flashprog_chips_probe_bus(matched_chips, &registered_masters[bus_index])) {
151 flashprog_chips_release(matched_chips);
152 return 1;
153 }
154 }
155
156 *chips = matched_chips;
157 return 0;
158}
159
Nico Huber48d4a042026-03-08 16:07:28 +0100160/**
161 * @brief Count the chips in an enumeration.
162 *
163 * @return The number of chips.
164 */
165unsigned int flashprog_chips_count(const struct flashprog_chips *chips)
166{
167 unsigned int count = 0;
168 const struct flashprog_chip *chip;
169 for (chip = flashprog_chip_first(chips); chip; chip = flashprog_chip_next(chip))
170 ++count;
171 return count;
172}
173
174/**
175 * @brief Free a set of enumerated chips.
176 *
177 * This also invalidates all references that were acquired via
178 * @ref flashprog_chip_first or @ref flashprog_chip_next from
179 * the given set.
180 *
181 * @param chips Chip enumeration to free.
182 */
183void flashprog_chips_release(struct flashprog_chips *chips)
184{
Nico Huberd9301142026-03-08 21:19:27 +0100185 if (!chips || chips == FLASHCHIPS_DB)
Nico Huber48d4a042026-03-08 16:07:28 +0100186 return;
187
Nico Huberd9301142026-03-08 21:19:27 +0100188 struct chip_entry *next;
189 for (; chips->entries; chips->entries = next) {
190 next = chips->entries->next;
191 free(chips->entries);
192 }
Nico Huber48d4a042026-03-08 16:07:28 +0100193 free(chips);
194}
195
196/**
197 * @brief Starts an iteration over a given set of enumerated chips.
198 *
199 * The referenced chip structure will stay valid until either the iteration
200 * is advanced (@ref flashprog_chip_next) or the provided chips enumeration
201 * is released. Note, each call may allocated additional resources that are
202 * only freed by walking the iteration to its end, or releasing the entire
203 * chips set.
204 *
205 * @param chips A set of enumerated chips.
206 * @return A pointer to the structure of the first chip or NULL if the set is empty.
207 */
208const struct flashprog_chip *flashprog_chip_first(const struct flashprog_chips *chips)
209{
210 if (chips == FLASHCHIPS_DB)
211 return flashchips;
212
Nico Huberd9301142026-03-08 21:19:27 +0100213 return &chips->entries->chip;
Nico Huber48d4a042026-03-08 16:07:28 +0100214}
215
216/**
217 * @brief Iterates to the next chip structure in a set of enumerated chips.
218 *
219 * The referenced chip structure will stay valid until either the iteration
220 * is advanced further or the original chips enumeration is released (cf.
221 * @ref flashprog_chip_first).
222 *
223 * @param chip The previous chip in the enumeration. The referenced
224 * structure will be invalidated by the call.
225 * @return A pointer to the structure of the next chip or NULL if there is none.
226 */
227const struct flashprog_chip *flashprog_chip_next(const struct flashprog_chip *chip)
228{
229 if (chip_from_db(chip)) {
230 for (++chip; chip->name; ++chip) {
231 if (chip->id.manufacture == PROGMANUF_ID)
232 continue;
233 if (chip->id.manufacture == GENERIC_MANUF_ID)
234 continue;
235 if (chip->id.model == GENERIC_DEVICE_ID)
236 continue;
237 return chip;
238 }
239 return NULL;
240 }
241
Nico Huberd9301142026-03-08 21:19:27 +0100242 /* If not in the DB, it must be a probed `chip_entry`. */
243 return &((const struct chip_entry *)chip)->next->chip;
Nico Huber48d4a042026-03-08 16:07:28 +0100244}
245
246/** @} */ /* end flashprog-chips */
247
248
249/**
250 * @defgroup flashprog-chip Chip Information
251 * @{
252 */
253
254/**
255 * @brief Get the vendor string of a given chip structure.
256 *
257 * @param chip reference to query.
258 * @return Vendor string.
259 */
260const char *flashprog_chip_vendor(const struct flashprog_chip *chip) {
261 return chip->vendor;
262}
263
264/**
265 * @brief Get the name string of a given chip structure.
266 *
267 * @param chip reference to query.
268 * @return Name string.
269 */
270const char *flashprog_chip_name(const struct flashprog_chip *chip) {
271 return chip->name;
272}
273
274/**
275 * @brief Get the size of a given chip in bytes.
276 *
277 * @param chip reference to query.
278 * @return Size in bytes.
279 */
280size_t flashprog_chip_size(const struct flashprog_chip *chip) {
281 return chip->total_size * KiB;
282}
283
Nico Huber0d2b45e2026-03-23 22:42:46 +0100284/**
285 * @brief Get a bit mask of the supported bus types.
286 *
287 * @param chip reference to query.
288 * @return bit mask of supported bus types.
289 */
290enum flashprog_bus_type flashprog_chip_buses(const struct flashprog_chip *chip) {
291 return chip->bustype;
292}
293
294/**
295 * @brief Get a string that lists the supported bus types.
296 *
297 * The resulting string needs to be freed with free().
298 *
299 * @param chip reference to query.
300 * @return comma-separated string of supported bus types.
301 */
302char *flashprog_chip_bus_names(const struct flashprog_chip *chip) {
303 return flashbuses_to_text(chip->bustype);
304}
305
306/**
307 * @brief Get the supported operating voltage range.
308 *
309 * @param chip reference to query.
310 * @return supported operating voltage range.
311 */
312struct flashprog_voltage_range flashprog_chip_voltage_range(const struct flashprog_chip *chip)
313{
314 return (struct flashprog_voltage_range) {
315 .min = chip->voltage.min / 1000.f,
316 .max = chip->voltage.max / 1000.f,
317 };
318}
319
320/**
321 * @brief Get the test status of a chip's standard features.
322 *
323 * @param chip reference to query.
324 * @return struct with the test status of the chip's standard features.
325 */
326struct flashprog_test_status flashprog_chip_test_status(const struct flashprog_chip *chip) {
327 return chip->tested;
328}
329
Nico Huber48d4a042026-03-08 16:07:28 +0100330/** @} */ /* end flashprog-chip */