mirror of https://github.com/acidanthera/audk.git
396 lines
11 KiB
C
396 lines
11 KiB
C
/** @file
|
|
|
|
Block I/O protocol for CE-ATA device
|
|
|
|
Copyright (c) 2013-2015 Intel Corporation.
|
|
|
|
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 "SDMediaDevice.h"
|
|
|
|
/**
|
|
Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
|
|
|
|
@param This The EFI_BLOCK_IO_PROTOCOL instance.
|
|
@param ExtendedVerification Indicates that the driver may perform a more exhaustive.
|
|
verification operation of the device during reset.
|
|
(This parameter is ingored in this driver.)
|
|
|
|
@retval EFI_SUCCESS Success
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CEATABlockReset (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN BOOLEAN ExtendedVerification
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CARD_DATA *CardData;
|
|
EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
|
|
|
|
CardData = CARD_DATA_FROM_THIS(This);
|
|
SDHostIo = CardData->SDHostIo;
|
|
|
|
if (!ExtendedVerification) {
|
|
Status = SoftwareReset (CardData);
|
|
} else {
|
|
Status = SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG((EFI_D_ERROR, "CEATABlockReset: Fail to ResetSDHost\n" ));
|
|
return Status;
|
|
}
|
|
Status = MMCSDCardInit (CardData);
|
|
}
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
/**
|
|
Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
|
|
|
|
@param This The EFI_BLOCK_IO_PROTOCOL instance.
|
|
@param MediaId The media id that the write request is for.
|
|
@param LBA The starting logical block address to read from on the device.
|
|
The caller is responsible for writing to only legitimate locations.
|
|
@param BufferSize The size of the Buffer in bytes. This must be a multiple of the
|
|
intrinsic block size of the device.
|
|
@param Buffer A pointer to the destination buffer for the data. The caller
|
|
is responsible for either having implicit or explicit ownership
|
|
of the buffer.
|
|
|
|
@retval EFI_SUCCESS Success
|
|
@retval EFI_DEVICE_ERROR Hardware Error
|
|
@retval EFI_INVALID_PARAMETER Parameter is error
|
|
@retval EFI_NO_MEDIA No media
|
|
@retval EFI_MEDIA_CHANGED Media Change
|
|
@retval EFI_BAD_BUFFER_SIZE Buffer size is bad
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CEATABlockReadBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN UINT32 MediaId,
|
|
IN EFI_LBA LBA,
|
|
IN UINTN BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CARD_DATA *CardData;
|
|
UINT32 TransferSize;
|
|
UINT8 *pBuf;
|
|
UINT32 Index;
|
|
UINT64 Address;
|
|
UINT32 Remainder;
|
|
UINT64 CEATALBA;
|
|
UINT32 BoundarySize;
|
|
|
|
Status = EFI_SUCCESS;
|
|
CardData = CARD_DATA_FROM_THIS(This);
|
|
pBuf = Buffer;
|
|
Index = 0;
|
|
Address = MultU64x32(LBA, CardData->BlockIoMedia.BlockSize);
|
|
BoundarySize = CardData->SDHostIo->HostCapability.BoundarySize;
|
|
|
|
if (!Buffer) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" ));
|
|
goto Exit;
|
|
}
|
|
|
|
if (MediaId != CardData->BlockIoMedia.MediaId) {
|
|
Status = EFI_MEDIA_CHANGED;
|
|
DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Media changed\n" ));
|
|
goto Exit;
|
|
}
|
|
|
|
if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
|
|
Status = EFI_BAD_BUFFER_SIZE;
|
|
DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Bad buffer size\n" ));
|
|
goto Exit;
|
|
}
|
|
|
|
if (BufferSize == 0) {
|
|
Status = EFI_SUCCESS;
|
|
goto Exit;
|
|
}
|
|
|
|
if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" ));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
do {
|
|
if (BufferSize < BoundarySize) {
|
|
TransferSize = (UINT32)BufferSize;
|
|
} else {
|
|
TransferSize = BoundarySize;
|
|
}
|
|
|
|
Address += Index * TransferSize;
|
|
CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder);
|
|
ASSERT(Remainder == 0);
|
|
|
|
Status = ReadDMAExt (
|
|
CardData,
|
|
CEATALBA,
|
|
pBuf,
|
|
(UINT16)(TransferSize / DATA_UNIT_SIZE)
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG((EFI_D_ERROR, "Read Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize));
|
|
This->Reset (This, TRUE);
|
|
goto Exit;
|
|
}
|
|
BufferSize -= TransferSize;
|
|
pBuf += TransferSize;
|
|
Index ++;
|
|
} while (BufferSize != 0);
|
|
|
|
|
|
Exit:
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
|
|
|
|
@param This The EFI_BLOCK_IO_PROTOCOL instance.
|
|
@param MediaId The media id that the write request is for.
|
|
@param LBA The starting logical block address to read from on the device.
|
|
The caller is responsible for writing to only legitimate locations.
|
|
@param BufferSize The size of the Buffer in bytes. This must be a multiple of the
|
|
intrinsic block size of the device.
|
|
@param Buffer A pointer to the destination buffer for the data. The caller
|
|
is responsible for either having implicit or explicit ownership
|
|
of the buffer.
|
|
|
|
@retval EFI_SUCCESS Success
|
|
@retval EFI_DEVICE_ERROR Hardware Error
|
|
@retval EFI_INVALID_PARAMETER Parameter is error
|
|
@retval EFI_NO_MEDIA No media
|
|
@retval EFI_MEDIA_CHANGED Media Change
|
|
@retval EFI_BAD_BUFFER_SIZE Buffer size is bad
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CEATABlockWriteBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN UINT32 MediaId,
|
|
IN EFI_LBA LBA,
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CARD_DATA *CardData;
|
|
UINT32 TransferSize;
|
|
UINT8 *pBuf;
|
|
UINT32 Index;
|
|
UINT64 Address;
|
|
UINT32 Remainder;
|
|
UINT64 CEATALBA;
|
|
UINT32 BoundarySize;
|
|
|
|
|
|
Status = EFI_SUCCESS;
|
|
CardData = CARD_DATA_FROM_THIS(This);
|
|
pBuf = Buffer;
|
|
Index = 0;
|
|
Address = MultU64x32(LBA, CardData->BlockIoMedia.BlockSize);
|
|
BoundarySize = CardData->SDHostIo->HostCapability.BoundarySize;
|
|
|
|
|
|
if (!Buffer) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
if (MediaId != CardData->BlockIoMedia.MediaId) {
|
|
Status = EFI_MEDIA_CHANGED;
|
|
goto Exit;
|
|
}
|
|
|
|
if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
|
|
Status = EFI_BAD_BUFFER_SIZE;
|
|
goto Exit;
|
|
}
|
|
|
|
if (BufferSize == 0) {
|
|
Status = EFI_SUCCESS;
|
|
goto Exit;
|
|
}
|
|
|
|
if (CardData->BlockIoMedia.ReadOnly) {
|
|
Status = EFI_WRITE_PROTECTED;
|
|
goto Exit;
|
|
}
|
|
|
|
if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
CardData->NeedFlush = TRUE;
|
|
|
|
do {
|
|
if (BufferSize < BoundarySize) {
|
|
TransferSize = (UINT32)BufferSize;
|
|
} else {
|
|
TransferSize = BoundarySize;
|
|
}
|
|
|
|
Address += Index * TransferSize;
|
|
CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder);
|
|
ASSERT(Remainder == 0);
|
|
|
|
Status = WriteDMAExt (
|
|
CardData,
|
|
CEATALBA,
|
|
pBuf,
|
|
(UINT16)(TransferSize / DATA_UNIT_SIZE)
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG((EFI_D_ERROR, "Write Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize));
|
|
This->Reset (This, TRUE);
|
|
goto Exit;
|
|
}
|
|
BufferSize -= TransferSize;
|
|
pBuf += TransferSize;
|
|
Index ++;
|
|
} while (BufferSize != 0);
|
|
|
|
|
|
Exit:
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
|
|
(In this driver, this function just returns EFI_SUCCESS.)
|
|
|
|
@param This The EFI_BLOCK_IO_PROTOCOL instance.
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval Others
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CEATABlockFlushBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This
|
|
)
|
|
{
|
|
|
|
CARD_DATA *CardData;
|
|
|
|
CardData = CARD_DATA_FROM_THIS(This);
|
|
|
|
if (CardData->NeedFlush) {
|
|
CardData->NeedFlush = FALSE;
|
|
FlushCache (CardData);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
CEATA card BlockIo init function.
|
|
|
|
@param CardData Pointer to CARD_DATA.
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval Others
|
|
**/
|
|
EFI_STATUS
|
|
CEATABlockIoInit (
|
|
IN CARD_DATA *CardData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
CEATA card BlockIo init function
|
|
|
|
Arguments:
|
|
CardData - Pointer to CARD_DATA
|
|
|
|
Returns:
|
|
EFI_SUCCESS - Success
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT64 MaxSize;
|
|
UINT32 Remainder;
|
|
//
|
|
//BlockIO protocol
|
|
//
|
|
CardData->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
|
|
CardData->BlockIo.Media = &(CardData->BlockIoMedia);
|
|
CardData->BlockIo.Reset = CEATABlockReset;
|
|
CardData->BlockIo.ReadBlocks = CEATABlockReadBlocks ;
|
|
CardData->BlockIo.WriteBlocks = CEATABlockWriteBlocks;
|
|
CardData->BlockIo.FlushBlocks = CEATABlockFlushBlocks;
|
|
|
|
CardData->BlockIoMedia.MediaId = 0;
|
|
CardData->BlockIoMedia.RemovableMedia = FALSE;
|
|
CardData->BlockIoMedia.MediaPresent = TRUE;
|
|
CardData->BlockIoMedia.LogicalPartition = FALSE;
|
|
|
|
if (CardData->CSDRegister.PERM_WRITE_PROTECT | CardData->CSDRegister.TMP_WRITE_PROTECT) {
|
|
CardData->BlockIoMedia.ReadOnly = TRUE;
|
|
} else {
|
|
CardData->BlockIoMedia.ReadOnly = FALSE;
|
|
}
|
|
|
|
|
|
CardData->BlockIoMedia.WriteCaching = FALSE;
|
|
CardData->BlockIoMedia.IoAlign = 1;
|
|
|
|
Status = IndentifyDevice (CardData);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
//Some device does not support this feature
|
|
//
|
|
|
|
if (CardData->IndentifyDeviceData.MaxWritesPerAddress == 0) {
|
|
CardData->BlockIoMedia.ReadOnly = TRUE;
|
|
}
|
|
|
|
CardData->BlockIoMedia.BlockSize = (1 << CardData->IndentifyDeviceData.Sectorsize);
|
|
ASSERT(CardData->BlockIoMedia.BlockSize >= 12);
|
|
|
|
|
|
MaxSize = *(UINT64*)(CardData->IndentifyDeviceData.MaximumLBA);
|
|
MaxSize = MultU64x32 (MaxSize, 512);
|
|
|
|
Remainder = 0;
|
|
CardData->BlockNumber = DivU64x32Remainder (MaxSize, CardData->BlockIoMedia.BlockSize, &Remainder);
|
|
ASSERT(Remainder == 0);
|
|
|
|
CardData->BlockIoMedia.LastBlock = (EFI_LBA)(CardData->BlockNumber - 1);
|
|
|
|
|
|
Exit:
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|