From 4cbb66637b974dec77544ab2f5772ad2a70767ab Mon Sep 17 00:00:00 2001 From: Tom Boshoven Date: Sat, 29 Jul 2017 21:14:14 +0200 Subject: [PATCH 1/6] Add support for SDHC. This add support for SD protocol 2 while staying compatible with protocol 1.01. Most of this is quite hacky, but it seems to be working well. The original implementation was quite confusing, so I didn't touch most of the stuff I did not understand. --- Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp | 219 +++++++++++++++++++++--- Source/Core/Core/IOS/SDIO/SDIOSlot0.h | 11 ++ 2 files changed, 209 insertions(+), 21 deletions(-) diff --git a/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp b/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp index 8e1689c9e6..eb8486bba3 100644 --- a/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp +++ b/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp @@ -82,6 +82,7 @@ ReturnCode SDIOSlot0::Open(const OpenRequest& request) m_registers.fill(0); m_is_active = true; + return IPC_SUCCESS; } @@ -154,7 +155,8 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer u32 pad0; } req; - req.command = Memory::Read_U32(_BufferIn + 0); + // Ignore the first two bits + req.command = Memory::Read_U32(_BufferIn + 0) & 0x3f; req.type = Memory::Read_U32(_BufferIn + 4); req.resp = Memory::Read_U32(_BufferIn + 8); req.arg = Memory::Read_U32(_BufferIn + 12); @@ -171,7 +173,21 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer switch (req.command) { case GO_IDLE_STATE: - // libogc can use it during init.. + INFO_LOG(IOS_SD, "GO_IDLE_STATE"); + if (m_Card) + { + if (m_Card.GetSize() > SDHC_BYTES) + { + m_Status |= CARD_SDHC; + Memory::Write_U32(0xc0ff8000, _BufferOut); + } + else + { + Memory::Write_U32(0x80ff8000, _BufferOut); + // No further initialization required. + m_Status |= CARD_INITIALIZED; + } + } break; case SEND_RELATIVE_ADDR: @@ -187,22 +203,148 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer break; case SEND_IF_COND: + INFO_LOG(IOS_SD, "SEND_IF_COND"); // If the card can operate on the supplied voltage, the response echoes back the supply // voltage and the check pattern that were set in the command argument. + // This instruction is used to differentiate between protocol v1 and v2. + m_Protocol = PROTOCOL_V2; Memory::Write_U32(req.arg, _BufferOut); break; case SEND_CSD: - INFO_LOG(IOS_SD, "SEND_CSD"); - // shuffle2_, OCR: 0x80ff8000 CID: 0x38a00000 0x480032d5 0x3c608030 0x8803d420 - // CSD: 0xff928040 0xc93efbcf 0x325f5a83 0x00002600 + { + u64 size = m_Card.GetSize(); + if (m_Protocol == PROTOCOL_V2) + { + if (size % (512 * 1024) != 0) + WARN_LOG(IOS_SD, "SDHC Card size cannot be divided by 1024 * 512"); - // Values used currently are from lpfaint99 - Memory::Write_U32(0x80168000, _BufferOut); - Memory::Write_U32(0xa9ffffff, _BufferOut + 4); - Memory::Write_U32(0x325b5a83, _BufferOut + 8); - Memory::Write_U32(0x00002e00, _BufferOut + 12); - break; + size /= 512 * 1024; + size -= 1; + + // 0b01 CSD_STRUCTURE (SDv2) + // 0b000000 reserved + // 0b00001110 TAAC (1.0 * 1ms) + // 0b00000000 NSAC + // 0b01011010 TRAN_SPEED (5.0 * 10 Mbit/s, max operating frequency) + + // 0b010111110101 CCC (TODO: Figure out what each command class does) + // 0b1001 READ_BL_LEN (512 bytes, fixed for SDHC) + // 0b0 READ_BL_PARTIAL + // 0b0 WRITE_BLK_MISALIGN + // 0b0 READ_BLK_MISALIGN + // 0b0 DSR_IMP (no driver stage register implemented) + // 0b000000 reserved + // 0b?????? C_SIZE (most significant 6 bits) + + // 0b???????????????? C_SIZE (least significant 16 bits) + // 0b0 reserved + // 0b1 ERASE_BLK_EN + // 0b1111111 SECTOR_SIZE + // 0b0000000 WP_GRP_SIZE (not supported in SDHC) + + // 0b0 WP_GRP_ENABLE + // 0b00 reserved + // 0b010 R2W_FACTOR (x4) + // 0b1001 WRITE_BL_LEN (512 bytes) + // 0b0 WRITE_BL_PARTIAL + // 0b00000 reserved + // 0b0 FILE_FORMAT_GRP + // 0b0 COPY + // 0b0 PERM_WRITE_PROTECT + // 0b0 TMP_WRITE_PROTECT + // 0b00 FILE_FORMAT + // 0b00 reserved + // 0b0000000 CRC + // 0b1 reserved + + // TODO: crc7 + u32 crc = 0; + + Memory::Write_U32(0x400e005a, _BufferOut); + Memory::Write_U32(0x5f590000 | (size >> 16), _BufferOut + 4); + Memory::Write_U32(0x00007f80 | (size << 16), _BufferOut + 8); + Memory::Write_U32(0x0a400001 | crc << 1, _BufferOut + 12); + } + else + { + // 2048 bytes/sector + u32 read_bl_len = 11; + + // size = (c_size + 1) * (1 << (2 + c_size_mult + read_bl_len)) + u64 c_size = size; + u32 c_size_mult = 0; + bool invalid_size = false; + while (c_size > 4096) + { + invalid_size |= c_size & 1; + c_size >>= 1; + if (++c_size_mult >= 8 + 2 + read_bl_len) + { + ERROR_LOG(IOS_SD, "SD Card is too big!"); + // Set max values + c_size = 4096; + c_size_mult = 7 + 2 + read_bl_len; + } + } + c_size_mult -= 2 + read_bl_len; + --c_size; + + if (invalid_size) + WARN_LOG(IOS_SD, "SD Card size is invalid"); + else + INFO_LOG(IOS_SD, "SD C_SIZE = %lu, C_SIZE_MULT = %u", c_size, c_size_mult); + + // 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 + u32 crc = 0; + + Memory::Write_U32(0x007f0032, _BufferOut); + Memory::Write_U32(0x5b5f8000 | (c_size >> 2), _BufferOut + 4); + Memory::Write_U32(0x3ffc7f80 | (c_size << 30) | (c_size_mult << 15), _BufferOut + 8); + Memory::Write_U32(0x07c04001 | (crc << 1), _BufferOut + 12); + } + } + break; case ALL_SEND_CID: case SEND_CID: @@ -232,7 +374,18 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer case ACMD_SENDOPCOND: // Sends host capacity support information (HCS) and asks the accessed card to send // its operating condition register (OCR) content - Memory::Write_U32(0x80ff8000, _BufferOut); + { + u32 ocr = 0x00ff8000; + // Never leave idle state if the card is not supported by the protocol + if (m_Protocol == PROTOCOL_V2 || !(m_Status & CARD_SDHC)) + { + m_Status |= CARD_INITIALIZED; + ocr |= 0x80000000; + if (m_Status & CARD_SDHC) + ocr |= 0x40000000; + } + Memory::Write_U32(ocr, _BufferOut); + } break; case READ_MULTIPLE_BLOCK: @@ -245,8 +398,13 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer if (m_Card) { u32 size = req.bsize * req.blocks; + u64 address = req.arg; + if (m_Status & CARD_SDHC) + { + address *= 512; + } - if (!m_Card.Seek(req.arg, SEEK_SET)) + if (!m_Card.Seek(address, SEEK_SET)) ERROR_LOG(IOS_SD, "Seek failed WTF"); if (m_Card.ReadBytes(Memory::GetPointer(req.addr), size)) @@ -274,8 +432,13 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer if (m_Card && SConfig::GetInstance().bEnableMemcardSdWriting) { u32 size = req.bsize * req.blocks; + u64 address = req.arg; + if (m_Status & CARD_SDHC) + { + address *= 512; + } - if (!m_Card.Seek(req.arg, SEEK_SET)) + if (!m_Card.Seek(address, SEEK_SET)) ERROR_LOG(IOS_SD, "fseeko failed WTF"); if (!m_Card.WriteBytes(Memory::GetPointer(req.addr), size)) @@ -289,6 +452,9 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer Memory::Write_U32(0x900, _BufferOut); break; + // The following events don't seem to be possible due to the command length being only 6 bits + // I don't want to delete this without more context on why it's there and what it's meant to do + /* case EVENT_REGISTER: // async INFO_LOG(IOS_SD, "Register event %x", req.arg); m_event = std::make_unique(static_cast(req.arg), request); @@ -308,6 +474,7 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer m_event.reset(); break; } + */ default: ERROR_LOG(IOS_SD, "Unknown SD command 0x%08x", req.command); @@ -371,11 +538,9 @@ IPCCommandResult SDIOSlot0::ResetCard(const IOCtlRequest& request) { INFO_LOG(IOS_SD, "IOCTL_RESETCARD"); - if (m_Card) - m_Status |= CARD_INITIALIZED; - // Returns 16bit RCA and 16bit 0s (meaning success) - Memory::Write_U32(0x9f620000, request.buffer_out); + Memory::Write_U32(m_Status, request.buffer_out); + return GetDefaultReply(IPC_SUCCESS); } @@ -417,7 +582,8 @@ IPCCommandResult SDIOSlot0::GetStatus(const IOCtlRequest& request) else m_Status = CARD_NOT_EXIST; - INFO_LOG(IOS_SD, "IOCTL_GETSTATUS. Replying that SD card is %s%s", + INFO_LOG(IOS_SD, "IOCTL_GETSTATUS. Replying that %s card is %s%s", + (m_Status & CARD_SDHC) ? "SDHC" : "SD", (m_Status & CARD_INSERTED) ? "inserted" : "not present", (m_Status & CARD_INITIALIZED) ? " and initialized" : ""); @@ -427,8 +593,18 @@ IPCCommandResult SDIOSlot0::GetStatus(const IOCtlRequest& request) IPCCommandResult SDIOSlot0::GetOCRegister(const IOCtlRequest& request) { - INFO_LOG(IOS_SD, "IOCTL_GETOCR"); - Memory::Write_U32(0x80ff8000, request.buffer_out); + u32 ocr = 0x00ff8000; + // Never leave idle state if the card is not supported by the protocol + if (m_Protocol == PROTOCOL_V2 || !(m_Status & CARD_SDHC)) + { + if (m_Status & CARD_INITIALIZED) + ocr |= 0x80000000; + if (m_Status & CARD_SDHC) + ocr |= 0x40000000; + } + INFO_LOG(IOS_SD, "IOCTL_GETOCR. Replying with ocr %x", ocr); + Memory::Write_U32(ocr, request.buffer_out); + return GetDefaultReply(IPC_SUCCESS); } @@ -444,6 +620,7 @@ IPCCommandResult SDIOSlot0::SendCommand(const IOCtlVRequest& request) return GetDefaultReply(return_value); } + } // namespace Device } // namespace HLE } // namespace IOS diff --git a/Source/Core/Core/IOS/SDIO/SDIOSlot0.h b/Source/Core/Core/IOS/SDIO/SDIOSlot0.h index 9ca7729dd0..ad3da73333 100644 --- a/Source/Core/Core/IOS/SDIO/SDIOSlot0.h +++ b/Source/Core/Core/IOS/SDIO/SDIOSlot0.h @@ -77,6 +77,7 @@ private: CARD_NOT_EXIST = 0, CARD_INSERTED = 1, CARD_INITIALIZED = 0x10000, + CARD_SDHC = 0x100000, }; // Commands @@ -111,6 +112,14 @@ private: EVENT_INVALID = 0xc210000 }; + enum SD_PROTOCOL + { + PROTOCOL_V1 = 0, + PROTOCOL_V2 = 1, + }; + + const u32 SDHC_BYTES = 0x80000000; + struct Event { Event(EventType type_, Request request_) : type(type_), request(request_) {} @@ -136,6 +145,8 @@ private: std::unique_ptr m_event; u32 m_Status = CARD_NOT_EXIST; + u32 m_Protocol = PROTOCOL_V1; + u32 m_BlockLength = 0; u32 m_BusWidth = 0; From fa683adaf53a4f701aed7ceeb10f2550126a315e Mon Sep 17 00:00:00 2001 From: Tom Boshoven Date: Sat, 29 Jul 2017 22:13:47 +0200 Subject: [PATCH 2/6] SDHC documentation and cleanups. Added some more comments. Cleanups based on PR feedback. Comment was unclear. --- Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp | 340 +++++++++++++----------- Source/Core/Core/IOS/SDIO/SDIOSlot0.h | 18 +- 2 files changed, 195 insertions(+), 163 deletions(-) diff --git a/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp b/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp index eb8486bba3..3df1bf126a 100644 --- a/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp +++ b/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp @@ -155,7 +155,7 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer u32 pad0; } req; - // Ignore the first two bits + // Ignore the first two bits (start bit and direction) req.command = Memory::Read_U32(_BufferIn + 0) & 0x3f; req.type = Memory::Read_U32(_BufferIn + 4); req.resp = Memory::Read_U32(_BufferIn + 8); @@ -178,16 +178,21 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer { if (m_Card.GetSize() > SDHC_BYTES) { + // SDHC requires further initialization (SEND_IF_COND) m_Status |= CARD_SDHC; - Memory::Write_U32(0xc0ff8000, _BufferOut); } else { - Memory::Write_U32(0x80ff8000, _BufferOut); // No further initialization required. m_Status |= CARD_INITIALIZED; } } + else + { + // Make sure we're not initialized + m_Status &= ~CARD_INITIALIZED; + } + Memory::Write_U32(GetOCRegister(), _BufferOut); break; case SEND_RELATIVE_ADDR: @@ -206,143 +211,22 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer INFO_LOG(IOS_SD, "SEND_IF_COND"); // If the card can operate on the supplied voltage, the response echoes back the supply // voltage and the check pattern that were set in the command argument. - // This instruction is used to differentiate between protocol v1 and v2. - m_Protocol = PROTOCOL_V2; + // This command is used to differentiate between protocol v1 and v2. + m_protocol = SDProtocol::V2; Memory::Write_U32(req.arg, _BufferOut); break; case SEND_CSD: { - u64 size = m_Card.GetSize(); - if (m_Protocol == PROTOCOL_V2) - { - if (size % (512 * 1024) != 0) - WARN_LOG(IOS_SD, "SDHC Card size cannot be divided by 1024 * 512"); - - size /= 512 * 1024; - size -= 1; - - // 0b01 CSD_STRUCTURE (SDv2) - // 0b000000 reserved - // 0b00001110 TAAC (1.0 * 1ms) - // 0b00000000 NSAC - // 0b01011010 TRAN_SPEED (5.0 * 10 Mbit/s, max operating frequency) - - // 0b010111110101 CCC (TODO: Figure out what each command class does) - // 0b1001 READ_BL_LEN (512 bytes, fixed for SDHC) - // 0b0 READ_BL_PARTIAL - // 0b0 WRITE_BLK_MISALIGN - // 0b0 READ_BLK_MISALIGN - // 0b0 DSR_IMP (no driver stage register implemented) - // 0b000000 reserved - // 0b?????? C_SIZE (most significant 6 bits) - - // 0b???????????????? C_SIZE (least significant 16 bits) - // 0b0 reserved - // 0b1 ERASE_BLK_EN - // 0b1111111 SECTOR_SIZE - // 0b0000000 WP_GRP_SIZE (not supported in SDHC) - - // 0b0 WP_GRP_ENABLE - // 0b00 reserved - // 0b010 R2W_FACTOR (x4) - // 0b1001 WRITE_BL_LEN (512 bytes) - // 0b0 WRITE_BL_PARTIAL - // 0b00000 reserved - // 0b0 FILE_FORMAT_GRP - // 0b0 COPY - // 0b0 PERM_WRITE_PROTECT - // 0b0 TMP_WRITE_PROTECT - // 0b00 FILE_FORMAT - // 0b00 reserved - // 0b0000000 CRC - // 0b1 reserved - - // TODO: crc7 - u32 crc = 0; - - Memory::Write_U32(0x400e005a, _BufferOut); - Memory::Write_U32(0x5f590000 | (size >> 16), _BufferOut + 4); - Memory::Write_U32(0x00007f80 | (size << 16), _BufferOut + 8); - Memory::Write_U32(0x0a400001 | crc << 1, _BufferOut + 12); - } + u32 csd[4]; + if (m_protocol == SDProtocol::V1) + GetCSDv1(csd); else - { - // 2048 bytes/sector - u32 read_bl_len = 11; - - // size = (c_size + 1) * (1 << (2 + c_size_mult + read_bl_len)) - u64 c_size = size; - u32 c_size_mult = 0; - bool invalid_size = false; - while (c_size > 4096) - { - invalid_size |= c_size & 1; - c_size >>= 1; - if (++c_size_mult >= 8 + 2 + read_bl_len) - { - ERROR_LOG(IOS_SD, "SD Card is too big!"); - // Set max values - c_size = 4096; - c_size_mult = 7 + 2 + read_bl_len; - } - } - c_size_mult -= 2 + read_bl_len; - --c_size; - - if (invalid_size) - WARN_LOG(IOS_SD, "SD Card size is invalid"); - else - INFO_LOG(IOS_SD, "SD C_SIZE = %lu, C_SIZE_MULT = %u", c_size, c_size_mult); - - // 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 - u32 crc = 0; - - Memory::Write_U32(0x007f0032, _BufferOut); - Memory::Write_U32(0x5b5f8000 | (c_size >> 2), _BufferOut + 4); - Memory::Write_U32(0x3ffc7f80 | (c_size << 30) | (c_size_mult << 15), _BufferOut + 8); - Memory::Write_U32(0x07c04001 | (crc << 1), _BufferOut + 12); - } + GetCSDv2(csd); + Memory::Write_U32(csd[0], _BufferOut); + Memory::Write_U32(csd[1], _BufferOut + 4); + Memory::Write_U32(csd[2], _BufferOut + 8); + Memory::Write_U32(csd[3], _BufferOut + 12); } break; @@ -375,15 +259,11 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer // Sends host capacity support information (HCS) and asks the accessed card to send // its operating condition register (OCR) content { - u32 ocr = 0x00ff8000; // Never leave idle state if the card is not supported by the protocol - if (m_Protocol == PROTOCOL_V2 || !(m_Status & CARD_SDHC)) - { + if (m_protocol == SDProtocol::V2 || !(m_Status & CARD_SDHC)) m_Status |= CARD_INITIALIZED; - ocr |= 0x80000000; - if (m_Status & CARD_SDHC) - ocr |= 0x40000000; - } + + u32 ocr = GetOCRegister(); Memory::Write_U32(ocr, _BufferOut); } break; @@ -398,11 +278,7 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer if (m_Card) { u32 size = req.bsize * req.blocks; - u64 address = req.arg; - if (m_Status & CARD_SDHC) - { - address *= 512; - } + u64 address = GetAddressFromRequest(req.arg); if (!m_Card.Seek(address, SEEK_SET)) ERROR_LOG(IOS_SD, "Seek failed WTF"); @@ -432,11 +308,7 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer if (m_Card && SConfig::GetInstance().bEnableMemcardSdWriting) { u32 size = req.bsize * req.blocks; - u64 address = req.arg; - if (m_Status & CARD_SDHC) - { - address *= 512; - } + u64 address = GetAddressFromRequest(req.arg); if (!m_Card.Seek(address, SEEK_SET)) ERROR_LOG(IOS_SD, "fseeko failed WTF"); @@ -593,15 +465,12 @@ IPCCommandResult SDIOSlot0::GetStatus(const IOCtlRequest& request) IPCCommandResult SDIOSlot0::GetOCRegister(const IOCtlRequest& request) { - u32 ocr = 0x00ff8000; - // Never leave idle state if the card is not supported by the protocol - if (m_Protocol == PROTOCOL_V2 || !(m_Status & CARD_SDHC)) + // Make sure we're not initialized if the card is not supported by the protocol + if (m_protocol != SDProtocol::V2 && (m_Status & CARD_SDHC)) { - if (m_Status & CARD_INITIALIZED) - ocr |= 0x80000000; - if (m_Status & CARD_SDHC) - ocr |= 0x40000000; + m_Status &= ~CARD_INITIALIZED; } + u32 ocr = GetOCRegister(); INFO_LOG(IOS_SD, "IOCTL_GETOCR. Replying with ocr %x", ocr); Memory::Write_U32(ocr, request.buffer_out); @@ -621,6 +490,161 @@ IPCCommandResult SDIOSlot0::SendCommand(const IOCtlVRequest& request) return GetDefaultReply(return_value); } +u32 SDIOSlot0::GetOCRegister() const +{ + u32 ocr = 0x00ff8000; + if (m_Status & CARD_INITIALIZED) + ocr |= 0x80000000; + if (m_Status & CARD_SDHC) + ocr |= 0x40000000; + return ocr; +} + +void SDIOSlot0::GetCSDv1(u32 csd[4]) +{ + u64 size = m_Card.GetSize(); + + // 2048 bytes/sector + u32 read_bl_len = 11; + + // size = (c_size + 1) * (1 << (2 + c_size_mult + read_bl_len)) + u64 c_size = size; + u32 c_size_mult = 0; + bool invalid_size = false; + while (c_size > 4096) + { + invalid_size |= c_size & 1; + c_size >>= 1; + if (++c_size_mult >= 8 + 2 + read_bl_len) + { + ERROR_LOG(IOS_SD, "SD Card is too big!"); + // Set max values + c_size = 4096; + c_size_mult = 7 + 2 + read_bl_len; + } + } + c_size_mult -= 2 + read_bl_len; + --c_size; + + if (invalid_size) + WARN_LOG(IOS_SD, "SD Card size is invalid"); + else + INFO_LOG(IOS_SD, "SD C_SIZE = %lu, C_SIZE_MULT = %u", c_size, c_size_mult); + + // 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) + u32 crc = 0; + + // Form the csd using the description above + csd[0] = 0x007f003; + csd[1] = 0x5b5f8000 | (c_size >> 2); + csd[2] = 0x3ffc7f80 | (c_size << 30) | (c_size_mult << 15); + csd[3] = 0x07c04001 | (crc << 1); +} + +void SDIOSlot0::GetCSDv2(u32 csd[4]) +{ + u64 size = m_Card.GetSize(); + + if (size % (512 * 1024) != 0) + WARN_LOG(IOS_SD, "SDHC Card size cannot be divided by 1024 * 512"); + + size /= 512 * 1024; + size -= 1; + + // 0b01 CSD_STRUCTURE (SDv2) + // 0b000000 reserved + // 0b00001110 TAAC (1.0 * 1ms) + // 0b00000000 NSAC + // 0b01011010 TRAN_SPEED (5.0 * 10 Mbit/s, max operating frequency) + + // 0b010111110101 CCC (TODO: Figure out what each command class does) + // 0b1001 READ_BL_LEN (512 bytes, fixed for SDHC) + // 0b0 READ_BL_PARTIAL + // 0b0 WRITE_BLK_MISALIGN + // 0b0 READ_BLK_MISALIGN + // 0b0 DSR_IMP (no driver stage register implemented) + // 0b000000 reserved + // 0b?????? C_SIZE (most significant 6 bits) + + // 0b???????????????? C_SIZE (least significant 16 bits) + // 0b0 reserved + // 0b1 ERASE_BLK_EN + // 0b1111111 SECTOR_SIZE + // 0b0000000 WP_GRP_SIZE (not supported in SDHC) + + // 0b0 WP_GRP_ENABLE + // 0b00 reserved + // 0b010 R2W_FACTOR (x4) + // 0b1001 WRITE_BL_LEN (512 bytes) + // 0b0 WRITE_BL_PARTIAL + // 0b00000 reserved + // 0b0 FILE_FORMAT_GRP + // 0b0 COPY + // 0b0 PERM_WRITE_PROTECT + // 0b0 TMP_WRITE_PROTECT + // 0b00 FILE_FORMAT + // 0b00 reserved + // 0b0000000 CRC + // 0b1 reserved + + // TODO: CRC7 (but so far it looks like nobody is actually verifying this) + u32 crc = 0; + + // Form the csd using the description above + csd[0] = 0x400e005a; + csd[1] = 0x5f590000 | (size >> 16); + csd[2] = 0x00007f80 | (size << 16); + csd[3] = 0x0a400001 | (crc << 1); +} + +u64 SDIOSlot0::GetAddressFromRequest(u32 arg) const +{ + u64 address = arg; + if (m_Status & CARD_SDHC) + address *= 512; + return address; +} + } // namespace Device } // namespace HLE } // namespace IOS diff --git a/Source/Core/Core/IOS/SDIO/SDIOSlot0.h b/Source/Core/Core/IOS/SDIO/SDIOSlot0.h index ad3da73333..30e7617b43 100644 --- a/Source/Core/Core/IOS/SDIO/SDIOSlot0.h +++ b/Source/Core/Core/IOS/SDIO/SDIOSlot0.h @@ -112,13 +112,14 @@ private: EVENT_INVALID = 0xc210000 }; - enum SD_PROTOCOL + enum class SDProtocol { - PROTOCOL_V1 = 0, - PROTOCOL_V2 = 1, + V1 = 0, + V2 = 1, }; - const u32 SDHC_BYTES = 0x80000000; + // Number of bytes to trigger using SDHC instead of SDSC + static constexpr u32 SDHC_BYTES = 0x80000000; struct Event { @@ -141,11 +142,18 @@ private: u32 BufferInSize2, u32 _BufferOut, u32 BufferOutSize); void OpenInternal(); + u32 GetOCRegister() const; + + void GetCSDv1(u32 csd[4]); + void GetCSDv2(u32 csd[4]); + + u64 GetAddressFromRequest(u32 arg) const; + // TODO: do we need more than one? std::unique_ptr m_event; u32 m_Status = CARD_NOT_EXIST; - u32 m_Protocol = PROTOCOL_V1; + SDProtocol m_protocol = SDProtocol::V1; u32 m_BlockLength = 0; u32 m_BusWidth = 0; From 494e935ca7503434a49596f11493a66af055de40 Mon Sep 17 00:00:00 2001 From: Tom Boshoven Date: Sun, 30 Jul 2017 21:50:08 +0200 Subject: [PATCH 3/6] Use std::array for CSD. Fix double negative in comment. Fixed member variable names, added some const correctness. --- Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp | 144 +++++++++++------------- Source/Core/Core/IOS/SDIO/SDIOSlot0.h | 16 +-- 2 files changed, 76 insertions(+), 84 deletions(-) diff --git a/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp b/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp index 3df1bf126a..5b7f94a866 100644 --- a/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp +++ b/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp @@ -36,9 +36,9 @@ void SDIOSlot0::DoState(PointerWrap& p) { OpenInternal(); } - p.Do(m_Status); - p.Do(m_BlockLength); - p.Do(m_BusWidth); + p.Do(m_status); + p.Do(m_block_length); + p.Do(m_bus_width); p.Do(m_registers); } @@ -59,16 +59,16 @@ void SDIOSlot0::EventNotify() void SDIOSlot0::OpenInternal() { const std::string filename = File::GetUserPath(F_WIISDCARD_IDX); - m_Card.Open(filename, "r+b"); - if (!m_Card) + m_card.Open(filename, "r+b"); + if (!m_card) { WARN_LOG(IOS_SD, "Failed to open SD Card image, trying to create a new 128MB image..."); if (SDCardCreate(128, filename)) { INFO_LOG(IOS_SD, "Successfully created %s", filename.c_str()); - m_Card.Open(filename, "r+b"); + m_card.Open(filename, "r+b"); } - if (!m_Card) + if (!m_card) { ERROR_LOG(IOS_SD, "Could not open SD Card image or create a new one, are you running " "from a read-only directory?"); @@ -88,9 +88,9 @@ ReturnCode SDIOSlot0::Open(const OpenRequest& request) ReturnCode SDIOSlot0::Close(u32 fd) { - m_Card.Close(); - m_BlockLength = 0; - m_BusWidth = 0; + m_card.Close(); + m_block_length = 0; + m_bus_width = 0; return Device::Close(fd); } @@ -174,23 +174,23 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer { case GO_IDLE_STATE: INFO_LOG(IOS_SD, "GO_IDLE_STATE"); - if (m_Card) + if (m_card) { - if (m_Card.GetSize() > SDHC_BYTES) + if (m_card.GetSize() > SDHC_BYTES) { // SDHC requires further initialization (SEND_IF_COND) - m_Status |= CARD_SDHC; + m_status |= CARD_SDHC; } else { // No further initialization required. - m_Status |= CARD_INITIALIZED; + m_status |= CARD_INITIALIZED; } } else { // Make sure we're not initialized - m_Status &= ~CARD_INITIALIZED; + m_status &= ~CARD_INITIALIZED; } Memory::Write_U32(GetOCRegister(), _BufferOut); break; @@ -218,15 +218,8 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer case SEND_CSD: { - u32 csd[4]; - if (m_protocol == SDProtocol::V1) - GetCSDv1(csd); - else - GetCSDv2(csd); - Memory::Write_U32(csd[0], _BufferOut); - Memory::Write_U32(csd[1], _BufferOut + 4); - Memory::Write_U32(csd[2], _BufferOut + 8); - Memory::Write_U32(csd[3], _BufferOut + 12); + const std::array csd = m_protocol == SDProtocol::V1 ? GetCSDv1() : GetCSDv2(); + Memory::CopyToEmuSwapped(_BufferOut, csd.data(), csd.size() * sizeof(u32)); } break; @@ -240,7 +233,7 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer break; case SET_BLOCKLEN: - m_BlockLength = req.arg; + m_block_length = req.arg; Memory::Write_U32(0x900, _BufferOut); break; @@ -251,7 +244,7 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer case ACMD_SETBUSWIDTH: // 0 = 1bit, 2 = 4bit - m_BusWidth = (req.arg & 3); + m_bus_width = (req.arg & 3); Memory::Write_U32(0x920, _BufferOut); break; @@ -259,9 +252,9 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer // Sends host capacity support information (HCS) and asks the accessed card to send // its operating condition register (OCR) content { - // Never leave idle state if the card is not supported by the protocol - if (m_protocol == SDProtocol::V2 || !(m_Status & CARD_SDHC)) - m_Status |= CARD_INITIALIZED; + // Only leave idle state if the card is supported by the protocol + if (m_protocol == SDProtocol::V2 || !(m_status & CARD_SDHC)) + m_status |= CARD_INITIALIZED; u32 ocr = GetOCRegister(); Memory::Write_U32(ocr, _BufferOut); @@ -275,22 +268,22 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer INFO_LOG(IOS_SD, "%sRead %i Block(s) from 0x%08x bsize %i into 0x%08x!", req.isDMA ? "DMA " : "", req.blocks, req.arg, req.bsize, req.addr); - if (m_Card) + if (m_card) { u32 size = req.bsize * req.blocks; u64 address = GetAddressFromRequest(req.arg); - if (!m_Card.Seek(address, SEEK_SET)) + if (!m_card.Seek(address, SEEK_SET)) ERROR_LOG(IOS_SD, "Seek failed WTF"); - if (m_Card.ReadBytes(Memory::GetPointer(req.addr), size)) + if (m_card.ReadBytes(Memory::GetPointer(req.addr), size)) { DEBUG_LOG(IOS_SD, "Outbuffer size %i got %i", _rwBufferSize, size); } else { - ERROR_LOG(IOS_SD, "Read Failed - error: %i, eof: %i", ferror(m_Card.GetHandle()), - feof(m_Card.GetHandle())); + ERROR_LOG(IOS_SD, "Read Failed - error: %i, eof: %i", ferror(m_card.GetHandle()), + feof(m_card.GetHandle())); ret = RET_FAIL; } } @@ -305,18 +298,18 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer INFO_LOG(IOS_SD, "%sWrite %i Block(s) from 0x%08x bsize %i to offset 0x%08x!", req.isDMA ? "DMA " : "", req.blocks, req.addr, req.bsize, req.arg); - if (m_Card && SConfig::GetInstance().bEnableMemcardSdWriting) + if (m_card && SConfig::GetInstance().bEnableMemcardSdWriting) { u32 size = req.bsize * req.blocks; u64 address = GetAddressFromRequest(req.arg); - if (!m_Card.Seek(address, SEEK_SET)) + if (!m_card.Seek(address, SEEK_SET)) ERROR_LOG(IOS_SD, "fseeko failed WTF"); - if (!m_Card.WriteBytes(Memory::GetPointer(req.addr), size)) + if (!m_card.WriteBytes(Memory::GetPointer(req.addr), size)) { - ERROR_LOG(IOS_SD, "Write Failed - error: %i, eof: %i", ferror(m_Card.GetHandle()), - feof(m_Card.GetHandle())); + ERROR_LOG(IOS_SD, "Write Failed - error: %i, eof: %i", ferror(m_card.GetHandle()), + feof(m_card.GetHandle())); ret = RET_FAIL; } } @@ -411,7 +404,7 @@ IPCCommandResult SDIOSlot0::ResetCard(const IOCtlRequest& request) INFO_LOG(IOS_SD, "IOCTL_RESETCARD"); // Returns 16bit RCA and 16bit 0s (meaning success) - Memory::Write_U32(m_Status, request.buffer_out); + Memory::Write_U32(m_status, request.buffer_out); return GetDefaultReply(IPC_SUCCESS); } @@ -450,25 +443,25 @@ IPCCommandResult SDIOSlot0::SendCommand(const IOCtlRequest& request) IPCCommandResult SDIOSlot0::GetStatus(const IOCtlRequest& request) { if (SConfig::GetInstance().m_WiiSDCard) - m_Status |= CARD_INSERTED; + m_status |= CARD_INSERTED; else - m_Status = CARD_NOT_EXIST; + m_status = CARD_NOT_EXIST; INFO_LOG(IOS_SD, "IOCTL_GETSTATUS. Replying that %s card is %s%s", - (m_Status & CARD_SDHC) ? "SDHC" : "SD", - (m_Status & CARD_INSERTED) ? "inserted" : "not present", - (m_Status & CARD_INITIALIZED) ? " and initialized" : ""); + (m_status & CARD_SDHC) ? "SDHC" : "SD", + (m_status & CARD_INSERTED) ? "inserted" : "not present", + (m_status & CARD_INITIALIZED) ? " and initialized" : ""); - Memory::Write_U32(m_Status, request.buffer_out); + Memory::Write_U32(m_status, request.buffer_out); return GetDefaultReply(IPC_SUCCESS); } IPCCommandResult SDIOSlot0::GetOCRegister(const IOCtlRequest& request) { // Make sure we're not initialized if the card is not supported by the protocol - if (m_protocol != SDProtocol::V2 && (m_Status & CARD_SDHC)) + if (m_protocol != SDProtocol::V2 && (m_status & CARD_SDHC)) { - m_Status &= ~CARD_INITIALIZED; + m_status &= ~CARD_INITIALIZED; } u32 ocr = GetOCRegister(); INFO_LOG(IOS_SD, "IOCTL_GETOCR. Replying with ocr %x", ocr); @@ -493,43 +486,44 @@ IPCCommandResult SDIOSlot0::SendCommand(const IOCtlVRequest& request) u32 SDIOSlot0::GetOCRegister() const { u32 ocr = 0x00ff8000; - if (m_Status & CARD_INITIALIZED) + if (m_status & CARD_INITIALIZED) ocr |= 0x80000000; - if (m_Status & CARD_SDHC) + if (m_status & CARD_SDHC) ocr |= 0x40000000; return ocr; } -void SDIOSlot0::GetCSDv1(u32 csd[4]) +std::array SDIOSlot0::GetCSDv1() { - u64 size = m_Card.GetSize(); + u64 size = m_card.GetSize(); // 2048 bytes/sector - u32 read_bl_len = 11; + // 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)) - u64 c_size = size; u32 c_size_mult = 0; bool invalid_size = false; - while (c_size > 4096) + while (size > 4096) { - invalid_size |= c_size & 1; - c_size >>= 1; + invalid_size |= size & 1; + size >>= 1; if (++c_size_mult >= 8 + 2 + read_bl_len) { ERROR_LOG(IOS_SD, "SD Card is too big!"); // Set max values - c_size = 4096; + size = 4096; c_size_mult = 7 + 2 + read_bl_len; } } c_size_mult -= 2 + read_bl_len; - --c_size; + --size; + const u32 c_size(size); if (invalid_size) WARN_LOG(IOS_SD, "SD Card size is invalid"); else - INFO_LOG(IOS_SD, "SD C_SIZE = %lu, C_SIZE_MULT = %u", c_size, c_size_mult); + INFO_LOG(IOS_SD, "SD C_SIZE = %u, C_SIZE_MULT = %u", c_size, c_size_mult); // 0b00 CSD_STRUCTURE (SDv1) // 0b000000 reserved @@ -572,24 +566,23 @@ void SDIOSlot0::GetCSDv1(u32 csd[4]) // 0b1 reserved // TODO: CRC7 (but so far it looks like nobody is actually verifying this) - u32 crc = 0; + constexpr u32 crc = 0; // Form the csd using the description above - csd[0] = 0x007f003; - csd[1] = 0x5b5f8000 | (c_size >> 2); - csd[2] = 0x3ffc7f80 | (c_size << 30) | (c_size_mult << 15); - csd[3] = 0x07c04001 | (crc << 1); + return { + 0x007f003, 0x5b5f8000 | (c_size >> 2), 0x3ffc7f80 | (c_size << 30) | (c_size_mult << 15), + 0x07c04001 | (crc << 1), + }; } -void SDIOSlot0::GetCSDv2(u32 csd[4]) +std::array SDIOSlot0::GetCSDv2() { - u64 size = m_Card.GetSize(); + const u64 size = m_card.GetSize(); if (size % (512 * 1024) != 0) WARN_LOG(IOS_SD, "SDHC Card size cannot be divided by 1024 * 512"); - size /= 512 * 1024; - size -= 1; + const u32 c_size(size / (512 * 1024) - 1); // 0b01 CSD_STRUCTURE (SDv2) // 0b000000 reserved @@ -628,19 +621,18 @@ void SDIOSlot0::GetCSDv2(u32 csd[4]) // 0b1 reserved // TODO: CRC7 (but so far it looks like nobody is actually verifying this) - u32 crc = 0; + constexpr u32 crc = 0; // Form the csd using the description above - csd[0] = 0x400e005a; - csd[1] = 0x5f590000 | (size >> 16); - csd[2] = 0x00007f80 | (size << 16); - csd[3] = 0x0a400001 | (crc << 1); + return { + 0x400e005a, 0x5f590000 | (c_size >> 16), 0x00007f80 | (c_size << 16), 0x0a400001 | (crc << 1), + }; } u64 SDIOSlot0::GetAddressFromRequest(u32 arg) const { - u64 address = arg; - if (m_Status & CARD_SDHC) + u64 address(arg); + if (m_status & CARD_SDHC) address *= 512; return address; } diff --git a/Source/Core/Core/IOS/SDIO/SDIOSlot0.h b/Source/Core/Core/IOS/SDIO/SDIOSlot0.h index 30e7617b43..c50ab50d54 100644 --- a/Source/Core/Core/IOS/SDIO/SDIOSlot0.h +++ b/Source/Core/Core/IOS/SDIO/SDIOSlot0.h @@ -114,8 +114,8 @@ private: enum class SDProtocol { - V1 = 0, - V2 = 1, + V1, + V2, }; // Number of bytes to trigger using SDHC instead of SDSC @@ -144,23 +144,23 @@ private: u32 GetOCRegister() const; - void GetCSDv1(u32 csd[4]); - void GetCSDv2(u32 csd[4]); + std::array GetCSDv1(); + std::array GetCSDv2(); u64 GetAddressFromRequest(u32 arg) const; // TODO: do we need more than one? std::unique_ptr m_event; - u32 m_Status = CARD_NOT_EXIST; + u32 m_status = CARD_NOT_EXIST; SDProtocol m_protocol = SDProtocol::V1; - u32 m_BlockLength = 0; - u32 m_BusWidth = 0; + u32 m_block_length = 0; + u32 m_bus_width = 0; std::array m_registers; - File::IOFile m_Card; + File::IOFile m_card; }; } // namespace Device } // namespace HLE From 47e056a65456ea04b6c14087a0c6c79eb46f478f Mon Sep 17 00:00:00 2001 From: Tom Boshoven Date: Sat, 5 Aug 2017 14:52:03 +0200 Subject: [PATCH 4/6] Re-enable SDIO events. --- Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp b/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp index 5b7f94a866..2ecd8f108a 100644 --- a/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp +++ b/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp @@ -155,8 +155,7 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer u32 pad0; } req; - // Ignore the first two bits (start bit and direction) - req.command = Memory::Read_U32(_BufferIn + 0) & 0x3f; + req.command = Memory::Read_U32(_BufferIn + 0); req.type = Memory::Read_U32(_BufferIn + 4); req.resp = Memory::Read_U32(_BufferIn + 8); req.arg = Memory::Read_U32(_BufferIn + 12); @@ -317,9 +316,6 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer Memory::Write_U32(0x900, _BufferOut); break; - // The following events don't seem to be possible due to the command length being only 6 bits - // I don't want to delete this without more context on why it's there and what it's meant to do - /* case EVENT_REGISTER: // async INFO_LOG(IOS_SD, "Register event %x", req.arg); m_event = std::make_unique(static_cast(req.arg), request); @@ -339,7 +335,6 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer m_event.reset(); break; } - */ default: ERROR_LOG(IOS_SD, "Unknown SD command 0x%08x", req.command); From b29c8c1a63e8a26a8f59243f87aa6977cdb878d0 Mon Sep 17 00:00:00 2001 From: Tom Boshoven Date: Sat, 5 Aug 2017 18:51:24 +0200 Subject: [PATCH 5/6] Redid initialization logic. Looks like initialization is done automatically by IOS versions that support SDHC. --- Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp | 95 ++++++++++++++----------- Source/Core/Core/IOS/SDIO/SDIOSlot0.h | 5 ++ 2 files changed, 59 insertions(+), 41 deletions(-) diff --git a/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp b/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp index 2ecd8f108a..d0634dce70 100644 --- a/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp +++ b/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp @@ -25,7 +25,28 @@ namespace HLE { namespace Device { -SDIOSlot0::SDIOSlot0(Kernel& ios, const std::string& device_name) : Device(ios, device_name) +constexpr bool SupportsSDHC(u32 ios_version) +{ + switch (ios_version) + { + // Known versions to support SDHC + case 48: + case 56: + case 57: + case 58: + case 59: + case 60: + case 61: + case 70: + case 80: + return true; + default: + return false; + }; +} + +SDIOSlot0::SDIOSlot0(Kernel& ios, const std::string& device_name) + : Device(ios, device_name), m_sdhc_supported(SupportsSDHC(ios.GetVersion())) { } @@ -173,25 +194,8 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer { case GO_IDLE_STATE: INFO_LOG(IOS_SD, "GO_IDLE_STATE"); - if (m_card) - { - if (m_card.GetSize() > SDHC_BYTES) - { - // SDHC requires further initialization (SEND_IF_COND) - m_status |= CARD_SDHC; - } - else - { - // No further initialization required. - m_status |= CARD_INITIALIZED; - } - } - else - { - // Make sure we're not initialized - m_status &= ~CARD_INITIALIZED; - } - Memory::Write_U32(GetOCRegister(), _BufferOut); + // Response is R1 (idle state) + Memory::Write_U32(0x00, _BufferOut); break; case SEND_RELATIVE_ADDR: @@ -212,6 +216,7 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer // voltage and the check pattern that were set in the command argument. // This command is used to differentiate between protocol v1 and v2. m_protocol = SDProtocol::V2; + m_status |= CARD_INITIALIZED; Memory::Write_U32(req.arg, _BufferOut); break; @@ -250,14 +255,7 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer case ACMD_SENDOPCOND: // Sends host capacity support information (HCS) and asks the accessed card to send // its operating condition register (OCR) content - { - // Only leave idle state if the card is supported by the protocol - if (m_protocol == SDProtocol::V2 || !(m_status & CARD_SDHC)) - m_status |= CARD_INITIALIZED; - - u32 ocr = GetOCRegister(); - Memory::Write_U32(ocr, _BufferOut); - } + Memory::Write_U32(GetOCRegister(), _BufferOut); break; case READ_MULTIPLE_BLOCK: @@ -437,27 +435,42 @@ IPCCommandResult SDIOSlot0::SendCommand(const IOCtlRequest& request) IPCCommandResult SDIOSlot0::GetStatus(const IOCtlRequest& request) { - if (SConfig::GetInstance().m_WiiSDCard) - m_status |= CARD_INSERTED; - else - m_status = CARD_NOT_EXIST; + // Since IOS does the SD initialization itself, we just say we're always initialized. + if (m_card) + { + if (m_card.GetSize() < SDHC_BYTES) + { + // No further initialization required. + m_status |= CARD_INITIALIZED; + } + else + { + // Some IOS versions support SDHC. + // Others will work if they are manually initialized (SEND_IF_COND) + if (m_sdhc_supported) + { + m_status |= CARD_INITIALIZED; + } + m_status |= CARD_SDHC; + } + } + + // Evaluate whether a card is currently inserted (config value). + // Make sure we don't modify m_status so we don't lose track of whether the card is SDHC. + const u32 status = + SConfig::GetInstance().m_WiiSDCard ? (m_status | CARD_INSERTED) : CARD_NOT_EXIST; INFO_LOG(IOS_SD, "IOCTL_GETSTATUS. Replying that %s card is %s%s", - (m_status & CARD_SDHC) ? "SDHC" : "SD", - (m_status & CARD_INSERTED) ? "inserted" : "not present", - (m_status & CARD_INITIALIZED) ? " and initialized" : ""); + (status & CARD_SDHC) ? "SDHC" : "SD", + (status & CARD_INSERTED) ? "inserted" : "not present", + (status & CARD_INITIALIZED) ? " and initialized" : ""); - Memory::Write_U32(m_status, request.buffer_out); + Memory::Write_U32(status, request.buffer_out); return GetDefaultReply(IPC_SUCCESS); } IPCCommandResult SDIOSlot0::GetOCRegister(const IOCtlRequest& request) { - // Make sure we're not initialized if the card is not supported by the protocol - if (m_protocol != SDProtocol::V2 && (m_status & CARD_SDHC)) - { - m_status &= ~CARD_INITIALIZED; - } u32 ocr = GetOCRegister(); INFO_LOG(IOS_SD, "IOCTL_GETOCR. Replying with ocr %x", ocr); Memory::Write_U32(ocr, request.buffer_out); diff --git a/Source/Core/Core/IOS/SDIO/SDIOSlot0.h b/Source/Core/Core/IOS/SDIO/SDIOSlot0.h index c50ab50d54..a219c19673 100644 --- a/Source/Core/Core/IOS/SDIO/SDIOSlot0.h +++ b/Source/Core/Core/IOS/SDIO/SDIOSlot0.h @@ -141,6 +141,7 @@ private: s32 ExecuteCommand(const Request& request, u32 BufferIn, u32 BufferInSize, u32 BufferIn2, u32 BufferInSize2, u32 _BufferOut, u32 BufferOutSize); void OpenInternal(); + void InitStatus(); u32 GetOCRegister() const; @@ -155,6 +156,10 @@ private: u32 m_status = CARD_NOT_EXIST; SDProtocol m_protocol = SDProtocol::V1; + // Is SDHC supported by the IOS? + // Other IOS requires manual SDHC initialization + const bool m_sdhc_supported; + u32 m_block_length = 0; u32 m_bus_width = 0; From 10c615d7db3dca26d0237a890dfc99f585e698fe Mon Sep 17 00:00:00 2001 From: Tom Boshoven Date: Sat, 5 Aug 2017 19:55:08 +0200 Subject: [PATCH 6/6] Added proper SDHC initialization to protocol v2. --- Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp | 12 +++++++++--- Source/Core/Core/IOS/SDIO/SDIOSlot0.h | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp b/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp index d0634dce70..d75135d5b9 100644 --- a/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp +++ b/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp @@ -215,8 +215,7 @@ s32 SDIOSlot0::ExecuteCommand(const Request& request, u32 _BufferIn, u32 _Buffer // If the card can operate on the supplied voltage, the response echoes back the supply // voltage and the check pattern that were set in the command argument. // This command is used to differentiate between protocol v1 and v2. - m_protocol = SDProtocol::V2; - m_status |= CARD_INITIALIZED; + InitSDHC(); Memory::Write_U32(req.arg, _BufferOut); break; @@ -449,7 +448,8 @@ IPCCommandResult SDIOSlot0::GetStatus(const IOCtlRequest& request) // Others will work if they are manually initialized (SEND_IF_COND) if (m_sdhc_supported) { - m_status |= CARD_INITIALIZED; + // All of the initialization is done internally by IOS, so we get to skip some steps. + InitSDHC(); } m_status |= CARD_SDHC; } @@ -645,6 +645,12 @@ u64 SDIOSlot0::GetAddressFromRequest(u32 arg) const return address; } +void SDIOSlot0::InitSDHC() +{ + m_protocol = SDProtocol::V2; + m_status |= CARD_INITIALIZED; +} + } // namespace Device } // namespace HLE } // namespace IOS diff --git a/Source/Core/Core/IOS/SDIO/SDIOSlot0.h b/Source/Core/Core/IOS/SDIO/SDIOSlot0.h index a219c19673..6f0f0255c6 100644 --- a/Source/Core/Core/IOS/SDIO/SDIOSlot0.h +++ b/Source/Core/Core/IOS/SDIO/SDIOSlot0.h @@ -147,6 +147,7 @@ private: std::array GetCSDv1(); std::array GetCSDv2(); + void InitSDHC(); u64 GetAddressFromRequest(u32 arg) const;