Files
system76-edk2/EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c
oliviermartin 40842a5e7c EmbeddedPkg/MmcDxe: Card Presence Detect Race Condition
The MMC driver defaults to assume a card is not present.  It then starts a timer in MmcDxeInitialize to check for card presence every 200ms.

However it does not immediately check to see if a card is present so if the EFI driver connection process occurs less than 200ms after the driver load, the connection process for partition 
or filesystem drivers will fail because MediaPresent still is FALSE.  To resolve this race condition, we need to immediately perform the presence check in the Start routine.


EmbeddedPkg/MmcDxe: Media ID Handling

Initialize the MMC device on Start or when presence changes instead of doing it on the Block IO calls. This way the layered drivers can be stopped and rebuilt with new Media IDs instead of 
experiencing errors on calls to Block IO.


Proposed-by: Eugene Cohen (HP)
Reviewed-by: oliviermartin




git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12237 6f19259b-4bc3-4df7-8a09-765794883524
2011-08-30 18:02:38 +00:00

685 lines
22 KiB
C

/** @file
*
* Copyright (c) 2011, ARM Limited. All rights reserved.
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
* which accompanies this distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*
**/
#include <Protocol/MmcHost.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/TimerLib.h>
#include "Mmc.h"
// Untested ...
//#define USE_STREAM
#define MAX_RETRY_COUNT 1000
#define CMD_RETRY_COUNT 20
EFI_STATUS
MmcNotifyState (
IN MMC_HOST_INSTANCE *MmcHostInstance,
IN MMC_STATE State
)
{
MmcHostInstance->State = State;
return MmcHostInstance->MmcHost->NotifyState(State);
}
VOID
PrintOCR (
IN UINT32 Ocr
)
{
UINTN minv, maxv, volts;
UINTN loop;
minv = 36; // 3.6
maxv = 20; // 2.0
volts = 20; // 2.0
// The MMC register bits [23:8] indicate the working range of the card
for (loop = 8; loop < 24; loop++) {
if (Ocr & (1 << loop)) {
if (minv > volts) minv = volts;
if (maxv < volts) maxv = volts + 1;
}
volts = volts + 1;
}
DEBUG((EFI_D_ERROR, "- PrintOCR Ocr (0x%X)\n",Ocr));
DEBUG((EFI_D_ERROR, "\t- Card operating voltage: %d.%d to %d.%d\n", minv/10, minv % 10, maxv/10, maxv % 10));
if (((Ocr >> 29) & 3) == 0) {
DEBUG((EFI_D_ERROR, "\t- AccessMode: Byte Mode\n"));
} else {
DEBUG((EFI_D_ERROR, "\t- AccessMode: Block Mode (0x%X)\n",((Ocr >> 29) & 3)));
}
if (Ocr & MMC_OCR_POWERUP) {
DEBUG((EFI_D_ERROR, "\t- PowerUp\n"));
} else {
DEBUG((EFI_D_ERROR, "\t- Voltage Not Supported\n"));
}
}
VOID PrintCID (
IN UINT32* Cid
)
{
DEBUG((EFI_D_ERROR, "- PrintCID\n"));
DEBUG((EFI_D_ERROR, "\t- Manufacturing date: %d/%d\n",(Cid[0] >> 8) & 0xF,(Cid[0] >> 12) & 0xFF));
DEBUG((EFI_D_ERROR, "\t- Product serial number: 0x%X%X\n",Cid[1] & 0xFFFFFF,(Cid[0] >> 24) & 0xFF));
DEBUG((EFI_D_ERROR, "\t- Product revision: %d\n",Cid[1] >> 24));
//DEBUG((EFI_D_ERROR, "\t- Product name: %s\n",(char*)(Cid + 2)));
DEBUG((EFI_D_ERROR, "\t- OEM ID: %c%c\n",(Cid[3] >> 8) & 0xFF,(Cid[3] >> 16) & 0xFF));
}
VOID
PrintCSD (
IN UINT32* Csd
)
{
UINTN Value;
#if !defined(MDEPKG_NDEBUG)
CONST CHAR8* str_unit[] = { "100kbit/s","1Mbit/s","10Mbit/s","100MBit/s","Unkbown","Unkbown","Unkbown","Unkbown" };
CONST CHAR8* str_value[] = { "1.0","1.2","1.3","1.5","2.0","2.5","3.0","3.5","4.0","4.5","5.0","Unknown","Unknown","Unknown","Unknown" };
#endif
if (((Csd[2] >> 30) & 0x3) == 0) {
DEBUG((EFI_D_ERROR, "- PrintCSD Version 1.01-1.10/Version 2.00/Standard Capacity\n"));
} else if (((Csd[2] >> 30) & 0x3) == 1) {
DEBUG((EFI_D_ERROR, "- PrintCSD Version 2.00/High Capacity\n"));
} else {
DEBUG((EFI_D_ERROR, "- PrintCSD Version Higher than v3.3\n"));
}
DEBUG((EFI_D_ERROR, "\t- Supported card command class: 0x%X\n",MMC_CSD_GET_CCC(Csd)));
DEBUG((EFI_D_ERROR, "\t- Speed: %a %a\n",str_value[(MMC_CSD_GET_TRANSPEED(Csd) >> 3) & 0xF],str_unit[MMC_CSD_GET_TRANSPEED(Csd) & 7]));
DEBUG((EFI_D_ERROR, "\t- Maximum Read Data Block: %d\n",2 << (MMC_CSD_GET_READBLLEN(Csd)-1)));
DEBUG((EFI_D_ERROR, "\t- Maximum Write Data Block: %d\n",2 << (MMC_CSD_GET_WRITEBLLEN(Csd)-1)));
if (!MMC_CSD_GET_FILEFORMATGRP(Csd)) {
Value = MMC_CSD_GET_FILEFORMAT(Csd);
if (Value == 0) DEBUG((EFI_D_ERROR, "\t- Format(0): Hard disk-like file system with partition table\n"));
else if (Value == 1) DEBUG((EFI_D_ERROR, "\t- Format(1): DOS FAT (floppy-like) with boot sector only (no partition table)\n"));
else if (Value == 2) DEBUG((EFI_D_ERROR, "\t- Format(2): Universal File Format\n"));
else DEBUG((EFI_D_ERROR, "\t- Format(3): Others/Unknown\n"));
} else {
DEBUG((EFI_D_ERROR, "\t- Format: Reserved\n"));
}
}
VOID
PrintRCA (
IN UINT32 Rca
)
{
DEBUG((EFI_D_ERROR, "- PrintRCA: 0x%X\n",Rca));
DEBUG((EFI_D_ERROR, "\t- Status: 0x%X\n",Rca & 0xFFFF));
DEBUG((EFI_D_ERROR, "\t- RCA: 0x%X\n",(Rca >> 16) & 0xFFFF));
}
VOID
PrintResponseR1 (
IN UINT32 Response
)
{
DEBUG((EFI_D_INFO, "Response: 0x%X\n",Response));
if (Response & (1 << 8)) DEBUG((EFI_D_INFO, "\t- READY_FOR_DATA\n"));
if (((Response >> 9) & 0xF) == 0) DEBUG((EFI_D_INFO, "\t- State: Idle\n"));
else if (((Response >> 9) & 0xF) == 1) DEBUG((EFI_D_INFO, "\t- State: Ready\n"));
else if (((Response >> 9) & 0xF) == 2) DEBUG((EFI_D_INFO, "\t- State: Ident\n"));
else if (((Response >> 9) & 0xF) == 3) DEBUG((EFI_D_INFO, "\t- State: StandBy\n"));
else if (((Response >> 9) & 0xF) == 4) DEBUG((EFI_D_INFO, "\t- State: Tran\n"));
else if (((Response >> 9) & 0xF) == 5) DEBUG((EFI_D_INFO, "\t- State: Data\n"));
else if (((Response >> 9) & 0xF) == 6) DEBUG((EFI_D_INFO, "\t- State: Rcv\n"));
else if (((Response >> 9) & 0xF) == 7) DEBUG((EFI_D_INFO, "\t- State: Prg\n"));
else if (((Response >> 9) & 0xF) == 8) DEBUG((EFI_D_INFO, "\t- State: Dis\n"));
else DEBUG((EFI_D_INFO, "\t- State: Reserved\n"));
}
EFI_STATUS
EFIAPI
MmcGetCardStatus(
IN MMC_HOST_INSTANCE *MmcHostInstance
)
{
EFI_STATUS Status;
UINT32 Response[4];
UINTN CmdArg;
EFI_MMC_HOST_PROTOCOL *MmcHost;
Status = EFI_SUCCESS;
MmcHost = MmcHostInstance->MmcHost;
CmdArg = 0;
if (MmcHost == NULL) {
return EFI_INVALID_PARAMETER;
}
if(MmcHostInstance->State != MmcHwInitializationState){
//Get the Status of the card.
CmdArg = MmcHostInstance->CardInfo.RCA << 16;
Status = MmcHost->SendCommand(MMC_CMD13, CmdArg);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "MmcGetCardStatus(MMC_CMD13): Error and Status = %r\n", Status));
return Status;
}
//Read Response
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_R1,Response);
PrintResponseR1(Response[0]);
}
return Status;
}
EFI_STATUS
EFIAPI
MmcIdentificationMode (
IN MMC_HOST_INSTANCE *MmcHostInstance
)
{
EFI_STATUS Status;
UINT32 Response[4];
UINTN Timeout;
UINTN CmdArg;
BOOLEAN IsHCS;
EFI_MMC_HOST_PROTOCOL *MmcHost;
MmcHost = MmcHostInstance->MmcHost;
CmdArg = 0;
IsHCS = FALSE;
if (MmcHost == NULL) {
return EFI_INVALID_PARAMETER;
}
// We can get into this function if we restart the identification mode
if (MmcHostInstance->State == MmcHwInitializationState) {
// Initialize the MMC Host HW
Status = MmcNotifyState (MmcHostInstance, MmcHwInitializationState);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState\n"));
return Status;
}
} else {
//Note: Could even be used in all cases. But it looks this command could put the state machine into inactive for some cards
Status = MmcHost->SendCommand(MMC_CMD0, 0);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD0): Error\n"));
return Status;
}
}
Status = MmcNotifyState (MmcHostInstance, MmcIdleState);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdleState\n"));
return Status;
}
// Are we using SDIO ?
Status = MmcHost->SendCommand(MMC_CMD5, 0);
if (Status == EFI_SUCCESS) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD5): Error - SDIO not supported.\n"));
return EFI_UNSUPPORTED;
}
// Check which kind of card we are using. Ver2.00 or later SD Memory Card (PL180 is SD v1.1)
CmdArg = (0x0UL << 12 | BIT8 | 0xCEUL << 0);
Status = MmcHost->SendCommand(MMC_CMD8, CmdArg);
if (Status == EFI_SUCCESS) {
DEBUG ((EFI_D_ERROR, "Card is SD2.0 => Supports high capacity\n"));
IsHCS = TRUE;
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_R7,Response);
PrintResponseR1(Response[0]);
//check if it is valid response
if(Response[0] != CmdArg){
DEBUG ((EFI_D_ERROR, "The Card is not usable\n"));
return EFI_UNSUPPORTED;
}
} else {
DEBUG ((EFI_D_ERROR, "Not a SD2.0 Card\n"));
}
// We need to wait for the MMC or SD card is ready => (gCardInfo.OCRData.Busy == 1)
Timeout = MAX_RETRY_COUNT;
while (Timeout > 0) {
// SD Card or MMC Card ? CMD55 indicates to the card that the next command is an application specific command
Status = MmcHost->SendCommand(MMC_CMD55, 0);
if (Status == EFI_SUCCESS) {
DEBUG ((EFI_D_INFO, "Card should be SD\n"));
if (IsHCS) {
MmcHostInstance->CardInfo.CardType = SD_CARD_2;
} else {
MmcHostInstance->CardInfo.CardType = SD_CARD;
}
// Note: The first time CmdArg will be zero
CmdArg = ((UINTN *) &(MmcHostInstance->CardInfo.OCRData))[0];
if (IsHCS) {
CmdArg |= BIT30;
}
Status = MmcHost->SendCommand(MMC_ACMD41, CmdArg);
if (!EFI_ERROR(Status)) {
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_OCR,Response);
((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];
}
} else {
DEBUG ((EFI_D_INFO, "Card should be MMC\n"));
MmcHostInstance->CardInfo.CardType = MMC_CARD;
Status = MmcHost->SendCommand(MMC_CMD1, 0x800000);
if (!EFI_ERROR(Status)) {
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_OCR,Response);
((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];
}
}
if (!EFI_ERROR(Status)) {
if (MmcHostInstance->CardInfo.OCRData.Busy == 0) {
MicroSecondDelay(1);
Timeout--;
} else {
if ((MmcHostInstance->CardInfo.CardType == SD_CARD_2) && (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1)) {
MmcHostInstance->CardInfo.CardType = SD_CARD_2_HIGH;
DEBUG ((EFI_D_ERROR, "High capacity card.\n"));
}
break; // The MMC/SD card is ready. Continue the Identification Mode
}
} else {
MicroSecondDelay(1);
Timeout--;
}
}
if (Timeout == 0) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(): No Card\n"));
return EFI_NO_MEDIA;
} else {
PrintOCR(Response[0]);
}
Status = MmcNotifyState (MmcHostInstance, MmcReadyState);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcReadyState\n"));
return Status;
}
Status = MmcHost->SendCommand(MMC_CMD2, 0);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD2): Error\n"));
return Status;
}
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_CID,Response);
PrintCID(Response);
Status = MmcNotifyState (MmcHostInstance, MmcIdentificationState);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdentificationState\n"));
return Status;
}
//
// Note, SD specifications say that "if the command execution causes a state change, it
// will be visible to the host in the response to the next command"
// The status returned for this CMD3 will be 2 - identification
//
CmdArg = 1;
Status = MmcHost->SendCommand(MMC_CMD3, CmdArg);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD3): Error\n"));
return Status;
}
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_RCA,Response);
PrintRCA(Response[0]);
// For MMC card, RCA is assigned by CMD3 while CMD3 dumps the RCA for SD card
if (MmcHostInstance->CardInfo.CardType != MMC_CARD) {
MmcHostInstance->CardInfo.RCA = Response[0] >> 16;
} else {
MmcHostInstance->CardInfo.RCA = CmdArg;
}
Status = MmcNotifyState (MmcHostInstance, MmcStandByState);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcStandByState\n"));
return Status;
}
return EFI_SUCCESS;
}
EFI_STATUS InitializeMmcDevice(
IN MMC_HOST_INSTANCE *MmcHostInstance
)
{
UINT32 Response[4];
EFI_STATUS Status;
UINTN CardSize, NumBlocks, BlockSize, CmdArg;
EFI_MMC_HOST_PROTOCOL *MmcHost;
UINTN BlockCount = 1;
MmcHost = MmcHostInstance->MmcHost;
MmcIdentificationMode (MmcHostInstance);
//Send a command to get Card specific data
CmdArg = MmcHostInstance->CardInfo.RCA << 16;
Status = MmcHost->SendCommand(MMC_CMD9, CmdArg);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD9): Error, Status=%r\n", Status));
return Status;
}
//Read Response
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_CSD,Response);
PrintCSD(Response);
if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) {
CardSize = HC_MMC_CSD_GET_DEVICESIZE(Response);
NumBlocks = ((CardSize + 1) * 1024);
BlockSize = 1 << MMC_CSD_GET_READBLLEN(Response);
} else {
CardSize = MMC_CSD_GET_DEVICESIZE(Response);
NumBlocks = (CardSize + 1) * (1 << (MMC_CSD_GET_DEVICESIZEMULT(Response) + 2));
BlockSize = 1 << MMC_CSD_GET_READBLLEN(Response);
}
//For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.
if (BlockSize > 512) {
NumBlocks = MultU64x32(NumBlocks, BlockSize/512);
BlockSize = 512;
}
MmcHostInstance->BlockIo.Media->LastBlock = (NumBlocks - 1);
MmcHostInstance->BlockIo.Media->BlockSize = BlockSize;
MmcHostInstance->BlockIo.Media->ReadOnly = MmcHost->IsReadOnly();
MmcHostInstance->BlockIo.Media->MediaPresent = TRUE;
MmcHostInstance->BlockIo.Media->MediaId++;
CmdArg = MmcHostInstance->CardInfo.RCA << 16;
Status = MmcHost->SendCommand(MMC_CMD7, CmdArg);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD7): Error and Status = %r\n", Status));
return Status;
}
Status = MmcNotifyState (MmcHostInstance, MmcTransferState);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcTransferState\n"));
return Status;
}
// Set Block Length
Status = MmcHost->SendCommand(MMC_CMD16, MmcHostInstance->BlockIo.Media->BlockSize);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD16): Error MmcHostInstance->BlockIo.Media->BlockSize: %d and Error = %r\n",MmcHostInstance->BlockIo.Media->BlockSize, Status));
return Status;
}
// Block Count (not used). Could return an error for SD card
if (MmcHostInstance->CardInfo.CardType == MMC_CARD) {
MmcHost->SendCommand(MMC_CMD23, BlockCount);
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
MmcReset (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
)
{
MMC_HOST_INSTANCE *MmcHostInstance;
MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS(This);
if (MmcHostInstance->MmcHost == NULL) {
// Nothing to do
return EFI_SUCCESS;
}
// If a card is not present then clear all media settings
if (!MmcHostInstance->MmcHost->IsCardPresent()) {
MmcHostInstance->BlockIo.Media->MediaPresent = FALSE;
MmcHostInstance->BlockIo.Media->LastBlock = 0;
MmcHostInstance->BlockIo.Media->BlockSize = 512; // Should be zero but there is a bug in DiskIo
MmcHostInstance->BlockIo.Media->ReadOnly = FALSE;
// Indicate that the driver requires initialization
MmcHostInstance->State = MmcHwInitializationState;
return EFI_SUCCESS;
}
// Implement me. Either send a CMD0 (could not work for some MMC host) or just turn off/turn
// on power and restart Identification mode
return EFI_SUCCESS;
}
EFI_STATUS
MmcDetectCard (
EFI_MMC_HOST_PROTOCOL *MmcHost
)
{
if (!MmcHost->IsCardPresent()) {
return EFI_NO_MEDIA;
} else {
return EFI_SUCCESS;
}
}
#define MMCI0_BLOCKLEN 512
#define MMCI0_TIMEOUT 10000
EFI_STATUS
MmcIoBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINTN Transfer,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
UINT32 Response[4];
EFI_STATUS Status;
UINTN CmdArg;
INTN Timeout;
UINTN Cmd;
MMC_HOST_INSTANCE *MmcHostInstance;
EFI_MMC_HOST_PROTOCOL *MmcHost;
UINTN BytesRemainingToBeTransfered;
UINTN BlockCount = 1;
MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS(This);
ASSERT(MmcHostInstance != 0);
MmcHost = MmcHostInstance->MmcHost;
ASSERT(MmcHost);
if ((MmcHost == 0)|| (Buffer == NULL)) {
return EFI_INVALID_PARAMETER;
}
// Check if a Card is Present
if (!MmcHostInstance->BlockIo.Media->MediaPresent) {
return EFI_NO_MEDIA;
}
// All blocks must be within the device
if ((Lba + (BufferSize / This->Media->BlockSize)) > (This->Media->LastBlock + 1)){
return EFI_INVALID_PARAMETER;
}
// The buffer size must not be zero and it must be an exact multiple of the block size
if ((BufferSize == 0) || ((BufferSize % This->Media->BlockSize) != 0)) {
return EFI_BAD_BUFFER_SIZE;
}
if (This->Media->MediaId != MediaId) {
return EFI_MEDIA_CHANGED;
}
if((Transfer == MMC_IOBLOCKS_WRITE) && (This->Media->ReadOnly == TRUE)) {
return EFI_WRITE_PROTECTED;
}
BytesRemainingToBeTransfered = BufferSize;
while (BytesRemainingToBeTransfered > 0) {
// Check if the Card is in Ready status
CmdArg = MmcHostInstance->CardInfo.RCA << 16;
Response[0] = 0;
Timeout = 20;
while(!(Response[0] & MMC_R0_READY_FOR_DATA) && (MMC_R0_CURRENTSTATE(Response) != MMC_R0_STATE_TRAN) && Timeout--) {
Status = MmcHost->SendCommand(MMC_CMD13, CmdArg);
if (!EFI_ERROR(Status)) {
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_R1,Response);
}
}
if (0 == Timeout) {
DEBUG((EFI_D_ERROR, "The Card is busy\n"));
return EFI_NOT_READY;
}
//Set command argument based on the card access mode (Byte mode or Block mode)
if (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1) {
CmdArg = Lba;
} else {
CmdArg = Lba * This->Media->BlockSize;
}
if (Transfer == MMC_IOBLOCKS_READ) {
#ifndef USE_STREAM
// Read a single block
Cmd = MMC_CMD17;
#else
//TODO: Should we support read stream (MMC_CMD11)
#endif
} else {
#ifndef USE_STREAM
// Write a single block
Cmd = MMC_CMD24;
#else
//TODO: Should we support write stream (MMC_CMD20)
#endif
}
Status = MmcHost->SendCommand(Cmd, CmdArg);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD%d): Error %r\n",Cmd, Status));
return Status;
}
if (Transfer == MMC_IOBLOCKS_READ) {
#ifndef USE_STREAM
// Read one block of Data
Status = MmcHost->ReadBlockData(Lba,This->Media->BlockSize,Buffer);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_BLKIO, "MmcIdentificationMode(): Error Read Block Data and Status = %r\n", Status));
return Status;
}
#else
//TODO: Read a steam
ASSERT(0);
#endif
Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcProgrammingState\n"));
return Status;
}
} else {
#ifndef USE_STREAM
// Write one block of Data
Status = MmcHost->WriteBlockData(Lba,This->Media->BlockSize,Buffer);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_BLKIO, "MmcIdentificationMode(): Error Write Block Data and Status = %r\n", Status));
return Status;
}
#else
//TODO: Write a steam
ASSERT(0);
#endif
}
// Command 12 - Stop transmission (ends read)
Status = MmcHost->SendCommand(MMC_CMD12, 0);
if (!EFI_ERROR(Status)) {
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_R1b,Response);
}
// Command 13 - Read status and wait for programming to complete (return to tran)
Timeout = MMCI0_TIMEOUT;
CmdArg = MmcHostInstance->CardInfo.RCA << 16;
Response[0] = 0;
while(!(Response[0] & MMC_R0_READY_FOR_DATA) && (MMC_R0_CURRENTSTATE(Response) != MMC_R0_STATE_TRAN) && Timeout--) {
Status = MmcHost->SendCommand(MMC_CMD13, CmdArg);
if (!EFI_ERROR(Status)) {
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_R1,Response);
}
NanoSecondDelay(100);
Timeout--;
}
Status = MmcNotifyState (MmcHostInstance, MmcTransferState);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcTransferState\n"));
return Status;
}
BytesRemainingToBeTransfered -= This->Media->BlockSize;
Lba += BlockCount;
Buffer = (UINT8 *)Buffer + This->Media->BlockSize;
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
MmcReadBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
return MmcIoBlocks (This, MMC_IOBLOCKS_READ, MediaId, Lba, BufferSize, Buffer);
}
EFI_STATUS
EFIAPI
MmcWriteBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
IN VOID *Buffer
)
{
return MmcIoBlocks (This, MMC_IOBLOCKS_WRITE, MediaId, Lba, BufferSize, Buffer);
}
EFI_STATUS
EFIAPI
MmcFlushBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This
)
{
return EFI_SUCCESS;
}