mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-03 11:32:43 +01:00
Restructure code; start implementing read/write commands
This commit is contained in:
parent
d98be4bdc9
commit
4f6cd4f535
@ -8,13 +8,36 @@
|
||||
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Hash.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/IOFile.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
namespace ExpansionInterface
|
||||
{
|
||||
CEXISD::CEXISD(Core::System& system) : IEXIDevice(system)
|
||||
{
|
||||
const std::string filename = File::GetUserPath(D_GCUSER_IDX) + "sdcard.bin";
|
||||
m_card.Open(filename, "r+b");
|
||||
if (!m_card)
|
||||
{
|
||||
WARN_LOG_FMT(EXPANSIONINTERFACE,
|
||||
"Failed to open SD Card image, trying to create a new 128 MB image...");
|
||||
m_card.Open(filename, "wb");
|
||||
// NOTE: Not using Common::SDCardCreate here yet, to test games formatting the card
|
||||
// themselves.
|
||||
if (m_card)
|
||||
{
|
||||
m_card.Resize(0x8000000);
|
||||
INFO_LOG_FMT(EXPANSIONINTERFACE, "Successfully created {}", filename);
|
||||
m_card.Open(filename, "r+b");
|
||||
}
|
||||
if (!m_card)
|
||||
{
|
||||
ERROR_LOG_FMT(EXPANSIONINTERFACE,
|
||||
"Could not open SD Card image or create a new one, are you running "
|
||||
"from a read-only directory?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEXISD::ImmWrite(u32 data, u32 size)
|
||||
@ -81,30 +104,33 @@ void CEXISD::DoState(PointerWrap& p)
|
||||
{
|
||||
p.Do(inited);
|
||||
p.Do(get_id);
|
||||
p.Do(m_uPosition);
|
||||
p.DoArray(cmd);
|
||||
p.Do(next_is_appcmd);
|
||||
p.Do(command_position);
|
||||
p.Do(block_position);
|
||||
p.DoArray(command_buffer);
|
||||
p.Do(response);
|
||||
p.DoArray(block_buffer);
|
||||
}
|
||||
|
||||
void CEXISD::WriteByte(u8 byte)
|
||||
{
|
||||
// TODO: Write-protect inversion(?)
|
||||
if (m_uPosition == 0)
|
||||
if (command_position == 0)
|
||||
{
|
||||
if ((byte & 0b11000000) == 0b01000000)
|
||||
{
|
||||
INFO_LOG_FMT(EXPANSIONINTERFACE, "EXI SD command started: {:02x}", byte);
|
||||
cmd[m_uPosition++] = byte;
|
||||
command_buffer[command_position++] = byte;
|
||||
}
|
||||
}
|
||||
else if (m_uPosition < 6)
|
||||
else if (command_position < 6)
|
||||
{
|
||||
cmd[m_uPosition++] = byte;
|
||||
command_buffer[command_position++] = byte;
|
||||
|
||||
if (m_uPosition == 6)
|
||||
if (command_position == 6)
|
||||
{
|
||||
// Buffer now full
|
||||
m_uPosition = 0;
|
||||
command_position = 0;
|
||||
|
||||
if ((byte & 1) != 1)
|
||||
{
|
||||
@ -114,201 +140,235 @@ void CEXISD::WriteByte(u8 byte)
|
||||
|
||||
// TODO: Check CRC
|
||||
|
||||
INFO_LOG_FMT(EXPANSIONINTERFACE, "EXI SD command received: {:02x}", fmt::join(cmd.begin(), cmd.end(), " "));
|
||||
u8 command = command_buffer[0] & 0x3f;
|
||||
u32 argument = command_buffer[1] << 24 | command_buffer[2] << 16 | command_buffer[3] << 8 |
|
||||
command_buffer[4];
|
||||
|
||||
if (cmd[0] == 0x40) // GO_IDLE_STATE
|
||||
{
|
||||
response.push_back(static_cast<u8>(R1::InIdleState));
|
||||
}
|
||||
else if (cmd[0] == 0x41) // SEND_OP_COND
|
||||
{
|
||||
// Used by libogc for non-SDHC cards
|
||||
bool hcs = cmd[1] & 0x40; // Host Capacity Support (for SDHC/SDXC cards)
|
||||
(void)hcs;
|
||||
response.push_back(0); // R1 - not idle
|
||||
}
|
||||
else if (cmd[0] == 0x48) // SEND_IF_COND
|
||||
{
|
||||
// Format R7
|
||||
u8 supply_voltage = cmd[4] & 0xF;
|
||||
u8 check_pattern = cmd[5];
|
||||
response.push_back(static_cast<u8>(R1::InIdleState)); // R1
|
||||
response.push_back(0); // Command version nybble (0), reserved
|
||||
response.push_back(0); // Reserved
|
||||
response.push_back(supply_voltage); // Reserved + voltage
|
||||
response.push_back(check_pattern);
|
||||
}
|
||||
else if (cmd[0] == 0x49) // SEND_CSD
|
||||
{
|
||||
u64 size = 0x8000000; // TODO
|
||||
INFO_LOG_FMT(EXPANSIONINTERFACE, "EXI SD command received: {:02x} {:08x}", command, argument);
|
||||
|
||||
// 2048 bytes/sector
|
||||
// We could make this dynamic to support a wider range of file sizes
|
||||
constexpr u32 read_bl_len = 11;
|
||||
|
||||
// size = (c_size + 1) * (1 << (2 + c_size_mult + read_bl_len))
|
||||
u32 c_size_mult = 0;
|
||||
bool invalid_size = false;
|
||||
while (size > 4096)
|
||||
{
|
||||
invalid_size |= size & 1;
|
||||
size >>= 1;
|
||||
if (++c_size_mult >= 8 + 2 + read_bl_len)
|
||||
{
|
||||
ERROR_LOG_FMT(IOS_SD, "SD Card is too big!");
|
||||
// Set max values
|
||||
size = 4096;
|
||||
c_size_mult = 7 + 2 + read_bl_len;
|
||||
}
|
||||
}
|
||||
c_size_mult -= 2 + read_bl_len;
|
||||
--size;
|
||||
const u32 c_size(size);
|
||||
|
||||
if (invalid_size)
|
||||
WARN_LOG_FMT(IOS_SD, "SD Card size is invalid");
|
||||
else
|
||||
INFO_LOG_FMT(IOS_SD, "SD C_SIZE = {}, C_SIZE_MULT = {}", c_size, c_size_mult);
|
||||
|
||||
// R1
|
||||
response.push_back(0);
|
||||
// Data ready token
|
||||
response.push_back(0xfe);
|
||||
// CSD
|
||||
// 0b00 CSD_STRUCTURE (SDv1)
|
||||
// 0b000000 reserved
|
||||
// 0b01111111 TAAC (8.0 * 10ms)
|
||||
// 0b00000000 NSAC
|
||||
// 0b00110010 TRAN_SPEED (2.5 * 10 Mbit/s, max operating frequency)
|
||||
|
||||
// 0b010110110101 CCC
|
||||
// 0b1111 READ_BL_LEN (2048 bytes)
|
||||
// 0b1 READ_BL_PARTIAL
|
||||
// 0b0 WRITE_BL_MISALIGN
|
||||
// 0b0 READ_BLK_MISALIGN
|
||||
// 0b0 DSR_IMP (no driver stage register implemented)
|
||||
// 0b00 reserved
|
||||
// 0b?????????? C_SIZE (most significant 10 bits)
|
||||
|
||||
// 0b?? C_SIZE (least significant 2 bits)
|
||||
// 0b111 VDD_R_CURR_MIN (100 mA)
|
||||
// 0b111 VDD_R_CURR_MAX (100 mA)
|
||||
// 0b111 VDD_W_CURR_MIN (100 mA)
|
||||
// 0b111 VDD_W_CURR_MAX (100 mA)
|
||||
// 0b??? C_SIZE_MULT
|
||||
// 0b1 ERASE_BLK_EN (erase unit = 512 bytes)
|
||||
// 0b1111111 SECTOR_SIZE (128 write blocks)
|
||||
// 0b0000000 WP_GRP_SIZE
|
||||
|
||||
// 0b0 WP_GRP_ENABLE (no write protection)
|
||||
// 0b00 reserved
|
||||
// 0b001 R2W_FACTOR (write half as fast as read)
|
||||
// 0b1111 WRITE_BL_LEN (= READ_BL_LEN)
|
||||
// 0b0 WRITE_BL_PARTIAL (no partial block writes)
|
||||
// 0b00000 reserved
|
||||
// 0b0 FILE_FORMAT_GRP (default)
|
||||
// 0b1 COPY (contents are copied)
|
||||
// 0b0 PERM_WRITE_PROTECT (not permanently write protected)
|
||||
// 0b0 TMP_READ_PROTECT (not temporarily write protected)
|
||||
// 0b00 FILE_FORMAT (contains partition table)
|
||||
// 0b00 reserved
|
||||
// 0b??????? CRC
|
||||
// 0b1 reserved
|
||||
|
||||
// TODO: CRC7 (but so far it looks like nobody is actually verifying this)
|
||||
constexpr u32 crc = 0;
|
||||
|
||||
// Form the csd using the description above
|
||||
response.push_back(0x00);
|
||||
response.push_back(0x07);
|
||||
response.push_back(0xf0);
|
||||
response.push_back(0x03);
|
||||
response.push_back(0x5b);
|
||||
response.push_back(0x5f);
|
||||
response.push_back(0x80 | (c_size >> 10));
|
||||
response.push_back(c_size >> 2);
|
||||
response.push_back(0x3f | c_size << 6);
|
||||
response.push_back(0xfc | (c_size_mult >> 1));
|
||||
response.push_back(0x7f | (c_size << 7));
|
||||
response.push_back(0x80);
|
||||
response.push_back(0x07);
|
||||
response.push_back(0xc0);
|
||||
response.push_back(0x40);
|
||||
response.push_back(0x01 | (crc << 1));
|
||||
// Hardcoded CRC16 (0x6a74)
|
||||
response.push_back(0x6a);
|
||||
response.push_back(0x74);
|
||||
}
|
||||
else if (cmd[0] == 0x4A) // SEND_CID
|
||||
if (next_is_appcmd)
|
||||
{
|
||||
// R1
|
||||
response.push_back(0);
|
||||
// Data ready token
|
||||
response.push_back(0xfe);
|
||||
// The CID -- no idea what the format is, copied from SDIOSlot0
|
||||
response.push_back(0x80);
|
||||
response.push_back(0x11);
|
||||
response.push_back(0x4d);
|
||||
response.push_back(0x1c);
|
||||
response.push_back(0x80);
|
||||
response.push_back(0x08);
|
||||
response.push_back(0x00);
|
||||
response.push_back(0x00);
|
||||
response.push_back(0x80);
|
||||
response.push_back(0x07);
|
||||
response.push_back(0xb5);
|
||||
response.push_back(0x20);
|
||||
response.push_back(0x80);
|
||||
response.push_back(0x08);
|
||||
response.push_back(0x00);
|
||||
response.push_back(0x00);
|
||||
// Hardcoded CRC16 (0x9e3e)
|
||||
response.push_back(0x9e);
|
||||
response.push_back(0x3e);
|
||||
}
|
||||
else if (cmd[0] == 0x4c) // STOP_TRANSMISSION
|
||||
{
|
||||
response.push_back(0); // R1
|
||||
// There can be further padding bytes, but it's not needed
|
||||
}
|
||||
else if (cmd[0] == 0x50) // SET_BLOCKLEN
|
||||
{
|
||||
response.push_back(0); // R1
|
||||
}
|
||||
else if (cmd[0] == 0x77) // APP_CMD
|
||||
{
|
||||
// The next command is an appcmd, which requires special treatment (not done here)
|
||||
response.push_back(0); // R1
|
||||
}
|
||||
else if (cmd[0] == 0x4d) // APP_CMD SD_STATUS
|
||||
{
|
||||
response.push_back(0); // R1
|
||||
response.push_back(0); // R2
|
||||
response.push_back(0xfe); // Data ready token
|
||||
for (size_t i = 0; i < 64; i++)
|
||||
{
|
||||
response.push_back(0);
|
||||
}
|
||||
// This CRC16 is 0, probably since the data is all 0
|
||||
response.push_back(0);
|
||||
response.push_back(0);
|
||||
}
|
||||
else if (cmd[0] == 0x69) // APP_CMD SD_SEND_OP_COND
|
||||
{
|
||||
// Used by Pokémon Channel for all cards, and libogc for SDHC cards
|
||||
bool hcs = cmd[1] & 0x40; // Host Capacity Support (for SDHC/SDXC cards)
|
||||
(void)hcs;
|
||||
response.push_back(0); // R1 - not idle
|
||||
next_is_appcmd = false;
|
||||
HandleAppCommand(static_cast<AppCommand>(command), argument);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't know it
|
||||
response.push_back(static_cast<u8>(R1::IllegalCommand));
|
||||
HandleCommand(static_cast<Command>(command), argument);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEXISD::HandleCommand(Command command, u32 argument)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case Command::GoIdleState:
|
||||
response.push_back(static_cast<u8>(R1::InIdleState));
|
||||
break;
|
||||
case Command::SendOpCond:
|
||||
{
|
||||
// Used by libogc for non-SDHC cards
|
||||
bool hcs = argument & (1 << 30); // Host Capacity Support (for SDHC/SDXC cards)
|
||||
(void)hcs;
|
||||
response.push_back(0); // R1 - not idle
|
||||
break;
|
||||
}
|
||||
case Command::SendInterfaceCond:
|
||||
{
|
||||
u8 supply_voltage = (argument >> 8) & 0xf;
|
||||
u8 check_pattern = argument & 0xff;
|
||||
// Format R7
|
||||
response.push_back(static_cast<u8>(R1::InIdleState)); // R1
|
||||
response.push_back(0); // Command version nybble (0), reserved
|
||||
response.push_back(0); // Reserved
|
||||
response.push_back(supply_voltage); // Reserved + voltage
|
||||
response.push_back(check_pattern);
|
||||
break;
|
||||
}
|
||||
case Command::SendCSD:
|
||||
{
|
||||
u64 size = m_card.GetSize();
|
||||
|
||||
// 2048 bytes/sector
|
||||
// We could make this dynamic to support a wider range of file sizes
|
||||
constexpr u32 read_bl_len = 11;
|
||||
|
||||
// size = (c_size + 1) * (1 << (2 + c_size_mult + read_bl_len))
|
||||
u32 c_size_mult = 0;
|
||||
bool invalid_size = false;
|
||||
while (size > 4096)
|
||||
{
|
||||
invalid_size |= size & 1;
|
||||
size >>= 1;
|
||||
if (++c_size_mult >= 8 + 2 + read_bl_len)
|
||||
{
|
||||
ERROR_LOG_FMT(IOS_SD, "SD Card is too big!");
|
||||
// Set max values
|
||||
size = 4096;
|
||||
c_size_mult = 7 + 2 + read_bl_len;
|
||||
}
|
||||
}
|
||||
c_size_mult -= 2 + read_bl_len;
|
||||
--size;
|
||||
const u32 c_size(size);
|
||||
|
||||
if (invalid_size)
|
||||
WARN_LOG_FMT(IOS_SD, "SD Card size is invalid");
|
||||
else
|
||||
INFO_LOG_FMT(IOS_SD, "SD C_SIZE = {}, C_SIZE_MULT = {}", c_size, c_size_mult);
|
||||
|
||||
// R1
|
||||
response.push_back(0);
|
||||
// Data ready token
|
||||
response.push_back(0xfe);
|
||||
// CSD
|
||||
// 0b00 CSD_STRUCTURE (SDv1)
|
||||
// 0b000000 reserved
|
||||
// 0b01111111 TAAC (8.0 * 10ms)
|
||||
// 0b00000000 NSAC
|
||||
// 0b00110010 TRAN_SPEED (2.5 * 10 Mbit/s, max operating frequency)
|
||||
|
||||
// 0b010110110101 CCC
|
||||
// 0b1111 READ_BL_LEN (2048 bytes)
|
||||
// 0b1 READ_BL_PARTIAL
|
||||
// 0b0 WRITE_BL_MISALIGN
|
||||
// 0b0 READ_BLK_MISALIGN
|
||||
// 0b0 DSR_IMP (no driver stage register implemented)
|
||||
// 0b00 reserved
|
||||
// 0b?????????? C_SIZE (most significant 10 bits)
|
||||
|
||||
// 0b?? C_SIZE (least significant 2 bits)
|
||||
// 0b111 VDD_R_CURR_MIN (100 mA)
|
||||
// 0b111 VDD_R_CURR_MAX (100 mA)
|
||||
// 0b111 VDD_W_CURR_MIN (100 mA)
|
||||
// 0b111 VDD_W_CURR_MAX (100 mA)
|
||||
// 0b??? C_SIZE_MULT
|
||||
// 0b1 ERASE_BLK_EN (erase unit = 512 bytes)
|
||||
// 0b1111111 SECTOR_SIZE (128 write blocks)
|
||||
// 0b0000000 WP_GRP_SIZE
|
||||
|
||||
// 0b0 WP_GRP_ENABLE (no write protection)
|
||||
// 0b00 reserved
|
||||
// 0b001 R2W_FACTOR (write half as fast as read)
|
||||
// 0b1111 WRITE_BL_LEN (= READ_BL_LEN)
|
||||
// 0b0 WRITE_BL_PARTIAL (no partial block writes)
|
||||
// 0b00000 reserved
|
||||
// 0b0 FILE_FORMAT_GRP (default)
|
||||
// 0b1 COPY (contents are copied)
|
||||
// 0b0 PERM_WRITE_PROTECT (not permanently write protected)
|
||||
// 0b0 TMP_READ_PROTECT (not temporarily write protected)
|
||||
// 0b00 FILE_FORMAT (contains partition table)
|
||||
// 0b00 reserved
|
||||
// 0b??????? CRC
|
||||
// 0b1 reserved
|
||||
|
||||
// TODO: CRC7 (but so far it looks like nobody is actually verifying this)
|
||||
constexpr u32 crc = 0;
|
||||
|
||||
// Form the csd using the description above
|
||||
response.push_back(0x00);
|
||||
response.push_back(0x07);
|
||||
response.push_back(0xf0);
|
||||
response.push_back(0x03);
|
||||
response.push_back(0x5b);
|
||||
response.push_back(0x5f);
|
||||
response.push_back(0x80 | (c_size >> 10));
|
||||
response.push_back(c_size >> 2);
|
||||
response.push_back(0x3f | c_size << 6);
|
||||
response.push_back(0xfc | (c_size_mult >> 1));
|
||||
response.push_back(0x7f | (c_size << 7));
|
||||
response.push_back(0x80);
|
||||
response.push_back(0x07);
|
||||
response.push_back(0xc0);
|
||||
response.push_back(0x40);
|
||||
response.push_back(0x01 | (crc << 1));
|
||||
// Hardcoded CRC16 (0x6a74)
|
||||
response.push_back(0x6a);
|
||||
response.push_back(0x74);
|
||||
break;
|
||||
}
|
||||
case Command::SendCID:
|
||||
{
|
||||
// R1
|
||||
response.push_back(0);
|
||||
// Data ready token
|
||||
response.push_back(0xfe);
|
||||
// The CID -- no idea what the format is, copied from SDIOSlot0
|
||||
response.push_back(0x80);
|
||||
response.push_back(0x11);
|
||||
response.push_back(0x4d);
|
||||
response.push_back(0x1c);
|
||||
response.push_back(0x80);
|
||||
response.push_back(0x08);
|
||||
response.push_back(0x00);
|
||||
response.push_back(0x00);
|
||||
response.push_back(0x80);
|
||||
response.push_back(0x07);
|
||||
response.push_back(0xb5);
|
||||
response.push_back(0x20);
|
||||
response.push_back(0x80);
|
||||
response.push_back(0x08);
|
||||
response.push_back(0x00);
|
||||
response.push_back(0x00);
|
||||
// Hardcoded CRC16 (0x9e3e)
|
||||
response.push_back(0x9e);
|
||||
response.push_back(0x3e);
|
||||
break;
|
||||
}
|
||||
case Command::StopTransmission:
|
||||
response.push_back(0); // R1
|
||||
// There can be further padding bytes, but it's not needed
|
||||
break;
|
||||
case Command::SetBlockLen:
|
||||
INFO_LOG_FMT(EXPANSIONINTERFACE, "Set blocklen to {}", argument);
|
||||
// TODO: error if blocklen not 512
|
||||
response.push_back(0); // R1
|
||||
break;
|
||||
case Command::AppCmd:
|
||||
next_is_appcmd = true;
|
||||
response.push_back(0); // R1
|
||||
break;
|
||||
default:
|
||||
// Don't know it
|
||||
WARN_LOG_FMT(EXPANSIONINTERFACE, "Unimplemented SD command {:02x} {:08x}",
|
||||
static_cast<u8>(command), argument);
|
||||
response.push_back(static_cast<u8>(R1::IllegalCommand));
|
||||
}
|
||||
}
|
||||
|
||||
void CEXISD::HandleAppCommand(AppCommand app_command, u32 argument)
|
||||
{
|
||||
switch (app_command)
|
||||
{
|
||||
case AppCommand::SDStatus:
|
||||
response.push_back(0); // R1
|
||||
response.push_back(0); // R2
|
||||
response.push_back(0xfe); // Data ready token
|
||||
for (size_t i = 0; i < 64; i++)
|
||||
{
|
||||
response.push_back(0);
|
||||
}
|
||||
// This CRC16 is 0, probably since the data is all 0
|
||||
response.push_back(0);
|
||||
response.push_back(0);
|
||||
break;
|
||||
case AppCommand::SDSendOpCond:
|
||||
{
|
||||
// Used by Pokémon Channel for all cards, and libogc for SDHC cards
|
||||
bool hcs = argument & (1 << 30); // Host Capacity Support (for SDHC/SDXC cards)
|
||||
(void)hcs;
|
||||
response.push_back(0); // R1 - not idle
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Don't know it
|
||||
WARN_LOG_FMT(EXPANSIONINTERFACE, "Unimplemented SD app command {:02x} {:08x}",
|
||||
static_cast<u8>(app_command), argument);
|
||||
response.push_back(static_cast<u8>(R1::IllegalCommand));
|
||||
}
|
||||
}
|
||||
|
||||
u8 CEXISD::ReadByte()
|
||||
{
|
||||
if (response.empty())
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/IOFile.h"
|
||||
#include "Core/HW/EXI/EXI_Device.h"
|
||||
|
||||
class PointerWrap;
|
||||
@ -31,7 +32,98 @@ public:
|
||||
void DoState(PointerWrap& p) override;
|
||||
|
||||
private:
|
||||
enum class Command
|
||||
{
|
||||
GoIdleState = 0,
|
||||
SendOpCond = 1,
|
||||
// AllSendCid = 2, // Not SPI
|
||||
// SendRelativeAddr = 3, // Not SPI
|
||||
// SetDSR = 4, // Not SPI
|
||||
// Reserved for SDIO
|
||||
SwitchFunc = 6,
|
||||
// SelectCard = 7, // or Deselect; not SPI
|
||||
SendInterfaceCond = 8,
|
||||
SendCSD = 9,
|
||||
SendCID = 10,
|
||||
// VoltageSwitch = 11, // Not SPI
|
||||
StopTransmission = 12,
|
||||
SendStatus = 13,
|
||||
// 14 Reserved
|
||||
// GoInactiveState = 15, // Not SPI
|
||||
|
||||
SetBlockLen = 16,
|
||||
ReadSingleBlock = 17,
|
||||
ReadMultipleBlock = 18,
|
||||
SendTuningBlock = 19,
|
||||
// SpeedClassControl = 20, // Not SPI
|
||||
// 21 Reserved
|
||||
// 22 Reserved
|
||||
SetBlockCount = 23,
|
||||
|
||||
WriteBlock = 24,
|
||||
WriteMultipleBlock = 25,
|
||||
// 26 Reserved for manufacturer
|
||||
ProgramCSD = 27,
|
||||
|
||||
SetWriteProt = 28,
|
||||
ClearWriteProt = 29,
|
||||
SendWriteProt = 30,
|
||||
// 31 Reserved
|
||||
|
||||
EraseWriteBlockStart = 32,
|
||||
EraseWriteBlockEnd = 33,
|
||||
// 34-37 Reserved for command system set by SwitchFunc
|
||||
Erase = 38,
|
||||
// 39 Reserved
|
||||
// 40 Reserved for security spec
|
||||
// 41 Reserved
|
||||
|
||||
LockUnlock = 42,
|
||||
// 43-49 Reserved
|
||||
// 50 Reserved for command system set by SwitchFunc
|
||||
// 51 Reserved
|
||||
// 52-54 used by SDIO
|
||||
|
||||
AppCmd = 55,
|
||||
GenCmd = 56,
|
||||
// 57-58 Reserved
|
||||
// 60-63 Reserved for manufacturer
|
||||
};
|
||||
|
||||
enum class AppCommand
|
||||
{
|
||||
// 1-5 Reserved
|
||||
// SetBusWidth = 6, // Not SPI
|
||||
// 7-12 Reserved
|
||||
SDStatus = 13,
|
||||
// 14-16 Reserved for security spec
|
||||
// 17 Reserved
|
||||
// 18 Reserved for SD security
|
||||
// 19-21 Reserved
|
||||
SendNumWrittenBlocks = 22,
|
||||
SetWriteBlockEraseCount = 23,
|
||||
// 24 Reserved
|
||||
// 25 Reserved for SD security
|
||||
// 26 Reserved for SD security
|
||||
// 27-28 Reserved for security spec
|
||||
// 29 Reserved
|
||||
// 30-35 Reserved for security spec
|
||||
// 36-37 Reserved
|
||||
// 38 Reserved for SD security
|
||||
// 39-40 Reserved
|
||||
SDSendOpCond = 41,
|
||||
SetClearCardDetect = 42,
|
||||
// 43 Reserved for SD security
|
||||
// 49 Reserved for SD security
|
||||
SendSCR = 51,
|
||||
// 52-54 Reserved for security spec
|
||||
AppCmd = 55,
|
||||
// 56-59 Reserved for security spec
|
||||
};
|
||||
|
||||
void WriteByte(u8 byte);
|
||||
void HandleCommand(Command command, u32 argument);
|
||||
void HandleAppCommand(AppCommand app_command, u32 argument);
|
||||
u8 ReadByte();
|
||||
|
||||
enum class R1
|
||||
@ -57,11 +149,16 @@ private:
|
||||
// OUT_OF_RANGE_OR_CSD_OVERWRITE, not documented in text?
|
||||
};
|
||||
|
||||
File::IOFile m_card;
|
||||
|
||||
// STATE_TO_SAVE
|
||||
bool inited = false;
|
||||
bool get_id = false;
|
||||
u32 m_uPosition = 0;
|
||||
std::array<u8, 6> cmd = {};
|
||||
bool next_is_appcmd = false;
|
||||
u32 command_position = 0;
|
||||
u32 block_position = 0;
|
||||
std::array<u8, 6> command_buffer = {};
|
||||
std::deque<u8> response;
|
||||
std::array<u8, 512> block_buffer = {};
|
||||
};
|
||||
} // namespace ExpansionInterface
|
||||
|
Loading…
x
Reference in New Issue
Block a user