blob: 12b4197bf690ee82f4464799df7cd04402817e11 [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 Huber50bf19f2026-03-14 12:14:18 +010061static bool flashprog_bus_match_chip(struct registered_master *bus, const struct flashprog_chip *chip)
62{
63 struct found_id *found_id;
64 for (found_id = bus->found_ids; found_id; found_id = found_id->next) {
65 if (found_id->info.id.type != chip->id.type)
66 continue;
67
68 if (bus->probing.match(chip, &found_id->info))
69 break;
70 }
71 return !!found_id;
72}
73
Nico Huberd9301142026-03-08 21:19:27 +010074static int flashprog_chips_probe_bus(struct flashprog_chips *chips,
75 struct registered_master *bus)
76{
77 flashprog_bus_probe(bus, NULL);
78
79 int chip;
80 for (chip = 0; flashchips[chip].name; ++chip) {
81 /* Ignore generic entries if we already have a match. */
82 if (chips->entries &&
83 ((flashchips[chip].id.model == SFDP_DEVICE_ID) ||
84 (flashchips[chip].id.model == GENERIC_DEVICE_ID)))
85 continue;
86
Nico Huber50bf19f2026-03-14 12:14:18 +010087 if (!flashprog_bus_match_chip(bus, &flashchips[chip]))
Nico Huberd9301142026-03-08 21:19:27 +010088 continue;
89
90 struct chip_entry *const entry = malloc(sizeof(*entry));
91 if (!entry) {
92 msg_cerr("Out of memory!\n");
93 return 1;
94 }
95
96 entry->chip = flashchips[chip];
97 entry->bus = &bus->common;
98 entry->next = chips->entries;
99
100 chips->entries = entry;
101 }
102
103 return 0;
104}
105
Nico Huberd4926fe2026-03-08 21:37:52 +0100106/** @private */
107const struct master_common *flashprog_chip_probe(
108 const struct flashprog_programmer *flashprog,
109 const struct flashchip *chip)
110{
111 if (!chip_from_db(chip))
112 /* If not in the DB, it must be a probed `chip_entry`. */
113 return ((const struct chip_entry *)chip)->bus;
114
115 int i;
116 for (i = 0; i < registered_master_count; ++i) {
117 struct registered_master *const bus = &registered_masters[i];
118
119 if (!(bus->buses_supported & chip->bustype))
120 continue;
121
122 /* If it can't be probed, assume it's there. */
123 if (chip->id.type == ID_NONE)
124 return &bus->common;
125
126 /* We probe for a specific chip, so we can adapt the voltage early. */
127 if (bus->common.adapt_voltage &&
128 bus->common.adapt_voltage(&bus->common, chip->voltage.min, chip->voltage.max))
129 return NULL;
130
131 flashprog_bus_probe(bus, chip);
Nico Huber50bf19f2026-03-14 12:14:18 +0100132 if (flashprog_bus_match_chip(bus, chip))
Nico Huberd4926fe2026-03-08 21:37:52 +0100133 return &bus->common;
134 }
135
136 return NULL;
137}
138
Nico Huberd9301142026-03-08 21:19:27 +0100139/**
140 * @brief Probe for flash chips.
141 *
142 * Probes for flash chips on a given programmer. Can return multiple
143 * matches in case of ambiguous IDs or when the programmer features
144 * multiple buses.
145 *
146 * @param[out] chips Points to a struct flashprog_chips pointer that gets
147 * set if probing is successful. *chips has to be freed
148 * by the caller with @ref flashprog_chips_release after
149 * successful calls.
150 * @param[in] flashprog The flash programmer used to access the chip.
151 * @return 0 on success
152 */
153int flashprog_chips_probe(struct flashprog_chips **chips, const struct flashprog_programmer *flashprog)
154{
155 struct flashprog_chips *const matched_chips = calloc(1, sizeof(*matched_chips));
156 if (!matched_chips) {
157 msg_gerr("Out of memory!\n");
158 return 1;
159 }
160
161 int bus_index;
162 for (bus_index = 0; bus_index < registered_master_count; bus_index++) {
163 if (flashprog_chips_probe_bus(matched_chips, &registered_masters[bus_index])) {
164 flashprog_chips_release(matched_chips);
165 return 1;
166 }
167 }
168
169 *chips = matched_chips;
170 return 0;
171}
172
Nico Huber48d4a042026-03-08 16:07:28 +0100173/**
174 * @brief Count the chips in an enumeration.
175 *
176 * @return The number of chips.
177 */
178unsigned int flashprog_chips_count(const struct flashprog_chips *chips)
179{
180 unsigned int count = 0;
181 const struct flashprog_chip *chip;
182 for (chip = flashprog_chip_first(chips); chip; chip = flashprog_chip_next(chip))
183 ++count;
184 return count;
185}
186
187/**
188 * @brief Free a set of enumerated chips.
189 *
190 * This also invalidates all references that were acquired via
191 * @ref flashprog_chip_first or @ref flashprog_chip_next from
192 * the given set.
193 *
194 * @param chips Chip enumeration to free.
195 */
196void flashprog_chips_release(struct flashprog_chips *chips)
197{
Nico Huberd9301142026-03-08 21:19:27 +0100198 if (!chips || chips == FLASHCHIPS_DB)
Nico Huber48d4a042026-03-08 16:07:28 +0100199 return;
200
Nico Huberd9301142026-03-08 21:19:27 +0100201 struct chip_entry *next;
202 for (; chips->entries; chips->entries = next) {
203 next = chips->entries->next;
204 free(chips->entries);
205 }
Nico Huber48d4a042026-03-08 16:07:28 +0100206 free(chips);
207}
208
209/**
210 * @brief Starts an iteration over a given set of enumerated chips.
211 *
212 * The referenced chip structure will stay valid until either the iteration
213 * is advanced (@ref flashprog_chip_next) or the provided chips enumeration
214 * is released. Note, each call may allocated additional resources that are
215 * only freed by walking the iteration to its end, or releasing the entire
216 * chips set.
217 *
218 * @param chips A set of enumerated chips.
219 * @return A pointer to the structure of the first chip or NULL if the set is empty.
220 */
221const struct flashprog_chip *flashprog_chip_first(const struct flashprog_chips *chips)
222{
223 if (chips == FLASHCHIPS_DB)
224 return flashchips;
225
Nico Huberd9301142026-03-08 21:19:27 +0100226 return &chips->entries->chip;
Nico Huber48d4a042026-03-08 16:07:28 +0100227}
228
229/**
230 * @brief Iterates to the next chip structure in a set of enumerated chips.
231 *
232 * The referenced chip structure will stay valid until either the iteration
233 * is advanced further or the original chips enumeration is released (cf.
234 * @ref flashprog_chip_first).
235 *
236 * @param chip The previous chip in the enumeration. The referenced
237 * structure will be invalidated by the call.
238 * @return A pointer to the structure of the next chip or NULL if there is none.
239 */
240const struct flashprog_chip *flashprog_chip_next(const struct flashprog_chip *chip)
241{
242 if (chip_from_db(chip)) {
243 for (++chip; chip->name; ++chip) {
244 if (chip->id.manufacture == PROGMANUF_ID)
245 continue;
246 if (chip->id.manufacture == GENERIC_MANUF_ID)
247 continue;
248 if (chip->id.model == GENERIC_DEVICE_ID)
249 continue;
250 return chip;
251 }
252 return NULL;
253 }
254
Nico Huberd9301142026-03-08 21:19:27 +0100255 /* If not in the DB, it must be a probed `chip_entry`. */
256 return &((const struct chip_entry *)chip)->next->chip;
Nico Huber48d4a042026-03-08 16:07:28 +0100257}
258
259/** @} */ /* end flashprog-chips */
260
261
262/**
263 * @defgroup flashprog-chip Chip Information
264 * @{
265 */
266
267/**
268 * @brief Get the vendor string of a given chip structure.
269 *
270 * @param chip reference to query.
271 * @return Vendor string.
272 */
273const char *flashprog_chip_vendor(const struct flashprog_chip *chip) {
274 return chip->vendor;
275}
276
277/**
278 * @brief Get the name string of a given chip structure.
279 *
280 * @param chip reference to query.
281 * @return Name string.
282 */
283const char *flashprog_chip_name(const struct flashprog_chip *chip) {
284 return chip->name;
285}
286
287/**
288 * @brief Get the size of a given chip in bytes.
289 *
290 * @param chip reference to query.
291 * @return Size in bytes.
292 */
293size_t flashprog_chip_size(const struct flashprog_chip *chip) {
294 return chip->total_size * KiB;
295}
296
Nico Huber0d2b45e2026-03-23 22:42:46 +0100297/**
298 * @brief Get a bit mask of the supported bus types.
299 *
300 * @param chip reference to query.
301 * @return bit mask of supported bus types.
302 */
303enum flashprog_bus_type flashprog_chip_buses(const struct flashprog_chip *chip) {
304 return chip->bustype;
305}
306
307/**
308 * @brief Get a string that lists the supported bus types.
309 *
310 * The resulting string needs to be freed with free().
311 *
312 * @param chip reference to query.
313 * @return comma-separated string of supported bus types.
314 */
315char *flashprog_chip_bus_names(const struct flashprog_chip *chip) {
316 return flashbuses_to_text(chip->bustype);
317}
318
319/**
320 * @brief Get the supported operating voltage range.
321 *
322 * @param chip reference to query.
323 * @return supported operating voltage range.
324 */
325struct flashprog_voltage_range flashprog_chip_voltage_range(const struct flashprog_chip *chip)
326{
327 return (struct flashprog_voltage_range) {
328 .min = chip->voltage.min / 1000.f,
329 .max = chip->voltage.max / 1000.f,
330 };
331}
332
333/**
334 * @brief Get the test status of a chip's standard features.
335 *
336 * @param chip reference to query.
337 * @return struct with the test status of the chip's standard features.
338 */
339struct flashprog_test_status flashprog_chip_test_status(const struct flashprog_chip *chip) {
340 return chip->tested;
341}
342
Nico Huber48d4a042026-03-08 16:07:28 +0100343/** @} */ /* end flashprog-chip */