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