//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//

// -- Intel Copyright Notice --
// 
// @par
// Copyright (c) 2002-2008 Intel Corporation All Rights Reserved.
// 
// @par
// The source code contained or described herein and all documents
// related to the source code ("Material") are owned by Intel Corporation
// or its suppliers or licensors.  Title to the Material remains with
// Intel Corporation or its suppliers and licensors.
// 
// @par
// The Material is protected by worldwide copyright and trade secret laws
// and treaty provisions. No part of the Material may be used, copied,
// reproduced, modified, published, uploaded, posted, transmitted,
// distributed, or disclosed in any way except in accordance with the
// applicable license agreement .
// 
// @par
// No license under any patent, copyright, trade secret or other
// intellectual property right is granted to or conferred upon you by
// disclosure or delivery of the Materials, either expressly, by
// implication, inducement, estoppel, except in accordance with the
// applicable license agreement.
// 
// @par
// Unless otherwise agreed by Intel in writing, you may not remove or
// alter this notice or any other notice embedded in Materials by Intel
// or Intel's suppliers or licensors in any way.
// 
// @par
// For further details, please see the file README.TXT distributed with
// this software.
// 
// @par
// -- End Intel Copyright Notice --
//

//------------------------------------------------------------------------------
//
//  File: sdpdd.c
//
//  This file implements SD PDD driver.
//
// 

#include <sdpdd.h>
#include <oal.h>
#include <pci.h>	
#include <sdhcd.h>
#include <sdcard.h>
#include <nkintr.h>		//for OEMGetRealTime()


volatile ULONG PCI_MEM_BASE[3];
static unsigned int SD_ActivePort;
BOOL bCommandCompleteOccurred = FALSE;
static WORD ResponseBuffer[10];  
//PSD_PARSED_REGISTER_CSD pParsedCSD;

//------------------------------------------------------------------------------
//
//  SDBoot - PDD Layer
//
//------------------------------------------------------------------------------
VOID SetActiveSlot(unsigned int ActiveSlot)
{	
	SD_ActivePort = ActiveSlot;
	
	//RETAILMSG(1, (TEXT("Active slot = %d\r\n"),SD_ActivePort));
}

BOOL PDD_SDInitializeHardware()
{
	PCI_SLOT_NUMBER     slotNumber;
	PCI_COMMON_CONFIG   pciConfig;
	int	bus, device, function;
	int length = 0;
	DWORD dwCap;
	BOOL bGotSDBaseMem = FALSE;
	
	if(SD_ActivePort >= 3)		//Add this to prevent SD_ActivePort hasn't been initialized. 
		SD_ActivePort = 1;
		
	// iterate through buses
    for (bus = 0; bus < PCI_MAX_BUS; bus++) 
    {
        // iterate through devices
        for (device = 0; device < PCI_MAX_DEVICES; device++) 
        {
        	slotNumber.u.bits.DeviceNumber = device;
            // iterate through functions
            for (function = 0; function < PCI_MAX_FUNCTION; function++) 
            {                
            	slotNumber.u.bits.FunctionNumber = function;
            	
                // read PCI config data   
                // Maybe the function PCIGetBusDataByOffset() should be modified for Trinity Lake                                      
				length = PCIGetBusDataByOffset(bus, slotNumber.u.AsULONG,
                                       &pciConfig, 0, sizeof(pciConfig));                                          

                if (length == 0 || (pciConfig.VendorID == 0xFFFF))
                    break;

                // Check SD hoster controller
                if ((pciConfig.BaseClass == 0x08) && (pciConfig.SubClass  == 0x05))  // SD hoster controller
                {
         			//RETAILMSG(TRUE, (TEXT("SD interrupt =0x%x\r\n"),pciConfig.u.type0.InterruptLine));
         			//RETAILMSG(1, (TEXT("slot%d's BaseAddress = 0x%X (Memory)\r\n"),function,pciConfig.u.type0.BaseAddresses[0] & 0xFFFFFFE0));
         			PCI_MEM_BASE[function] = pciConfig.u.type0.BaseAddresses[0] & 0xFFFFFFE0;
         			bGotSDBaseMem = TRUE;
                }
            }
        }
    }
    
    if(bGotSDBaseMem == FALSE)
    {
    	RETAILMSG(1, (TEXT("Can't find PCI_MEM_BASE for SD host controller\r\n")));
    	return FALSE;
    }
    
    // Issue soft reset    
    SoftwareReset(SOFT_RESET_ALL);
    // Get the capabilities register.
	dwCap = ReadSDHCReg32(SDHC_CAPABILITIES);    
	//RETAILMSG(1, (TEXT("cap Register = 0x%08X\r\n"),dwCap));	
	// timeout control
    WriteSDHCReg8(SDHC_TIMEOUT_CONTROL, 0x0E);  //Set to Max timeout
    
    WriteSDHCReg16(SDHC_ERROR_INT_STATUS_ENABLE, 0x1ff);
    WriteSDHCReg16(SDHC_ERROR_INT_SIGNAL_ENABLE, 0x1ff);    
	WriteSDHCReg16(SDHC_NORMAL_INT_SIGNAL_ENABLE, 0x1ff);
	WriteSDHCReg16(SDHC_NORMAL_INT_STATUS_ENABLE, 0x1ff);
	// Detect Card 
	if(DetectSDCard() == TRUE)
		RETAILMSG(1, (TEXT("Slot%d Card detected\r\n"),SD_ActivePort));
	else {
		RETAILMSG(1, (TEXT("Slot%d No Card\r\n"),SD_ActivePort));		
		return FALSE;
	}

	PowerOnSD(); 
	
	//WriteSDHCReg8(SDHC_HOST_CONTROL, 0x01); //test LED
		
	return TRUE;
}

VOID SD_SleepMSec(DWORD dwTimeout)
{
	DWORD dwCurrMSec = SD_GetMSecond ();
	
	while (SD_GetMSecond () - dwCurrMSec < dwTimeout);
}

DWORD SD_GetMSecond()
{	
	SYSTEMTIME st;
	DWORD dwRet;
	
	OEMGetRealTime( &st );
	dwRet = (1000UL * (60UL * (60UL * (24UL * (31UL * st.wMonth + st.wDay) + st.wHour) + st.wMinute) + st.wSecond) + st.wMilliseconds);
	
	return dwRet;
}


BYTE ReadSDHCReg8(DWORD dwOffset)
{
	volatile BYTE *ptRegister; 
	
	ptRegister = (volatile BYTE *)(PCI_MEM_BASE[SD_ActivePort] + dwOffset);	
	return *ptRegister;
}
WORD ReadSDHCReg16(DWORD dwOffset)
{
	volatile WORD *ptRegister; 
	
	ptRegister = (volatile WORD *)(PCI_MEM_BASE[SD_ActivePort] + dwOffset);	
	return *ptRegister;
}
DWORD ReadSDHCReg32(DWORD dwOffset)
{
	volatile DWORD *ptRegister; 
	
	ptRegister = (volatile DWORD *)(PCI_MEM_BASE[SD_ActivePort] + dwOffset);	
	return *ptRegister;
}
VOID WriteSDHCReg8(DWORD dwOffset,  BYTE Value) 
{
	volatile BYTE *ptRegister; 
	
	ptRegister = (volatile BYTE *)(PCI_MEM_BASE[SD_ActivePort] + dwOffset);
	*ptRegister = Value;
	
	//RETAILMSG(1, (TEXT("SDHC's Register 0x%X = 0x%X \r\n"),ptRegister, Value));
}
VOID WriteSDHCReg16(DWORD dwOffset,  WORD Value) 
{
	volatile WORD *ptRegister; 
	
	ptRegister = (volatile WORD *)(PCI_MEM_BASE[SD_ActivePort] + dwOffset);
	*ptRegister = Value;
	
	//RETAILMSG(1, (TEXT("SDHC's Register 0x%X = 0x%X \r\n"),ptRegister, Value));
}
VOID WriteSDHCReg32(DWORD dwOffset,  DWORD Value) 
{
	volatile DWORD *ptRegister; 
	
	ptRegister = (volatile DWORD *)(PCI_MEM_BASE[SD_ActivePort] + dwOffset);
	*ptRegister = Value;
	
	//RETAILMSG(1, (TEXT("sSDHC's Register 0x%X = 0x%X \r\n"),ptRegister, Value));
}
BOOL DetectSDCard()
{
	DWORD dwRegValue;
	//Enable int of card detect
	WriteSDHCReg16(SDHC_NORMAL_INT_STATUS_ENABLE,  NORMAL_INT_ENABLE_CARD_INSERTION | NORMAL_INT_ENABLE_CARD_REMOVAL | NORMAL_INT_ENABLE_CMD_COMPLETE);
	//Read state register
	dwRegValue = ReadSDHCReg32(SDHC_PRESENT_STATE);    
	if(dwRegValue & STATE_CARD_DETECT_SIGNAL)
		return TRUE;
	else 
		return FALSE;		
}

BOOL CheckCmdInhibit()
{
	
	return TRUE;
}
BOOL PDD_SDSendCommand(UINT8 cmd, UINT32 arg, RESP_TYPE resp, CMD_TYPE type, BOOL read)
{
	WORD	wRegCommand;
	WORD 	wRegTxnMode = 0;
	WORD 	wIntStatusEn;
	DWORD 	dwFlagCmdInhibit;
	int		i;		
	
	wIntStatusEn = ReadSDHCReg16(SDHC_NORMAL_INT_STATUS_ENABLE);
	// initialize command register with command code
    wRegCommand = (cmd << CMD_INDEX_SHIFT) & CMD_INDEX_MASK;
       
    switch (resp) 
    {
        case RESP_TYPE_NONE:
    	        break;

        case RESP_TYPE_R1B:
        		wRegCommand |= CMD_RESPONSE_R1B_R5B;   
	            break;

        case RESP_TYPE_R1:
        case RESP_TYPE_R5:
        case RESP_TYPE_R6:
        		wRegCommand |= CMD_RESPONSE_R1_R5_R6_R7;
	            break;

        case RESP_TYPE_R2:    
        		wRegCommand |= CMD_RESPONSE_R2;
	            break;

        case RESP_TYPE_R3:
        case RESP_TYPE_R4:    
        		wRegCommand |= CMD_RESPONSE_R3_R4;
	            break;

        default:
        		RETAILMSG(1, (TEXT("Unmatched response type\r\n")));
            	return FALSE;
    }
    
    // Check Command/Data conflict
	dwFlagCmdInhibit = STATE_CMD_INHIBIT;
	if((type == CMD_TYPE_ADTC) || (resp == RESP_TYPE_R1B))
		dwFlagCmdInhibit |= STATE_DAT_INHIBIT;
		
	for( i=0; ReadSDHCReg32(SDHC_PRESENT_STATE) & dwFlagCmdInhibit; i++)
	{
		if(i >= 10)		//we wait max 10 ms
		{
			RETAILMSG(1, (TEXT("Command/Data conflict error\r\n")));
			return FALSE;
		}
		SD_SleepMSec(1);
	}
		
	SDClockOff();	
    
 	if (type == CMD_TYPE_AC || 
        type == CMD_TYPE_BC ||
        type == CMD_TYPE_BCR)		//command-only
    {	
    	//following three lines are work around for the Pegasus.
    	//WriteSDHCReg32(SDHC_SYSTEMADDRESS_LO, 0);  
    	//WriteSDHCReg16(SDHC_BLOCKSIZE, 0);
        //WriteSDHCReg16(SDHC_BLOCKCOUNT, 0);        
    } else if (type == CMD_TYPE_ADTC) {		//command w/ data
    	
        // set the length of the block
        WriteSDHCReg16(SDHC_BLOCKSIZE, 0x200); // 512 bytes
        // set the number of blocks
        WriteSDHCReg16(SDHC_BLOCKCOUNT, 1);
		
		if(read)
		{
			wRegTxnMode |= TXN_MODE_DATA_DIRECTION_READ;     
			wIntStatusEn |= NORMAL_INT_ENABLE_BUF_READ_RDY;
		} else {
			wIntStatusEn |= NORMAL_INT_ENABLE_BUF_WRITE_RDY;
		}
        // its a command with a data phase
        wRegCommand |= CMD_DATA_PRESENT;
    }   
 
 	WriteSDHCReg16(SDHC_TRANSFERMODE, wRegTxnMode);
 	
	if(cmd == 0x11)		//CMD17 : READ_SINGLE_BLOCK
	{
		if(arg % 0x200000 == 0)
		{
	   		RETAILMSG(1,(TEXT("Load image offset = 0x%08X\r\n"),arg));
    		//RETAILMSG(1,(TEXT("Transfer mode register = 0x%04X\r\n"),wRegTxnMode));
		}
	} else {
		RETAILMSG(1,(TEXT("Sending command register 0x%04X\r\n"),wRegCommand));
    	RETAILMSG(1,(TEXT("Sending command Argument 0x%08X\r\n"),arg));
    	//RETAILMSG(1,(TEXT("Transfer mode register = 0x%04X\r\n"),wRegTxnMode));
    }
        
    WriteSDHCReg32(SDHC_ARGUMENT_0, arg);

    WriteSDHCReg16(SDHC_NORMAL_INT_STATUS_ENABLE, wIntStatusEn);    
    
    SDClockOn();
    
    WriteSDHCReg16(SDHC_COMMAND, wRegCommand);      
    
  	if(PollingForCommandComplete() == FALSE)
   		return FALSE;
    
	return TRUE;
}

BOOL PollingForCommandComplete()
{
	BOOL fContinue = TRUE;
	WORD wIntStatus;
	DWORD dwIndex;

	// Assume we reading PCI register at 66 Mhz. for times of 100 us. it should be 10*1000 time
 	for (dwIndex=0; fContinue  && dwIndex<10*1000; dwIndex ++ ) 
 	{
        wIntStatus = ReadSDHCReg16(SDHC_NORMAL_INT_STATUS);
        if (wIntStatus != 0) 
        {
        	
            // Error handling. Make sure to handle errors first. 
            if ( wIntStatus & NORMAL_INT_STATUS_ERROR_INT ) 
            {
                HandleErrors();
                fContinue = FALSE;               
            }

            // Command Complete handling.
            if ( wIntStatus & NORMAL_INT_STATUS_CMD_COMPLETE ) 
            {
                // Clear status
                bCommandCompleteOccurred = TRUE;
                fContinue = FALSE;
                WriteSDHCReg16(SDHC_NORMAL_INT_STATUS, NORMAL_INT_STATUS_CMD_COMPLETE);
                if (HandleCommandComplete())  // If completed. 
                {
                    WriteSDHCReg16(SDHC_NORMAL_INT_STATUS, (wIntStatus & NORMAL_INT_STATUS_TRX_COMPLETE));
                }
            }
        }
    }
    
    if(fContinue == TRUE)
    	RETAILMSG(1, (TEXT("PollingForCommandComplete() time out\r\n")));	
    	
   return (!fContinue);
}

BOOL HandleCommandComplete()
{   
//	int i;	
	
	memset(ResponseBuffer, 0, sizeof(ResponseBuffer));
  
    ResponseBuffer[0] = ReadSDHCReg16(SDHC_R0);
    ResponseBuffer[1] = ReadSDHCReg16(SDHC_R1);
    ResponseBuffer[2] = ReadSDHCReg16(SDHC_R2);
    ResponseBuffer[3] = ReadSDHCReg16(SDHC_R3);
    ResponseBuffer[4] = ReadSDHCReg16(SDHC_R4);
    ResponseBuffer[5] = ReadSDHCReg16(SDHC_R5);
    ResponseBuffer[6] = ReadSDHCReg16(SDHC_R6);
    ResponseBuffer[7] = ReadSDHCReg16(SDHC_R7);
    
    //for(i=0;i<8;i++)
    	//RETAILMSG(1,(TEXT("SDHC_R%d = 0x%04X\r\n"),i, ResponseBuffer[i]));

    return TRUE;
}

UINT32 PDD_SDGetResponse(SD_RESPONSE whichResp) 
{
    UINT32 response = 0;
    UINT16 regVal = 0;

    switch( whichResp ) 
    {
        case RCA_REGISTER: 
	            response = ResponseBuffer[1];
	            RETAILMSG(1,(TEXT("RCA_REGISTER = 0x%04X\r\n"),response));
	            break;

        case CARD_STATUS_REGISTER:
        		response = ResponseBuffer[0];
	            response |= (ResponseBuffer[1] << 16);
	            RETAILMSG(1,(TEXT("Status_REGISTER = 0x%08X\r\n"),response));
            	break;

        case OCR_REGISTER: 
	            //32-bit responses 
	            response = ResponseBuffer[0];
	            response |= (ResponseBuffer[1] << 16);
	            RETAILMSG(1,(TEXT("OCR_REGISTER = 0x%08X\r\n"),response));
	            break;

        case SCR_REGISTER:  //64-bit response
        case CID_REGISTER:  //128-bit responses
        case CSD_REGISTER:
        default:
	            response = 0;      //Not implemented
    }

    return response;
}

VOID PowerOnSD()
{
	WORD wRegClkCtl;
	int i;
	
	// Enable bus power    
    WriteSDHCReg8(SDHC_POWER_CONTROL, 0x0F);	//Enable Bus Power
    SD_SleepMSec(10);
    
    // Set clock
   	wRegClkCtl = ReadSDHCReg16(SDHC_CLOCK_CONTROL);
	wRegClkCtl |= CLOCK_INTERNAL_ENABLE;
	WriteSDHCReg16(SDHC_CLOCK_CONTROL, wRegClkCtl);
	
	for(i=0;i<1000;i++)
	{
		wRegClkCtl = ReadSDHCReg16(SDHC_CLOCK_CONTROL);
		if((wRegClkCtl & CLOCK_STABLE) == CLOCK_STABLE)
			break;
	}
	wRegClkCtl |= CLOCK_ENABLE;
	WriteSDHCReg16(SDHC_CLOCK_CONTROL, wRegClkCtl);	
}        
VOID SDClockOn()
{
    WORD wRegClkCtl;
	
	wRegClkCtl = ReadSDHCReg16(SDHC_CLOCK_CONTROL);
	wRegClkCtl |= CLOCK_ENABLE;
	WriteSDHCReg16(SDHC_CLOCK_CONTROL, wRegClkCtl);
}

VOID SDClockOff()
{
	WORD wRegClkCtl;
	
	wRegClkCtl = ReadSDHCReg16(SDHC_CLOCK_CONTROL);
	wRegClkCtl &= ~CLOCK_ENABLE;
	WriteSDHCReg16(SDHC_CLOCK_CONTROL, wRegClkCtl);
}

VOID PDD_SDSetPDDCapabilities(PDD_IOCTL whichAbility, UINT32 Ability) 
{
    UINT32 Rate = Ability;
    BYTE value;
    
    switch( whichAbility ) 
    {
        case SET_4BIT_MODE:
        	value = ReadSDHCReg8(SDHC_HOST_CONTROL);
            if( Ability ) 
            {
            	WriteSDHCReg8(SDHC_HOST_CONTROL, value |= HOSTCTL_DAT_WIDTH_4BIT);
            } 
            else 
            {
                WriteSDHCReg8(SDHC_HOST_CONTROL, value &= ~HOSTCTL_DAT_WIDTH_4BIT);
            }
            break;

        case SET_CLOCK_RATE:
            SetClockRate(&Rate);
            break;
    }
}

VOID SetClockRate(PDWORD pdwRate)
{ 
	DWORD dwCap;    
	DWORD dwBaseClock;
    const DWORD dwClockRate = *pdwRate;
    DWORD dwMaxClockRate;
    int i = 0; // 2^i is the divisor value
    DWORD dwDivisor;
    WORD wRegClkCtl;

	// Get the Base clock frequency
	dwCap = ReadSDHCReg32(SDHC_CAPABILITIES);    
	dwBaseClock = ((dwCap >> 8) & 0x0000003F) * 1000000;
	dwMaxClockRate = dwBaseClock;
	RETAILMSG(TRUE, (TEXT("dwBaseClock =%d\r\n"),dwBaseClock));	//Poulsbo's base clock is 48MHz
	
    // shift dwMaxClockRate until we find the closest frequency <= target
    while ( (dwClockRate < dwMaxClockRate) && ( i < 8 ) ) 
    {
        dwMaxClockRate = dwMaxClockRate >> 1;
        i++;
    }
    RETAILMSG(TRUE, (TEXT("The actual clock rate =%d\r\n"),dwMaxClockRate));

    // set the actual clock rate 
    *pdwRate = dwMaxClockRate;

	dwDivisor = 0;
    if (i != 0) 
        dwDivisor = 1 << (i - 1);
        
    dwDivisor = (dwDivisor << 8);

	// Set to register
	wRegClkCtl = 0;
	wRegClkCtl |= (WORD) dwDivisor;
	wRegClkCtl |= CLOCK_INTERNAL_ENABLE;
	WriteSDHCReg16(SDHC_CLOCK_CONTROL, wRegClkCtl);
	
	for(i=0;i<100;i++)
	{
		wRegClkCtl = ReadSDHCReg16(SDHC_CLOCK_CONTROL);
		if((wRegClkCtl & CLOCK_STABLE) == CLOCK_STABLE)
			break;
	}
	wRegClkCtl |= CLOCK_ENABLE;
	WriteSDHCReg16(SDHC_CLOCK_CONTROL, wRegClkCtl);   
	RETAILMSG(TRUE, (TEXT("Clock control register = 0x%04X\r\n"),wRegClkCtl));
}

BOOL PDD_SDReceiveData(UINT8* pBuffer) 
{
	WORD wIntStatus;
    UINT32 bytesRead;
    DWORD* pDWBuffer;
    int i;

    //Check Buffer Read Ready flag
	i = 0;
	do {    	
		wIntStatus = ReadSDHCReg16(SDHC_NORMAL_INT_STATUS);    	
   		if (wIntStatus & NORMAL_INT_STATUS_BUF_READ_RDY ) 
   		{
            // Clear status
	        WriteSDHCReg16(SDHC_NORMAL_INT_STATUS, NORMAL_INT_STATUS_BUF_READ_RDY);
               break;
        }
        //SD_SleepMSec(10);    
        i++;
    } while(i<1000);
        
    if(i>=1000)
    {
      	RETAILMSG(TRUE, (TEXT("Error : Wait for NORMAL_INT_STATUS_BUF_READ_RDY time out \r\n")));
      	return FALSE;
    }


	pDWBuffer = (DWORD*) pBuffer;
	bytesRead = 0;
	
	while(bytesRead < BLOCK_LEN)
	{
		*pDWBuffer = ReadSDHCReg32(SDHC_BUFFER_DATA_PORT_0);
		bytesRead += 4;
		pDWBuffer++;
	}
	
	return TRUE;
}

VOID PDD_SDStallExecute(UINT32 waitMs) 
{
    SD_SleepMSec(waitMs);
}

UINT32 PDD_SDGetPDDCapabilities(PDD_IOCTL whichAbility) 
{
    switch( whichAbility ) 
    {
        case GET_SUPPORTED_OCR_SD:
	            return (SD_VDD_WINDOW_3_2_TO_3_3 | SD_VDD_WINDOW_3_3_TO_3_4);

        default:
    	        return 0;
    }
}

BOOL SoftwareReset(BYTE bResetBits)
{
	int i;
	
    // Reset the controller
    WriteSDHCReg8(SDHC_SOFT_RESET, bResetBits);
    
    // HW clears the bit when it's done */
	for(i=0;ReadSDHCReg8(SDHC_SOFT_RESET) & bResetBits; i++) 
	{
		if(i>=200)		//We wait max 200 msecs.
			break;
			
		SD_SleepMSec(1);
		
	}

    return TRUE;
}

VOID HandleErrors()
{
    WORD wErrorStatus;
    WORD wErrIntSignal;
    
    wErrorStatus = ReadSDHCReg16(SDHC_ERROR_INT_STATUS);
    
    RETAILMSG(1, (TEXT("-------------------- HandleErrors - ERROR INT STATUS=0x%02X ------------------\n"), wErrorStatus));
    
    // clear all error status
    WriteSDHCReg16(SDHC_ERROR_INT_STATUS, 0);
    

	// Perform basic error recovery
    wErrIntSignal = ReadSDHCReg16(SDHC_ERROR_INT_SIGNAL_ENABLE);
    WriteSDHCReg16(SDHC_ERROR_INT_SIGNAL_ENABLE, 0);

    if ((wErrorStatus & 0x0F) != 0) 	//This is command line error
    {
        // Reset CMD line
        //RETAILMSG(1, (TEXT("HandleErrors - Command line error (0x%x). Resetting CMD line.\r\n"), wErrorStatus));
        SoftwareReset(SOFT_RESET_CMD);
    }

   if ((wErrorStatus & 0x70) !=0) 		//This is data line error
   {
        // Reset DAT line
        //RETAILMSG(1, (TEXT("HandleErrors - Data line error (0x%x). Resetting DAT line.\r\n"), wErrorStatus));
        SoftwareReset(SOFT_RESET_DAT);
   }

   // clear all error status
   WriteSDHCReg16(SDHC_ERROR_INT_STATUS, wErrorStatus);

   // re-enable error interrupt signals
   WriteSDHCReg16(SDHC_ERROR_INT_SIGNAL_ENABLE, wErrIntSignal);    
}
//------------------------------------------------------

