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