--- /dev/null
+/** @file\r
+ The helper functions for BlockIo and BlockIo2 protocol.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdDxe.h"\r
+\r
+/**\r
+ Nonblocking I/O callback funtion when the event is signaled.\r
+\r
+ @param[in] Event The Event this notify function registered to.\r
+ @param[in] Context Pointer to the context data registered to the\r
+ Event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AsyncIoCallback (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ SD_REQUEST *Request;\r
+\r
+ gBS->CloseEvent (Event);\r
+\r
+ Request = (SD_REQUEST *) Context;\r
+\r
+ DEBUG_CODE_BEGIN ();\r
+ DEBUG ((EFI_D_INFO, "Sd Async Request: CmdIndex[%d] Arg[%08x] %r\n",\r
+ Request->SdMmcCmdBlk.CommandIndex, Request->SdMmcCmdBlk.CommandArgument,\r
+ Request->Packet.TransactionStatus));\r
+ DEBUG_CODE_END ();\r
+\r
+ if (EFI_ERROR (Request->Packet.TransactionStatus)) {\r
+ Request->Token->TransactionStatus = Request->Packet.TransactionStatus;\r
+ }\r
+\r
+ RemoveEntryList (&Request->Link);\r
+\r
+ if (Request->IsEnd) {\r
+ gBS->SignalEvent (Request->Token->Event);\r
+ }\r
+\r
+ FreePool (Request);\r
+}\r
+\r
+/**\r
+ Send command SET_RELATIVE_ADDRESS to the device to set the device address.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[out] Rca The relative device address to assign.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdSetRca (\r
+ IN SD_DEVICE *Device,\r
+ OUT UINT16 *Rca\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "Set RCA succeeds with Resp0 = 0x%x\n", SdMmcStatusBlk.Resp0));\r
+ *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SELECT to the device to select/deselect the device.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdSelect (\r
+ IN SD_DEVICE *Device,\r
+ IN UINT16 Rca\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_STATUS to the device to get device status.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+ @param[out] DevStatus The buffer to store the device status.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdSendStatus (\r
+ IN SD_DEVICE *Device,\r
+ IN UINT16 Rca,\r
+ OUT UINT32 *DevStatus\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32));\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_CSD to the device to get the CSD register data.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+ @param[out] Csd The buffer to store the SD_CSD register data.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdGetCsd (\r
+ IN SD_DEVICE *Device,\r
+ IN UINT16 Rca,\r
+ OUT SD_CSD *Csd\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ ZeroMem (Csd, sizeof (SD_CSD));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SEND_CSD;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+ //\r
+ CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_CID to the device to get the CID register data.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+ @param[out] Cid The buffer to store the SD_CID register data.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdGetCid (\r
+ IN SD_DEVICE *Device,\r
+ IN UINT16 Rca,\r
+ OUT SD_CID *Cid\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ ZeroMem (Cid, sizeof (SD_CID));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SEND_CID;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+ //\r
+ CopyMem (((UINT8*)Cid) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CID) - 1);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read/write single block through sync or async I/O request.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Lba The starting logical block address to be read/written.\r
+ The caller is responsible for reading/writing to only\r
+ legitimate locations.\r
+ @param[in] Buffer A pointer to the destination/source buffer for the data.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[in] IsRead Indicates it is a read or write operation.\r
+ @param[in] Token A pointer to the token associated with the transaction.\r
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
+ This parameter is only meaningful in async I/O request.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdRwSingleBlock (\r
+ IN SD_DEVICE *Device,\r
+ IN EFI_LBA Lba,\r
+ IN VOID *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN BOOLEAN IsRead,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN BOOLEAN IsEnd\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ SD_REQUEST *RwSingleBlkReq;\r
+ EFI_TPL OldTpl;\r
+\r
+ RwSingleBlkReq = NULL;\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ RwSingleBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));\r
+ if (RwSingleBlkReq == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ RwSingleBlkReq->Signature = SD_REQUEST_SIGNATURE;\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ InsertTailList (&Device->Queue, &RwSingleBlkReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ RwSingleBlkReq->Packet.SdMmcCmdBlk = &RwSingleBlkReq->SdMmcCmdBlk;\r
+ RwSingleBlkReq->Packet.SdMmcStatusBlk = &RwSingleBlkReq->SdMmcStatusBlk;\r
+ //\r
+ // Calculate timeout value through the below formula.\r
+ // Timeout = (transfer size) / (2MB/s).\r
+ // Taking 2MB/s as divisor as it's the lowest transfer speed\r
+ // above class 2.\r
+ // Refer to SD Physical Layer Simplified spec section 3.4 for details.\r
+ //\r
+ RwSingleBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;\r
+\r
+ if (IsRead) {\r
+ RwSingleBlkReq->Packet.InDataBuffer = Buffer;\r
+ RwSingleBlkReq->Packet.InTransferLength = (UINT32)BufferSize;\r
+\r
+ RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK;\r
+ RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ } else {\r
+ RwSingleBlkReq->Packet.OutDataBuffer = Buffer;\r
+ RwSingleBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;\r
+\r
+ RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK;\r
+ RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ }\r
+\r
+ if (Device->SectorAddressing) {\r
+ RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;\r
+ } else {\r
+ RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);\r
+ }\r
+\r
+ RwSingleBlkReq->IsEnd = IsEnd;\r
+ RwSingleBlkReq->Token = Token;\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ AsyncIoCallback,\r
+ RwSingleBlkReq,\r
+ &RwSingleBlkReq->Event\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ } else {\r
+ RwSingleBlkReq->Event = NULL;\r
+ }\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &RwSingleBlkReq->Packet, RwSingleBlkReq->Event);\r
+\r
+Error:\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ //\r
+ // For asynchronous operation, only free request and event in error case.\r
+ // The request and event will be freed in asynchronous callback for success case.\r
+ //\r
+ if (EFI_ERROR (Status) && (RwSingleBlkReq != NULL)) {\r
+ RemoveEntryList (&RwSingleBlkReq->Link);\r
+ if (RwSingleBlkReq->Event != NULL) {\r
+ gBS->CloseEvent (RwSingleBlkReq->Event);\r
+ }\r
+ FreePool (RwSingleBlkReq);\r
+ }\r
+ } else {\r
+ //\r
+ // For synchronous operation, free request whatever the execution result is.\r
+ //\r
+ if (RwSingleBlkReq != NULL) {\r
+ RemoveEntryList (&RwSingleBlkReq->Link);\r
+ FreePool (RwSingleBlkReq);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read/write multiple blocks through sync or async I/O request.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Lba The starting logical block address to be read/written.\r
+ The caller is responsible for reading/writing to only\r
+ legitimate locations.\r
+ @param[in] Buffer A pointer to the destination/source buffer for the data.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[in] IsRead Indicates it is a read or write operation.\r
+ @param[in] Token A pointer to the token associated with the transaction.\r
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
+ This parameter is only meaningful in async I/O request.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdRwMultiBlocks (\r
+ IN SD_DEVICE *Device,\r
+ IN EFI_LBA Lba,\r
+ IN VOID *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN BOOLEAN IsRead,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN BOOLEAN IsEnd\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_REQUEST *RwMultiBlkReq;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_TPL OldTpl;\r
+\r
+ RwMultiBlkReq = NULL;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ RwMultiBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));\r
+ if (RwMultiBlkReq == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ RwMultiBlkReq->Signature = SD_REQUEST_SIGNATURE;\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ InsertTailList (&Device->Queue, &RwMultiBlkReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ RwMultiBlkReq->Packet.SdMmcCmdBlk = &RwMultiBlkReq->SdMmcCmdBlk;\r
+ RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;\r
+ //\r
+ // Calculate timeout value through the below formula.\r
+ // Timeout = (transfer size) / (2MB/s).\r
+ // Taking 2MB/s as divisor as it's the lowest transfer speed\r
+ // above class 2.\r
+ // Refer to SD Physical Layer Simplified spec section 3.4 for details.\r
+ //\r
+ RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;\r
+\r
+ if (IsRead) {\r
+ RwMultiBlkReq->Packet.InDataBuffer = Buffer;\r
+ RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;\r
+\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK;\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ } else {\r
+ RwMultiBlkReq->Packet.OutDataBuffer = Buffer;\r
+ RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;\r
+\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ }\r
+\r
+ if (Device->SectorAddressing) {\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;\r
+ } else {\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);\r
+ }\r
+\r
+ RwMultiBlkReq->IsEnd = IsEnd;\r
+ RwMultiBlkReq->Token = Token;\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ AsyncIoCallback,\r
+ RwMultiBlkReq,\r
+ &RwMultiBlkReq->Event\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ } else {\r
+ RwMultiBlkReq->Event = NULL;\r
+ }\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);\r
+\r
+Error:\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ //\r
+ // For asynchronous operation, only free request and event in error case.\r
+ // The request and event will be freed in asynchronous callback for success case.\r
+ //\r
+ if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {\r
+ RemoveEntryList (&RwMultiBlkReq->Link);\r
+ if (RwMultiBlkReq->Event != NULL) {\r
+ gBS->CloseEvent (RwMultiBlkReq->Event);\r
+ }\r
+ FreePool (RwMultiBlkReq);\r
+ }\r
+ } else {\r
+ //\r
+ // For synchronous operation, free request whatever the execution result is.\r
+ //\r
+ if (RwMultiBlkReq != NULL) {\r
+ RemoveEntryList (&RwMultiBlkReq->Link);\r
+ FreePool (RwMultiBlkReq);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function transfers data from/to the sd memory card device.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] MediaId The media ID that the read/write request is for.\r
+ @param[in] Lba The starting logical block address to be read/written.\r
+ The caller is responsible for reading/writing to only\r
+ legitimate locations.\r
+ @param[in, out] Buffer A pointer to the destination/source buffer for the data.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[in] IsRead Indicates it is a read or write operation.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+\r
+ @retval EFI_SUCCESS The data was read/written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be read/written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+SdReadWrite (\r
+ IN SD_DEVICE *Device,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT VOID *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN BOOLEAN IsRead,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ UINTN BlockSize;\r
+ UINTN BlockNum;\r
+ UINTN IoAlign;\r
+ UINTN Remaining;\r
+ UINT32 MaxBlock;\r
+ BOOLEAN LastRw;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Media = &Device->BlockMedia;\r
+ LastRw = FALSE;\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if (!IsRead && Media->ReadOnly) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
+ //\r
+ // Check parameters.\r
+ //\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ BlockSize = Media->BlockSize;\r
+ if ((BufferSize % BlockSize) != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ BlockNum = BufferSize / BlockSize;\r
+ if ((Lba + BlockNum - 1) > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ IoAlign = Media->IoAlign;\r
+ if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Start to execute data transfer. The max block number in single cmd is 65535 blocks.\r
+ //\r
+ Remaining = BlockNum;\r
+ MaxBlock = 0xFFFF;\r
+\r
+ while (Remaining > 0) {\r
+ if (Remaining <= MaxBlock) {\r
+ BlockNum = Remaining;\r
+ LastRw = TRUE;\r
+ } else {\r
+ BlockNum = MaxBlock;\r
+ }\r
+\r
+ BufferSize = BlockNum * BlockSize;\r
+ if (BlockNum == 1) {\r
+ Status = SdRwSingleBlock (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);\r
+ } else {\r
+ Status = SdRwMultiBlocks (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ DEBUG ((EFI_D_INFO, "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", IsRead ? "Read" : "Write", Lba, BlockNum, Token->Event, Status));\r
+\r
+ Lba += BlockNum;\r
+ Buffer = (UINT8*)Buffer + BufferSize;\r
+ Remaining -= BlockNum;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Reset the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
+ not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdReset (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_DEVICE *Device;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+\r
+ Device = SD_DEVICE_DATA_FROM_BLKIO (This);\r
+\r
+ PassThru = Device->Private->PassThru;\r
+ Status = PassThru->ResetDevice (PassThru, Device->Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId Id of the media, changes every time the media is replaced.\r
+ @param Lba The starting Logical Block Address to read from\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller is\r
+ responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdReadBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_DEVICE *Device;\r
+\r
+ Device = SD_DEVICE_DATA_FROM_BLKIO (This);\r
+\r
+ Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId The media ID that the write request is for.\r
+ @param Lba The starting logical block address to be written. The caller is\r
+ responsible for writing to only legitimate locations.\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The data was written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdWriteBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_DEVICE *Device;\r
+\r
+ Device = SD_DEVICE_DATA_FROM_BLKIO (This);\r
+\r
+ Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Flush the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+\r
+ @retval EFI_SUCCESS All outstanding data was written to the device\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdFlushBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This\r
+ )\r
+{\r
+ //\r
+ // return directly\r
+ //\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Reset the Block Device.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
+ not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdResetEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ SD_DEVICE *Device;\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *NextLink;\r
+ SD_REQUEST *Request;\r
+ EFI_TPL OldTpl;\r
+\r
+ Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ for (Link = GetFirstNode (&Device->Queue);\r
+ !IsNull (&Device->Queue, Link);\r
+ Link = NextLink) {\r
+ NextLink = GetNextNode (&Device->Queue, Link);\r
+ RemoveEntryList (Link);\r
+\r
+ Request = SD_REQUEST_FROM_LINK (Link);\r
+\r
+ gBS->CloseEvent (Request->Event);\r
+ Request->Token->TransactionStatus = EFI_ABORTED;\r
+\r
+ if (Request->IsEnd) {\r
+ gBS->SignalEvent (Request->Token->Event);\r
+ }\r
+\r
+ FreePool (Request);\r
+ }\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read BufferSize bytes from Lba into Buffer.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId Id of the media, changes every time the media is replaced.\r
+ @param[in] Lba The starting Logical Block Address to read from.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[out] Buffer A pointer to the destination buffer for the data. The caller is\r
+ responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The read request was queued if Event is not NULL.\r
+ The data was read correctly from the device if\r
+ the Event is NULL.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing\r
+ the read.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r
+ intrinsic block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
+ of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdReadBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_DEVICE *Device;\r
+\r
+ Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);\r
+\r
+ Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, Token);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId The media ID that the write request is for.\r
+ @param[in] Lba The starting logical block address to be written. The\r
+ caller is responsible for writing to only legitimate\r
+ locations.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[in] Buffer A pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The data was written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdWriteBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_DEVICE *Device;\r
+\r
+ Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);\r
+\r
+ Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, Token);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Flush the Block Device.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+\r
+ @retval EFI_SUCCESS All outstanding data was written to the device\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdFlushBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ //\r
+ // Signal event and return directly.\r
+ //\r
+ if (Token != NULL && Token->Event != NULL) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r