9abdc676ceb3d231cb0c21a9efe84da1f3d65064
[SCSI2SD.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 <string.h>\r
28 \r
29 // CYDEV_EEPROM_ROW_SIZE == 16.\r
30 static char magic[CYDEV_EEPROM_ROW_SIZE] = "codesrc_00000001";\r
31 \r
32 // Config shadow RAM (copy of EEPROM)\r
33 static Config shadow =\r
34 {\r
35         0, // SCSI ID\r
36         " codesrc", // vendor  (68k Apple Drive Setup: Set to " SEAGATE")\r
37         "         SCSI2SD", //prodId (68k Apple Drive Setup: Set to "          ST225N")\r
38         " 3.3", // revision (68k Apple Drive Setup: Set to "1.0 ")\r
39         1, // enable parity\r
40         1, // enable unit attention,\r
41         0 // Max blocks (0 == disabled)\r
42         // reserved bytes will be initialised to 0.\r
43 };\r
44 \r
45 enum USB_ENDPOINTS\r
46 {\r
47         USB_EP_OUT = 1,\r
48         USB_EP_IN = 2\r
49 };\r
50 enum USB_STATE\r
51 {\r
52         USB_IDLE,\r
53         USB_DATA_SENT\r
54 };\r
55 int usbInEpState;\r
56 \r
57 int usbReady;\r
58 \r
59 // Global\r
60 Config* config = NULL;\r
61 \r
62 // The PSoC 5LP compile to little-endian format.\r
63 static uint32_t ntohl(uint32_t val)\r
64 {\r
65         return\r
66                 ((val & 0xFF) << 24) |\r
67                 ((val & 0xFF00) << 8) |\r
68                 ((val >> 8) & 0xFF00) |\r
69                 ((val >> 24) & 0xFF);\r
70 }\r
71 static uint32_t htonl(uint32_t val)\r
72 {\r
73         return\r
74                 ((val & 0xFF) << 24) |\r
75                 ((val & 0xFF00) << 8) |\r
76                 ((val >> 8) & 0xFF00) |\r
77                 ((val >> 24) & 0xFF);\r
78 }\r
79 \r
80 static void saveConfig()\r
81 {\r
82         int shadowRows = (sizeof(shadow) / CYDEV_EEPROM_ROW_SIZE) + 1;\r
83         int row;\r
84         int status = CYRET_SUCCESS;\r
85 \r
86         CySetTemp();\r
87         for (row = 0; (row < shadowRows) && (status == CYRET_SUCCESS); ++row)\r
88         {\r
89                 CFG_EEPROM_Write(((uint8*)&shadow) + (row * CYDEV_EEPROM_ROW_SIZE), row);\r
90         }\r
91         if (status == CYRET_SUCCESS)\r
92         {\r
93                 CFG_EEPROM_Write((uint8*)magic, row);\r
94         }\r
95 }\r
96 \r
97 void configInit()\r
98 {\r
99         int shadowRows, shadowBytes;\r
100         uint8* eeprom = (uint8*)CYDEV_EE_BASE;\r
101 \r
102         // We could map cfgPtr directly into the EEPROM memory,\r
103         // but that would waste power. Copy it to RAM then turn off\r
104         // the EEPROM.\r
105         CFG_EEPROM_Start();\r
106         CyDelayUs(5); // 5us to start per datasheet.\r
107 \r
108         // Check magic\r
109         shadowRows = (sizeof(shadow) / CYDEV_EEPROM_ROW_SIZE) + 1;\r
110         shadowBytes = CYDEV_EEPROM_ROW_SIZE * shadowRows;\r
111 \r
112         if (memcmp(eeprom + shadowBytes, magic, sizeof(magic)))\r
113         {\r
114                 saveConfig();\r
115         }\r
116         else\r
117         {\r
118                 memcpy(&shadow, eeprom, sizeof(shadow));\r
119         }\r
120         config = &shadow;\r
121         CFG_EEPROM_Stop();\r
122 \r
123         // The USB block will be powered by an internal 3.3V regulator.\r
124         // The PSoC must be operating between 4.6V and 5V for the regulator\r
125         // to work.\r
126         USBFS_Start(0, USBFS_5V_OPERATION);\r
127         usbInEpState = USB_IDLE;\r
128         usbReady = 0; // We don't know if host is connected yet.\r
129 }\r
130 \r
131 void configPoll()\r
132 {\r
133         int reset = 0;\r
134         if (!usbReady || USBFS_IsConfigurationChanged())\r
135         {\r
136                 reset = 1;\r
137         }\r
138         usbReady = USBFS_bGetConfiguration();\r
139 \r
140         if (!usbReady)\r
141         {\r
142                 return;\r
143         }\r
144 \r
145         if (reset)\r
146         {\r
147                 USBFS_EnableOutEP(USB_EP_OUT);\r
148                 usbInEpState = USB_IDLE;\r
149         }\r
150 \r
151         if(USBFS_GetEPState(USB_EP_OUT) == USBFS_OUT_BUFFER_FULL)\r
152         {\r
153                 int byteCount;\r
154 \r
155                 ledOn();\r
156 \r
157                 // The host sent us some data!\r
158                 byteCount = USBFS_GetEPCount(USB_EP_OUT);\r
159 \r
160                 // Assume that byteCount <= sizeof(shadow).\r
161                 // shadow should be padded out to 64bytes, which is the largest\r
162                 // possible HID transfer.\r
163                 USBFS_ReadOutEP(USB_EP_OUT, (uint8 *)&shadow, byteCount);\r
164                 shadow.maxBlocks = htonl(shadow.maxBlocks);\r
165 \r
166                 CFG_EEPROM_Start();\r
167                 saveConfig(); // write to eeprom\r
168                 CFG_EEPROM_Stop();\r
169 \r
170                 // Send the updated data.\r
171                 usbInEpState = USB_IDLE;\r
172 \r
173                 // Allow the host to send us another updated config.\r
174                 USBFS_EnableOutEP(USB_EP_OUT);\r
175 \r
176                 ledOff();\r
177         }\r
178 \r
179         switch (usbInEpState)\r
180         {\r
181         case USB_IDLE:\r
182                 shadow.maxBlocks = htonl(shadow.maxBlocks);\r
183                 \r
184                 #ifdef MM_DEBUG\r
185                 memcpy(&shadow.reserved, &scsiDev.cdb, 12);\r
186                 shadow.reserved[12] = scsiDev.msgIn;\r
187                 shadow.reserved[13] = scsiDev.msgOut;\r
188                 shadow.reserved[14] = scsiDev.lastStatus;\r
189                 shadow.reserved[15] = scsiDev.lastSense;\r
190                 shadow.reserved[16] = scsiDev.phase;\r
191                 shadow.reserved[17] = SCSI_ReadPin(SCSI_In_BSY);\r
192                 shadow.reserved[18] = SCSI_ReadPin(SCSI_In_SEL);\r
193                 shadow.reserved[19] = SCSI_ReadPin(SCSI_ATN_INT);\r
194                 shadow.reserved[20] = SCSI_ReadPin(SCSI_RST_INT);\r
195                 shadow.reserved[21] = scsiDev.rstCount;\r
196                 shadow.reserved[22] = scsiDev.selCount;\r
197                 shadow.reserved[23] = scsiDev.msgCount;\r
198                 shadow.reserved[24] = scsiDev.cmdCount;\r
199                 shadow.reserved[25] = scsiDev.watchdogTick;\r
200                 shadow.reserved[26] = blockDev.state;\r
201                 shadow.reserved[27] = scsiReadDBxPins();\r
202                 #endif\r
203 \r
204                 USBFS_LoadInEP(USB_EP_IN, (uint8 *)&shadow, sizeof(shadow));\r
205                 shadow.maxBlocks = ntohl(shadow.maxBlocks);\r
206                 usbInEpState = USB_DATA_SENT;\r
207                 break;\r
208 \r
209         case USB_DATA_SENT:\r
210                 if (USBFS_bGetEPAckState(USB_EP_IN))\r
211                 {\r
212                         // Data accepted.\r
213                         usbInEpState = USB_IDLE;\r
214                 }\r
215                 break;\r
216         }\r
217 }\r
218 \r