1 // Copyright (C) 2014 Michael McMaster <michael@codesrc.com>
\r
3 // This file is part of SCSI2SD.
\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
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
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
24 #include "scsiPhy.h"
\r
29 // CYDEV_EEPROM_ROW_SIZE == 16.
\r
30 static char magic[CYDEV_EEPROM_ROW_SIZE] = "codesrc_00000002";
\r
32 // Config shadow RAM (copy of EEPROM)
\r
33 static Config shadow =
\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
40 1, // enable unit attention,
\r
42 0, // Max sectors (0 == disabled)
\r
44 // reserved bytes will be initialised to 0.
\r
62 Config* config = NULL;
\r
64 // The PSoC 5LP compile to little-endian format.
\r
65 static uint32_t ntohl(uint32_t val)
\r
68 ((val & 0xFF) << 24) |
\r
69 ((val & 0xFF00) << 8) |
\r
70 ((val >> 8) & 0xFF00) |
\r
71 ((val >> 24) & 0xFF);
\r
73 static uint16_t ntohs(uint16_t val)
\r
76 ((val & 0xFF) << 8) |
\r
77 ((val >> 8) & 0xFF);
\r
79 static uint32_t htonl(uint32_t val)
\r
82 ((val & 0xFF) << 24) |
\r
83 ((val & 0xFF00) << 8) |
\r
84 ((val >> 8) & 0xFF00) |
\r
85 ((val >> 24) & 0xFF);
\r
87 static uint16_t htons(uint16_t val)
\r
90 ((val & 0xFF) << 8) |
\r
91 ((val >> 8) & 0xFF);
\r
94 static void saveConfig()
\r
96 int shadowRows = (sizeof(shadow) / CYDEV_EEPROM_ROW_SIZE) + 1;
\r
98 int status = CYRET_SUCCESS;
\r
101 for (row = 0; (row < shadowRows) && (status == CYRET_SUCCESS); ++row)
\r
103 CFG_EEPROM_Write(((uint8*)&shadow) + (row * CYDEV_EEPROM_ROW_SIZE), row);
\r
105 if (status == CYRET_SUCCESS)
\r
107 CFG_EEPROM_Write((uint8*)magic, row);
\r
113 int shadowRows, shadowBytes;
\r
114 uint8* eeprom = (uint8*)CYDEV_EE_BASE;
\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
119 CFG_EEPROM_Start();
\r
120 CyDelayUs(5); // 5us to start per datasheet.
\r
123 shadowRows = (sizeof(shadow) / CYDEV_EEPROM_ROW_SIZE) + 1;
\r
124 shadowBytes = CYDEV_EEPROM_ROW_SIZE * shadowRows;
\r
126 if (memcmp(eeprom + shadowBytes, magic, sizeof(magic)))
\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
132 // Upgrade from version 1.
\r
133 memcpy(&shadow, eeprom, sizeof(shadow));
\r
134 shadow.bytesPerSector = 512;
\r
141 memcpy(&shadow, eeprom, sizeof(shadow));
\r
146 // The USB block will be powered by an internal 3.3V regulator.
\r
147 // The PSoC must be operating between 4.6V and 5V for the regulator
\r
149 USBFS_Start(0, USBFS_5V_OPERATION);
\r
150 usbInEpState = USB_IDLE;
\r
151 usbReady = 0; // We don't know if host is connected yet.
\r
157 if (!usbReady || USBFS_IsConfigurationChanged())
\r
161 usbReady = USBFS_bGetConfiguration();
\r
170 USBFS_EnableOutEP(USB_EP_OUT);
\r
171 usbInEpState = USB_IDLE;
\r
174 if(USBFS_GetEPState(USB_EP_OUT) == USBFS_OUT_BUFFER_FULL)
\r
180 // The host sent us some data!
\r
181 byteCount = USBFS_GetEPCount(USB_EP_OUT);
\r
183 // Assume that byteCount <= sizeof(shadow).
\r
184 // shadow should be padded out to 64bytes, which is the largest
\r
185 // possible HID transfer.
\r
186 USBFS_ReadOutEP(USB_EP_OUT, (uint8 *)&shadow, byteCount);
\r
187 shadow.maxSectors = ntohl(shadow.maxSectors);
\r
188 shadow.bytesPerSector = ntohs(shadow.bytesPerSector);
\r
190 if (shadow.bytesPerSector > MAX_SECTOR_SIZE)
\r
192 shadow.bytesPerSector = MAX_SECTOR_SIZE;
\r
194 else if (shadow.bytesPerSector < MIN_SECTOR_SIZE)
\r
196 shadow.bytesPerSector = MIN_SECTOR_SIZE;
\r
199 CFG_EEPROM_Start();
\r
200 saveConfig(); // write to eeprom
\r
203 // Send the updated data.
\r
204 usbInEpState = USB_IDLE;
\r
206 // Allow the host to send us another updated config.
\r
207 USBFS_EnableOutEP(USB_EP_OUT);
\r
209 // Set unt attention as the block size may have changed.
\r
210 scsiDev.unitAttention = MODE_PARAMETERS_CHANGED;
\r
215 switch (usbInEpState)
\r
218 shadow.maxSectors = htonl(shadow.maxSectors);
\r
219 shadow.bytesPerSector = htons(shadow.bytesPerSector);
\r
222 memcpy(&shadow.reserved, &scsiDev.cdb, 12);
\r
223 shadow.reserved[12] = scsiDev.msgIn;
\r
224 shadow.reserved[13] = scsiDev.msgOut;
\r
225 shadow.reserved[14] = scsiDev.lastStatus;
\r
226 shadow.reserved[15] = scsiDev.lastSense;
\r
227 shadow.reserved[16] = scsiDev.phase;
\r
228 shadow.reserved[17] = SCSI_ReadPin(SCSI_In_BSY);
\r
229 shadow.reserved[18] = SCSI_ReadPin(SCSI_In_SEL);
\r
230 shadow.reserved[19] = SCSI_ReadPin(SCSI_ATN_INT);
\r
231 shadow.reserved[20] = SCSI_ReadPin(SCSI_RST_INT);
\r
232 shadow.reserved[21] = scsiDev.rstCount;
\r
233 shadow.reserved[22] = scsiDev.selCount;
\r
234 shadow.reserved[23] = scsiDev.msgCount;
\r
235 shadow.reserved[24] = scsiDev.cmdCount;
\r
236 shadow.reserved[25] = scsiDev.watchdogTick;
\r
239 USBFS_LoadInEP(USB_EP_IN, (uint8 *)&shadow, sizeof(shadow));
\r
240 shadow.maxSectors = ntohl(shadow.maxSectors);
\r
241 shadow.bytesPerSector = ntohs(shadow.bytesPerSector);
\r
242 usbInEpState = USB_DATA_SENT;
\r
245 case USB_DATA_SENT:
\r
246 if (USBFS_bGetEPAckState(USB_EP_IN))
\r
249 usbInEpState = USB_IDLE;
\r
255 // Public method for storing MODE SELECT results.
\r
258 CFG_EEPROM_Start();
\r
259 saveConfig(); // write to eeprom
\r