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