hidPacket_send(response, pos);\r
}\r
\r
+static void\r
+deviceEraseCommand(const uint8_t* cmd)\r
+{\r
+ int deviceCount;\r
+ S2S_Device** devices = s2s_GetDevices(&deviceCount);\r
+ \r
+ uint32_t sectorNum =\r
+ ((uint32_t)cmd[2]) << 24 |\r
+ ((uint32_t)cmd[3]) << 16 |\r
+ ((uint32_t)cmd[4]) << 8 |\r
+ ((uint32_t)cmd[5]);\r
+\r
+ uint32_t count =\r
+ ((uint32_t)cmd[6]) << 24 |\r
+ ((uint32_t)cmd[7]) << 16 |\r
+ ((uint32_t)cmd[8]) << 8 |\r
+ ((uint32_t)cmd[9]);\r
+\r
+ devices[cmd[1]]->erase(devices[cmd[1]], sectorNum, count);\r
+ \r
+ uint8_t response[] =\r
+ {\r
+ CONFIG_STATUS_GOOD\r
+ };\r
+ hidPacket_send(response, sizeof(response));\r
+}\r
+\r
+static void\r
+deviceWriteCommand(const uint8_t* cmd)\r
+{\r
+ int deviceCount;\r
+ S2S_Device** devices = s2s_GetDevices(&deviceCount);\r
+ \r
+ uint32_t sectorNum =\r
+ ((uint32_t)cmd[2]) << 24 |\r
+ ((uint32_t)cmd[3]) << 16 |\r
+ ((uint32_t)cmd[4]) << 8 |\r
+ ((uint32_t)cmd[5]);\r
+\r
+ devices[cmd[1]]->write(devices[cmd[1]], sectorNum, 1, &cmd[6]);\r
+ \r
+ uint8_t response[] =\r
+ {\r
+ CONFIG_STATUS_GOOD\r
+ };\r
+ hidPacket_send(response, sizeof(response));\r
+}\r
+\r
+\r
+static void\r
+deviceReadCommand(const uint8_t* cmd)\r
+{\r
+ int deviceCount;\r
+ S2S_Device** devices = s2s_GetDevices(&deviceCount);\r
+ \r
+ uint32_t sectorNum =\r
+ ((uint32_t)cmd[2]) << 24 |\r
+ ((uint32_t)cmd[3]) << 16 |\r
+ ((uint32_t)cmd[4]) << 8 |\r
+ ((uint32_t)cmd[5]);\r
+\r
+ uint32_t response[512];\r
+ devices[cmd[1]]->read(devices[cmd[1]], sectorNum, 1, &response[0]);\r
+ \r
+ hidPacket_send(&response[0], 512);\r
+}\r
+\r
static void\r
processCommand(const uint8_t* cmd, size_t cmdSize)\r
{\r
case S2S_CMD_DEV_LIST:\r
deviceListCommand();\r
break;\r
+\r
+ case S2S_CMD_DEV_ERASE:\r
+ deviceEraseCommand(cmd);\r
+ break;\r
+\r
+ case S2S_CMD_DEV_WRITE:\r
+ deviceWriteCommand(cmd);\r
+ break;\r
+\r
+ case S2S_CMD_DEV_READ:\r
+ deviceReadCommand(cmd);\r
+ break;\r
\r
case CONFIG_NONE: // invalid\r
default:\r
-// Copyright (C) 2013 Michael McMaster <michael@codesrc.com>
+// Copyright (C) 2013 Michael McMaster <michael@codesrc.com>
//
-// This file is part of SCSI2SD.
+// This file is part of SCSI2SD.
//
-// SCSI2SD is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
+// SCSI2SD is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
//
-// SCSI2SD is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
+// SCSI2SD is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
//
-// You should have received a copy of the GNU General Public License
-// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
+// You should have received a copy of the GNU General Public License
+// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
#include "device.h"
#include "flash.h"
typedef struct
{
- S2S_Device dev;
+ S2S_Device dev;
- S2S_Target targets[MAX_SCSI_TARGETS];
+ S2S_Target targets[MAX_SCSI_TARGETS];
uint32_t capacity; // in 512 byte blocks
static uint32_t spiFlash_getCapacity(S2S_Device* dev);
static int spiFlash_pollMediaChange(S2S_Device* dev);
static void spiFlash_pollMediaBusy(S2S_Device* dev);
+static void spiFlash_erase(S2S_Device* dev, uint32_t sectorNumber, uint32_t count);
+static void spiFlash_read(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer);
+static void spiFlash_write(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer);
SpiFlash spiFlash = {
- {
- spiFlash_earlyInit,
+ {
+ spiFlash_earlyInit,
spiFlash_init,
- spiFlash_getTargets,
- spiFlash_getCapacity,
- spiFlash_pollMediaChange,
- spiFlash_pollMediaBusy,
+ spiFlash_getTargets,
+ spiFlash_getCapacity,
+ spiFlash_pollMediaChange,
+ spiFlash_pollMediaBusy,
+ spiFlash_erase,
+ spiFlash_read,
+ spiFlash_write,
0, // initial mediaState
CONFIG_STOREDEVICE_FLASH
- }
+ }
};
S2S_Device* spiFlashDevice = &(spiFlash.dev);
// Read and write 1 byte.
static uint8_t spiFlashByte(uint8_t value)
{
- NOR_SPI_WriteTxData(value);
- while (!(NOR_SPI_ReadRxStatus() & NOR_SPI_STS_RX_FIFO_NOT_EMPTY)) {}
- return NOR_SPI_ReadRxData();
+ NOR_SPI_WriteTxData(value);
+ while (!(NOR_SPI_ReadRxStatus() & NOR_SPI_STS_RX_FIFO_NOT_EMPTY)) {}
+ return NOR_SPI_ReadRxData();
}
static void spiFlash_earlyInit(S2S_Device* dev)
{
- SpiFlash* spiFlash = (SpiFlash*)dev;
+ SpiFlash* spiFlash = (SpiFlash*)dev;
- for (int i = 0; i < MAX_SCSI_TARGETS; ++i)
- {
- spiFlash->targets[i].device = dev;
+ for (int i = 0; i < MAX_SCSI_TARGETS; ++i)
+ {
+ spiFlash->targets[i].device = dev;
const S2S_TargetCfg* cfg = getConfigByIndex(i);
if (cfg->storageDevice == CONFIG_STOREDEVICE_FLASH)
{
- spiFlash->targets[i].cfg = (S2S_TargetCfg*)cfg;
+ spiFlash->targets[i].cfg = (S2S_TargetCfg*)cfg;
}
else
{
spiFlash->targets[i].cfg = NULL;
}
- }
+ }
- // Don't require the host to send us a START STOP UNIT command
- spiFlash->dev.mediaState = MEDIA_STARTED;
+ // Don't require the host to send us a START STOP UNIT command
+ spiFlash->dev.mediaState = MEDIA_STARTED;
}
static void spiFlash_init(S2S_Device* dev)
SpiFlash* spiFlash = (SpiFlash*)dev;
spiFlash->capacity = 0;
- nNOR_WP_Write(0); // Enable Write Protect
+ nNOR_WP_Write(1); // We don't need write Protect
nNOR_CS_Write(1); // Deselect
NOR_SPI_Start();
// Don't bother reading the rest. Deselecting will cancel the command.
nNOR_CS_Write(1); // Deselect
-
}
static S2S_Target* spiFlash_getTargets(S2S_Device* dev, int* count)
{
- SpiFlash* spiFlash = (SpiFlash*)dev;
- *count = MAX_SCSI_TARGETS;
- return spiFlash->targets;
+ SpiFlash* spiFlash = (SpiFlash*)dev;
+ *count = MAX_SCSI_TARGETS;
+ return spiFlash->targets;
}
static uint32_t spiFlash_getCapacity(S2S_Device* dev)
{
- SpiFlash* spiFlash = (SpiFlash*)dev;
- return spiFlash->capacity;
+ SpiFlash* spiFlash = (SpiFlash*)dev;
+ return spiFlash->capacity;
}
static int spiFlash_pollMediaChange(S2S_Device* dev)
static void spiFlash_pollMediaBusy(S2S_Device* dev)
{
- // Non-removable
+ // Non-removable
+}
+
+static void spiFlash_WaitForWIP()
+{
+ int inProgress = 1;
+ while (inProgress)
+ {
+ nNOR_CS_Write(0);
+ uint8_t status = spiFlashByte(0x05); // Read Status Register 1;
+ inProgress = status & 1;
+ nNOR_CS_Write(1);
+ }
+}
+
+static void spiFlash_erase(S2S_Device* dev, uint32_t sectorNumber, uint32_t count)
+{
+ SpiFlash* spiFlash = (SpiFlash*)dev;
+
+ nNOR_CS_Write(0); // Select
+
+ // Send the WREN - Write Enable command
+ spiFlashByte(0x06);
+
+ // We NEED to deselect the device now for writes to work
+ nNOR_CS_Write(1);
+
+ // For now we assume 256kb sectors. This needs to be expanded to cater for
+ // different sector sizes. We safely assume it will always be >= 512 bytes.
+ const uint32_t flashSectorSize = 256*1024;
+
+ // We don't have enough memory to do a read-modify-write cycle, so the caller
+ // had better line these up on sector boundaries.
+ for (uint32_t linearAddress = sectorNumber * 512;
+ linearAddress < (sectorNumber + count) * 512;
+ linearAddress += flashSectorSize)
+ {
+ nNOR_CS_Write(0);
+
+ spiFlashByte(0xDC);
+
+ // 4-byte address
+ spiFlashByte(linearAddress >> 24);
+ spiFlashByte(linearAddress >> 16);
+ spiFlashByte(linearAddress >> 8);
+ spiFlashByte(linearAddress);
+
+ // Initiate erase
+ nNOR_CS_Write(1)
+
+ spiFlash_WaitForWIP();
+ }
+
+ nNOR_CS_Write(0)
+
+ // Send the WREN - Write Disable command
+ spiFlashByte(0x04);
+
+ nNOR_CS_Write(1); // Deselect
+}
+
+static void spiFlash_write(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer)
+{
+ SpiFlash* spiFlash = (SpiFlash*)dev;
+
+ nNOR_CS_Write(0); // Select
+
+ // Send the WREN - Write Enable command
+ spiFlashByte(0x06);
+
+ // We NEED to deselect the device now for writes to work
+ nNOR_CS_Write(1);
+
+ // We're assuming here that the page size is 512 bytes or more.
+ for (int i = 0; i < count; ++i)
+ {
+ nNOR_CS_Write(0);
+
+ spiFlashByte(0x12);
+
+ uint32_t linearAddress = (sectorNumber + i) * 512;
+ spiFlashByte(linearAddress >> 24);
+ spiFlashByte(linearAddress >> 16);
+ spiFlashByte(linearAddress >> 8);
+ spiFlashByte(linearAddress);
+
+ for (int off = 0; off < 512; ++off)
+ {
+ spiFlashByte(buffer[i * 512 + off]);
+ }
+
+ // Initiate write
+ nNOR_CS_Write(1)
+
+ spiFlash_WaitForWIP();
+ }
+
+ nNOR_CS_Write(0)
+
+ // Send the WREN - Write Disable command
+ spiFlashByte(0x04);
+
+ nNOR_CS_Write(1); // Deselect
+}
+
+static void spiFlash_read(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer)
+{
+ SpiFlash* spiFlash = (SpiFlash*)dev;
+
+ nNOR_CS_Write(0); // Select
+ spiFlashByte(0x13);
+
+ uint32_t linearAddress = sectorNumber * 512;
+ spiFlashByte(linearAddress >> 24);
+ spiFlashByte(linearAddress >> 16);
+ spiFlashByte(linearAddress >> 8);
+ spiFlashByte(linearAddress);
+
+ // There's no harm in reading -extra- data, so keep the FIFO
+ // one step ahead.
+ NOR_SPI_WriteTxData(0xFF);
+ NOR_SPI_WriteTxData(0xFF);
+ NOR_SPI_WriteTxData(0xFF);
+
+ for (int off = 0; off < count * 512; ++off)
+ {
+ NOR_SPI_WriteTxData(0xFF);
+
+ while (!(NOR_SPI_ReadRxStatus() & NOR_SPI_STS_RX_FIFO_NOT_EMPTY)) {}
+ buffer[off] = NOR_SPI_ReadRxData();
+ }
+
+ // Read and discard the extra bytes of data. It was only used to improve
+ // performance with a full FIFO.
+ for (int i = 0; i < 3; ++i)
+ {
+ while (!(NOR_SPI_ReadRxStatus() & NOR_SPI_STS_RX_FIFO_NOT_EMPTY)) {}
+ NOR_SPI_ReadRxData();
+ }
+
+ nNOR_CS_Write(1); // Deselect
}