mirror of
https://github.com/wiiu-env/libfat.git
synced 2024-11-22 18:09:17 +01:00
Added SCSD support. Fixed a few FAT errors.
This commit is contained in:
parent
9ad203bc6d
commit
8bf1f6e7fb
@ -87,9 +87,9 @@ IO_INTERFACE* ioInterfaces[] = {
|
|||||||
&_io_nmmc,
|
&_io_nmmc,
|
||||||
#endif
|
#endif
|
||||||
// Place Slot 2 (GBA Cart) interfaces here
|
// Place Slot 2 (GBA Cart) interfaces here
|
||||||
&_io_mpcf, &_io_m3cf, &_io_m3sd, &_io_sccf, &_io_fcsr
|
&_io_mpcf, &_io_m3cf, &_io_sccf, &_io_scsd, &_io_m3sd, &_io_fcsr
|
||||||
// Experimental Slot 2 interfaces
|
// Experimental Slot 2 interfaces
|
||||||
, &_io_mmcf, &_io_scsd, &_io_efa2
|
, &_io_mmcf, &_io_efa2
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -47,14 +47,14 @@
|
|||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Send / receive timeouts, to stop infinite wait loops
|
// Send / receive timeouts, to stop infinite wait loops
|
||||||
#define MAX_STARTUP_TRIES 100 // Arbitrary value, check if the card is ready 100 times before giving up
|
#define MAX_STARTUP_TRIES 10 // Arbitrary value, check if the card is ready 10 times before giving up
|
||||||
#define NUM_STARTUP_CLOCKS 100 // Number of empty (0xFF when sending) bytes to send/receive to/from the card
|
#define NUM_STARTUP_CLOCKS 100 // Number of empty (0xFF when sending) bytes to send/receive to/from the card
|
||||||
#define TRANSMIT_TIMEOUT 0x100 // Time to wait for the M3 to respond to transmit or receive requests
|
#define TRANSMIT_TIMEOUT 2000 // Time to wait for the M3 to respond to transmit or receive requests
|
||||||
#define RESPONSE_TIMEOUT 256 // Number of clocks sent to the SD card before giving up
|
#define RESPONSE_TIMEOUT 256 // Number of clocks sent to the SD card before giving up
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Variables required for tracking SD state
|
// Variables required for tracking SD state
|
||||||
static u32 relativeCardAddress = 0; // Preshifted Relative Card Address
|
static u32 _M3SD_relativeCardAddress = 0; // Preshifted Relative Card Address
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Internal M3 SD functions
|
// Internal M3 SD functions
|
||||||
@ -241,7 +241,7 @@ static bool _M3SD_initCard (void) {
|
|||||||
_M3SD_getClocks (NUM_STARTUP_CLOCKS);
|
_M3SD_getClocks (NUM_STARTUP_CLOCKS);
|
||||||
|
|
||||||
// Card is now reset, including it's address
|
// Card is now reset, including it's address
|
||||||
relativeCardAddress = 0;
|
_M3SD_relativeCardAddress = 0;
|
||||||
|
|
||||||
for (i = 0; i < MAX_STARTUP_TRIES ; i++) {
|
for (i = 0; i < MAX_STARTUP_TRIES ; i++) {
|
||||||
_M3SD_sendCommand (APP_CMD, 0);
|
_M3SD_sendCommand (APP_CMD, 0);
|
||||||
@ -265,18 +265,18 @@ static bool _M3SD_initCard (void) {
|
|||||||
// Get a new address
|
// Get a new address
|
||||||
_M3SD_sendCommand (SEND_RELATIVE_ADDR, 0);
|
_M3SD_sendCommand (SEND_RELATIVE_ADDR, 0);
|
||||||
_M3SD_getResponse_R6 (responseBuffer);
|
_M3SD_getResponse_R6 (responseBuffer);
|
||||||
relativeCardAddress = (responseBuffer[1] << 24) | (responseBuffer[2] << 16);
|
_M3SD_relativeCardAddress = (responseBuffer[1] << 24) | (responseBuffer[2] << 16);
|
||||||
|
|
||||||
// Some cards won't go to higher speeds unless they think you checked their capabilities
|
// Some cards won't go to higher speeds unless they think you checked their capabilities
|
||||||
_M3SD_sendCommand (SEND_CSD, relativeCardAddress);
|
_M3SD_sendCommand (SEND_CSD, _M3SD_relativeCardAddress);
|
||||||
_M3SD_getResponse_R2 (responseBuffer);
|
_M3SD_getResponse_R2 (responseBuffer);
|
||||||
|
|
||||||
// Only this card should respond to all future commands
|
// Only this card should respond to all future commands
|
||||||
_M3SD_sendCommand (SELECT_CARD, relativeCardAddress);
|
_M3SD_sendCommand (SELECT_CARD, _M3SD_relativeCardAddress);
|
||||||
_M3SD_getResponse_R1 (responseBuffer);
|
_M3SD_getResponse_R1 (responseBuffer);
|
||||||
|
|
||||||
// Set a 4 bit data bus
|
// Set a 4 bit data bus
|
||||||
_M3SD_sendCommand (APP_CMD, relativeCardAddress);
|
_M3SD_sendCommand (APP_CMD, _M3SD_relativeCardAddress);
|
||||||
_M3SD_getResponse_R1 (responseBuffer);
|
_M3SD_getResponse_R1 (responseBuffer);
|
||||||
|
|
||||||
_M3SD_sendCommand (SET_BUS_WIDTH, 2);
|
_M3SD_sendCommand (SET_BUS_WIDTH, 2);
|
||||||
@ -293,9 +293,8 @@ static bool _M3SD_initCard (void) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
_M3SD_sendCommand (SEND_STATUS, relativeCardAddress);
|
_M3SD_sendCommand (SEND_STATUS, _M3SD_relativeCardAddress);
|
||||||
} while ((!_M3SD_getResponse_R1 (responseBuffer)) && ((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
|
} while ((!_M3SD_getResponse_R1 (responseBuffer)) && ((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@
|
|||||||
#define REG_MMCF_LBA3 ((vu16*)0x080A0000) // 3rd byte of sector address
|
#define REG_MMCF_LBA3 ((vu16*)0x080A0000) // 3rd byte of sector address
|
||||||
#define REG_MMCF_LBA4 ((vu16*)0x080C0000) // last nibble of sector address | 0xE0
|
#define REG_MMCF_LBA4 ((vu16*)0x080C0000) // last nibble of sector address | 0xE0
|
||||||
|
|
||||||
#define REG_MMCF_DATA ((vu16*)0x09000000) // Pointer to buffer of CF data transered from card
|
#define REG_MMCF_DATA ((vu16*)0x08000000) // Pointer to buffer of CF data transered from card
|
||||||
|
|
||||||
static const CF_REGISTERS _MMCF_Registers = {
|
static const CF_REGISTERS _MMCF_Registers = {
|
||||||
REG_MMCF_DATA,
|
REG_MMCF_DATA,
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#include <nds/card.h>
|
#include <nds/card.h>
|
||||||
|
|
||||||
int spi_freq = 3;
|
int _NMMC_spi_freq = 3;
|
||||||
|
|
||||||
#define MK2_CONFIG_ZIP_RAM_CLOSE (1 << 5)
|
#define MK2_CONFIG_ZIP_RAM_CLOSE (1 << 5)
|
||||||
#define MK2_CONFIG_GAME_FLASH_CLOSE ((1 << 4) | (1 << 0))
|
#define MK2_CONFIG_GAME_FLASH_CLOSE ((1 << 4) | (1 << 0))
|
||||||
@ -61,13 +61,13 @@ static inline void _Neo_CloseSPI ( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void _Neo_MK2GameMode() {
|
static inline void _Neo_MK2GameMode() {
|
||||||
_Neo_OpenSPI(spi_freq); // Enable DS Card's SPI port
|
_Neo_OpenSPI(_NMMC_spi_freq); // Enable DS Card's SPI port
|
||||||
_Neo_SPI(0xF1); // Switch to game mode
|
_Neo_SPI(0xF1); // Switch to game mode
|
||||||
_Neo_CloseSPI(); // Disable DS Card's SPI port
|
_Neo_CloseSPI(); // Disable DS Card's SPI port
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _Neo_EnableEEPROM( bool enable ) {
|
static inline void _Neo_EnableEEPROM( bool enable ) {
|
||||||
_Neo_OpenSPI(spi_freq);
|
_Neo_OpenSPI(_NMMC_spi_freq);
|
||||||
if(enable) _Neo_SPI(0x06);
|
if(enable) _Neo_SPI(0x06);
|
||||||
else _Neo_SPI(0x0E);
|
else _Neo_SPI(0x0E);
|
||||||
_Neo_CloseSPI();
|
_Neo_CloseSPI();
|
||||||
@ -75,7 +75,7 @@ static inline void _Neo_EnableEEPROM( bool enable ) {
|
|||||||
|
|
||||||
static void _Neo_WriteMK2Config(u8 config) {
|
static void _Neo_WriteMK2Config(u8 config) {
|
||||||
_Neo_EnableEEPROM(true);
|
_Neo_EnableEEPROM(true);
|
||||||
_Neo_OpenSPI(spi_freq);
|
_Neo_OpenSPI(_NMMC_spi_freq);
|
||||||
_Neo_SPI(0xFA); // Send mem conf write command
|
_Neo_SPI(0xFA); // Send mem conf write command
|
||||||
_Neo_SPI(0x01); // Send high byte (0x01)
|
_Neo_SPI(0x01); // Send high byte (0x01)
|
||||||
_Neo_SPI(config); // Send low byte
|
_Neo_SPI(config); // Send low byte
|
||||||
@ -87,7 +87,7 @@ static u8 _Neo_ReadMK2Config(void)
|
|||||||
{
|
{
|
||||||
u8 config;
|
u8 config;
|
||||||
_Neo_EnableEEPROM(true);
|
_Neo_EnableEEPROM(true);
|
||||||
_Neo_OpenSPI(spi_freq);
|
_Neo_OpenSPI(_NMMC_spi_freq);
|
||||||
_Neo_SPI(0xf8); // Send mem conf read command
|
_Neo_SPI(0xf8); // Send mem conf read command
|
||||||
_Neo_SPI(0x01); // Send high byte
|
_Neo_SPI(0x01); // Send high byte
|
||||||
config = _Neo_SPI(0x00); // Get low byte
|
config = _Neo_SPI(0x00); // Get low byte
|
||||||
@ -118,7 +118,7 @@ static void _Neo_EnableMMC( bool enable )
|
|||||||
} else {
|
} else {
|
||||||
_Neo_SelectMMC (1);
|
_Neo_SelectMMC (1);
|
||||||
_Neo_SelectMMC (1);
|
_Neo_SelectMMC (1);
|
||||||
_Neo_OpenSPI (spi_freq);
|
_Neo_OpenSPI (_NMMC_spi_freq);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -246,7 +246,7 @@ bool _NMMC_startUp(void) {
|
|||||||
_Neo_SPI(0xFF);
|
_Neo_SPI(0xFF);
|
||||||
}
|
}
|
||||||
if ((transSpeed & 0xf0) >= 0x30) {
|
if ((transSpeed & 0xf0) >= 0x30) {
|
||||||
spi_freq = 0;
|
_NMMC_spi_freq = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_Neo_EnableMMC( false );
|
_Neo_EnableMMC( false );
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
2006-07-22 - Chishm
|
||||||
|
* First release of stable code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "io_scsd.h"
|
#include "io_scsd.h"
|
||||||
@ -58,15 +61,18 @@
|
|||||||
// Send / receive timeouts, to stop infinite wait loops
|
// Send / receive timeouts, to stop infinite wait loops
|
||||||
#define MAX_STARTUP_TRIES 100 // Arbitrary value, check if the card is ready 100 times before giving up
|
#define MAX_STARTUP_TRIES 100 // Arbitrary value, check if the card is ready 100 times before giving up
|
||||||
#define NUM_STARTUP_CLOCKS 100 // Number of empty (0xFF when sending) bytes to send/receive to/from the card
|
#define NUM_STARTUP_CLOCKS 100 // Number of empty (0xFF when sending) bytes to send/receive to/from the card
|
||||||
#define TRANSMIT_TIMEOUT 0x100 // Time to wait for the M3 to respond to transmit or receive requests
|
#define TRANSMIT_TIMEOUT 10000 // Time to wait for the SC to respond to transmit or receive requests
|
||||||
#define RESPONSE_TIMEOUT 256 // Number of clocks sent to the SD card before giving up
|
#define RESPONSE_TIMEOUT 256 // Number of clocks sent to the SD card before giving up
|
||||||
#define BUSY_WAIT_TIMEOUT 500000
|
#define BUSY_WAIT_TIMEOUT 500000
|
||||||
|
#define WRITE_TIMEOUT 10000 // Time to wait for the card to finish writing
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Variables required for tracking SD state
|
// Variables required for tracking SD state
|
||||||
static u32 relativeCardAddress = 0; // Preshifted Relative Card Address
|
static u32 _SCSD_relativeCardAddress = 0; // Preshifted Relative Card Address
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Internal M3 SD functions
|
// Internal SC SD functions
|
||||||
|
|
||||||
|
extern bool _SCSD_writeData_s (u8 *data, u16* crc);
|
||||||
|
|
||||||
static inline void _SCSD_unlock (void) {
|
static inline void _SCSD_unlock (void) {
|
||||||
_SC_changeMode (SC_MODE_MEDIA);
|
_SC_changeMode (SC_MODE_MEDIA);
|
||||||
@ -97,81 +103,57 @@ static bool _SCSD_sendCommand (u8 command, u32 argument) {
|
|||||||
|
|
||||||
tempDataPtr = databuff;
|
tempDataPtr = databuff;
|
||||||
|
|
||||||
do {
|
while (length--) {
|
||||||
dataByte = *tempDataPtr++;
|
dataByte = *tempDataPtr++;
|
||||||
for (curBit = 7; curBit >=0; curBit--){
|
for (curBit = 7; curBit >=0; curBit--){
|
||||||
REG_SCSD_CMD = dataByte;
|
REG_SCSD_CMD = dataByte;
|
||||||
dataByte = dataByte << 1;
|
dataByte = dataByte << 1;
|
||||||
}
|
}
|
||||||
} while (length--);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u8 _SCSD_getByte (void) {
|
|
||||||
// With every 16 bit read to REG_SCSD_CMD, read a single bit.
|
|
||||||
u32 res = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 1; i < 8; i++) {
|
|
||||||
res = (res << 1) | REG_SCSD_CMD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (u8)res;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the response from the SD card to a previous command.
|
// Returns the response from the SD card to a previous command.
|
||||||
static bool _SCSD_getResponse (u8* dest, u32 length) {
|
static bool _SCSD_getResponse (u8* dest, u32 length) {
|
||||||
u32 i;
|
u32 i;
|
||||||
u8 dataByte;
|
int dataByte;
|
||||||
int shiftAmount;
|
int numBits = length * 8;
|
||||||
|
|
||||||
// Wait for the card to be non-busy
|
// Wait for the card to be non-busy
|
||||||
for (i = 0; i < RESPONSE_TIMEOUT; i++) {
|
i = BUSY_WAIT_TIMEOUT;
|
||||||
dataByte = _SCSD_getByte();
|
while (((REG_SCSD_CMD & 0x01) != 0) && (--i));
|
||||||
if (dataByte != SD_CARD_BUSY) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dest == NULL) {
|
if (dest == NULL) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
// Still busy after the timeout has passed
|
// Still busy after the timeout has passed
|
||||||
if (dataByte == 0xff) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read response into buffer
|
// The first bit is always 0
|
||||||
for ( i = 0; i < length; i++) {
|
dataByte = 0;
|
||||||
dest[i] = dataByte;
|
numBits--;
|
||||||
dataByte = _SCSD_getByte();
|
// Read the remaining bits in the response.
|
||||||
|
// It's always most significant bit first
|
||||||
|
while (numBits--) {
|
||||||
|
dataByte = (dataByte << 1) | (REG_SCSD_CMD & 0x01);
|
||||||
|
if ((numBits & 0x7) == 0) {
|
||||||
|
// It's read a whole byte, so store it
|
||||||
|
*dest++ = (u8)dataByte;
|
||||||
|
dataByte = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// dataByte will contain the last piece of the response
|
|
||||||
|
|
||||||
// Send 16 more clocks, 8 more than the delay required between a response and the next command
|
// Send 16 more clocks, 8 more than the delay required between a response and the next command
|
||||||
i = _SCSD_getByte();
|
for (i = 0; i < 16; i++) {
|
||||||
i = _SCSD_getByte();
|
dataByte = REG_SCSD_CMD;
|
||||||
|
|
||||||
// Shift response so that the bytes are correctly aligned
|
|
||||||
// The register may not contain properly aligned data
|
|
||||||
for (shiftAmount = 0; ((dest[0] << shiftAmount) & 0x80) != 0x00; shiftAmount++) {
|
|
||||||
if (shiftAmount >= 7) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < length - 1; i++) {
|
|
||||||
dest[i] = (dest[i] << shiftAmount) | (dest[i+1] >> (8-shiftAmount));
|
|
||||||
}
|
|
||||||
// Get the last piece of the response from dataByte
|
|
||||||
dest[i] = (dest[i] << shiftAmount) | (dataByte >> (8-shiftAmount));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool _SCSD_getResponse_R1 (u8* dest) {
|
static inline bool _SCSD_getResponse_R1 (u8* dest) {
|
||||||
return _SCSD_getResponse (dest, 6);
|
return _SCSD_getResponse (dest, 6);
|
||||||
}
|
}
|
||||||
@ -200,23 +182,21 @@ static void _SCSD_sendClocks (u32 numClocks) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool _SCSD_initCard (void) {
|
static bool _SCSD_initCard (void) {
|
||||||
//iprintf ("init card\n");
|
|
||||||
int i;
|
int i;
|
||||||
u8 responseBuffer[17]; // sizeof 17 to hold the maximum response size possible
|
u8 responseBuffer[17] = {0}; // sizeof 17 to hold the maximum response size possible
|
||||||
|
|
||||||
// Give the card time to stabilise
|
// Give the card time to stabilise
|
||||||
_SCSD_sendClocks (NUM_STARTUP_CLOCKS);
|
_SCSD_sendClocks (NUM_STARTUP_CLOCKS);
|
||||||
|
|
||||||
// Reset the card
|
// Reset the card
|
||||||
if (!_SCSD_sendCommand (GO_IDLE_STATE, 0)) {
|
if (!_SCSD_sendCommand (GO_IDLE_STATE, 0)) {
|
||||||
//iprintf ("can't idle\n");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_SCSD_sendClocks (NUM_STARTUP_CLOCKS);
|
_SCSD_sendClocks (NUM_STARTUP_CLOCKS);
|
||||||
|
|
||||||
// Card is now reset, including it's address
|
// Card is now reset, including it's address
|
||||||
relativeCardAddress = 0;
|
_SCSD_relativeCardAddress = 0;
|
||||||
|
|
||||||
for (i = 0; i < MAX_STARTUP_TRIES ; i++) {
|
for (i = 0; i < MAX_STARTUP_TRIES ; i++) {
|
||||||
_SCSD_sendCommand (APP_CMD, 0);
|
_SCSD_sendCommand (APP_CMD, 0);
|
||||||
@ -230,7 +210,6 @@ static bool _SCSD_initCard (void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (i >= MAX_STARTUP_TRIES) {
|
if (i >= MAX_STARTUP_TRIES) {
|
||||||
//iprintf ("timeout on OP_COND\n");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,19 +220,18 @@ static bool _SCSD_initCard (void) {
|
|||||||
// Get a new address
|
// Get a new address
|
||||||
_SCSD_sendCommand (SEND_RELATIVE_ADDR, 0);
|
_SCSD_sendCommand (SEND_RELATIVE_ADDR, 0);
|
||||||
_SCSD_getResponse_R6 (responseBuffer);
|
_SCSD_getResponse_R6 (responseBuffer);
|
||||||
relativeCardAddress = (responseBuffer[1] << 24) | (responseBuffer[2] << 16);
|
_SCSD_relativeCardAddress = (responseBuffer[1] << 24) | (responseBuffer[2] << 16);
|
||||||
//iprintf ("Relative Address: %08X\n", relativeCardAddress);
|
|
||||||
|
|
||||||
// Some cards won't go to higher speeds unless they think you checked their capabilities
|
// Some cards won't go to higher speeds unless they think you checked their capabilities
|
||||||
_SCSD_sendCommand (SEND_CSD, relativeCardAddress);
|
_SCSD_sendCommand (SEND_CSD, _SCSD_relativeCardAddress);
|
||||||
_SCSD_getResponse_R2 (responseBuffer);
|
_SCSD_getResponse_R2 (responseBuffer);
|
||||||
|
|
||||||
// Only this card should respond to all future commands
|
// Only this card should respond to all future commands
|
||||||
_SCSD_sendCommand (SELECT_CARD, relativeCardAddress);
|
_SCSD_sendCommand (SELECT_CARD, _SCSD_relativeCardAddress);
|
||||||
_SCSD_getResponse_R1 (responseBuffer);
|
_SCSD_getResponse_R1 (responseBuffer);
|
||||||
|
|
||||||
// Set a 4 bit data bus
|
// Set a 4 bit data bus
|
||||||
_SCSD_sendCommand (APP_CMD, relativeCardAddress);
|
_SCSD_sendCommand (APP_CMD, _SCSD_relativeCardAddress);
|
||||||
_SCSD_getResponse_R1 (responseBuffer);
|
_SCSD_getResponse_R1 (responseBuffer);
|
||||||
|
|
||||||
_SCSD_sendCommand (SET_BUS_WIDTH, 2);
|
_SCSD_sendCommand (SET_BUS_WIDTH, 2);
|
||||||
@ -267,11 +245,10 @@ static bool _SCSD_initCard (void) {
|
|||||||
i = 0;
|
i = 0;
|
||||||
do {
|
do {
|
||||||
if (i >= RESPONSE_TIMEOUT) {
|
if (i >= RESPONSE_TIMEOUT) {
|
||||||
//iprintf ("timeout on SEND_STATUS\n");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
_SCSD_sendCommand (SEND_STATUS, relativeCardAddress);
|
_SCSD_sendCommand (SEND_STATUS, _SCSD_relativeCardAddress);
|
||||||
} while ((!_SCSD_getResponse_R1 (responseBuffer)) && ((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
|
} while ((!_SCSD_getResponse_R1 (responseBuffer)) && ((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -280,7 +257,7 @@ static bool _SCSD_initCard (void) {
|
|||||||
static bool _SCSD_readData (void* buffer) {
|
static bool _SCSD_readData (void* buffer) {
|
||||||
u8* buff_u8 = (u8*)buffer;
|
u8* buff_u8 = (u8*)buffer;
|
||||||
u16* buff = (u16*)buffer;
|
u16* buff = (u16*)buffer;
|
||||||
u32 temp;
|
volatile register u32 temp;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
i = BUSY_WAIT_TIMEOUT;
|
i = BUSY_WAIT_TIMEOUT;
|
||||||
@ -291,18 +268,18 @@ static bool _SCSD_readData (void* buffer) {
|
|||||||
|
|
||||||
i=256;
|
i=256;
|
||||||
if ((u32)buff_u8 & 0x01) {
|
if ((u32)buff_u8 & 0x01) {
|
||||||
while(i--)
|
while(i--) {
|
||||||
{
|
|
||||||
temp = REG_SCSD_DATAREAD_32;
|
temp = REG_SCSD_DATAREAD_32;
|
||||||
temp = REG_SCSD_DATAREAD_32 >> 16;
|
temp = REG_SCSD_DATAREAD_32 >> 16;
|
||||||
*buff_u8++ = (u8)temp;
|
*buff_u8++ = (u8)temp;
|
||||||
*buff_u8++ = (u8)(temp >> 8);
|
*buff_u8++ = (u8)(temp >> 8);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while(i--)
|
while(i--) {
|
||||||
temp = REG_SCSD_DATAREAD_32;
|
temp = REG_SCSD_DATAREAD_32;
|
||||||
temp = REG_SCSD_DATAREAD_32 >> 16;
|
temp = REG_SCSD_DATAREAD_32 >> 16;
|
||||||
*buff++ = (u16)temp;
|
*buff++ = temp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -315,52 +292,6 @@ static bool _SCSD_readData (void* buffer) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _SCSD_writeData (u8* data, u8* crc) {
|
|
||||||
int pos;
|
|
||||||
u16 dataHWord;
|
|
||||||
u16 temp;
|
|
||||||
|
|
||||||
while ((REG_SCSD_DATAREAD & SCSD_STS_BUSY) == 0);
|
|
||||||
|
|
||||||
temp = REG_SCSD_DATAREAD;
|
|
||||||
|
|
||||||
REG_SCSD_DATAWRITE = 0; // start bit;
|
|
||||||
|
|
||||||
pos = BYTES_PER_READ / 2;
|
|
||||||
while (pos--) {
|
|
||||||
dataHWord = data[0] | (data[1] << 8);
|
|
||||||
data+=2;
|
|
||||||
|
|
||||||
REG_SCSD_DATAWRITE = dataHWord;
|
|
||||||
REG_SCSD_DATAWRITE = dataHWord << 4;
|
|
||||||
REG_SCSD_DATAWRITE = dataHWord << 8;
|
|
||||||
REG_SCSD_DATAWRITE = dataHWord << 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (crc != 0) {
|
|
||||||
pos = 4;
|
|
||||||
while (pos--) {
|
|
||||||
dataHWord = *crc++;
|
|
||||||
|
|
||||||
REG_SCSD_DATAWRITE = dataHWord;
|
|
||||||
REG_SCSD_DATAWRITE = dataHWord << 4;
|
|
||||||
REG_SCSD_DATAWRITE = dataHWord << 8;
|
|
||||||
REG_SCSD_DATAWRITE = dataHWord << 12;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
REG_SCSD_DATAWRITE = 0xff; // end bit
|
|
||||||
|
|
||||||
while ((REG_SCSD_DATAREAD & SCSD_STS_BUSY) == 0);
|
|
||||||
|
|
||||||
temp = REG_SCSD_DATAREAD;
|
|
||||||
temp = REG_SCSD_DATAREAD;
|
|
||||||
temp = REG_SCSD_DATAREAD;
|
|
||||||
temp = REG_SCSD_DATAREAD;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Functions needed for the external interface
|
// Functions needed for the external interface
|
||||||
|
|
||||||
@ -423,13 +354,16 @@ bool _SCSD_readSectors (u32 sector, u32 numSectors, void* buffer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool _SCSD_writeSectors (u32 sector, u32 numSectors, const void* buffer) {
|
bool _SCSD_writeSectors (u32 sector, u32 numSectors, const void* buffer) {
|
||||||
u16 crcBuff[4];
|
u16 crc[4]; // One per data line
|
||||||
u8* crc = (u8*)crcBuff; // Force crcBuff to be halfword aligned
|
|
||||||
u8 responseBuffer[6];
|
u8 responseBuffer[6];
|
||||||
u32 offset = sector * BYTES_PER_READ;
|
u32 offset = sector * BYTES_PER_READ;
|
||||||
u8* data = (u8*) buffer;
|
u8* data = (u8*) buffer;
|
||||||
|
int i;
|
||||||
|
|
||||||
while (numSectors--) {
|
while (numSectors--) {
|
||||||
|
// Calculate the CRC16
|
||||||
|
_SD_CRC16 ( data, BYTES_PER_READ, (u8*)crc);
|
||||||
|
|
||||||
// Send write command and get a response
|
// Send write command and get a response
|
||||||
_SCSD_sendCommand (WRITE_BLOCK, offset);
|
_SCSD_sendCommand (WRITE_BLOCK, offset);
|
||||||
if (!_SCSD_getResponse_R1 (responseBuffer)) {
|
if (!_SCSD_getResponse_R1 (responseBuffer)) {
|
||||||
@ -437,8 +371,7 @@ bool _SCSD_writeSectors (u32 sector, u32 numSectors, const void* buffer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send the data and CRC
|
// Send the data and CRC
|
||||||
_SD_CRC16 ( data, BYTES_PER_READ, crc);
|
if (! _SCSD_writeData_s (data, crc)) {
|
||||||
if (! _SCSD_writeData( data, crc)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -447,10 +380,21 @@ bool _SCSD_writeSectors (u32 sector, u32 numSectors, const void* buffer) {
|
|||||||
|
|
||||||
offset += BYTES_PER_READ;
|
offset += BYTES_PER_READ;
|
||||||
data += BYTES_PER_READ;
|
data += BYTES_PER_READ;
|
||||||
|
|
||||||
|
// Wait until card is finished programming
|
||||||
|
i = WRITE_TIMEOUT;
|
||||||
|
responseBuffer[3] = 0;
|
||||||
|
do {
|
||||||
|
_SCSD_sendCommand (SEND_STATUS, _SCSD_relativeCardAddress);
|
||||||
|
_SCSD_getResponse_R1 (responseBuffer);
|
||||||
|
i--;
|
||||||
|
if (i <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} while (((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _SCSD_clearStatus (void) {
|
bool _SCSD_clearStatus (void) {
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
|
|
||||||
2006-07-11 - Chishm
|
2006-07-11 - Chishm
|
||||||
* Original release
|
* Original release
|
||||||
|
|
||||||
|
2006-07-22 - Chishm
|
||||||
|
* First release of stable code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IO_SCSD_H
|
#ifndef IO_SCSD_H
|
||||||
|
128
source/disc_io/io_scsd_s.s
Normal file
128
source/disc_io/io_scsd_s.s
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||||
|
@ io_scsd_s.s
|
||||||
|
@
|
||||||
|
@ Hardware Routines for reading a Secure Digital card
|
||||||
|
@ using the SC SD
|
||||||
|
@
|
||||||
|
@ Based on code supplied by Romman
|
||||||
|
@
|
||||||
|
@ Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
@
|
||||||
|
@ Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
@ are permitted provided that the following conditions are met:
|
||||||
|
@
|
||||||
|
@ 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
@ this list of conditions and the following disclaimer.
|
||||||
|
@ 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
@ this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
@ other materials provided with the distribution.
|
||||||
|
@ 3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
@ from this software without specific prior written permission.
|
||||||
|
@
|
||||||
|
@ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
@ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
@ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
@ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
@
|
||||||
|
@ 2006-07-22 - Chishm
|
||||||
|
@ * First release of stable code
|
||||||
|
@
|
||||||
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
.arm
|
||||||
|
|
||||||
|
.equ REG_SCSD_DATAWRITE, 0x09000000
|
||||||
|
.equ BYTES_PER_READ, 0x200
|
||||||
|
.equ SCSD_STS_BUSY, 0x100
|
||||||
|
.equ BUSY_WAIT_TIMEOUT, 0x10000
|
||||||
|
.equ FALSE, 0
|
||||||
|
.equ TRUE, 1
|
||||||
|
|
||||||
|
@ bool _SCSD_writeData_s (u8 *data, u16* crc)
|
||||||
|
|
||||||
|
.global _SCSD_writeData_s
|
||||||
|
|
||||||
|
_SCSD_writeData_s:
|
||||||
|
stmfd r13!, {r4-r5}
|
||||||
|
mov r5, #BYTES_PER_READ
|
||||||
|
mov r2, #REG_SCSD_DATAWRITE
|
||||||
|
|
||||||
|
@ Wait for a free data buffer on the SD card
|
||||||
|
mov r4, #BUSY_WAIT_TIMEOUT
|
||||||
|
_SCSD_writeData_busy_wait:
|
||||||
|
@ Test for timeout
|
||||||
|
subs r4, r4, #1
|
||||||
|
moveq r0, #FALSE @ return false on failure
|
||||||
|
beq _SCSD_writeData_return
|
||||||
|
@ Check the busy bit of the status register
|
||||||
|
ldrh r3, [r2]
|
||||||
|
tst r3, #SCSD_STS_BUSY
|
||||||
|
beq _SCSD_writeData_busy_wait
|
||||||
|
|
||||||
|
ldrh r3, [r2] @ extra clock
|
||||||
|
|
||||||
|
mov r3, #0 @ start bit
|
||||||
|
strh r3,[r2]
|
||||||
|
|
||||||
|
@ Check if the data buffer is aligned on a halfword boundary
|
||||||
|
tst r0, #1
|
||||||
|
beq _SCSD_writeData_data_loop
|
||||||
|
|
||||||
|
@ Used when the source data is unaligned
|
||||||
|
_SCSD_writeData_data_loop_unaligned:
|
||||||
|
ldrb r3, [r0], #1
|
||||||
|
ldrb r4, [r0], #1
|
||||||
|
orr r3, r3, r4, lsl #8
|
||||||
|
stmia r2, {r3-r4}
|
||||||
|
subs r5, r5, #2
|
||||||
|
bne _SCSD_writeData_data_loop_unaligned
|
||||||
|
b _SCSD_writeData_crc
|
||||||
|
|
||||||
|
@ Write the data to the card
|
||||||
|
@ 4 halfwords are transmitted to the Supercard at once, for timing purposes
|
||||||
|
@ Only the first halfword needs to contain data
|
||||||
|
_SCSD_writeData_data_loop:
|
||||||
|
ldrh r3, [r0], #2
|
||||||
|
stmia r2, {r3-r4}
|
||||||
|
subs r5, r5, #2
|
||||||
|
bne _SCSD_writeData_data_loop
|
||||||
|
|
||||||
|
@ Send the data CRC
|
||||||
|
_SCSD_writeData_crc:
|
||||||
|
cmp r1, #0
|
||||||
|
movne r0, r1
|
||||||
|
movne r1, #0
|
||||||
|
movne r5, #8
|
||||||
|
bne _SCSD_writeData_data_loop
|
||||||
|
|
||||||
|
mov r3, #0xff @ end bit
|
||||||
|
strh r3, [r2]
|
||||||
|
|
||||||
|
@ Wait for the SD card to signal that it is finished recieving
|
||||||
|
mov r4, #BUSY_WAIT_TIMEOUT
|
||||||
|
_SCSD_writeData_finished_wait:
|
||||||
|
@ Test for timeout
|
||||||
|
subs r4, r4, #1
|
||||||
|
moveq r0, #FALSE @ return false on failure
|
||||||
|
beq _SCSD_writeData_return
|
||||||
|
@ Check the busy bit of the status register
|
||||||
|
ldrh r3, [r2]
|
||||||
|
tst r3, #0x100
|
||||||
|
bne _SCSD_writeData_finished_wait
|
||||||
|
|
||||||
|
@ Send 8 more clocks, as required by the SD card
|
||||||
|
ldmia r2, {r3-r4}
|
||||||
|
|
||||||
|
@ return true for success
|
||||||
|
mov r0, #TRUE
|
||||||
|
|
||||||
|
_SCSD_writeData_return:
|
||||||
|
ldmfd r13!,{r4-r5}
|
||||||
|
bx r14
|
||||||
|
|
@ -52,6 +52,7 @@
|
|||||||
#define READ_SINGLE_BLOCK 17
|
#define READ_SINGLE_BLOCK 17
|
||||||
#define READ_MULTIPLE_BLOCK 18
|
#define READ_MULTIPLE_BLOCK 18
|
||||||
#define WRITE_BLOCK 24
|
#define WRITE_BLOCK 24
|
||||||
|
#define WRITE_MULTIPLE_BLOCK 25
|
||||||
#define APP_CMD 55
|
#define APP_CMD 55
|
||||||
|
|
||||||
/* SD App commands */
|
/* SD App commands */
|
||||||
|
@ -28,6 +28,9 @@
|
|||||||
|
|
||||||
2006-07-11 - Chishm
|
2006-07-11 - Chishm
|
||||||
* Original release
|
* Original release
|
||||||
|
|
||||||
|
2006-07-11 - Chishm
|
||||||
|
* Made several fixes related to free clusters, thanks to Loopy
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -202,6 +205,7 @@ u32 _FAT_fat_linkFreeCluster(PARTITION* partition, u32 cluster) {
|
|||||||
u32 firstFree;
|
u32 firstFree;
|
||||||
u32 curLink;
|
u32 curLink;
|
||||||
u32 lastCluster;
|
u32 lastCluster;
|
||||||
|
bool loopedAroundFAT = false;
|
||||||
|
|
||||||
lastCluster = partition->fat.lastCluster;
|
lastCluster = partition->fat.lastCluster;
|
||||||
|
|
||||||
@ -211,7 +215,7 @@ u32 _FAT_fat_linkFreeCluster(PARTITION* partition, u32 cluster) {
|
|||||||
|
|
||||||
// Check if the cluster already has a link, and return it if so
|
// Check if the cluster already has a link, and return it if so
|
||||||
curLink = _FAT_fat_nextCluster(partition, cluster);
|
curLink = _FAT_fat_nextCluster(partition, cluster);
|
||||||
if ((curLink >= CLUSTER_FIRST) && (curLink < lastCluster)) {
|
if ((curLink >= CLUSTER_FIRST) && (curLink <= lastCluster)) {
|
||||||
return curLink; // Return the current link - don't allocate a new one
|
return curLink; // Return the current link - don't allocate a new one
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,13 +227,20 @@ u32 _FAT_fat_linkFreeCluster(PARTITION* partition, u32 cluster) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Search until a free cluster is found
|
// Search until a free cluster is found
|
||||||
while ((_FAT_fat_nextCluster(partition, firstFree) != CLUSTER_FREE) && (firstFree <= lastCluster)) {
|
while (_FAT_fat_nextCluster(partition, firstFree) != CLUSTER_FREE) {
|
||||||
firstFree++;
|
firstFree++;
|
||||||
}
|
|
||||||
if (firstFree > lastCluster) {
|
if (firstFree > lastCluster) {
|
||||||
|
if (loopedAroundFAT) {
|
||||||
// If couldn't get a free cluster then return, saying this fact
|
// If couldn't get a free cluster then return, saying this fact
|
||||||
partition->fat.firstFree = firstFree;
|
partition->fat.firstFree = firstFree;
|
||||||
return CLUSTER_FREE;
|
return CLUSTER_FREE;
|
||||||
|
} else {
|
||||||
|
// Try looping back to the beginning of the FAT
|
||||||
|
// This was suggested by loopy
|
||||||
|
firstFree = CLUSTER_FIRST;
|
||||||
|
loopedAroundFAT = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
partition->fat.firstFree = firstFree;
|
partition->fat.firstFree = firstFree;
|
||||||
|
|
||||||
@ -254,6 +265,11 @@ bool _FAT_fat_clearLinks (PARTITION* partition, u32 cluster) {
|
|||||||
if ((cluster < 0x0002) || (cluster > partition->fat.lastCluster))
|
if ((cluster < 0x0002) || (cluster > partition->fat.lastCluster))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// If this clears up more space in the FAT before the current free pointer, move it backwards
|
||||||
|
if (cluster < partition->fat.firstFree) {
|
||||||
|
partition->fat.firstFree = cluster;
|
||||||
|
}
|
||||||
|
|
||||||
while ((cluster != CLUSTER_EOF) && (cluster != CLUSTER_FREE)) {
|
while ((cluster != CLUSTER_EOF) && (cluster != CLUSTER_FREE)) {
|
||||||
// Store next cluster before erasing the link
|
// Store next cluster before erasing the link
|
||||||
nextCluster = _FAT_fat_nextCluster (partition, cluster);
|
nextCluster = _FAT_fat_nextCluster (partition, cluster);
|
||||||
|
@ -112,7 +112,7 @@ static PARTITION* _FAT_partition_constructor ( IO_INTERFACE* disc, u32 cacheSize
|
|||||||
PARTITION* partition;
|
PARTITION* partition;
|
||||||
int i;
|
int i;
|
||||||
u32 bootSector;
|
u32 bootSector;
|
||||||
u8 sectorBuffer[BYTES_PER_READ];
|
u8 sectorBuffer[BYTES_PER_READ] = {0};
|
||||||
|
|
||||||
// Read first sector of disc
|
// Read first sector of disc
|
||||||
if ( !_FAT_disc_readSectors (disc, 0, 1, sectorBuffer)) {
|
if ( !_FAT_disc_readSectors (disc, 0, 1, sectorBuffer)) {
|
||||||
@ -156,7 +156,7 @@ static PARTITION* _FAT_partition_constructor ( IO_INTERFACE* disc, u32 cacheSize
|
|||||||
|
|
||||||
partition = (PARTITION*) _FAT_mem_allocate (sizeof(PARTITION));
|
partition = (PARTITION*) _FAT_mem_allocate (sizeof(PARTITION));
|
||||||
if (partition == NULL) {
|
if (partition == NULL) {
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set partition's disc interface
|
// Set partition's disc interface
|
||||||
|
Loading…
Reference in New Issue
Block a user