mirror of
https://github.com/fhgwright/SCSI2SD.git
synced 2025-04-10 01:37:07 +00:00
Addd spi flash read/write/erase
This commit is contained in:
parent
846bde57dd
commit
c8b3288ba9
@ -222,6 +222,73 @@ deviceListCommand()
|
||||
hidPacket_send(response, pos);
|
||||
}
|
||||
|
||||
static void
|
||||
deviceEraseCommand(const uint8_t* cmd)
|
||||
{
|
||||
int deviceCount;
|
||||
S2S_Device** devices = s2s_GetDevices(&deviceCount);
|
||||
|
||||
uint32_t sectorNum =
|
||||
((uint32_t)cmd[2]) << 24 |
|
||||
((uint32_t)cmd[3]) << 16 |
|
||||
((uint32_t)cmd[4]) << 8 |
|
||||
((uint32_t)cmd[5]);
|
||||
|
||||
uint32_t count =
|
||||
((uint32_t)cmd[6]) << 24 |
|
||||
((uint32_t)cmd[7]) << 16 |
|
||||
((uint32_t)cmd[8]) << 8 |
|
||||
((uint32_t)cmd[9]);
|
||||
|
||||
devices[cmd[1]]->erase(devices[cmd[1]], sectorNum, count);
|
||||
|
||||
uint8_t response[] =
|
||||
{
|
||||
CONFIG_STATUS_GOOD
|
||||
};
|
||||
hidPacket_send(response, sizeof(response));
|
||||
}
|
||||
|
||||
static void
|
||||
deviceWriteCommand(const uint8_t* cmd)
|
||||
{
|
||||
int deviceCount;
|
||||
S2S_Device** devices = s2s_GetDevices(&deviceCount);
|
||||
|
||||
uint32_t sectorNum =
|
||||
((uint32_t)cmd[2]) << 24 |
|
||||
((uint32_t)cmd[3]) << 16 |
|
||||
((uint32_t)cmd[4]) << 8 |
|
||||
((uint32_t)cmd[5]);
|
||||
|
||||
devices[cmd[1]]->write(devices[cmd[1]], sectorNum, 1, &cmd[6]);
|
||||
|
||||
uint8_t response[] =
|
||||
{
|
||||
CONFIG_STATUS_GOOD
|
||||
};
|
||||
hidPacket_send(response, sizeof(response));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
deviceReadCommand(const uint8_t* cmd)
|
||||
{
|
||||
int deviceCount;
|
||||
S2S_Device** devices = s2s_GetDevices(&deviceCount);
|
||||
|
||||
uint32_t sectorNum =
|
||||
((uint32_t)cmd[2]) << 24 |
|
||||
((uint32_t)cmd[3]) << 16 |
|
||||
((uint32_t)cmd[4]) << 8 |
|
||||
((uint32_t)cmd[5]);
|
||||
|
||||
uint32_t response[512];
|
||||
devices[cmd[1]]->read(devices[cmd[1]], sectorNum, 1, &response[0]);
|
||||
|
||||
hidPacket_send(&response[0], 512);
|
||||
}
|
||||
|
||||
static void
|
||||
processCommand(const uint8_t* cmd, size_t cmdSize)
|
||||
{
|
||||
@ -254,6 +321,18 @@ processCommand(const uint8_t* cmd, size_t cmdSize)
|
||||
case S2S_CMD_DEV_LIST:
|
||||
deviceListCommand();
|
||||
break;
|
||||
|
||||
case S2S_CMD_DEV_ERASE:
|
||||
deviceEraseCommand(cmd);
|
||||
break;
|
||||
|
||||
case S2S_CMD_DEV_WRITE:
|
||||
deviceWriteCommand(cmd);
|
||||
break;
|
||||
|
||||
case S2S_CMD_DEV_READ:
|
||||
deviceReadCommand(cmd);
|
||||
break;
|
||||
|
||||
case CONFIG_NONE: // invalid
|
||||
default:
|
||||
|
@ -1,19 +1,19 @@
|
||||
// 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"
|
||||
@ -24,9 +24,9 @@
|
||||
|
||||
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
|
||||
|
||||
@ -43,18 +43,24 @@ static S2S_Target* spiFlash_getTargets(S2S_Device* dev, int* count);
|
||||
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);
|
||||
@ -62,32 +68,32 @@ 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)
|
||||
@ -95,7 +101,7 @@ 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();
|
||||
@ -132,20 +138,19 @@ static void spiFlash_init(S2S_Device* dev)
|
||||
// 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)
|
||||
@ -156,6 +161,146 @@ 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
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,10 @@ static S2S_Target* sd_getTargets(S2S_Device* dev, int* count);
|
||||
static uint32_t sd_getCapacity(S2S_Device* dev);
|
||||
static int sd_pollMediaChange(S2S_Device* dev);
|
||||
static void sd_pollMediaBusy(S2S_Device* dev);
|
||||
static void sd_erase(S2S_Device* dev, uint32_t sectorNumber, uint32_t count);
|
||||
static void sd_read(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer);
|
||||
static void sd_write(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer);
|
||||
|
||||
|
||||
// Global
|
||||
SdCard sdCard = {
|
||||
@ -44,6 +48,9 @@ SdCard sdCard = {
|
||||
sd_getCapacity,
|
||||
sd_pollMediaChange,
|
||||
sd_pollMediaBusy,
|
||||
sd_erase,
|
||||
sd_read,
|
||||
sd_write,
|
||||
0, // initial mediaState
|
||||
CONFIG_STOREDEVICE_SD
|
||||
}
|
||||
@ -1098,3 +1105,17 @@ static void sd_pollMediaBusy(S2S_Device* dev)
|
||||
sdCardDevice->lastPollMediaTime = getTime_ms();
|
||||
}
|
||||
|
||||
static void sd_erase(S2S_Device* dev, uint32_t sectorNumber, uint32_t count)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void sd_read(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void sd_write(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
@ -76,6 +76,10 @@ struct S2S_DeviceStruct
|
||||
int (*pollMediaChange)(S2S_Device* dev);
|
||||
void (*pollMediaBusy)(S2S_Device* dev);
|
||||
|
||||
void (*erase)(S2S_Device* dev, uint32_t sectorNumber, uint32_t count);
|
||||
void (*read)(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer);
|
||||
void (*write)(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer);
|
||||
|
||||
MEDIA_STATE mediaState;
|
||||
CONFIG_STOREDEVICE deviceType;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user