19b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney/** @file
29b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
39b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyBlock I/O protocol for CE-ATA device
49b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
59b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyCopyright (c) 2013-2015 Intel Corporation.
69b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
79b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyThis program and the accompanying materials
89b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinneyare licensed and made available under the terms and conditions of the BSD License
99b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinneywhich accompanies this distribution.  The full text of the license may be found at
109b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinneyhttp://opensource.org/licenses/bsd-license.php
119b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
129b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyTHE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
139b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyWITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
149b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
159b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney**/
169b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
179b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney#include "SDMediaDevice.h"
189b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
199b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney/**
209b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
219b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
229b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
239b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @param  ExtendedVerification   Indicates that the driver may perform a more exhaustive.
249b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney                                 verification operation of the device during reset.
259b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney                                 (This parameter is ingored in this driver.)
269b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
279b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval EFI_SUCCESS                Success
289b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney**/
299b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyEFI_STATUS
309b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyEFIAPI
319b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyCEATABlockReset (
329b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  IN  EFI_BLOCK_IO_PROTOCOL   *This,
339b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  IN  BOOLEAN                 ExtendedVerification
349b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  )
359b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney{
369b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  EFI_STATUS                 Status;
379b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CARD_DATA                  *CardData;
389b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
399b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
409b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData  = CARD_DATA_FROM_THIS(This);
419b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  SDHostIo = CardData->SDHostIo;
429b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
439b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  if (!ExtendedVerification) {
449b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = SoftwareReset (CardData);
459b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  } else {
469b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);
479b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    if (EFI_ERROR (Status)) {
489b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    DEBUG((EFI_D_ERROR, "CEATABlockReset: Fail to ResetSDHost\n" ));
499b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney      return Status;
509b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    }
519b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = MMCSDCardInit (CardData);
529b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  }
539b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
549b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
559b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  return Status;
569b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
579b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney }
589b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
599b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney/**
609b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
619b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
629b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
639b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @param  MediaId                The media id that the write request is for.
649b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @param  LBA                    The starting logical block address to read from on the device.
659b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney                                 The caller is responsible for writing to only legitimate locations.
669b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @param  BufferSize             The size of the Buffer in bytes. This must be a multiple of the
679b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney                                 intrinsic block size of the device.
689b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @param  Buffer                 A pointer to the destination buffer for the data. The caller
699b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney                                 is responsible for either having implicit or explicit ownership
709b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney                                 of the buffer.
719b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
729b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval EFI_SUCCESS                Success
739b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval EFI_DEVICE_ERROR           Hardware Error
749b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval EFI_INVALID_PARAMETER      Parameter is error
759b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval EFI_NO_MEDIA               No media
769b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval EFI_MEDIA_CHANGED          Media Change
779b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
789b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney**/
799b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyEFI_STATUS
809b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyEFIAPI
819b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyCEATABlockReadBlocks (
829b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  IN  EFI_BLOCK_IO_PROTOCOL   *This,
839b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  IN  UINT32                  MediaId,
849b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  IN  EFI_LBA                 LBA,
859b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  IN  UINTN                   BufferSize,
869b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  OUT VOID                    *Buffer
879b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  )
889b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney{
899b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  EFI_STATUS                  Status;
909b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CARD_DATA                   *CardData;
919b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  UINT32                      TransferSize;
929b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  UINT8                       *pBuf;
939b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  UINT32                      Index;
949b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  UINT64                      Address;
959b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  UINT32                      Remainder;
969b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  UINT64                      CEATALBA;
979b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  UINT32                      BoundarySize;
989b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
999b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  Status       = EFI_SUCCESS;
1009b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData     = CARD_DATA_FROM_THIS(This);
1019b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  pBuf         = Buffer;
1029b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  Index        = 0;
1039b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  Address      = MultU64x32(LBA, CardData->BlockIoMedia.BlockSize);
1049b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  BoundarySize = CardData->SDHostIo->HostCapability.BoundarySize;
1059b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
1069b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  if (!Buffer) {
1079b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = EFI_INVALID_PARAMETER;
1089b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" ));
1099b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    goto Exit;
1109b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  }
1119b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
1129b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  if (MediaId != CardData->BlockIoMedia.MediaId) {
1139b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = EFI_MEDIA_CHANGED;
1149b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Media changed\n" ));
1159b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    goto Exit;
1169b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  }
1179b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
1189b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
1199b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = EFI_BAD_BUFFER_SIZE;
1209b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Bad buffer size\n" ));
1219b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    goto Exit;
1229b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  }
1239b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
1249b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  if (BufferSize == 0) {
1259b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = EFI_SUCCESS;
1269b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    goto Exit;
1279b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  }
1289b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
1299b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) {
1309b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = EFI_INVALID_PARAMETER;
1319b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" ));
1329b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    goto Exit;
1339b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  }
1349b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
1359b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
1369b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  do {
1379b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    if (BufferSize < BoundarySize) {
1389b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney      TransferSize = (UINT32)BufferSize;
1399b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    } else {
1409b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney      TransferSize = BoundarySize;
1419b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    }
1429b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
1439b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Address += Index * TransferSize;
1449b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder);
1459b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    ASSERT(Remainder == 0);
1469b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
1479b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = ReadDMAExt (
1489b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney               CardData,
1499b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney               CEATALBA,
1509b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney               pBuf,
1519b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney               (UINT16)(TransferSize / DATA_UNIT_SIZE)
1529b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney               );
1539b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    if (EFI_ERROR (Status)) {
1549b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney     DEBUG((EFI_D_ERROR, "Read Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize));
1559b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney     This->Reset (This, TRUE);
1569b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney     goto Exit;
1579b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    }
1589b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    BufferSize -= TransferSize;
1599b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    pBuf       += TransferSize;
1609b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Index ++;
1619b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  } while (BufferSize != 0);
1629b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
1639b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
1649b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyExit:
1659b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  return Status;
1669b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney}
1679b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
1689b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney/**
1699b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
1709b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
1719b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
1729b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @param  MediaId                The media id that the write request is for.
1739b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @param  LBA                    The starting logical block address to read from on the device.
1749b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney                                 The caller is responsible for writing to only legitimate locations.
1759b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @param  BufferSize             The size of the Buffer in bytes. This must be a multiple of the
1769b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney                                 intrinsic block size of the device.
1779b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @param  Buffer                 A pointer to the destination buffer for the data. The caller
1789b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney                                 is responsible for either having implicit or explicit ownership
1799b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney                                 of the buffer.
1809b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
1819b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval EFI_SUCCESS                Success
1829b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval EFI_DEVICE_ERROR           Hardware Error
1839b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval EFI_INVALID_PARAMETER      Parameter is error
1849b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval EFI_NO_MEDIA               No media
1859b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval EFI_MEDIA_CHANGED          Media Change
1869b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
1879b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney**/
1889b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyEFI_STATUS
1899b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyEFIAPI
1909b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyCEATABlockWriteBlocks (
1919b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  IN  EFI_BLOCK_IO_PROTOCOL   *This,
1929b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  IN  UINT32                  MediaId,
1939b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  IN  EFI_LBA                 LBA,
1949b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  IN  UINTN                   BufferSize,
1959b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  IN  VOID                    *Buffer
1969b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  )
1979b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney{
1989b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  EFI_STATUS                  Status;
1999b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CARD_DATA                   *CardData;
2009b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  UINT32                      TransferSize;
2019b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  UINT8                       *pBuf;
2029b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  UINT32                      Index;
2039b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  UINT64                      Address;
2049b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  UINT32                      Remainder;
2059b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  UINT64                      CEATALBA;
2069b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  UINT32                      BoundarySize;
2079b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2089b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2099b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  Status       = EFI_SUCCESS;
2109b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData     = CARD_DATA_FROM_THIS(This);
2119b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  pBuf         = Buffer;
2129b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  Index        = 0;
2139b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  Address      = MultU64x32(LBA, CardData->BlockIoMedia.BlockSize);
2149b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  BoundarySize = CardData->SDHostIo->HostCapability.BoundarySize;
2159b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2169b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2179b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  if (!Buffer) {
2189b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = EFI_INVALID_PARAMETER;
2199b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    goto Exit;
2209b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  }
2219b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2229b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  if (MediaId != CardData->BlockIoMedia.MediaId) {
2239b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = EFI_MEDIA_CHANGED;
2249b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    goto Exit;
2259b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  }
2269b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2279b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
2289b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = EFI_BAD_BUFFER_SIZE;
2299b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    goto Exit;
2309b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  }
2319b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2329b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  if (BufferSize == 0) {
2339b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = EFI_SUCCESS;
2349b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    goto Exit;
2359b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  }
2369b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2379b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  if (CardData->BlockIoMedia.ReadOnly) {
2389b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = EFI_WRITE_PROTECTED;
2399b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    goto Exit;
2409b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  }
2419b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2429b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) {
2439b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = EFI_INVALID_PARAMETER;
2449b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    goto Exit;
2459b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  }
2469b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2479b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData->NeedFlush = TRUE;
2489b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2499b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  do {
2509b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    if (BufferSize < BoundarySize) {
2519b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney      TransferSize = (UINT32)BufferSize;
2529b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    } else {
2539b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney      TransferSize = BoundarySize;
2549b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    }
2559b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2569b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Address += Index * TransferSize;
2579b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder);
2589b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    ASSERT(Remainder == 0);
2599b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2609b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = WriteDMAExt (
2619b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney               CardData,
2629b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney               CEATALBA,
2639b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney               pBuf,
2649b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney               (UINT16)(TransferSize / DATA_UNIT_SIZE)
2659b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney               );
2669b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    if (EFI_ERROR (Status)) {
2679b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney     DEBUG((EFI_D_ERROR, "Write Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize));
2689b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney     This->Reset (This, TRUE);
2699b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney     goto Exit;
2709b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    }
2719b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    BufferSize -= TransferSize;
2729b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    pBuf       += TransferSize;
2739b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Index ++;
2749b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  } while (BufferSize != 0);
2759b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2769b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2779b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyExit:
2789b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  return Status;
2799b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney}
2809b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2819b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney/**
2829b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
2839b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    (In this driver, this function just returns EFI_SUCCESS.)
2849b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2859b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
2869b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2879b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval EFI_SUCCESS
2889b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval Others
2899b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney**/
2909b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyEFI_STATUS
2919b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyEFIAPI
2929b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyCEATABlockFlushBlocks (
2939b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  IN  EFI_BLOCK_IO_PROTOCOL   *This
2949b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  )
2959b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney{
2969b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
2979b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  EFI_STATUS                  Status;
2989b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CARD_DATA                   *CardData;
2999b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3009b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData  = CARD_DATA_FROM_THIS(This);
3019b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3029b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  if (CardData->NeedFlush) {
3039b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    CardData->NeedFlush = FALSE;
3049b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    Status = FlushCache (CardData);
3059b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  }
3069b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3079b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  return EFI_SUCCESS;
3089b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney}
3099b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3109b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3119b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney/**
3129b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CEATA card BlockIo init function.
3139b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3149b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @param  CardData               Pointer to CARD_DATA.
3159b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3169b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval EFI_SUCCESS
3179b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  @retval Others
3189b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney**/
3199b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyEFI_STATUS
3209b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyCEATABlockIoInit (
3219b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  IN  CARD_DATA    *CardData
3229b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  )
3239b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney/*++
3249b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3259b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  Routine Description:
3269b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    CEATA card BlockIo init function
3279b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3289b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  Arguments:
3299b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    CardData  -   Pointer to CARD_DATA
3309b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3319b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  Returns:
3329b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    EFI_SUCCESS - Success
3339b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney--*/
3349b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney{
3359b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  EFI_STATUS   Status;
3369b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  UINT64       MaxSize;
3379b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  UINT32       Remainder;
3389b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  //
3399b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  //BlockIO protocol
3409b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  //
3419b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData->BlockIo.Revision    = EFI_BLOCK_IO_PROTOCOL_REVISION;
3429b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData->BlockIo.Media       = &(CardData->BlockIoMedia);
3439b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData->BlockIo.Reset       = CEATABlockReset;
3449b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData->BlockIo.ReadBlocks  = CEATABlockReadBlocks ;
3459b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData->BlockIo.WriteBlocks = CEATABlockWriteBlocks;
3469b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData->BlockIo.FlushBlocks = CEATABlockFlushBlocks;
3479b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3489b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData->BlockIoMedia.MediaId          = 0;
3499b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData->BlockIoMedia.RemovableMedia   = FALSE;
3509b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData->BlockIoMedia.MediaPresent     = TRUE;
3519b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData->BlockIoMedia.LogicalPartition = FALSE;
3529b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3539b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  if (CardData->CSDRegister.PERM_WRITE_PROTECT | CardData->CSDRegister.TMP_WRITE_PROTECT) {
3549b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    CardData->BlockIoMedia.ReadOnly       = TRUE;
3559b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  } else {
3569b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    CardData->BlockIoMedia.ReadOnly       = FALSE;
3579b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  }
3589b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3599b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3609b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData->BlockIoMedia.WriteCaching     = FALSE;
3619b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData->BlockIoMedia.IoAlign          = 1;
3629b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3639b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  Status = IndentifyDevice (CardData);
3649b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  if (EFI_ERROR (Status)) {
3659b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney   goto Exit;
3669b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  }
3679b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3689b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  //
3699b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  //Some device does not support this feature
3709b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  //
3719b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3729b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  if (CardData->IndentifyDeviceData.MaxWritesPerAddress == 0) {
3739b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney    CardData->BlockIoMedia.ReadOnly       = TRUE;
3749b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  }
3759b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3769b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData->BlockIoMedia.BlockSize        = (1 << CardData->IndentifyDeviceData.Sectorsize);
3779b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  ASSERT(CardData->BlockIoMedia.BlockSize >= 12);
3789b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3799b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3809b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  MaxSize = *(UINT64*)(CardData->IndentifyDeviceData.MaximumLBA);
3819b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  MaxSize = MultU64x32 (MaxSize, 512);
3829b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3839b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  Remainder = 0;
3849b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData->BlockNumber = DivU64x32Remainder (MaxSize, CardData->BlockIoMedia.BlockSize, &Remainder);
3859b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  ASSERT(Remainder == 0);
3869b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3879b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  CardData->BlockIoMedia.LastBlock        = (EFI_LBA)(CardData->BlockNumber - 1);
3889b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3899b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3909b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael KinneyExit:
3919b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney  return Status;
3929b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3939b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney}
3949b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3959b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
3969b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164Michael Kinney
397