Line data Source code
1 : /**
2 : * @file pin_repository.cpp
3 : * @brief I/O pin registry code
4 : *
5 : * This job of this class is to make sure that we are not using same hardware pin for two
6 : * different purposes.
7 : *
8 : * @date Jan 15, 2013
9 : * @author Andrey Belomutskiy, (c) 2012-2020
10 : */
11 :
12 : #include "pch.h"
13 :
14 20 : static size_t getBrainPinTotalNum() {
15 20 : return BRAIN_PIN_TOTAL_PINS;
16 : }
17 :
18 21 : const char* & getBrainUsedPin(size_t index) {
19 21 : return engine->pinRepository.getBrainUsedPin(index);
20 : }
21 :
22 : /* Common for firmware and unit tests */
23 66824 : bool isBrainPinValid(brain_pin_e brainPin) {
24 66824 : if ((brainPin == Gpio::Unassigned) || (brainPin == Gpio::Invalid))
25 65417 : return false;
26 :
27 1407 : if (brainPin > BRAIN_PIN_LAST)
28 : /* something terribly wrong */
29 0 : return false;
30 :
31 1407 : return true;
32 : }
33 :
34 1143 : int brainPin_to_index(Gpio brainPin) {
35 1143 : if (brainPin < Gpio::A0)
36 1123 : return -1;
37 :
38 20 : size_t i = brainPin - Gpio::A0;
39 :
40 20 : if (i >= getBrainPinTotalNum())
41 0 : return -1;
42 :
43 20 : return i;
44 : }
45 :
46 : /**
47 : * See also brain_pin_markUnused()
48 : * @return true if this pin was already used, false otherwise
49 : */
50 :
51 14 : bool brain_pin_markUsed(Gpio brainPin, const char *msg) {
52 : #ifndef EFI_BOOTLOADER
53 14 : efiPrintf("pin_markUsed: %s on %s", msg, hwPortname(brainPin));
54 : #endif
55 :
56 14 : int index = brainPin_to_index(brainPin);
57 14 : if (index < 0)
58 0 : return true;
59 :
60 14 : if (engine->pinRepository.getBrainUsedPin(index) != nullptr) {
61 : // hwPortname and share a buffer behind the scenes, even while they probably never use it for different
62 : // values here let's have an explicit second buffer to make this more reliable
63 0 : char physicalPinName[32];
64 0 : strncpy(physicalPinName, hwPhysicalPinName(brainPin), sizeof(physicalPinName) - 1);
65 0 : criticalError("Pin \"%s\" (%s) required by \"%s\" but is used by \"%s\"",
66 : hwPortname(brainPin),
67 : physicalPinName,
68 : msg,
69 : getBrainUsedPin(index));
70 0 : return true;
71 : }
72 :
73 14 : getBrainUsedPin(index) = msg;
74 14 : return false;
75 : }
76 :
77 : /**
78 : * See also brain_pin_markUsed()
79 : */
80 :
81 1128 : void brain_pin_markUnused(brain_pin_e brainPin) {
82 : #ifndef EFI_BOOTLOADER
83 1128 : efiPrintf("pin_markUnused: %s", hwPortname(brainPin));
84 : #endif
85 1128 : int index = brainPin_to_index(brainPin);
86 1128 : if (index < 0)
87 1123 : return;
88 :
89 5 : getBrainUsedPin(index) = nullptr;
90 : }
91 :
92 : #if EFI_PROD_CODE
93 : #include "memstreams.h"
94 : static MemoryStream portNameStream;
95 : static char portNameBuffer[20];
96 : #endif /* EFI_PROD_CODE */
97 :
98 437 : PinRepository::PinRepository() {
99 : #if EFI_PROD_CODE
100 : msObjectInit(&portNameStream, (uint8_t*) portNameBuffer, sizeof(portNameBuffer), 0);
101 : #endif /* EFI_PROD_CODE */
102 :
103 437 : memset(PIN_USED, 0, sizeof(PIN_USED));
104 437 : }
105 :
106 : #if EFI_PROD_CODE
107 :
108 : #include "eficonsole.h"
109 : #include "drivers/gpio/gpio_ext.h"
110 : #include "smart_gpio.h"
111 : #include "hardware.h"
112 :
113 : void pinDiag2string(char *buffer, size_t size, brain_pin_diag_e pin_diag) {
114 : /* use autogeneraged helpers here? */
115 : if (pin_diag == PIN_OK) {
116 : chsnprintf(buffer, size, "Ok");
117 : } else if (pin_diag != PIN_UNKNOWN) {
118 : chsnprintf(buffer, size, "%s%s%s%s%s%s",
119 : pin_diag & PIN_DRIVER_OFF ? "driver_off " : "",
120 : pin_diag & PIN_OPEN ? "open_load " : "",
121 : pin_diag & PIN_SHORT_TO_GND ? "short_to_gnd " : "",
122 : pin_diag & PIN_SHORT_TO_BAT ? "short_to_bat " : "",
123 : pin_diag & PIN_OVERLOAD ? "overload " : "",
124 : pin_diag & PIN_DRIVER_OVERTEMP ? "overtemp": "");
125 : } else {
126 : chsnprintf(buffer, size, "INVALID");
127 : }
128 : }
129 :
130 : static brain_pin_e index_to_brainPin(unsigned int i)
131 : {
132 : if (i < getBrainPinTotalNum())
133 : return Gpio::A0 + i;
134 :
135 : return Gpio::Invalid;
136 : }
137 :
138 : static void reportPins() {
139 : int totalPinsUsed = 0;
140 :
141 : for (unsigned int i = 0; i < getBrainPinOnchipNum(); i++) {
142 : const char *pin_user = getBrainUsedPin(i);
143 :
144 : /* show used pins */
145 : if (pin_user != NULL) {
146 : static char pin_state[64];
147 : brain_pin_e brainPin = index_to_brainPin(i);
148 : int pin = getBrainPinIndex(brainPin);
149 : ioportid_t port = getBrainPinPort(brainPin);
150 : debugBrainPin(pin_state, sizeof(pin_state), brainPin);
151 :
152 : const char *boardPinName = getBoardSpecificPinName(brainPin);
153 : efiPrintf("pin %s%d (%s): %s %s", portname(port), pin, boardPinName, pin_user, pin_state);
154 : totalPinsUsed++;
155 : }
156 : }
157 :
158 : #if (BOARD_EXT_GPIOCHIPS > 0)
159 : for (unsigned int i = getBrainPinOnchipNum() ; i < getBrainPinTotalNum(); i++) {
160 : static char pin_error[64];
161 : brain_pin_e brainPin = index_to_brainPin(i);
162 :
163 : const char *pin_name = gpiochips_getPinName(brainPin);
164 : const char *pin_user = getBrainUsedPin(i);
165 : brain_pin_diag_e pin_diag = gpiochips_getDiag(brainPin);
166 :
167 : pinDiag2string(pin_error, sizeof(pin_error), pin_diag);
168 :
169 : /* here show all pins, unused too */
170 : if (pin_name != NULL) {
171 : // this probably uses a lot of output buffer!
172 : efiPrintf("ext %s: %s diagnostic: %s",
173 : pin_name, pin_user ? pin_user : "free", pin_error);
174 : } else {
175 : const char *chip_name = gpiochips_getChipName(brainPin);
176 : /* if chip exist */
177 : if (chip_name != NULL) {
178 : efiPrintf("ext %s.%d: %s diagnostic: %s",
179 : chip_name, gpiochips_getPinOffset(brainPin), pin_user ? pin_user : "free", pin_error);
180 : }
181 : }
182 : if (pin_user != NULL) {
183 : totalPinsUsed++;
184 : }
185 : }
186 : #endif
187 :
188 : efiPrintf("Total pins used: %d", totalPinsUsed);
189 :
190 : gpiochips_debug();
191 : }
192 :
193 : __attribute__((weak)) const char * getBoardSpecificPinName(brain_pin_e /*brainPin*/) {
194 : return nullptr;
195 : }
196 :
197 : static const char *hwOnChipPhysicalPinName(ioportid_t hwPort, int hwPin) {
198 : portNameStream.eos = 0; // reset
199 : if (hwPort == GPIO_NULL) {
200 : return "NONE";
201 : }
202 : chprintf((BaseSequentialStream *) &portNameStream, "%s%d", portname(hwPort), hwPin);
203 : portNameStream.buffer[portNameStream.eos] = 0; // need to terminate explicitly
204 : return portNameBuffer;
205 : }
206 :
207 : const char *hwPhysicalPinName(Gpio brainPin) {
208 : if (brainPin == Gpio::Invalid) {
209 : return "INVALID";
210 : }
211 : if (brainPin == Gpio::Unassigned) {
212 : return "NONE";
213 : }
214 :
215 : if (brain_pin_is_onchip(brainPin)) {
216 : ioportid_t hwPort = getHwPort("hostname", brainPin);
217 : int hwPin = getHwPin("hostname", brainPin);
218 : return hwOnChipPhysicalPinName(hwPort, hwPin);
219 : }
220 : #if (BOARD_EXT_GPIOCHIPS > 0)
221 : else {
222 : portNameStream.eos = 0; // reset
223 : const char *pin_name = gpiochips_getPinName(brainPin);
224 :
225 : if (pin_name) {
226 : chprintf((BaseSequentialStream *) &portNameStream, "ext:%s",
227 : pin_name);
228 : } else {
229 : chprintf((BaseSequentialStream *) &portNameStream, "ext:%s.%d",
230 : gpiochips_getChipName(brainPin), gpiochips_getPinOffset(brainPin));
231 : }
232 : portNameStream.buffer[portNameStream.eos] = 0; // need to terminate explicitly
233 : return portNameBuffer;
234 : }
235 : #endif
236 : return "unexpected";
237 : }
238 :
239 : const char *hwPortname(brain_pin_e brainPin) {
240 : const char * boardSpecificPinName = getBoardSpecificPinName(brainPin);
241 : if (boardSpecificPinName != nullptr) {
242 : return boardSpecificPinName;
243 : }
244 : return hwPhysicalPinName(brainPin);
245 : }
246 :
247 : void initPinRepository(void) {
248 : /**
249 : * this method cannot use console because this method is invoked before console is initialized
250 : */
251 :
252 : addConsoleAction(CMD_PINS, reportPins);
253 :
254 : #if (BOARD_TLE8888_COUNT > 0)
255 : addConsoleAction("tle8888", tle8888_dump_regs);
256 : addConsoleAction("tle8888init", tle8888_req_init);
257 : #endif
258 : }
259 :
260 : bool brain_pin_is_onchip(brain_pin_e brainPin)
261 : {
262 : if ((brainPin < Gpio::A0) || (brainPin > BRAIN_PIN_ONCHIP_LAST))
263 : return false;
264 :
265 : return true;
266 : }
267 :
268 : bool brain_pin_is_ext(brain_pin_e brainPin)
269 : {
270 : if (brainPin > BRAIN_PIN_ONCHIP_LAST)
271 : return true;
272 :
273 : return false;
274 : }
275 :
276 : /**
277 : * Marks on-chip gpio port-pin as used. Works only for on-chip gpios
278 : * To be replaced with brain_pin_markUsed later
279 : */
280 :
281 : bool gpio_pin_markUsed(ioportid_t port, ioportmask_t pin, const char *msg) {
282 : int index = getPortPinIndex(port, pin);
283 : #ifndef EFI_BOOTLOADER
284 : efiPrintf("pin_markUsed: %s on %s", msg, hwOnChipPhysicalPinName(port, pin));
285 : #endif
286 :
287 : if (getBrainUsedPin(index) != NULL) {
288 : /**
289 : * todo: the problem is that this warning happens before the console is even
290 : * connected, so the warning is never displayed on the console and that's quite a problem!
291 : */
292 : // warning(ObdCode::OBD_PCM_Processor_Fault, "%s%d req by %s used by %s", portname(port), pin, msg, getBrainUsedPin(index));
293 : firmwareError(ObdCode::CUSTOM_ERR_PIN_ALREADY_USED_1, "%s%d req by %s used by %s", portname(port), (int)pin, msg, getBrainUsedPin(index));
294 : return true;
295 : }
296 : getBrainUsedPin(index) = msg;
297 : return false;
298 : }
299 :
300 : /**
301 : * Marks on-chip gpio port-pin as UNused. Works only for on-chip gpios
302 : * To be replaced with brain_pin_markUnused later
303 : */
304 :
305 : void gpio_pin_markUnused(ioportid_t port, ioportmask_t pin) {
306 : int index = getPortPinIndex(port, pin);
307 :
308 : getBrainUsedPin(index) = nullptr;
309 : }
310 :
311 : const char *getPinFunction(brain_input_pin_e brainPin) {
312 : int index;
313 :
314 : index = brainPin_to_index(brainPin);
315 : if (index < 0)
316 : return NULL;
317 :
318 : return getBrainUsedPin(index);
319 : }
320 : #else
321 0 : const char *hwPhysicalPinName(Gpio brainPin) {
322 0 : return "N/A";
323 : }
324 1265 : const char *hwPortname(Gpio brainPin) {
325 : (void)brainPin;
326 1265 : return "N/A";
327 : }
328 : #endif /* EFI_PROD_CODE */
|