mirror of
https://github.com/wiiu-env/libfat.git
synced 2024-11-22 09:59:18 +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,
|
||||
#endif
|
||||
// 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
|
||||
, &_io_mmcf, &_io_scsd, &_io_efa2
|
||||
, &_io_mmcf, &_io_efa2
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -47,14 +47,14 @@
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// 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 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
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// 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
|
||||
@ -241,7 +241,7 @@ static bool _M3SD_initCard (void) {
|
||||
_M3SD_getClocks (NUM_STARTUP_CLOCKS);
|
||||
|
||||
// Card is now reset, including it's address
|
||||
relativeCardAddress = 0;
|
||||
_M3SD_relativeCardAddress = 0;
|
||||
|
||||
for (i = 0; i < MAX_STARTUP_TRIES ; i++) {
|
||||
_M3SD_sendCommand (APP_CMD, 0);
|
||||
@ -265,18 +265,18 @@ static bool _M3SD_initCard (void) {
|
||||
// Get a new address
|
||||
_M3SD_sendCommand (SEND_RELATIVE_ADDR, 0);
|
||||
_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
|
||||
_M3SD_sendCommand (SEND_CSD, relativeCardAddress);
|
||||
_M3SD_sendCommand (SEND_CSD, _M3SD_relativeCardAddress);
|
||||
_M3SD_getResponse_R2 (responseBuffer);
|
||||
|
||||
// Only this card should respond to all future commands
|
||||
_M3SD_sendCommand (SELECT_CARD, relativeCardAddress);
|
||||
_M3SD_sendCommand (SELECT_CARD, _M3SD_relativeCardAddress);
|
||||
_M3SD_getResponse_R1 (responseBuffer);
|
||||
|
||||
// Set a 4 bit data bus
|
||||
_M3SD_sendCommand (APP_CMD, relativeCardAddress);
|
||||
_M3SD_sendCommand (APP_CMD, _M3SD_relativeCardAddress);
|
||||
_M3SD_getResponse_R1 (responseBuffer);
|
||||
|
||||
_M3SD_sendCommand (SET_BUS_WIDTH, 2);
|
||||
@ -293,9 +293,8 @@ static bool _M3SD_initCard (void) {
|
||||
return false;
|
||||
}
|
||||
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)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@
|
||||
#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_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 = {
|
||||
REG_MMCF_DATA,
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
#include <nds/card.h>
|
||||
|
||||
int spi_freq = 3;
|
||||
int _NMMC_spi_freq = 3;
|
||||
|
||||
#define MK2_CONFIG_ZIP_RAM_CLOSE (1 << 5)
|
||||
#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() {
|
||||
_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_CloseSPI(); // Disable DS Card's SPI port
|
||||
}
|
||||
|
||||
static inline void _Neo_EnableEEPROM( bool enable ) {
|
||||
_Neo_OpenSPI(spi_freq);
|
||||
_Neo_OpenSPI(_NMMC_spi_freq);
|
||||
if(enable) _Neo_SPI(0x06);
|
||||
else _Neo_SPI(0x0E);
|
||||
_Neo_CloseSPI();
|
||||
@ -75,7 +75,7 @@ static inline void _Neo_EnableEEPROM( bool enable ) {
|
||||
|
||||
static void _Neo_WriteMK2Config(u8 config) {
|
||||
_Neo_EnableEEPROM(true);
|
||||
_Neo_OpenSPI(spi_freq);
|
||||
_Neo_OpenSPI(_NMMC_spi_freq);
|
||||
_Neo_SPI(0xFA); // Send mem conf write command
|
||||
_Neo_SPI(0x01); // Send high byte (0x01)
|
||||
_Neo_SPI(config); // Send low byte
|
||||
@ -87,7 +87,7 @@ static u8 _Neo_ReadMK2Config(void)
|
||||
{
|
||||
u8 config;
|
||||
_Neo_EnableEEPROM(true);
|
||||
_Neo_OpenSPI(spi_freq);
|
||||
_Neo_OpenSPI(_NMMC_spi_freq);
|
||||
_Neo_SPI(0xf8); // Send mem conf read command
|
||||
_Neo_SPI(0x01); // Send high byte
|
||||
config = _Neo_SPI(0x00); // Get low byte
|
||||
@ -118,7 +118,7 @@ static void _Neo_EnableMMC( bool enable )
|
||||
} else {
|
||||
_Neo_SelectMMC (1);
|
||||
_Neo_SelectMMC (1);
|
||||
_Neo_OpenSPI (spi_freq);
|
||||
_Neo_OpenSPI (_NMMC_spi_freq);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -246,7 +246,7 @@ bool _NMMC_startUp(void) {
|
||||
_Neo_SPI(0xFF);
|
||||
}
|
||||
if ((transSpeed & 0xf0) >= 0x30) {
|
||||
spi_freq = 0;
|
||||
_NMMC_spi_freq = 0;
|
||||
}
|
||||
|
||||
_Neo_EnableMMC( false );
|
||||
|
@ -29,6 +29,9 @@
|
||||
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
|
||||
*/
|
||||
|
||||
#include "io_scsd.h"
|
||||
@ -58,15 +61,18 @@
|
||||
// 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 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 BUSY_WAIT_TIMEOUT 500000
|
||||
#define WRITE_TIMEOUT 10000 // Time to wait for the card to finish writing
|
||||
//---------------------------------------------------------------
|
||||
// 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) {
|
||||
_SC_changeMode (SC_MODE_MEDIA);
|
||||
@ -97,81 +103,57 @@ static bool _SCSD_sendCommand (u8 command, u32 argument) {
|
||||
|
||||
tempDataPtr = databuff;
|
||||
|
||||
do {
|
||||
while (length--) {
|
||||
dataByte = *tempDataPtr++;
|
||||
for (curBit = 7; curBit >=0; curBit--){
|
||||
REG_SCSD_CMD = dataByte;
|
||||
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.
|
||||
static bool _SCSD_getResponse (u8* dest, u32 length) {
|
||||
u32 i;
|
||||
u8 dataByte;
|
||||
int shiftAmount;
|
||||
int dataByte;
|
||||
int numBits = length * 8;
|
||||
|
||||
// Wait for the card to be non-busy
|
||||
for (i = 0; i < RESPONSE_TIMEOUT; i++) {
|
||||
dataByte = _SCSD_getByte();
|
||||
if (dataByte != SD_CARD_BUSY) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i = BUSY_WAIT_TIMEOUT;
|
||||
while (((REG_SCSD_CMD & 0x01) != 0) && (--i));
|
||||
if (dest == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Still busy after the timeout has passed
|
||||
if (dataByte == 0xff) {
|
||||
if (i == 0) {
|
||||
// Still busy after the timeout has passed
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read response into buffer
|
||||
for ( i = 0; i < length; i++) {
|
||||
dest[i] = dataByte;
|
||||
dataByte = _SCSD_getByte();
|
||||
}
|
||||
// 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
|
||||
i = _SCSD_getByte();
|
||||
i = _SCSD_getByte();
|
||||
|
||||
// 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;
|
||||
// The first bit is always 0
|
||||
dataByte = 0;
|
||||
numBits--;
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < length - 1; i++) {
|
||||
dest[i] = (dest[i] << shiftAmount) | (dest[i+1] >> (8-shiftAmount));
|
||||
// Send 16 more clocks, 8 more than the delay required between a response and the next command
|
||||
for (i = 0; i < 16; i++) {
|
||||
dataByte = REG_SCSD_CMD;
|
||||
}
|
||||
// Get the last piece of the response from dataByte
|
||||
dest[i] = (dest[i] << shiftAmount) | (dataByte >> (8-shiftAmount));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static inline bool _SCSD_getResponse_R1 (u8* dest) {
|
||||
return _SCSD_getResponse (dest, 6);
|
||||
}
|
||||
@ -200,23 +182,21 @@ static void _SCSD_sendClocks (u32 numClocks) {
|
||||
}
|
||||
|
||||
static bool _SCSD_initCard (void) {
|
||||
//iprintf ("init card\n");
|
||||
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
|
||||
_SCSD_sendClocks (NUM_STARTUP_CLOCKS);
|
||||
|
||||
// Reset the card
|
||||
if (!_SCSD_sendCommand (GO_IDLE_STATE, 0)) {
|
||||
//iprintf ("can't idle\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
_SCSD_sendClocks (NUM_STARTUP_CLOCKS);
|
||||
|
||||
// Card is now reset, including it's address
|
||||
relativeCardAddress = 0;
|
||||
_SCSD_relativeCardAddress = 0;
|
||||
|
||||
for (i = 0; i < MAX_STARTUP_TRIES ; i++) {
|
||||
_SCSD_sendCommand (APP_CMD, 0);
|
||||
@ -230,7 +210,6 @@ static bool _SCSD_initCard (void) {
|
||||
}
|
||||
|
||||
if (i >= MAX_STARTUP_TRIES) {
|
||||
//iprintf ("timeout on OP_COND\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -241,19 +220,18 @@ static bool _SCSD_initCard (void) {
|
||||
// Get a new address
|
||||
_SCSD_sendCommand (SEND_RELATIVE_ADDR, 0);
|
||||
_SCSD_getResponse_R6 (responseBuffer);
|
||||
relativeCardAddress = (responseBuffer[1] << 24) | (responseBuffer[2] << 16);
|
||||
//iprintf ("Relative Address: %08X\n", relativeCardAddress);
|
||||
_SCSD_relativeCardAddress = (responseBuffer[1] << 24) | (responseBuffer[2] << 16);
|
||||
|
||||
// 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);
|
||||
|
||||
// Only this card should respond to all future commands
|
||||
_SCSD_sendCommand (SELECT_CARD, relativeCardAddress);
|
||||
_SCSD_sendCommand (SELECT_CARD, _SCSD_relativeCardAddress);
|
||||
_SCSD_getResponse_R1 (responseBuffer);
|
||||
|
||||
// Set a 4 bit data bus
|
||||
_SCSD_sendCommand (APP_CMD, relativeCardAddress);
|
||||
_SCSD_sendCommand (APP_CMD, _SCSD_relativeCardAddress);
|
||||
_SCSD_getResponse_R1 (responseBuffer);
|
||||
|
||||
_SCSD_sendCommand (SET_BUS_WIDTH, 2);
|
||||
@ -267,11 +245,10 @@ static bool _SCSD_initCard (void) {
|
||||
i = 0;
|
||||
do {
|
||||
if (i >= RESPONSE_TIMEOUT) {
|
||||
//iprintf ("timeout on SEND_STATUS\n");
|
||||
return false;
|
||||
}
|
||||
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)));
|
||||
|
||||
return true;
|
||||
@ -280,7 +257,7 @@ static bool _SCSD_initCard (void) {
|
||||
static bool _SCSD_readData (void* buffer) {
|
||||
u8* buff_u8 = (u8*)buffer;
|
||||
u16* buff = (u16*)buffer;
|
||||
u32 temp;
|
||||
volatile register u32 temp;
|
||||
int i;
|
||||
|
||||
i = BUSY_WAIT_TIMEOUT;
|
||||
@ -291,18 +268,18 @@ static bool _SCSD_readData (void* buffer) {
|
||||
|
||||
i=256;
|
||||
if ((u32)buff_u8 & 0x01) {
|
||||
while(i--)
|
||||
{
|
||||
while(i--) {
|
||||
temp = REG_SCSD_DATAREAD_32;
|
||||
temp = REG_SCSD_DATAREAD_32 >> 16;
|
||||
*buff_u8++ = (u8)temp;
|
||||
*buff_u8++ = (u8)(temp >> 8);
|
||||
}
|
||||
} else {
|
||||
while(i--)
|
||||
while(i--) {
|
||||
temp = REG_SCSD_DATAREAD_32;
|
||||
temp = REG_SCSD_DATAREAD_32 >> 16;
|
||||
*buff++ = (u16)temp;
|
||||
*buff++ = temp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -315,52 +292,6 @@ static bool _SCSD_readData (void* buffer) {
|
||||
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
|
||||
|
||||
@ -423,13 +354,16 @@ bool _SCSD_readSectors (u32 sector, u32 numSectors, void* buffer) {
|
||||
}
|
||||
|
||||
bool _SCSD_writeSectors (u32 sector, u32 numSectors, const void* buffer) {
|
||||
u16 crcBuff[4];
|
||||
u8* crc = (u8*)crcBuff; // Force crcBuff to be halfword aligned
|
||||
u16 crc[4]; // One per data line
|
||||
u8 responseBuffer[6];
|
||||
u32 offset = sector * BYTES_PER_READ;
|
||||
u8* data = (u8*) buffer;
|
||||
int i;
|
||||
|
||||
while (numSectors--) {
|
||||
// Calculate the CRC16
|
||||
_SD_CRC16 ( data, BYTES_PER_READ, (u8*)crc);
|
||||
|
||||
// Send write command and get a response
|
||||
_SCSD_sendCommand (WRITE_BLOCK, offset);
|
||||
if (!_SCSD_getResponse_R1 (responseBuffer)) {
|
||||
@ -437,8 +371,7 @@ bool _SCSD_writeSectors (u32 sector, u32 numSectors, const void* buffer) {
|
||||
}
|
||||
|
||||
// Send the data and CRC
|
||||
_SD_CRC16 ( data, BYTES_PER_READ, crc);
|
||||
if (! _SCSD_writeData( data, crc)) {
|
||||
if (! _SCSD_writeData_s (data, crc)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -447,10 +380,21 @@ bool _SCSD_writeSectors (u32 sector, u32 numSectors, const void* buffer) {
|
||||
|
||||
offset += 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;
|
||||
|
||||
}
|
||||
|
||||
bool _SCSD_clearStatus (void) {
|
||||
|
@ -29,6 +29,9 @@
|
||||
|
||||
2006-07-11 - Chishm
|
||||
* Original release
|
||||
|
||||
2006-07-22 - Chishm
|
||||
* First release of stable code
|
||||
*/
|
||||
|
||||
#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_MULTIPLE_BLOCK 18
|
||||
#define WRITE_BLOCK 24
|
||||
#define WRITE_MULTIPLE_BLOCK 25
|
||||
#define APP_CMD 55
|
||||
|
||||
/* SD App commands */
|
||||
|
@ -28,6 +28,9 @@
|
||||
|
||||
2006-07-11 - Chishm
|
||||
* 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 curLink;
|
||||
u32 lastCluster;
|
||||
bool loopedAroundFAT = false;
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
@ -223,13 +227,20 @@ u32 _FAT_fat_linkFreeCluster(PARTITION* partition, u32 cluster) {
|
||||
}
|
||||
|
||||
// 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++;
|
||||
}
|
||||
if (firstFree > lastCluster) {
|
||||
// If couldn't get a free cluster then return, saying this fact
|
||||
partition->fat.firstFree = firstFree;
|
||||
return CLUSTER_FREE;
|
||||
if (firstFree > lastCluster) {
|
||||
if (loopedAroundFAT) {
|
||||
// If couldn't get a free cluster then return, saying this fact
|
||||
partition->fat.firstFree = firstFree;
|
||||
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;
|
||||
|
||||
@ -254,6 +265,11 @@ bool _FAT_fat_clearLinks (PARTITION* partition, u32 cluster) {
|
||||
if ((cluster < 0x0002) || (cluster > partition->fat.lastCluster))
|
||||
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)) {
|
||||
// Store next cluster before erasing the link
|
||||
nextCluster = _FAT_fat_nextCluster (partition, cluster);
|
||||
|
@ -112,7 +112,7 @@ static PARTITION* _FAT_partition_constructor ( IO_INTERFACE* disc, u32 cacheSize
|
||||
PARTITION* partition;
|
||||
int i;
|
||||
u32 bootSector;
|
||||
u8 sectorBuffer[BYTES_PER_READ];
|
||||
u8 sectorBuffer[BYTES_PER_READ] = {0};
|
||||
|
||||
// Read first sector of disc
|
||||
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));
|
||||
if (partition == NULL) {
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Set partition's disc interface
|
||||
|
Loading…
Reference in New Issue
Block a user