/******************************************************************************
 *
 *               Microchip Memory Disk Drive File System
 *
 ******************************************************************************
 * FileName:        SD-SPI.c
 * Dependencies:    SD-SPI.h
 *                  string.h
 *                  FSIO.h
 *                  FSDefs.h
 * Processor:       PIC18/PIC24/dsPIC30/dsPIC33/PIC32
 * Compiler:        C18/C30/C32
 * Company:         Microchip Technology, Inc.
 * Version:         1.2.4
 *
 * Software License Agreement
 *
 * The software supplied herewith by Microchip Technology Incorporated
 * (the “Company? for its PICmicro?Microcontroller is intended and
 * supplied to you, the Company’s customer, for use solely and
 * exclusively on Microchip PICmicro Microcontroller products. The
 * software is owned by the Company and/or its supplier, and is
 * protected under applicable copyright laws. All rights are reserved.
 * Any use in violation of the foregoing restrictions may subject the
 * user to criminal sanctions under applicable laws, as well as to
 * civil liability for the breach of the terms and conditions of this
 * license.
 *
 * THIS SOFTWARE IS PROVIDED IN AN “AS IS?CONDITION. NO WARRANTIES,
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 *
*****************************************************************************/

#include "Compiler.h"
#include "GenericTypeDefs.h"
#include "MDD File System\FSIO.h"
#include "MDD File System\FSDefs.h"
#include "MDD File System\SD-SPI.h"
#include "string.h"
#include "FSconfig.h"
#include "HardwareProfile.h"

/******************************************************************************
 * Global Variables
 *****************************************************************************/

// Description:  Used for the mass-storage library to determine capacity
DWORD MDD_SDSPI_finalLBA;
WORD gMediaSectorSize;
BYTE gSDMode;
static MEDIA_INFORMATION mediaInformation;

#ifdef __18CXX
    // Summary: Table of SD card commands and parameters
    // Description: The sdmmc_cmdtable contains an array of SD card commands, the corresponding CRC code, the
    //              response type that the card will return, and a parameter indicating whether to expect
    //              additional data from the card.
    const rom typMMC_CMD sdmmc_cmdtable[] =
#else
    const typMMC_CMD sdmmc_cmdtable[] =
#endif
{
    // cmd                      crc     response
    {cmdGO_IDLE_STATE,          0x95,   R1,     NODATA},
    {cmdSEND_OP_COND,           0xF9,   R1,     NODATA},
    {cmdSEND_IF_COND,      		0x87,   R7,     NODATA},
    {cmdSEND_CSD,               0xAF,   R1,     MOREDATA},
    {cmdSEND_CID,               0x1B,   R1,     MOREDATA},
    {cmdSTOP_TRANSMISSION,      0xC3,   R1,     NODATA},
    {cmdSEND_STATUS,            0xAF,   R2,     NODATA},
    {cmdSET_BLOCKLEN,           0xFF,   R1,     NODATA},
    {cmdREAD_SINGLE_BLOCK,      0xFF,   R1,     MOREDATA},
    {cmdREAD_MULTI_BLOCK,       0xFF,   R1,     MOREDATA},
    {cmdWRITE_SINGLE_BLOCK,     0xFF,   R1,     MOREDATA},
    {cmdWRITE_MULTI_BLOCK,      0xFF,   R1,     MOREDATA}, 
    {cmdTAG_SECTOR_START,       0xFF,   R1,     NODATA},
    {cmdTAG_SECTOR_END,         0xFF,   R1,     NODATA},
    {cmdERASE,                  0xDF,   R1b,    NODATA},
    {cmdAPP_CMD,                0x73,   R1,     NODATA},
    {cmdREAD_OCR,               0x25,   R7,     NODATA},
    {cmdCRC_ON_OFF,             0x25,   R1,     NODATA}
};




/******************************************************************************
 * Prototypes
 *****************************************************************************/
extern void Delayms(BYTE milliseconds);
BYTE MDD_SDSPI_ReadMedia(void);
MEDIA_INFORMATION * MDD_SDSPI_MediaInitialize(void);
MMC_RESPONSE SendMMCCmd(BYTE cmd, DWORD address);

#if defined __C30__ || defined __C32__
    void OpenSPIM ( unsigned int sync_mode);
    void CloseSPIM( void );
    unsigned char WriteSPIM( unsigned char data_out );
#elif defined __18CXX
    void OpenSPIM ( unsigned char sync_mode);
    void CloseSPIM( void );
    unsigned char WriteSPIM( unsigned char data_out );

    unsigned char WriteSPIManual(unsigned char data_out);
    BYTE ReadMediaManual (void);
    MMC_RESPONSE SendMMCCmdManual(BYTE cmd, DWORD address);
#endif


#ifdef __PIC32MX__
/*********************************************************
  Function:
    static inline __attribute__((always_inline)) unsigned char SPICacutateBRG (unsigned int pb_clk, unsigned int spi_clk)
  Summary:
    Calculate the PIC32 SPI BRG value
  Conditions:
    None
  Input:
    pb_clk -  The value of the PIC32 peripheral clock
    spi_clk - The desired baud rate
  Return:
    The corresponding BRG register value.
  Side Effects:
    None.
  Description:
    The SPICalutateBRG function is used to determine an appropriate BRG register value for the PIC32 SPI module.
  Remarks:
    None                                                  
  *********************************************************/

static inline __attribute__((always_inline)) unsigned char SPICalutateBRG(unsigned int pb_clk, unsigned int spi_clk)
{
    unsigned int brg;

    brg = pb_clk / (2 * spi_clk);

    if(pb_clk % (2 * spi_clk))
        brg++;

    if(brg > 0x100)
        brg = 0x100;

    if(brg)
        brg--;

    return (unsigned char) brg;
}
#endif


/*********************************************************
  Function:
    BYTE MDD_SDSPI_MediaDetect
  Summary:
    Determines whether an SD card is present
  Conditions:
    The MDD_MediaDetect function pointer must be configured
    to point to this function in FSconfig.h
  Input:
    None
  Return Values:
    TRUE -  Card detected
    FALSE - No card detected
  Side Effects:
    None.
  Description:
    The MDD_SDSPI_MediaDetect function determine if an SD card is connected to 
    the microcontroller.
    If the MEDIA_SOFT_DETECT is not defined, the detection is done by polling
    the SD card detect pin.
    The MicroSD connector does not have a card detect pin, and therefore a
    software mechanism must be used. To do this, the SEND_STATUS command is sent 
    to the card. If the card is not answering with 0x00, the card is either not 
    present, not configured, or in an error state. If this is the case, we try
    to reconfigure the card. If the configuration fails, we consider the card not 
    present (it still may be present, but malfunctioning). In order to use the 
    software card detect mechanism, the MEDIA_SOFT_DETECT macro must be defined.
    
  Remarks:
    None                                                  
  *********************************************************/

BYTE MDD_SDSPI_MediaDetect (void)
{
#ifndef MEDIA_SOFT_DETECT
    return(!SD_CD);
#else
	MMC_RESPONSE    response;

	if (SPIENABLE == 0)
	{
		/* If the SPI module is not enabled, send manually the SEND_STATUS command */
		#if (GetSystemClock() >= 25600000)
			/* should only be here when GetSystemClock() >= 25600000 */
	    	response = SendMMCCmdManual(SEND_STATUS,0x0);
		#endif
	}
	else
	{
    	response = SendMMCCmd(SEND_STATUS,0x0);
	}

	/* Check the response to the SEND_STATUS command*/
	if(response.r2._word != 0x00)
	{
		/* the card has not responded correctly to the SEND_STATUS command; try to reinitialize it */
		MDD_SDSPI_MediaInitialize();
		if (mediaInformation.errorCode == MEDIA_NO_ERROR)
		{
			/* if the card was reinitialized correctly, it means it is present */
			return 1;
		}
		else 
		{
			return 0;
		}
	}
	else
	{
    /* No error was reported, the card is present and not  */
		return 1;
	}
#endif

}//end MediaDetect



/*********************************************************
  Function:
    WORD MDD_SDSPI_ReadSectorSize (void)
  Summary:
    Determines the current sector size on the SD card
  Conditions:
    MDD_MediaInitialize() is complete
  Input:
    None
  Return:
    The size of the sectors for the physical media
  Side Effects:
    None.
  Description:
    The MDD_SDSPI_ReadSectorSize function is used by the
    USB mass storage class to return the card's sector
    size to the PC on request.
  Remarks:
    None
  *********************************************************/

WORD MDD_SDSPI_ReadSectorSize(void)
{
    return gMediaSectorSize;
}


/*********************************************************
  Function:
    DWORD MDD_SDSPI_ReadCapacity (void)
  Summary:
    Determines the current capacity of the SD card
  Conditions:
    MDD_MediaInitialize() is complete
  Input:
    None
  Return:
    The capacity of the device
  Side Effects:
    None.
  Description:
    The MDD_SDSPI_ReadCapacity function is used by the
    USB mass storage class to return the total number
    of sectors on the card.
  Remarks:
    None
  *********************************************************/
DWORD MDD_SDSPI_ReadCapacity(void)
{
    return (MDD_SDSPI_finalLBA);
}


/*********************************************************
  Function:
    WORD MDD_SDSPI_InitIO (void)
  Summary:
    Initializes the I/O lines connected to the card
  Conditions:
    MDD_MediaInitialize() is complete.  The MDD_InitIO
    function pointer is pointing to this function.
  Input:
    None
  Return:
    None
  Side Effects:
    None.
  Description:
    The MDD_SDSPI_InitIO function initializes the I/O
    pins connected to the SD card.
  Remarks:
    None
  *********************************************************/

void MDD_SDSPI_InitIO (void)
{
    // Turn off the card
    SD_CD_TRIS = INPUT;            //Card Detect - input
    SD_CS = 1;                     //Initialize Chip Select line
    SD_CS_TRIS = OUTPUT;            //Card Select - output
    SD_WE_TRIS = INPUT;            //Write Protect - input
}



/*********************************************************
  Function:
    BYTE MDD_SDSPI_ShutdownMedia (void)
  Summary:
    Disables the SD card
  Conditions:
    The MDD_ShutdownMedia function pointer is pointing 
    towards this function.
  Input:
    None
  Return:
    None
  Side Effects:
    None.
  Description:
    This function will disable the SPI port and deselect
    the SD card.
  Remarks:
    None
  *********************************************************/

BYTE MDD_SDSPI_ShutdownMedia(void)
{
    // close the spi bus
    CloseSPIM();
    
    // deselect the device
    SD_CS = 1;

    return 0;
}


/*****************************************************************************
  Function:
    MMC_RESPONSE SendMMCCmd (BYTE cmd, DWORD address)
  Summary:
    Sends a command packet to the SD card.
  Conditions:
    None.
  Input:
    None.
  Return Values:
    MMC_RESPONSE    - The response from the card
                    - Bit 0 - Idle state
                    - Bit 1 - Erase Reset
                    - Bit 2 - Illegal Command
                    - Bit 3 - Command CRC Error
                    - Bit 4 - Erase Sequence Error
                    - Bit 5 - Address Error
                    - Bit 6 - Parameter Error
                    - Bit 7 - Unused. Always 0.
  Side Effects:
    None.
  Description:
    SendMMCCmd prepares a command packet and sends it out over the SPI interface.
    Response data of type 'R1' (as indicated by the SD/MMC product manual is returned.
  Remarks:
    None.
  ***************************************************************************************/

MMC_RESPONSE SendMMCCmd(BYTE cmd, DWORD address)
{
    WORD timeout = 0x8;
    BYTE index;
    MMC_RESPONSE    response;
    CMD_PACKET  CmdPacket;
    
    SD_CS = 0;                           //Card Select
    
    // Copy over data
    CmdPacket.cmd        = sdmmc_cmdtable[cmd].CmdCode;
    CmdPacket.address    = address;
    CmdPacket.crc        = sdmmc_cmdtable[cmd].CRC;       // Calc CRC here
    
    CmdPacket.TRANSMIT_BIT = 1;             //Set Tranmission bit
    
    WriteSPIM(CmdPacket.cmd);                //Send Command
    WriteSPIM(CmdPacket.addr3);              //Most Significant Byte
    WriteSPIM(CmdPacket.addr2);
    WriteSPIM(CmdPacket.addr1);
    WriteSPIM(CmdPacket.addr0);              //Least Significant Byte
    WriteSPIM(CmdPacket.crc);                //Send CRC
    
    // see if we are going to get a response
    if(sdmmc_cmdtable[cmd].responsetype == R1 || sdmmc_cmdtable[cmd].responsetype == R1b || sdmmc_cmdtable[cmd].responsetype == R7)
    {
        do
        {
            response.r1._byte = MDD_SDSPI_ReadMedia();
            timeout--;
        }while(response.r1._byte == MMC_FLOATING_BUS && timeout != 0);
    }
    else if(sdmmc_cmdtable[cmd].responsetype == R2)
    {
        MDD_SDSPI_ReadMedia();
        
        response.r2._byte1 = MDD_SDSPI_ReadMedia();
        response.r2._byte0 = MDD_SDSPI_ReadMedia();
    }

    if(sdmmc_cmdtable[cmd].responsetype == R1b)
    {
        response.r1._byte = 0x00;
        
        for(index =0; index < 0xFF && response.r1._byte == 0x00; index++)
        {
            timeout = 0xFFFF;
            
            do
            {
                response.r1._byte = MDD_SDSPI_ReadMedia();
                timeout--;
            }while(response.r1._byte == 0x00 && timeout != 0);
        }
    }

    if (sdmmc_cmdtable[cmd].responsetype == R7)
    {
        response.r7.bytewise._returnVal = (DWORD)MDD_SDSPI_ReadMedia() << 24;
        response.r7.bytewise._returnVal += (DWORD)MDD_SDSPI_ReadMedia() << 16;
        response.r7.bytewise._returnVal += (DWORD)MDD_SDSPI_ReadMedia() << 8;
        response.r7.bytewise._returnVal += (DWORD)MDD_SDSPI_ReadMedia();
    }

    mSend8ClkCycles();                      //Required clocking (see spec)

    // see if we are expecting data or not
    if(!(sdmmc_cmdtable[cmd].moredataexpected))
        SD_CS = 1;

    return(response);
}

#ifdef __18CXX
#if (GetSystemClock() >= 25600000)

/*****************************************************************************
  Function:
    MMC_RESPONSE SendMMCCmdManual (BYTE cmd, DWORD address)
  Summary:
    Sends a command packet to the SD card with bit-bang SPI.
  Conditions:
    None.
  Input:
    None.
  Return Values:
    MMC_RESPONSE    - The response from the card
                    - Bit 0 - Idle state
                    - Bit 1 - Erase Reset
                    - Bit 2 - Illegal Command
                    - Bit 3 - Command CRC Error
                    - Bit 4 - Erase Sequence Error
                    - Bit 5 - Address Error
                    - Bit 6 - Parameter Error
                    - Bit 7 - Unused. Always 0.
  Side Effects:
    None.
  Description:
    SendMMCCmd prepares a command packet and sends it out over the SPI interface.
    Response data of type 'R1' (as indicated by the SD/MMC product manual is returned.
    This function is intended to be used when the clock speed of a PIC18 device is
    so high that the maximum SPI divider can't reduce the clock below the maximum
    SD card initialization sequence speed.
  Remarks:
    None.
  ***************************************************************************************/

MMC_RESPONSE SendMMCCmdManual(BYTE cmd, DWORD address)
{
    WORD timeout = 0x8;
    BYTE index;
    MMC_RESPONSE    response;
    CMD_PACKET  CmdPacket;
    
    SD_CS = 0;                           //Card Select
    
    // Copy over data
    CmdPacket.cmd        = sdmmc_cmdtable[cmd].CmdCode;
    CmdPacket.address    = address;
    CmdPacket.crc        = sdmmc_cmdtable[cmd].CRC;       // Calc CRC here
    
    CmdPacket.TRANSMIT_BIT = 1;             //Set Tranmission bit
    
    WriteSPIManual(CmdPacket.cmd);                //Send Command
    WriteSPIManual(CmdPacket.addr3);              //Most Significant Byte
    WriteSPIManual(CmdPacket.addr2);
    WriteSPIManual(CmdPacket.addr1);
    WriteSPIManual(CmdPacket.addr0);              //Least Significant Byte
    WriteSPIManual(CmdPacket.crc);                //Send CRC
    
    // see if we are going to get a response
    if(sdmmc_cmdtable[cmd].responsetype == R1 || sdmmc_cmdtable[cmd].responsetype == R1b || sdmmc_cmdtable[cmd].responsetype == R7)
    {
        do
        {
            response.r1._byte = ReadMediaManual();
            timeout--;
        }while(response.r1._byte == MMC_FLOATING_BUS && timeout != 0);
    }
    else if(sdmmc_cmdtable[cmd].responsetype == R2)
    {
        ReadMediaManual();
        
        response.r2._byte1 = ReadMediaManual();
        response.r2._byte0 = ReadMediaManual();
    }

    if(sdmmc_cmdtable[cmd].responsetype == R1b)
    {
        response.r1._byte = 0x00;
        
        for(index =0; index < 0xFF && response.r1._byte == 0x00; index++)
        {
            timeout = 0xFFFF;
            
            do
            {
                response.r1._byte = ReadMediaManual();
                timeout--;
            }while(response.r1._byte == 0x00 && timeout != 0);
        }
    }
    if (sdmmc_cmdtable[cmd].responsetype == R7)
    {
        response.r7.bytewise._returnVal = (DWORD)ReadMediaManual() << 24;
        response.r7.bytewise._returnVal += (DWORD)ReadMediaManual() << 16;
        response.r7.bytewise._returnVal += (DWORD)ReadMediaManual() << 8;
        response.r7.bytewise._returnVal += (DWORD)ReadMediaManual();
    }

    WriteSPIManual(0xFF);                      //Required clocking (see spec)

    // see if we are expecting data or not
    if(!(sdmmc_cmdtable[cmd].moredataexpected))
        SD_CS = 1;

    return(response);
}
#endif
#endif



/*****************************************************************************
  Function:
    BYTE MDD_SDSPI_SectorRead (DWORD sector_addr, BYTE * buffer)
  Summary:
    Reads a sector of data from an SD card.
  Conditions:
    The MDD_SectorRead function pointer must be pointing towards this function.
  Input:
    sector_addr - The address of the sector on the card.
    byffer -      The buffer where the retrieved data will be stored.  If
                  buffer is NULL, do not store the data anywhere.
  Return Values:
    TRUE -  The sector was read successfully
    FALSE - The sector could not be read
  Side Effects:
    None
  Description:
    The MDD_SDSPI_SectorRead function reads a sector of data bytes (512 bytes) 
    of data from the SD card starting at the sector address and stores them in 
    the location pointed to by 'buffer.'
  Remarks:
    The card expects the address field in the command packet to be a byte address.
    The sector_addr value is converted to a byte address by shifting it left nine
    times (multiplying by 512).
  ***************************************************************************************/

BYTE MDD_SDSPI_SectorRead(DWORD sector_addr, BYTE* buffer)
{
    WORD index;
    WORD delay;
    MMC_RESPONSE    response;
    BYTE data_token;
    BYTE status = TRUE;
    DWORD   new_addr;
   
    // send the cmd
    if (gSDMode == SD_MODE_NORMAL)
        new_addr = sector_addr << 9;
    else
        new_addr = sector_addr;
    response = SendMMCCmd(READ_SINGLE_BLOCK,new_addr);

    // Make sure the command was accepted
    if(response.r1._byte != 0x00)
    {
        response = SendMMCCmd (READ_SINGLE_BLOCK,new_addr);
        if(response.r1._byte != 0x00)
        {
            return FALSE;
        }
    }

    index = 0x2FF;
    
    // Timing delay- at least 8 clock cycles
    delay = 0x40;
    while (delay)
        delay--;
  
    //Now, must wait for the start token of data block
    do
    {
        data_token = MDD_SDSPI_ReadMedia();
        index--;   
        
        delay = 0x40;
        while (delay)
            delay--;

    }while((data_token == MMC_FLOATING_BUS) && (index != 0));

    // Hopefully that zero is the datatoken
    if((index == 0) || (data_token != DATA_START_TOKEN))
    {
        status = FALSE;
    }
    else
    {
        for(index = 0; index < gMediaSectorSize; index++)      //Reads in a sector of data (512 bytes)
        {
            if(buffer != NULL)
            {
				#ifdef __18CXX
	                data_token = SPIBUF;
	                SPI_INTERRUPT_FLAG = 0;
	                SPIBUF = 0xFF;
	                while(!SPI_INTERRUPT_FLAG);
	                buffer[index] = SPIBUF;
				#elif defined (__PIC32MX__)
                	buffer[index] = MDD_SDSPI_ReadMedia();
				#else
	                SPIBUF = 0xFF;
	                while (!SPISTAT_RBF);
	                buffer[index] = SPIBUF;
				#endif
            }
            else
            {
                MDD_SDSPI_ReadMedia();
            }
        }
        // Now ensure CRC
        mReadCRC();               //Read 2 bytes of CRC
        //status = mmcCardCRCError;
    }

    mSend8ClkCycles();            //Required clocking (see spec)

    SD_CS = 1;

    return(status);
}//end SectorRead


/*****************************************************************************
  Function:
    BYTE MDD_SDSPI_SectorWrite (DWORD sector_addr, BYTE * buffer, BYTE allowWriteToZero)
  Summary:
    Writes a sector of data to an SD card.
  Conditions:
    The MDD_SectorWrite function pointer must be pointing to this function.
  Input:
    sector_addr -      The address of the sector on the card.
    buffer -           The buffer with the data to write.
    allowWriteToZero -
                     - TRUE -  Writes to the 0 sector (MBR) are allowed
                     - FALSE - Any write to the 0 sector will fail.
  Return Values:
    TRUE -  The sector was written successfully.
    FALSE - The sector could not be written.
  Side Effects:
    None.
  Description:
    The MDD_SDSPI_SectorWrite function writes one sector of data (512 bytes) 
    of data from the location pointed to by 'buffer' to the specified sector of 
    the SD card.
  Remarks:
    The card expects the address field in the command packet to be a byte address.
    The sector_addr value is ocnverted to a byte address by shifting it left nine
    times (multiplying by 512).
  ***************************************************************************************/

BYTE MDD_SDSPI_SectorWrite(DWORD sector_addr, BYTE* buffer, BYTE allowWriteToZero)
{
    WORD            index;
    DWORD           counter;
    BYTE            data_response;
    MMC_RESPONSE    response; 
    BYTE            status = TRUE;

    if (sector_addr == 0 && allowWriteToZero == FALSE)
        status = FALSE;
    else
    {
        // send the cmd

        if (gSDMode == SD_MODE_NORMAL)
            response = SendMMCCmd(WRITE_SINGLE_BLOCK,(sector_addr << 9));
        else
            response = SendMMCCmd(WRITE_SINGLE_BLOCK,(sector_addr));
        
        // see if it was accepted
        if(response.r1._byte != 0x00)
            status = FALSE;
        else
        {
            WriteSPIM(DATA_START_TOKEN);                 //Send data start token

            for(index = 0; index < gMediaSectorSize; index++)      //Send 512 bytes
            {
				#ifdef __18CXX
	                data_response = SPIBUF;			//Clear BF flag, just in case it was previously left set.
	                SPI_INTERRUPT_FLAG = 0;			//Clear interrupt flag, in case it was previously left set.
	                SPIBUF = buffer[index];         // write byte to SSP1BUF register
	                while( !SPI_INTERRUPT_FLAG );   // wait until bus cycle complete
	                data_response = SPIBUF;         // Clear the SPIBUF
				#elif defined (__PIC32MX__)
    	            WriteSPIM(buffer[index]);
				#else
	                SPIBUF = buffer[index];
	                while (!SPISTAT_RBF);
	                data_response = SPIBUF;
				#endif
            }

            // calc crc
            mSendCRC();                                 //Send 2 bytes of CRC
            
            data_response = MDD_SDSPI_ReadMedia();                //Read response
            
            if((data_response & 0x0F) != DATA_ACCEPTED)
            {
                status = FALSE;
            }
            else
            {
				#if defined (__PIC32MX__)
					do
					{
					    putcSPI((unsigned int)0xFF);
					    data_response = getcSPI();
					}while(!data_response);
				#else
					#ifdef __18CXX
                		counter = GetInstructionClock() / 82;                
		                do                  //Wait for write completion
		                {
		                    data_response = SPIBUF;
		                    SPI_INTERRUPT_FLAG = 0;
		                    SPIBUF = 0xFF;
		                    counter--;
		                    while(!SPI_INTERRUPT_FLAG);
		                    data_response = SPIBUF;
		                }while((data_response == 0x00) && (counter != 0));		                    
					#else
                		counter = GetInstructionClock() / 44;                
		                do                  //Wait for write completion
		                {
		                    SPIBUF = 0xFF;
		                    counter--;
		                    while(!SPISTAT_RBF);
		                    data_response = SPIBUF;
		                }while((data_response == 0x00) && (counter != 0));
					#endif
					
	                if(counter == 0)                                  //if timeout first
	                    status = FALSE;
				#endif
            }

            mSend8ClkCycles();
        }

        SD_CS = 1;

    } // Not writing to 0 sector

    return(status);
} //end SectorWrite


/*****************************************************************************
  Function:
    BYTE MDD_SDSPI_WriteProtectState
  Summary:
    Indicates whether the card is write-protected.
  Conditions:
    The MDD_WriteProtectState function pointer must be pointing to this function.
  Input:
    None.
  Return Values:
    TRUE -  The card is write-protected
    FALSE - The card is not write-protected
  Side Effects:
    None.
  Description:
    The MDD_SDSPI_WriteProtectState function will determine if the SD card is
    write protected by checking the electrical signal that corresponds to the
    physical write-protect switch.
  Remarks:
    None
  ***************************************************************************************/

BYTE MDD_SDSPI_WriteProtectState(void)
{
    return(SD_WE);
}


/*****************************************************************************
  Function:
    void Delayms (BYTE milliseconds)
  Summary:
    Delay.
  Conditions:
    None.
  Input:
    BYTE milliseconds - Number of ms to delay
  Return:
    None.
  Side Effects:
    None.
  Description:
    The Delayms function will delay a specified number of milliseconds.  Used for SPI
    timing.
  Remarks:
    Depending on compiler revisions, this function may delay for the exact time
    specified.  This shouldn't create a significant problem.
***************************************************************************************/

void Delayms(BYTE milliseconds)
{
    BYTE    ms;
    DWORD   count;
    
    ms = milliseconds;
    while (ms--)
    {
        count = MILLISECDELAY;
        while (count--);
    }
    Nop();
    return;
}


/*****************************************************************************
  Function:
    void CloseSPIM (void)
  Summary:
    Disables the SPI module.
  Conditions:
    None.
  Input:
    None.
  Return:
    None.
  Side Effects:
    None.
  Description:
    Disables the SPI module.
  Remarks:
    None.
  ***************************************************************************************/

void CloseSPIM (void)
{
#if defined __C30__ || defined __C32__

    SPISTAT &= 0x7FFF;

#elif defined __18CXX

    SPICON1 &= 0xDF;

#endif
}



/*****************************************************************************
  Function:
    unsigned char WriteSPIM (unsigned char data_out)
  Summary:
    Writes data to the SD card.
  Conditions:
    None.
  Input:
    data_out - The data to write.
  Return:
    0.
  Side Effects:
    None.
  Description:
    The WriteSPIM function will write a byte of data from the microcontroller to the
    SD card.
  Remarks:
    None.
  ***************************************************************************************/

unsigned char WriteSPIM( unsigned char data_out )
{
#ifdef __PIC32MX__
    BYTE   clear;
    putcSPI((BYTE)data_out);
    clear = getcSPI();
    return ( 0 );                // return non-negative#
#elif defined __18CXX
    BYTE clear;
    clear = SPIBUF;
    SPI_INTERRUPT_FLAG = 0;
    SPIBUF = data_out;
    if (SPICON1 & 0x80)
        return -1;
    else
        while (!SPI_INTERRUPT_FLAG);
    return 0;
#else
    BYTE   clear;
    SPIBUF = data_out;          // write byte to SSP1BUF register
    while( !SPISTAT_RBF ); // wait until bus cycle complete
    clear = SPIBUF;
    return ( 0 );                // return non-negative#
#endif
}



/*****************************************************************************
  Function:
    BYTE MDD_SDSPI_ReadMedia (void)
  Summary:
    Reads a byte of data from the SD card.
  Conditions:
    None.
  Input:
    None.
  Return:
    The byte read.
  Side Effects:
    None.
  Description:
    The MDD_SDSPI_ReadMedia function will read one byte from the SPI port.
  Remarks:
    This function replaces ReadSPI, since some implementations of that function
    will initialize SSPBUF/SPIBUF to 0x00 when reading.  The card expects 0xFF.
  ***************************************************************************************/
BYTE MDD_SDSPI_ReadMedia(void)
{

#ifdef __C32__

    putcSPI((BYTE)0xFF);
    return (BYTE)getcSPI();

#elif defined __18CXX

    BYTE clear;
    clear = SPIBUF;
    SPI_INTERRUPT_FLAG = 0;
    SPIBUF = 0xFF;
    while (!SPI_INTERRUPT_FLAG);
    return SPIBUF;

#else
    SPIBUF = 0xFF;                              //Data Out - Logic ones
    while(!SPISTAT_RBF);                     //Wait until cycle complete
    return(SPIBUF);                             //Return with byte read
#endif
}

/*****************************************************************************
  Function:
    void OpenSPIM (unsigned int sync_mode)
  Summary:
    Initializes the SPI module
  Conditions:
    None.
  Input:
    sync_mode - Sets synchronization
  Return:
    None.
  Side Effects:
    None.
  Description:
    The OpenSPIM function will enable and configure the SPI module.
  Remarks:
    None.
  ***************************************************************************************/

#ifdef __18CXX
void OpenSPIM (unsigned char sync_mode)
#else
void OpenSPIM( unsigned int sync_mode)
#endif
{
    SPISTAT = 0x0000;               // power on state 

#ifndef __PIC32MX__
    SPICON1 = 0x0000;                // power on state
    SPICON1 |= sync_mode;          // select serial mode 
#endif

#ifdef __18CXX
    SPICON1 |= 0x80;
    SPISTATbits.CKE = 1;
#else
    SPICON1bits.CKP = 1;
    SPICON1bits.CKE = 0;
#endif

    SPICLOCK = 0;
    SPIOUT = 0;                  // define SDO1 as output (master or slave)
    SPIIN = 1;                  // define SDI1 as input (master or slave)
    SPIENABLE = 1;             // enable synchronous serial port
}


#ifdef __18CXX
#if (GetSystemClock() >= 25600000)

// Description: Delay value for the manual SPI clock
#define MANUAL_SPI_CLOCK_VALUE             1
/*****************************************************************************
  Function:
    unsigned char WriteSPIManual (unsigned char data_out)
  Summary:
    Write a character to the SD card with bit-bang SPI.
  Conditions:
    Make sure the SDI pin is pre-configured as a digital pin, if it is 
    multiplexed with analog functionality.
  Input:
    data_out - Data to send.
  Return:
    0.
  Side Effects:
    None.
  Description:
    Writes a character to the SD card.
  Remarks:
    The WriteSPIManual function is for use on a PIC18 when the clock speed is so
    high that the maximum SPI clock divider cannot reduce the SPI clock speed below
    the maximum SD card initialization speed.
  ***************************************************************************************/
unsigned char WriteSPIManual(unsigned char data_out)
{
    unsigned char i;
    unsigned char clock;

    SPICLOCKLAT = 0;
    SPIOUTLAT = 1;
    SPICLOCK = OUTPUT;
    SPIOUT = OUTPUT;

	//Loop to send out 8 bits of SDO data and associated SCK clock.
	for(i = 0; i < 8; i++)
	{
		SPICLOCKLAT = 0;
		if(data_out & 0x80)
			SPIOUTLAT = 1;
		else
			SPIOUTLAT = 0;
		data_out = data_out << 1;				//Bit shift, so next bit to send is in MSb position
    	clock = MANUAL_SPI_CLOCK_VALUE;
    	while (clock--);
    	SPICLOCKLAT = 1;
    	clock = MANUAL_SPI_CLOCK_VALUE;
    	while (clock--);    			
	}	
    SPICLOCKLAT = 0;

    return 0; 
}


/*****************************************************************************
  Function:
    BYTE ReadMediaManual (void)
  Summary:
    Reads a byte of data from the SD card.
  Conditions:
    None.
  Input:
    None.
  Return:
    The byte read.
  Side Effects:
    None.
  Description:
    The MDD_SDSPI_ReadMedia function will read one byte from the SPI port.
  Remarks:
    This function replaces ReadSPI, since some implementations of that function
    will initialize SSPBUF/SPIBUF to 0x00 when reading.  The card expects 0xFF.
    This function is for use on a PIC18 when the clock speed is so high that the
    maximum SPI clock prescaler cannot reduce the SPI clock below the maximum SD card
    initialization speed.
  ***************************************************************************************/
BYTE ReadMediaManual (void)
{
    unsigned char i;
    unsigned char clock;
    unsigned char result = 0x00;

    SPIOUTLAT = 1;
    SPIOUT = OUTPUT;
    SPIIN = INPUT;
    SPICLOCKLAT = 0;
    SPICLOCK = OUTPUT;
 
 	//Loop to send 8 clock pulses and read in the returned bits of data. Data "sent" will be = 0xFF
	for(i = 0; i < 8; i++)
	{
		SPICLOCKLAT = 0;
    	clock = MANUAL_SPI_CLOCK_VALUE;
    	while (clock--);
    	SPICLOCKLAT = 1;
    	clock = MANUAL_SPI_CLOCK_VALUE;
    	while (clock--);
		result = result << 1;	//Bit shift the previous result.  We receive the byte MSb first. This operation makes LSb = 0.  
    	if(SPIINPORT)
    		result++;			//Set the LSb if we detected a '1' on the SPIINPORT pin, otherwise leave as 0.
	}	
    SPICLOCKLAT = 0;

    return result;
}//end ReadMedia

#endif      // End >25600000
#endif      // End __18CXX


/*****************************************************************************
  Function:
    MEDIA_INFORMATION *  MDD_SDSPI_MediaInitialize (void)
  Summary:
    Initializes the SD card.
  Conditions:
    The MDD_MediaInitialize function pointer must be pointing to this function.
  Input:
    None.
  Return Values:
    The function returns a pointer to the MEDIA_INFORMATION structure.  The
    errorCode member may contain the following values:
        * MEDIA_NO_ERROR - The media initialized successfully
        * MEDIA_CANNOT_INITIALIZE - Cannot initialize the media.  
  Side Effects:
    None.
  Description:
    This function will send initialization commands to and SD card.
  Remarks:
    None.
  ***************************************************************************************/
MEDIA_INFORMATION *  MDD_SDSPI_MediaInitialize(void)
{
    WORD timeout;
    MMC_RESPONSE    response;
	BYTE CSDResponse[20];
	BYTE count, index;
	DWORD c_size;
	BYTE c_size_mult;
 
	#if defined __C30__ || defined __C32__
    	WORD spiconvalue = 0x0003;
	#endif
    mediaInformation.errorCode = MEDIA_NO_ERROR;
    mediaInformation.validityFlags.value = 0;
    MDD_SDSPI_finalLBA = 0x00000000;	//Will compute a valid value later, from the CSD register values we get from the card

    SD_CS = 1;               //Initialize Chip Select line
    
    //Media powers up in the open-drain mode and cannot handle a clock faster
    //than 400kHz. Initialize SPI port to slower than 400kHz
	#if defined __C30__ || defined __C32__
		#ifdef __PIC32MX__
			OpenSPI(SPI_START_CFG_1, SPI_START_CFG_2);
		    SPIBRG = SPICalutateBRG(GetPeripheralClock(), 400000);
		#else	//else C30 = PIC24/dsPIC devices
		    // Calculate the prescaler needed for the clock
		    timeout = GetSystemClock() / 400000;
		    // if timeout is less than 400k and greater than 100k use a 1:1 prescaler
		    if (timeout == 0)
		    {
		        OpenSPIM (MASTER_ENABLE_ON | PRI_PRESCAL_1_1 | SEC_PRESCAL_1_1);
		    }
		    else
		    {
		        while (timeout != 0)
		        {
		            if (timeout > 8)
		            {
		                spiconvalue--;
		                // round up
		                if ((timeout % 4) != 0)
		                    timeout += 4;
		                timeout /= 4;
		            }
		            else
		            {
		                break;
		            }
		        }
		        
		        timeout--;
		    
		        OpenSPIM (MASTER_ENABLE_ON | spiconvalue | ((~(timeout << 2)) & 0x1C));
		    }
		#endif   //#ifdef __PIC32MX__ (and corresponding #else)


	    // let the card power on and initialize
	    Delayms(1);
	    
	    //Media requires 80 clock cycles to startup [8 clocks/BYTE * 10 us]
	    for(timeout=0; timeout<10; timeout++)
	        mSend8ClkCycles();
	
	    SD_CS = 0;
	    
	    Delayms(1);
	    
	    // Send CMD0 to reset the media
	    response = SendMMCCmd(GO_IDLE_STATE,0x0);
	    
	    if((response.r1._byte == MMC_BAD_RESPONSE) || ((response.r1._byte & 0xF7) != 0x01))
	    {
	        SD_CS = 1;                               // deselect the devices
	        mediaInformation.errorCode = MEDIA_CANNOT_INITIALIZE;
	        return &mediaInformation;
	    }
	
	    response = SendMMCCmd(SEND_IF_COND, 0x1AA);
	    if (((response.r7.bytewise._returnVal & 0xFFF) == 0x1AA) && (!response.r7.bitwise.bits.ILLEGAL_CMD))
		{
	        timeout = 0xFFF;
	        do
	        {
	        	response = SendMMCCmd(SEND_OP_COND, 0x40000000);
	            timeout--;
	        }while(response.r1._byte != 0x00 && timeout != 0);
			response = SendMMCCmd(READ_OCR, 0x0);
	        if (((response.r7.bytewise._returnVal & 0xC0000000) == 0xC0000000) && (response.r7.bytewise._byte == 0))
			{
	        	gSDMode = SD_MODE_HC;
			}
	        else //if (((response.r7.bytewise._returnVal & 0xC0000000) == 0x80000000) && (response.r7.bytewise._byte == 0))
			{
				gSDMode = SD_MODE_NORMAL;
			}
		}
	    else
		{
	        gSDMode = SD_MODE_NORMAL;
	
		    // According to spec cmd1 must be repeated until the card is fully initialized
		    timeout = 0xFFF;
		    do
		    {
		        response = SendMMCCmd(SEND_OP_COND,0x0);
		        timeout--;
		    }while(response.r1._byte != 0x00 && timeout != 0);
		}
	
	    // see if it failed
	    if(timeout == 0)
	    {
	        mediaInformation.errorCode = MEDIA_CANNOT_INITIALIZE;
	        SD_CS = 1;                               // deselect the devices
	    }
	    else      
	    {
	#else	//PIC18 device (#else of: #if defined __C30__ || defined __C32__)
    
	    // let the card power on and initialize
	    Delayms(1);
	    
	    #if (GetSystemClock() < 25600000)
	
	        #if (GetSystemClock() < 1600000)
	            OpenSPIM (SYNC_MODE_FAST);
	        #elif (GetSystemClock() < 6400000)
	            OpenSPIM (SYNC_MODE_MED);
	        #else
	            OpenSPIM (SYNC_MODE_SLOW);
	        #endif
	        
	        // let the card power on and initialize
	        Delayms(1);
	        
	        //Media requires 80 clock cycles to startup [8 clocks/BYTE * 10 us]
	        for(timeout=0; timeout<10; timeout++)
	            mSend8ClkCycles();
	    
	        SD_CS = 0;
	        
	        Delayms(1);
	        
	        // Send CMD0 to reset the media
	        response = SendMMCCmd(GO_IDLE_STATE,0x0);
	        
	        if((response.r1._byte == MMC_BAD_RESPONSE) || ((response.r1._byte & 0xF7) != 0x01))
	        {
	            mediaInformation.errorCode = MEDIA_CANNOT_INITIALIZE;
	            SD_CS = 1;                               // deselect the devices
	            return &mediaInformation;
	        }
	
	        response = SendMMCCmd(SEND_IF_COND, 0x1AA);
	        if (((response.r7.bytewise._returnVal & 0xFFF) == 0x1AA) && (!response.r7.bitwise.bits.ILLEGAL_CMD))
			{
		        timeout = 0xFFF;
		        do
		        {
	                response = SendMMCCmd(SEND_OP_COND, 0x40000000);
		            timeout--;
		        }while(response.r1._byte != 0x00 && timeout != 0);
				response = SendMMCCmd(READ_OCR, 0x0);
		        if (((response.r7.bytewise._returnVal & 0xC0000000) == 0xC0000000) && (response.r7.bytewise._byte == 0))
				{
	            	gSDMode = SD_MODE_HC;
				}
		        else //if (((response.r7.bytewise._returnVal & 0xC0000000) == 0x80000000) && (response.r7.bytewise._byte == 0))
				{
					gSDMode = SD_MODE_NORMAL;
				}
			}
	        else
			{
	            gSDMode = SD_MODE_NORMAL;
	
		        // According to spec cmd1 must be repeated until the card is fully initialized
		        timeout = 0xFFF;
		        do
		        {
		            response = SendMMCCmd(SEND_OP_COND,0x0);
		            timeout--;
		        }while(response.r1._byte != 0x00 && timeout != 0);
			}

   		#else	//else of (#if (GetSystemClock() < 25600000))
	        // Make sure the SPI module doesn't control the bus
	        SPICON1 = 0x00;
	
	        //Media requires 80 clock cycles to startup [8 clocks/BYTE * 10 us]
	        for(timeout=0; timeout<10; timeout++)
	            WriteSPIManual(0xFF);
	    
	        SD_CS = 0;
	        
	        Delayms(1);
	    
	        // Send CMD0 to reset the media
	        response = SendMMCCmdManual (GO_IDLE_STATE, 0x0);
	
	        if ((response.r1._byte == MMC_BAD_RESPONSE) || ((response.r1._byte & 0xF7) != 0x01))
	        {
	            SD_CS = 1;                              // deselect the devices
	            mediaInformation.errorCode = MEDIA_CANNOT_INITIALIZE;
	            return &mediaInformation;
	        }
	
	        response = SendMMCCmdManual(SEND_IF_COND, 0x1AA);
	        if (((response.r7.bytewise._returnVal & 0xFFF) == 0x1AA) && (!response.r7.bitwise.bits.ILLEGAL_CMD))
			{
		        timeout = 0xFFF;
		        do
		        {
	                response = SendMMCCmdManual(SEND_OP_COND, 0x40000000);
		            timeout--;
		        }while(response.r1._byte != 0x00 && timeout != 0);
				response = SendMMCCmdManual(READ_OCR, 0x0);
		        if (((response.r7.bytewise._returnVal & 0xC0000000) == 0xC0000000) && (response.r7.bytewise._byte == 0))
				{
	            	gSDMode = SD_MODE_HC;
				}
		        else //if (((response.r7.bytewise._returnVal & 0xC0000000) == 0x80000000) && (response.r7.bytewise._byte == 0))
				{
					gSDMode = SD_MODE_NORMAL;
				}
			}
	        else
			{
	            gSDMode = SD_MODE_NORMAL;
	        	// According to the spec cmd1 must be repeated until the card is fully initialized
	        	timeout = 0xFFF;
		        do
		        {
		            response = SendMMCCmdManual (SEND_OP_COND, 0x0);
		            timeout--;
		        }while(response.r1._byte != 0x00 && timeout != 0);
			}
    	#endif //end of #if (GetSystemClock() < 25600000), and #else

    // see if it failed
    if (timeout == 0)
    {
        mediaInformation.errorCode = MEDIA_CANNOT_INITIALIZE;
        SD_CS = 1;                              // deselect the devices
    }
    else
    {
	#endif	//end of (#if defined __C30__ || defined __C32__)), and #else (PIC18)
	//Common code below for all processors.

        Delayms (2);

        #ifdef __PIC32MX__
            #if (GetSystemClock() <= 20000000)
                SPIBRG = SPICalutateBRG(GetPeripheralClock(), 10000);
            #else
                SPIBRG = SPICalutateBRG(GetPeripheralClock(), SPI_FREQUENCY);
            #endif
        #else
            OpenSPIM(SYNC_MODE_FAST);
        #endif

		/* Send the CMD9 to read the CSD register */
        timeout = 0xFFF;
        do
        {
			response = SendMMCCmd(SEND_CSD, 0x00);
            timeout--;
        }while((response.r1._byte != 0x00) && (timeout != 0));

		/* According to the simplified spec, section 7.2.6, the card will respond
		with a standard response token, followed by a data block of 16 bytes
		suffixed with a 16-bit CRC.*/
		index = 0;
		for (count = 0; count < 20; count ++)
		{
			CSDResponse[index] = MDD_SDSPI_ReadMedia();
			index ++;			
			/* Hopefully the first byte is the datatoken, however, some cards do
			not send the response token before the CSD register.*/
			if((count == 0) && (CSDResponse[0] == DATA_START_TOKEN))
			{
				/* As the first byte was the datatoken, we can drop it. */
				index = 0;
			}
		}

		//Extract some fields from the response for computing the card capacity.
		//Note: The structure format depends on if it is a CSD V1 or V2 device.
		//Therefore, need to first determine version of the specs that the card 
		//is designed for, before interpreting the individual fields.

 		//-------------------------------------------------------------
 		//READ_BL_LEN: CSD Structure v1 cards always support 512 byte
 		//read and write block lengths.  Some v1 cards may optionally report
 		//READ_BL_LEN = 1024 or 2048 bytes (and therefore WRITE_BL_LEN also 
 		//1024 or 2048).  However, even on these cards, 512 byte partial reads
 		//and 512 byte write are required to be supported.
 		//On CSD structure v2 cards, it is always required that READ_BL_LEN 
 		//(and therefore WRITE_BL_LEN) be 512 bytes, and partial reads and
 		//writes are not allowed.
 		//Therefore, all cards support 512 byte reads/writes, but only a subset
 		//of cards support other sizes.  For best compatibility with all cards,
 		//and the simplest firmware design, it is therefore preferrable to 
 		//simply ignore the READ_BL_LEN and WRITE_BL_LEN values altogether,
 		//and simply hardcode the read/write block size as 512 bytes.
 		//-------------------------------------------------------------
		gMediaSectorSize = 512u;
		mediaInformation.validityFlags.bits.sectorSize = TRUE;
 		mediaInformation.sectorSize = gMediaSectorSize;
 		//-------------------------------------------------------------

		//Calculate the MDD_SDSPI_finalLBA (see SD card physical layer simplified spec 2.0, section 5.3.2).
		//In USB mass storage applications, we will need this information to 
		//correctly respond to SCSI get capacity requests.  Note: method of computing 
		//MDD_SDSPI_finalLBA depends on CSD structure spec version (either v1 or v2).
		if(CSDResponse[0] & 0xC0)	//Check CSD_STRUCTURE field for v2+ struct device
		{
			//Must be a v2 device (or a reserved higher version, that doesn't currently exist)

			//Extract the C_SIZE field from the response.  It is a 22-bit number in bit position 69:48.  This is different from v1.  
			//It spans bytes 7, 8, and 9 of the response.
			c_size = (((DWORD)CSDResponse[7] & 0x3F) << 16) | ((WORD)CSDResponse[8] << 8) | CSDResponse[9];
			
			MDD_SDSPI_finalLBA = ((DWORD)(c_size + 1) * (WORD)(1024u)) - 1; //-1 on end is correction factor, since LBA = 0 is valid.
		}
		else //if(CSDResponse[0] & 0xC0)	//Check CSD_STRUCTURE field for v1 struct device
		{
			//Must be a v1 device.
			//Extract the C_SIZE field from the response.  It is a 12-bit number in bit position 73:62.  
			//Although it is only a 12-bit number, it spans bytes 6, 7, and 8, since it isn't byte aligned.
			c_size = ((DWORD)CSDResponse[6] << 16) | ((WORD)CSDResponse[7] << 8) | CSDResponse[8];	//Get the bytes in the correct positions
			c_size &= 0x0003FFC0;	//Clear all bits that aren't part of the C_SIZE
			c_size = c_size >> 6;	//Shift value down, so the 12-bit C_SIZE is properly right justified in the DWORD.
			
			//Extract the C_SIZE_MULT field from the response.  It is a 3-bit number in bit position 49:47.
			c_size_mult = ((WORD)((CSDResponse[9] & 0x03) << 1)) | ((WORD)((CSDResponse[10] & 0x80) >> 7));
			
			//Calculate the MDD_SDSPI_finalLBA (see SD card physical layer simplified spec 2.0, section 5.3.2).
			//In USB mass storage applications, we will need this information to 
			//correctly respond to SCSI get capacity requests (which will cause MDD_SDSPI_ReadCapacity() to get called).
			MDD_SDSPI_finalLBA = ((DWORD)(c_size + 1) * (WORD)((WORD)1 << (c_size_mult + 2))) - 1;	//-1 on end is correction factor, since LBA = 0 is valid.		
		}	
		

        // Turn off CRC7 if we can, might be an invalid cmd on some cards (CMD59)
        response = SendMMCCmd(CRC_ON_OFF,0x0);

        // Now set the block length to media sector size. It should be already
        response = SendMMCCmd(SET_BLOCKLEN,gMediaSectorSize);
    }

    return &mediaInformation;
}//end MediaInitialize

