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_00000001";
\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
41 0 // Max blocks (0 == disabled)
\r
42 // reserved bytes will be initialised to 0.
\r
60 Config* config = NULL;
\r
62 // The PSoC 5LP compile to little-endian format.
\r
63 static uint32_t ntohl(uint32_t val)
\r
66 ((val & 0xFF) << 24) |
\r
67 ((val & 0xFF00) << 8) |
\r
68 ((val >> 8) & 0xFF00) |
\r
69 ((val >> 24) & 0xFF);
\r
71 static uint32_t htonl(uint32_t val)
\r
74 ((val & 0xFF) << 24) |
\r
75 ((val & 0xFF00) << 8) |
\r
76 ((val >> 8) & 0xFF00) |
\r
77 ((val >> 24) & 0xFF);
\r
80 static void saveConfig()
\r
82 int shadowRows = (sizeof(shadow) / CYDEV_EEPROM_ROW_SIZE) + 1;
\r
84 int status = CYRET_SUCCESS;
\r
87 for (row = 0; (row < shadowRows) && (status == CYRET_SUCCESS); ++row)
\r
89 CFG_EEPROM_Write(((uint8*)&shadow) + (row * CYDEV_EEPROM_ROW_SIZE), row);
\r
91 if (status == CYRET_SUCCESS)
\r
93 CFG_EEPROM_Write((uint8*)magic, row);
\r
99 int shadowRows, shadowBytes;
\r
100 uint8* eeprom = (uint8*)CYDEV_EE_BASE;
\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
105 CFG_EEPROM_Start();
\r
106 CyDelayUs(5); // 5us to start per datasheet.
\r
109 shadowRows = (sizeof(shadow) / CYDEV_EEPROM_ROW_SIZE) + 1;
\r
110 shadowBytes = CYDEV_EEPROM_ROW_SIZE * shadowRows;
\r
112 if (memcmp(eeprom + shadowBytes, magic, sizeof(magic)))
\r
118 memcpy(&shadow, eeprom, sizeof(shadow));
\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
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
134 if (!usbReady || USBFS_IsConfigurationChanged())
\r
138 usbReady = USBFS_bGetConfiguration();
\r
147 USBFS_EnableOutEP(USB_EP_OUT);
\r
148 usbInEpState = USB_IDLE;
\r
151 if(USBFS_GetEPState(USB_EP_OUT) == USBFS_OUT_BUFFER_FULL)
\r
157 // The host sent us some data!
\r
158 byteCount = USBFS_GetEPCount(USB_EP_OUT);
\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
166 CFG_EEPROM_Start();
\r
167 saveConfig(); // write to eeprom
\r
170 // Send the updated data.
\r
171 usbInEpState = USB_IDLE;
\r
173 // Allow the host to send us another updated config.
\r
174 USBFS_EnableOutEP(USB_EP_OUT);
\r
179 switch (usbInEpState)
\r
182 shadow.maxBlocks = htonl(shadow.maxBlocks);
\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
204 USBFS_LoadInEP(USB_EP_IN, (uint8 *)&shadow, sizeof(shadow));
\r
205 shadow.maxBlocks = ntohl(shadow.maxBlocks);
\r
206 usbInEpState = USB_DATA_SENT;
\r
209 case USB_DATA_SENT:
\r
210 if (USBFS_bGetEPAckState(USB_EP_IN))
\r
213 usbInEpState = USB_IDLE;
\r