Small compatibility improvements, and added scsi2sd-monitor test program
[SCSI2SD-V6.git] / software / SCSI2SD / src / config.c
CommitLineData
6c8cbf54 1// Copyright (C) 2014 Michael McMaster <michael@codesrc.com>\r
b9ed3652
MM
2//\r
3// This file is part of SCSI2SD.\r
4//\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
9//\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
14//\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
95b51978
MM
17#pragma GCC push_options\r
18#pragma GCC optimize("-flto")\r
b9ed3652
MM
19\r
20#include "device.h"\r
21#include "config.h"\r
70257ca8 22#include "debug.h"\r
7193c6f2
MM
23#include "USBFS.h"\r
24#include "led.h"\r
b9ed3652 25\r
6c8cbf54
MM
26#include "scsi.h"\r
27#include "scsiPhy.h"\r
030fc25f 28#include "disk.h"\r
6c8cbf54 29\r
75f825e6
MM
30#include "../../include/scsi2sd.h"\r
31#include "../../include/hidpacket.h"\r
32\r
b9ed3652
MM
33#include <string.h>\r
34\r
9ad7cc15 35static const uint16_t FIRMWARE_VERSION = 0x0422;\r
b9ed3652 36\r
7193c6f2
MM
37enum USB_ENDPOINTS\r
38{\r
39 USB_EP_OUT = 1,\r
db9c3160 40 USB_EP_IN = 2,\r
5e0f1e33 41 USB_EP_COMMAND = 3,\r
db9c3160 42 USB_EP_DEBUG = 4\r
7193c6f2
MM
43};\r
44enum USB_STATE\r
45{\r
46 USB_IDLE,\r
47 USB_DATA_SENT\r
48};\r
7193c6f2 49\r
75f825e6
MM
50static uint8_t hidBuffer[USBHID_LEN];\r
51\r
52static int usbInEpState;\r
53static int usbDebugEpState;\r
54static int usbReady;\r
7193c6f2 55\r
9ad7cc15
MM
56uint8_t DEFAULT_CONFIG[256]\r
57 __attribute__ ((section(".DEFAULT_CONFIG"))) =\r
58{\r
59 CONFIG_TARGET_ENABLED,\r
60 CONFIG_FIXED,\r
61 0,\r
62 0,\r
63 0, 0, 0, 0,\r
64 0xff, 0xff, 0x3f, 0x00, // 4194303, 2GB - 1 sector\r
65 0x00, 0x02, //512\r
66 63, 0,\r
67 255, 0,\r
68 ' ', 'c', 'o', 'd', 'e', 's', 'r', 'c',\r
69 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'S', 'C', 'S', 'I', '2', 'S', 'D',\r
70 ' ', '4', '.', '2',\r
71 '1','2','3','4','5','6','7','8','1','2','3','4','5','6','7','8'\r
72};\r
73// otherwise linker removes unused section.\r
74volatile uint8_t trickLinker;\r
75\r
b9ed3652
MM
76void configInit()\r
77{\r
9ad7cc15
MM
78 trickLinker = DEFAULT_CONFIG[0];\r
79\r
7193c6f2
MM
80 // The USB block will be powered by an internal 3.3V regulator.\r
81 // The PSoC must be operating between 4.6V and 5V for the regulator\r
82 // to work.\r
83 USBFS_Start(0, USBFS_5V_OPERATION);\r
db9c3160 84 usbInEpState = usbDebugEpState = USB_IDLE;\r
7193c6f2
MM
85 usbReady = 0; // We don't know if host is connected yet.\r
86}\r
87\r
75f825e6
MM
88static void\r
89readFlashCommand(const uint8_t* cmd, size_t cmdSize)\r
90{\r
91 if (cmdSize < 3)\r
92 {\r
93 return; // ignore.\r
94 }\r
95 uint8_t flashArray = cmd[1];\r
96 uint8_t flashRow = cmd[2];\r
97\r
98 uint8_t* flash =\r
99 CY_FLASH_BASE +\r
100 (CY_FLASH_SIZEOF_ARRAY * (size_t) flashArray) +\r
101 (CY_FLASH_SIZEOF_ROW * (size_t) flashRow);\r
102\r
103 hidPacket_send(flash, SCSI_CONFIG_ROW_SIZE);\r
104}\r
105\r
106static void\r
107writeFlashCommand(const uint8_t* cmd, size_t cmdSize)\r
108{\r
109 if (cmdSize < 259)\r
110 {\r
111 return; // ignore.\r
112 }\r
113 uint8_t flashArray = cmd[257];\r
114 uint8_t flashRow = cmd[258];\r
115\r
116 // Be very careful not to overwrite the bootloader or other\r
117 // code\r
118 if ((flashArray != SCSI_CONFIG_ARRAY) ||\r
119 (flashRow < SCSI_CONFIG_0_ROW) ||\r
120 (flashRow >= SCSI_CONFIG_3_ROW + SCSI_CONFIG_ROWS))\r
121 {\r
122 uint8_t response[] = { CONFIG_STATUS_ERR};\r
123 hidPacket_send(response, sizeof(response));\r
124 }\r
125 else\r
126 {\r
75f825e6
MM
127 CySetTemp();\r
128 int status = CyWriteRowData(flashArray, flashRow, cmd + 1);\r
75f825e6
MM
129\r
130 uint8_t response[] =\r
131 {\r
132 status == CYRET_SUCCESS ? CONFIG_STATUS_GOOD : CONFIG_STATUS_ERR\r
133 };\r
134 hidPacket_send(response, sizeof(response));\r
135 }\r
136}\r
137\r
138static void\r
139pingCommand()\r
140{\r
141 uint8_t response[] =\r
142 {\r
143 CONFIG_STATUS_GOOD\r
144 };\r
145 hidPacket_send(response, sizeof(response));\r
146}\r
147\r
70257ca8
MM
148static void\r
149sdInfoCommand()\r
150{\r
151 uint8_t response[sizeof(sdDev.csd) + sizeof(sdDev.cid)];\r
152 memcpy(response, sdDev.csd, sizeof(sdDev.csd));\r
153 memcpy(response + sizeof(sdDev.csd), sdDev.cid, sizeof(sdDev.cid));\r
154\r
155 hidPacket_send(response, sizeof(response));\r
156}\r
9ad7cc15
MM
157\r
158\r
159static void\r
160scsiTestCommand()\r
161{\r
162 int resultCode = scsiSelfTest();\r
163 uint8_t response[] =\r
164 {\r
165 resultCode == 0 ? CONFIG_STATUS_GOOD : CONFIG_STATUS_ERR,\r
166 resultCode\r
167 };\r
168 hidPacket_send(response, sizeof(response));\r
169}\r
170\r
75f825e6
MM
171static void\r
172processCommand(const uint8_t* cmd, size_t cmdSize)\r
173{\r
174 switch (cmd[0])\r
175 {\r
176 case CONFIG_PING:\r
177 pingCommand();\r
178 break;\r
179\r
180 case CONFIG_READFLASH:\r
181 readFlashCommand(cmd, cmdSize);\r
182 break;\r
183\r
184 case CONFIG_WRITEFLASH:\r
185 writeFlashCommand(cmd, cmdSize);\r
186 break;\r
187\r
188 case CONFIG_REBOOT:\r
189 Bootloadable_1_Load();\r
190 break;\r
191\r
70257ca8
MM
192 case CONFIG_SDINFO:\r
193 sdInfoCommand();\r
194 break;\r
195\r
9ad7cc15
MM
196 case CONFIG_SCSITEST:\r
197 scsiTestCommand();\r
198 break;\r
199\r
75f825e6
MM
200 case CONFIG_NONE: // invalid\r
201 default:\r
202 break;\r
203 }\r
204}\r
205\r
7193c6f2
MM
206void configPoll()\r
207{\r
208 int reset = 0;\r
209 if (!usbReady || USBFS_IsConfigurationChanged())\r
210 {\r
211 reset = 1;\r
212 }\r
213 usbReady = USBFS_bGetConfiguration();\r
214\r
215 if (!usbReady)\r
216 {\r
217 return;\r
218 }\r
6c8cbf54 219\r
7193c6f2
MM
220 if (reset)\r
221 {\r
222 USBFS_EnableOutEP(USB_EP_OUT);\r
5e0f1e33 223 USBFS_EnableOutEP(USB_EP_COMMAND);\r
db9c3160 224 usbInEpState = usbDebugEpState = USB_IDLE;\r
6c8cbf54 225 }\r
7193c6f2
MM
226\r
227 if(USBFS_GetEPState(USB_EP_OUT) == USBFS_OUT_BUFFER_FULL)\r
228 {\r
c8389e5f 229 ledOn();\r
6c8cbf54 230\r
7193c6f2 231 // The host sent us some data!\r
75f825e6
MM
232 int byteCount = USBFS_GetEPCount(USB_EP_OUT);\r
233 USBFS_ReadOutEP(USB_EP_OUT, hidBuffer, sizeof(hidBuffer));\r
234 hidPacket_recv(hidBuffer, byteCount);\r
7193c6f2 235\r
75f825e6
MM
236 size_t cmdSize;\r
237 const uint8_t* cmd = hidPacket_getPacket(&cmdSize);\r
238 if (cmd && (cmdSize > 0))\r
0bb5ed83 239 {\r
75f825e6 240 processCommand(cmd, cmdSize);\r
0bb5ed83 241 }\r
7193c6f2 242\r
7193c6f2
MM
243 // Allow the host to send us another updated config.\r
244 USBFS_EnableOutEP(USB_EP_OUT);\r
245\r
6c8cbf54 246 ledOff();\r
7193c6f2
MM
247 }\r
248\r
249 switch (usbInEpState)\r
250 {\r
251 case USB_IDLE:\r
75f825e6
MM
252 {\r
253 const uint8_t* nextChunk = hidPacket_getHIDBytes(hidBuffer);\r
0bb5ed83 254\r
75f825e6
MM
255 if (nextChunk)\r
256 {\r
257 USBFS_LoadInEP(USB_EP_IN, nextChunk, sizeof(hidBuffer));\r
258 usbInEpState = USB_DATA_SENT;\r
259 }\r
260 }\r
7193c6f2
MM
261 break;\r
262\r
263 case USB_DATA_SENT:\r
264 if (USBFS_bGetEPAckState(USB_EP_IN))\r
265 {\r
266 // Data accepted.\r
267 usbInEpState = USB_IDLE;\r
268 }\r
269 break;\r
270 }\r
271}\r
272\r
db9c3160
MM
273void debugPoll()\r
274{\r
275 if (!usbReady)\r
276 {\r
277 return;\r
278 }\r
5e0f1e33
MM
279\r
280 if(USBFS_GetEPState(USB_EP_COMMAND) == USBFS_OUT_BUFFER_FULL)\r
281 {\r
282 // The host sent us some data!\r
283 int byteCount = USBFS_GetEPCount(USB_EP_COMMAND);\r
75f825e6 284 USBFS_ReadOutEP(USB_EP_COMMAND, (uint8 *)&hidBuffer, byteCount);\r
5e0f1e33
MM
285\r
286 if (byteCount >= 1 &&\r
75f825e6 287 hidBuffer[0] == 0x01)\r
5e0f1e33
MM
288 {\r
289 // Reboot command.\r
290 Bootloadable_1_Load();\r
291 }\r
292\r
293 // Allow the host to send us another command.\r
294 // (assuming we didn't reboot outselves)\r
295 USBFS_EnableOutEP(USB_EP_COMMAND);\r
296 }\r
297\r
db9c3160
MM
298 switch (usbDebugEpState)\r
299 {\r
300 case USB_IDLE:\r
75f825e6
MM
301 memcpy(&hidBuffer, &scsiDev.cdb, 12);\r
302 hidBuffer[12] = scsiDev.msgIn;\r
303 hidBuffer[13] = scsiDev.msgOut;\r
304 hidBuffer[14] = scsiDev.lastStatus;\r
305 hidBuffer[15] = scsiDev.lastSense;\r
306 hidBuffer[16] = scsiDev.phase;\r
b19a0a4c
MM
307 hidBuffer[17] = SCSI_ReadFilt(SCSI_Filt_BSY);\r
308 hidBuffer[18] = SCSI_ReadFilt(SCSI_Filt_SEL);\r
309 hidBuffer[19] = SCSI_ReadFilt(SCSI_Filt_ATN);\r
310 hidBuffer[20] = SCSI_ReadFilt(SCSI_Filt_RST);\r
75f825e6
MM
311 hidBuffer[21] = scsiDev.rstCount;\r
312 hidBuffer[22] = scsiDev.selCount;\r
313 hidBuffer[23] = scsiDev.msgCount;\r
314 hidBuffer[24] = scsiDev.cmdCount;\r
315 hidBuffer[25] = scsiDev.watchdogTick;\r
638c94ce 316 hidBuffer[26] = blockDev.state;\r
70257ca8
MM
317 hidBuffer[27] = scsiDev.lastSenseASC >> 8;\r
318 hidBuffer[28] = scsiDev.lastSenseASC;\r
95b51978 319 hidBuffer[29] = scsiReadDBxPins();\r
70257ca8 320\r
75f825e6
MM
321 hidBuffer[58] = sdDev.capacity >> 24;\r
322 hidBuffer[59] = sdDev.capacity >> 16;\r
323 hidBuffer[60] = sdDev.capacity >> 8;\r
324 hidBuffer[61] = sdDev.capacity;\r
325\r
326 hidBuffer[62] = FIRMWARE_VERSION >> 8;\r
327 hidBuffer[63] = FIRMWARE_VERSION;\r
328\r
329 USBFS_LoadInEP(USB_EP_DEBUG, (uint8 *)&hidBuffer, sizeof(hidBuffer));\r
db9c3160
MM
330 usbDebugEpState = USB_DATA_SENT;\r
331 break;\r
332\r
333 case USB_DATA_SENT:\r
334 if (USBFS_bGetEPAckState(USB_EP_DEBUG))\r
335 {\r
336 // Data accepted.\r
337 usbDebugEpState = USB_IDLE;\r
338 }\r
339 break;\r
340 }\r
341}\r
342\r
343CY_ISR(debugTimerISR)\r
344{\r
345 Debug_Timer_ReadStatusRegister();\r
346 Debug_Timer_Interrupt_ClearPending();\r
347 uint8 savedIntrStatus = CyEnterCriticalSection();\r
348 debugPoll();\r
75f825e6 349 CyExitCriticalSection(savedIntrStatus);\r
db9c3160
MM
350}\r
351\r
352void debugInit()\r
353{\r
db9c3160
MM
354 Debug_Timer_Interrupt_StartEx(debugTimerISR);\r
355 Debug_Timer_Start();\r
db9c3160
MM
356}\r
357\r
70257ca8
MM
358void debugPause()\r
359{\r
360 Debug_Timer_Stop();\r
361}\r
362\r
363void debugResume()\r
364{\r
365 Debug_Timer_Start();\r
366}\r
367\r
95b51978
MM
368int isDebugEnabled()\r
369{\r
370 return usbReady;\r
371}\r
372\r
0bb5ed83 373// Public method for storing MODE SELECT results.\r
638c94ce 374void configSave(int scsiId, uint16_t bytesPerSector)\r
0bb5ed83 375{\r
638c94ce
MM
376 int cfgIdx;\r
377 for (cfgIdx = 0; cfgIdx < MAX_SCSI_TARGETS; ++cfgIdx)\r
378 {\r
379 const TargetConfig* tgt = getConfigByIndex(cfgIdx);\r
380 if ((tgt->scsiId & CONFIG_TARGET_ID_BITS) == scsiId)\r
381 {\r
382 // Save row to flash\r
383 // We only save the first row of the configuration\r
384 // this contains the parameters changeable by a MODE SELECT command\r
385 uint8_t rowData[CYDEV_FLS_ROW_SIZE];\r
386 TargetConfig* rowCfgData = (TargetConfig*)&rowData;\r
387 memcpy(rowCfgData, tgt, sizeof(rowData));\r
388 rowCfgData->bytesPerSector = bytesPerSector;\r
389\r
638c94ce
MM
390 CySetTemp();\r
391 CyWriteRowData(\r
392 SCSI_CONFIG_ARRAY,\r
393 SCSI_CONFIG_0_ROW + (cfgIdx * SCSI_CONFIG_ROWS),\r
394 (uint8_t*)rowCfgData);\r
638c94ce
MM
395 return;\r
396 }\r
397 }\r
0bb5ed83
MM
398}\r
399\r
b19a0a4c
MM
400\r
401const TargetConfig* getConfigByIndex(int i)\r
402{\r
403 size_t row = SCSI_CONFIG_0_ROW + (i * SCSI_CONFIG_ROWS);\r
404 return (const TargetConfig*)\r
405 (\r
406 CY_FLASH_BASE +\r
407 (CY_FLASH_SIZEOF_ARRAY * (size_t) SCSI_CONFIG_ARRAY) +\r
408 (CY_FLASH_SIZEOF_ROW * row)\r
409 );\r
410}\r
411\r
412const TargetConfig* getConfigById(int scsiId)\r
413{\r
414 int i;\r
415 for (i = 0; i < MAX_SCSI_TARGETS; ++i)\r
416 {\r
417 const TargetConfig* tgt = getConfigByIndex(i);\r
418 if ((tgt->scsiId & CONFIG_TARGET_ID_BITS) == scsiId)\r
419 {\r
420 return tgt;\r
421 }\r
422 }\r
423 return NULL;\r
424\r
425}\r
426\r
95b51978 427#pragma GCC pop_options\r