e75be816c4983835776a2fc7ac7ebfef7cdae28d
[SCSI2SD-V6.git] / src / firmware / config.c
1 // Copyright (C) 2014 Michael McMaster <michael@codesrc.com>
2 //
3 // This file is part of SCSI2SD.
4 //
5 // SCSI2SD is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // SCSI2SD is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
17
18 #include "config.h"
19 #include "led.h"
20 #include "bsp.h"
21 #include "scsi.h"
22 #include "scsiPhy.h"
23 #include "sd.h"
24 #include "disk.h"
25 #include "bootloader.h"
26 #include "spinlock.h"
27
28 #include "../../include/scsi2sd.h"
29 #include "../../include/hidpacket.h"
30
31 #include "usb_device/usb_device.h"
32 #include "usb_device/usbd_hid.h"
33 #include "usb_device/usbd_composite.h"
34 #include "bsp_driver_sd.h"
35
36
37 #include <string.h>
38
39 static const uint16_t FIRMWARE_VERSION = 0x0641;
40
41 // Optional static config
42 extern uint8_t* __fixed_config;
43
44 #ifdef S2S_USB_HS
45 #define configUsbDev hUsbDeviceHS
46 #else
47 #define configUsbDev hUsbDeviceFS
48 #endif
49
50 // 1 flash row
51 static const uint8_t DEFAULT_CONFIG[128] =
52 {
53 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 0x00,
54 0x00, 0x02, 0x3F, 0x00, 0xFF, 0x00, 0x20, 0x63, 0x6F, 0x64, 0x65, 0x73,
55 0x72, 0x63, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,
56 0x43, 0x53, 0x49, 0x32, 0x53, 0x44, 0x20, 0x31, 0x2E, 0x30, 0x31, 0x32,
57 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
58 0x37, 0x38, 0x00, 0x00
59 };
60
61
62 static uint8_t s2s_cfg[S2S_CFG_SIZE] S2S_DMA_ALIGN;
63 static uint8_t configDmaBuf[512] S2S_DMA_ALIGN; // For SD card writes.
64
65
66 enum USB_STATE
67 {
68 USB_IDLE,
69 USB_DATA_SENT
70 };
71
72
73 static int usbInEpState;
74
75 static void s2s_debugTimer();
76
77 // Debug timer to log via USB.
78 // Timer 6 & 7 is a simple counter with no external IO supported.
79 static s2s_lock_t usbDevLock = s2s_lock_init;
80 TIM_HandleTypeDef htim7;
81 static int debugTimerStarted = 0;
82 void TIM7_IRQHandler()
83 {
84 HAL_TIM_IRQHandler(&htim7);
85 }
86 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
87 {
88 if (s2s_spin_trylock(&usbDevLock)) {
89 s2s_debugTimer();
90 s2s_spin_unlock(&usbDevLock);
91 }
92 }
93
94 void s2s_configInit(S2S_BoardCfg* config)
95 {
96 usbInEpState = USB_IDLE;
97
98 if (memcmp(__fixed_config, "BCFG", 4) == 0)
99 {
100 // Use hardcoded config
101 memcpy(s2s_cfg, __fixed_config, S2S_CFG_SIZE);
102 memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));
103 }
104
105 else if ((blockDev.state & DISK_PRESENT) && sdDev.capacity)
106 {
107 int cfgSectors = (S2S_CFG_SIZE + 511) / 512;
108 BSP_SD_ReadBlocks_DMA(
109 &s2s_cfg[0],
110 sdDev.capacity - cfgSectors,
111 cfgSectors);
112
113 memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));
114
115 if (memcmp(config->magic, "BCFG", 4))
116 {
117 // Invalid SD card config, use default.
118 memset(&s2s_cfg[0], 0, S2S_CFG_SIZE);
119 memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));
120 memcpy(config->magic, "BCFG", 4);
121 config->selectionDelay = 255; // auto
122 config->flags6 = S2S_CFG_ENABLE_TERMINATOR;
123
124 memcpy(
125 &s2s_cfg[0] + sizeof(S2S_BoardCfg),
126 DEFAULT_CONFIG,
127 sizeof(S2S_TargetCfg));
128 }
129 }
130 else
131 {
132 // No SD card, use existing config if valid
133 if (memcmp(config->magic, "BCFG", 4))
134 {
135 // Not valid, use empty config with no disks.
136 memset(&s2s_cfg[0], 0, S2S_CFG_SIZE);
137 memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));
138 config->selectionDelay = 255; // auto
139 config->flags6 = S2S_CFG_ENABLE_TERMINATOR;
140 }
141 }
142 }
143
144 static void debugInit(void)
145 {
146 if (debugTimerStarted == 1) return;
147
148 debugTimerStarted = 1;
149 // 10ms debug timer to capture logs over USB
150 __TIM7_CLK_ENABLE();
151 htim7.Instance = TIM7;
152 #ifdef STM32F2xx
153 htim7.Init.Prescaler = 10800 - 1; // 16bit. 108MHz down to 10KHz
154 #else
155 htim7.Init.Prescaler = 18000 - 1; // 16bit. 180MHz down to 10KHz
156 #endif
157
158 htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
159 htim7.Init.Period = 100 - 1; // 16bit. 10KHz down to 10ms.
160 htim7.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
161 HAL_TIM_Base_Init(&htim7);
162 HAL_TIM_Base_Start_IT(&htim7);
163
164 HAL_NVIC_SetPriority(TIM7_IRQn, 10, 0);
165 HAL_NVIC_EnableIRQ(TIM7_IRQn);
166 }
167
168
169 static void
170 pingCommand()
171 {
172 uint8_t response[] =
173 {
174 S2S_CFG_STATUS_GOOD
175 };
176 hidPacket_send(response, sizeof(response));
177 }
178
179 static void
180 sdInfoCommand()
181 {
182 uint8_t response[sizeof(sdDev.csd) + sizeof(sdDev.cid)];
183 memcpy(response, sdDev.csd, sizeof(sdDev.csd));
184 memcpy(response + sizeof(sdDev.csd), sdDev.cid, sizeof(sdDev.cid));
185
186 hidPacket_send(response, sizeof(response));
187 }
188
189
190 static void
191 scsiTestCommand()
192 {
193 int resultCode = scsiSelfTest();
194 uint8_t response[] =
195 {
196 resultCode == 0 ? S2S_CFG_STATUS_GOOD : S2S_CFG_STATUS_ERR,
197 resultCode
198 };
199 hidPacket_send(response, sizeof(response));
200 }
201
202 static void
203 scsiDevInfoCommand()
204 {
205 uint8_t response[] =
206 {
207 FIRMWARE_VERSION >> 8,
208 FIRMWARE_VERSION & 0xff,
209 sdDev.capacity >> 24,
210 sdDev.capacity >> 16,
211 sdDev.capacity >> 8,
212 sdDev.capacity,
213 1 // useSdConfig, always true for V6.
214 };
215 hidPacket_send(response, sizeof(response));
216 }
217
218 static void
219 debugCommand()
220 {
221 uint8_t response[32];
222 memcpy(&response, &scsiDev.cdb, 12);
223 response[12] = scsiDev.msgIn;
224 response[13] = scsiDev.msgOut;
225 response[14] = scsiDev.lastStatus;
226 response[15] = scsiDev.lastSense;
227 response[16] = scsiDev.phase;
228 response[17] = *SCSI_STS_SCSI;
229 response[18] = scsiDev.target != NULL ? scsiDev.target->syncOffset : 0;
230 response[19] = scsiDev.target != NULL ? scsiDev.target->syncPeriod : 0;
231 response[20] = scsiDev.minSyncPeriod;
232 response[21] = scsiDev.rstCount;
233 response[22] = scsiDev.selCount;
234 response[23] = scsiDev.msgCount;
235 response[24] = scsiDev.cmdCount;
236 response[25] = scsiDev.watchdogTick;
237 response[26] = blockDev.state;
238 response[27] = scsiDev.lastSenseASC >> 8;
239 response[28] = scsiDev.lastSenseASC;
240 response[29] = *SCSI_STS_DBX & 0xff; // What we've read
241 response[30] = *SCSI_STS_SELECTED;
242 response[31] = *SCSI_STS_DBX >> 8; // What we're writing
243 hidPacket_send(response, sizeof(response));
244 }
245
246 static void
247 sdWriteCommand(const uint8_t* cmd, size_t cmdSize)
248 {
249 if (cmdSize < 517)
250 {
251 return; // ignore.
252 }
253 uint32_t lba =
254 (((uint32_t)cmd[1]) << 24) |
255 (((uint32_t)cmd[2]) << 16) |
256 (((uint32_t)cmd[3]) << 8) |
257 ((uint32_t)cmd[4]);
258
259 memcpy(configDmaBuf, &cmd[5], 512);
260 BSP_SD_WriteBlocks_DMA(configDmaBuf, lba, 1);
261
262 uint8_t response[] =
263 {
264 S2S_CFG_STATUS_GOOD
265 };
266 hidPacket_send(response, sizeof(response));
267 }
268
269 static void
270 sdReadCommand(const uint8_t* cmd, size_t cmdSize)
271 {
272 if (cmdSize < 5)
273 {
274 return; // ignore.
275 }
276 uint32_t lba =
277 (((uint32_t)cmd[1]) << 24) |
278 (((uint32_t)cmd[2]) << 16) |
279 (((uint32_t)cmd[3]) << 8) |
280 ((uint32_t)cmd[4]);
281
282 BSP_SD_ReadBlocks_DMA(configDmaBuf, lba, 1);
283 hidPacket_send(configDmaBuf, 512);
284 }
285
286 static void
287 processCommand(const uint8_t* cmd, size_t cmdSize)
288 {
289 switch (cmd[0])
290 {
291 case S2S_CMD_PING:
292 pingCommand();
293 break;
294
295 case S2S_CMD_REBOOT:
296 s2s_enterBootloader();
297 break;
298
299 case S2S_CMD_SDINFO:
300 sdInfoCommand();
301 break;
302
303 case S2S_CMD_SCSITEST:
304 scsiTestCommand();
305 break;
306
307 case S2S_CMD_DEVINFO:
308 scsiDevInfoCommand();
309 break;
310
311 case S2S_CMD_SD_WRITE:
312 sdWriteCommand(cmd, cmdSize);
313 break;
314
315 case S2S_CMD_SD_READ:
316 sdReadCommand(cmd, cmdSize);
317 break;
318
319 case S2S_CMD_DEBUG:
320 if (debugTimerStarted == 0) {
321 debugInit();
322 }
323 debugCommand();
324 break;
325
326 case S2S_CMD_NONE: // invalid
327 default:
328 break;
329 }
330 }
331
332 void s2s_configPoll()
333 {
334 s2s_spin_lock(&usbDevLock);
335
336 if (!USBD_Composite_IsConfigured(&configUsbDev))
337 {
338 usbInEpState = USB_IDLE;
339 hidPacket_reset();
340 goto out;
341 }
342
343 if (USBD_HID_IsReportReady(&configUsbDev))
344 {
345 // Check if we have a previous command outstanding
346 // before accepting another
347 size_t cmdSize;
348 if (hidPacket_peekPacket(&cmdSize) == NULL)
349 {
350 uint8_t hidBuffer[USBHID_LEN];
351 int byteCount = USBD_HID_GetReport(&configUsbDev, hidBuffer, sizeof(hidBuffer));
352 hidPacket_recv(hidBuffer, byteCount);
353 }
354 }
355
356 if (hidPacket_getHIDBytesReady() == 0) // Nothing queued to send
357 {
358 size_t cmdSize;
359 const uint8_t* cmd = hidPacket_getPacket(&cmdSize);
360 if (cmd && (cmdSize > 0))
361 {
362 s2s_ledOn();
363 processCommand(cmd, cmdSize);
364 s2s_ledOff();
365 }
366 }
367
368 switch (usbInEpState)
369 {
370 case USB_IDLE:
371 {
372 uint8_t hidBuffer[USBHID_LEN];
373 const uint8_t* nextChunk = hidPacket_getHIDBytes(hidBuffer);
374
375 if (nextChunk)
376 {
377 USBD_HID_SendReport (&configUsbDev, nextChunk, sizeof(hidBuffer));
378 usbInEpState = USB_DATA_SENT;
379 }
380 }
381 break;
382
383 case USB_DATA_SENT:
384 if (!USBD_HID_IsBusy(&configUsbDev))
385 {
386 // Data accepted.
387 usbInEpState = USB_IDLE;
388 }
389 break;
390 }
391
392 out:
393 s2s_spin_unlock(&usbDevLock);
394 }
395
396 void s2s_debugTimer()
397 {
398 if (!USBD_Composite_IsConfigured(&configUsbDev))
399 {
400 usbInEpState = USB_IDLE;
401 return;
402 }
403
404 if (USBD_HID_IsReportReady(&configUsbDev))
405 {
406 // Check if we have a previous command outstanding
407 // before accepting another
408 size_t cmdSize;
409 if (hidPacket_peekPacket(&cmdSize) == NULL)
410 {
411 uint8_t hidBuffer[USBHID_LEN];
412 int byteCount = USBD_HID_GetReport(&configUsbDev, hidBuffer, sizeof(hidBuffer));
413 hidPacket_recv(hidBuffer, byteCount);
414 }
415 }
416
417 if (hidPacket_getHIDBytesReady() == 0) // Nothing queued to send
418 {
419 size_t cmdSize;
420 const uint8_t* cmd = hidPacket_peekPacket(&cmdSize);
421 // This is called from an ISR, only process simple commands.
422 if (cmd && (cmdSize > 0))
423 {
424 if (cmd[0] == S2S_CMD_DEBUG)
425 {
426 hidPacket_getPacket(&cmdSize);
427 debugCommand();
428 }
429 else if (cmd[0] == S2S_CMD_PING)
430 {
431 hidPacket_getPacket(&cmdSize);
432 pingCommand();
433 }
434 }
435 }
436
437 switch (usbInEpState)
438 {
439 case USB_IDLE:
440 {
441 uint8_t hidBuffer[USBHID_LEN];
442 const uint8_t* nextChunk = hidPacket_getHIDBytes(hidBuffer);
443
444 if (nextChunk)
445 {
446 USBD_HID_SendReport (&configUsbDev, nextChunk, sizeof(hidBuffer));
447 usbInEpState = USB_DATA_SENT;
448 }
449 }
450 break;
451
452 case USB_DATA_SENT:
453 if (!USBD_HID_IsBusy(&configUsbDev))
454 {
455 // Data accepted.
456 usbInEpState = USB_IDLE;
457 }
458 break;
459 }
460 }
461
462
463
464 // Public method for storing MODE SELECT results.
465 void s2s_configSave(int scsiId, uint16_t bytesPerSector)
466 {
467 S2S_TargetCfg* cfg = (S2S_TargetCfg*) s2s_getConfigById(scsiId);
468 cfg->bytesPerSector = bytesPerSector;
469
470 BSP_SD_WriteBlocks_DMA(
471 &s2s_cfg[0],
472 sdDev.capacity - S2S_CFG_SIZE,
473 (S2S_CFG_SIZE + 511) / 512);
474 }
475
476
477 const S2S_TargetCfg* s2s_getConfigByIndex(int i)
478 {
479 return (const S2S_TargetCfg*)
480 (s2s_cfg + sizeof(S2S_BoardCfg) + (i * sizeof(S2S_TargetCfg)));
481 }
482
483 const S2S_TargetCfg* s2s_getConfigById(int scsiId)
484 {
485 int i;
486 for (i = 0; i < S2S_MAX_TARGETS; ++i)
487 {
488 const S2S_TargetCfg* tgt = s2s_getConfigByIndex(i);
489 if ((tgt->scsiId & S2S_CFG_TARGET_ID_BITS) == scsiId)
490 {
491 return tgt;
492 }
493 }
494 return NULL;
495
496 }
497