1 // Copyright (C) 2014 Michael McMaster <michael@codesrc.com>
3 // This file is part of SCSI2SD.
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.
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.
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/>.
25 #include "bootloader.h"
28 #include "../../include/scsi2sd.h"
29 #include "../../include/hidpacket.h"
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"
39 static const uint16_t FIRMWARE_VERSION
= 0x0641;
41 // Optional static config
42 extern uint8_t* __fixed_config
;
45 #define configUsbDev hUsbDeviceHS
47 #define configUsbDev hUsbDeviceFS
51 static const uint8_t DEFAULT_CONFIG
[128] =
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
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.
73 static int usbInEpState
;
75 static void s2s_debugTimer();
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()
84 HAL_TIM_IRQHandler(&htim7
);
86 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef
*htim
)
88 if (s2s_spin_trylock(&usbDevLock
)) {
90 s2s_spin_unlock(&usbDevLock
);
94 void s2s_configInit(S2S_BoardCfg
* config
)
96 usbInEpState
= USB_IDLE
;
98 if (memcmp(__fixed_config
, "BCFG", 4) == 0)
100 // Use hardcoded config
101 memcpy(s2s_cfg
, __fixed_config
, S2S_CFG_SIZE
);
102 memcpy(config
, s2s_cfg
, sizeof(S2S_BoardCfg
));
105 else if ((blockDev
.state
& DISK_PRESENT
) && sdDev
.capacity
)
107 int cfgSectors
= (S2S_CFG_SIZE
+ 511) / 512;
108 BSP_SD_ReadBlocks_DMA(
110 sdDev
.capacity
- cfgSectors
,
113 memcpy(config
, s2s_cfg
, sizeof(S2S_BoardCfg
));
115 if (memcmp(config
->magic
, "BCFG", 4))
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
;
125 &s2s_cfg
[0] + sizeof(S2S_BoardCfg
),
127 sizeof(S2S_TargetCfg
));
132 // No SD card, use existing config if valid
133 if (memcmp(config
->magic
, "BCFG", 4))
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
;
144 static void debugInit(void)
146 if (debugTimerStarted
== 1) return;
148 debugTimerStarted
= 1;
149 // 10ms debug timer to capture logs over USB
151 htim7
.Instance
= TIM7
;
153 htim7
.Init
.Prescaler
= 10800 - 1; // 16bit. 108MHz down to 10KHz
155 htim7
.Init
.Prescaler
= 18000 - 1; // 16bit. 180MHz down to 10KHz
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
);
164 HAL_NVIC_SetPriority(TIM7_IRQn
, 10, 0);
165 HAL_NVIC_EnableIRQ(TIM7_IRQn
);
176 hidPacket_send(response
, sizeof(response
));
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
));
186 hidPacket_send(response
, sizeof(response
));
193 int resultCode
= scsiSelfTest();
196 resultCode
== 0 ? S2S_CFG_STATUS_GOOD
: S2S_CFG_STATUS_ERR
,
199 hidPacket_send(response
, sizeof(response
));
207 FIRMWARE_VERSION
>> 8,
208 FIRMWARE_VERSION
& 0xff,
209 sdDev
.capacity
>> 24,
210 sdDev
.capacity
>> 16,
213 1 // useSdConfig, always true for V6.
215 hidPacket_send(response
, sizeof(response
));
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
));
247 sdWriteCommand(const uint8_t* cmd
, size_t cmdSize
)
254 (((uint32_t)cmd
[1]) << 24) |
255 (((uint32_t)cmd
[2]) << 16) |
256 (((uint32_t)cmd
[3]) << 8) |
259 memcpy(configDmaBuf
, &cmd
[5], 512);
260 BSP_SD_WriteBlocks_DMA(configDmaBuf
, lba
, 1);
266 hidPacket_send(response
, sizeof(response
));
270 sdReadCommand(const uint8_t* cmd
, size_t cmdSize
)
277 (((uint32_t)cmd
[1]) << 24) |
278 (((uint32_t)cmd
[2]) << 16) |
279 (((uint32_t)cmd
[3]) << 8) |
282 BSP_SD_ReadBlocks_DMA(configDmaBuf
, lba
, 1);
283 hidPacket_send(configDmaBuf
, 512);
287 processCommand(const uint8_t* cmd
, size_t cmdSize
)
296 s2s_enterBootloader();
303 case S2S_CMD_SCSITEST
:
307 case S2S_CMD_DEVINFO
:
308 scsiDevInfoCommand();
311 case S2S_CMD_SD_WRITE
:
312 sdWriteCommand(cmd
, cmdSize
);
315 case S2S_CMD_SD_READ
:
316 sdReadCommand(cmd
, cmdSize
);
320 if (debugTimerStarted
== 0) {
326 case S2S_CMD_NONE
: // invalid
332 void s2s_configPoll()
334 s2s_spin_lock(&usbDevLock
);
336 if (!USBD_Composite_IsConfigured(&configUsbDev
))
338 usbInEpState
= USB_IDLE
;
343 if (USBD_HID_IsReportReady(&configUsbDev
))
345 // Check if we have a previous command outstanding
346 // before accepting another
348 if (hidPacket_peekPacket(&cmdSize
) == NULL
)
350 uint8_t hidBuffer
[USBHID_LEN
];
351 int byteCount
= USBD_HID_GetReport(&configUsbDev
, hidBuffer
, sizeof(hidBuffer
));
352 hidPacket_recv(hidBuffer
, byteCount
);
356 if (hidPacket_getHIDBytesReady() == 0) // Nothing queued to send
359 const uint8_t* cmd
= hidPacket_getPacket(&cmdSize
);
360 if (cmd
&& (cmdSize
> 0))
363 processCommand(cmd
, cmdSize
);
368 switch (usbInEpState
)
372 uint8_t hidBuffer
[USBHID_LEN
];
373 const uint8_t* nextChunk
= hidPacket_getHIDBytes(hidBuffer
);
377 USBD_HID_SendReport (&configUsbDev
, nextChunk
, sizeof(hidBuffer
));
378 usbInEpState
= USB_DATA_SENT
;
384 if (!USBD_HID_IsBusy(&configUsbDev
))
387 usbInEpState
= USB_IDLE
;
393 s2s_spin_unlock(&usbDevLock
);
396 void s2s_debugTimer()
398 if (!USBD_Composite_IsConfigured(&configUsbDev
))
400 usbInEpState
= USB_IDLE
;
404 if (USBD_HID_IsReportReady(&configUsbDev
))
406 // Check if we have a previous command outstanding
407 // before accepting another
409 if (hidPacket_peekPacket(&cmdSize
) == NULL
)
411 uint8_t hidBuffer
[USBHID_LEN
];
412 int byteCount
= USBD_HID_GetReport(&configUsbDev
, hidBuffer
, sizeof(hidBuffer
));
413 hidPacket_recv(hidBuffer
, byteCount
);
417 if (hidPacket_getHIDBytesReady() == 0) // Nothing queued to send
420 const uint8_t* cmd
= hidPacket_peekPacket(&cmdSize
);
421 // This is called from an ISR, only process simple commands.
422 if (cmd
&& (cmdSize
> 0))
424 if (cmd
[0] == S2S_CMD_DEBUG
)
426 hidPacket_getPacket(&cmdSize
);
429 else if (cmd
[0] == S2S_CMD_PING
)
431 hidPacket_getPacket(&cmdSize
);
437 switch (usbInEpState
)
441 uint8_t hidBuffer
[USBHID_LEN
];
442 const uint8_t* nextChunk
= hidPacket_getHIDBytes(hidBuffer
);
446 USBD_HID_SendReport (&configUsbDev
, nextChunk
, sizeof(hidBuffer
));
447 usbInEpState
= USB_DATA_SENT
;
453 if (!USBD_HID_IsBusy(&configUsbDev
))
456 usbInEpState
= USB_IDLE
;
464 // Public method for storing MODE SELECT results.
465 void s2s_configSave(int scsiId
, uint16_t bytesPerSector
)
467 S2S_TargetCfg
* cfg
= (S2S_TargetCfg
*) s2s_getConfigById(scsiId
);
468 cfg
->bytesPerSector
= bytesPerSector
;
470 BSP_SD_WriteBlocks_DMA(
472 sdDev
.capacity
- S2S_CFG_SIZE
,
473 (S2S_CFG_SIZE
+ 511) / 512);
477 const S2S_TargetCfg
* s2s_getConfigByIndex(int i
)
479 return (const S2S_TargetCfg
*)
480 (s2s_cfg
+ sizeof(S2S_BoardCfg
) + (i
* sizeof(S2S_TargetCfg
)));
483 const S2S_TargetCfg
* s2s_getConfigById(int scsiId
)
486 for (i
= 0; i
< S2S_MAX_TARGETS
; ++i
)
488 const S2S_TargetCfg
* tgt
= s2s_getConfigByIndex(i
);
489 if ((tgt
->scsiId
& S2S_CFG_TARGET_ID_BITS
) == scsiId
)