127ca1b53ed015e069ef1629ecdefb369bef0b17
[SCSI2SD-V6.git] / src / firmware / 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 "config.h"\r
19 #include "led.h"\r
20 \r
21 #include "scsi.h"\r
22 #include "scsiPhy.h"\r
23 #include "sd.h"\r
24 #include "disk.h"\r
25 #include "trace.h"\r
26 #include "bootloader.h"\r
27 #include "bsp.h"\r
28 \r
29 #include "../../include/scsi2sd.h"\r
30 #include "../../include/hidpacket.h"\r
31 \r
32 #include "usb_device/usb_device.h"\r
33 #include "usb_device/usbd_hid.h"\r
34 #include "usb_device/usbd_composite.h"\r
35 #include "bsp_driver_sd.h"\r
36 \r
37 \r
38 #include <string.h>\r
39 \r
40 static const uint16_t FIRMWARE_VERSION = 0x060E;\r
41 \r
42 // 1 flash row\r
43 static const uint8_t DEFAULT_CONFIG[128] =\r
44 {\r
45         0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 0x00,\r
46         0x00, 0x02, 0x3F, 0x00, 0xFF, 0x00, 0x20, 0x63, 0x6F, 0x64, 0x65, 0x73,\r
47         0x72, 0x63, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,\r
48         0x43, 0x53, 0x49, 0x32, 0x53, 0x44, 0x20, 0x31, 0x2E, 0x30, 0x31, 0x32,\r
49         0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,\r
50         0x37, 0x38, 0x00, 0x00\r
51 };\r
52 \r
53 \r
54 static uint8_t s2s_cfg[S2S_CFG_SIZE] S2S_DMA_ALIGN;\r
55 static uint8_t configDmaBuf[512] S2S_DMA_ALIGN; // For SD card writes.\r
56 \r
57 \r
58 enum USB_STATE\r
59 {\r
60         USB_IDLE,\r
61         USB_DATA_SENT\r
62 };\r
63 \r
64 \r
65 static int usbInEpState;\r
66 \r
67 void s2s_configInit(S2S_BoardCfg* config)\r
68 {\r
69 \r
70         usbInEpState = USB_IDLE;\r
71 \r
72 \r
73         if ((blockDev.state & DISK_PRESENT) && sdDev.capacity)\r
74         {\r
75                 int cfgSectors = (S2S_CFG_SIZE + 511) / 512;\r
76                 BSP_SD_ReadBlocks_DMA(\r
77                         (uint32_t*) &s2s_cfg[0],\r
78                         (sdDev.capacity - cfgSectors) * 512ll,\r
79                         512,\r
80                         cfgSectors);\r
81 \r
82                 memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));\r
83 \r
84                 if (memcmp(config->magic, "BCFG", 4))\r
85                 {\r
86                         // Invalid SD card config, use default.\r
87                         memset(&s2s_cfg[0], 0, S2S_CFG_SIZE);\r
88                         memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));\r
89                         memcpy(config->magic, "BCFG", 4);\r
90                         config->selectionDelay = 255; // auto\r
91                         config->flags6 = S2S_CFG_ENABLE_TERMINATOR;\r
92 \r
93                         memcpy(\r
94                                 &s2s_cfg[0] + sizeof(S2S_BoardCfg),\r
95                                 DEFAULT_CONFIG,\r
96                                 sizeof(S2S_TargetCfg));\r
97                 }\r
98         }\r
99         else\r
100         {\r
101                 // No SD card, use existing config if valid\r
102                 if (memcmp(config->magic, "BCFG", 4))\r
103                 {\r
104                         // Not valid, use empty config with no disks.\r
105                         memset(&s2s_cfg[0], 0, S2S_CFG_SIZE);\r
106                         memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));\r
107                         config->selectionDelay = 255; // auto\r
108                         config->flags6 = S2S_CFG_ENABLE_TERMINATOR;\r
109                 }\r
110         }\r
111 \r
112 }\r
113 \r
114 \r
115 static void\r
116 pingCommand()\r
117 {\r
118         uint8_t response[] =\r
119         {\r
120                 S2S_CFG_STATUS_GOOD\r
121         };\r
122         hidPacket_send(response, sizeof(response));\r
123 }\r
124 \r
125 static void\r
126 sdInfoCommand()\r
127 {\r
128         uint8_t response[sizeof(sdDev.csd) + sizeof(sdDev.cid)];\r
129         memcpy(response, sdDev.csd, sizeof(sdDev.csd));\r
130         memcpy(response + sizeof(sdDev.csd), sdDev.cid, sizeof(sdDev.cid));\r
131 \r
132         hidPacket_send(response, sizeof(response));\r
133 }\r
134 \r
135 \r
136 static void\r
137 scsiTestCommand()\r
138 {\r
139         int resultCode = scsiSelfTest();\r
140         uint8_t response[] =\r
141         {\r
142                 resultCode == 0 ? S2S_CFG_STATUS_GOOD : S2S_CFG_STATUS_ERR,\r
143                 resultCode\r
144         };\r
145         hidPacket_send(response, sizeof(response));\r
146 }\r
147 \r
148 static void\r
149 scsiDevInfoCommand()\r
150 {\r
151         uint8_t response[] =\r
152         {\r
153                 FIRMWARE_VERSION >> 8,\r
154                 FIRMWARE_VERSION & 0xff,\r
155                 sdDev.capacity >> 24,\r
156                 sdDev.capacity >> 16,\r
157                 sdDev.capacity >> 8,\r
158                 sdDev.capacity\r
159         };\r
160         hidPacket_send(response, sizeof(response));\r
161 }\r
162 \r
163 static void\r
164 debugCommand()\r
165 {\r
166         uint8_t response[32];\r
167         memcpy(&response, &scsiDev.cdb, 12);\r
168         response[12] = scsiDev.msgIn;\r
169         response[13] = scsiDev.msgOut;\r
170         response[14] = scsiDev.lastStatus;\r
171         response[15] = scsiDev.lastSense;\r
172         response[16] = scsiDev.phase;\r
173         response[17] = *SCSI_STS_SCSI;\r
174         response[18] = scsiDev.target != NULL ? scsiDev.target->syncOffset : 0;\r
175         response[19] = scsiDev.target != NULL ? scsiDev.target->syncPeriod : 0;\r
176         response[20] = scsiDev.minSyncPeriod;\r
177         response[21] = scsiDev.rstCount;\r
178         response[22] = scsiDev.selCount;\r
179         response[23] = scsiDev.msgCount;\r
180         response[24] = scsiDev.cmdCount;\r
181         response[25] = scsiDev.watchdogTick;\r
182         response[26] = blockDev.state;\r
183         response[27] = scsiDev.lastSenseASC >> 8;\r
184         response[28] = scsiDev.lastSenseASC;\r
185         response[29] = *SCSI_STS_DBX;\r
186         response[30] = LastTrace;\r
187         response[31] = 0; // Unused\r
188         hidPacket_send(response, sizeof(response));\r
189 }\r
190 \r
191 static void\r
192 sdWriteCommand(const uint8_t* cmd, size_t cmdSize)\r
193 {\r
194         if (cmdSize < 517)\r
195         {\r
196                 return; // ignore.\r
197         }\r
198         uint32_t lba =\r
199                 (((uint32_t)cmd[1]) << 24) |\r
200                 (((uint32_t)cmd[2]) << 16) |\r
201                 (((uint32_t)cmd[3]) << 8) |\r
202                 ((uint32_t)cmd[4]);\r
203 \r
204         memcpy(configDmaBuf, &cmd[5], 512);\r
205         BSP_SD_WriteBlocks_DMA((uint32_t*) configDmaBuf, lba * 512ll, 512, 1);\r
206 \r
207         uint8_t response[] =\r
208         {\r
209                 S2S_CFG_STATUS_GOOD\r
210         };\r
211         hidPacket_send(response, sizeof(response));\r
212 }\r
213 \r
214 static void\r
215 sdReadCommand(const uint8_t* cmd, size_t cmdSize)\r
216 {\r
217         if (cmdSize < 5)\r
218         {\r
219                 return; // ignore.\r
220         }\r
221         uint32_t lba =\r
222                 (((uint32_t)cmd[1]) << 24) |\r
223                 (((uint32_t)cmd[2]) << 16) |\r
224                 (((uint32_t)cmd[3]) << 8) |\r
225                 ((uint32_t)cmd[4]);\r
226 \r
227         BSP_SD_ReadBlocks_DMA((uint32_t*) configDmaBuf, lba * 512ll, 512, 1);\r
228         hidPacket_send(configDmaBuf, 512);\r
229 }\r
230 \r
231 static void\r
232 processCommand(const uint8_t* cmd, size_t cmdSize)\r
233 {\r
234         switch (cmd[0])\r
235         {\r
236         case S2S_CMD_PING:\r
237                 pingCommand();\r
238                 break;\r
239 \r
240         case S2S_CMD_REBOOT:\r
241                 s2s_enterBootloader();\r
242                 break;\r
243 \r
244         case S2S_CMD_SDINFO:\r
245                 sdInfoCommand();\r
246                 break;\r
247 \r
248         case S2S_CMD_SCSITEST:\r
249                 scsiTestCommand();\r
250                 break;\r
251 \r
252         case S2S_CMD_DEVINFO:\r
253                 scsiDevInfoCommand();\r
254                 break;\r
255 \r
256         case S2S_CMD_SD_WRITE:\r
257                 sdWriteCommand(cmd, cmdSize);\r
258                 break;\r
259 \r
260         case S2S_CMD_SD_READ:\r
261                 sdReadCommand(cmd, cmdSize);\r
262                 break;\r
263 \r
264         case S2S_CMD_DEBUG:\r
265                 debugCommand();\r
266                 break;\r
267 \r
268         case S2S_CMD_NONE: // invalid\r
269         default:\r
270                 break;\r
271         }\r
272 }\r
273 \r
274 void s2s_configPoll()\r
275 {\r
276         if (!USBD_Composite_IsConfigured(&hUsbDeviceFS))\r
277         {\r
278                 usbInEpState = USB_IDLE;\r
279                 return;\r
280         }\r
281 \r
282         if (USBD_HID_IsReportReady(&hUsbDeviceFS))\r
283         {\r
284                 s2s_ledOn();\r
285 \r
286                 // The host sent us some data!\r
287                 uint8_t hidBuffer[USBHID_LEN];\r
288                 int byteCount = USBD_HID_GetReport(&hUsbDeviceFS, hidBuffer, sizeof(hidBuffer));\r
289                 hidPacket_recv(hidBuffer, byteCount);\r
290 \r
291                 size_t cmdSize;\r
292                 const uint8_t* cmd = hidPacket_getPacket(&cmdSize);\r
293                 if (cmd && (cmdSize > 0))\r
294                 {\r
295                         processCommand(cmd, cmdSize);\r
296                 }\r
297 \r
298                 s2s_ledOff();\r
299         }\r
300 \r
301         switch (usbInEpState)\r
302         {\r
303         case USB_IDLE:\r
304                 {\r
305                         uint8_t hidBuffer[USBHID_LEN];\r
306                         const uint8_t* nextChunk = hidPacket_getHIDBytes(hidBuffer);\r
307 \r
308                         if (nextChunk)\r
309                         {\r
310                                 USBD_HID_SendReport (&hUsbDeviceFS, nextChunk, sizeof(hidBuffer));\r
311                                 usbInEpState = USB_DATA_SENT;\r
312                         }\r
313                 }\r
314                 break;\r
315 \r
316         case USB_DATA_SENT:\r
317                 if (!USBD_HID_IsBusy(&hUsbDeviceFS))\r
318                 {\r
319                         // Data accepted.\r
320                         usbInEpState = USB_IDLE;\r
321                 }\r
322                 break;\r
323         }\r
324 \r
325 }\r
326 \r
327 \r
328 \r
329 // Public method for storing MODE SELECT results.\r
330 void s2s_configSave(int scsiId, uint16_t bytesPerSector)\r
331 {\r
332         S2S_TargetCfg* cfg = (S2S_TargetCfg*) s2s_getConfigById(scsiId);\r
333         cfg->bytesPerSector = bytesPerSector;\r
334 \r
335         BSP_SD_WriteBlocks_DMA(\r
336                 (uint32_t*) &s2s_cfg[0],\r
337                 (sdDev.capacity - S2S_CFG_SIZE) * 512ll,\r
338                 512,\r
339                 (S2S_CFG_SIZE + 511) / 512);\r
340 }\r
341 \r
342 \r
343 const S2S_TargetCfg* s2s_getConfigByIndex(int i)\r
344 {\r
345         return (const S2S_TargetCfg*)\r
346                 (s2s_cfg + sizeof(S2S_BoardCfg) + (i * sizeof(S2S_TargetCfg)));\r
347 }\r
348 \r
349 const S2S_TargetCfg* s2s_getConfigById(int scsiId)\r
350 {\r
351         int i;\r
352         for (i = 0; i < S2S_MAX_TARGETS; ++i)\r
353         {\r
354                 const S2S_TargetCfg* tgt = s2s_getConfigByIndex(i);\r
355                 if ((tgt->scsiId & S2S_CFG_TARGET_ID_BITS) == scsiId)\r
356                 {\r
357                         return tgt;\r
358                 }\r
359         }\r
360         return NULL;\r
361 \r
362 }\r
363 \r