/*
* $Header: /home/cvspm/ATLASBD/DRIVERS/SDMMC/DRIVER/sdmmc.c,v 1.1.1.1 2003/10/10 07:16:11 weijie Exp $
* Copyright (c) 2002-2003 Centrality Comunications Inc.
* All Rights Reserved.
*
* Confidential and Proprietary to Centrality Communications Inc.
*
* sdmmc.c - SD/MMC protocol
* Author: Feng Yan
*
* $Log: sdmmc.c,v $
* Revision 1.1.1.1 2003/10/10 07:16:11 weijie
* no message
*
* Revision 1.3 2003/08/06 02:46:49 yanfeng
* kill some bugs
*
* Revision 1.2 2003/07/21 02:46:58 tangrui
* no message
*
*
*
*/
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/********************************************************************************
* Filename: sdmmc.c - SD/MMC protocol
*
* SanDisk Host Developer's Toolkit
*
* Copyright (c) 1997 - 2000 SanDisk Corporation
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
* Description:
* This module can be used to interface to the MMC card in MMC or
* SPI modes. It supports a multiple card environment. The reset and
* identification processes assume multiple cards on the bus.
* In MMC mode, the card number is used as the RCA operand in the
* commands.
* In SPI mode, the card number is passed to the low level hardware drivers
* where the appropriate CS signal should be asserted.
*
********************************************************************************/
#include "sdconfig.h"
#include "debug.h"
#include "sdmmc.h"
void dump(PBYTE buf, int len) {
int i;
for (i=0; i< len; i++) {
if ((i%8) == 0) {
DEBUGMSG(ZONE_DATA, (TEXT("\r\n[%x]"), i));
}
DEBUGMSG(ZONE_DATA, (TEXT(" %x"), buf[i]));
}
DEBUGMSG(ZONE_DATA, (TEXT("\r\n")));
}
/*******************************************************************************
* Name: mmcSDApplCmd - Handle all application commands
*
* Description:
* Send CMD55 to switch the card into application mode. Then,
* the application command is sent.
*
* NOTE: buff is a pointer to data buffer. This buffer is ONLY for the
* command associated with data to/from the card. For the command
* without data requirement, this buff should be set to NULL before
* calling this routine.
*
* Input:
* PDEVICE_CONTROLLER pc
* UCHAR *buff
* ULONG multipp
* UINT16 RCA
* RESP_TYPE resp
* UINT16 Cmd
*
* Output:
* Depending on the type of the command.
*
* Returns:
* Completion code
*
********************************************************************************/
MMC_CC mmcSDApplCmd(PDEVICE_CONTROLLER pc, UCHAR *buff, ULONG multipp, UINT16 noBlocks, UINT16 RCA, RESP_TYPE resp, UINT16 Cmd)
{
MMC_CC respErr;
UINT16 tLength;
tLength = 0;
if (Cmd & SECURITY_CMD_BIT) {
tLength = noBlocks;
}
DEBUGMSG(ZONE_SD, (TEXT("mmcSDApplCmd, Cmd%d \r\n"), (Cmd&0x3f)));
/* ONLY FOR data transfer when buff is set */
if (buff)
{
/* Put the card in transfer state. */
respErr = mmcSetXferState (pc, RCA);
}
/* Send CMD55 to the card to start Application Specific Command */
respErr = mmcCommandAndResponse ( pc,
(((ULONG)RCA) << 16),
APPL_CMD,
0,
R1 );
/* The CMD55 is not supported by MMC card. The MMC card may
not responded or responded with an error to this command.
Check for error here to tell if it is MMC or SD card.
*/
/***********************************************************
An SD card should behave well to this command (NO ERROR).
MMC card in SPI mode should reject or not respond to it.
MMC card in MMC mode should reject or not respond to it.
***********************************************************/
if ( ( respErr != MMC_NO_ERROR) && (respErr == MMC_COMUNC_ILLEG_COM) ) {
pc->error_code = (UINT16)respErr;
return respErr;
}
/* Application Specific command follows CMD55. */
respErr = mmcCommandAndResponse ( pc,
multipp,
Cmd,
tLength,
resp );
/* The buff is ONLY for data transfer. Check it here for that purpose. */
if (buff) {
/* Security data will be handled different module */
if (Cmd & SECURITY_CMD_BIT) {
return respErr;
}
/* Set up the buffer */
pc->user_address = (USERADDRESS)buff;
/* Get information */
if (respErr == MMC_NO_ERROR) {
if (Cmd == SD_SEND_SCR) {
tLength = SD_SCR_LENGTH;
} else if (Cmd == SD_STATUS) {
tLength = SD_STATUS_LENGTH;
}
/* Get data */
respErr = receive_data( pc, tLength, 1, NO );
}
}
return respErr;
}
/*******************************************************************************
* Name: mmcReset - Initialize the card
*
* Description:
* Resets the cards and the MMC or SPI HW port.
* It must be called after power on before any other commands.
*
* This function sends reset command (CMD0) to the card and waits for the
* card to complete the initialization process by polling its status using
* send_op_condition command (CMD1) to complete its reset process.
*
* In MMC mode, this function can be used to query a card stack for the
* the common voltage range or to set a voltage range and initialize
* the cards to be ready.
*
* In SPI mode, the reset is card specific. The card number is used for the
* device to be intialized for the card to be ready.
*
* Input:
* setupInfo In MMC mode, Host operating voltage range.
* In SPI mode, Card Address.
*
* Output:
* Initialization process is finished.
*
* Returns:
* Completion code
*
********************************************************************************/
MMC_CC mmcReset( PDEVICE_CONTROLLER pc, ULONG setupInfo )
{
UINT32 cardType;
MMC_CC resErr;
UINT16 sdFlag;
UINT16 readyFlag;
UINT16 i, bInterface;
UINT16 devCount;
pc->timer = (RESET_DELAY << 2);
cardType = NO;
readyFlag = NO;
resErr = MMC_NO_ERROR;
/* Reset all devices on the bus. */
mmcCommandAndResponse ( pc,
0L,
GO_IDLE_STATE,
0,
R0 );
bInterface = 0;
devCount = 0;
sdFlag = NO;
DO_ALL_BUS_INTERFACE:
for (i = 0; i < (CID_BYTE_LENGTH/2); pc->LastResponse[i++] = 0); /* Clear buffer */
/* Delay it for a while */
Sleep(25);
/* Wait for all cards to be ready */
while (pc->timer)
{
/* There is no way to tell what type of the card is at this
point. The command CMD1 is sent first to test the card.
Because the MMC card is always responded to CMD1, if there
is no response, or an error, on the return, we could assume
that the card is not MMC card, the application command ACMD41
will be sent next to test for SD card.
*/
/* Now, check for MMC card. SD do not support CMD1 in MMC mode. */
if (!sdFlag) { /* The current card may be an MMC card */
/* Check for MMC card. */
resErr = mmcCommandAnd