1 // Copyright (C) 2014 Michael McMaster <michael@codesrc.com>
\r
3 // This file is part of SCSI2SD.
\r
5 // SCSI2SD is free software: you can redistribute it and/or modify
\r
6 // it under the terms of the GNU General Public License as published by
\r
7 // the Free Software Foundation, either version 3 of the License, or
\r
8 // (at your option) any later version.
\r
10 // SCSI2SD is distributed in the hope that it will be useful,
\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 // GNU General Public License for more details.
\r
15 // You should have received a copy of the GNU General Public License
\r
16 // along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
\r
17 #pragma GCC push_options
\r
18 #pragma GCC optimize("-flto")
\r
27 #include "scsiPhy.h"
\r
30 #include "../../include/scsi2sd.h"
\r
31 #include "../../include/hidpacket.h"
\r
35 static const uint16_t FIRMWARE_VERSION = 0x0422;
\r
50 static uint8_t hidBuffer[USBHID_LEN];
\r
52 static int usbInEpState;
\r
53 static int usbDebugEpState;
\r
54 static int usbReady;
\r
58 // The USB block will be powered by an internal 3.3V regulator.
\r
59 // The PSoC must be operating between 4.6V and 5V for the regulator
\r
61 USBFS_Start(0, USBFS_5V_OPERATION);
\r
62 usbInEpState = usbDebugEpState = USB_IDLE;
\r
63 usbReady = 0; // We don't know if host is connected yet.
\r
67 readFlashCommand(const uint8_t* cmd, size_t cmdSize)
\r
73 uint8_t flashArray = cmd[1];
\r
74 uint8_t flashRow = cmd[2];
\r
78 (CY_FLASH_SIZEOF_ARRAY * (size_t) flashArray) +
\r
79 (CY_FLASH_SIZEOF_ROW * (size_t) flashRow);
\r
81 hidPacket_send(flash, SCSI_CONFIG_ROW_SIZE);
\r
85 writeFlashCommand(const uint8_t* cmd, size_t cmdSize)
\r
91 uint8_t flashArray = cmd[257];
\r
92 uint8_t flashRow = cmd[258];
\r
94 // Be very careful not to overwrite the bootloader or other
\r
96 if ((flashArray != SCSI_CONFIG_ARRAY) ||
\r
97 (flashRow < SCSI_CONFIG_0_ROW) ||
\r
98 (flashRow >= SCSI_CONFIG_3_ROW + SCSI_CONFIG_ROWS))
\r
100 uint8_t response[] = { CONFIG_STATUS_ERR};
\r
101 hidPacket_send(response, sizeof(response));
\r
106 int status = CyWriteRowData(flashArray, flashRow, cmd + 1);
\r
108 uint8_t response[] =
\r
110 status == CYRET_SUCCESS ? CONFIG_STATUS_GOOD : CONFIG_STATUS_ERR
\r
112 hidPacket_send(response, sizeof(response));
\r
119 uint8_t response[] =
\r
123 hidPacket_send(response, sizeof(response));
\r
129 uint8_t response[sizeof(sdDev.csd) + sizeof(sdDev.cid)];
\r
130 memcpy(response, sdDev.csd, sizeof(sdDev.csd));
\r
131 memcpy(response + sizeof(sdDev.csd), sdDev.cid, sizeof(sdDev.cid));
\r
133 hidPacket_send(response, sizeof(response));
\r
140 int resultCode = scsiSelfTest();
\r
141 uint8_t response[] =
\r
143 resultCode == 0 ? CONFIG_STATUS_GOOD : CONFIG_STATUS_ERR,
\r
146 hidPacket_send(response, sizeof(response));
\r
150 processCommand(const uint8_t* cmd, size_t cmdSize)
\r
158 case CONFIG_READFLASH:
\r
159 readFlashCommand(cmd, cmdSize);
\r
162 case CONFIG_WRITEFLASH:
\r
163 writeFlashCommand(cmd, cmdSize);
\r
166 case CONFIG_REBOOT:
\r
167 Bootloadable_1_Load();
\r
170 case CONFIG_SDINFO:
\r
174 case CONFIG_SCSITEST:
\r
178 case CONFIG_NONE: // invalid
\r
187 if (!usbReady || USBFS_IsConfigurationChanged())
\r
191 usbReady = USBFS_bGetConfiguration();
\r
200 USBFS_EnableOutEP(USB_EP_OUT);
\r
201 USBFS_EnableOutEP(USB_EP_COMMAND);
\r
202 usbInEpState = usbDebugEpState = USB_IDLE;
\r
205 if(USBFS_GetEPState(USB_EP_OUT) == USBFS_OUT_BUFFER_FULL)
\r
209 // The host sent us some data!
\r
210 int byteCount = USBFS_GetEPCount(USB_EP_OUT);
\r
211 USBFS_ReadOutEP(USB_EP_OUT, hidBuffer, sizeof(hidBuffer));
\r
212 hidPacket_recv(hidBuffer, byteCount);
\r
215 const uint8_t* cmd = hidPacket_getPacket(&cmdSize);
\r
216 if (cmd && (cmdSize > 0))
\r
218 processCommand(cmd, cmdSize);
\r
221 // Allow the host to send us another updated config.
\r
222 USBFS_EnableOutEP(USB_EP_OUT);
\r
227 switch (usbInEpState)
\r
231 const uint8_t* nextChunk = hidPacket_getHIDBytes(hidBuffer);
\r
235 USBFS_LoadInEP(USB_EP_IN, nextChunk, sizeof(hidBuffer));
\r
236 usbInEpState = USB_DATA_SENT;
\r
241 case USB_DATA_SENT:
\r
242 if (USBFS_bGetEPAckState(USB_EP_IN))
\r
245 usbInEpState = USB_IDLE;
\r
258 if(USBFS_GetEPState(USB_EP_COMMAND) == USBFS_OUT_BUFFER_FULL)
\r
260 // The host sent us some data!
\r
261 int byteCount = USBFS_GetEPCount(USB_EP_COMMAND);
\r
262 USBFS_ReadOutEP(USB_EP_COMMAND, (uint8 *)&hidBuffer, byteCount);
\r
264 if (byteCount >= 1 &&
\r
265 hidBuffer[0] == 0x01)
\r
268 Bootloadable_1_Load();
\r
271 // Allow the host to send us another command.
\r
272 // (assuming we didn't reboot outselves)
\r
273 USBFS_EnableOutEP(USB_EP_COMMAND);
\r
276 switch (usbDebugEpState)
\r
279 memcpy(&hidBuffer, &scsiDev.cdb, 12);
\r
280 hidBuffer[12] = scsiDev.msgIn;
\r
281 hidBuffer[13] = scsiDev.msgOut;
\r
282 hidBuffer[14] = scsiDev.lastStatus;
\r
283 hidBuffer[15] = scsiDev.lastSense;
\r
284 hidBuffer[16] = scsiDev.phase;
\r
285 hidBuffer[17] = SCSI_ReadFilt(SCSI_Filt_BSY);
\r
286 hidBuffer[18] = SCSI_ReadFilt(SCSI_Filt_SEL);
\r
287 hidBuffer[19] = SCSI_ReadFilt(SCSI_Filt_ATN);
\r
288 hidBuffer[20] = SCSI_ReadFilt(SCSI_Filt_RST);
\r
289 hidBuffer[21] = scsiDev.rstCount;
\r
290 hidBuffer[22] = scsiDev.selCount;
\r
291 hidBuffer[23] = scsiDev.msgCount;
\r
292 hidBuffer[24] = scsiDev.cmdCount;
\r
293 hidBuffer[25] = scsiDev.watchdogTick;
\r
294 hidBuffer[26] = blockDev.state;
\r
295 hidBuffer[27] = scsiDev.lastSenseASC >> 8;
\r
296 hidBuffer[28] = scsiDev.lastSenseASC;
\r
297 hidBuffer[29] = scsiReadDBxPins();
\r
299 hidBuffer[58] = sdDev.capacity >> 24;
\r
300 hidBuffer[59] = sdDev.capacity >> 16;
\r
301 hidBuffer[60] = sdDev.capacity >> 8;
\r
302 hidBuffer[61] = sdDev.capacity;
\r
304 hidBuffer[62] = FIRMWARE_VERSION >> 8;
\r
305 hidBuffer[63] = FIRMWARE_VERSION;
\r
307 USBFS_LoadInEP(USB_EP_DEBUG, (uint8 *)&hidBuffer, sizeof(hidBuffer));
\r
308 usbDebugEpState = USB_DATA_SENT;
\r
311 case USB_DATA_SENT:
\r
312 if (USBFS_bGetEPAckState(USB_EP_DEBUG))
\r
315 usbDebugEpState = USB_IDLE;
\r
321 CY_ISR(debugTimerISR)
\r
323 Debug_Timer_ReadStatusRegister();
\r
324 Debug_Timer_Interrupt_ClearPending();
\r
325 uint8 savedIntrStatus = CyEnterCriticalSection();
\r
327 CyExitCriticalSection(savedIntrStatus);
\r
332 Debug_Timer_Interrupt_StartEx(debugTimerISR);
\r
333 Debug_Timer_Start();
\r
338 Debug_Timer_Stop();
\r
343 Debug_Timer_Start();
\r
346 int isDebugEnabled()
\r
351 // Public method for storing MODE SELECT results.
\r
352 void configSave(int scsiId, uint16_t bytesPerSector)
\r
355 for (cfgIdx = 0; cfgIdx < MAX_SCSI_TARGETS; ++cfgIdx)
\r
357 const TargetConfig* tgt = getConfigByIndex(cfgIdx);
\r
358 if ((tgt->scsiId & CONFIG_TARGET_ID_BITS) == scsiId)
\r
360 // Save row to flash
\r
361 // We only save the first row of the configuration
\r
362 // this contains the parameters changeable by a MODE SELECT command
\r
363 uint8_t rowData[CYDEV_FLS_ROW_SIZE];
\r
364 TargetConfig* rowCfgData = (TargetConfig*)&rowData;
\r
365 memcpy(rowCfgData, tgt, sizeof(rowData));
\r
366 rowCfgData->bytesPerSector = bytesPerSector;
\r
371 SCSI_CONFIG_0_ROW + (cfgIdx * SCSI_CONFIG_ROWS),
\r
372 (uint8_t*)rowCfgData);
\r
379 const TargetConfig* getConfigByIndex(int i)
\r
381 size_t row = SCSI_CONFIG_0_ROW + (i * SCSI_CONFIG_ROWS);
\r
382 return (const TargetConfig*)
\r
385 (CY_FLASH_SIZEOF_ARRAY * (size_t) SCSI_CONFIG_ARRAY) +
\r
386 (CY_FLASH_SIZEOF_ROW * row)
\r
390 const TargetConfig* getConfigById(int scsiId)
\r
393 for (i = 0; i < MAX_SCSI_TARGETS; ++i)
\r
395 const TargetConfig* tgt = getConfigByIndex(i);
\r
396 if ((tgt->scsiId & CONFIG_TARGET_ID_BITS) == scsiId)
\r
405 #pragma GCC pop_options
\r