blob: 919d0eb204e1f35cfc36eeda38d63628ea66846c [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
93/**
94 * @brief Probe for flash chips.
95 *
96 * Probes for flash chips on a given programmer. Can return multiple
97 * matches in case of ambiguous IDs or when the programmer features
98 * multiple buses.
99 *
100 * @param[out] chips Points to a struct flashprog_chips pointer that gets
101 * set if probing is successful. *chips has to be freed
102 * by the caller with @ref flashprog_chips_release after
103 * successful calls.
104 * @param[in] flashprog The flash programmer used to access the chip.
105 * @return 0 on success
106 */
107int flashprog_chips_probe(struct flashprog_chips **chips, const struct flashprog_programmer *flashprog)
108{
109 struct flashprog_chips *const matched_chips = calloc(1, sizeof(*matched_chips));
110 if (!matched_chips) {
111 msg_gerr("Out of memory!\n");
112 return 1;
113 }
114
115 int bus_index;
116 for (bus_index = 0; bus_index < registered_master_count; bus_index++) {
117 if (flashprog_chips_probe_bus(matched_chips, &registered_masters[bus_index])) {
118 flashprog_chips_release(matched_chips);
119 return 1;
120 }
121 }
122
123 *chips = matched_chips;
124 return 0;
125}
126
Nico Huber48d4a042026-03-08 16:07:28 +0100127/**
128 * @brief Count the chips in an enumeration.
129 *
130 * @return The number of chips.
131 */
132unsigned int flashprog_chips_count(const struct flashprog_chips *chips)
133{
134 unsigned int count = 0;
135 const struct flashprog_chip *chip;
136 for (chip = flashprog_chip_first(chips); chip; chip = flashprog_chip_next(chip))
137 ++count;
138 return count;
139}
140
141/**
142 * @brief Free a set of enumerated chips.
143 *
144 * This also invalidates all references that were acquired via
145 * @ref flashprog_chip_first or @ref flashprog_chip_next from
146 * the given set.
147 *
148 * @param chips Chip enumeration to free.
149 */
150void flashprog_chips_release(struct flashprog_chips *chips)
151{
Nico Huberd9301142026-03-08 21:19:27 +0100152 if (!chips || chips == FLASHCHIPS_DB)
Nico Huber48d4a042026-03-08 16:07:28 +0100153 return;
154
Nico Huberd9301142026-03-08 21:19:27 +0100155 struct chip_entry *next;
156 for (; chips->entries; chips->entries = next) {
157 next = chips->entries->next;
158 free(chips->entries);
159 }
Nico Huber48d4a042026-03-08 16:07:28 +0100160 free(chips);
161}
162
163/**
164 * @brief Starts an iteration over a given set of enumerated chips.
165 *
166 * The referenced chip structure will stay valid until either the iteration
167 * is advanced (@ref flashprog_chip_next) or the provided chips enumeration
168 * is released. Note, each call may allocated additional resources that are
169 * only freed by walking the iteration to its end, or releasing the entire
170 * chips set.
171 *
172 * @param chips A set of enumerated chips.
173 * @return A pointer to the structure of the first chip or NULL if the set is empty.
174 */
175const struct flashprog_chip *flashprog_chip_first(const struct flashprog_chips *chips)
176{
177 if (chips == FLASHCHIPS_DB)
178 return flashchips;
179
Nico Huberd9301142026-03-08 21:19:27 +0100180 return &chips->entries->chip;
Nico Huber48d4a042026-03-08 16:07:28 +0100181}
182
183/**
184 * @brief Iterates to the next chip structure in a set of enumerated chips.
185 *
186 * The referenced chip structure will stay valid until either the iteration
187 * is advanced further or the original chips enumeration is released (cf.
188 * @ref flashprog_chip_first).
189 *
190 * @param chip The previous chip in the enumeration. The referenced
191 * structure will be invalidated by the call.
192 * @return A pointer to the structure of the next chip or NULL if there is none.
193 */
194const struct flashprog_chip *flashprog_chip_next(const struct flashprog_chip *chip)
195{
196 if (chip_from_db(chip)) {
197 for (++chip; chip->name; ++chip) {
198 if (chip->id.manufacture == PROGMANUF_ID)
199 continue;
200 if (chip->id.manufacture == GENERIC_MANUF_ID)
201 continue;
202 if (chip->id.model == GENERIC_DEVICE_ID)
203 continue;
204 return chip;
205 }
206 return NULL;
207 }
208
Nico Huberd9301142026-03-08 21:19:27 +0100209 /* If not in the DB, it must be a probed `chip_entry`. */
210 return &((const struct chip_entry *)chip)->next->chip;
Nico Huber48d4a042026-03-08 16:07:28 +0100211}
212
213/** @} */ /* end flashprog-chips */
214
215
216/**
217 * @defgroup flashprog-chip Chip Information
218 * @{
219 */
220
221/**
222 * @brief Get the vendor string of a given chip structure.
223 *
224 * @param chip reference to query.
225 * @return Vendor string.
226 */
227const char *flashprog_chip_vendor(const struct flashprog_chip *chip) {
228 return chip->vendor;
229}
230
231/**
232 * @brief Get the name string of a given chip structure.
233 *
234 * @param chip reference to query.
235 * @return Name string.
236 */
237const char *flashprog_chip_name(const struct flashprog_chip *chip) {
238 return chip->name;
239}
240
241/**
242 * @brief Get the size of a given chip in bytes.
243 *
244 * @param chip reference to query.
245 * @return Size in bytes.
246 */
247size_t flashprog_chip_size(const struct flashprog_chip *chip) {
248 return chip->total_size * KiB;
249}
250
Nico Huber0d2b45e2026-03-23 22:42:46 +0100251/**
252 * @brief Get a bit mask of the supported bus types.
253 *
254 * @param chip reference to query.
255 * @return bit mask of supported bus types.
256 */
257enum flashprog_bus_type flashprog_chip_buses(const struct flashprog_chip *chip) {
258 return chip->bustype;
259}
260
261/**
262 * @brief Get a string that lists the supported bus types.
263 *
264 * The resulting string needs to be freed with free().
265 *
266 * @param chip reference to query.
267 * @return comma-separated string of supported bus types.
268 */
269char *flashprog_chip_bus_names(const struct flashprog_chip *chip) {
270 return flashbuses_to_text(chip->bustype);
271}
272
273/**
274 * @brief Get the supported operating voltage range.
275 *
276 * @param chip reference to query.
277 * @return supported operating voltage range.
278 */
279struct flashprog_voltage_range flashprog_chip_voltage_range(const struct flashprog_chip *chip)
280{
281 return (struct flashprog_voltage_range) {
282 .min = chip->voltage.min / 1000.f,
283 .max = chip->voltage.max / 1000.f,
284 };
285}
286
287/**
288 * @brief Get the test status of a chip's standard features.
289 *
290 * @param chip reference to query.
291 * @return struct with the test status of the chip's standard features.
292 */
293struct flashprog_test_status flashprog_chip_test_status(const struct flashprog_chip *chip) {
294 return chip->tested;
295}
296
Nico Huber48d4a042026-03-08 16:07:28 +0100297/** @} */ /* end flashprog-chip */