Add all phase bits to a control register for atomic phase changes.
[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 <string.h>\r
28 \r
29 // CYDEV_EEPROM_ROW_SIZE == 16.\r
30 static const char magic[CYDEV_EEPROM_ROW_SIZE] = "codesrc_00000002";\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.4", // revision (68k Apple Drive Setup: Set to "1.0 ")\r
39         1, // enable parity\r
40         1, // enable unit attention,\r
41         0, // RESERVED\r
42         0, // Max sectors (0 == disabled)\r
43         512 // Sector size\r
44         // reserved bytes will be initialised to 0.\r
45 };\r
46 \r
47 enum USB_ENDPOINTS\r
48 {\r
49         USB_EP_OUT = 1,\r
50         USB_EP_IN = 2\r
51 };\r
52 enum USB_STATE\r
53 {\r
54         USB_IDLE,\r
55         USB_DATA_SENT\r
56 };\r
57 int usbInEpState;\r
58 \r
59 int usbReady;\r
60 \r
61 // Global\r
62 Config* config = NULL;\r
63 \r
64 // The PSoC 5LP compile to little-endian format.\r
65 static uint32_t ntohl(uint32_t val)\r
66 {\r
67         return\r
68                 ((val & 0xFF) << 24) |\r
69                 ((val & 0xFF00) << 8) |\r
70                 ((val >> 8) & 0xFF00) |\r
71                 ((val >> 24) & 0xFF);\r
72 }\r
73 static uint16_t ntohs(uint16_t val)\r
74 {\r
75         return\r
76                 ((val & 0xFF) << 8) |\r
77                 ((val >> 8) & 0xFF);\r
78 }\r
79 static uint32_t htonl(uint32_t val)\r
80 {\r
81         return\r
82                 ((val & 0xFF) << 24) |\r
83                 ((val & 0xFF00) << 8) |\r
84                 ((val >> 8) & 0xFF00) |\r
85                 ((val >> 24) & 0xFF);\r
86 }\r
87 static uint16_t htons(uint16_t val)\r
88 {\r
89         return\r
90                 ((val & 0xFF) << 8) |\r
91                 ((val >> 8) & 0xFF);\r
92 }\r
93 \r
94 static void saveConfig()\r
95 {\r
96         int shadowRows = (sizeof(shadow) / CYDEV_EEPROM_ROW_SIZE) + 1;\r
97         int row;\r
98         int status = CYRET_SUCCESS;\r
99 \r
100         CySetTemp();\r
101         for (row = 0; (row < shadowRows) && (status == CYRET_SUCCESS); ++row)\r
102         {\r
103                 CFG_EEPROM_Write(((uint8*)&shadow) + (row * CYDEV_EEPROM_ROW_SIZE), row);\r
104         }\r
105         if (status == CYRET_SUCCESS)\r
106         {\r
107                 CFG_EEPROM_Write((uint8*)magic, row);\r
108         }\r
109 }\r
110 \r
111 void configInit()\r
112 {\r
113         int shadowRows, shadowBytes;\r
114         uint8* eeprom = (uint8*)CYDEV_EE_BASE;\r
115 \r
116         // We could map cfgPtr directly into the EEPROM memory,\r
117         // but that would waste power. Copy it to RAM then turn off\r
118         // the EEPROM.\r
119         CFG_EEPROM_Start();\r
120         CyDelayUs(5); // 5us to start per datasheet.\r
121 \r
122         // Check magic\r
123         shadowRows = (sizeof(shadow) / CYDEV_EEPROM_ROW_SIZE) + 1;\r
124         shadowBytes = CYDEV_EEPROM_ROW_SIZE * shadowRows;\r
125 \r
126         if (memcmp(eeprom + shadowBytes, magic, sizeof(magic)))\r
127         {\r
128                 // Initial state, invalid, or upgrade required.\r
129                 if (!memcmp(eeprom + shadowBytes, magic, sizeof(magic) - 1) &&\r
130                         ((eeprom + shadowBytes)[sizeof(magic) - 2] == '1'))\r
131                 {\r
132                         // Upgrade from version 1.\r
133                         memcpy(&shadow, eeprom, sizeof(shadow));\r
134                         shadow.bytesPerSector = 512;\r
135                 }\r
136 \r
137                 saveConfig();\r
138         }\r
139         else\r
140         {\r
141                 memcpy(&shadow, eeprom, sizeof(shadow));\r
142         }\r
143 \r
144         config = &shadow;\r
145         CFG_EEPROM_Stop();\r
146 \r
147         // The USB block will be powered by an internal 3.3V regulator.\r
148         // The PSoC must be operating between 4.6V and 5V for the regulator\r
149         // to work.\r
150         USBFS_Start(0, USBFS_5V_OPERATION);\r
151         usbInEpState = USB_IDLE;\r
152         usbReady = 0; // We don't know if host is connected yet.\r
153 }\r
154 \r
155 void configPoll()\r
156 {\r
157         int reset = 0;\r
158         if (!usbReady || USBFS_IsConfigurationChanged())\r
159         {\r
160                 reset = 1;\r
161         }\r
162         usbReady = USBFS_bGetConfiguration();\r
163 \r
164         if (!usbReady)\r
165         {\r
166                 return;\r
167         }\r
168 \r
169         if (reset)\r
170         {\r
171                 USBFS_EnableOutEP(USB_EP_OUT);\r
172                 usbInEpState = USB_IDLE;\r
173         }\r
174 \r
175         if(USBFS_GetEPState(USB_EP_OUT) == USBFS_OUT_BUFFER_FULL)\r
176         {\r
177                 int byteCount;\r
178 \r
179                 ledOn();\r
180 \r
181                 // The host sent us some data!\r
182                 byteCount = USBFS_GetEPCount(USB_EP_OUT);\r
183 \r
184                 // Assume that byteCount <= sizeof(shadow).\r
185                 // shadow should be padded out to 64bytes, which is the largest\r
186                 // possible HID transfer.\r
187                 USBFS_ReadOutEP(USB_EP_OUT, (uint8 *)&shadow, byteCount);\r
188                 shadow.maxSectors = ntohl(shadow.maxSectors);\r
189                 shadow.bytesPerSector = ntohs(shadow.bytesPerSector);\r
190 \r
191                 if (shadow.bytesPerSector > MAX_SECTOR_SIZE)\r
192                 {\r
193                         shadow.bytesPerSector = MAX_SECTOR_SIZE;\r
194                 }\r
195                 else if (shadow.bytesPerSector < MIN_SECTOR_SIZE)\r
196                 {\r
197                         shadow.bytesPerSector = MIN_SECTOR_SIZE;\r
198                 }\r
199 \r
200                 CFG_EEPROM_Start();\r
201                 saveConfig(); // write to eeprom\r
202                 CFG_EEPROM_Stop();\r
203 \r
204                 // Send the updated data.\r
205                 usbInEpState = USB_IDLE;\r
206 \r
207                 // Allow the host to send us another updated config.\r
208                 USBFS_EnableOutEP(USB_EP_OUT);\r
209 \r
210                 // Set unt attention as the block size may have changed.\r
211                 scsiDev.unitAttention = MODE_PARAMETERS_CHANGED;\r
212 \r
213                 ledOff();\r
214         }\r
215 \r
216         switch (usbInEpState)\r
217         {\r
218         case USB_IDLE:\r
219                 shadow.maxSectors = htonl(shadow.maxSectors);\r
220                 shadow.bytesPerSector = htons(shadow.bytesPerSector);\r
221 \r
222                 #ifdef MM_DEBUG\r
223                 memcpy(&shadow.reserved, &scsiDev.cdb, 12);\r
224                 shadow.reserved[12] = scsiDev.msgIn;\r
225                 shadow.reserved[13] = scsiDev.msgOut;\r
226                 shadow.reserved[14] = scsiDev.lastStatus;\r
227                 shadow.reserved[15] = scsiDev.lastSense;\r
228                 shadow.reserved[16] = scsiDev.phase;\r
229                 shadow.reserved[17] = SCSI_ReadPin(SCSI_In_BSY);\r
230                 shadow.reserved[18] = SCSI_ReadPin(SCSI_In_SEL);\r
231                 shadow.reserved[19] = SCSI_ReadPin(SCSI_ATN_INT);\r
232                 shadow.reserved[20] = SCSI_ReadPin(SCSI_RST_INT);\r
233                 shadow.reserved[21] = scsiDev.rstCount;\r
234                 shadow.reserved[22] = scsiDev.selCount;\r
235                 shadow.reserved[23] = scsiDev.msgCount;\r
236                 shadow.reserved[24] = scsiDev.cmdCount;\r
237                 shadow.reserved[25] = scsiDev.watchdogTick;\r
238                 #endif\r
239 \r
240                 USBFS_LoadInEP(USB_EP_IN, (uint8 *)&shadow, sizeof(shadow));\r
241                 shadow.maxSectors = ntohl(shadow.maxSectors);\r
242                 shadow.bytesPerSector = ntohs(shadow.bytesPerSector);\r
243                 usbInEpState = USB_DATA_SENT;\r
244                 break;\r
245 \r
246         case USB_DATA_SENT:\r
247                 if (USBFS_bGetEPAckState(USB_EP_IN))\r
248                 {\r
249                         // Data accepted.\r
250                         usbInEpState = USB_IDLE;\r
251                 }\r
252                 break;\r
253         }\r
254 }\r
255 \r
256 // Public method for storing MODE SELECT results.\r
257 void configSave()\r
258 {\r
259         CFG_EEPROM_Start();\r
260         saveConfig(); // write to eeprom\r
261         CFG_EEPROM_Stop();\r
262 }\r
263 \r