Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/Ata.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/Ata.c	(revision 33024)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/Ata.c	(revision 33024)
@@ -0,0 +1,2798 @@
+/** @file
+  This file contains all helper functions on the ATA command 
+  
+  Copyright (c) 2006 - 2008, Intel Corporation.<BR>
+  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.
+
+  @par Revision Reference:
+  2002-6: Add Atapi6 enhancement, support >120GB hard disk, including
+  update - ATAIdentity() func
+  update - AtaBlockIoReadBlocks() func
+  update - AtaBlockIoWriteBlocks() func
+  add    - AtaAtapi6Identify() func
+  add    - AtaReadSectorsExt() func
+  add    - AtaWriteSectorsExt() func
+  add    - AtaPioDataInExt() func
+  add    - AtaPioDataOutExt() func
+
+**/
+
+#include "IdeBus.h"
+/**
+  This function is called by ATAIdentify() to identity whether this disk
+  supports ATA/ATAPI6 48bit addressing, ie support >120G capacity
+
+  @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+                all the information of the IDE device.
+
+  @retval EFI_SUCCESS       The disk specified by IdeDev is a Atapi6 supported one and 
+                            48-bit addressing must be used
+  @retval EFI_UNSUPPORTED   The disk dosn't not support Atapi6 or it supports but the 
+                            capacity is below 120G, 48bit addressing is not needed
+  @retval  EFI_DEVICE_ERROR      The identify data in IdeDev is incorrect
+  @retval  EFI_INVALID_PARAMETER The identify data in IdeDev is NULL.
+
+  @note  This function must be called after DEVICE_IDENTITY command has been
+          successfully returned
+
+**/
+EFI_STATUS
+AtaAtapi6Identify (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  )
+{
+  UINT8             Index;
+  EFI_LBA           TmpLba;
+  EFI_LBA           Capacity;
+  EFI_IDENTIFY_DATA *Atapi6IdentifyStruct;
+
+  if (IdeDev->IdData == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Atapi6IdentifyStruct = IdeDev->IdData;
+
+  if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & (BIT15 | BIT14)) != 0x4000) {
+    //
+    // Per ATA-6 spec, word83: bit15 is zero and bit14 is one
+    //
+    return EFI_DEVICE_ERROR;
+  }
+
+  if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & BIT10) == 0) {
+    //
+    // The device dosn't support 48 bit addressing
+    //
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // 48 bit address feature set is supported, get maximum capacity
+  //
+  Capacity = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[0];
+  for (Index = 1; Index < 4; Index++) {
+    //
+    // Lower byte goes first: word[100] is the lowest word, word[103] is highest
+    //
+    TmpLba = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[Index];
+    Capacity |= LShiftU64 (TmpLba, 16 * Index);
+  }
+
+  if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {
+    //
+    // Capacity exceeds 120GB. 48-bit addressing is really needed
+    //
+    IdeDev->Type = Ide48bitAddressingHardDisk;
+
+    //
+    // Fill block media information:Media->LogicalPartition ,
+    // Media->WriteCaching will be filledin the DiscoverIdeDevcie() function.
+    //
+    IdeDev->BlkIo.Media->IoAlign        = 4;
+    IdeDev->BlkIo.Media->MediaId        = 1;
+    IdeDev->BlkIo.Media->RemovableMedia = FALSE;
+    IdeDev->BlkIo.Media->MediaPresent   = TRUE;
+    IdeDev->BlkIo.Media->ReadOnly       = FALSE;
+    IdeDev->BlkIo.Media->BlockSize      = 0x200;
+    IdeDev->BlkIo.Media->LastBlock      = Capacity - 1;
+
+    return EFI_SUCCESS;
+  }
+
+  return EFI_UNSUPPORTED;
+}
+/**
+  Enable SMART of the disk if supported
+
+  @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to record 
+                all the information of the IDE device.
+**/
+VOID
+AtaSMARTSupport (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  )
+{
+  EFI_STATUS        Status;
+  BOOLEAN           SMARTSupported;
+  UINT8             Device;
+  EFI_IDENTIFY_DATA *TmpAtaIdentifyPointer;
+  UINT8             DeviceSelect;
+  UINT8             LBAMid;
+  UINT8             LBAHigh;
+
+  //
+  // Detect if the device supports S.M.A.R.T.
+  //
+  if ((IdeDev->IdData->AtaData.command_set_supported_83 & 0xc000) != 0x4000) {
+    //
+    // Data in word 82 is not valid (bit15 shall be zero and bit14 shall be to one)
+    //
+    return ;
+  } else {
+    if ((IdeDev->IdData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {
+      //
+      // S.M.A.R.T is not supported by the device
+      //
+      SMARTSupported = FALSE;
+    } else {
+      SMARTSupported = TRUE;
+    }
+  }
+
+  if (!SMARTSupported) {
+    //
+    // Report nonsupport status code
+    //
+    REPORT_STATUS_CODE (
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,
+      (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)
+      );
+  } else {
+    //
+    // Enable this feature
+    //
+    REPORT_STATUS_CODE (
+      EFI_PROGRESS_CODE,
+      (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)
+      );
+
+    Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);
+    Status = AtaNonDataCommandIn (
+              IdeDev,
+              ATA_CMD_SMART,
+              Device,
+              ATA_SMART_ENABLE_OPERATION,
+              0,
+              0,
+              ATA_CONSTANT_4F,
+              ATA_CONSTANT_C2
+              );
+    //
+    // Detect if this feature is enabled
+    //
+    TmpAtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));
+    if (TmpAtaIdentifyPointer == NULL) {
+      return;
+    }
+
+    DeviceSelect          = (UINT8) ((IdeDev->Device) << 4);
+    Status = AtaPioDataIn (
+              IdeDev,
+              (VOID *) TmpAtaIdentifyPointer,
+              sizeof (EFI_IDENTIFY_DATA),
+              ATA_CMD_IDENTIFY_DRIVE,
+              DeviceSelect,
+              0,
+              0,
+              0,
+              0
+              );
+    if (EFI_ERROR (Status)) {
+      gBS->FreePool (TmpAtaIdentifyPointer);
+      return ;
+    }
+
+    //
+    // Check if the feature is enabled
+    //
+    if ((TmpAtaIdentifyPointer->AtaData.command_set_feature_enb_85 & 0x0001) == 0x0001) {
+      //
+      // Read status data
+      //
+      AtaNonDataCommandIn (
+        IdeDev,
+        ATA_CMD_SMART,
+        Device,
+        ATA_SMART_RETURN_STATUS,
+        0,
+        0,
+        ATA_CONSTANT_4F,
+        ATA_CONSTANT_C2
+        );
+      LBAMid  = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);
+      LBAHigh = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb);
+
+      if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {
+        //
+        // The threshold exceeded condition is not detected by the device
+        //
+        REPORT_STATUS_CODE (
+              EFI_PROGRESS_CODE,
+              (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)
+              );
+
+      } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {
+        //
+        // The threshold exceeded condition is  detected by the device
+        //
+        REPORT_STATUS_CODE (
+              EFI_PROGRESS_CODE,
+              (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)
+              );
+      }
+
+    } else {
+      //
+      // Report disabled status code
+      //
+      REPORT_STATUS_CODE (
+            EFI_ERROR_CODE | EFI_ERROR_MINOR,
+            (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)
+            );
+    }
+
+    gBS->FreePool (TmpAtaIdentifyPointer);
+  }
+
+  return ;
+}
+/**
+  Sends out an ATA Identify Command to the specified device.
+
+  This function is called by DiscoverIdeDevice() during its device
+  identification. It sends out the ATA Identify Command to the
+  specified device. Only ATA device responses to this command. If
+  the command succeeds, it returns the Identify data structure which
+  contains information about the device. This function extracts the
+  information it needs to fill the IDE_BLK_IO_DEV data structure,
+  including device type, media block size, media capacity, and etc.
+
+  @param IdeDev  pointer pointing to IDE_BLK_IO_DEV data structure,used to record 
+                 all the information of the IDE device.
+
+  @retval EFI_SUCCESS      Identify ATA device successfully.
+  @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device.
+  @note  parameter IdeDev will be updated in this function.
+
+**/
+EFI_STATUS
+ATAIdentify (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  )
+{
+  EFI_STATUS        Status;
+  EFI_IDENTIFY_DATA *AtaIdentifyPointer;
+  UINT32            Capacity;
+  UINT8             DeviceSelect;
+  UINTN				Retry;
+
+  //
+  //  AtaIdentifyPointer is used for accommodating returned IDENTIFY data of
+  //  the ATA Identify command
+  //
+  AtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));
+  if (AtaIdentifyPointer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  //  use ATA PIO Data In protocol to send ATA Identify command
+  //  and receive data from device
+  //
+  DeviceSelect  = (UINT8) ((IdeDev->Device) << 4);
+
+  
+  Retry = 3;
+  while (Retry > 0) {	
+    Status = AtaPioDataIn (
+              IdeDev,
+              (VOID *) AtaIdentifyPointer,
+              sizeof (EFI_IDENTIFY_DATA),
+              ATA_CMD_IDENTIFY_DRIVE,
+              DeviceSelect,
+              0,
+              0,
+              0,
+              0
+              );
+    //
+    // If ATA Identify command succeeds, then according to the received
+    // IDENTIFY data,
+    // identify the device type ( ATA or not ).
+    // If ATA device, fill the information in IdeDev.
+    // If not ATA device, return IDE_DEVICE_ERROR
+    //
+    if (!EFI_ERROR (Status)) {
+
+      IdeDev->IdData = AtaIdentifyPointer;
+
+      //
+      // Print ATA Module Name
+      //
+      PrintAtaModuleName (IdeDev);
+
+      //
+      // bit 15 of pAtaIdentify->config is used to identify whether device is
+      // ATA device or ATAPI device.
+      // if 0, means ATA device; if 1, means ATAPI device.
+      //
+      if ((AtaIdentifyPointer->AtaData.config & 0x8000) == 0x00) {
+        //
+        // Detect if support S.M.A.R.T. If yes, enable it as default
+        //
+        AtaSMARTSupport (IdeDev);
+
+        //
+        // Check whether this device needs 48-bit addressing (ATAPI-6 ata device)
+        //
+        Status = AtaAtapi6Identify (IdeDev);
+        if (!EFI_ERROR (Status)) {
+          //
+          // It's a disk with >120GB capacity, initialized in AtaAtapi6Identify()
+          //
+          return EFI_SUCCESS;
+        } else if (Status == EFI_DEVICE_ERROR) {
+		  //
+		  // Some disk with big capacity (>200GB) is slow when being identified
+		  // and will return all zero for word83.
+		  // We try twice at first. If it fails, we do a SoftRest and try again.
+		  //
+		  Retry--;
+		  if (Retry == 1) {
+		    //
+		    // Do a SoftRest before the third attempt.
+		    //
+		    AtaSoftReset (IdeDev);
+		  }
+		  continue;
+	    }
+        //
+        // This is a hard disk <= 120GB capacity, treat it as normal hard disk
+        //
+        IdeDev->Type = IdeHardDisk;
+
+        //
+        // Block Media Information:
+        // Media->LogicalPartition , Media->WriteCaching will be filled
+        // in the DiscoverIdeDevcie() function.
+        //
+        IdeDev->BlkIo.Media->IoAlign        = 4;
+        IdeDev->BlkIo.Media->MediaId        = 1;
+        IdeDev->BlkIo.Media->RemovableMedia = FALSE;
+        IdeDev->BlkIo.Media->MediaPresent   = TRUE;
+        IdeDev->BlkIo.Media->ReadOnly       = FALSE;
+        IdeDev->BlkIo.Media->BlockSize      = 0x200;
+
+        //
+        // Calculate device capacity
+        //
+        Capacity = ((UINT32)AtaIdentifyPointer->AtaData.user_addressable_sectors_hi << 16) |
+                  AtaIdentifyPointer->AtaData.user_addressable_sectors_lo ;
+        IdeDev->BlkIo.Media->LastBlock = Capacity - 1;
+
+        return EFI_SUCCESS;
+      }
+
+    }
+  	break;
+  }
+
+  gBS->FreePool (AtaIdentifyPointer);
+  //
+  // Make sure the pIdData will not be freed again.
+  //
+  IdeDev->IdData = NULL;
+
+  return EFI_DEVICE_ERROR;
+}
+
+/**
+  This function is a helper function used to change the char order in a string. It
+  is designed specially for the PrintAtaModuleName() function. After the IDE device 
+  is detected, the IDE driver gets the device module name by sending ATA command 
+  called ATA Identify Command or ATAPI Identify Command to the specified IDE device.
+  The module name returned is a string of ASCII characters: the first character is bit8--bit15
+  of the first word, the second character is BIT0--bit7 of the first word and so on. Thus
+  the string can not be print directly before it is preprocessed by this func to change 
+  the order of characters in each word in the string.
+
+  @param Destination Indicates the destination string.
+  @param Source      Indicates the source string.
+  @param Size         the length of the string
+**/
+VOID
+SwapStringChars (
+  IN CHAR8  *Destination,
+  IN CHAR8  *Source,
+  IN UINT32 Size
+  )
+{
+  UINT32  Index;
+  CHAR8   Temp;
+
+  for (Index = 0; Index < Size; Index += 2) {
+
+    Temp                    = Source[Index + 1];
+    Destination[Index + 1]  = Source[Index];
+    Destination[Index]      = Temp;
+  }
+}
+/**
+  This function is called by ATAIdentify() or ATAPIIdentify() to print device's module name.
+
+  @param  IdeDev   pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+                   all the information of the IDE device.
+**/
+VOID
+PrintAtaModuleName (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  )
+{
+  if (IdeDev->IdData == NULL) {
+    return ;
+  }
+
+  SwapStringChars (IdeDev->ModelName, IdeDev->IdData->AtaData.ModelName, 40);
+  IdeDev->ModelName[40] = 0x00;
+}
+
+/**
+  This function is used to send out ATA commands conforms to the PIO Data In Protocol.
+
+  @param IdeDev       pointer pointing to IDE_BLK_IO_DEV data structure, used to record 
+                      all the information of the IDE device.
+  @param Buffer       buffer contained data transferred from device to host.
+  @param ByteCount    data size in byte unit of the buffer.
+  @param AtaCommand   value of the Command Register
+  @param Head         value of the Head/Device Register
+  @param SectorCount  value of the Sector Count Register
+  @param SectorNumber value of the Sector Number Register
+  @param CylinderLsb  value of the low byte of the Cylinder Register
+  @param CylinderMsb  value of the high byte of the Cylinder Register
+  
+  @retval EFI_SUCCESS      send out the ATA command and device send required data successfully.
+  @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+EFI_STATUS
+AtaPioDataIn (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  VOID            *Buffer,
+  IN  UINT32          ByteCount,
+  IN  UINT8           AtaCommand,
+  IN  UINT8           Head,
+  IN  UINT8           SectorCount,
+  IN  UINT8           SectorNumber,
+  IN  UINT8           CylinderLsb,
+  IN  UINT8           CylinderMsb
+  )
+{
+  UINTN       WordCount;
+  UINTN       Increment;
+  UINT16      *Buffer16;
+  EFI_STATUS  Status;
+
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  //  e0:1110,0000-- bit7 and bit5 are reserved bits.
+  //           bit6 set means LBA mode
+  //
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->Head,
+    (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head)
+    );
+
+  //
+  // All ATAPI device's ATA commands can be issued regardless of the
+  // state of the DRDY
+  //
+  if (IdeDev->Type == IdeHardDisk) {
+
+    Status = DRDYReady (IdeDev, ATATIMEOUT);
+    if (EFI_ERROR (Status)) {
+      return EFI_DEVICE_ERROR;
+    }
+  }
+  //
+  // set all the command parameters
+  // Before write to all the following registers, BSY and DRQ must be 0.
+  //
+  Status = DRQClear2 (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (AtaCommand == ATA_CMD_SET_FEATURES) {
+    IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);
+  }
+
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb);
+
+  //
+  // send command via Command Register
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+  Buffer16 = (UINT16 *) Buffer;
+
+  //
+  // According to PIO data in protocol, host can perform a series of reads to
+  // the data register after each time device set DRQ ready;
+  // The data size of "a series of read" is command specific.
+  // For most ATA command, data size received from device will not exceed
+  // 1 sector, hence the data size for "a series of read" can be the whole data
+  // size of one command request.
+  // For ATA command such as Read Sector command, the data size of one ATA
+  // command request is often larger than 1 sector, according to the
+  // Read Sector command, the data size of "a series of read" is exactly 1
+  // sector.
+  // Here for simplification reason, we specify the data size for
+  // "a series of read" to 1 sector (256 words) if data size of one ATA command
+  // request is larger than 256 words.
+  //
+  Increment = 256;
+
+  //
+  // used to record bytes of currently transfered data
+  //
+  WordCount = 0;
+
+  while (WordCount < ByteCount / 2) {
+    //
+    // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.
+    //
+    Status = DRQReady2 (IdeDev, ATATIMEOUT);
+    if (EFI_ERROR (Status)) {
+      return EFI_DEVICE_ERROR;
+    }
+
+    Status = CheckErrorStatus (IdeDev);
+    if (EFI_ERROR (Status)) {
+      return EFI_DEVICE_ERROR;
+    }
+
+    //
+    // Get the byte count for one series of read
+    //
+    if ((WordCount + Increment) > ByteCount / 2) {
+      Increment = ByteCount / 2 - WordCount;
+    }
+
+    IDEReadPortWMultiple (
+      IdeDev->PciIo,
+      IdeDev->IoPort->Data,
+      Increment,
+      Buffer16
+      );
+
+    WordCount += Increment;
+    Buffer16 += Increment;
+
+  }
+
+  DRQClear (IdeDev, ATATIMEOUT);
+
+  return CheckErrorStatus (IdeDev);
+}
+
+/**
+  This function is used to send out ATA commands conforms to the
+  PIO Data Out Protocol.
+
+  @param IdeDev       pointer pointing to IDE_BLK_IO_DEV data structure, used
+                      to record all the information of the IDE device.
+  @param *Buffer      buffer contained data transferred from host to device.
+  @param ByteCount    data size in byte unit of the buffer.
+  @param AtaCommand   value of the Command Register
+  @param Head         value of the Head/Device Register
+  @param SectorCount  value of the Sector Count Register
+  @param SectorNumber value of the Sector Number Register
+  @param CylinderLsb  value of the low byte of the Cylinder Register
+  @param CylinderMsb  value of the high byte of the Cylinder Register
+
+  @retval EFI_SUCCESS      send out the ATA command and device received required
+                           data successfully.
+  @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+EFI_STATUS
+AtaPioDataOut (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  VOID            *Buffer,
+  IN  UINT32          ByteCount,
+  IN  UINT8           AtaCommand,
+  IN  UINT8           Head,
+  IN  UINT8           SectorCount,
+  IN  UINT8           SectorNumber,
+  IN  UINT8           CylinderLsb,
+  IN  UINT8           CylinderMsb
+  )
+{
+  UINTN       WordCount;
+  UINTN       Increment;
+  UINT16      *Buffer16;
+  EFI_STATUS  Status;
+
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // select device via Head/Device register.
+  // Before write Head/Device register, BSY and DRQ must be 0.
+  //
+  Status = DRQClear2 (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // e0:1110,0000-- bit7 and bit5 are reserved bits.
+  //          bit6 set means LBA mode
+  //
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->Head,
+    (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head)
+    );
+
+  Status = DRDYReady (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // set all the command parameters
+  // Before write to all the following registers, BSY and DRQ must be 0.
+  //
+  Status = DRQClear2 (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb);
+
+  //
+  // send command via Command Register
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+  Buffer16 = (UINT16 *) Buffer;
+
+  //
+  // According to PIO data out protocol, host can perform a series of
+  // writes to the data register after each time device set DRQ ready;
+  // The data size of "a series of read" is command specific.
+  // For most ATA command, data size written to device will not exceed 1 sector,
+  // hence the data size for "a series of write" can be the data size of one
+  // command request.
+  // For ATA command such as Write Sector command, the data size of one
+  // ATA command request is often larger than 1 sector, according to the
+  // Write Sector command, the data size of "a series of read" is exactly
+  // 1 sector.
+  // Here for simplification reason, we specify the data size for
+  // "a series of write" to 1 sector (256 words) if data size of one ATA command
+  // request is larger than 256 words.
+  //
+  Increment = 256;
+  WordCount = 0;
+
+  while (WordCount < ByteCount / 2) {
+
+    //
+    // DRQReady2-- read Alternate Status Register to determine the DRQ bit
+    // data transfer can be performed only when DRQ is ready.
+    //
+    Status = DRQReady2 (IdeDev, ATATIMEOUT);
+    if (EFI_ERROR (Status)) {
+      return EFI_DEVICE_ERROR;
+    }
+
+    Status = CheckErrorStatus (IdeDev);
+    if (EFI_ERROR (Status)) {
+      return EFI_DEVICE_ERROR;
+    }
+
+   //
+   // Check the remaining byte count is less than 512 bytes
+   //
+   if ((WordCount + Increment) > ByteCount / 2) {
+      Increment = ByteCount / 2 - WordCount;
+    }
+    //
+    // perform a series of write without check DRQ ready
+    //
+
+    IDEWritePortWMultiple (
+      IdeDev->PciIo,
+      IdeDev->IoPort->Data,
+      Increment,
+      Buffer16
+      );
+    WordCount += Increment;
+    Buffer16 += Increment;
+
+  }
+
+  DRQClear (IdeDev, ATATIMEOUT);
+
+  return CheckErrorStatus (IdeDev);
+}
+
+/**
+  This function is used to analyze the Status Register and print out
+  some debug information and if there is ERR bit set in the Status
+  Register, the Error Register's value is also be parsed and print out.
+
+  @param IdeDev  pointer pointing to IDE_BLK_IO_DEV data structure, used to 
+                 record all the information of the IDE device.
+
+  @retval EFI_SUCCESS       No err information in the Status Register.
+  @retval EFI_DEVICE_ERROR  Any err information in the Status Register.
+
+**/
+EFI_STATUS
+CheckErrorStatus (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  )
+{
+  UINT8 StatusRegister;
+  UINT8 ErrorRegister;
+
+  StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+  DEBUG_CODE_BEGIN ();
+
+  if ((StatusRegister & ATA_STSREG_DWF) != 0) {
+    DEBUG (
+      (EFI_D_BLKIO,
+      "CheckErrorStatus()-- %02x : Error : Write Fault\n",
+      StatusRegister)
+      );
+  }
+
+  if ((StatusRegister & ATA_STSREG_CORR) != 0) {
+    DEBUG (
+      (EFI_D_BLKIO,
+      "CheckErrorStatus()-- %02x : Error : Corrected Data\n",
+      StatusRegister)
+      );
+   }
+
+  if ((StatusRegister & ATA_STSREG_ERR) != 0) {
+    ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+
+    if ((ErrorRegister & ATA_ERRREG_BBK) != 0) {
+      DEBUG (
+        (EFI_D_BLKIO,
+        "CheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
+        ErrorRegister)
+        );
+      }
+
+      if ((ErrorRegister & ATA_ERRREG_UNC) != 0) {
+        DEBUG (
+          (EFI_D_BLKIO,
+          "CheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
+          ErrorRegister)
+          );
+      }
+
+      if ((ErrorRegister & ATA_ERRREG_MC) != 0) {
+        DEBUG (
+          (EFI_D_BLKIO,
+          "CheckErrorStatus()-- %02x : Error : Media Change\n",
+          ErrorRegister)
+          );
+      }
+
+      if ((ErrorRegister & ATA_ERRREG_ABRT) != 0) {
+        DEBUG (
+          (EFI_D_BLKIO,
+          "CheckErrorStatus()-- %02x : Error : Abort\n",
+          ErrorRegister)
+          );
+      }
+
+      if ((ErrorRegister & ATA_ERRREG_TK0NF) != 0) {
+        DEBUG (
+          (EFI_D_BLKIO,
+          "CheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
+          ErrorRegister)
+          );
+      }
+
+      if ((ErrorRegister & ATA_ERRREG_AMNF) != 0) {
+        DEBUG (
+          (EFI_D_BLKIO,
+          "CheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
+          ErrorRegister)
+          );
+      }
+    }
+
+  DEBUG_CODE_END ();
+
+  if ((StatusRegister & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {
+    return EFI_SUCCESS;
+  }
+
+  return EFI_DEVICE_ERROR;
+
+}
+
+/**
+  This function is called by the AtaBlkIoReadBlocks() to perform reading from 
+  media in block unit.
+
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure, used to record 
+                        all the information of the IDE device.
+  @param DataBuffer     A pointer to the destination buffer for the data.
+  @param Lba            The starting logical block address to read from on the device media.
+  @param NumberOfBlocks The number of transfer data blocks.
+  
+  @return status is fully dependent on the return status of AtaPioDataIn() function.
+
+**/
+EFI_STATUS
+AtaReadSectors (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  VOID            *DataBuffer,
+  IN  EFI_LBA         Lba,
+  IN  UINTN           NumberOfBlocks
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       BlocksRemaining;
+  UINT32      Lba32;
+  UINT8       Lba0;
+  UINT8       Lba1;
+  UINT8       Lba2;
+  UINT8       Lba3;
+  UINT8       AtaCommand;
+  UINT8       SectorCount8;
+  UINT16      SectorCount;
+  UINTN       ByteCount;
+  VOID        *Buffer;
+
+  Buffer = DataBuffer;
+
+  //
+  // Using ATA Read Sector(s) command (opcode=0x20) with PIO DATA IN protocol
+  //
+  AtaCommand      = ATA_CMD_READ_SECTORS;
+
+
+  BlocksRemaining = NumberOfBlocks;
+
+  Lba32           = (UINT32) Lba;
+
+  Status          = EFI_SUCCESS;
+
+  while (BlocksRemaining > 0) {
+
+    //
+    // in ATA-3 spec, LBA is in 28 bit width
+    //
+    Lba0  = (UINT8) Lba32;
+    Lba1  = (UINT8) (Lba32 >> 8);
+    Lba2  = (UINT8) (Lba32 >> 16);
+    //
+    // low 4 bit of Lba3 stands for LBA bit24~bit27.
+    //
+    Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f);
+
+    if (BlocksRemaining >= 0x100) {
+
+      //
+      //  SectorCount8 is sent to Sector Count register, 0x00 means 256
+      //  sectors to be read
+      //
+      SectorCount8 = 0x00;
+      //
+      //  SectorCount is used to record the number of sectors to be read
+      //
+      SectorCount = 256;
+    } else {
+
+      SectorCount8  = (UINT8) BlocksRemaining;
+      SectorCount   = (UINT16) BlocksRemaining;
+    }
+
+    //
+    // ByteCount is the number of bytes that will be read
+    //
+    ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);
+
+    //
+    // call AtaPioDataIn() to send Read Sector Command and receive data read
+    //
+    Status = AtaPioDataIn (
+              IdeDev,
+              Buffer,
+              (UINT32) ByteCount,
+              AtaCommand,
+              Lba3,
+              SectorCount8,
+              Lba0,
+              Lba1,
+              Lba2
+              );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Lba32 += SectorCount;
+    Buffer = ((UINT8 *) Buffer + ByteCount);
+    BlocksRemaining -= SectorCount;
+  }
+
+  return Status;
+}
+
+/**
+  This function is called by the AtaBlkIoWriteBlocks() to perform writing onto 
+  media in block unit.
+
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure,used to record
+                        all the information of the IDE device.
+  @param BufferData     A pointer to the source buffer for the data.
+  @param Lba            The starting logical block address to write onto the device media.
+  @param NumberOfBlocks The number of transfer data blocks.
+  
+  @return status is fully dependent on the return status of AtaPioDataIn() function.
+
+**/
+EFI_STATUS
+AtaWriteSectors (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  VOID            *BufferData,
+  IN  EFI_LBA         Lba,
+  IN  UINTN           NumberOfBlocks
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       BlocksRemaining;
+  UINT32      Lba32;
+  UINT8       Lba0;
+  UINT8       Lba1;
+  UINT8       Lba2;
+  UINT8       Lba3;
+  UINT8       AtaCommand;
+  UINT8       SectorCount8;
+  UINT16      SectorCount;
+  UINTN       ByteCount;
+  VOID        *Buffer;
+
+  Buffer = BufferData;
+
+  //
+  // Using Write Sector(s) command (opcode=0x30) with PIO DATA OUT protocol
+  //
+  AtaCommand      = ATA_CMD_WRITE_SECTORS;
+
+  BlocksRemaining = NumberOfBlocks;
+
+  Lba32           = (UINT32) Lba;
+
+  Status          = EFI_SUCCESS;
+
+  while (BlocksRemaining > 0) {
+
+    Lba0  = (UINT8) Lba32;
+    Lba1  = (UINT8) (Lba32 >> 8);
+    Lba2  = (UINT8) (Lba32 >> 16);
+    Lba3  = (UINT8) ((Lba32 >> 24) & 0x0f);
+
+    if (BlocksRemaining >= 0x100) {
+
+      //
+      //  SectorCount8 is sent to Sector Count register, 0x00 means 256 sectors
+      //  to be written
+      //
+      SectorCount8 = 0x00;
+      //
+      //  SectorCount is used to record the number of sectors to be written
+      //
+      SectorCount = 256;
+    } else {
+
+      SectorCount8  = (UINT8) BlocksRemaining;
+      SectorCount   = (UINT16) BlocksRemaining;
+    }
+
+    ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);
+
+    Status = AtaPioDataOut (
+              IdeDev,
+              Buffer,
+              (UINT32) ByteCount,
+              AtaCommand,
+              Lba3,
+              SectorCount8,
+              Lba0,
+              Lba1,
+              Lba2
+              );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Lba32 += SectorCount;
+    Buffer = ((UINT8 *) Buffer + ByteCount);
+    BlocksRemaining -= SectorCount;
+  }
+
+  return Status;
+}
+/**
+  This function is used to implement the Soft Reset on the specified device. But,
+  the ATA Soft Reset mechanism is so strong a reset method that it will force 
+  resetting on both devices connected to the same cable.
+
+  It is called by IdeBlkIoReset(), a interface function of Block
+  I/O protocol.
+
+  This function can also be used by the ATAPI device to perform reset when
+  ATAPI Reset command is failed.
+
+  @param IdeDev  pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+                 all the information of the IDE device.
+  @retval EFI_SUCCESS       Soft reset completes successfully.
+  @retval EFI_DEVICE_ERROR  Any step during the reset process is failed.
+
+  @note  The registers initial values after ATA soft reset are different
+         to the ATA device and ATAPI device.
+**/
+EFI_STATUS
+AtaSoftReset (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  )
+{
+
+  UINT8 DeviceControl;
+
+  DeviceControl = 0;
+  //
+  // set SRST bit to initiate soft reset
+  //
+  DeviceControl |= ATA_CTLREG_SRST;
+
+  //
+  // disable Interrupt
+  //
+  DeviceControl |= BIT1;
+
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+  //
+  // SRST should assert for at least 5 us, we use 10 us for
+  // better compatibility
+  //
+  gBS->Stall (10);
+
+  //
+  // Enable interrupt to support UDMA, and clear SRST bit
+  //
+  DeviceControl = 0;
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+  //
+  // Wait for at least 2 ms to check BSY status, we use 10 ms
+  // for better compatibility
+  //
+  gBS->Stall(10000);
+  //
+  // slave device needs at most 31s to clear BSY
+  //
+  if (WaitForBSYClear (IdeDev, 31000) == EFI_TIMEOUT) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+/**
+  This function is used to send out ATA commands conforms to the PIO Data In 
+  Protocol, supporting ATA/ATAPI-6 standard
+
+  Comparing with ATA-3 data in protocol, we have two differents here:
+  1. Do NOT wait for DRQ clear before sending command into IDE device.(the
+  wait will frequently fail... cause writing function return error)
+
+  2. Do NOT wait for DRQ clear after all data readed.(the wait greatly
+  slow down writing performance by 100 times!)
+
+  @param IdeDev       pointer pointing to IDE_BLK_IO_DEV data structure, used
+                      to record all the information of the IDE device.
+  @param Buffer       buffer contained data transferred from device to host.
+  @param ByteCount    data size in byte unit of the buffer.
+  @param AtaCommand   value of the Command Register
+  @param StartLba     the start LBA of this transaction
+  @param SectorCount  the count of sectors to be transfered
+
+  @retval EFI_SUCCESS      send out the ATA command and device send required data successfully.
+  @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+EFI_STATUS
+AtaPioDataInExt (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  OUT VOID        *Buffer,
+  IN  UINT32          ByteCount,
+  IN  UINT8           AtaCommand,
+  IN  EFI_LBA         StartLba,
+  IN  UINT16          SectorCount
+  )
+{
+  UINT8       DevSel;
+  UINT8       SectorCount8;
+  UINT8       LbaLow;
+  UINT8       LbaMid;
+  UINT8       LbaHigh;
+  UINTN       WordCount;
+  UINTN       Increment;
+  UINT16      *Buffer16;
+  EFI_STATUS  Status;
+
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Select device, set bit6 as 1 to indicate LBA mode is used
+  //
+  DevSel = (UINT8) (IdeDev->Device << 4);
+  DevSel |= 0x40;
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->Head,
+    DevSel
+    );
+
+  //
+  // Wait for DRDY singnal asserting. ATAPI device needn't wait
+  //
+  if ( (IdeDev->Type == IdeHardDisk)  ||
+        (IdeDev->Type == Ide48bitAddressingHardDisk)) {
+
+    Status = DRDYReady (IdeDev, ATATIMEOUT);
+    if (EFI_ERROR (Status)) {
+      return EFI_DEVICE_ERROR;
+    }
+  }
+
+  //
+  // Fill feature register if needed
+  //
+  if (AtaCommand == ATA_CMD_SET_FEATURES) {
+    IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);
+  }
+
+  //
+  // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+  //
+  SectorCount8 = (UINT8) (SectorCount >> 8);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+  SectorCount8 = (UINT8) SectorCount;
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+  //
+  // Fill the start LBA registers, which are also two-byte FIFO
+  //
+  LbaLow  = (UINT8) RShiftU64 (StartLba, 24);
+  LbaMid  = (UINT8) RShiftU64 (StartLba, 32);
+  LbaHigh = (UINT8) RShiftU64 (StartLba, 40);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+  LbaLow  = (UINT8) StartLba;
+  LbaMid  = (UINT8) RShiftU64 (StartLba, 8);
+  LbaHigh = (UINT8) RShiftU64 (StartLba, 16);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+  //
+  // Send command via Command Register, invoking the processing of this command
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+  Buffer16 = (UINT16 *) Buffer;
+
+  //
+  // According to PIO data in protocol, host can perform a series of reads to
+  // the data register after each time device set DRQ ready;
+  //
+
+  //
+  // 256 words
+  //
+  Increment = 256;
+
+  //
+  // used to record bytes of currently transfered data
+  //
+  WordCount = 0;
+
+  while (WordCount < ByteCount / 2) {
+    //
+    // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.
+    //
+    Status = DRQReady2 (IdeDev, ATATIMEOUT);
+    if (EFI_ERROR (Status)) {
+      return EFI_DEVICE_ERROR;
+    }
+
+    Status = CheckErrorStatus (IdeDev);
+    if (EFI_ERROR (Status)) {
+      return EFI_DEVICE_ERROR;
+    }
+
+    //
+    // Get the byte count for one series of read
+    //
+    if ((WordCount + Increment) > ByteCount / 2) {
+      Increment = ByteCount / 2 - WordCount;
+    }
+
+    IDEReadPortWMultiple (
+      IdeDev->PciIo,
+      IdeDev->IoPort->Data,
+      Increment,
+      Buffer16
+      );
+
+    WordCount += Increment;
+    Buffer16 += Increment;
+
+  }
+
+  return CheckErrorStatus (IdeDev);
+}
+/**
+  Send ATA Ext command into device with NON_DATA protocol.
+
+  @param  IdeDev Standard IDE device private data structure
+  @param  AtaCommand The ATA command to be sent
+  @param  Device The value in Device register
+  @param  Feature The value in Feature register
+  @param  SectorCount The value in SectorCount register
+  @param  LbaAddress The LBA address in 48-bit mode
+
+  @retval  EFI_SUCCESS Reading succeed
+  @retval  EFI_DEVICE_ERROR Error executing commands on this device.
+
+**/
+EFI_STATUS
+AtaCommandIssueExt (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINT8           AtaCommand,
+  IN  UINT8           Device,
+  IN  UINT16          Feature,
+  IN  UINT16          SectorCount,
+  IN  EFI_LBA         LbaAddress
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       SectorCount8;
+  UINT8       Feature8;
+  UINT8       LbaLow;
+  UINT8       LbaMid;
+  UINT8       LbaHigh;
+
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
+  //
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->Head,
+    (UINT8) ((IdeDev->Device << 4) | 0xe0)
+    );
+
+  //
+  // ATA commands for ATA device must be issued when DRDY is set
+  //
+  Status = DRDYReady (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Pass parameter into device register block
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+
+  //
+  // Fill the feature register, which is a two-byte FIFO. Need write twice.
+  //
+  Feature8 = (UINT8) (Feature >> 8);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
+
+  Feature8 = (UINT8) Feature;
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
+
+  //
+  // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+  //
+  SectorCount8 = (UINT8) (SectorCount >> 8);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+  SectorCount8 = (UINT8) SectorCount;
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+  //
+  // Fill the start LBA registers, which are also two-byte FIFO
+  //
+  LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+  LbaLow = (UINT8) LbaAddress;
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+
+  LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+  LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+
+  LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+  LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+  //
+  // Work around for Segate 160G disk writing
+  //
+  gBS->Stall (1800);
+
+  //
+  // Send command via Command Register
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+  //
+  // Stall at least 400ns
+  //
+  gBS->Stall (100);
+
+  return EFI_SUCCESS;
+}
+/**
+  Send ATA Ext command into device with NON_DATA protocol
+
+  @param  IdeDev Standard IDE device private data structure
+  @param  AtaCommand The ATA command to be sent
+  @param  Device The value in Device register
+  @param  Feature The value in Feature register
+  @param  SectorCount The value in SectorCount register
+  @param  LbaAddress The LBA address in 48-bit mode
+
+  @retval  EFI_SUCCESS Reading succeed
+  @retval  EFI_DEVICE_ERROR Error executing commands on this device.
+
+**/
+EFI_STATUS
+AtaCommandIssue (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINT8           AtaCommand,
+  IN  UINT8           Device,
+  IN  UINT16          Feature,
+  IN  UINT16          SectorCount,
+  IN  EFI_LBA         LbaAddress
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       SectorCount8;
+  UINT8       Feature8;
+  UINT8       Lba0;
+  UINT8       Lba1;
+  UINT8       Lba2;
+  UINT8       Lba3;
+
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
+  //
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->Head,
+    (UINT8) ((IdeDev->Device << 4) | 0xe0)
+    );
+
+  //
+  // ATA commands for ATA device must be issued when DRDY is set
+  //
+  Status = DRDYReady (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  Lba0  = (UINT8) LbaAddress;
+  Lba1  = (UINT8) RShiftU64 (LbaAddress, 8);
+  Lba2  = (UINT8) RShiftU64 (LbaAddress, 16);
+  Lba3  = (UINT8) RShiftU64 (LbaAddress, 24);
+  Device = (UINT8) (Device | Lba3);
+
+  //
+  // Pass parameter into device register block
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+
+  //
+  // Fill the feature register, which is a two-byte FIFO. Need write twice.
+  //
+  Feature8 = (UINT8) Feature;
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
+
+  //
+  // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+  //
+  SectorCount8 = (UINT8) SectorCount;
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+  //
+  // Fill the start LBA registers, which are also two-byte FIFO
+  //
+
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, Lba0);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, Lba1);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, Lba2);
+
+  //
+  // Send command via Command Register
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+  //
+  // Stall at least 400ns
+  //
+  gBS->Stall (100);
+
+  return EFI_SUCCESS;
+}
+/**
+  Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).
+
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure, used
+                        to record all the information of the IDE device.
+  @param DataBuffer     A pointer to the source buffer for the data.
+  @param StartLba       The starting logical block address to write to
+                        on the device media.
+  @param NumberOfBlocks The number of transfer data blocks.
+  @param UdmaOp         The perform operations could be AtaUdmaReadOp, AtaUdmaReadExOp,
+                        AtaUdmaWriteOp, AtaUdmaWriteExOp
+
+  @retval EFI_SUCCESS          the operation is successful.
+  @retval EFI_OUT_OF_RESOURCES Build PRD table failed
+  @retval EFI_UNSUPPORTED      Unknown channel or operations command
+  @retval EFI_DEVICE_ERROR     Ata command execute failed
+
+**/
+EFI_STATUS
+DoAtaUdma (
+  IN  IDE_BLK_IO_DEV      *IdeDev,
+  IN  VOID                *DataBuffer,
+  IN  EFI_LBA             StartLba,
+  IN  UINTN               NumberOfBlocks,
+  IN  ATA_UDMA_OPERATION  UdmaOp
+  )
+{
+  IDE_DMA_PRD                   *PrdAddr;
+  IDE_DMA_PRD                   *UsedPrdAddr;
+  IDE_DMA_PRD                   *TempPrdAddr;
+  UINT8                         RegisterValue;
+  UINT8                         Device;
+  UINT64                        IoPortForBmic;
+  UINT64                        IoPortForBmis;
+  UINT64                        IoPortForBmid;
+  EFI_STATUS                    Status;
+  UINTN                         PrdTableNum;
+  UINTN                         ByteCount;
+  UINTN                         ByteAvailable;
+  UINT8                         *PrdBuffer;
+  UINTN                         RemainBlockNum;
+  UINT8                         DeviceControl;
+  UINT32                        Count;
+  UINTN                         PageCount;
+  VOID                          *Map;
+  VOID                          *MemPage;
+  EFI_PHYSICAL_ADDRESS          DeviceAddress;
+  UINTN                         MaxDmaCommandSectors;
+  EFI_PCI_IO_PROTOCOL_OPERATION PciIoProtocolOp;
+  UINT8                         AtaCommand;
+
+  switch (UdmaOp) {
+  case AtaUdmaReadOp:
+    MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS;
+    PciIoProtocolOp      = EfiPciIoOperationBusMasterWrite;
+    AtaCommand           = ATA_CMD_READ_DMA;
+    break;
+  case AtaUdmaReadExtOp:
+    MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS;
+    PciIoProtocolOp      = EfiPciIoOperationBusMasterWrite;
+    AtaCommand           = ATA_CMD_READ_DMA_EXT;
+    break;
+  case AtaUdmaWriteOp:
+    MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS;
+    PciIoProtocolOp      = EfiPciIoOperationBusMasterRead;
+    AtaCommand           = ATA_CMD_WRITE_DMA;
+    break;
+  case AtaUdmaWriteExtOp:
+    MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS;
+    PciIoProtocolOp      = EfiPciIoOperationBusMasterRead;
+    AtaCommand           = ATA_CMD_WRITE_DMA_EXT;
+    break;
+  default:
+    return EFI_UNSUPPORTED;
+    break;
+  }
+
+  //
+  // Select device
+  //
+  Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+
+  //
+  // Enable interrupt to support UDMA
+  //
+  DeviceControl = 0;
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+  if (IdePrimary == IdeDev->Channel) {
+    IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;
+    IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;
+    IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;
+  } else {
+    if (IdeSecondary == IdeDev->Channel) {
+      IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;
+      IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;
+      IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;
+    } else {
+      return EFI_UNSUPPORTED;
+    }
+  }
+
+  //
+  // Read BMIS register and clear ERROR and INTR bit
+  //
+  IdeDev->PciIo->Io.Read (
+					  IdeDev->PciIo,
+					  EfiPciIoWidthUint8,
+					  EFI_PCI_IO_PASS_THROUGH_BAR,
+					  IoPortForBmis,
+					  1,
+					  &RegisterValue
+					  );
+  
+  RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);
+  
+  IdeDev->PciIo->Io.Write (
+					  IdeDev->PciIo,
+					  EfiPciIoWidthUint8,
+					  EFI_PCI_IO_PASS_THROUGH_BAR,
+					  IoPortForBmis,
+					  1,
+					  &RegisterValue
+					  );
+
+  Status = EFI_SUCCESS;
+  
+  RemainBlockNum = NumberOfBlocks;
+  while (RemainBlockNum > 0) {
+
+    if (RemainBlockNum >= MaxDmaCommandSectors) {
+      //
+      //  SectorCount is used to record the number of sectors to be read
+      //  Max 65536 sectors can be transfered at a time.
+      //
+      NumberOfBlocks = MaxDmaCommandSectors;
+      RemainBlockNum -= MaxDmaCommandSectors;
+    } else {
+      NumberOfBlocks  = (UINT16) RemainBlockNum;
+      RemainBlockNum  = 0;
+    }
+
+    //
+    // Calculate the number of PRD table to make sure the memory region
+    // not cross 64K boundary
+    //
+    ByteCount   = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;
+    PrdTableNum = ((ByteCount >> 16) + 1) + 1;
+
+    //
+    // Build PRD table
+    //
+    PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));
+    Status = IdeDev->PciIo->AllocateBuffer (
+                    IdeDev->PciIo,
+                    AllocateAnyPages,
+                    EfiBootServicesData,
+                    PageCount,
+                    &MemPage,
+                    0
+                    );
+    if (EFI_ERROR (Status)) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+    ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));
+
+    PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);
+    //
+    // To make sure PRD is allocated in one 64K page
+    //
+    if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {
+      UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);
+    } else {
+      if ((UINTN) PrdAddr & 0x03) {
+        UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);
+      } else {
+        UsedPrdAddr = PrdAddr;
+      }
+    }
+
+    //
+    // Build the PRD table
+    //
+    Status = IdeDev->PciIo->Map (
+                       IdeDev->PciIo,
+                       PciIoProtocolOp,
+                       DataBuffer,
+                       &ByteCount,
+                       &DeviceAddress,
+                       &Map
+                       );
+    if (EFI_ERROR (Status)) {
+      IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);
+      return EFI_OUT_OF_RESOURCES;
+    }
+    PrdBuffer   = (VOID *) ((UINTN) DeviceAddress);
+    TempPrdAddr = UsedPrdAddr;
+    while (TRUE) {
+
+      ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);
+
+      if (ByteCount <= ByteAvailable) {
+        TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);
+        TempPrdAddr->ByteCount      = (UINT16) ByteCount;
+        TempPrdAddr->EndOfTable     = 0x8000;
+        break;
+      }
+
+      TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);
+      TempPrdAddr->ByteCount      = (UINT16) ByteAvailable;
+
+      ByteCount -= ByteAvailable;
+      PrdBuffer += ByteAvailable;
+      TempPrdAddr++;
+    }
+
+    //
+    // Set the base address to BMID register
+    //
+    IdeDev->PciIo->Io.Write (
+                        IdeDev->PciIo,
+                        EfiPciIoWidthUint32,
+                        EFI_PCI_IO_PASS_THROUGH_BAR,
+                        IoPortForBmid,
+                        1,
+                        &UsedPrdAddr
+                        );
+
+    //
+    // Set BMIC register to identify the operation direction
+    //
+    IdeDev->PciIo->Io.Read (
+                        IdeDev->PciIo,
+                        EfiPciIoWidthUint8,
+                        EFI_PCI_IO_PASS_THROUGH_BAR,
+                        IoPortForBmic,
+                        1,
+                        &RegisterValue
+                        );
+
+    if (UdmaOp == AtaUdmaReadExtOp || UdmaOp == AtaUdmaReadOp) {
+      RegisterValue |= BMIC_NREAD;
+    } else {
+      RegisterValue &= ~((UINT8) BMIC_NREAD);
+    }
+
+    IdeDev->PciIo->Io.Write (
+                        IdeDev->PciIo,
+                        EfiPciIoWidthUint8,
+                        EFI_PCI_IO_PASS_THROUGH_BAR,
+                        IoPortForBmic,
+                        1,
+                        &RegisterValue
+                        );
+
+    if (UdmaOp == AtaUdmaWriteExtOp || UdmaOp == AtaUdmaReadExtOp) {
+      Status = AtaCommandIssueExt (
+                 IdeDev,
+                 AtaCommand,
+                 Device,
+                 0,
+                 (UINT16) NumberOfBlocks,
+                 StartLba
+                 );
+    } else {
+      Status = AtaCommandIssue (
+                 IdeDev,
+                 AtaCommand,
+                 Device,
+                 0,
+                 (UINT16) NumberOfBlocks,
+                 StartLba
+                 );
+    }
+
+    if (EFI_ERROR (Status)) {
+      IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);
+      IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
+      return EFI_DEVICE_ERROR;
+    }
+
+    //
+    // Set START bit of BMIC register
+    //
+    IdeDev->PciIo->Io.Read (
+                        IdeDev->PciIo,
+                        EfiPciIoWidthUint8,
+                        EFI_PCI_IO_PASS_THROUGH_BAR,
+                        IoPortForBmic,
+                        1,
+                        &RegisterValue
+                        );
+
+    RegisterValue |= BMIC_START;
+
+    IdeDev->PciIo->Io.Write (
+                        IdeDev->PciIo,
+                        EfiPciIoWidthUint8,
+                        EFI_PCI_IO_PASS_THROUGH_BAR,
+                        IoPortForBmic,
+                        1,
+                        &RegisterValue
+                        );
+
+    //
+    // Check the INTERRUPT and ERROR bit of BMIS
+    // Max transfer number of sectors for one command is 65536(32Mbyte),
+    // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).
+    // So set the variable Count to 2000, for about 2 second timeout time.
+    //
+    Status = EFI_SUCCESS;
+    Count = 2000;
+    while (TRUE) {
+
+      IdeDev->PciIo->Io.Read (
+                          IdeDev->PciIo,
+                          EfiPciIoWidthUint8,
+                          EFI_PCI_IO_PASS_THROUGH_BAR,
+                          IoPortForBmis,
+                          1,
+                          &RegisterValue
+                          );
+      if (((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) != 0) || (Count == 0)) {
+        if (((RegisterValue & BMIS_ERROR) != 0) || (Count == 0)) {
+		  Status = EFI_DEVICE_ERROR;
+		  break;
+        }
+        break;
+      }
+
+      gBS->Stall (1000);
+      Count --;
+    }
+
+    IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);
+    IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
+    //
+    // Read BMIS register and clear ERROR and INTR bit
+    //
+    IdeDev->PciIo->Io.Read (
+                        IdeDev->PciIo,
+                        EfiPciIoWidthUint8,
+                        EFI_PCI_IO_PASS_THROUGH_BAR,
+                        IoPortForBmis,
+                        1,
+                        &RegisterValue
+                        );
+
+    RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);
+
+    IdeDev->PciIo->Io.Write (
+                        IdeDev->PciIo,
+                        EfiPciIoWidthUint8,
+                        EFI_PCI_IO_PASS_THROUGH_BAR,
+                        IoPortForBmis,
+                        1,
+                        &RegisterValue
+                        );
+	//
+    // Read Status Register of IDE device to clear interrupt
+    //
+    RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);
+    //
+    // Clear START bit of BMIC register
+    //
+    IdeDev->PciIo->Io.Read (
+                        IdeDev->PciIo,
+                        EfiPciIoWidthUint8,
+                        EFI_PCI_IO_PASS_THROUGH_BAR,
+                        IoPortForBmic,
+                        1,
+                        &RegisterValue
+                        );
+
+    RegisterValue &= ~((UINT8) BMIC_START);
+
+    IdeDev->PciIo->Io.Write (
+                        IdeDev->PciIo,
+                        EfiPciIoWidthUint8,
+                        EFI_PCI_IO_PASS_THROUGH_BAR,
+                        IoPortForBmic,
+                        1,
+                        &RegisterValue
+                        );
+
+    if ((RegisterValue & BMIS_ERROR) != 0) {
+      return EFI_DEVICE_ERROR;
+    }
+
+	if (EFI_ERROR (Status)) {
+	  break;
+	}
+    DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;
+    StartLba += NumberOfBlocks;
+  }
+
+  //
+  // Disable interrupt of Select device
+  //
+  IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);
+  DeviceControl |= ATA_CTLREG_IEN_L;
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+  return Status;
+}
+
+
+/**
+  This function is called by the AtaBlkIoReadBlocks() to perform reading from
+  media in block unit. The function has been enhanced to support >120GB access 
+  and transfer at most 65536 blocks per command
+
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure, used to record 
+                        all the information of the IDE device.
+  @param DataBuffer     A pointer to the destination buffer for the data.
+  @param StartLba       The starting logical block address to read from on the device media.
+  @param NumberOfBlocks The number of transfer data blocks.
+
+  @return status depends on the function DoAtaUdma() returns.
+**/
+EFI_STATUS
+AtaUdmaReadExt (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  VOID            *DataBuffer,
+  IN  EFI_LBA         StartLba,
+  IN  UINTN           NumberOfBlocks
+  )
+{
+  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadExtOp);
+}
+/**
+  This function is called by the AtaBlkIoReadBlocks() to perform
+  reading from media in block unit. The function has been enhanced to
+  support >120GB access and transfer at most 65536 blocks per command
+
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+                        all the information of the IDE device.
+  @param DataBuffer     A pointer to the destination buffer for the data.
+  @param StartLba       The starting logical block address to read from
+                        on the device media.
+  @param NumberOfBlocks The number of transfer data blocks.
+  
+  @return status depends on the function DoAtaUdma() returns.
+**/
+EFI_STATUS
+AtaUdmaRead (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  VOID            *DataBuffer,
+  IN  EFI_LBA         StartLba,
+  IN  UINTN           NumberOfBlocks
+  )
+{
+  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadOp);
+}
+
+/**
+  This function is called by the AtaBlkIoReadBlocks() to perform
+  reading from media in block unit. The function has been enhanced to
+  support >120GB access and transfer at most 65536 blocks per command
+
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+                        all the information of the IDE device.
+  @param DataBuffer     A pointer to the destination buffer for the data.
+  @param StartLba       The starting logical block address to read from on the device media.
+  @param NumberOfBlocks The number of transfer data blocks.
+
+  @return status is fully dependent on the return status of AtaPioDataInExt() function.
+**/
+EFI_STATUS
+AtaReadSectorsExt (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  VOID            *DataBuffer,
+  IN  EFI_LBA         StartLba,
+  IN  UINTN           NumberOfBlocks
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       BlocksRemaining;
+  EFI_LBA     Lba64;
+  UINT8       AtaCommand;
+  UINT16      SectorCount;
+  UINT32      ByteCount;
+  VOID        *Buffer;
+
+  //
+  // Using ATA "Read Sectors Ext" command(opcode=0x24) with PIO DATA IN protocol
+  //
+  AtaCommand      = ATA_CMD_READ_SECTORS_EXT;
+  Buffer          = DataBuffer;
+  BlocksRemaining = NumberOfBlocks;
+  Lba64           = StartLba;
+  Status          = EFI_SUCCESS;
+
+  while (BlocksRemaining > 0) {
+
+    if (BlocksRemaining >= 0x10000) {
+      //
+      //  SectorCount is used to record the number of sectors to be read
+      //  Max 65536 sectors can be transfered at a time.
+      //
+      SectorCount = 0xffff;
+    } else {
+      SectorCount = (UINT16) BlocksRemaining;
+    }
+
+    //
+    // ByteCount is the number of bytes that will be read
+    //
+    ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);
+
+    //
+    // call AtaPioDataInExt() to send Read Sector Command and receive data read
+    //
+    Status = AtaPioDataInExt (
+              IdeDev,
+              Buffer,
+              ByteCount,
+              AtaCommand,
+              Lba64,
+              SectorCount
+              );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Lba64 += SectorCount;
+    Buffer = ((UINT8 *) Buffer + ByteCount);
+    BlocksRemaining -= SectorCount;
+  }
+
+  return Status;
+}
+/**
+  This function is the ATA implementation for ReadBlocks in the
+  Block I/O Protocol interface.
+
+  @param IdeBlkIoDevice Indicates the calling context.
+  @param MediaId        The media id that the read request is for.
+  @param Lba            The starting logical block address to read from on the device.
+  @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 memory that data is read into.
+
+  @retval EFI_SUCCESS          Read Blocks successfully.
+  @retval EFI_DEVICE_ERROR     Read Blocks failed.
+  @retval EFI_NO_MEDIA         There is no media in the device.
+  @retval EFI_MEDIA_CHANGE     The MediaId is not for the current media.
+  @retval EFI_BAD_BUFFER_SIZE  The BufferSize parameter is not a multiple of the
+                               intrinsic block size of the device.
+  @retval EFI_INVALID_PARAMETER  The read request contains LBAs that are not valid,
+                                 or the data buffer is not valid.
+
+  @note If Read Block error because of device error, this function will call
+        AtaSoftReset() function to reset device.
+
+**/
+EFI_STATUS
+AtaBlkIoReadBlocks (
+  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,
+  IN UINT32           MediaId,
+  IN EFI_LBA          Lba,
+  IN UINTN            BufferSize,
+  OUT VOID            *Buffer
+  )
+{
+  EFI_BLOCK_IO_MEDIA  *Media;
+  UINTN               BlockSize;
+  UINTN               NumberOfBlocks;
+  EFI_STATUS          Status;
+
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BufferSize == 0) {
+    return EFI_SUCCESS;
+  }
+
+  Status = EFI_SUCCESS;
+
+  //
+  //  Get the intrinsic block size
+  //
+  Media           = IdeBlkIoDevice->BlkIo.Media;
+  BlockSize       = Media->BlockSize;
+
+  NumberOfBlocks  = BufferSize / BlockSize;
+
+  if (MediaId != Media->MediaId) {
+    return EFI_MEDIA_CHANGED;
+  }
+
+  if (BufferSize % BlockSize != 0) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  if (!(Media->MediaPresent)) {
+    return EFI_NO_MEDIA;
+  }
+
+  if (Lba > Media->LastBlock) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = EFI_SUCCESS;
+  if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+    //
+    // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism
+    //
+    if (IdeBlkIoDevice->UdmaMode.Valid) {
+      Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+    } else {
+      Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+    }
+  } else {
+    //
+    // For ATA-3 compatible device, use ATA-3 read block mechanism
+    //
+    if (IdeBlkIoDevice->UdmaMode.Valid) {
+      Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+    } else {
+      Status = AtaReadSectors (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+    }
+  }
+
+  if (EFI_ERROR (Status)) {
+    AtaSoftReset (IdeBlkIoDevice);
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+
+}
+/**
+  This function is used to send out ATA commands conforms to the
+  PIO Data Out Protocol, supporting ATA/ATAPI-6 standard
+
+  Comparing with ATA-3 data out protocol, we have two differents here:<BR>
+  1. Do NOT wait for DRQ clear before sending command into IDE device.(the
+  wait will frequently fail... cause writing function return error)
+
+  2. Do NOT wait for DRQ clear after all data readed.(the wait greatly
+  slow down writing performance by 100 times!)
+
+  @param IdeDev       pointer pointing to IDE_BLK_IO_DEV data structure, used
+                       to record all the information of the IDE device.
+  @param Buffer       buffer contained data transferred from host to device.
+  @param ByteCount    data size in byte unit of the buffer.
+  @param AtaCommand   value of the Command Register
+  @param StartLba     the start LBA of this transaction
+  @param SectorCount  the count of sectors to be transfered
+
+  @retval EFI_SUCCESS      send out the ATA command and device receive required
+                           data successfully.
+  @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+EFI_STATUS
+AtaPioDataOutExt (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  VOID            *Buffer,
+  IN  UINT32          ByteCount,
+  IN  UINT8           AtaCommand,
+  IN  EFI_LBA         StartLba,
+  IN  UINT16          SectorCount
+  )
+{
+  UINT8       DevSel;
+  UINT8       SectorCount8;
+  UINT8       LbaLow;
+  UINT8       LbaMid;
+  UINT8       LbaHigh;
+  UINTN       WordCount;
+  UINTN       Increment;
+  UINT16      *Buffer16;
+  EFI_STATUS  Status;
+
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Select device. Set bit6 as 1 to indicate LBA mode is used
+  //
+  DevSel = (UINT8) (IdeDev->Device << 4);
+  DevSel |= 0x40;
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->Head,
+    DevSel
+    );
+
+  //
+  // Wait for DRDY singnal asserting.
+  //
+  Status = DRDYReady (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Fill feature register if needed
+  //
+  if (AtaCommand == ATA_CMD_SET_FEATURES) {
+    IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);
+  }
+
+  //
+  // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+  //
+  SectorCount8 = (UINT8) (SectorCount >> 8);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+  SectorCount8 = (UINT8) SectorCount;
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+  //
+  // Fill the start LBA registers, which are also two-byte FIFO
+  //
+  LbaLow  = (UINT8) RShiftU64 (StartLba, 24);
+  LbaMid  = (UINT8) RShiftU64 (StartLba, 32);
+  LbaHigh = (UINT8) RShiftU64 (StartLba, 40);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+  LbaLow  = (UINT8) StartLba;
+  LbaMid  = (UINT8) RShiftU64 (StartLba, 8);
+  LbaHigh = (UINT8) RShiftU64 (StartLba, 16);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+  //
+  // Send command via Command Register, invoking the processing of this command
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+  Buffer16 = (UINT16 *) Buffer;
+
+  //
+  // According to PIO Data Out protocol, host can perform a series of writes to
+  // the data register after each time device set DRQ ready;
+  //
+  Increment = 256;
+
+  //
+  // used to record bytes of currently transfered data
+  //
+  WordCount = 0;
+
+  while (WordCount < ByteCount / 2) {
+    //
+    // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.
+    //
+    Status = DRQReady2 (IdeDev, ATATIMEOUT);
+    if (EFI_ERROR (Status)) {
+      return EFI_DEVICE_ERROR;
+    }
+
+    Status = CheckErrorStatus (IdeDev);
+    if (EFI_ERROR (Status)) {
+      return EFI_DEVICE_ERROR;
+    }
+
+    //
+    // Write data into device by one series of writing to data register
+    //
+    if ((WordCount + Increment) > ByteCount / 2) {
+      Increment = ByteCount / 2 - WordCount;
+    }
+
+    IDEWritePortWMultiple (
+      IdeDev->PciIo,
+      IdeDev->IoPort->Data,
+      Increment,
+      Buffer16
+      );
+
+    WordCount += Increment;
+    Buffer16 += Increment;
+
+  }
+  return CheckErrorStatus (IdeDev);
+}
+/**
+  This function is called by the AtaBlkIoWriteBlocks() to perform
+  writing to media in block unit. The function has been enhanced to
+  support >120GB access and transfer at most 65536 blocks per command
+
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure, used
+                        to record all the information of the IDE device.
+  @param DataBuffer     A pointer to the source buffer for the data.
+  @param StartLba       The starting logical block address to write to
+                        on the device media.
+  @param NumberOfBlocks The number of transfer data blocks.
+
+  @return status depends on the function DoAtaUdma() returns.
+**/
+EFI_STATUS
+AtaUdmaWriteExt (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  VOID            *DataBuffer,
+  IN  EFI_LBA         StartLba,
+  IN  UINTN           NumberOfBlocks
+  )
+{
+  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteExtOp);
+}
+
+/**
+  This function is called by the AtaBlkIoWriteBlocks() to perform
+  writing to media in block unit. 
+
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure, used
+                        to record all the information of the IDE device.
+  @param DataBuffer     A pointer to the source buffer for the data.
+  @param StartLba       The starting logical block address to write to
+                        on the device media.
+  @param NumberOfBlocks The number of transfer data blocks.
+  
+  @return status depends on the function DoAtaUdma() returns.
+**/
+EFI_STATUS
+AtaUdmaWrite (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  VOID            *DataBuffer,
+  IN  EFI_LBA         StartLba,
+  IN  UINTN           NumberOfBlocks
+  )
+{
+  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteOp);
+}
+/**
+  This function is called by the AtaBlkIoWriteBlocks() to perform
+  writing onto media in block unit. The function has been enhanced to
+  support >120GB access and transfer at most 65536 blocks per command
+
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure,used
+                        to record all the information of the IDE device.
+  @param DataBuffer     A pointer to the source buffer for the data.
+  @param StartLba       The starting logical block address to write onto the device 
+                        media.
+  @param NumberOfBlocks The number of transfer data blocks.
+
+  @return status is fully dependent on the return status of AtaPioDataOutExt() function.
+**/
+EFI_STATUS
+AtaWriteSectorsExt (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  VOID            *DataBuffer,
+  IN  EFI_LBA         StartLba,
+  IN  UINTN           NumberOfBlocks
+  )
+{
+  EFI_STATUS  Status;
+  EFI_LBA     Lba64;
+  UINTN       BlocksRemaining;
+  UINT8       AtaCommand;
+  UINT16      SectorCount;
+  UINT32      ByteCount;
+  VOID        *Buffer;
+
+  //
+  // Using ATA "Write Sectors Ext" cmd(opcode=0x24) with PIO DATA OUT protocol
+  //
+  AtaCommand      = ATA_CMD_WRITE_SECTORS_EXT;
+  Lba64           = StartLba;
+  Buffer          = DataBuffer;
+  BlocksRemaining = NumberOfBlocks;
+
+  Status          = EFI_SUCCESS;
+
+  while (BlocksRemaining > 0) {
+
+    if (BlocksRemaining >= 0x10000) {
+      //
+      //  SectorCount is used to record the number of sectors to be written.
+      //  Max 65536 sectors can be transfered at a time.
+      //
+      SectorCount = 0xffff;
+    } else {
+      SectorCount = (UINT16) BlocksRemaining;
+    }
+
+    //
+    // ByteCount is the number of bytes that will be written
+    //
+    ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);
+
+    //
+    // Call AtaPioDataOutExt() to send "Write Sectors Ext" Command
+    //
+    Status = AtaPioDataOutExt (
+              IdeDev,
+              Buffer,
+              ByteCount,
+              AtaCommand,
+              Lba64,
+              SectorCount
+              );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Lba64 += SectorCount;
+    Buffer = ((UINT8 *) Buffer + ByteCount);
+    BlocksRemaining -= SectorCount;
+  }
+
+  return Status;
+}
+/**
+  This function is the ATA implementation for WriteBlocks in the
+  Block I/O Protocol interface.
+
+  @param IdeBlkIoDevice  Indicates the calling context.
+  @param MediaId         The media id that the write request is for.
+  @param Lba             The starting logical block address to write onto the device.
+  @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 source buffer for the data.The caller
+                         is responsible for either having implicit or explicit 
+                         ownership of the memory that data is written from.
+
+  @retval EFI_SUCCESS       Write Blocks successfully.
+  @retval EFI_DEVICE_ERROR  Write Blocks failed.
+  @retval EFI_NO_MEDIA      There is no media in the device.
+  @retval EFI_MEDIA_CHANGE  The MediaId is not for the current media.
+
+  @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of the
+                                intrinsic block size of the device.
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+                                or the data buffer is not valid.
+
+  @note If Write Block error because of device error, this function will call
+        AtaSoftReset() function to reset device.
+**/
+EFI_STATUS
+AtaBlkIoWriteBlocks (
+  IN  IDE_BLK_IO_DEV   *IdeBlkIoDevice,
+  IN  UINT32           MediaId,
+  IN  EFI_LBA          Lba,
+  IN  UINTN            BufferSize,
+  OUT VOID             *Buffer
+  )
+{
+
+  EFI_BLOCK_IO_MEDIA  *Media;
+  UINTN               BlockSize;
+  UINTN               NumberOfBlocks;
+  EFI_STATUS          Status;
+
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BufferSize == 0) {
+    return EFI_SUCCESS;
+  }
+
+  Status = EFI_SUCCESS;
+
+  //
+  // Get the intrinsic block size
+  //
+  Media           = IdeBlkIoDevice->BlkIo.Media;
+  BlockSize       = Media->BlockSize;
+  NumberOfBlocks  = BufferSize / BlockSize;
+
+  if (MediaId != Media->MediaId) {
+    return EFI_MEDIA_CHANGED;
+  }
+
+  if (BufferSize % BlockSize != 0) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  if (Lba > Media->LastBlock) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = EFI_SUCCESS;
+  if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+    //
+    // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism
+    //
+    if (IdeBlkIoDevice->UdmaMode.Valid) {
+      Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+    } else {
+      Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+    }
+  } else {
+    //
+    // For ATA-3 compatible device, use ATA-3 write block mechanism
+    //
+    if (IdeBlkIoDevice->UdmaMode.Valid) {
+      Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+    } else {
+      Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+    }
+  }
+
+  if (EFI_ERROR (Status)) {
+    AtaSoftReset (IdeBlkIoDevice);
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+/**
+  Enable Long Physical Sector Feature for ATA device.
+
+  @param   IdeDev  The IDE device data
+
+  @retval  EFI_SUCCESS      The ATA device supports Long Physical Sector feature
+                            and corresponding fields in BlockIo structure is updated.
+  @retval  EFI_UNSUPPORTED  The device is not ATA device or Long Physical Sector
+                            feature is not supported.
+**/
+EFI_STATUS
+AtaEnableLongPhysicalSector (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  )
+{
+  EFI_ATA_IDENTIFY_DATA  *AtaIdentifyData;
+  UINT16                 PhyLogicSectorSupport;
+
+  ASSERT (IdeDev->IdData != NULL);
+  //
+  // Only valid for ATA device
+  //
+  AtaIdentifyData       = (EFI_ATA_IDENTIFY_DATA *) &IdeDev->IdData->AtaData;
+  if ((AtaIdentifyData->config & 0x8000) != 0) {
+    return EFI_UNSUPPORTED;
+  }
+  PhyLogicSectorSupport = AtaIdentifyData->phy_logic_sector_support;
+  //
+  // Check whether Long Physical Sector Feature is supported
+  //
+  if ((PhyLogicSectorSupport & 0xc000) == 0x4000) {
+    IdeDev->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 1;
+    IdeDev->BlkIo.Media->LowestAlignedLba              = 0;
+    //
+    // Check whether one physical block contains multiple physical blocks
+    //
+    if ((PhyLogicSectorSupport & 0x2000) != 0) {
+      IdeDev->BlkIo.Media->LogicalBlocksPerPhysicalBlock =
+        (UINT32) (1 << (PhyLogicSectorSupport & 0x000f));
+      //
+      // Check lowest alignment of logical blocks within physical block
+      //
+      if ((AtaIdentifyData->alignment_logic_in_phy_blocks & 0xc000) == 0x4000) {
+        IdeDev->BlkIo.Media->LowestAlignedLba =
+          (EFI_LBA) (AtaIdentifyData->alignment_logic_in_phy_blocks & 0x3fff);
+      }
+    }
+    //
+    // Check logical block size
+    //
+    IdeDev->BlkIo.Media->BlockSize = 0x200;
+    if ((PhyLogicSectorSupport & 0x1000) != 0) {
+      IdeDev->BlkIo.Media->BlockSize = (UINT32) (
+        ((AtaIdentifyData->logic_sector_size_hi << 16) |
+         AtaIdentifyData->logic_sector_size_lo) * sizeof (UINT16)
+        );
+    }
+    return EFI_SUCCESS;
+  } else {
+    return EFI_UNSUPPORTED;
+  }
+}
+/**
+  Send ATA command into device with NON_DATA protocol
+
+  @param  IdeDev Standard IDE device private data structure
+  @param  AtaCommand The ATA command to be sent
+  @param  Device The value in Device register
+  @param  Feature The value in Feature register
+  @param  SectorCount The value in SectorCount register
+  @param  LbaLow The value in LBA_LOW register
+  @param  LbaMiddle The value in LBA_MIDDLE register
+  @param  LbaHigh The value in LBA_HIGH register
+
+  @retval  EFI_SUCCESS Reading succeed
+  @retval  EFI_ABORTED Command failed
+  @retval  EFI_DEVICE_ERROR Device status error.
+
+**/
+EFI_STATUS
+AtaNonDataCommandIn (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINT8           AtaCommand,
+  IN  UINT8           Device,
+  IN  UINT8           Feature,
+  IN  UINT8           SectorCount,
+  IN  UINT8           LbaLow,
+  IN  UINT8           LbaMiddle,
+  IN  UINT8           LbaHigh
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       StatusRegister;
+
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Select device (bit4), set Lba mode(bit6) (use 0xe0 for compatibility)
+  //
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->Head,
+    (UINT8) ((IdeDev->Device << 4) | 0xe0)
+    );
+
+  //
+  // ATA commands for ATA device must be issued when DRDY is set
+  //
+  Status = DRDYReady (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Pass parameter into device register block
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMiddle);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+  //
+  // Send command via Command Register
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+  //
+  // Wait for command completion
+  // For ATAPI_SMART_CMD, we may need more timeout to let device
+  // adjust internal states.
+  //
+  if (AtaCommand == ATA_CMD_SMART) {
+    Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT);
+  } else {
+    Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+  }
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+  if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {
+    //
+    // Failed to execute command, abort operation
+    //
+    return EFI_ABORTED;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Send ATA Ext command into device with NON_DATA protocol
+
+  @param  IdeDev Standard IDE device private data structure
+  @param  AtaCommand The ATA command to be sent
+  @param  Device The value in Device register
+  @param  Feature The value in Feature register
+  @param  SectorCount The value in SectorCount register
+  @param  LbaAddress The LBA address in 48-bit mode
+
+  @retval  EFI_SUCCESS Reading succeed
+  @retval  EFI_ABORTED Command failed
+  @retval  EFI_DEVICE_ERROR Device status error.
+
+**/
+EFI_STATUS
+AtaNonDataCommandInExt (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINT8           AtaCommand,
+  IN  UINT8           Device,
+  IN  UINT16          Feature,
+  IN  UINT16          SectorCount,
+  IN  EFI_LBA         LbaAddress
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       StatusRegister;
+  UINT8       SectorCount8;
+  UINT8       Feature8;
+  UINT8       LbaLow;
+  UINT8       LbaMid;
+  UINT8       LbaHigh;
+
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
+  //
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->Head,
+    (UINT8) ((IdeDev->Device << 4) | 0xe0)
+    );
+
+  //
+  // ATA commands for ATA device must be issued when DRDY is set
+  //
+  Status = DRDYReady (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Pass parameter into device register block
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+
+  //
+  // Fill the feature register, which is a two-byte FIFO. Need write twice.
+  //
+  Feature8 = (UINT8) (Feature >> 8);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
+
+  Feature8 = (UINT8) Feature;
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
+
+  //
+  // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+  //
+  SectorCount8 = (UINT8) (SectorCount >> 8);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+  SectorCount8 = (UINT8) SectorCount;
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+  //
+  // Fill the start LBA registers, which are also two-byte FIFO
+  //
+  LbaLow  = (UINT8) RShiftU64 (LbaAddress, 24);
+  LbaMid  = (UINT8) RShiftU64 (LbaAddress, 32);
+  LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+  LbaLow  = (UINT8) LbaAddress;
+  LbaMid  = (UINT8) RShiftU64 (LbaAddress, 8);
+  LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+  //
+  // Send command via Command Register
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+  //
+  // Wait for command completion
+  //
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+  if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {
+    //
+    // Failed to execute command, abort operation
+    //
+    return EFI_ABORTED;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/Atapi.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/Atapi.c	(revision 33024)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/Atapi.c	(revision 33024)
@@ -0,0 +1,1952 @@
+/** @file
+   This file contains all helper functions on the ATAPI command 
+  
+  Copyright (c) 2006 - 2008, Intel Corporation                                                        
+  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 "IdeBus.h"
+
+/**
+  This function is used to get the current status of the media residing
+  in the LS-120 drive or ZIP drive. The media status is returned in the 
+  Error Status.
+
+  @param IdeDev   pointer pointing to IDE_BLK_IO_DEV data structure, used
+                  to record all the information of the IDE device.
+
+  @retval EFI_SUCCESS         The media status is achieved successfully and the media
+                              can be read/written.
+  @retval EFI_DEVICE_ERROR    Get Media Status Command is failed.
+  @retval EFI_NO_MEDIA        There is no media in the drive.
+  @retval EFI_WRITE_PROTECTED The media is writing protected.
+
+  @note  This function must be called after the LS120EnableMediaStatus() 
+         with second parameter set to TRUE 
+         (means enable media status notification) is called.
+**/
+EFI_STATUS
+LS120GetMediaStatus (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  )
+{
+  UINT8       DeviceSelect;
+  UINT8       StatusValue;
+  EFI_STATUS  EfiStatus;
+  //
+  // Poll Alternate Register for BSY clear within timeout.
+  //
+  EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (EfiStatus)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Select device via Device/Head Register.
+  //
+  DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);
+
+  //
+  // Poll Alternate Register for DRDY set within timeout.
+  // After device is selected, DRDY set indicates the device is ready to
+  // accept command.
+  //
+  EfiStatus = DRDYReady2 (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (EfiStatus)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Get Media Status Command is sent
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xDA);
+
+  //
+  // BSY bit will clear after command is complete.
+  //
+  EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (EfiStatus)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // the media status is returned by the command in the ERROR register
+  //
+  StatusValue = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+
+  if ((StatusValue & BIT1) != 0) {
+    return EFI_NO_MEDIA;
+  }
+
+  if ((StatusValue & BIT6) != 0) {
+    return EFI_WRITE_PROTECTED;
+  } else {
+    return EFI_SUCCESS;
+  }
+}
+/**
+  This function is used to send Enable Media Status Notification Command
+  or Disable Media Status Notification Command.
+
+  @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+                to record all the information of the IDE device.
+
+  @param Enable a flag that indicates whether enable or disable media
+                status notification.
+  @retval EFI_SUCCESS      If command completes successfully.
+  @retval EFI_DEVICE_ERROR If command failed.
+**/
+EFI_STATUS
+LS120EnableMediaStatus (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  BOOLEAN         Enable
+  )
+{
+  UINT8       DeviceSelect;
+  EFI_STATUS  Status;
+
+  //
+  // Poll Alternate Register for BSY clear within timeout.
+  //
+  Status = WaitForBSYClear2 (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Select device via Device/Head Register.
+  //
+  DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0);
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);
+
+  //
+  // Poll Alternate Register for DRDY set within timeout.
+  // After device is selected, DRDY set indicates the device is ready to
+  // accept command.
+  //
+  Status = DRDYReady2 (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (Enable) {
+    //
+    // 0x95: Enable media status notification
+    //
+    IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x95);
+  } else {
+    //
+    // 0x31: Disable media status notification
+    //
+    IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x31);
+  }
+  //
+  // Set Feature Command is sent
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xEF);
+
+  //
+  // BSY bit will clear after command is complete.
+  //
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+/**
+  This function reads the pending data in the device.
+
+  @param IdeDev   Indicates the calling context.
+
+  @retval EFI_SUCCESS   Successfully read.
+  @retval EFI_NOT_READY The BSY is set avoiding reading.
+
+**/
+EFI_STATUS
+AtapiReadPendingData (
+  IN IDE_BLK_IO_DEV     *IdeDev
+  )
+{
+  UINT8     AltRegister;
+  UINT16    TempWordBuffer;
+
+  AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
+  if ((AltRegister & ATA_STSREG_BSY) == ATA_STSREG_BSY) {
+    return EFI_NOT_READY;
+  }
+  if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
+    TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);
+    while ((TempWordBuffer & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
+      IDEReadPortWMultiple (
+        IdeDev->PciIo,
+        IdeDev->IoPort->Data, 
+        1, 
+        &TempWordBuffer
+        );
+      TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  This function is called by either AtapiPacketCommandIn() or AtapiPacketCommandOut(). 
+  It is used to transfer data between host and device. The data direction is specified
+  by the fourth parameter.
+
+  @param IdeDev     pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+                    all the information of the IDE device.
+  @param Buffer     buffer contained data transferred between host and device.
+  @param ByteCount  data size in byte unit of the buffer.
+  @param Read       flag used to determine the data transfer direction.
+                    Read equals 1, means data transferred from device to host;
+                    Read equals 0, means data transferred from host to device.
+  @param TimeOut    timeout value for wait DRQ ready before each data stream's transfer.
+
+  @retval EFI_SUCCESS      data is transferred successfully.
+  @retval EFI_DEVICE_ERROR the device failed to transfer data.
+**/
+EFI_STATUS
+PioReadWriteData (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINT16          *Buffer,
+  IN  UINT32          ByteCount,
+  IN  BOOLEAN         Read,
+  IN  UINTN           TimeOut
+  )
+{
+  //
+  // required transfer data in word unit.
+  //
+  UINT32      RequiredWordCount;
+
+  //
+  // actual transfer data in word unit.
+  //
+  UINT32      ActualWordCount;
+  UINT32      WordCount;
+  EFI_STATUS  Status;
+  UINT16      *PtrBuffer;
+
+  //
+  // No data transfer is premitted.
+  //
+  if (ByteCount == 0) {
+    return EFI_SUCCESS;
+  }
+  //
+  // for performance, we assert the ByteCount is an even number
+  // which is actually a resonable assumption  
+  ASSERT((ByteCount%2) == 0);
+  
+  PtrBuffer         = Buffer;
+  RequiredWordCount = ByteCount / 2;
+  //
+  // ActuralWordCount means the word count of data really transferred.
+  //
+  ActualWordCount = 0;
+
+  while (ActualWordCount < RequiredWordCount) {
+    
+    //
+    // before each data transfer stream, the host should poll DRQ bit ready,
+    // to see whether indicates device is ready to transfer data.
+    //
+    Status = DRQReady2 (IdeDev, TimeOut);
+    if (EFI_ERROR (Status)) {
+      return CheckErrorStatus (IdeDev);
+    }
+    
+    //
+    // read Status Register will clear interrupt
+    //
+    IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+    //
+    // get current data transfer size from Cylinder Registers.
+    //
+    WordCount = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) << 8;
+    WordCount = WordCount | IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);
+    WordCount = WordCount & 0xffff;
+    WordCount /= 2;
+
+    WordCount = MIN (WordCount, (RequiredWordCount - ActualWordCount));
+
+    if (Read) {
+      IDEReadPortWMultiple (
+        IdeDev->PciIo,
+        IdeDev->IoPort->Data,
+        WordCount,
+        PtrBuffer
+        );
+    } else {
+      IDEWritePortWMultiple (
+        IdeDev->PciIo,
+        IdeDev->IoPort->Data,
+        WordCount,
+        PtrBuffer
+        );
+    }
+
+    PtrBuffer += WordCount;
+    ActualWordCount += WordCount;
+  }
+  
+  if (Read) {
+    //
+    // In the case where the drive wants to send more data than we need to read,
+    // the DRQ bit will be set and cause delays from DRQClear2().
+    // We need to read data from the drive until it clears DRQ so we can move on.
+    //
+    AtapiReadPendingData (IdeDev);
+  }
+
+  //
+  // After data transfer is completed, normally, DRQ bit should clear.
+  //
+  Status = DRQClear2 (IdeDev, ATAPITIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // read status register to check whether error happens.
+  //
+  return CheckErrorStatus (IdeDev);
+}
+
+/**
+  This function is used to send out ATAPI commands conforms to the Packet Command 
+  with PIO Data In Protocol.
+
+  @param IdeDev    pointer pointing to IDE_BLK_IO_DEV data structure, used
+                   to record all the information of the IDE device.
+  @param Packet    pointer pointing to ATAPI_PACKET_COMMAND data structure
+                   which contains the contents of the command.     
+  @param Buffer    buffer contained data transferred from device to host.
+  @param ByteCount data size in byte unit of the buffer.
+  @param TimeOut   this parameter is used to specify the timeout value for the 
+                   PioReadWriteData() function. 
+
+  @retval EFI_SUCCESS       send out the ATAPI packet command successfully
+                            and device sends data successfully.
+  @retval EFI_DEVICE_ERROR  the device failed to send data.
+
+**/
+EFI_STATUS
+AtapiPacketCommandIn (
+  IN  IDE_BLK_IO_DEV        *IdeDev,
+  IN  ATAPI_PACKET_COMMAND  *Packet,
+  IN  UINT16                *Buffer,
+  IN  UINT32                ByteCount,
+  IN  UINTN                 TimeOut
+  )
+{
+  UINT16      *CommandIndex;
+  EFI_STATUS  Status;
+  UINT32      Count;
+
+  //
+  // Set all the command parameters by fill related registers.
+  // Before write to all the following registers, BSY and DRQ must be 0.
+  //
+  Status = DRQClear2 (IdeDev, ATAPITIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Select device via Device/Head Register.
+  //
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->Head,
+    (UINT8) ((IdeDev->Device << 4) | ATA_DEFAULT_CMD)  // DEFAULT_CMD: 0xa0 (1010,0000)
+    );
+
+  //
+  // No OVL; No DMA
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);
+
+  //
+  // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device
+  // determine how many data should be transferred.
+  //
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->CylinderLsb,
+    (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff)
+    );
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->CylinderMsb,
+    (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8)
+    );
+
+  //
+  //  ATA_DEFAULT_CTL:0x0a (0000,1010)
+  //  Disable interrupt
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, ATA_DEFAULT_CTL);
+
+  //
+  // Send Packet command to inform device
+  // that the following data bytes are command packet.
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, ATA_CMD_PACKET);
+
+  Status = DRQReady (IdeDev, ATAPITIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Send out command packet
+  //
+  CommandIndex = Packet->Data16;
+  for (Count = 0; Count < 6; Count++, CommandIndex++) {
+
+    IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex);
+    gBS->Stall (10);
+  }
+
+  //
+  // call PioReadWriteData() function to get
+  // requested transfer data form device.
+  //
+  return PioReadWriteData (IdeDev, Buffer, ByteCount, 1, TimeOut);
+}
+/**
+  This function is used to send out ATAPI commands conforms to the Packet Command
+  with PIO Data Out Protocol.
+
+  @param IdeDev      pointer pointing to IDE_BLK_IO_DEV data structure, used
+                     to record all the information of the IDE device.
+  @param Packet      pointer pointing to ATAPI_PACKET_COMMAND data structure
+                     which contains the contents of the command.
+  @param Buffer      buffer contained data transferred from host to device.
+  @param ByteCount   data size in byte unit of the buffer.
+  @param TimeOut     this parameter is used to specify the timeout value 
+                     for the PioReadWriteData() function. 
+  @retval EFI_SUCCESS      send out the ATAPI packet command successfully
+                           and device received data successfully.  
+  @retval EFI_DEVICE_ERROR the device failed to send data.
+
+**/
+EFI_STATUS
+AtapiPacketCommandOut (
+  IN  IDE_BLK_IO_DEV        *IdeDev,
+  IN  ATAPI_PACKET_COMMAND  *Packet,
+  IN  UINT16                *Buffer,
+  IN  UINT32                ByteCount,
+  IN  UINTN                 TimeOut
+  )
+{
+  UINT16      *CommandIndex;
+  EFI_STATUS  Status;
+  UINT32      Count;
+
+  //
+  // set all the command parameters
+  // Before write to all the following registers, BSY and DRQ must be 0.
+  //
+  Status = DRQClear2 (IdeDev, ATAPITIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  
+  //
+  // Select device via Device/Head Register.
+  //
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->Head,
+    (UINT8) ((IdeDev->Device << 4) | ATA_DEFAULT_CMD)   // ATA_DEFAULT_CMD: 0xa0 (1010,0000)
+    );
+
+  //
+  // No OVL; No DMA
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);
+
+  //
+  // set the transfersize to ATAPI_MAX_BYTE_COUNT to
+  // let the device determine how many data should be transferred.
+  //
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->CylinderLsb,
+    (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff)
+    );
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->CylinderMsb,
+    (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8)
+    );
+
+  //
+  //  DEFAULT_CTL:0x0a (0000,1010)
+  //  Disable interrupt
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, ATA_DEFAULT_CTL);
+
+  //
+  // Send Packet command to inform device
+  // that the following data bytes are command packet.
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, ATA_CMD_PACKET);
+
+  Status = DRQReady2 (IdeDev, ATAPITIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Send out command packet
+  //
+  CommandIndex = Packet->Data16;
+  for (Count = 0; Count < 6; Count++, CommandIndex++) {
+    IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex);
+    gBS->Stall (10);
+  }
+
+  //
+  // call PioReadWriteData() function to send requested transfer data to device.
+  //
+  return PioReadWriteData (IdeDev, Buffer, ByteCount, 0, TimeOut);
+}
+/**
+  Sends out ATAPI Inquiry Packet Command to the specified device. This command will
+  return INQUIRY data of the device.
+
+  @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+                to record all the information of the IDE device.
+
+  @retval EFI_SUCCESS       Inquiry command completes successfully.
+  @retval EFI_DEVICE_ERROR  Inquiry command failed.
+
+  @note  Parameter "IdeDev" will be updated in this function.
+
+**/
+EFI_STATUS
+AtapiInquiry (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  )
+{
+  ATAPI_PACKET_COMMAND  Packet;
+  EFI_STATUS            Status;
+  ATAPI_INQUIRY_DATA          *InquiryData;
+
+  //
+  // prepare command packet for the ATAPI Inquiry Packet Command.
+  //
+  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+  Packet.Inquiry.opcode             = ATA_CMD_INQUIRY;
+  Packet.Inquiry.page_code          = 0;
+  Packet.Inquiry.allocation_length  = sizeof (ATAPI_INQUIRY_DATA);
+
+  InquiryData                       = AllocatePool (sizeof (ATAPI_INQUIRY_DATA));
+  if (InquiryData == NULL) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Send command packet and get requested Inquiry data.
+  //
+  Status = AtapiPacketCommandIn (
+            IdeDev,
+            &Packet,
+            (UINT16 *) InquiryData,
+            sizeof (ATAPI_INQUIRY_DATA),
+            ATAPITIMEOUT
+            );
+  if (EFI_ERROR (Status)) {
+    gBS->FreePool (InquiryData);
+    return EFI_DEVICE_ERROR;
+  }
+
+  IdeDev->InquiryData = InquiryData;
+
+  return EFI_SUCCESS;
+}
+/**
+  This function is called by DiscoverIdeDevice() during its device
+  identification.
+  Its main purpose is to get enough information for the device media
+  to fill in the Media data structure of the Block I/O Protocol interface.
+
+  There are 5 steps to reach such objective:
+  1. Sends out the ATAPI Identify Command to the specified device. 
+  Only ATAPI device responses to this command. If the command succeeds,
+  it returns the Identify data structure which filled with information 
+  about the device. Since the ATAPI device contains removable media, 
+  the only meaningful information is the device module name.
+  2. Sends out ATAPI Inquiry Packet Command to the specified device.
+  This command will return inquiry data of the device, which contains
+  the device type information.
+  3. Allocate sense data space for future use. We don't detect the media
+  presence here to improvement boot performance, especially when CD 
+  media is present. The media detection will be performed just before
+  each BLK_IO read/write
+  
+  @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+                 to record all the information of the IDE device.
+
+  @retval EFI_SUCCESS       Identify ATAPI device successfully.
+  @retval EFI_DEVICE_ERROR  ATAPI Identify Device Command failed or device type
+                            is not supported by this IDE driver.
+  @retval EFI_OUT_OF_RESOURCES Allocate memory for sense data failed 
+
+  @note   Parameter "IdeDev" will be updated in this function.
+**/
+EFI_STATUS
+ATAPIIdentify (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  )
+{
+  EFI_IDENTIFY_DATA *AtapiIdentifyPointer;
+  UINT8             DeviceSelect;
+  EFI_STATUS        Status;
+
+  //
+  // device select bit
+  //
+  DeviceSelect          = (UINT8) ((IdeDev->Device) << 4);
+
+  AtapiIdentifyPointer  = AllocatePool (sizeof (EFI_IDENTIFY_DATA));
+  if (AtapiIdentifyPointer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  //
+  // Send ATAPI Identify Command to get IDENTIFY data.
+  //
+  Status = AtaPioDataIn (
+            IdeDev,
+            (VOID *) AtapiIdentifyPointer,
+            sizeof (EFI_IDENTIFY_DATA),
+            ATA_CMD_IDENTIFY_DEVICE,
+            DeviceSelect,
+            0,
+            0,
+            0,
+            0
+            );
+
+  if (EFI_ERROR (Status)) {
+    gBS->FreePool (AtapiIdentifyPointer);
+    return EFI_DEVICE_ERROR;
+  }
+
+  IdeDev->IdData = AtapiIdentifyPointer;
+  PrintAtaModuleName (IdeDev);
+
+  //
+  // Send ATAPI Inquiry Packet Command to get INQUIRY data.
+  //
+  Status = AtapiInquiry (IdeDev);
+  if (EFI_ERROR (Status)) {
+    gBS->FreePool (IdeDev->IdData);
+    //
+    // Make sure the pIdData will not be freed again.
+    //
+    IdeDev->IdData = NULL;
+    return EFI_DEVICE_ERROR;
+  }
+  //
+  // Get media removable info from INQUIRY data.
+  //
+  IdeDev->BlkIo.Media->RemovableMedia = (UINT8) ((IdeDev->InquiryData->RMB & 0x80) == 0x80);
+
+  //
+  // Identify device type via INQUIRY data.
+  //
+  switch (IdeDev->InquiryData->peripheral_type & 0x1f) {
+
+  //
+  // Magnetic Disk
+  //
+  case 0x00:
+
+    //
+    // device is LS120 or ZIP drive.
+    //
+    IdeDev->Type = IdeMagnetic;
+
+    IdeDev->BlkIo.Media->MediaId      = 0;
+    //
+    // Give initial value
+    //
+    IdeDev->BlkIo.Media->MediaPresent = FALSE;
+
+    IdeDev->BlkIo.Media->LastBlock  = 0;
+    IdeDev->BlkIo.Media->BlockSize  = 0x200;
+    break;
+
+  //
+  // CD-ROM
+  //
+  case 0x05:
+
+    IdeDev->Type                      = IdeCdRom;
+    IdeDev->BlkIo.Media->MediaId      = 0;
+    //
+    // Give initial value
+    //
+    IdeDev->BlkIo.Media->MediaPresent = FALSE;
+
+    IdeDev->BlkIo.Media->LastBlock  = 0;
+    IdeDev->BlkIo.Media->BlockSize  = 0x800;
+    IdeDev->BlkIo.Media->ReadOnly   = TRUE;
+    break;
+
+  //
+  // Tape
+  //
+  case 0x01:
+
+  //
+  // WORM
+  //
+  case 0x04:
+  
+  //
+  // Optical
+  //
+  case 0x07:
+
+  default:
+    IdeDev->Type = IdeUnknown;
+    gBS->FreePool (IdeDev->IdData);
+    gBS->FreePool (IdeDev->InquiryData);
+    //
+    // Make sure the pIdData and pInquiryData will not be freed again.
+    //
+    IdeDev->IdData       = NULL;
+    IdeDev->InquiryData  = NULL;
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // original sense data numbers
+  //
+  IdeDev->SenseDataNumber = 20;
+
+  IdeDev->SenseData = AllocatePool (IdeDev->SenseDataNumber * sizeof (ATAPI_REQUEST_SENSE_DATA));
+  if (IdeDev->SenseData == NULL) {
+    gBS->FreePool (IdeDev->IdData);
+    gBS->FreePool (IdeDev->InquiryData);
+    //
+    // Make sure the pIdData and pInquiryData will not be freed again.
+    //
+    IdeDev->IdData       = NULL;
+    IdeDev->InquiryData  = NULL;
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  return EFI_SUCCESS;
+}
+/**
+  Sends out ATAPI Request Sense Packet Command to the specified device. This command
+  will return all the current Sense data in the device.  This function will pack 
+  all the Sense data in one single buffer.
+
+  @param IdeDev       pointer pointing to IDE_BLK_IO_DEV data structure, used
+                      to record all the information of the IDE device.
+  @param SenseCounts  allocated in this function, and freed by the calling function.
+                      This buffer is used to accommodate all the sense data returned 
+                      by the device.
+
+  @retval EFI_SUCCESS      Request Sense command completes successfully.
+  @retval EFI_DEVICE_ERROR Request Sense command failed.
+**/
+EFI_STATUS
+AtapiRequestSense (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  OUT UINTN           *SenseCounts
+  )
+{
+  EFI_STATUS            Status;
+  ATAPI_REQUEST_SENSE_DATA    *Sense;
+  UINT16                *Ptr;
+  BOOLEAN               FetchSenseData;
+  ATAPI_PACKET_COMMAND  Packet;
+
+  *SenseCounts = 0;
+
+  ZeroMem (IdeDev->SenseData, sizeof (ATAPI_REQUEST_SENSE_DATA) * (IdeDev->SenseDataNumber));
+  //
+  // fill command packet for Request Sense Packet Command
+  //
+  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+  Packet.RequestSence.opcode            = ATA_CMD_REQUEST_SENSE;
+  Packet.RequestSence.allocation_length = sizeof (ATAPI_REQUEST_SENSE_DATA);
+
+  //
+  // initialize pointer
+  //
+  Ptr = (UINT16 *) IdeDev->SenseData;
+  //
+  //  request sense data from device continuously until no sense data
+  //  exists in the device.
+  //
+  for (FetchSenseData = TRUE; FetchSenseData;) {
+
+    Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr;
+
+    //
+    // send out Request Sense Packet Command and get one Sense data form device
+    //
+    Status = AtapiPacketCommandIn (
+              IdeDev,
+              &Packet,
+              Ptr,
+              sizeof (ATAPI_REQUEST_SENSE_DATA),
+              ATAPITIMEOUT
+              );
+    //
+    // failed to get Sense data
+    //
+    if (EFI_ERROR (Status)) {
+      if (*SenseCounts == 0) {
+        return EFI_DEVICE_ERROR;
+      } else {
+        return EFI_SUCCESS;
+      }
+    }
+
+    (*SenseCounts)++;
+    //
+    // We limit MAX sense data count to 20 in order to avoid dead loop. Some
+    // incompatible ATAPI devices don't retrive NO_SENSE when there is no media.
+    // In this case, dead loop occurs if we don't have a gatekeeper. 20 is
+    // supposed to be large enough for any ATAPI device.
+    //
+    if ((Sense->sense_key != ATA_SK_NO_SENSE) && ((*SenseCounts) < 20)) {
+      //
+      // Ptr is word-based pointer
+      //
+      Ptr += (sizeof (ATAPI_REQUEST_SENSE_DATA) + 1) >> 1;
+
+    } else {
+      //
+      // when no sense key, skip out the loop
+      //
+      FetchSenseData = FALSE;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+/**
+  This function is used to parse sense data. Only the first sense data is honoured
+  
+  @param IdeDev     Indicates the calling context.
+  @param SenseCount Count of sense data.
+  @param Result    The parsed result.
+
+  @retval EFI_SUCCESS           Successfully parsed.
+  @retval EFI_INVALID_PARAMETER Count of sense data is zero.
+
+**/
+EFI_STATUS
+ParseSenseData (
+  IN IDE_BLK_IO_DEV     *IdeDev,
+  IN UINTN              SenseCount,
+  OUT SENSE_RESULT      *Result
+  )
+{
+  ATAPI_REQUEST_SENSE_DATA      *SenseData;
+
+  if (SenseCount == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Only use the first sense data
+  //
+  SenseData = IdeDev->SenseData;
+  *Result   = SenseOtherSense;
+
+  switch (SenseData->sense_key) {
+  case ATA_SK_NO_SENSE:
+    *Result = SenseNoSenseKey;
+    break;
+  case ATA_SK_NOT_READY:
+    switch (SenseData->addnl_sense_code) {
+    case ATA_ASC_NO_MEDIA:
+      *Result = SenseNoMedia;
+      break;
+    case ATA_ASC_MEDIA_UPSIDE_DOWN:
+      *Result = SenseMediaError;
+      break;
+    case ATA_ASC_NOT_READY:
+      if (SenseData->addnl_sense_code_qualifier == ATA_ASCQ_IN_PROGRESS) {
+        *Result = SenseDeviceNotReadyNeedRetry;
+      } else {
+        *Result = SenseDeviceNotReadyNoRetry;
+      }
+      break;
+    }
+    break;
+  case ATA_SK_UNIT_ATTENTION:
+    if (SenseData->addnl_sense_code == ATA_ASC_MEDIA_CHANGE) {
+      *Result = SenseMediaChange;
+    }
+    break;
+  case ATA_SK_MEDIUM_ERROR:
+    switch (SenseData->addnl_sense_code) {
+    case ATA_ASC_MEDIA_ERR1:
+    case ATA_ASC_MEDIA_ERR2:
+    case ATA_ASC_MEDIA_ERR3:
+    case ATA_ASC_MEDIA_ERR4:
+      *Result = SenseMediaError;
+      break;
+    }
+    break;
+  default:
+    break;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Sends out ATAPI Test Unit Ready Packet Command to the specified device
+  to find out whether device is accessible.
+
+  @param IdeDev    Pointer pointing to IDE_BLK_IO_DEV data structure, used
+                   to record all the information of the IDE device.
+  @param SResult   Sense result for this packet command.
+
+  @retval EFI_SUCCESS      Device is accessible.
+  @retval EFI_DEVICE_ERROR Device is not accessible.
+
+**/
+EFI_STATUS
+AtapiTestUnitReady (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  OUT SENSE_RESULT    *SResult  
+  )
+{
+  ATAPI_PACKET_COMMAND  Packet;
+  EFI_STATUS            Status;
+  UINTN 				SenseCount;
+
+  //
+  // fill command packet
+  //
+  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+  Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY;
+
+  //
+  // send command packet
+  //
+  Status = AtapiPacketCommandIn (IdeDev, &Packet, NULL, 0, ATAPITIMEOUT);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = AtapiRequestSense (IdeDev, &SenseCount);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  ParseSenseData (IdeDev, SenseCount, SResult);
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Sends out ATAPI Read Capacity Packet Command to the specified device.
+  This command will return the information regarding the capacity of the
+  media in the device.
+
+  Current device status will impact device's response to the Read Capacity
+  Command. For example, if the device once reset, the Read Capacity
+  Command will fail. The Sense data record the current device status, so 
+  if the Read Capacity Command failed, the Sense data must be requested
+  and be analyzed to determine if the Read Capacity Command should retry.
+
+  @param IdeDev    Pointer pointing to IDE_BLK_IO_DEV data structure, used
+                   to record all the information of the IDE device.
+  @param SResult   Sense result for this packet command
+
+  @retval EFI_SUCCESS      Read Capacity Command finally completes successfully.
+  @retval EFI_DEVICE_ERROR Read Capacity Command failed because of device error.
+  @retval EFI_NOT_READY    Operation succeeds but returned capacity is 0
+
+  @note Parameter "IdeDev" will be updated in this function.
+
+  
+**/
+EFI_STATUS
+AtapiReadCapacity (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  OUT SENSE_RESULT	  *SResult  
+  )
+{
+  //
+  // status returned by Read Capacity Packet Command
+  //
+  EFI_STATUS                Status;
+  EFI_STATUS                SenseStatus;
+  ATAPI_PACKET_COMMAND      Packet;
+  UINTN 					SenseCount;
+
+  //
+  // used for capacity data returned from ATAPI device
+  //
+  ATAPI_READ_CAPACITY_DATA        Data;
+  ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;
+
+  ZeroMem (&Data, sizeof (Data));
+  ZeroMem (&FormatData, sizeof (FormatData));
+
+  if (IdeDev->Type == IdeCdRom) {
+
+    ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+    Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;
+    Status = AtapiPacketCommandIn (
+               IdeDev,
+               &Packet,
+               (UINT16 *) &Data,
+               sizeof (ATAPI_READ_CAPACITY_DATA),
+               ATAPITIMEOUT
+               );
+
+  } else {
+    //
+    // Type == IdeMagnetic
+    //
+    ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+    Packet.ReadFormatCapacity.opcode                = ATA_CMD_READ_FORMAT_CAPACITY;
+    Packet.ReadFormatCapacity.allocation_length_lo  = 12;
+    Status = AtapiPacketCommandIn (
+               IdeDev,
+               &Packet,
+               (UINT16 *) &FormatData,
+               sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA),
+               ATAPITIMEOUT
+               );
+  }
+
+  if (Status == EFI_TIMEOUT) {
+    return Status;
+  }
+
+  SenseStatus = AtapiRequestSense (IdeDev, &SenseCount);
+
+  if (!EFI_ERROR (SenseStatus)) {
+	ParseSenseData (IdeDev, SenseCount, SResult);			 
+															 
+	if (!EFI_ERROR (Status) && *SResult == SenseNoSenseKey) {
+      if (IdeDev->Type == IdeCdRom) {
+
+        IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) |
+          (Data.LastLba2 << 16) |
+          (Data.LastLba1 << 8) |
+          Data.LastLba0;
+
+	      IdeDev->BlkIo.Media->MediaPresent = TRUE;
+
+        IdeDev->BlkIo.Media->ReadOnly = TRUE;
+
+        //
+        // Because the user data portion in the sector of the Data CD supported
+        // is always 0x800
+        //
+        IdeDev->BlkIo.Media->BlockSize = 0x800;
+      }
+
+      if (IdeDev->Type == IdeMagnetic) {
+
+        if (FormatData.DesCode == 3) {
+          IdeDev->BlkIo.Media->MediaPresent = FALSE;
+          IdeDev->BlkIo.Media->LastBlock    = 0;
+        } else {
+
+          IdeDev->BlkIo.Media->LastBlock =  (FormatData.LastLba3 << 24) |
+            (FormatData.LastLba2 << 16) | 
+            (FormatData.LastLba1 << 8)  |
+            FormatData.LastLba0;
+          if (IdeDev->BlkIo.Media->LastBlock != 0) {
+            IdeDev->BlkIo.Media->LastBlock--;
+
+            IdeDev->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) |
+              (FormatData.BlockSize1 << 8) |
+              FormatData.BlockSize0;
+
+            IdeDev->BlkIo.Media->MediaPresent = TRUE;
+          } else {
+            IdeDev->BlkIo.Media->MediaPresent = FALSE;
+            //
+            // Return EFI_NOT_READY operation succeeds but returned capacity is 0
+            //
+            return EFI_NOT_READY;
+          }
+
+          IdeDev->BlkIo.Media->BlockSize = 0x200;
+
+        }
+      }
+    }
+
+    return EFI_SUCCESS;
+
+  } else {
+    return EFI_DEVICE_ERROR;
+  }
+}
+/**
+  This function is used to test the current media write-protected or not residing
+  in the LS-120 drive or ZIP drive. 
+  @param IdeDev          pointer pointing to IDE_BLK_IO_DEV data structure, used
+                         to record all the information of the IDE device.
+  @param WriteProtected  if True, current media is write protected.
+                         if FALSE, current media is writable
+
+  @retval EFI_SUCCESS         The media write-protected status is achieved successfully
+  @retval EFI_DEVICE_ERROR    Get Media Status Command is failed.
+**/
+EFI_STATUS
+IsLS120orZipWriteProtected (
+  IN  IDE_BLK_IO_DEV    *IdeDev,
+  OUT BOOLEAN           *WriteProtected
+  )
+{
+  EFI_STATUS  Status;
+
+  *WriteProtected = FALSE;
+
+  Status          = LS120EnableMediaStatus (IdeDev, TRUE);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // the Get Media Status Command is only valid
+  // if a Set Features/Enable Media Status Command has been priviously issued.
+  //
+  if (LS120GetMediaStatus (IdeDev) == EFI_WRITE_PROTECTED) {
+
+    *WriteProtected = TRUE;
+  } else {
+
+    *WriteProtected = FALSE;
+  }
+
+  //
+  // After Get Media Status Command completes,
+  // Set Features/Disable Media Command should be sent.
+  //
+  Status = LS120EnableMediaStatus (IdeDev, FALSE);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Used before read/write blocks from/to ATAPI device media. Since ATAPI device 
+  media is removable, it is necessary to detect whether media is present and 
+  get current present media's information, and if media has been changed, Block
+  I/O Protocol need to be reinstalled.
+
+  @param IdeDev       pointer pointing to IDE_BLK_IO_DEV data structure, used
+                      to record all the information of the IDE device.
+  @param MediaChange  return value that indicates if the media of the device has been
+                      changed.
+
+  @retval EFI_SUCCESS       media found successfully.
+  @retval EFI_DEVICE_ERROR  any error encounters during media detection.
+  @retval EFI_NO_MEDIA      media not found.
+
+  @note
+  parameter IdeDev may be updated in this function.
+
+**/
+EFI_STATUS
+AtapiDetectMedia (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  OUT BOOLEAN         *MediaChange
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_STATUS                    CleanStateStatus;
+  EFI_BLOCK_IO_MEDIA            OldMediaInfo;
+  UINTN                         RetryTimes;
+  UINTN                         RetryNotReady;
+  SENSE_RESULT                  SResult;
+  BOOLEAN                       WriteProtected;
+
+  CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (EFI_BLOCK_IO_MEDIA));
+  *MediaChange  = FALSE;
+  //
+  // Retry for SenseDeviceNotReadyNeedRetry.
+  // Each retry takes 1s and we limit the upper boundary to
+  // 120 times about 2 min.
+  //
+  RetryNotReady = 120;
+
+  //
+  // Do Test Unit Ready
+  //
+ DoTUR:
+  //
+  // Retry 5 times
+  //
+  RetryTimes = 5;
+  while (RetryTimes != 0) {
+
+    Status = AtapiTestUnitReady (IdeDev, &SResult);
+
+    if (EFI_ERROR (Status)) {
+      //
+      // Test Unit Ready error without sense data.
+      // For some devices, this means there's extra data
+      // that has not been read, so we read these extra
+      // data out before going on.
+      //
+      CleanStateStatus = AtapiReadPendingData (IdeDev);
+      if (EFI_ERROR (CleanStateStatus)) {
+        //
+        // Busy wait failed, try again
+        //
+        RetryTimes--;
+      }
+      //
+      // Try again without counting down RetryTimes
+      //
+      continue;
+    } else {
+      switch (SResult) {
+      case SenseNoSenseKey:
+        if (IdeDev->BlkIo.Media->MediaPresent) {
+          goto Done;
+        } else {
+          //
+          // Media present but the internal structure need refreshed.
+          // Try Read Capacity
+          //
+          goto DoRC;
+        }
+        break;
+
+      case SenseDeviceNotReadyNeedRetry:
+        if (--RetryNotReady == 0) {
+          return EFI_DEVICE_ERROR;
+        }
+        gBS->Stall (1000 * STALL_1_MILLI_SECOND);
+        continue;
+        break;
+
+      case SenseNoMedia:
+        IdeDev->BlkIo.Media->MediaPresent = FALSE;
+        IdeDev->BlkIo.Media->LastBlock    = 0;
+        goto Done;
+        break;
+
+      case SenseDeviceNotReadyNoRetry:
+      case SenseMediaError:
+        return EFI_DEVICE_ERROR;
+
+      case SenseMediaChange:
+        IdeDev->BlkIo.Media->MediaId++;
+        goto DoRC;
+        break;
+
+      default:
+        RetryTimes--;
+        break;
+      }
+    }
+  }
+
+  return EFI_DEVICE_ERROR;
+
+  //
+  // Do Read Capacity
+  //
+ DoRC:
+    RetryTimes = 5;
+
+    while (RetryTimes != 0) {
+
+      Status = AtapiReadCapacity (IdeDev, &SResult);
+
+      if (EFI_ERROR (Status)) {
+        RetryTimes--;
+        continue;
+      } else {
+        switch (SResult) {
+        case SenseNoSenseKey:
+          goto Done;
+          break;
+
+        case SenseDeviceNotReadyNeedRetry:
+          //
+          // We use Test Unit Ready to retry which
+          // is faster.
+          //
+          goto DoTUR;
+          break;
+
+        case SenseNoMedia:
+          IdeDev->BlkIo.Media->MediaPresent = FALSE;
+          IdeDev->BlkIo.Media->LastBlock    = 0;
+          goto Done;
+          break;
+
+        case SenseDeviceNotReadyNoRetry:
+        case SenseMediaError:
+          return EFI_DEVICE_ERROR;
+
+        case SenseMediaChange:
+          IdeDev->BlkIo.Media->MediaId++;
+          continue;
+          break;
+
+        default:
+          RetryTimes--;
+          break;
+        }
+      }
+    }
+
+  return EFI_DEVICE_ERROR;
+
+ Done:
+  //
+  // the following code is to check the write-protected for LS120 media
+  //
+  if ((IdeDev->BlkIo.Media->MediaPresent) && (IdeDev->Type == IdeMagnetic)) {
+
+    Status = IsLS120orZipWriteProtected (IdeDev, &WriteProtected);
+    if (!EFI_ERROR (Status)) {
+
+      if (WriteProtected) {
+
+        IdeDev->BlkIo.Media->ReadOnly = TRUE;
+      } else {
+
+        IdeDev->BlkIo.Media->ReadOnly = FALSE;
+      }
+
+    }
+  }
+
+  if (IdeDev->BlkIo.Media->MediaId != OldMediaInfo.MediaId) {
+    //
+    // Media change information got from the device
+    //
+    *MediaChange = TRUE;
+  }
+
+  if (IdeDev->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) {
+    *MediaChange = TRUE;
+    IdeDev->BlkIo.Media->MediaId += 1;
+  }
+
+  if (IdeDev->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) {
+    *MediaChange = TRUE;
+    IdeDev->BlkIo.Media->MediaId += 1;
+  }
+
+  if (IdeDev->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) {
+    *MediaChange = TRUE;
+    IdeDev->BlkIo.Media->MediaId += 1;
+  }
+
+  if (IdeDev->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) {
+    if (IdeDev->BlkIo.Media->MediaPresent) {
+      //
+      // when change from no media to media present, reset the MediaId to 1.
+      //
+      IdeDev->BlkIo.Media->MediaId = 1;
+    } else {
+      //
+      // when no media, reset the MediaId to zero.
+      //
+      IdeDev->BlkIo.Media->MediaId = 0;
+    }
+
+    *MediaChange = TRUE;
+  }
+
+  //
+  // if any change on current existing media,
+  // the Block I/O protocol need to be reinstalled.
+  //
+  if (*MediaChange) {
+    gBS->ReinstallProtocolInterface (
+          IdeDev->Handle,
+          &gEfiBlockIoProtocolGuid,
+          &IdeDev->BlkIo,
+          &IdeDev->BlkIo
+          );
+  }
+
+  if (IdeDev->BlkIo.Media->MediaPresent) {
+    return EFI_SUCCESS;
+  } else {
+    return EFI_NO_MEDIA;
+  }
+}
+
+/**
+  This function is called by the AtapiBlkIoReadBlocks() to perform
+  read from media in block unit.
+
+  The main command used to access media here is READ(10) Command. 
+  READ(10) Command requests that the ATAPI device media transfer 
+  specified data to the host. Data is transferred in block(sector) 
+  unit. The maximum number of blocks that can be transferred once is
+  65536. This is the main difference between READ(10) and READ(12) 
+  Command. The maximum number of blocks in READ(12) is 2 power 32.
+
+  @param IdeDev           pointer pointing to IDE_BLK_IO_DEV data structure, used
+                          to record all the information of the IDE device.
+  @param Buffer           A pointer to the destination buffer for the data. 
+  @param Lba              The starting logical block address to read from on the 
+                          device media.
+  @param NumberOfBlocks   The number of transfer data blocks.
+
+  @return status is fully dependent on the return status of AtapiPacketCommandIn() function.
+
+**/
+EFI_STATUS
+AtapiReadSectors (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  VOID            *Buffer,
+  IN  EFI_LBA         Lba,
+  IN  UINTN           NumberOfBlocks
+  )
+{
+
+  ATAPI_PACKET_COMMAND  Packet;
+  ATAPI_READ10_CMD            *Read10Packet;
+  EFI_STATUS            Status;
+  UINTN                 BlocksRemaining;
+  UINT32                Lba32;
+  UINT32                BlockSize;
+  UINT32                ByteCount;
+  UINT16                SectorCount;
+  VOID                  *PtrBuffer;
+  UINT16                MaxBlock;
+  UINTN                 TimeOut;
+
+  //
+  // fill command packet for Read(10) command
+  //
+  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+  Read10Packet  = &Packet.Read10;
+  Lba32         = (UINT32) Lba;
+  PtrBuffer     = Buffer;
+
+  BlockSize     = IdeDev->BlkIo.Media->BlockSize;
+
+  //
+  // limit the data bytes that can be transferred by one Read(10) Command
+  //
+  MaxBlock        = 65535;
+
+  BlocksRemaining = NumberOfBlocks;
+
+  Status          = EFI_SUCCESS;
+  while (BlocksRemaining > 0) {
+
+    if (BlocksRemaining <= MaxBlock) {
+
+      SectorCount = (UINT16) BlocksRemaining;
+    } else {
+
+      SectorCount = MaxBlock;
+    }
+
+    //
+    // fill the Packet data structure
+    //
+
+    Read10Packet->opcode = ATA_CMD_READ_10;
+
+    //
+    // Lba0 ~ Lba3 specify the start logical block address of the data transfer.
+    // Lba0 is MSB, Lba3 is LSB
+    //
+    Read10Packet->Lba3  = (UINT8) (Lba32 & 0xff);
+    Read10Packet->Lba2  = (UINT8) (Lba32 >> 8);
+    Read10Packet->Lba1  = (UINT8) (Lba32 >> 16);
+    Read10Packet->Lba0  = (UINT8) (Lba32 >> 24);
+
+    //
+    // TranLen0 ~ TranLen1 specify the transfer length in block unit.
+    // TranLen0 is MSB, TranLen is LSB
+    //
+    Read10Packet->TranLen1  = (UINT8) (SectorCount & 0xff);
+    Read10Packet->TranLen0  = (UINT8) (SectorCount >> 8);
+
+    ByteCount               = SectorCount * BlockSize;
+
+    if (IdeDev->Type == IdeCdRom) {
+      TimeOut = CDROMLONGTIMEOUT;
+    } else {
+      TimeOut = ATAPILONGTIMEOUT;
+    }
+
+    Status = AtapiPacketCommandIn (
+              IdeDev,
+              &Packet,
+              (UINT16 *) PtrBuffer,
+              ByteCount,
+              TimeOut
+              );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Lba32 += SectorCount;
+    PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;
+    BlocksRemaining -= SectorCount;
+  }
+
+  return Status;
+}
+
+/**
+  This function is called by the AtapiBlkIoWriteBlocks() to perform
+  write onto media in block unit.
+  The main command used to access media here is Write(10) Command. 
+  Write(10) Command requests that the ATAPI device media transfer 
+  specified data to the host. Data is transferred in block (sector) 
+  unit. The maximum number of blocks that can be transferred once is
+  65536. 
+
+  @param IdeDev          pointer pointing to IDE_BLK_IO_DEV data structure, used
+                         to record all the information of the IDE device.
+  @param Buffer          A pointer to the source buffer for the data. 
+  @param Lba             The starting logical block address to write onto 
+                         the device media.
+  @param NumberOfBlocks  The number of transfer data blocks.
+  
+  @return status is fully dependent on the return status of AtapiPacketCommandOut() function.
+
+**/
+EFI_STATUS
+AtapiWriteSectors (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  VOID            *Buffer,
+  IN  EFI_LBA         Lba,
+  IN  UINTN           NumberOfBlocks
+  )
+{
+
+  ATAPI_PACKET_COMMAND  Packet;
+  ATAPI_READ10_CMD            *Read10Packet;
+
+  EFI_STATUS            Status;
+  UINTN                 BlocksRemaining;
+  UINT32                Lba32;
+  UINT32                BlockSize;
+  UINT32                ByteCount;
+  UINT16                SectorCount;
+  VOID                  *PtrBuffer;
+  UINT16                MaxBlock;
+
+  //
+  // fill command packet for Write(10) command
+  // Write(10) command packet has the same data structure as
+  // Read(10) command packet,
+  // so here use the Read10Packet data structure
+  // for the Write(10) command packet.
+  //
+  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+  Read10Packet  = &Packet.Read10;
+
+  Lba32         = (UINT32) Lba;
+  PtrBuffer     = Buffer;
+
+  BlockSize     = IdeDev->BlkIo.Media->BlockSize;
+
+  //
+  // limit the data bytes that can be transferred by one Read(10) Command
+  //
+  MaxBlock        = (UINT16) (65536 / BlockSize);
+
+  BlocksRemaining = NumberOfBlocks;
+
+  Status          = EFI_SUCCESS;
+  while (BlocksRemaining > 0) {
+
+    if (BlocksRemaining >= MaxBlock) {
+      SectorCount = MaxBlock;
+    } else {
+      SectorCount = (UINT16) BlocksRemaining;
+    }
+  
+    //
+    // Command code is WRITE_10.
+    //
+    Read10Packet->opcode = ATA_CMD_WRITE_10;
+
+    //
+    // Lba0 ~ Lba3 specify the start logical block address of the data transfer.
+    // Lba0 is MSB, Lba3 is LSB
+    //
+    Read10Packet->Lba3  = (UINT8) (Lba32 & 0xff);
+    Read10Packet->Lba2  = (UINT8) (Lba32 >> 8);
+    Read10Packet->Lba1  = (UINT8) (Lba32 >> 16);
+    Read10Packet->Lba0  = (UINT8) (Lba32 >> 24);
+
+    //
+    // TranLen0 ~ TranLen1 specify the transfer length in block unit.
+    // TranLen0 is MSB, TranLen is LSB
+    //
+    Read10Packet->TranLen1  = (UINT8) (SectorCount & 0xff);
+    Read10Packet->TranLen0  = (UINT8) (SectorCount >> 8);
+
+    ByteCount               = SectorCount * BlockSize;
+
+    Status = AtapiPacketCommandOut (
+              IdeDev,
+              &Packet,
+              (UINT16 *) PtrBuffer,
+              ByteCount,
+              ATAPILONGTIMEOUT
+              );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Lba32 += SectorCount;
+    PtrBuffer = ((UINT8 *) PtrBuffer + SectorCount * BlockSize);
+    BlocksRemaining -= SectorCount;
+  }
+
+  return Status;
+}
+/**
+  This function is used to implement the Soft Reset on the specified
+  ATAPI device. Different from the AtaSoftReset(), here reset is a ATA
+  Soft Reset Command special for ATAPI device, and it only take effects
+  on the specified ATAPI device, not on the whole IDE bus.
+  Since the ATAPI soft reset is needed when device is in exceptional
+  condition (such as BSY bit is always set ), I think the Soft Reset
+  command should be sent without waiting for the BSY clear and DRDY
+  set.
+  This function is called by IdeBlkIoReset(), 
+  a interface function of Block I/O protocol.
+
+  @param IdeDev    pointer pointing to IDE_BLK_IO_DEV data structure, used
+                   to record all the information of the IDE device.
+
+  @retval EFI_SUCCESS      Soft reset completes successfully.
+  @retval EFI_DEVICE_ERROR Any step during the reset process is failed.
+
+**/
+EFI_STATUS
+AtapiSoftReset (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  )
+{
+  UINT8       Command;
+  UINT8       DeviceSelect;
+  EFI_STATUS  Status;
+
+  //
+  // for ATAPI device, no need to wait DRDY ready after device selecting.
+  // (bit7 and bit5 are both set to 1 for backward compatibility)
+  //
+  DeviceSelect = (UINT8) (((BIT7 | BIT5) | (IdeDev->Device << 4)));
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);
+
+  Command = ATA_CMD_SOFT_RESET;
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, Command);
+
+  //
+  // BSY cleared is the only status return to the host by the device
+  // when reset is completed.
+  // slave device needs at most 31s to clear BSY
+  //
+  Status = WaitForBSYClear (IdeDev, 31000);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+  
+  //
+  // stall 5 seconds to make the device status stable
+  //
+  gBS->Stall (5000000);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function is the ATAPI implementation for ReadBlocks in the
+  Block I/O Protocol interface.
+
+  @param IdeBlkIoDevice Indicates the calling context.
+  @param MediaId        The media id that the read request is for.
+  @param Lba            The starting logical block address to read from on the device.
+  @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 memory that data is read into.
+  
+  @retval EFI_SUCCESS           Read Blocks successfully.
+  @retval EFI_DEVICE_ERROR      Read Blocks failed.
+  @retval EFI_NO_MEDIA          There is no media in the device.
+  @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.
+  @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of the
+                                intrinsic block size of the device.
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+                                or the data buffer is not valid.
+**/
+EFI_STATUS
+AtapiBlkIoReadBlocks (
+  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,
+  IN UINT32           MediaId,
+  IN EFI_LBA          Lba,
+  IN UINTN            BufferSize,
+  OUT VOID            *Buffer
+  )
+{
+  EFI_BLOCK_IO_MEDIA  *Media;
+  UINTN               BlockSize;
+  UINTN               NumberOfBlocks;
+  EFI_STATUS          Status;
+
+  BOOLEAN             MediaChange;
+
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BufferSize == 0) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // ATAPI device media is removable, so it is a must
+  // to detect media first before read operation
+  //
+  MediaChange = FALSE;
+  Status      = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);
+  if (EFI_ERROR (Status)) {
+
+    if (IdeBlkIoDevice->Cache != NULL) {
+      gBS->FreePool (IdeBlkIoDevice->Cache);
+      IdeBlkIoDevice->Cache = NULL;
+    }
+
+    return Status;
+  }
+  //
+  // Get the intrinsic block size
+  //
+  Media           = IdeBlkIoDevice->BlkIo.Media;
+  BlockSize       = Media->BlockSize;
+
+  NumberOfBlocks  = BufferSize / BlockSize;
+
+  if (!(Media->MediaPresent)) {
+
+    if (IdeBlkIoDevice->Cache != NULL) {
+      gBS->FreePool (IdeBlkIoDevice->Cache);
+      IdeBlkIoDevice->Cache = NULL;
+    }
+    return EFI_NO_MEDIA;
+
+  }
+
+  if ((MediaId != Media->MediaId) || MediaChange) {
+
+    if (IdeBlkIoDevice->Cache != NULL) {
+      gBS->FreePool (IdeBlkIoDevice->Cache);
+      IdeBlkIoDevice->Cache = NULL;
+    }
+    return EFI_MEDIA_CHANGED;
+  }
+
+  if (BufferSize % BlockSize != 0) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  if (Lba > Media->LastBlock) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // if all the parameters are valid, then perform read sectors command
+  // to transfer data from device to host.
+  //
+  Status = AtapiReadSectors (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+  
+  //
+  // Read blocks succeeded
+  //
+  
+  //
+  // save the first block to the cache for performance
+  //
+  if (Lba == 0 && (IdeBlkIoDevice->Cache == NULL)) {
+    IdeBlkIoDevice->Cache = AllocatePool (BlockSize);
+    if (IdeBlkIoDevice->Cache!= NULL) {
+      CopyMem ((UINT8 *) IdeBlkIoDevice->Cache, (UINT8 *) Buffer, BlockSize);
+    }
+  }
+
+  return EFI_SUCCESS;
+
+}
+/**
+  This function is the ATAPI implementation for WriteBlocks in the
+  Block I/O Protocol interface.
+
+  @param IdeBlkIoDevice  Indicates the calling context.
+  @param MediaId         The media id that the write request is for.
+  @param Lba             The starting logical block address to write onto the device.
+  @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 source buffer for the data. The caller
+                         is responsible for either having implicit or explicit ownership
+                         of the memory that data is written from.
+
+  @retval EFI_SUCCESS            Write Blocks successfully.
+  @retval EFI_DEVICE_ERROR       Write Blocks failed.
+  @retval EFI_NO_MEDIA           There is no media in the device.
+  @retval EFI_MEDIA_CHANGE       The MediaId is not for the current media.
+  @retval EFI_BAD_BUFFER_SIZE    The BufferSize parameter is not a multiple of the
+                                 intrinsic block size of the device.  
+  @retval EFI_INVALID_PARAMETER  The write request contains LBAs that are not valid, 
+                                 or the data buffer is not valid.
+
+  @retval EFI_WRITE_PROTECTED    The write protected is enabled or the media does not support write
+**/
+EFI_STATUS
+AtapiBlkIoWriteBlocks (
+  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,
+  IN UINT32           MediaId,
+  IN EFI_LBA          Lba,
+  IN UINTN            BufferSize,
+  OUT VOID            *Buffer
+  )
+{
+
+  EFI_BLOCK_IO_MEDIA  *Media;
+  UINTN               BlockSize;
+  UINTN               NumberOfBlocks;
+  EFI_STATUS          Status;
+  BOOLEAN             MediaChange;
+
+  if (Lba == 0 && IdeBlkIoDevice->Cache != NULL) {
+    gBS->FreePool (IdeBlkIoDevice->Cache);
+    IdeBlkIoDevice->Cache = NULL;
+  }
+
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BufferSize == 0) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // ATAPI device media is removable,
+  // so it is a must to detect media first before write operation
+  //
+  MediaChange = FALSE;
+  Status      = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);
+  if (EFI_ERROR (Status)) {
+
+    if (Lba == 0 && IdeBlkIoDevice->Cache != NULL) {
+      gBS->FreePool (IdeBlkIoDevice->Cache);
+      IdeBlkIoDevice->Cache = NULL;
+    }
+    return Status;
+  }
+  
+  //
+  // Get the intrinsic block size
+  //
+  Media           = IdeBlkIoDevice->BlkIo.Media;
+  BlockSize       = Media->BlockSize;
+  NumberOfBlocks  = BufferSize / BlockSize;
+
+  if (!(Media->MediaPresent)) {
+
+    if (Lba == 0 && IdeBlkIoDevice->Cache != NULL) {
+      gBS->FreePool (IdeBlkIoDevice->Cache);
+      IdeBlkIoDevice->Cache = NULL;
+    }
+    return EFI_NO_MEDIA;
+  }
+
+  if ((MediaId != Media->MediaId) || MediaChange) {
+
+    if (Lba == 0 && IdeBlkIoDevice->Cache != NULL) {
+      gBS->FreePool (IdeBlkIoDevice->Cache);
+      IdeBlkIoDevice->Cache = NULL;
+    }
+    return EFI_MEDIA_CHANGED;
+  }
+
+  if (Media->ReadOnly) {
+    return EFI_WRITE_PROTECTED;
+  }
+
+  if (BufferSize % BlockSize != 0) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  if (Lba > Media->LastBlock) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // if all the parameters are valid,
+  // then perform write sectors command to transfer data from host to device.
+  //
+  Status = AtapiWriteSectors (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+
+}
+
+
+
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/ComponentName.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/ComponentName.c	(revision 33024)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/ComponentName.c	(revision 33024)
@@ -0,0 +1,278 @@
+/** @file
+  UEFI Component Name(2) protocol implementation for ConPlatform driver.
+  
+  Copyright (c) 2006 - 2008, Intel Corporation                                                         
+  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 "IdeBus.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gIDEBusComponentName = {
+  IDEBusComponentNameGetDriverName,
+  IDEBusComponentNameGetControllerName,
+  "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gIDEBusComponentName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) IDEBusComponentNameGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) IDEBusComponentNameGetControllerName,
+  "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIDEBusDriverNameTable[] = {
+  { "eng;en", (CHAR16 *) L"PCI IDE/ATAPI Bus Driver" },
+  { NULL , NULL }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIDEBusControllerNameTable[] = {
+  { "eng;en", (CHAR16 *) L"PCI IDE/ATAPI Controller" },
+  { NULL , NULL }
+};
+
+/**
+  Retrieves a Unicode string that is the user readable name of the driver.
+
+  This function retrieves the user readable name of a driver in the form of a
+  Unicode string. If the driver specified by This has a user readable name in
+  the language specified by Language, then a pointer to the driver name is
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+  by This does not support the language specified by Language,
+  then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language. This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified
+                                in RFC 4646 or ISO 639-2 language code format.
+
+  @param  DriverName[out]       A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                driver specified by This in the language
+                                specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
+                                This and the language specified by Language was
+                                returned in DriverName.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mIDEBusDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gIDEBusComponentName)
+           );
+}
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by a driver.
+
+  This function retrieves the user readable name of the controller specified by
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the
+  driver specified by This has a user readable name in the language specified by
+  Language, then a pointer to the controller name is returned in ControllerName,
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
+  managing the controller specified by ControllerHandle and ChildHandle,
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  ControllerHandle[in]  The handle of a controller that the driver
+                                specified by This is managing.  This handle
+                                specifies the controller whose name is to be
+                                returned.
+
+  @param  ChildHandle[in]       The handle of the child controller to retrieve
+                                the name of.  This is an optional parameter that
+                                may be NULL.  It will be NULL for device
+                                drivers.  It will also be NULL for a bus drivers
+                                that wish to retrieve the name of the bus
+                                controller.  It will not be NULL for a bus
+                                driver that wishes to retrieve the name of a
+                                child controller.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language.  This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified in
+                                RFC 4646 or ISO 639-2 language code format.
+
+  @param  ControllerName[out]   A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                controller specified by ControllerHandle and
+                                ChildHandle in the language specified by
+                                Language from the point of view of the driver
+                                specified by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in
+                                the language specified by Language for the
+                                driver specified by This was returned in
+                                DriverName.
+
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
+                                managing the controller specified by
+                                ControllerHandle and ChildHandle.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  )
+{
+  EFI_STATUS            Status;
+  EFI_BLOCK_IO_PROTOCOL *BlockIo;
+  IDE_BLK_IO_DEV        *IdeBlkIoDevice;
+
+  //
+  // Make sure this driver is currently managing ControllHandle
+  //
+  Status = EfiTestManagedDevice (
+             ControllerHandle,
+             gIDEBusDriverBinding.DriverBindingHandle,
+             &gEfiIdeControllerInitProtocolGuid
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (ChildHandle == NULL) {
+    return LookupUnicodeString2 (
+             Language,
+             This->SupportedLanguages,
+             mIDEBusControllerNameTable,
+             ControllerName,
+             (BOOLEAN)(This == &gIDEBusComponentName)
+             );
+  }
+
+  Status = EfiTestChildHandle (
+             ControllerHandle,
+             ChildHandle,
+             &gEfiPciIoProtocolGuid
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Get the child context
+  //
+  Status = gBS->OpenProtocol (
+                  ChildHandle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &BlockIo,
+                  gIDEBusDriverBinding.DriverBindingHandle,
+                  ChildHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlockIo);
+
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           IdeBlkIoDevice->ControllerNameTable,
+           ControllerName,
+           (BOOLEAN)(This == &gIDEBusComponentName)
+           );
+}
+
+/**
+  Add the component name for the IDE/ATAPI device
+
+  @param  IdeBlkIoDevicePtr A pointer to the IDE_BLK_IO_DEV instance.
+
+**/
+VOID
+AddName (
+  IN  IDE_BLK_IO_DEV               *IdeBlkIoDevicePtr
+  )
+{
+  UINTN   StringIndex;
+  CHAR16  ModelName[41];
+
+  //
+  // Add Component Name for the IDE/ATAPI device that was discovered.
+  //
+  IdeBlkIoDevicePtr->ControllerNameTable = NULL;
+  for (StringIndex = 0; StringIndex < 41; StringIndex++) {
+    ModelName[StringIndex] = IdeBlkIoDevicePtr->ModelName[StringIndex];
+  }
+
+  AddUnicodeString2 (
+    "eng",
+    gIDEBusComponentName.SupportedLanguages,
+    &IdeBlkIoDevicePtr->ControllerNameTable,
+    ModelName,
+    TRUE
+    );
+  AddUnicodeString2 (
+    "en",
+    gIDEBusComponentName2.SupportedLanguages,
+    &IdeBlkIoDevicePtr->ControllerNameTable,
+    ModelName,
+    FALSE
+    );
+
+}
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/ComponentName.h
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/ComponentName.h	(revision 33024)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/ComponentName.h	(revision 33024)
@@ -0,0 +1,166 @@
+/** @file
+  
+  UEFI Component Name(2) protocol implementation header file for IDE Bus driver.
+  
+  Copyright (c) 2006, Intel Corporation
+  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.
+
+**/
+
+#ifndef _IDE_BUS_COMPONENT_NAME_H_
+#define _IDE_BUS_COMPONENT_NAME_H_
+
+#define ADD_IDE_ATAPI_NAME(x) AddName ((x));
+
+extern EFI_COMPONENT_NAME_PROTOCOL   gIDEBusComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL  gIDEBusComponentName2;
+
+
+//
+// EFI Component Name Functions
+//
+/**
+  Retrieves a Unicode string that is the user readable name of the driver.
+
+  This function retrieves the user readable name of a driver in the form of a
+  Unicode string. If the driver specified by This has a user readable name in
+  the language specified by Language, then a pointer to the driver name is
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+  by This does not support the language specified by Language,
+  then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language. This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified
+                                in RFC 4646 or ISO 639-2 language code format.
+
+  @param  DriverName[out]       A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                driver specified by This in the language
+                                specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
+                                This and the language specified by Language was
+                                returned in DriverName.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  );
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by a driver.
+
+  This function retrieves the user readable name of the controller specified by
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the
+  driver specified by This has a user readable name in the language specified by
+  Language, then a pointer to the controller name is returned in ControllerName,
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
+  managing the controller specified by ControllerHandle and ChildHandle,
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  ControllerHandle[in]  The handle of a controller that the driver
+                                specified by This is managing.  This handle
+                                specifies the controller whose name is to be
+                                returned.
+
+  @param  ChildHandle[in]       The handle of the child controller to retrieve
+                                the name of.  This is an optional parameter that
+                                may be NULL.  It will be NULL for device
+                                drivers.  It will also be NULL for a bus drivers
+                                that wish to retrieve the name of the bus
+                                controller.  It will not be NULL for a bus
+                                driver that wishes to retrieve the name of a
+                                child controller.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language.  This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified in
+                                RFC 4646 or ISO 639-2 language code format.
+
+  @param  ControllerName[out]   A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                controller specified by ControllerHandle and
+                                ChildHandle in the language specified by
+                                Language from the point of view of the driver
+                                specified by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in
+                                the language specified by Language for the
+                                driver specified by This was returned in
+                                DriverName.
+
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
+                                managing the controller specified by
+                                ControllerHandle and ChildHandle.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  );
+
+
+/**
+  Add the component name for the IDE/ATAPI device
+
+  @param  IdeBlkIoDevicePtr A pointer to the IDE_BLK_IO_DEV instance.
+
+**/
+VOID
+AddName (
+  IN  IDE_BLK_IO_DEV               *IdeBlkIoDevicePtr
+  );
+
+#endif
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/DriverConfiguration.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/DriverConfiguration.c	(revision 33024)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/DriverConfiguration.c	(revision 33024)
@@ -0,0 +1,292 @@
+/** @file
+  Implementation of UEFI Driver Configuration Protocol for IDE bus driver which 
+  provides ability to set IDE bus controller specific options.
+  
+  Copyright (c) 2006 - 2008, Intel Corporation                                                         
+  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 "IdeBus.h"
+
+CHAR16 *OptionString[4] = {
+  L"Enable Primary Master    (Y/N)? -->",
+  L"Enable Primary Slave     (Y/N)? -->",
+  L"Enable Secondary Master  (Y/N)? -->",
+  L"Enable Secondary Slave   (Y/N)? -->"
+};
+
+//
+// EFI Driver Configuration Protocol
+//
+EFI_DRIVER_CONFIGURATION_PROTOCOL gIDEBusDriverConfiguration = {
+  IDEBusDriverConfigurationSetOptions,
+  IDEBusDriverConfigurationOptionsValid,
+  IDEBusDriverConfigurationForceDefaults,
+  "eng"
+};
+
+/**
+  Interprete keyboard input.
+
+  @retval  EFI_ABORTED  Get an 'ESC' key inputed.
+  @retval  EFI_SUCCESS  Get an 'Y' or 'y' inputed.
+  @retval  EFI_NOT_FOUND Get an 'N' or 'n' inputed..
+
+**/
+EFI_STATUS
+GetResponse (
+  VOID
+  )
+{
+  EFI_STATUS    Status;
+  EFI_INPUT_KEY Key;
+
+  while (TRUE) {
+    Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+    if (!EFI_ERROR (Status)) {
+      if (Key.ScanCode == SCAN_ESC) {
+        return EFI_ABORTED;
+      }
+
+      switch (Key.UnicodeChar) {
+
+      //
+      // fall through
+      //
+      case L'y':
+      case L'Y':
+        gST->ConOut->OutputString (gST->ConOut, L"Y\n");
+        return EFI_SUCCESS;
+
+      //
+      // fall through
+      //
+      case L'n':
+      case L'N':
+        gST->ConOut->OutputString (gST->ConOut, L"N\n");
+        return EFI_NOT_FOUND;
+      }
+
+    }
+  }
+}
+
+/**
+  Allows the user to set controller specific options for a controller that a 
+  driver is currently managing.
+
+  @param  This              A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL instance.
+  @param  ControllerHandle  The handle of the controller to set options on.
+  @param  ChildHandle       The handle of the child controller to set options on.
+                            This is an optional parameter that may be NULL.
+                            It will be NULL for device drivers, and for a bus drivers
+                            that wish to set options for the bus controller.
+                            It will not be NULL for a bus driver that wishes to set
+                            options for one of its child controllers.
+  @param  Language          A pointer to a three character ISO 639-2 language identifier. 
+                            This is the language of the user interface that should be presented 
+                            to the user, and it must match one of the languages specified in 
+                            SupportedLanguages. The number of languages supported by a driver is up to
+                            the driver writer.
+  @param  ActionRequired    A pointer to the action that the calling agent is required 
+                            to perform when this function returns.
+  
+
+  @retval  EFI_SUCCESS           The driver specified by This successfully set the configuration 
+                                 options for the controller specified by ControllerHandle..
+  @retval  EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+  @retval  EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+  @retval  EFI_INVALID_PARAMETER ActionRequired is NULL.
+  @retval  EFI_UNSUPPORTED       The driver specified by This does not support setting configuration options for 
+                                 the controller specified by ControllerHandle and ChildHandle.
+  @retval  EFI_UNSUPPORTED       The driver specified by This does not support the language specified by Language.
+  @retval  EFI_DEVICE_ERROR      A device error occurred while attempt to set the configuration options for the 
+                                 controller specified by ControllerHandle and ChildHandle.
+  @retval  EFI_OUT_RESOURCES     There are not enough resources available to set the configuration options for the 
+                                 controller specified by ControllerHandle and ChildHandle
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverConfigurationSetOptions (
+  IN  EFI_DRIVER_CONFIGURATION_PROTOCOL                      *This,
+  IN  EFI_HANDLE                                             ControllerHandle,
+  IN  EFI_HANDLE                                             ChildHandle  OPTIONAL,
+  IN  CHAR8                                                  *Language,
+  OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED               *ActionRequired
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       Value;
+  UINT8       NewValue;
+  UINTN       DataSize;
+  UINTN       Index;
+
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  *ActionRequired = EfiDriverConfigurationActionNone;
+
+  DataSize        = sizeof (Value);
+  Status = gRT->GetVariable (
+                  L"Configuration",
+                  &gEfiCallerIdGuid,
+                  NULL,
+                  &DataSize,
+                  &Value
+                  );
+
+  gST->ConOut->OutputString (gST->ConOut, L"IDE Bus Driver Configuration\n");
+  gST->ConOut->OutputString (gST->ConOut, L"===============================\n");
+
+  NewValue = 0;
+  for (Index = 0; Index < 4; Index++) {
+    gST->ConOut->OutputString (gST->ConOut, OptionString[Index]);
+
+    Status = GetResponse ();
+    if (Status == EFI_ABORTED) {
+      return EFI_SUCCESS;
+    }
+
+    if (!EFI_ERROR (Status)) {
+      NewValue = (UINT8) (NewValue | (1 << Index));
+    }
+  }
+
+  if (EFI_ERROR (Status) || (NewValue != Value)) {
+    gRT->SetVariable (
+          L"Configuration",
+          &gEfiCallerIdGuid,
+          EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+          sizeof (NewValue),
+          &NewValue
+          );
+
+    *ActionRequired = EfiDriverConfigurationActionRestartController;
+  } else {
+    *ActionRequired = EfiDriverConfigurationActionNone;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Tests to see if a controller's current configuration options are valid.
+
+  @param  This             A pointer to the EFI_DRIVER_CONFIGURATION_PROTOCOL instance.
+  @param  ControllerHandle The handle of the controller to test if it's current configuration options 
+                           are valid.
+  @param  ChildHandle      The handle of the child controller to test if it's current configuration 
+                           options are valid.  This is an optional parameter that may be NULL. It will 
+                           be NULL for device drivers.  It will also be NULL for a bus drivers that
+                           wish to test the configuration options for the bus controller. It will 
+                           not be NULL for a bus driver that wishes to test configuration options for 
+                           one of its child controllers.
+  @retval  EFI_SUCCESS           The controller specified by ControllerHandle and ChildHandle that is being
+                                 managed by the driver specified by This has a valid set of  configuration
+                                 options.
+  @retval  EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+  @retval  EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+  @retval  EFI_UNSUPPORTED       The driver specified by This is not currently  managing the controller 
+                                 specified by ControllerHandle and ChildHandle.
+  @retval  EFI_DEVICE_ERROR      The controller specified by ControllerHandle and ChildHandle that is being
+                                 managed by the driver specified by This has an invalid set of configuration
+                                 options.
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverConfigurationOptionsValid (
+  IN  EFI_DRIVER_CONFIGURATION_PROTOCOL               *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle  OPTIONAL
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       Value;
+  UINTN       DataSize;
+
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  DataSize = sizeof (Value);
+  Status = gRT->GetVariable (
+                  L"Configuration",
+                  &gEfiCallerIdGuid,
+                  NULL,
+                  &DataSize,
+                  &Value
+                  );
+  if (EFI_ERROR (Status) || Value > 0x0f) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+/**
+  Forces a driver to set the default configuration options for a controller.
+
+  @param  This             A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL instance.
+  @param  ControllerHandle The handle of the controller to force default configuration options on.
+  @param  ChildHandle      The handle of the child controller to force default configuration 
+                           options on  This is an optional parameter that may be NULL.  It 
+                           will be NULL for device drivers. It will also be NULL for a bus 
+                           drivers that wish to force default configuration options for the bus
+                           controller.  It will not be NULL for a bus driver that wishes to force
+                           default configuration options for one of its child controllers.
+  @param  DefaultType      The type of default configuration options to force on the controller 
+                           specified by ControllerHandle and ChildHandle. 
+  @param  ActionRequired   A pointer to the action that the calling agent is required to perform 
+                           when this function returns.
+
+  @retval  EFI_SUCCESS           The driver specified by This successfully forced the 
+                                 default configuration options on the controller specified by 
+                                 ControllerHandle and ChildHandle.
+  @retval  EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+  @retval  EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+  @retval  EFI_INVALID_PARAMETER ActionRequired is NULL.
+  @retval  EFI_UNSUPPORTED       The driver specified by This does not support forcing the default 
+                                 configuration options on the controller specified by ControllerHandle
+                                 and ChildHandle.
+  @retval  EFI_UNSUPPORTED       The driver specified by This does not support the configuration type 
+                                 specified by DefaultType.
+  @retval  EFI_DEVICE_ERROR      A device error occurred while attempt to force the default configuration 
+                                 options on the controller specified by  ControllerHandle and ChildHandle.
+  @retval  EFI_OUT_RESOURCES     There are not enough resources available to force the default configuration 
+                                 options on the controller specified by ControllerHandle and ChildHandle.
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverConfigurationForceDefaults (
+  IN  EFI_DRIVER_CONFIGURATION_PROTOCOL                      *This,
+  IN  EFI_HANDLE                                             ControllerHandle,
+  IN  EFI_HANDLE                                             ChildHandle  OPTIONAL,
+  IN  UINT32                                                 DefaultType,
+  OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED               *ActionRequired
+  )
+{
+  UINT8 Value;
+
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Value = 0x0f;
+  gRT->SetVariable (
+        L"Configuration",
+        &gEfiCallerIdGuid,
+        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+        sizeof (Value),
+        &Value
+        );
+  *ActionRequired = EfiDriverConfigurationActionRestartController;
+  return EFI_SUCCESS;
+}
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/DriverDiagnostics.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/DriverDiagnostics.c	(revision 33024)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/DriverDiagnostics.c	(revision 33024)
@@ -0,0 +1,245 @@
+/** @file
+  Implementation of UEFI driver Dialnostics protocol which to perform diagnostic on the IDE
+  Bus controller.
+  
+  Copyright (c) 2006 - 2008, Intel Corporation                                                         
+  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 "IdeBus.h"
+
+#define IDE_BUS_DIAGNOSTIC_ERROR  L"PCI IDE/ATAPI Driver Diagnostics Failed"
+
+//
+// EFI Driver Diagnostics Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_DRIVER_DIAGNOSTICS_PROTOCOL gIDEBusDriverDiagnostics = {
+  IDEBusDriverDiagnosticsRunDiagnostics,
+  "eng"
+};
+
+//
+// EFI Driver Diagnostics 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gIDEBusDriverDiagnostics2 = {
+  (EFI_DRIVER_DIAGNOSTICS2_RUN_DIAGNOSTICS) IDEBusDriverDiagnosticsRunDiagnostics,
+  "en"
+};
+
+/**
+  Runs diagnostics on a controller.
+
+  @param  This             A pointer to the EFI_DRIVER_DIAGNOSTICS_PROTOCOLinstance.
+  @param  ControllerHandle The handle of the controller to run diagnostics on.
+  @param  ChildHandle      The handle of the child controller to run diagnostics on
+                           This is an optional parameter that may be NULL.  It will
+                           be NULL for device drivers.  It will also be NULL for a
+                           bus drivers that wish to run diagnostics on the bus controller. 
+                           It will not be NULL for a bus driver that wishes to run 
+                           diagnostics on one of its child controllers.
+  @param  DiagnosticType   Indicates type of diagnostics to perform on the controller
+                           specified by ControllerHandle and ChildHandle.
+  @param  Language         A pointer to a three character ISO 639-2 language identifier. 
+                           This is the language in which the optional error message should 
+                           be returned in Buffer, and it must match one of the languages 
+                           specified in SupportedLanguages. The number of languages supported by
+                           a driver is up to the driver writer.
+  @param  ErrorType        A GUID that defines the format of the data returned in Buffer.
+  @param  BufferSize       The size, in bytes, of the data returned in Buffer.
+  @param  Buffer           A buffer that contains a Null-terminated Unicode string
+                           plus some additional data whose format is defined by ErrorType.  
+                           Buffer is allocated by this function with AllocatePool(), and 
+                           it is the caller's responsibility to free it with a call to FreePool().
+
+  @retval  EFI_SUCCESS           The controller specified by ControllerHandle and ChildHandle passed 
+                                 the diagnostic.
+  @retval  EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+  @retval  EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+  @retval  EFI_INVALID_PARAMETER Language is NULL.
+  @retval  EFI_INVALID_PARAMETER ErrorType is NULL.
+  @retval  EFI_INVALID_PARAMETER BufferType is NULL.
+  @retval  EFI_INVALID_PARAMETER Buffer is NULL.
+  @retval  EFI_UNSUPPORTED       The driver specified by This does not support running 
+                                 diagnostics for the controller specified by ControllerHandle 
+                                 and ChildHandle.
+  @retval  EFI_UNSUPPORTED       The driver specified by This does not support the
+                                 type of diagnostic specified by DiagnosticType.
+  @retval  EFI_UNSUPPORTED       The driver specified by This does not support the language 
+                                 specified by Language.
+  @retval  EFI_OUT_OF_RESOURCES  There are not enough resources available to complete the 
+                                 diagnostics.
+  @retval  EFI_OUT_OF_RESOURCES  There are not enough resources available to return the 
+                                 status information in ErrorType, BufferSize,and Buffer.
+  @retval  EFI_DEVICE_ERROR      The controller specified by ControllerHandle and ChildHandle 
+                                 did not pass the diagnostic.
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverDiagnosticsRunDiagnostics (
+  IN  EFI_DRIVER_DIAGNOSTICS_PROTOCOL               *This,
+  IN  EFI_HANDLE                                    ControllerHandle,
+  IN  EFI_HANDLE                                    ChildHandle  OPTIONAL,
+  IN  EFI_DRIVER_DIAGNOSTIC_TYPE                    DiagnosticType,
+  IN  CHAR8                                         *Language,
+  OUT EFI_GUID                                      **ErrorType,
+  OUT UINTN                                         *BufferSize,
+  OUT CHAR16                                        **Buffer
+  )
+{
+  EFI_STATUS            Status;
+  EFI_PCI_IO_PROTOCOL   *PciIo;
+  EFI_BLOCK_IO_PROTOCOL *BlkIo;
+  IDE_BLK_IO_DEV        *IdeBlkIoDevice;
+  UINT32                VendorDeviceId;
+  VOID                  *BlockBuffer;
+  CHAR8                 *SupportedLanguages;
+  BOOLEAN               Iso639Language;
+  BOOLEAN               Found;
+  UINTN                 Index;
+
+  if (Language         == NULL ||
+      ErrorType        == NULL ||
+      Buffer           == NULL ||
+      ControllerHandle == NULL ||
+      BufferSize       == NULL) {
+
+    return EFI_INVALID_PARAMETER;
+  }
+
+  SupportedLanguages = This->SupportedLanguages;
+  Iso639Language = (BOOLEAN)(This == &gIDEBusDriverDiagnostics);
+  //
+  // Make sure Language is in the set of Supported Languages
+  //
+  Found = FALSE;
+  while (*SupportedLanguages != 0) {
+    if (Iso639Language) {
+      if (CompareMem (Language, SupportedLanguages, 3) == 0) {
+        Found = TRUE;
+        break;
+      }
+      SupportedLanguages += 3;
+    } else {
+      for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
+      if ((AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) && (Language[Index] == 0)) {
+        Found = TRUE;
+        break;
+      }
+      SupportedLanguages += Index;
+      for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
+    }
+  }
+  //
+  // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
+  //
+  if (!Found) {
+    return EFI_UNSUPPORTED;
+  }
+
+  *ErrorType  = NULL;
+  *BufferSize = 0;
+
+  if (ChildHandle == NULL) {
+    Status = gBS->OpenProtocol (
+                    ControllerHandle,
+                    &gEfiCallerIdGuid,
+                    NULL,
+                    gIDEBusDriverBinding.DriverBindingHandle,
+                    ControllerHandle,
+                    EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+                    );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Status = gBS->OpenProtocol (
+                    ControllerHandle,
+                    &gEfiPciIoProtocolGuid,
+                    (VOID **) &PciIo,
+                    gIDEBusDriverBinding.DriverBindingHandle,
+                    ControllerHandle,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                    );
+    if (EFI_ERROR (Status)) {
+      return EFI_DEVICE_ERROR;
+    }
+
+    //
+    // Use services of PCI I/O Protocol to test the PCI IDE/ATAPI Controller
+    // The following test simply reads the Device ID and Vendor ID.
+    // It should never fail.  A real test would perform more advanced
+    // diagnostics.
+    //
+
+    Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, 1, &VendorDeviceId);
+    if (EFI_ERROR (Status) || VendorDeviceId == 0xffffffff) {
+      return EFI_DEVICE_ERROR;
+    }
+
+    return EFI_SUCCESS;
+  }
+
+  Status = gBS->OpenProtocol (
+                  ChildHandle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &BlkIo,
+                  gIDEBusDriverBinding.DriverBindingHandle,
+                  ChildHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlkIo);
+
+  //
+  // Use services available from IdeBlkIoDevice to test the IDE/ATAPI device
+  //
+  Status = gBS->AllocatePool (
+                  EfiBootServicesData,
+                  IdeBlkIoDevice->BlkMedia.BlockSize,
+                  (VOID **) &BlockBuffer
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = IdeBlkIoDevice->BlkIo.ReadBlocks (
+                                  &IdeBlkIoDevice->BlkIo,
+                                  IdeBlkIoDevice->BlkMedia.MediaId,
+                                  0,
+                                  IdeBlkIoDevice->BlkMedia.BlockSize,
+                                  BlockBuffer
+                                  );
+
+  if (EFI_ERROR (Status)) {
+    *ErrorType  = &gEfiCallerIdGuid;
+    *BufferSize = sizeof (IDE_BUS_DIAGNOSTIC_ERROR);
+
+    Status = gBS->AllocatePool (
+                    EfiBootServicesData,
+                    (UINTN) (*BufferSize),
+                    (VOID **) Buffer
+                    );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    CopyMem (*Buffer, IDE_BUS_DIAGNOSTIC_ERROR, *BufferSize);
+
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  gBS->FreePool (BlockBuffer);
+
+  return Status;
+}
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/Ide.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/Ide.c	(revision 33024)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/Ide.c	(revision 33024)
@@ -0,0 +1,1330 @@
+/** @file
+  The file ontaining the helper functions implement of the Ide Bus driver
+  
+  Copyright (c) 2006 - 2008, Intel Corporation
+  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 "IdeBus.h"
+
+BOOLEAN ChannelDeviceDetected = FALSE;
+BOOLEAN SlaveDeviceExist      = FALSE;
+UINT8   SlaveDeviceType       = INVALID_DEVICE_TYPE;
+BOOLEAN MasterDeviceExist     = FALSE;
+UINT8   MasterDeviceType      = INVALID_DEVICE_TYPE;
+
+/**
+  read a one-byte data from a IDE port.
+
+  @param  PciIo  The PCI IO protocol instance
+  @param  Port   the IDE Port number 
+
+  @return  the one-byte data read from IDE port
+**/
+UINT8
+IDEReadPortB (
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN  UINT16                Port
+  )
+{
+  UINT8 Data;
+
+  Data = 0;
+  //
+  // perform 1-byte data read from register
+  //
+  PciIo->Io.Read (
+              PciIo,
+              EfiPciIoWidthUint8,
+              EFI_PCI_IO_PASS_THROUGH_BAR,
+              (UINT64) Port,
+              1,
+              &Data
+              );
+  return Data;
+}
+/**
+  Reads multiple words of data from the IDE data port.
+  Call the IO abstraction once to do the complete read,
+  not one word at a time
+
+  @param  PciIo Pointer to the EFI_PCI_IO instance
+  @param  Port IO port to read
+  @param  Count No. of UINT16's to read
+  @param  Buffer Pointer to the data buffer for read
+
+**/
+VOID
+IDEReadPortWMultiple (
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN  UINT16                Port,
+  IN  UINTN                 Count,
+  OUT VOID                  *Buffer
+  )
+{
+  UINT16  *AlignedBuffer;
+  UINT16  *WorkingBuffer;
+  UINTN   Size;
+
+  //
+  // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
+  // not perform actual I/O operations if buffer pointer passed in is not at
+  // natural boundary. The "Buffer" argument is passed in by user and may not
+  // at 16-bit natural boundary.
+  //
+  Size = sizeof (UINT16) * Count;
+
+  gBS->AllocatePool (
+        EfiBootServicesData,
+        Size + 1,
+        (VOID**)&WorkingBuffer
+        );
+
+  AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));
+
+  //
+  // Perform UINT16 data read from FIFO
+  //
+  PciIo->Io.Read (
+              PciIo,
+              EfiPciIoWidthFifoUint16,
+              EFI_PCI_IO_PASS_THROUGH_BAR,
+              (UINT64) Port,
+              Count,
+              (UINT16*)AlignedBuffer
+              );
+
+  //
+  // Copy data to user buffer
+  //
+  CopyMem (Buffer, (UINT16*)AlignedBuffer, Size);
+  gBS->FreePool (WorkingBuffer);
+}
+
+/**
+  write a 1-byte data to a specific IDE port.
+
+  @param  PciIo  PCI IO protocol instance
+  @param  Port   The IDE port to be writen
+  @param  Data   The data to write to the port
+**/
+VOID
+IDEWritePortB (
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN  UINT16                Port,
+  IN  UINT8                 Data
+  )
+{
+  //
+  // perform 1-byte data write to register
+  //
+  PciIo->Io.Write (
+              PciIo,
+              EfiPciIoWidthUint8,
+              EFI_PCI_IO_PASS_THROUGH_BAR,
+              (UINT64) Port,
+              1,
+              &Data
+              );
+
+}
+
+/**
+  write a 1-word data to a specific IDE port.
+
+  @param  PciIo  PCI IO protocol instance
+  @param  Port   The IDE port to be writen
+  @param  Data   The data to write to the port
+**/
+VOID
+IDEWritePortW (
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN  UINT16                Port,
+  IN  UINT16                Data
+  )
+{
+  //
+  // perform 1-word data write to register
+  //
+  PciIo->Io.Write (
+              PciIo,
+              EfiPciIoWidthUint16,
+              EFI_PCI_IO_PASS_THROUGH_BAR,
+              (UINT64) Port,
+              1,
+              &Data
+              );
+}
+
+/**
+  Write multiple words of data to the IDE data port.
+  Call the IO abstraction once to do the complete read,
+  not one word at a time
+
+  @param  PciIo Pointer to the EFI_PCI_IO instance
+  @param  Port IO port to read
+  @param  Count No. of UINT16's to read
+  @param  Buffer Pointer to the data buffer for read
+
+**/
+VOID
+IDEWritePortWMultiple (
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN  UINT16                Port,
+  IN  UINTN                 Count,
+  IN  VOID                  *Buffer
+  )
+{
+  UINT16  *AlignedBuffer;
+  UINT32  *WorkingBuffer;
+  UINTN   Size;
+
+  //
+  // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
+  // not perform actual I/O operations if buffer pointer passed in is not at
+  // natural boundary. The "Buffer" argument is passed in by user and may not
+  // at 16-bit natural boundary.
+  //
+  Size = sizeof (UINT16) * Count;
+
+  gBS->AllocatePool (
+        EfiBootServicesData,
+        Size + 1,
+        (VOID **) &WorkingBuffer
+        );
+
+  AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));
+
+  //
+  // Copy data from user buffer to working buffer
+  //
+  CopyMem ((UINT16 *) AlignedBuffer, Buffer, Size);
+
+  //
+  // perform UINT16 data write to the FIFO
+  //
+  PciIo->Io.Write (
+              PciIo,
+              EfiPciIoWidthFifoUint16,
+              EFI_PCI_IO_PASS_THROUGH_BAR,
+              (UINT64) Port,
+              Count,
+              (UINT16 *) AlignedBuffer
+              );
+
+  gBS->FreePool (WorkingBuffer);
+}
+/**
+  Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
+  use fixed addresses. In Native-PCI mode, get base addresses from BARs in
+  the PCI IDE controller's Configuration Space.
+
+  The steps to get IDE IO port registers' base addresses for each channel
+  as follows:
+
+  1. Examine the Programming Interface byte of the Class Code fields in PCI IDE
+  controller's Configuration Space to determine the operating mode.
+
+  2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
+  <pre>
+  ___________________________________________
+  |           | Command Block | Control Block |
+  |  Channel  |   Registers   |   Registers   |
+  |___________|_______________|_______________|
+  |  Primary  |  1F0h - 1F7h  |  3F6h - 3F7h  |
+  |___________|_______________|_______________|
+  | Secondary |  170h - 177h  |  376h - 377h  |
+  |___________|_______________|_______________|
+
+  Table 1. Compatibility resource mappings
+  </pre>
+
+  b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
+  in IDE controller's PCI Configuration Space, shown in the Table 2 below.
+  <pre>
+  ___________________________________________________
+  |           |   Command Block   |   Control Block   |
+  |  Channel  |     Registers     |     Registers     |
+  |___________|___________________|___________________|
+  |  Primary  | BAR at offset 0x10| BAR at offset 0x14|
+  |___________|___________________|___________________|
+  | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
+  |___________|___________________|___________________|
+
+  Table 2. BARs for Register Mapping
+  </pre>
+  @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for
+  primary, 0374h for secondary. So 2 bytes extra offset should be
+  added to the base addresses read from BARs.
+
+  For more details, please refer to PCI IDE Controller Specification and Intel
+  ICH4 Datasheet.
+
+  @param  PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
+  @param  IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to
+           receive IDE IO port registers' base addresses
+           
+  @retval EFI_UNSUPPORTED return this value when the BARs is not IO type
+  @retval EFI_SUCCESS     Get the Base address successfully
+  @retval other           read the pci configureation data error
+
+**/
+EFI_STATUS
+GetIdeRegistersBaseAddr (
+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,
+  OUT IDE_REGISTERS_BASE_ADDR     *IdeRegsBaseAddr
+  )
+{
+  EFI_STATUS  Status;
+  PCI_TYPE00  PciData;
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint8,
+                        0,
+                        sizeof (PciData),
+                        &PciData
+                        );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {
+    IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr  = 0x1f0;
+    IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr  = 0x3f6;
+    IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr     =
+    (UINT16)((PciData.Device.Bar[4] & 0x0000fff0));
+  } else {
+    //
+    // The BARs should be of IO type
+    //
+    if ((PciData.Device.Bar[0] & BIT0) == 0 ||
+        (PciData.Device.Bar[1] & BIT0) == 0) {
+      return EFI_UNSUPPORTED;
+    }
+
+    IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr  =
+    (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);
+    IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr  =
+    (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);
+    IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr     =
+    (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));
+  }
+
+  if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {
+    IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr  = 0x170;
+    IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr  = 0x376;
+    IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr     =
+    (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));
+  } else {
+    //
+    // The BARs should be of IO type
+    //
+    if ((PciData.Device.Bar[2] & BIT0) == 0 ||
+        (PciData.Device.Bar[3] & BIT0) == 0) {
+      return EFI_UNSUPPORTED;
+    }
+
+    IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr  =
+    (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);
+    IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr  =
+    (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);
+    IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr     =
+    (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function is used to requery IDE resources. The IDE controller will
+  probably switch between native and legacy modes during the EFI->CSM->OS
+  transfer. We do this everytime before an BlkIo operation to ensure its
+  succeess.
+
+  @param  IdeDev The BLK_IO private data which specifies the IDE device
+  
+  @retval EFI_INVALID_PARAMETER return this value when the channel is invalid
+  @retval EFI_SUCCESS           reassign the IDE IO resource successfully
+  @retval other                 get the IDE current base address effor
+
+**/
+EFI_STATUS
+ReassignIdeResources (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  )
+{
+  EFI_STATUS              Status;
+  IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel];
+  UINT16                  CommandBlockBaseAddr;
+  UINT16                  ControlBlockBaseAddr;
+
+  if (IdeDev->Channel >= IdeMaxChannel) {
+    return EFI_INVALID_PARAMETER;
+  }
+  
+  //
+  // Requery IDE IO port registers' base addresses in case of the switch of
+  // native and legacy modes
+  //
+  Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS));
+  CommandBlockBaseAddr                = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr;
+  ControlBlockBaseAddr                = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr;
+
+  IdeDev->IoPort->Data                = CommandBlockBaseAddr;
+  (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);
+  IdeDev->IoPort->SectorCount         = (UINT16) (CommandBlockBaseAddr + 0x02);
+  IdeDev->IoPort->SectorNumber        = (UINT16) (CommandBlockBaseAddr + 0x03);
+  IdeDev->IoPort->CylinderLsb         = (UINT16) (CommandBlockBaseAddr + 0x04);
+  IdeDev->IoPort->CylinderMsb         = (UINT16) (CommandBlockBaseAddr + 0x05);
+  IdeDev->IoPort->Head                = (UINT16) (CommandBlockBaseAddr + 0x06);
+
+  (*(UINT16 *) &IdeDev->IoPort->Reg)  = (UINT16) (CommandBlockBaseAddr + 0x07);
+  (*(UINT16 *) &IdeDev->IoPort->Alt)  = ControlBlockBaseAddr;
+  IdeDev->IoPort->DriveAddress        = (UINT16) (ControlBlockBaseAddr + 0x01);
+  IdeDev->IoPort->MasterSlave         = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0);
+
+  IdeDev->IoPort->BusMasterBaseAddr   = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr;
+  return EFI_SUCCESS;
+}
+
+/**
+  This function is called by DiscoverIdeDevice(). It is used for detect
+  whether the IDE device exists in the specified Channel as the specified
+  Device Number.
+
+  There is two IDE channels: one is Primary Channel, the other is
+  Secondary Channel.(Channel is the logical name for the physical "Cable".)
+  Different channel has different register group.
+
+  On each IDE channel, at most two IDE devices attach,
+  one is called Device 0 (Master device), the other is called Device 1
+  (Slave device). The devices on the same channel co-use the same register
+  group, so before sending out a command for a specified device via command
+  register, it is a must to select the current device to accept the command
+  by set the device number in the Head/Device Register.
+
+  @param IdeDev  pointer to IDE_BLK_IO_DEV data structure, used to record all the
+                 information of the IDE device.
+
+  @retval EFI_SUCCESS successfully detects device.
+
+  @retval other       any failure during detection process will return this value.
+
+**/
+EFI_STATUS
+DetectIDEController (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       SectorCountReg;
+  UINT8       LBALowReg;
+  UINT8       LBAMidReg;
+  UINT8       LBAHighReg;
+  UINT8       InitStatusReg;
+  UINT8       StatusReg;
+
+  //
+  // Select slave device
+  //
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->Head,
+    (UINT8) ((1 << 4) | 0xe0)
+    );
+  gBS->Stall (100);
+
+  //
+  // Save the init slave status register
+  //
+  InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+  //
+  // Select Master back
+  //
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->Head,
+    (UINT8) ((0 << 4) | 0xe0)
+    );
+  gBS->Stall (100);
+
+  //
+  // Send ATA Device Execut Diagnostic command.
+  // This command should work no matter DRDY is ready or not
+  //
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);
+
+  Status    = WaitForBSYClear (IdeDev, 3500);
+  if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));
+    return Status;
+  }
+  //
+  // Read device signature
+  //
+  //
+  // Select Master
+  //
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->Head,
+    (UINT8) ((0 << 4) | 0xe0)
+    );
+  gBS->Stall (100);
+  SectorCountReg = IDEReadPortB (
+                     IdeDev->PciIo,
+                     IdeDev->IoPort->SectorCount
+                     );
+  LBALowReg      = IDEReadPortB (
+                     IdeDev->PciIo,
+                     IdeDev->IoPort->SectorNumber
+                     );
+  LBAMidReg      = IDEReadPortB (
+                     IdeDev->PciIo,
+                     IdeDev->IoPort->CylinderLsb
+                     );
+  LBAHighReg     = IDEReadPortB (
+                     IdeDev->PciIo,
+                     IdeDev->IoPort->CylinderMsb
+                     );
+  if ((SectorCountReg == 0x1) &&
+      (LBALowReg      == 0x1) &&
+      (LBAMidReg      == 0x0) &&
+      (LBAHighReg     == 0x0)) {
+    MasterDeviceExist = TRUE;
+    MasterDeviceType  = ATA_DEVICE_TYPE;
+  } else {
+    if ((LBAMidReg      == 0x14) &&
+        (LBAHighReg     == 0xeb)) {
+      MasterDeviceExist = TRUE;
+      MasterDeviceType  = ATAPI_DEVICE_TYPE;
+    }
+  }
+
+  //
+  // For some Hard Drive, it takes some time to get
+  // the right signature when operating in single slave mode.
+  // We stall 20ms to work around this.
+  //
+  if (!MasterDeviceExist) {
+    gBS->Stall (20000);
+  }
+
+  //
+  // Select Slave
+  //
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->Head,
+    (UINT8) ((1 << 4) | 0xe0)
+    );
+  gBS->Stall (100);
+  SectorCountReg = IDEReadPortB (
+                     IdeDev->PciIo,
+                     IdeDev->IoPort->SectorCount
+                     );
+  LBALowReg  = IDEReadPortB (
+                 IdeDev->PciIo,
+                 IdeDev->IoPort->SectorNumber
+                 );
+  LBAMidReg  = IDEReadPortB (
+                 IdeDev->PciIo,
+                 IdeDev->IoPort->CylinderLsb
+                 );
+  LBAHighReg = IDEReadPortB (
+                 IdeDev->PciIo,
+                 IdeDev->IoPort->CylinderMsb
+                 );
+  StatusReg  = IDEReadPortB (
+                 IdeDev->PciIo,
+                 IdeDev->IoPort->Reg.Status
+                 );
+  if ((SectorCountReg == 0x1) &&
+      (LBALowReg      == 0x1) &&
+      (LBAMidReg      == 0x0) &&
+      (LBAHighReg     == 0x0)) {
+    SlaveDeviceExist = TRUE;
+    SlaveDeviceType  = ATA_DEVICE_TYPE;
+  } else {
+    if ((LBAMidReg     == 0x14) &&
+        (LBAHighReg    == 0xeb)) {
+      SlaveDeviceExist = TRUE;
+      SlaveDeviceType  = ATAPI_DEVICE_TYPE;
+    }
+  }
+
+  //
+  // When single master is plugged, slave device
+  // will be wrongly detected. Here's the workaround
+  // for ATA devices by detecting DRY bit in status
+  // register.
+  // NOTE: This workaround doesn't apply to ATAPI.
+  //
+  if (MasterDeviceExist && SlaveDeviceExist &&
+      (StatusReg & ATA_STSREG_DRDY) == 0               &&
+      (InitStatusReg & ATA_STSREG_DRDY) == 0           &&
+      MasterDeviceType == SlaveDeviceType   &&
+      SlaveDeviceType != ATAPI_DEVICE_TYPE) {
+    SlaveDeviceExist = FALSE;
+  }
+
+  //
+  // Indicate this channel has been detected
+  //
+  ChannelDeviceDetected = TRUE;
+  return EFI_SUCCESS;
+}
+/**
+  Detect if there is disk attached to this port
+
+  @param  IdeDev The BLK_IO private data which specifies the IDE device.
+  
+  @retval EFI_NOT_FOUND   The device or channel is not found
+  @retval EFI_SUCCESS     The device is found
+
+**/
+EFI_STATUS
+DiscoverIdeDevice (
+  IN IDE_BLK_IO_DEV *IdeDev
+  )
+{
+  EFI_STATUS  Status;
+  EFI_STATUS  LongPhyStatus;
+
+  //
+  // If a channel has not been checked, check it now. Then set it to "checked" state
+  // After this step, all devices in this channel have been checked.
+  //
+  if (!ChannelDeviceDetected) {
+    Status = DetectIDEController (IdeDev);
+    if (EFI_ERROR (Status)) {
+      return EFI_NOT_FOUND;
+    }
+  }
+
+  Status = EFI_NOT_FOUND;
+
+  //
+  // Device exists. test if it is an ATA device.
+  // Prefer the result from DetectIDEController,
+  // if failed, try another device type to handle
+  // devices that not follow the spec.
+  //
+  if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {
+    if (MasterDeviceType == ATA_DEVICE_TYPE) {
+      Status = ATAIdentify (IdeDev);
+      if (EFI_ERROR (Status)) {
+        Status = ATAPIIdentify (IdeDev);
+        if (!EFI_ERROR (Status)) {
+          MasterDeviceType = ATAPI_DEVICE_TYPE;
+        }
+      }
+    } else {
+      Status = ATAPIIdentify (IdeDev);
+      if (EFI_ERROR (Status)) {
+        Status = ATAIdentify (IdeDev);
+        if (!EFI_ERROR (Status)) {
+          MasterDeviceType = ATA_DEVICE_TYPE;
+        }
+      }
+    }
+  }
+  if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {
+    if (SlaveDeviceType == ATA_DEVICE_TYPE) {
+      Status = ATAIdentify (IdeDev);
+      if (EFI_ERROR (Status)) {
+        Status = ATAPIIdentify (IdeDev);
+        if (!EFI_ERROR (Status)) {
+          SlaveDeviceType = ATAPI_DEVICE_TYPE;
+        }
+      }
+    } else {
+      Status = ATAPIIdentify (IdeDev);
+      if (EFI_ERROR (Status)) {
+        Status = ATAIdentify (IdeDev);
+        if (!EFI_ERROR (Status)) {
+          SlaveDeviceType = ATA_DEVICE_TYPE;
+        }
+      }
+    }
+  }
+  if (EFI_ERROR (Status)) {
+    return EFI_NOT_FOUND;
+  }
+  //
+  // Init Block I/O interface
+  //
+  LongPhyStatus = AtaEnableLongPhysicalSector (IdeDev);
+  if (!EFI_ERROR (LongPhyStatus)) {
+    IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;
+  } else {
+    IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
+  }
+  IdeDev->BlkIo.Reset               = IDEBlkIoReset;
+  IdeDev->BlkIo.ReadBlocks          = IDEBlkIoReadBlocks;
+  IdeDev->BlkIo.WriteBlocks         = IDEBlkIoWriteBlocks;
+  IdeDev->BlkIo.FlushBlocks         = IDEBlkIoFlushBlocks;
+
+  IdeDev->BlkMedia.LogicalPartition = FALSE;
+  IdeDev->BlkMedia.WriteCaching     = FALSE;
+
+  //
+  // Init Disk Info interface
+  //
+  gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID));
+  IdeDev->DiskInfo.Inquiry    = IDEDiskInfoInquiry;
+  IdeDev->DiskInfo.Identify   = IDEDiskInfoIdentify;
+  IdeDev->DiskInfo.SenseData  = IDEDiskInfoSenseData;
+  IdeDev->DiskInfo.WhichIde   = IDEDiskInfoWhichIde;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This interface is used to initialize all state data related to the detection of one
+  channel.
+**/
+VOID
+InitializeIDEChannelData (
+  VOID
+  )
+{
+  ChannelDeviceDetected = FALSE;
+  MasterDeviceExist = FALSE;
+  MasterDeviceType  = 0xff;
+  SlaveDeviceExist  = FALSE;
+  SlaveDeviceType   = 0xff;
+}
+/**
+  This function is used to poll for the DRQ bit clear in the Status
+  Register. DRQ is cleared when the device is finished transferring data.
+  So this function is called after data transfer is finished.
+
+  @param IdeDev                 pointer pointing to IDE_BLK_IO_DEV data structure, used 
+                                to record all the information of the IDE device.
+  @param TimeoutInMilliSeconds  used to designate the timeout for the DRQ clear.
+
+  @retval EFI_SUCCESS           DRQ bit clear within the time out.
+
+  @retval EFI_TIMEOUT           DRQ bit not clear within the time out.
+
+  @note
+  Read Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+DRQClear (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINTN           TimeoutInMilliSeconds
+  )
+{
+  UINT32  Delay;
+  UINT8   StatusRegister;
+  UINT8   ErrorRegister;
+
+  Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+  do {
+
+    StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+    //
+    // wait for BSY == 0 and DRQ == 0
+    //
+    if ((StatusRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {
+      break;
+    }
+
+    if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+      ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+        return EFI_ABORTED;
+      }
+    }
+
+    //
+    //  Stall for 30 us
+    //
+    gBS->Stall (30);
+
+    Delay--;
+
+  } while (Delay > 0);
+
+  if (Delay == 0) {
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+/**
+  This function is used to poll for the DRQ bit clear in the Alternate
+  Status Register. DRQ is cleared when the device is finished
+  transferring data. So this function is called after data transfer
+  is finished.
+
+  @param IdeDev                pointer pointing to IDE_BLK_IO_DEV data structure, used 
+                               to record all the information of the IDE device.
+
+  @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.
+
+  @retval EFI_SUCCESS          DRQ bit clear within the time out.
+
+  @retval EFI_TIMEOUT          DRQ bit not clear within the time out.
+  @note   Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+DRQClear2 (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINTN           TimeoutInMilliSeconds
+  )
+{
+  UINT32  Delay;
+  UINT8   AltRegister;
+  UINT8   ErrorRegister;
+
+  Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+  do {
+
+    AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
+
+    //
+    //  wait for BSY == 0 and DRQ == 0
+    //
+    if ((AltRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {
+      break;
+    }
+
+    if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+      ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+        return EFI_ABORTED;
+      }
+    }
+
+    //
+    // Stall for 30 us
+    //
+    gBS->Stall (30);
+
+    Delay--;
+
+  } while (Delay > 0);
+
+  if (Delay == 0) {
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function is used to poll for the DRQ bit set in the
+  Status Register.
+  DRQ is set when the device is ready to transfer data. So this function
+  is called after the command is sent to the device and before required
+  data is transferred.
+
+  @param IdeDev                pointer pointing to IDE_BLK_IO_DEV data structure,used to
+                               record all the information of the IDE device.
+  @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
+
+  @retval EFI_SUCCESS          DRQ bit set within the time out.
+  @retval EFI_TIMEOUT          DRQ bit not set within the time out.
+  @retval EFI_ABORTED          DRQ bit not set caused by the command abort.
+
+  @note  Read Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+DRQReady (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINTN           TimeoutInMilliSeconds
+  )
+{
+  UINT32  Delay;
+  UINT8   StatusRegister;
+  UINT8   ErrorRegister;
+
+  Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+  do {
+    //
+    //  read Status Register will clear interrupt
+    //
+    StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+    //
+    //  BSY==0,DRQ==1
+    //
+    if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
+      break;
+    }
+
+    if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+      ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+        return EFI_ABORTED;
+      }
+    }
+
+    //
+    // Stall for 30 us
+    //
+    gBS->Stall (30);
+
+    Delay--;
+  } while (Delay > 0);
+
+  if (Delay == 0) {
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+/**
+  This function is used to poll for the DRQ bit set in the Alternate Status Register.
+  DRQ is set when the device is ready to transfer data. So this function is called after 
+  the command is sent to the device and before required data is transferred.
+
+  @param IdeDev                pointer pointing to IDE_BLK_IO_DEV data structure, used to 
+                               record all the information of the IDE device.
+
+  @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
+
+  @retval EFI_SUCCESS           DRQ bit set within the time out.
+  @retval EFI_TIMEOUT           DRQ bit not set within the time out.
+  @retval EFI_ABORTED           DRQ bit not set caused by the command abort.
+  @note  Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+DRQReady2 (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINTN           TimeoutInMilliSeconds
+  )
+{
+  UINT32  Delay;
+  UINT8   AltRegister;
+  UINT8   ErrorRegister;
+
+  Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+
+  do {
+    //
+    //  Read Alternate Status Register will not clear interrupt status
+    //
+    AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
+    //
+    // BSY == 0 , DRQ == 1
+    //
+    if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
+      break;
+    }
+
+    if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+      ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+        return EFI_ABORTED;
+      }
+    }
+
+    //
+    // Stall for 30 us
+    //
+    gBS->Stall (30);
+
+    Delay--;
+  } while (Delay > 0);
+
+  if (Delay == 0) {
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function is used to poll for the BSY bit clear in the Status Register. BSY
+  is clear when the device is not busy. Every command must be sent after device is not busy.
+
+  @param IdeDev                pointer pointing to IDE_BLK_IO_DEV data structure, used 
+                               to record all the information of the IDE device.
+  @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
+
+  @retval EFI_SUCCESS          BSY bit clear within the time out.
+  @retval EFI_TIMEOUT          BSY bit not clear within the time out.
+
+  @note Read Status Register will clear interrupt status.
+**/
+EFI_STATUS
+WaitForBSYClear (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINTN           TimeoutInMilliSeconds
+  )
+{
+  UINT32  Delay;
+  UINT8   StatusRegister;
+
+  Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+  do {
+
+    StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+    if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {
+      break;
+    }
+
+    //
+    // Stall for 30 us
+    //
+    gBS->Stall (30);
+
+    Delay--;
+
+  } while (Delay > 0);
+
+  if (Delay == 0) {
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+/**
+  This function is used to poll for the BSY bit clear in the Alternate Status Register. 
+  BSY is clear when the device is not busy. Every command must be sent after device is 
+  not busy.
+
+  @param IdeDev               pointer pointing to IDE_BLK_IO_DEV data structure, used to record 
+                              all the information of the IDE device.
+  @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
+
+  @retval EFI_SUCCESS         BSY bit clear within the time out.
+  @retval EFI_TIMEOUT         BSY bit not clear within the time out.
+  @note   Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+WaitForBSYClear2 (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINTN           TimeoutInMilliSeconds
+  )
+{
+  UINT32  Delay;
+  UINT8   AltRegister;
+
+  Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+  do {
+    AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
+    if ((AltRegister & ATA_STSREG_BSY) == 0x00) {
+      break;
+    }
+
+    gBS->Stall (30);
+
+    Delay--;
+
+  } while (Delay > 0);
+
+  if (Delay == 0) {
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+/**
+  This function is used to poll for the DRDY bit set in the Status Register. DRDY
+  bit is set when the device is ready to accept command. Most ATA commands must be 
+  sent after DRDY set except the ATAPI Packet Command.
+
+  @param IdeDev               pointer pointing to IDE_BLK_IO_DEV data structure, used
+                              to record all the information of the IDE device.
+  @param DelayInMilliSeconds  used to designate the timeout for the DRQ ready.
+
+  @retval EFI_SUCCESS         DRDY bit set within the time out.
+  @retval EFI_TIMEOUT         DRDY bit not set within the time out.
+
+  @note  Read Status Register will clear interrupt status.
+**/
+EFI_STATUS
+DRDYReady (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINTN           DelayInMilliSeconds
+  )
+{
+  UINT32  Delay;
+  UINT8   StatusRegister;
+  UINT8   ErrorRegister;
+
+  Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+  do {
+    StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+    //
+    //  BSY == 0 , DRDY == 1
+    //
+    if ((StatusRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {
+      break;
+    }
+
+    if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+      ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+        return EFI_ABORTED;
+      }
+    }
+
+    gBS->Stall (30);
+
+    Delay--;
+  } while (Delay > 0);
+
+  if (Delay == 0) {
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+/**
+  This function is used to poll for the DRDY bit set in the Alternate Status Register. 
+  DRDY bit is set when the device is ready to accept command. Most ATA commands must 
+  be sent after DRDY set except the ATAPI Packet Command.
+
+  @param IdeDev              pointer pointing to IDE_BLK_IO_DEV data structure, used
+                             to record all the information of the IDE device.
+  @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.
+
+  @retval EFI_SUCCESS      DRDY bit set within the time out.
+  @retval EFI_TIMEOUT      DRDY bit not set within the time out.
+
+  @note  Read Alternate Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+DRDYReady2 (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINTN           DelayInMilliSeconds
+  )
+{
+  UINT32  Delay;
+  UINT8   AltRegister;
+  UINT8   ErrorRegister;
+
+  Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+  do {
+    AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
+    //
+    //  BSY == 0 , DRDY == 1
+    //
+    if ((AltRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {
+      break;
+    }
+
+    if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+      ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+        return EFI_ABORTED;
+      }
+    }
+
+    gBS->Stall (30);
+
+    Delay--;
+  } while (Delay > 0);
+
+  if (Delay == 0) {
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+/**
+  Release resources of an IDE device before stopping it.
+
+  @param IdeBlkIoDevice  Standard IDE device private data structure
+
+**/
+VOID
+ReleaseIdeResources (
+  IN  IDE_BLK_IO_DEV  *IdeBlkIoDevice
+  )
+{
+  if (IdeBlkIoDevice == NULL) {
+    return ;
+  }
+
+  //
+  // Release all the resourses occupied by the IDE_BLK_IO_DEV
+  //
+
+  if (IdeBlkIoDevice->SenseData != NULL) {
+    gBS->FreePool (IdeBlkIoDevice->SenseData);
+    IdeBlkIoDevice->SenseData = NULL;
+  }
+
+  if (IdeBlkIoDevice->Cache != NULL) {
+    gBS->FreePool (IdeBlkIoDevice->Cache);
+    IdeBlkIoDevice->Cache = NULL;
+  }
+
+  if (IdeBlkIoDevice->IdData != NULL) {
+    gBS->FreePool (IdeBlkIoDevice->IdData);
+    IdeBlkIoDevice->IdData = NULL;
+  }
+
+  if (IdeBlkIoDevice->InquiryData != NULL) {
+    gBS->FreePool (IdeBlkIoDevice->InquiryData);
+    IdeBlkIoDevice->InquiryData = NULL;
+  }
+
+  if (IdeBlkIoDevice->ControllerNameTable != NULL) {
+    FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);
+    IdeBlkIoDevice->ControllerNameTable = NULL;
+  }
+
+  if (IdeBlkIoDevice->IoPort != NULL) {
+    gBS->FreePool (IdeBlkIoDevice->IoPort);
+  }
+
+  if (IdeBlkIoDevice->DevicePath != NULL) {
+    gBS->FreePool (IdeBlkIoDevice->DevicePath);
+  }
+
+  if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {
+    gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);
+    IdeBlkIoDevice->ExitBootServiceEvent = NULL;
+  }
+
+  gBS->FreePool (IdeBlkIoDevice);
+  IdeBlkIoDevice = NULL;
+
+  return ;
+}
+/**
+  Set the calculated Best transfer mode to a detected device.
+
+  @param IdeDev       Standard IDE device private data structure
+  @param TransferMode The device transfer mode to be set
+  @return Set transfer mode Command execute status.
+
+**/
+EFI_STATUS
+SetDeviceTransferMode (
+  IN IDE_BLK_IO_DEV       *IdeDev,
+  IN ATA_TRANSFER_MODE    *TransferMode
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       DeviceSelect;
+  UINT8       SectorCount;
+
+  DeviceSelect  = 0;
+  DeviceSelect  = (UINT8) ((IdeDev->Device) << 4);
+  SectorCount   = *((UINT8 *) TransferMode);
+
+  //
+  // Send SET FEATURE command (sub command 0x03) to set pio mode.
+  //
+  Status = AtaNonDataCommandIn (
+            IdeDev,
+            ATA_CMD_SET_FEATURES,
+            DeviceSelect,
+            0x03,
+            SectorCount,
+            0,
+            0,
+            0
+            );
+
+  return Status;
+}
+/**
+  Set drive parameters for devices not support PACKETS command.
+
+  @param IdeDev          Standard IDE device private data structure
+  @param DriveParameters The device parameters to be set into the disk
+  @return SetParameters Command execute status.
+
+**/
+EFI_STATUS
+SetDriveParameters (
+  IN IDE_BLK_IO_DEV       *IdeDev,
+  IN ATA_DRIVE_PARMS      *DriveParameters
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       DeviceSelect;
+
+  DeviceSelect  = 0;
+  DeviceSelect  = (UINT8) ((IdeDev->Device) << 4);
+
+  //
+  // Send Init drive parameters
+  //
+  Status = AtaNonDataCommandIn (
+            IdeDev,
+            ATA_CMD_INIT_DRIVE_PARAM,
+            (UINT8) (DeviceSelect + DriveParameters->Heads),
+            0,
+            DriveParameters->Sector,
+            0,
+            0,
+            0
+            );
+
+  //
+  // Send Set Multiple parameters
+  //
+  Status = AtaNonDataCommandIn (
+            IdeDev,
+            ATA_CMD_SET_MULTIPLE_MODE,
+            DeviceSelect,
+            0,
+            DriveParameters->MultipleSector,
+            0,
+            0,
+            0
+            );
+  return Status;
+}
+
+/**
+  Enable Interrupt on IDE controller.
+
+  @param  IdeDev   Standard IDE device private data structure
+
+  @retval  EFI_SUCCESS Enable Interrupt successfully
+**/
+EFI_STATUS
+EnableInterrupt (
+  IN IDE_BLK_IO_DEV       *IdeDev
+  )
+{
+  UINT8 DeviceControl;
+
+  //
+  // Enable interrupt for DMA operation
+  //
+  DeviceControl = 0;
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+  return EFI_SUCCESS;
+}
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/Ide.h
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/Ide.h	(revision 33024)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/Ide.h	(revision 33024)
@@ -0,0 +1,835 @@
+/** @file
+  Header file for IDE Bus Driver, containing the helper functions'
+  prototype.
+
+  Copyright (c) 2006 - 2007 Intel Corporation. <BR>
+  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.
+
+  @par Revision Reference:
+  2002-6: Add Atapi6 enhancement, support >120GB hard disk, including
+  Add - IDEBlkIoReadBlocksExt() func definition
+  Add - IDEBlkIoWriteBlocksExt() func definition
+
+**/
+
+#ifndef _IDE_H_
+#define _IDE_H_
+
+//
+// Helper functions Prototype
+//
+/**
+  read a one-byte data from a IDE port.
+
+  @param  PciIo  The PCI IO protocol instance
+  @param  Port   the IDE Port number 
+
+  return  the one-byte data read from IDE port
+**/
+UINT8
+IDEReadPortB (
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN  UINT16                Port
+  );
+
+/**
+  Reads multiple words of data from the IDE data port.
+  Call the IO abstraction once to do the complete read,
+  not one word at a time.
+
+  @param  PciIo Pointer to the EFI_PCI_IO instance
+  @param  Port IO port to read
+  @param  Count No. of UINT16's to read
+  @param  Buffer Pointer to the data buffer for read
+
+**/
+VOID
+IDEReadPortWMultiple (
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN  UINT16                Port,
+  IN  UINTN                 Count,
+  OUT  VOID                 *Buffer
+  );
+
+/**
+  write a 1-byte data to a specific IDE port.
+
+  @param  PciIo  PCI IO protocol instance
+  @param  Port   The IDE port to be writen
+  @param  Data   The data to write to the port
+**/
+VOID
+IDEWritePortB (
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN  UINT16                Port,
+  IN  UINT8                 Data
+  );
+
+/**
+  write a 1-word data to a specific IDE port.
+
+  @param  PciIo  PCI IO protocol instance
+  @param  Port   The IDE port to be writen
+  @param  Data   The data to write to the port
+**/
+VOID
+IDEWritePortW (
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN  UINT16                Port,
+  IN  UINT16                Data
+  );
+
+/**
+  Write multiple words of data to the IDE data port.
+  Call the IO abstraction once to do the complete read,
+  not one word at a time.
+
+  @param  PciIo Pointer to the EFI_PCI_IO instance
+  @param  Port IO port to read
+  @param  Count No. of UINT16's to read
+  @param  Buffer Pointer to the data buffer for read
+
+**/
+VOID
+IDEWritePortWMultiple (
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN  UINT16                Port,
+  IN  UINTN                 Count,
+  IN  VOID                  *Buffer
+  );
+
+/**
+  Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
+  use fixed addresses. In Native-PCI mode, get base addresses from BARs in
+  the PCI IDE controller's Configuration Space.
+
+  The steps to get IDE IO port registers' base addresses for each channel
+  as follows:
+
+  1. Examine the Programming Interface byte of the Class Code fields in PCI IDE
+  controller's Configuration Space to determine the operating mode.
+
+  2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
+  <pre>
+  ___________________________________________
+  |           | Command Block | Control Block |
+  |  Channel  |   Registers   |   Registers   |
+  |___________|_______________|_______________|
+  |  Primary  |  1F0h - 1F7h  |  3F6h - 3F7h  |
+  |___________|_______________|_______________|
+  | Secondary |  170h - 177h  |  376h - 377h  |
+  |___________|_______________|_______________|
+
+  Table 1. Compatibility resource mappings
+  </pre>
+
+  b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
+  in IDE controller's PCI Configuration Space, shown in the Table 2 below.
+  <pre>
+  ___________________________________________________
+  |           |   Command Block   |   Control Block   |
+  |  Channel  |     Registers     |     Registers     |
+  |___________|___________________|___________________|
+  |  Primary  | BAR at offset 0x10| BAR at offset 0x14|
+  |___________|___________________|___________________|
+  | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
+  |___________|___________________|___________________|
+
+  Table 2. BARs for Register Mapping
+  </pre>
+  @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for
+  primary, 0374h for secondary. So 2 bytes extra offset should be
+  added to the base addresses read from BARs.
+
+  For more details, please refer to PCI IDE Controller Specification and Intel
+  ICH4 Datasheet.
+
+  @param  PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
+  @param  IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to
+          receive IDE IO port registers' base addresses
+  
+  @retval EFI_UNSUPPORTED return this value when the BARs is not IO type
+  @retval EFI_SUCCESS     Get the Base address successfully
+  @retval other           read the pci configureation data error
+
+**/
+EFI_STATUS
+GetIdeRegistersBaseAddr (
+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,
+  OUT IDE_REGISTERS_BASE_ADDR     *IdeRegsBaseAddr
+  );
+
+/**
+  This function is used to requery IDE resources. The IDE controller will
+  probably switch between native and legacy modes during the EFI->CSM->OS
+  transfer. We do this everytime before an BlkIo operation to ensure its
+  succeess.
+
+  @param  IdeDev The BLK_IO private data which specifies the IDE device
+
+  @retval EFI_INVALID_PARAMETER return this value when the channel is invalid
+  @retval EFI_SUCCESS           reassign the IDE IO resource successfully
+  @retval other                 get the IDE current base address effor
+
+**/
+EFI_STATUS
+ReassignIdeResources (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  );
+
+/**
+  Detect if there is disk attached to this port.
+
+  @param  IdeDev The BLK_IO private data which specifies the IDE device.
+  
+  @retval EFI_NOT_FOUND   The device or channel is not found
+  @retval EFI_SUCCESS     The device is found
+
+**/
+EFI_STATUS
+DiscoverIdeDevice (
+  IN IDE_BLK_IO_DEV *IdeDev
+  );
+
+/**
+  This interface is used to initialize all state data related to the
+  detection of one channel.
+
+**/
+VOID
+InitializeIDEChannelData (
+  VOID
+  );
+
+/**
+  This function is used to poll for the DRQ bit clear in the Status
+  Register. DRQ is cleared when the device is finished transferring data.
+  So this function is called after data transfer is finished.
+
+  @param IdeDev                 pointer pointing to IDE_BLK_IO_DEV data structure, used 
+                                to record all the information of the IDE device.
+  @param TimeoutInMilliSeconds  used to designate the timeout for the DRQ clear.
+
+  @retval EFI_SUCCESS           DRQ bit clear within the time out.
+
+  @retval EFI_TIMEOUT           DRQ bit not clear within the time out.
+
+  @note
+  Read Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+DRQClear (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINTN           TimeoutInMilliSeconds
+  );
+
+/**
+  This function is used to poll for the DRQ bit clear in the Alternate
+  Status Register. DRQ is cleared when the device is finished
+  transferring data. So this function is called after data transfer
+  is finished.
+
+  @param IdeDev                pointer pointing to IDE_BLK_IO_DEV data structure, used 
+                               to record all the information of the IDE device.
+
+  @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.
+
+  @retval EFI_SUCCESS          DRQ bit clear within the time out.
+
+  @retval EFI_TIMEOUT          DRQ bit not clear within the time out.
+  @note
+  Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+DRQClear2 (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINTN           TimeoutInMilliSeconds
+  );
+
+/**
+  This function is used to poll for the DRQ bit set in the
+  Status Register.
+  DRQ is set when the device is ready to transfer data. So this function
+  is called after the command is sent to the device and before required
+  data is transferred.
+
+  @param IdeDev                pointer pointing to IDE_BLK_IO_DEV data structure,used to
+                               record all the information of the IDE device.
+  @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
+
+  @retval EFI_SUCCESS          DRQ bit set within the time out.
+  @retval EFI_TIMEOUT          DRQ bit not set within the time out.
+  @retval EFI_ABORTED          DRQ bit not set caused by the command abort.
+
+  @note  Read Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+DRQReady (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINTN           TimeoutInMilliSeconds
+  );
+
+/**
+  This function is used to poll for the DRQ bit set in the Alternate Status Register.
+  DRQ is set when the device is ready to transfer data. So this function is called after 
+  the command is sent to the device and before required data is transferred.
+
+  @param IdeDev                pointer pointing to IDE_BLK_IO_DEV data structure, used to 
+                               record all the information of the IDE device.
+
+  @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
+
+  @retval EFI_SUCCESS           DRQ bit set within the time out.
+  @retval EFI_TIMEOUT           DRQ bit not set within the time out.
+  @retval EFI_ABORTED           DRQ bit not set caused by the command abort.
+  @note  Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+DRQReady2 (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINTN           TimeoutInMilliSeconds
+  );
+
+/**
+  This function is used to poll for the BSY bit clear in the Status Register. BSY
+  is clear when the device is not busy. Every command must be sent after device is not busy.
+
+  @param IdeDev                pointer pointing to IDE_BLK_IO_DEV data structure, used 
+                               to record all the information of the IDE device.
+  @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
+
+  @retval EFI_SUCCESS          BSY bit clear within the time out.
+  @retval EFI_TIMEOUT          BSY bit not clear within the time out.
+
+  @note Read Status Register will clear interrupt status.
+**/
+EFI_STATUS
+WaitForBSYClear (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINTN           TimeoutInMilliSeconds
+  );
+
+/**
+  This function is used to poll for the BSY bit clear in the Alternate Status Register. 
+  BSY is clear when the device is not busy. Every command must be sent after device is 
+  not busy.
+
+  @param IdeDev               pointer pointing to IDE_BLK_IO_DEV data structure, used to record 
+                              all the information of the IDE device.
+  @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
+
+  @retval EFI_SUCCESS         BSY bit clear within the time out.
+  @retval EFI_TIMEOUT         BSY bit not clear within the time out.
+  @note   Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+WaitForBSYClear2 (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINTN           TimeoutInMilliSeconds
+  );
+
+/**
+  This function is used to poll for the DRDY bit set in the Status Register. DRDY
+  bit is set when the device is ready to accept command. Most ATA commands must be 
+  sent after DRDY set except the ATAPI Packet Command.
+
+  @param IdeDev               pointer pointing to IDE_BLK_IO_DEV data structure, used
+                              to record all the information of the IDE device.
+  @param DelayInMilliSeconds  used to designate the timeout for the DRQ ready.
+
+  @retval EFI_SUCCESS         DRDY bit set within the time out.
+  @retval EFI_TIMEOUT         DRDY bit not set within the time out.
+
+  @note  Read Status Register will clear interrupt status.
+**/
+EFI_STATUS
+DRDYReady (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINTN           DelayInMilliSeconds
+  );
+
+/**
+  This function is used to poll for the DRDY bit set in the Alternate Status Register. 
+  DRDY bit is set when the device is ready to accept command. Most ATA commands must 
+  be sent after DRDY set except the ATAPI Packet Command.
+
+  @param IdeDev              pointer pointing to IDE_BLK_IO_DEV data structure, used
+                             to record all the information of the IDE device.
+  @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.
+
+  @retval EFI_SUCCESS      DRDY bit set within the time out.
+  @retval EFI_TIMEOUT      DRDY bit not set within the time out.
+
+  @note  Read Alternate Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+DRDYReady2 (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINTN           DelayInMilliSeconds
+  );
+
+//
+//  ATA device functions' prototype
+//
+/**
+  Sends out an ATA Identify Command to the specified device.
+
+  This function is called by DiscoverIdeDevice() during its device
+  identification. It sends out the ATA Identify Command to the
+  specified device. Only ATA device responses to this command. If
+  the command succeeds, it returns the Identify data structure which
+  contains information about the device. This function extracts the
+  information it needs to fill the IDE_BLK_IO_DEV data structure,
+  including device type, media block size, media capacity, and etc.
+
+  @param IdeDev  pointer pointing to IDE_BLK_IO_DEV data structure,used to record 
+                 all the information of the IDE device.
+
+  @retval EFI_SUCCESS      Identify ATA device successfully.
+  @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device.
+  @note  parameter IdeDev will be updated in this function.
+
+**/
+EFI_STATUS
+ATAIdentify (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  );
+
+/**
+  This function is called by ATAIdentify() or ATAPIIdentify() to print device's module name.
+
+  @param  IdeDev   pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+                   all the information of the IDE device.
+**/
+VOID
+PrintAtaModuleName (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  );
+/**
+  This function is used to send out ATA commands conforms to the PIO Data In Protocol.
+
+  @param IdeDev       pointer pointing to IDE_BLK_IO_DEV data structure, used to record 
+                      all the information of the IDE device.
+  @param Buffer       buffer contained data transferred from device to host.
+  @param ByteCount    data size in byte unit of the buffer.
+  @param AtaCommand   value of the Command Register
+  @param Head         value of the Head/Device Register
+  @param SectorCount  value of the Sector Count Register
+  @param SectorNumber value of the Sector Number Register
+  @param CylinderLsb  value of the low byte of the Cylinder Register
+  @param CylinderMsb  value of the high byte of the Cylinder Register
+  
+  @retval EFI_SUCCESS      send out the ATA command and device send required data successfully.
+  @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+EFI_STATUS
+AtaPioDataIn (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  VOID            *Buffer,
+  IN  UINT32          ByteCount,
+  IN  UINT8           AtaCommand,
+  IN  UINT8           Head,
+  IN  UINT8           SectorCount,
+  IN  UINT8           SectorNumber,
+  IN  UINT8           CylinderLsb,
+  IN  UINT8           CylinderMsb
+  );
+
+/**
+  This function is used to send out ATA commands conforms to the
+  PIO Data Out Protocol.
+
+  @param IdeDev       pointer pointing to IDE_BLK_IO_DEV data structure, used
+                      to record all the information of the IDE device.
+  @param *Buffer      buffer contained data transferred from host to device.
+  @param ByteCount    data size in byte unit of the buffer.
+  @param AtaCommand   value of the Command Register
+  @param Head         value of the Head/Device Register
+  @param SectorCount  value of the Sector Count Register
+  @param SectorNumber value of the Sector Number Register
+  @param CylinderLsb  value of the low byte of the Cylinder Register
+  @param CylinderMsb  value of the high byte of the Cylinder Register
+
+  @retval EFI_SUCCESS      send out the ATA command and device received required
+                           data successfully.
+  @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+EFI_STATUS
+AtaPioDataOut (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  VOID            *Buffer,
+  IN  UINT32          ByteCount,
+  IN  UINT8           AtaCommand,
+  IN  UINT8           Head,
+  IN  UINT8           SectorCount,
+  IN  UINT8           SectorNumber,
+  IN  UINT8           CylinderLsb,
+  IN  UINT8           CylinderMsb
+  );
+
+/**
+  This function is used to analyze the Status Register and print out
+  some debug information and if there is ERR bit set in the Status
+  Register, the Error Register's value is also be parsed and print out.
+
+  @param IdeDev  pointer pointing to IDE_BLK_IO_DEV data structure, used to 
+                 record all the information of the IDE device.
+
+  @retval EFI_SUCCESS       No err information in the Status Register.
+  @retval EFI_DEVICE_ERROR  Any err information in the Status Register.
+
+**/
+EFI_STATUS
+CheckErrorStatus (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  );
+
+/**
+  This function is used to implement the Soft Reset on the specified device. But,
+  the ATA Soft Reset mechanism is so strong a reset method that it will force 
+  resetting on both devices connected to the same cable.
+
+  It is called by IdeBlkIoReset(), a interface function of Block
+  I/O protocol.
+
+  This function can also be used by the ATAPI device to perform reset when
+  ATAPI Reset command is failed.
+
+  @param IdeDev  pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+                 all the information of the IDE device.
+  @retval EFI_SUCCESS       Soft reset completes successfully.
+  @retval EFI_DEVICE_ERROR  Any step during the reset process is failed.
+
+  @note  The registers initial values after ATA soft reset are different
+         to the ATA device and ATAPI device.
+**/
+EFI_STATUS
+AtaSoftReset (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  );
+
+/**
+  This function is the ATA implementation for ReadBlocks in the
+  Block I/O Protocol interface.
+
+  @param IdeBlkIoDevice Indicates the calling context.
+  @param MediaId        The media id that the read request is for.
+  @param Lba            The starting logical block address to read from on the device.
+  @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 memory that data is read into.
+
+  @retval EFI_SUCCESS          Read Blocks successfully.
+  @retval EFI_DEVICE_ERROR     Read Blocks failed.
+  @retval EFI_NO_MEDIA         There is no media in the device.
+  @retval EFI_MEDIA_CHANGE     The MediaId is not for the current media.
+  @retval EFI_BAD_BUFFER_SIZE  The BufferSize parameter is not a multiple of the
+                               intrinsic block size of the device.
+  @retval EFI_INVALID_PARAMETER  The read request contains LBAs that are not valid,
+                                 or the data buffer is not valid.
+
+  @note If Read Block error because of device error, this function will call
+        AtaSoftReset() function to reset device.
+
+**/
+EFI_STATUS
+AtaBlkIoReadBlocks (
+  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,
+  IN UINT32           MediaId,
+  IN EFI_LBA          Lba,
+  IN UINTN            BufferSize,
+  OUT VOID            *Buffer
+  );
+
+/**
+  This function is the ATA implementation for WriteBlocks in the
+  Block I/O Protocol interface.
+
+  @param IdeBlkIoDevice  Indicates the calling context.
+  @param MediaId         The media id that the write request is for.
+  @param Lba             The starting logical block address to write onto the device.
+  @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 source buffer for the data.The caller
+                         is responsible for either having implicit or explicit 
+                         ownership of the memory that data is written from.
+
+  @retval EFI_SUCCESS       Write Blocks successfully.
+  @retval EFI_DEVICE_ERROR  Write Blocks failed.
+  @retval EFI_NO_MEDIA      There is no media in the device.
+  @retval EFI_MEDIA_CHANGE  The MediaId is not for the current media.
+
+  @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of the
+                                intrinsic block size of the device.
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+                                or the data buffer is not valid.
+
+  @note If Write Block error because of device error, this function will call
+        AtaSoftReset() function to reset device.
+**/
+EFI_STATUS
+AtaBlkIoWriteBlocks (
+  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,
+  IN UINT32           MediaId,
+  IN EFI_LBA          Lba,
+  IN UINTN            BufferSize,
+  OUT VOID            *Buffer
+  );
+
+/**
+  This function is called by DiscoverIdeDevice() during its device
+  identification.
+  Its main purpose is to get enough information for the device media
+  to fill in the Media data structure of the Block I/O Protocol interface.
+
+  There are 5 steps to reach such objective:
+  1. Sends out the ATAPI Identify Command to the specified device. 
+  Only ATAPI device responses to this command. If the command succeeds,
+  it returns the Identify data structure which filled with information 
+  about the device. Since the ATAPI device contains removable media, 
+  the only meaningful information is the device module name.
+  2. Sends out ATAPI Inquiry Packet Command to the specified device.
+  This command will return inquiry data of the device, which contains
+  the device type information.
+  3. Allocate sense data space for future use. We don't detect the media
+  presence here to improvement boot performance, especially when CD 
+  media is present. The media detection will be performed just before
+  each BLK_IO read/write
+  
+  @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+                 to record all the information of the IDE device.
+
+  @retval EFI_SUCCESS       Identify ATAPI device successfully.
+  @retval EFI_DEVICE_ERROR  ATAPI Identify Device Command failed or device type
+                            is not supported by this IDE driver.
+  @retval EFI_OUT_OF_RESOURCES Allocate memory for sense data failed 
+
+  @note   Parameter "IdeDev" will be updated in this function.
+**/
+EFI_STATUS
+ATAPIIdentify (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  );
+
+/**
+  This function is used to implement the Soft Reset on the specified
+  ATAPI device. Different from the AtaSoftReset(), here reset is a ATA
+  Soft Reset Command special for ATAPI device, and it only take effects
+  on the specified ATAPI device, not on the whole IDE bus.
+  Since the ATAPI soft reset is needed when device is in exceptional
+  condition (such as BSY bit is always set ), I think the Soft Reset
+  command should be sent without waiting for the BSY clear and DRDY
+  set.
+  This function is called by IdeBlkIoReset(), 
+  a interface function of Block I/O protocol.
+
+  @param IdeDev    pointer pointing to IDE_BLK_IO_DEV data structure, used
+                   to record all the information of the IDE device.
+
+  @retval EFI_SUCCESS      Soft reset completes successfully.
+  @retval EFI_DEVICE_ERROR Any step during the reset process is failed.
+
+**/
+EFI_STATUS
+AtapiSoftReset (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  );
+
+/**
+  This function is the ATAPI implementation for ReadBlocks in the
+  Block I/O Protocol interface.
+
+  @param IdeBlkIoDevice Indicates the calling context.
+  @param MediaId        The media id that the read request is for.
+  @param Lba            The starting logical block address to read from on the device.
+  @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 memory that data is read into.
+  
+  @retval EFI_SUCCESS           Read Blocks successfully.
+  @retval EFI_DEVICE_ERROR      Read Blocks failed.
+  @retval EFI_NO_MEDIA          There is no media in the device.
+  @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.
+  @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of the
+                                intrinsic block size of the device.
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+                                or the data buffer is not valid.
+**/
+EFI_STATUS
+AtapiBlkIoReadBlocks (
+  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,
+  IN UINT32           MediaId,
+  IN EFI_LBA          Lba,
+  IN UINTN            BufferSize,
+  OUT VOID            *Buffer
+  );
+
+/**
+  This function is the ATAPI implementation for WriteBlocks in the
+  Block I/O Protocol interface.
+
+  @param IdeBlkIoDevice  Indicates the calling context.
+  @param MediaId         The media id that the write request is for.
+  @param Lba             The starting logical block address to write onto the device.
+  @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 source buffer for the data. The caller
+                         is responsible for either having implicit or explicit ownership
+                         of the memory that data is written from.
+
+  @retval EFI_SUCCESS            Write Blocks successfully.
+  @retval EFI_DEVICE_ERROR       Write Blocks failed.
+  @retval EFI_NO_MEDIA           There is no media in the device.
+  @retval EFI_MEDIA_CHANGE       The MediaId is not for the current media.
+  @retval EFI_BAD_BUFFER_SIZE    The BufferSize parameter is not a multiple of the
+                                 intrinsic block size of the device.  
+  @retval EFI_INVALID_PARAMETER  The write request contains LBAs that are not valid, 
+                                 or the data buffer is not valid.
+
+  @retval EFI_WRITE_PROTECTED    The write protected is enabled or the media does not support write
+**/
+EFI_STATUS
+AtapiBlkIoWriteBlocks (
+  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,
+  IN UINT32           MediaId,
+  IN EFI_LBA          Lba,
+  IN UINTN            BufferSize,
+  OUT VOID            *Buffer
+  );
+
+/**
+  Release resources of an IDE device before stopping it.
+
+  @param IdeBlkIoDevice  Standard IDE device private data structure
+
+**/
+VOID
+ReleaseIdeResources (
+  IN  IDE_BLK_IO_DEV  *IdeBlkIoDevice
+  );
+
+/**
+  Set the calculated Best transfer mode to a detected device
+
+  @param IdeDev       Standard IDE device private data structure
+  @param TransferMode The device transfer mode to be set
+  @return Set transfer mode Command execute status.
+**/
+EFI_STATUS
+SetDeviceTransferMode (
+  IN IDE_BLK_IO_DEV       *IdeDev,
+  IN ATA_TRANSFER_MODE    *TransferMode
+  );
+/**
+  Send ATA command into device with NON_DATA protocol.
+
+  @param  IdeDev Standard IDE device private data structure
+  @param  AtaCommand The ATA command to be sent
+  @param  Device The value in Device register
+  @param  Feature The value in Feature register
+  @param  SectorCount The value in SectorCount register
+  @param  LbaLow The value in LBA_LOW register
+  @param  LbaMiddle The value in LBA_MIDDLE register
+  @param  LbaHigh The value in LBA_HIGH register
+
+  @retval  EFI_SUCCESS Reading succeed
+  @retval  EFI_ABORTED Command failed
+  @retval  EFI_DEVICE_ERROR Device status error.
+
+**/
+EFI_STATUS
+AtaNonDataCommandIn (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINT8           AtaCommand,
+  IN  UINT8           Device,
+  IN  UINT8           Feature,
+  IN  UINT8           SectorCount,
+  IN  UINT8           LbaLow,
+  IN  UINT8           LbaMiddle,
+  IN  UINT8           LbaHigh
+  );
+
+/**
+  Send ATA Ext command into device with NON_DATA protocol.
+
+  @param  IdeDev Standard IDE device private data structure
+  @param  AtaCommand The ATA command to be sent
+  @param  Device The value in Device register
+  @param  Feature The value in Feature register
+  @param  SectorCount The value in SectorCount register
+  @param  LbaAddress The Lba address in 48-bit mode
+
+  @retval  EFI_SUCCESS Reading succeed
+  @retval  EFI_ABORTED Command failed
+  @retval  EFI_DEVICE_ERROR Device status error.
+
+**/
+EFI_STATUS
+AtaNonDataCommandInExt (
+  IN  IDE_BLK_IO_DEV  *IdeDev,
+  IN  UINT8           AtaCommand,
+  IN  UINT8           Device,
+  IN  UINT16          Feature,
+  IN  UINT16          SectorCount,
+  IN  EFI_LBA         LbaAddress
+  );
+/**
+  Enable Long Physical Sector Feature for ATA device.
+
+  @param   IdeDev  The IDE device data
+
+  @retval  EFI_SUCCESS      The ATA device supports Long Physical Sector feature
+                            and corresponding fields in BlockIo structure is updated.
+  @retval  EFI_UNSUPPORTED  The device is not ATA device or Long Physical Sector
+                            feature is not supported.
+**/
+EFI_STATUS
+AtaEnableLongPhysicalSector (
+  IN  IDE_BLK_IO_DEV  *IdeDev
+  );
+
+/**
+  Set drive parameters for devices not support PACKETS command.
+
+  @param IdeDev          Standard IDE device private data structure
+  @param DriveParameters The device parameters to be set into the disk
+  @return SetParameters Command execute status.
+
+**/
+EFI_STATUS
+SetDriveParameters (
+  IN IDE_BLK_IO_DEV       *IdeDev,
+  IN ATA_DRIVE_PARMS      *DriveParameters
+  );
+
+/**
+  Enable Interrupt on IDE controller.
+
+  @param  IdeDev   Standard IDE device private data structure
+
+  @retval  EFI_SUCCESS Enable Interrupt successfully
+**/
+EFI_STATUS
+EnableInterrupt (
+  IN IDE_BLK_IO_DEV       *IdeDev
+  );
+#endif
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/IdeBus.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/IdeBus.c	(revision 33024)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/IdeBus.c	(revision 33024)
@@ -0,0 +1,1532 @@
+/** @file
+  This file implement UEFI driver for IDE Bus which includes device identification, 
+  Child device(Disk, CDROM, etc) enumeration and child handler installation, and 
+  driver stop.
+    
+  Copyright (c) 2006 - 2009, Intel Corporation
+  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.
+
+  @par Revision Reference:
+  This module is modified from DXE\IDE module for Ide Contriller Init support
+
+**/
+
+#include "IdeBus.h"
+
+#define PCI_CLASS_MASS_STORAGE  0x01
+#define PCI_SUB_CLASS_IDE       0x01
+
+
+//
+// IDE Bus Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gIDEBusDriverBinding = {
+  IDEBusDriverBindingSupported,
+  IDEBusDriverBindingStart,
+  IDEBusDriverBindingStop,
+  0xa,
+  NULL,
+  NULL
+};
+/**
+  Deregister an IDE device and free resources
+
+  @param  This Protocol instance pointer.
+  @param  Controller Ide device handle
+  @param  Handle Handle of device to deregister driver on
+
+  @retval EFI_SUCCESS  Deregiter a specific IDE device successfully
+
+
+**/
+EFI_STATUS
+DeRegisterIdeDevice (
+  IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
+  IN  EFI_HANDLE                     Controller,
+  IN  EFI_HANDLE                     Handle
+  )
+{
+  EFI_STATUS            Status;
+  EFI_BLOCK_IO_PROTOCOL *BlkIo;
+  IDE_BLK_IO_DEV        *IdeBlkIoDevice;
+  EFI_PCI_IO_PROTOCOL   *PciIo;
+  UINTN                 Index;
+
+  Status = gBS->OpenProtocol (
+                  Handle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &BlkIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlkIo);
+
+  //
+  // Report Status code: Device disabled
+  //
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+    EFI_PROGRESS_CODE,
+    (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_DISABLE),
+    IdeBlkIoDevice->DevicePath
+    );
+
+  //
+  // Close the child handle
+  //
+  Status = gBS->CloseProtocol (
+                  Controller,
+                  &gEfiPciIoProtocolGuid,
+                  This->DriverBindingHandle,
+                  Handle
+                  );
+
+  Status = gBS->UninstallMultipleProtocolInterfaces (
+                  Handle,
+                  &gEfiDevicePathProtocolGuid,
+                  IdeBlkIoDevice->DevicePath,
+                  &gEfiBlockIoProtocolGuid,
+                  &IdeBlkIoDevice->BlkIo,
+                  &gEfiDiskInfoProtocolGuid,
+                  &IdeBlkIoDevice->DiskInfo,
+                  NULL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    gBS->OpenProtocol (
+          Controller,
+          &gEfiPciIoProtocolGuid,
+          (VOID **) &PciIo,
+          This->DriverBindingHandle,
+          Handle,
+          EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+          );
+    return Status;
+  }
+
+  //
+  // Release allocated resources
+  //
+  Index = IdeBlkIoDevice->Channel * 2 + IdeBlkIoDevice->Device;
+  if (Index < MAX_IDE_DEVICE) {
+    IdeBlkIoDevice->IdeBusDriverPrivateData->HaveScannedDevice[Index] = FALSE;
+  }
+  ReleaseIdeResources (IdeBlkIoDevice);
+
+  return EFI_SUCCESS;
+}
+/**
+  Supported function of Driver Binding protocol for this driver.
+
+  @param This                A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param ControllerHandle    The handle of the controller to test.
+  @param RemainingDevicePath A pointer to the remaining portion of a device path.
+
+  @retval  EFI_SUCCESS Driver loaded.
+  @retval  other       Driver not loaded.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_DEVICE_PATH_PROTOCOL          *ParentDevicePath;
+  EFI_DEV_PATH                      *Node;
+  EFI_IDE_CONTROLLER_INIT_PROTOCOL  *IdeInit;
+
+  if (RemainingDevicePath != NULL) {
+    Node = (EFI_DEV_PATH *) RemainingDevicePath;
+    //
+    // Check if RemainingDevicePath is the End of Device Path Node, 
+    // if yes, go on checking other conditions
+    //
+    if (!IsDevicePathEnd (Node)) {
+      //
+      // If RemainingDevicePath isn't the End of Device Path Node,
+      // check its validation
+      //
+      if (Node->DevPath.Type != MESSAGING_DEVICE_PATH ||
+          Node->DevPath.SubType != MSG_ATAPI_DP ||
+          DevicePathNodeLength(&Node->DevPath) != sizeof(ATAPI_DEVICE_PATH)) {
+        return EFI_UNSUPPORTED;
+      }
+    }
+  }
+
+  //
+  // Verify the Ide Controller Init Protocol, which installed by the
+  // IdeController module.
+  // Note 1: PciIo protocol has been opened BY_DRIVER by ide_init, so We can't
+  //         open BY_DRIVER here) That's why we don't check pciio protocol
+  // Note 2: ide_init driver check ide controller's pci config space, so we dont
+  //         check here any more to save code size
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiIdeControllerInitProtocolGuid,
+                  (VOID **) &IdeInit,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+
+  if (Status == EFI_ALREADY_STARTED) {
+    return EFI_SUCCESS;
+  }
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  
+  //
+  // Close the I/O Abstraction(s) used to perform the supported test
+  //
+  gBS->CloseProtocol (
+        Controller,
+        &gEfiIdeControllerInitProtocolGuid,
+        This->DriverBindingHandle,
+        Controller
+        );
+
+  //
+  // Open the EFI Device Path protocol needed to perform the supported test
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiDevicePathProtocolGuid,
+                  (VOID **) &ParentDevicePath,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (Status == EFI_ALREADY_STARTED) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Close protocol, don't use device path protocol in the Support() function
+  //
+  gBS->CloseProtocol (
+        Controller,
+        &gEfiDevicePathProtocolGuid,
+        This->DriverBindingHandle,
+        Controller
+        );
+
+  return Status;
+}
+
+
+/**
+  Start function of Driver binding protocol which start this driver on Controller
+  by detecting all disks and installing BlockIo protocol on them.
+
+  @param  This                Protocol instance pointer.
+  @param  Controller          Handle of device to bind driver to.
+  @param  RemainingDevicePath produce all possible children.
+
+  @retval  EFI_SUCCESS         This driver is added to ControllerHandle.
+  @retval  EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
+  @retval  other               This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_STATUS                        SavedStatus;
+  EFI_PCI_IO_PROTOCOL               *PciIo;
+  EFI_DEVICE_PATH_PROTOCOL          *ParentDevicePath;
+  EFI_DEV_PATH                      *Node;
+  UINT8                             IdeChannel;
+  UINT8                             BeginningIdeChannel;
+  UINT8                             EndIdeChannel;
+  UINT8                             IdeDevice;
+  UINT8                             BeginningIdeDevice;
+  UINT8                             EndIdeDevice;
+  IDE_BLK_IO_DEV                    *IdeBlkIoDevice[IdeMaxChannel][IdeMaxDevice];
+  IDE_BLK_IO_DEV                    *IdeBlkIoDevicePtr;
+  IDE_REGISTERS_BASE_ADDR           IdeRegsBaseAddr[IdeMaxChannel];
+  ATA_TRANSFER_MODE                 TransferMode;
+  ATA_DRIVE_PARMS                   DriveParameters;
+  EFI_DEV_PATH                      NewNode;
+  UINT8                             ConfigurationOptions;
+  UINT16                            CommandBlockBaseAddr;
+  UINT16                            ControlBlockBaseAddr;
+  UINTN                             DataSize;
+  IDE_BUS_DRIVER_PRIVATE_DATA       *IdeBusDriverPrivateData;
+  UINT64                            Supports;
+
+  //
+  // Local variables declaration for IdeControllerInit support
+  //
+  EFI_IDE_CONTROLLER_INIT_PROTOCOL  *IdeInit;
+  BOOLEAN                           EnumAll;
+  BOOLEAN                           ChannelEnabled;
+  UINT8                             MaxDevices;
+  EFI_IDENTIFY_DATA                 IdentifyData;
+  EFI_ATA_COLLECTIVE_MODE           *SupportedModes;
+
+  IdeBusDriverPrivateData = NULL;
+  SupportedModes          = NULL;
+
+  //
+  // Perform IdeBus initialization
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiDevicePathProtocolGuid,
+                  (VOID **) &ParentDevicePath,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
+    return Status;
+  }
+
+  //
+  // Now open the IDE_CONTROLLER_INIT protocol. Step7.1
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiIdeControllerInitProtocolGuid,
+                  (VOID **) &IdeInit,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+
+  //
+  // The following OpenProtocol function with _GET_PROTOCOL attribute and
+  // will not return EFI_ALREADY_STARTED, so save it for now
+  //
+  SavedStatus = Status;
+
+  if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
+    DEBUG ((EFI_D_ERROR, "Open Init, Status=%x", Status));
+    //
+    // open protocol is not SUCCESS or not ALREADY_STARTED, error exit
+    //
+    goto ErrorExit;
+  }
+
+  //
+  // Save Enumall. Step7.2
+  //
+  EnumAll       = IdeInit->EnumAll;
+
+  //
+  // Consume PCI I/O protocol. Note that the OpenProtocol with _GET_PROTOCOL
+  // attribute will not return EFI_ALREADY_STARTED
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID **) &PciIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Open PciIo, Status=%x", Status));
+    goto ErrorExit;
+  }
+
+  //
+  // We must check EFI_ALREADY_STARTED because many ATAPI devices are removable
+  //
+  if (SavedStatus != EFI_ALREADY_STARTED) {
+    IdeBusDriverPrivateData = AllocatePool (sizeof (IDE_BUS_DRIVER_PRIVATE_DATA));
+    if (IdeBusDriverPrivateData == NULL) {
+      Status = EFI_OUT_OF_RESOURCES;
+      goto ErrorExit;
+    }
+
+    ZeroMem (IdeBusDriverPrivateData, sizeof (IDE_BUS_DRIVER_PRIVATE_DATA));
+    Status = gBS->InstallMultipleProtocolInterfaces (
+                    &Controller,
+                    &gEfiCallerIdGuid,
+                    IdeBusDriverPrivateData,
+                    NULL
+                    );
+    if (EFI_ERROR (Status)) {
+      goto ErrorExit;
+    }
+
+  } else {
+    Status = gBS->OpenProtocol (
+                    Controller,
+                    &gEfiCallerIdGuid,
+                    (VOID **) &IdeBusDriverPrivateData,
+                    This->DriverBindingHandle,
+                    Controller,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                    );
+    if (EFI_ERROR (Status)) {
+      IdeBusDriverPrivateData = NULL;
+      goto ErrorExit;
+    }
+  }
+
+  Status = PciIo->Attributes (
+                    PciIo,
+                    EfiPciIoAttributeOperationSupported,
+                    0,
+                    &Supports
+                    );
+  if (!EFI_ERROR (Status)) {
+    Supports &= EFI_PCI_DEVICE_ENABLE;
+    Status = PciIo->Attributes (
+                      PciIo,
+                      EfiPciIoAttributeOperationEnable,
+                      Supports,
+                      NULL
+                      );
+  }
+
+  if (EFI_ERROR (Status)) {
+    goto ErrorExit;
+  }
+
+  //
+  // Read the environment variable that contains the IDEBus Driver's
+  // Config options that were set by the Driver Configuration Protocol
+  //
+  DataSize = sizeof (ConfigurationOptions);
+  Status = gRT->GetVariable (
+                  (CHAR16 *) L"Configuration",
+                  &gEfiCallerIdGuid,
+                  NULL,
+                  &DataSize,
+                  &ConfigurationOptions
+                  );
+  if (EFI_ERROR (Status)) {
+    ConfigurationOptions = 0x0f;
+  }
+
+   if (EnumAll || RemainingDevicePath == NULL) {
+    //
+    // If IdeInit->EnumAll is TRUE or RemainingDevicePath is NULL, 
+    // must enumerate all IDE devices anyway
+    //
+    BeginningIdeChannel = IdePrimary;
+    EndIdeChannel       = IdeSecondary;
+    BeginningIdeDevice  = IdeMaster;
+    EndIdeDevice        = IdeSlave;
+
+  } else if (!IsDevicePathEnd (RemainingDevicePath)) {
+    //
+    // If RemainingDevicePath isn't the End of Device Path Node, 
+    // only scan the specified device by RemainingDevicePath
+    //
+    Node                = (EFI_DEV_PATH *) RemainingDevicePath;
+    BeginningIdeChannel = Node->Atapi.PrimarySecondary;
+    EndIdeChannel       = BeginningIdeChannel;
+    BeginningIdeDevice  = Node->Atapi.SlaveMaster;
+    EndIdeDevice        = BeginningIdeDevice;
+    if (BeginningIdeChannel >= IdeMaxChannel || EndIdeChannel >= IdeMaxChannel) {
+      Status = EFI_INVALID_PARAMETER;
+      goto ErrorExit;
+    }
+    if (BeginningIdeDevice >= IdeMaxDevice|| EndIdeDevice >= IdeMaxDevice) {
+      Status = EFI_INVALID_PARAMETER;
+      goto ErrorExit;
+    }
+
+  } else {
+    //
+    // If RemainingDevicePath is the End of Device Path Node,
+    // skip enumerate any device and return EFI_SUCESSS
+    // 
+    BeginningIdeChannel = IdeMaxChannel;
+    EndIdeChannel       = IdeMaxChannel - 1;
+    BeginningIdeDevice  = IdeMaxDevice;
+    EndIdeDevice        = IdeMaxDevice - 1;
+  }
+
+  //
+  // Obtain IDE IO port registers' base addresses
+  //
+  Status = GetIdeRegistersBaseAddr (PciIo, IdeRegsBaseAddr);
+  if (EFI_ERROR (Status)) {
+    goto ErrorExit;
+  }
+
+  //
+  // Report status code: begin IdeBus initialization
+  //
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+    EFI_PROGRESS_CODE,
+    (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),
+    ParentDevicePath
+    );
+
+  //
+  // Strictly follow the enumeration based on IDE_CONTROLLER_INIT protocol
+  //
+  for (IdeChannel = BeginningIdeChannel; IdeChannel <= EndIdeChannel; IdeChannel++) {
+
+    IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, IdeChannel);
+
+    //
+    // now obtain channel information fron IdeControllerInit protocol. Step9
+    //
+    Status = IdeInit->GetChannelInfo (
+                        IdeInit,
+                        IdeChannel,
+                        &ChannelEnabled,
+                        &MaxDevices
+                        );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "[GetChannel, Status=%x]", Status));
+      continue;
+    }
+
+    if (!ChannelEnabled) {
+      continue;
+    }
+
+    EndIdeDevice = (UINT8) MIN ((MaxDevices - 1), EndIdeDevice);
+    ASSERT (EndIdeDevice < IdeMaxDevice);
+    //
+    // Now inform the IDE Controller Init Module. Sept10
+    //
+    IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelReset, IdeChannel);
+
+    //
+    // No reset channel function implemented. Sept11
+    //
+    IdeInit->NotifyPhase (IdeInit, EfiIdeAfterChannelReset, IdeChannel);
+
+    //
+    // Step13
+    //
+    IdeInit->NotifyPhase (
+              IdeInit,
+              EfiIdeBusBeforeDevicePresenceDetection,
+              IdeChannel
+              );
+
+    //
+    // Prepare to detect IDE device of this channel
+    //
+    InitializeIDEChannelData ();
+
+    //
+    // -- 1st inner loop --- Master/Slave ------------  Step14
+    //
+    for (IdeDevice = BeginningIdeDevice; IdeDevice <= EndIdeDevice; IdeDevice++) {
+      //
+      // Check whether the configuration options allow this device
+      //
+      if ((ConfigurationOptions & (1 << (IdeChannel * 2 + IdeDevice))) == 0) {
+        continue;
+      }
+
+      //
+      // The device has been scanned in another Start(), No need to scan it again
+      // for perf optimization.
+      //
+      if (IdeBusDriverPrivateData->HaveScannedDevice[IdeChannel * 2 + IdeDevice]) {
+        continue;
+      }
+
+      //
+      // create child handle for the detected device.
+      //
+      IdeBlkIoDevice[IdeChannel][IdeDevice] = AllocatePool (sizeof (IDE_BLK_IO_DEV));
+      if (IdeBlkIoDevice[IdeChannel][IdeDevice] == NULL) {
+        continue;
+      }
+
+      IdeBlkIoDevicePtr = IdeBlkIoDevice[IdeChannel][IdeDevice];
+
+      ZeroMem (IdeBlkIoDevicePtr, sizeof (IDE_BLK_IO_DEV));
+
+      IdeBlkIoDevicePtr->Signature  = IDE_BLK_IO_DEV_SIGNATURE;
+      IdeBlkIoDevicePtr->Channel    = (EFI_IDE_CHANNEL) IdeChannel;
+      IdeBlkIoDevicePtr->Device     = (EFI_IDE_DEVICE) IdeDevice;
+
+      //
+      // initialize Block IO interface's Media pointer
+      //
+      IdeBlkIoDevicePtr->BlkIo.Media = &IdeBlkIoDevicePtr->BlkMedia;
+
+      //
+      // Initialize IDE IO port addresses, including Command Block registers
+      // and Control Block registers
+      //
+      IdeBlkIoDevicePtr->IoPort = AllocatePool (sizeof (IDE_BASE_REGISTERS));
+      if (IdeBlkIoDevicePtr->IoPort == NULL) {
+        continue;
+      }
+
+      ZeroMem (IdeBlkIoDevicePtr->IoPort, sizeof (IDE_BASE_REGISTERS));
+      CommandBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].CommandBlockBaseAddr;
+      ControlBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].ControlBlockBaseAddr;
+
+      IdeBlkIoDevicePtr->IoPort->Data = CommandBlockBaseAddr;
+      (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);
+      IdeBlkIoDevicePtr->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);
+      IdeBlkIoDevicePtr->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);
+      IdeBlkIoDevicePtr->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);
+      IdeBlkIoDevicePtr->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);
+      IdeBlkIoDevicePtr->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06);
+      (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);
+
+      (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Alt) = ControlBlockBaseAddr;
+      IdeBlkIoDevicePtr->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);
+
+      IdeBlkIoDevicePtr->IoPort->MasterSlave = (UINT16) ((IdeDevice == IdeMaster) ? 1 : 0);
+
+      IdeBlkIoDevicePtr->PciIo = PciIo;
+      IdeBlkIoDevicePtr->IdeBusDriverPrivateData = IdeBusDriverPrivateData;
+      IdeBlkIoDevicePtr->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeChannel].BusMasterBaseAddr;
+
+      //
+      // Report Status code: is about to detect IDE drive
+      //
+      REPORT_STATUS_CODE_EX (
+        EFI_PROGRESS_CODE,
+        (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_PRESENCE_DETECT),
+        0,
+        &gEfiCallerIdGuid,
+        NULL,
+        NULL,
+        0
+      );
+
+      //
+      // Discover device, now!
+      //
+      PERF_START (NULL, "DiscoverIdeDevice", "IDE", 0);
+      Status = DiscoverIdeDevice (IdeBlkIoDevicePtr);
+      PERF_END (NULL, "DiscoverIdeDevice", "IDE", 0);
+
+      IdeBusDriverPrivateData->HaveScannedDevice[IdeChannel * 2 + IdeDevice]  = TRUE;
+      IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice]    = FALSE;
+
+      if (!EFI_ERROR (Status)) {
+        //
+        // Set Device Path
+        //
+        ZeroMem (&NewNode, sizeof (NewNode));
+        NewNode.DevPath.Type    = MESSAGING_DEVICE_PATH;
+        NewNode.DevPath.SubType = MSG_ATAPI_DP;
+        SetDevicePathNodeLength (&NewNode.DevPath, sizeof (ATAPI_DEVICE_PATH));
+
+        NewNode.Atapi.PrimarySecondary  = (UINT8) IdeBlkIoDevicePtr->Channel;
+        NewNode.Atapi.SlaveMaster       = (UINT8) IdeBlkIoDevicePtr->Device;
+        NewNode.Atapi.Lun               = IdeBlkIoDevicePtr->Lun;
+        IdeBlkIoDevicePtr->DevicePath = AppendDevicePathNode (
+                                          ParentDevicePath,
+                                          &NewNode.DevPath
+                                          );
+        if (IdeBlkIoDevicePtr->DevicePath == NULL) {
+          ReleaseIdeResources (IdeBlkIoDevicePtr);
+          continue;
+        }
+
+        //
+        // Submit identify data to IDE controller init driver
+        //
+        CopyMem (&IdentifyData, IdeBlkIoDevicePtr->IdData, sizeof (IdentifyData));
+        IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = TRUE;
+        IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, &IdentifyData);
+      } else {
+        //
+        // Device detection failed
+        //
+        IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE;
+        IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, NULL);
+        ReleaseIdeResources (IdeBlkIoDevicePtr);
+        IdeBlkIoDevicePtr = NULL;
+      }
+      //
+      // end of 1st inner loop ---
+      //
+    }
+    //
+    // end of 1st outer loop =========
+    //
+  }
+
+  //
+  // = 2nd outer loop == Primary/Secondary =================
+  //
+  for (IdeChannel = BeginningIdeChannel; IdeChannel <= EndIdeChannel; IdeChannel++) {
+
+    //
+    // -- 2nd inner loop --- Master/Slave --------
+    //
+    for (IdeDevice = BeginningIdeDevice; IdeDevice <= EndIdeDevice; IdeDevice++) {
+
+      if (IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice]) {
+        continue;
+      }
+
+      if (!IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice]) {
+        continue;
+      }
+
+      Status = IdeInit->CalculateMode (
+                          IdeInit,
+                          IdeChannel,
+                          IdeDevice,
+                          &SupportedModes
+                          );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "[bStStp20S=%x]", Status));
+        continue;
+      }
+
+      IdeBlkIoDevicePtr = IdeBlkIoDevice[IdeChannel][IdeDevice];
+
+      //
+      // Set best supported PIO mode on this IDE device
+      //
+      if (SupportedModes->PioMode.Mode <= AtaPioMode2) {
+        TransferMode.ModeCategory = ATA_MODE_CATEGORY_DEFAULT_PIO;
+      } else {
+        TransferMode.ModeCategory = ATA_MODE_CATEGORY_FLOW_PIO;
+      }
+
+      TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);
+
+      if (SupportedModes->ExtModeCount == 0){
+        Status                  = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode);
+
+        if (EFI_ERROR (Status)) {
+          IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE;
+          ReleaseIdeResources (IdeBlkIoDevicePtr);
+          IdeBlkIoDevicePtr = NULL;
+          continue;
+        }
+      }
+
+      //
+      // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't
+      // be set together. Only one DMA mode can be set to a device. If setting
+      // DMA mode operation fails, we can continue moving on because we only use
+      // PIO mode at boot time. DMA modes are used by certain kind of OS booting
+      //
+      if (SupportedModes->UdmaMode.Valid) {
+
+        TransferMode.ModeCategory = ATA_MODE_CATEGORY_UDMA;
+        TransferMode.ModeNumber   = (UINT8) (SupportedModes->UdmaMode.Mode);
+        Status                    = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode);
+
+        if (EFI_ERROR (Status)) {
+          IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE;
+          ReleaseIdeResources (IdeBlkIoDevicePtr);
+          IdeBlkIoDevicePtr = NULL;
+          continue;
+        }
+        //
+        // Record Udma Mode
+        //
+        IdeBlkIoDevicePtr->UdmaMode.Valid = TRUE;
+        IdeBlkIoDevicePtr->UdmaMode.Mode  = SupportedModes->UdmaMode.Mode;
+        EnableInterrupt (IdeBlkIoDevicePtr);
+      } else if (SupportedModes->MultiWordDmaMode.Valid) {
+
+        TransferMode.ModeCategory = ATA_MODE_CATEGORY_MDMA;
+        TransferMode.ModeNumber   = (UINT8) SupportedModes->MultiWordDmaMode.Mode;
+        Status                    = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode);
+
+        if (EFI_ERROR (Status)) {
+          IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE;
+          ReleaseIdeResources (IdeBlkIoDevicePtr);
+          IdeBlkIoDevicePtr = NULL;
+          continue;
+        }
+
+        EnableInterrupt (IdeBlkIoDevicePtr);
+      }
+      //
+      // Init driver parameters
+      //
+      DriveParameters.Sector          = (UINT8) IdeBlkIoDevicePtr->IdData->AtaData.sectors_per_track;
+      DriveParameters.Heads           = (UINT8) (IdeBlkIoDevicePtr->IdData->AtaData.heads - 1);
+      DriveParameters.MultipleSector  = (UINT8) IdeBlkIoDevicePtr->IdData->AtaData.multi_sector_cmd_max_sct_cnt;
+      //
+      // Set Parameters for the device:
+      // 1) Init
+      // 2) Establish the block count for READ/WRITE MULTIPLE (EXT) command
+      //
+      if ((IdeBlkIoDevicePtr->Type == IdeHardDisk) || (IdeBlkIoDevicePtr->Type == Ide48bitAddressingHardDisk)) {
+        Status = SetDriveParameters (IdeBlkIoDevicePtr, &DriveParameters);
+      }
+
+      //
+      // Record PIO mode used in private data
+      //
+      IdeBlkIoDevicePtr->PioMode = (ATA_PIO_MODE) SupportedModes->PioMode.Mode;
+
+      //
+      // Set IDE controller Timing Blocks in the PCI Configuration Space
+      //
+      IdeInit->SetTiming (IdeInit, IdeChannel, IdeDevice, SupportedModes);
+
+      //
+      // Add Component Name for the IDE/ATAPI device that was discovered.
+      //
+      IdeBlkIoDevicePtr->ControllerNameTable = NULL;
+      ADD_IDE_ATAPI_NAME (IdeBlkIoDevicePtr);
+
+      Status = gBS->InstallMultipleProtocolInterfaces (
+                      &IdeBlkIoDevicePtr->Handle,
+                      &gEfiDevicePathProtocolGuid,
+                      IdeBlkIoDevicePtr->DevicePath,
+                      &gEfiBlockIoProtocolGuid,
+                      &IdeBlkIoDevicePtr->BlkIo,
+                      &gEfiDiskInfoProtocolGuid,
+                      &IdeBlkIoDevicePtr->DiskInfo,
+                      NULL
+                      );
+
+      if (EFI_ERROR (Status)) {
+        ReleaseIdeResources (IdeBlkIoDevicePtr);
+      }
+
+      gBS->OpenProtocol (
+            Controller,
+            &gEfiPciIoProtocolGuid,
+            (VOID **) &PciIo,
+            This->DriverBindingHandle,
+            IdeBlkIoDevicePtr->Handle,
+            EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+            );
+
+      IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice] = TRUE;
+
+      //
+      // Report status code: device eanbled!
+      //
+      REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+        EFI_PROGRESS_CODE,
+        (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_ENABLE),
+        IdeBlkIoDevicePtr->DevicePath
+        );
+
+      //
+      // Create event to clear pending IDE interrupt
+      //
+      Status = gBS->CreateEventEx (
+                      EVT_NOTIFY_SIGNAL,
+                      TPL_NOTIFY,
+                      ClearInterrupt,
+                      IdeBlkIoDevicePtr,
+                      &gEfiEventExitBootServicesGuid,
+                      &IdeBlkIoDevicePtr->ExitBootServiceEvent
+                      );
+
+      //
+      // end of 2nd inner loop ----
+      //
+    }
+    //
+    // end of 2nd outer loop ==========
+    //
+  }
+
+  //
+  // All configurations done! Notify IdeController to do post initialization
+  // work such as saving IDE controller PCI settings for S3 resume
+  //
+  IdeInit->NotifyPhase (IdeInit, EfiIdeBusPhaseMaximum, 0);
+
+  if (SupportedModes != NULL) {
+    FreePool (SupportedModes);
+  }
+
+  PERF_START (NULL, "Finish IDE detection", "IDE", 1);
+  PERF_END (NULL, "Finish IDE detection", "IDE", 0);
+
+  return EFI_SUCCESS;
+
+ErrorExit:
+
+  //
+  // Report error code: controller error
+  //
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+    EFI_ERROR_CODE | EFI_ERROR_MINOR,
+    (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_EC_CONTROLLER_ERROR),
+    ParentDevicePath
+    );
+
+  gBS->CloseProtocol (
+        Controller,
+        &gEfiIdeControllerInitProtocolGuid,
+        This->DriverBindingHandle,
+        Controller
+        );
+
+  gBS->UninstallMultipleProtocolInterfaces (
+        Controller,
+        &gEfiCallerIdGuid,
+        IdeBusDriverPrivateData,
+        NULL
+        );
+
+  if (IdeBusDriverPrivateData != NULL) {
+    gBS->FreePool (IdeBusDriverPrivateData);
+  }
+
+  if (SupportedModes != NULL) {
+    gBS->FreePool (SupportedModes);
+  }
+
+  gBS->CloseProtocol (
+        Controller,
+        &gEfiPciIoProtocolGuid,
+        This->DriverBindingHandle,
+        Controller
+        );
+
+  gBS->CloseProtocol (
+        Controller,
+        &gEfiDevicePathProtocolGuid,
+        This->DriverBindingHandle,
+        Controller
+        );
+
+  return Status;
+
+}
+/**
+  Stop function of Driver Binding Protocol which is to stop the driver on Controller Handle and all
+  child handle attached to the controller handle if there are.
+
+  @param  This Protocol instance pointer.
+  @param  Controller Handle of device to stop driver on
+  @param  NumberOfChildren Not used
+  @param  ChildHandleBuffer Not used
+
+  @retval  EFI_SUCCESS This driver is removed DeviceHandle
+  @retval  other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN  EFI_HANDLE                      Controller,
+  IN  UINTN                           NumberOfChildren,
+  IN  EFI_HANDLE                      *ChildHandleBuffer
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_PCI_IO_PROTOCOL         *PciIo;
+  BOOLEAN                     AllChildrenStopped;
+  UINTN                       Index;
+  IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData;
+  UINT64                      Supports;
+
+  IdeBusDriverPrivateData = NULL;
+
+  if (NumberOfChildren == 0) {
+
+    Status = gBS->OpenProtocol (
+                    Controller,
+                    &gEfiPciIoProtocolGuid,
+                    (VOID **) &PciIo,
+                    This->DriverBindingHandle,
+                    Controller,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                    );
+    if (!EFI_ERROR (Status)) {
+      Status = PciIo->Attributes (
+                        PciIo,
+                        EfiPciIoAttributeOperationSupported,
+                        0,
+                        &Supports
+                        );
+      if (!EFI_ERROR (Status)) {
+        Supports &= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE;
+        PciIo->Attributes (
+                PciIo,
+                EfiPciIoAttributeOperationDisable,
+                Supports,
+                NULL
+                );
+      }
+    }
+
+    gBS->OpenProtocol (
+          Controller,
+          &gEfiCallerIdGuid,
+          (VOID **) &IdeBusDriverPrivateData,
+          This->DriverBindingHandle,
+          Controller,
+          EFI_OPEN_PROTOCOL_GET_PROTOCOL
+          );
+
+    gBS->UninstallMultipleProtocolInterfaces (
+          Controller,
+          &gEfiCallerIdGuid,
+          IdeBusDriverPrivateData,
+          NULL
+          );
+
+    if (IdeBusDriverPrivateData != NULL) {
+      gBS->FreePool (IdeBusDriverPrivateData);
+    }
+    //
+    // Close the bus driver
+    //
+    gBS->CloseProtocol (
+          Controller,
+          &gEfiIdeControllerInitProtocolGuid,
+          This->DriverBindingHandle,
+          Controller
+          );
+    gBS->CloseProtocol (
+          Controller,
+          &gEfiPciIoProtocolGuid,
+          This->DriverBindingHandle,
+          Controller
+          );
+    gBS->CloseProtocol (
+          Controller,
+          &gEfiDevicePathProtocolGuid,
+          This->DriverBindingHandle,
+          Controller
+          );
+
+    return EFI_SUCCESS;
+  }
+
+  AllChildrenStopped = TRUE;
+
+  for (Index = 0; Index < NumberOfChildren; Index++) {
+
+    Status = DeRegisterIdeDevice (This, Controller, ChildHandleBuffer[Index]);
+
+    if (EFI_ERROR (Status)) {
+      AllChildrenStopped = FALSE;
+    }
+  }
+
+  if (!AllChildrenStopped) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  issue ATA or ATAPI command to reset a block IO device.
+  @param  This                  Block IO protocol instance pointer.
+  @param  ExtendedVerification  If FALSE,for ATAPI device, driver will only invoke ATAPI reset method
+                                If TRUE, for ATAPI device, driver need invoke ATA reset method after
+                                invoke ATAPI reset method
+
+  @retval EFI_DEVICE_ERROR      When the device is neighther ATA device or ATAPI device.
+  @retval EFI_SUCCESS           The device reset successfully
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoReset (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  BOOLEAN                 ExtendedVerification
+  )
+{
+  IDE_BLK_IO_DEV  *IdeBlkIoDevice;
+  EFI_STATUS      Status;
+  EFI_TPL         OldTpl;
+
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+  IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (This);
+  //
+  // Requery IDE IO resources in case of the switch of native and legacy modes
+  //
+  ReassignIdeResources (IdeBlkIoDevice);
+
+  //
+  // for ATA device, using ATA reset method
+  //
+  if (IdeBlkIoDevice->Type == IdeHardDisk ||
+      IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+    Status = AtaSoftReset (IdeBlkIoDevice);
+    goto Done;
+  }
+
+  if (IdeBlkIoDevice->Type == IdeUnknown) {
+    Status = EFI_DEVICE_ERROR;
+    goto Done;
+  }
+
+  //
+  // for ATAPI device, using ATAPI reset method
+  //
+  Status = AtapiSoftReset (IdeBlkIoDevice);
+  if (ExtendedVerification) {
+    Status = AtaSoftReset (IdeBlkIoDevice);
+  }
+
+Done:
+  gBS->RestoreTPL (OldTpl);
+  return Status;
+}
+
+/**
+  Read data from a block IO device
+
+  @param  This       Block IO protocol instance pointer.
+  @param  MediaId    The media ID of the device
+  @param  Lba        Starting LBA address to read data
+  @param  BufferSize The size of data to be read
+  @param  Buffer     Caller supplied buffer to save data
+
+  @retval EFI_DEVICE_ERROR  unknown device type
+  @retval other             read data status.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoReadBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 Lba,
+  IN  UINTN                   BufferSize,
+  OUT VOID                    *Buffer
+  )
+{
+  IDE_BLK_IO_DEV  *IdeBlkIoDevice;
+  EFI_STATUS      Status;
+  EFI_TPL         OldTpl;
+
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+  IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (This);
+
+  //
+  // Requery IDE IO resources in case of the switch of native and legacy modes
+  //
+  ReassignIdeResources (IdeBlkIoDevice);
+
+  //
+  // For ATA compatible device, use ATA read block's mechanism
+  //
+  if (IdeBlkIoDevice->Type == IdeHardDisk ||
+      IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+    Status = AtaBlkIoReadBlocks (
+            IdeBlkIoDevice,
+            MediaId,
+            Lba,
+            BufferSize,
+            Buffer
+            );
+    goto Done;
+  }
+
+  if (IdeBlkIoDevice->Type == IdeUnknown) {
+    Status = EFI_DEVICE_ERROR;
+    goto Done;
+  }
+
+  //
+  // for ATAPI device, using ATAPI read block's mechanism
+  //
+  Status = AtapiBlkIoReadBlocks (
+          IdeBlkIoDevice,
+          MediaId,
+          Lba,
+          BufferSize,
+          Buffer
+          );
+
+Done:
+  gBS->RestoreTPL (OldTpl);
+
+  return Status;
+}
+
+/**
+  Write data to block io device.
+
+  @param  This       Protocol instance pointer.
+  @param  MediaId    The media ID of the device
+  @param  Lba        Starting LBA address to write data
+  @param  BufferSize The size of data to be written
+  @param  Buffer     Caller supplied buffer to save data
+
+  @retval EFI_DEVICE_ERROR  unknown device type
+  @retval other             write data status
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoWriteBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 Lba,
+  IN  UINTN                   BufferSize,
+  IN  VOID                    *Buffer
+  )
+{
+  IDE_BLK_IO_DEV  *IdeBlkIoDevice;
+  EFI_STATUS      Status;
+  EFI_TPL         OldTpl;
+
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+  IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (This);
+  //
+  // Requery IDE IO resources in case of the switch of native and legacy modes
+  //
+  ReassignIdeResources (IdeBlkIoDevice);
+
+  //
+  // for ATA device, using ATA write block's mechanism
+  //
+  if (IdeBlkIoDevice->Type == IdeHardDisk ||
+      IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+
+    Status = AtaBlkIoWriteBlocks (
+            IdeBlkIoDevice,
+            MediaId,
+            Lba,
+            BufferSize,
+            Buffer
+            );
+    goto Done;
+  }
+
+  if (IdeBlkIoDevice->Type == IdeUnknown) {
+    Status = EFI_DEVICE_ERROR;
+    goto Done;
+  }
+
+  //
+  // for ATAPI device, using ATAPI write block's mechanism
+  //
+  Status = AtapiBlkIoWriteBlocks (
+          IdeBlkIoDevice,
+          MediaId,
+          Lba,
+          BufferSize,
+          Buffer
+          );
+
+Done:
+  gBS->RestoreTPL (OldTpl);
+  return Status;
+}
+/**
+  Flushes all modified data to a physical block devices
+
+  @param  This  Indicates a pointer to the calling context which to sepcify a
+                sepcific block device
+
+  @retval EFI_SUCCESS   Always return success.
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoFlushBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This
+  )
+{
+  //
+  // return directly
+  //
+  return EFI_SUCCESS;
+}
+
+/**
+  This function is used by the IDE bus driver to get inquiry data. 
+  Data format of Identify data is defined by the Interface GUID.
+
+  @param  This                  Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+  @param  InquiryData           Pointer to a buffer for the inquiry data.
+  @param  InquiryDataSize       Pointer to the value for the inquiry data size.
+
+  @retval EFI_SUCCESS           The command was accepted without any errors.
+  @retval EFI_NOT_FOUND         Device does not support this data class 
+  @retval EFI_DEVICE_ERROR      Error reading InquiryData from device 
+  @retval EFI_BUFFER_TOO_SMALL  IntquiryDataSize not big enough 
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoInquiry (
+  IN     EFI_DISK_INFO_PROTOCOL   *This,
+  IN OUT VOID                     *InquiryData,
+  IN OUT UINT32                   *InquiryDataSize
+  )
+{
+  IDE_BLK_IO_DEV  *IdeBlkIoDevice;
+
+  IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This);
+
+  if (*InquiryDataSize < sizeof (ATAPI_INQUIRY_DATA)) {
+    *InquiryDataSize = sizeof (ATAPI_INQUIRY_DATA);
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  if (IdeBlkIoDevice->InquiryData == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  gBS->CopyMem (InquiryData, IdeBlkIoDevice->InquiryData, sizeof (ATAPI_INQUIRY_DATA));
+  *InquiryDataSize = sizeof (ATAPI_INQUIRY_DATA);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function is used by the IDE bus driver to get identify data. 
+  Data format of Identify data is defined by the Interface GUID.
+
+  @param  This                  Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+  @param  IdentifyData          Pointer to a buffer for the identify data.
+  @param  IdentifyDataSize      Pointer to the value for the identify data size.
+
+  @retval EFI_SUCCESS           The command was accepted without any errors.
+  @retval EFI_NOT_FOUND         Device does not support this data class 
+  @retval EFI_DEVICE_ERROR      Error reading IdentifyData from device 
+  @retval EFI_BUFFER_TOO_SMALL  IdentifyDataSize not big enough 
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoIdentify (
+  IN     EFI_DISK_INFO_PROTOCOL   *This,
+  IN OUT VOID                     *IdentifyData,
+  IN OUT UINT32                   *IdentifyDataSize
+  )
+{
+  IDE_BLK_IO_DEV  *IdeBlkIoDevice;
+
+  IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This);
+
+  if (*IdentifyDataSize < sizeof (EFI_IDENTIFY_DATA)) {
+    *IdentifyDataSize = sizeof (EFI_IDENTIFY_DATA);
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  if (IdeBlkIoDevice->IdData == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  gBS->CopyMem (IdentifyData, IdeBlkIoDevice->IdData, sizeof (EFI_IDENTIFY_DATA));
+  *IdentifyDataSize = sizeof (EFI_IDENTIFY_DATA);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function is used by the IDE bus driver to get sense data. 
+  Data format of Sense data is defined by the Interface GUID.
+
+  @param  This                  Pointer to the EFI_DISK_INFO_PROTOCOL instance. 
+  @param  SenseData             Pointer to the SenseData. 
+  @param  SenseDataSize         Size of SenseData in bytes. 
+  @param  SenseDataNumber       Pointer to the value for the identify data size.
+
+  @retval EFI_SUCCESS           The command was accepted without any errors.
+  @retval EFI_NOT_FOUND         Device does not support this data class 
+  @retval EFI_DEVICE_ERROR      Error reading InquiryData from device 
+  @retval EFI_BUFFER_TOO_SMALL  SenseDataSize not big enough 
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoSenseData (
+  IN     EFI_DISK_INFO_PROTOCOL   *This,
+  IN OUT VOID                     *SenseData,
+  IN OUT UINT32                   *SenseDataSize,
+  OUT    UINT8                    *SenseDataNumber
+  )
+{
+  return EFI_NOT_FOUND;
+}
+
+/**
+  This function is used by the IDE bus driver to get controller information.
+
+  @param  This                  Pointer to the EFI_DISK_INFO_PROTOCOL instance. 
+  @param  IdeChannel            Pointer to the Ide Channel number. Primary or secondary.
+  @param  IdeDevice             Pointer to the Ide Device number. Master or slave.
+
+  @retval EFI_SUCCESS           IdeChannel and IdeDevice are valid 
+  @retval EFI_UNSUPPORTED       This is not an IDE device 
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoWhichIde (
+  IN  EFI_DISK_INFO_PROTOCOL   *This,
+  OUT UINT32                   *IdeChannel,
+  OUT UINT32                   *IdeDevice
+  )
+{
+  IDE_BLK_IO_DEV  *IdeBlkIoDevice;
+
+  IdeBlkIoDevice  = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This);
+  *IdeChannel     = IdeBlkIoDevice->Channel;
+  *IdeDevice      = IdeBlkIoDevice->Device;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  The is an event(generally the event is exitBootService event) call back function.
+  Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.
+
+  @param  Event   Pointer to this event
+  @param  Context Event hanlder private data
+
+**/
+VOID
+EFIAPI
+ClearInterrupt (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  EFI_STATUS      Status;
+  UINT64          IoPortForBmis;
+  UINT8           RegisterValue;
+  IDE_BLK_IO_DEV  *IdeDev;
+
+  //
+  // Get our context
+  //
+  IdeDev = (IDE_BLK_IO_DEV *) Context;
+
+  //
+  // Obtain IDE IO port registers' base addresses
+  //
+  Status = ReassignIdeResources (IdeDev);
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  //
+  // Check whether interrupt is pending
+  //
+
+  //
+  // Reset IDE device to force it de-assert interrupt pin
+  // Note: this will reset all devices on this IDE channel
+  //
+  AtaSoftReset (IdeDev);
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  //
+  // Get base address of IDE Bus Master Status Regsiter
+  //
+  if (IdePrimary == IdeDev->Channel) {
+    IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;
+  } else {
+    if (IdeSecondary == IdeDev->Channel) {
+      IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;
+    } else {
+      return;
+    }
+  }
+  //
+  // Read BMIS register and clear ERROR and INTR bit
+  //
+  IdeDev->PciIo->Io.Read (
+                      IdeDev->PciIo,
+                      EfiPciIoWidthUint8,
+                      EFI_PCI_IO_PASS_THROUGH_BAR,
+                      IoPortForBmis,
+                      1,
+                      &RegisterValue
+                      );
+
+  RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);
+
+  IdeDev->PciIo->Io.Write (
+                      IdeDev->PciIo,
+                      EfiPciIoWidthUint8,
+                      EFI_PCI_IO_PASS_THROUGH_BAR,
+                      IoPortForBmis,
+                      1,
+                      &RegisterValue
+                      );
+
+  //
+  // Select the other device on this channel to ensure this device to release the interrupt pin
+  //
+  if (IdeDev->Device == 0) {
+    RegisterValue = (1 << 4) | 0xe0;
+  } else {
+    RegisterValue = (0 << 4) | 0xe0;
+  }
+  IDEWritePortB (
+    IdeDev->PciIo,
+    IdeDev->IoPort->Head,
+    RegisterValue
+    );
+
+}
+
+/**
+  The user Entry Point for module IdeBus. The user code starts with this function.
+
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
+  @param[in] SystemTable    A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS       The entry point is executed successfully.
+  @retval other             Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeIdeBus(
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  EFI_STATUS              Status;
+
+  //
+  // Install driver model protocol(s).
+  //
+  Status = EfiLibInstallAllDriverProtocols2 (
+             ImageHandle,
+             SystemTable,
+             &gIDEBusDriverBinding,
+             ImageHandle,
+             &gIDEBusComponentName,
+             &gIDEBusComponentName2,
+             NULL,
+             NULL,
+             &gIDEBusDriverDiagnostics,
+             &gIDEBusDriverDiagnostics2
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/IdeBus.h
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/IdeBus.h	(revision 33024)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/IdeBus.h	(revision 33024)
@@ -0,0 +1,540 @@
+/** @file
+  Header file for IDE Bus Driver.
+
+  Copyright (c) 2006 - 2007 Intel Corporation. <BR>
+  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.
+
+**/
+
+#ifndef _IDE_BUS_H_
+#define _IDE_BUS_H_
+
+
+
+#include <FrameworkDxe.h>
+
+#include <Protocol/IdeControllerInit.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/DiskInfo.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <Guid/EventGroup.h>
+
+#include <IndustryStandard/Pci.h>
+#include "IdeData.h"
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL      gIDEBusDriverBinding;
+extern EFI_DRIVER_DIAGNOSTICS_PROTOCOL  gIDEBusDriverDiagnostics;
+extern EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gIDEBusDriverDiagnostics2;
+
+//
+// Extra Definition to porting
+//
+#define MAX_IDE_DEVICE    4
+#define MAX_IDE_CHANNELS  2
+#define MAX_IDE_DRIVES    2
+
+#define INVALID_DEVICE_TYPE 0xff
+#define ATA_DEVICE_TYPE     0x00
+#define ATAPI_DEVICE_TYPE   0x01
+
+typedef struct {
+  BOOLEAN HaveScannedDevice[MAX_IDE_DEVICE];
+  BOOLEAN DeviceFound[MAX_IDE_DEVICE];
+  BOOLEAN DeviceProcessed[MAX_IDE_DEVICE];
+} IDE_BUS_DRIVER_PRIVATE_DATA;
+
+#define IDE_BLK_IO_DEV_SIGNATURE  SIGNATURE_32 ('i', 'b', 'i', 'd')
+
+typedef struct {
+  UINT32                      Signature;
+
+  EFI_HANDLE                  Handle;
+  EFI_BLOCK_IO_PROTOCOL       BlkIo;
+  EFI_BLOCK_IO_MEDIA          BlkMedia;
+  EFI_DISK_INFO_PROTOCOL      DiskInfo;
+  EFI_DEVICE_PATH_PROTOCOL    *DevicePath;
+  EFI_PCI_IO_PROTOCOL         *PciIo;
+  IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData;
+
+  //
+  // Local Data for IDE interface goes here
+  //
+  EFI_IDE_CHANNEL             Channel;
+  EFI_IDE_DEVICE              Device;
+  UINT16                      Lun;
+  IDE_DEVICE_TYPE             Type;
+
+  IDE_BASE_REGISTERS          *IoPort;
+  UINT16                      AtapiError;
+
+  ATAPI_INQUIRY_DATA                *InquiryData;
+  EFI_IDENTIFY_DATA           *IdData;
+  ATA_PIO_MODE                PioMode;
+  EFI_ATA_MODE                UdmaMode;
+  CHAR8                       ModelName[41];
+  ATAPI_REQUEST_SENSE_DATA          *SenseData;
+  UINT8                       SenseDataNumber;
+  UINT8                       *Cache;
+
+  //
+  // ExitBootService Event, it is used to clear pending IDE interrupt
+  //
+  EFI_EVENT                   ExitBootServiceEvent;
+
+  EFI_UNICODE_STRING_TABLE    *ControllerNameTable;
+} IDE_BLK_IO_DEV;
+
+#include "ComponentName.h"
+
+#define IDE_BLOCK_IO_DEV_FROM_THIS(a)           CR (a, IDE_BLK_IO_DEV, BlkIo, IDE_BLK_IO_DEV_SIGNATURE)
+#define IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS(a) CR (a, IDE_BLK_IO_DEV, DiskInfo, IDE_BLK_IO_DEV_SIGNATURE)
+
+#include "Ide.h"
+
+
+/**
+  Supported function of Driver Binding protocol for this driver.
+
+  @param This                A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param ControllerHandle    The handle of the controller to test.
+  @param RemainingDevicePath A pointer to the remaining portion of a device path.
+
+  @retval  EFI_SUCCESS Driver loaded.
+  @retval  other       Driver not loaded.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  );
+
+/**
+  Start function of Driver binding protocol which start this driver on Controller
+  by detecting all disks and installing BlockIo protocol on them.
+
+  @param  This                Protocol instance pointer.
+  @param  Controller          Handle of device to bind driver to.
+  @param  RemainingDevicePath produce all possible children.
+
+  @retval  EFI_SUCCESS         This driver is added to ControllerHandle.
+  @retval  EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
+  @retval  other               This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  );
+
+/**
+  Stop function of Driver Binding Protocol which is to stop the driver on Controller Handle and all
+  child handle attached to the controller handle if there are.
+
+  @param  This Protocol instance pointer.
+  @param  Controller Handle of device to stop driver on
+  @param  NumberOfChildren Not used
+  @param  ChildHandleBuffer Not used
+
+  @retval  EFI_SUCCESS This driver is removed DeviceHandle
+  @retval  other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN  EFI_HANDLE                  Controller,
+  IN  UINTN                       NumberOfChildren,
+  IN  EFI_HANDLE                  *ChildHandleBuffer
+  );
+
+//
+// EFI Driver Configuration Functions
+//
+/**
+  Allows the user to set controller specific options for a controller that a 
+  driver is currently managing.
+
+  @param  This              A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL instance.
+  @param  ControllerHandle  The handle of the controller to set options on.
+  @param  ChildHandle       The handle of the child controller to set options on.
+                            This is an optional parameter that may be NULL.
+                            It will be NULL for device drivers, and for a bus drivers
+                            that wish to set options for the bus controller.
+                            It will not be NULL for a bus driver that wishes to set
+                            options for one of its child controllers.
+  @param  Language          A pointer to a three character ISO 639-2 language identifier. 
+                            This is the language of the user interface that should be presented 
+                            to the user, and it must match one of the languages specified in 
+                            SupportedLanguages. The number of languages supported by a driver is up to
+                            the driver writer.
+  @param  ActionRequired    A pointer to the action that the calling agent is required 
+                            to perform when this function returns.
+  
+
+  @retval  EFI_SUCCESS           The driver specified by This successfully set the configuration 
+                                 options for the controller specified by ControllerHandle..
+  @retval  EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+  @retval  EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+  @retval  EFI_INVALID_PARAMETER ActionRequired is NULL.
+  @retval  EFI_UNSUPPORTED       The driver specified by This does not support setting configuration options for 
+                                 the controller specified by ControllerHandle and ChildHandle.
+  @retval  EFI_UNSUPPORTED       The driver specified by This does not support the language specified by Language.
+  @retval  EFI_DEVICE_ERROR      A device error occurred while attempt to set the configuration options for the 
+                                 controller specified by ControllerHandle and ChildHandle.
+  @retval  EFI_OUT_RESOURCES     There are not enough resources available to set the configuration options for the 
+                                 controller specified by ControllerHandle and ChildHandle
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverConfigurationSetOptions (
+  IN  EFI_DRIVER_CONFIGURATION_PROTOCOL                      *This,
+  IN  EFI_HANDLE                                             ControllerHandle,
+  IN  EFI_HANDLE                                             ChildHandle  OPTIONAL,
+  IN  CHAR8                                                  *Language,
+  OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED               *ActionRequired
+  );
+
+/**
+  Tests to see if a controller's current configuration options are valid.
+
+  @param  This             A pointer to the EFI_DRIVER_CONFIGURATION_PROTOCOL instance.
+  @param  ControllerHandle The handle of the controller to test if it's current configuration options 
+                           are valid.
+  @param  ChildHandle      The handle of the child controller to test if it's current configuration 
+                           options are valid.  This is an optional parameter that may be NULL. It will 
+                           be NULL for device drivers.  It will also be NULL for a bus drivers that
+                           wish to test the configuration options for the bus controller. It will 
+                           not be NULL for a bus driver that wishes to test configuration options for 
+                           one of its child controllers.
+  @retval  EFI_SUCCESS           The controller specified by ControllerHandle and ChildHandle that is being
+                                 managed by the driver specified by This has a valid set of  configuration
+                                 options.
+  @retval  EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+  @retval  EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+  @retval  EFI_UNSUPPORTED       The driver specified by This is not currently  managing the controller 
+                                 specified by ControllerHandle and ChildHandle.
+  @retval  EFI_DEVICE_ERROR      The controller specified by ControllerHandle and ChildHandle that is being
+                                 managed by the driver specified by This has an invalid set of configuration
+                                 options.
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverConfigurationOptionsValid (
+  IN  EFI_DRIVER_CONFIGURATION_PROTOCOL               *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle  OPTIONAL
+  );
+
+/**
+  Forces a driver to set the default configuration options for a controller.
+
+  @param  This             A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL instance.
+  @param  ControllerHandle The handle of the controller to force default configuration options on.
+  @param  ChildHandle      The handle of the child controller to force default configuration 
+                           options on  This is an optional parameter that may be NULL.  It 
+                           will be NULL for device drivers. It will also be NULL for a bus 
+                           drivers that wish to force default configuration options for the bus
+                           controller.  It will not be NULL for a bus driver that wishes to force
+                           default configuration options for one of its child controllers.
+  @param  DefaultType      The type of default configuration options to force on the controller 
+                           specified by ControllerHandle and ChildHandle. 
+  @param  ActionRequired   A pointer to the action that the calling agent is required to perform 
+                           when this function returns.
+
+  @retval  EFI_SUCCESS           The driver specified by This successfully forced the 
+                                 default configuration options on the controller specified by 
+                                 ControllerHandle and ChildHandle.
+  @retval  EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+  @retval  EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+  @retval  EFI_INVALID_PARAMETER ActionRequired is NULL.
+  @retval  EFI_UNSUPPORTED       The driver specified by This does not support forcing the default 
+                                 configuration options on the controller specified by ControllerHandle
+                                 and ChildHandle.
+  @retval  EFI_UNSUPPORTED       The driver specified by This does not support the configuration type 
+                                 specified by DefaultType.
+  @retval  EFI_DEVICE_ERROR      A device error occurred while attempt to force the default configuration 
+                                 options on the controller specified by  ControllerHandle and ChildHandle.
+  @retval  EFI_OUT_RESOURCES     There are not enough resources available to force the default configuration 
+                                 options on the controller specified by ControllerHandle and ChildHandle.
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverConfigurationForceDefaults (
+  IN  EFI_DRIVER_CONFIGURATION_PROTOCOL                      *This,
+  IN  EFI_HANDLE                                             ControllerHandle,
+  IN  EFI_HANDLE                                             ChildHandle  OPTIONAL,
+  IN  UINT32                                                 DefaultType,
+  OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED               *ActionRequired
+  );
+
+//
+// EFI Driver Diagnostics Functions
+//
+/**
+  Runs diagnostics on a controller.
+
+  @param  This             A pointer to the EFI_DRIVER_DIAGNOSTICS_PROTOCOLinstance.
+  @param  ControllerHandle The handle of the controller to run diagnostics on.
+  @param  ChildHandle      The handle of the child controller to run diagnostics on
+                           This is an optional parameter that may be NULL.  It will
+                           be NULL for device drivers.  It will also be NULL for a
+                           bus drivers that wish to run diagnostics on the bus controller. 
+                           It will not be NULL for a bus driver that wishes to run 
+                           diagnostics on one of its child controllers.
+  @param  DiagnosticType   Indicates type of diagnostics to perform on the controller
+                           specified by ControllerHandle and ChildHandle.
+  @param  Language         A pointer to a three character ISO 639-2 language identifier. 
+                           This is the language in which the optional error message should 
+                           be returned in Buffer, and it must match one of the languages 
+                           specified in SupportedLanguages. The number of languages supported by
+                           a driver is up to the driver writer.
+  @param  ErrorType        A GUID that defines the format of the data returned in Buffer.
+  @param  BufferSize       The size, in bytes, of the data returned in Buffer.
+  @param  Buffer           A buffer that contains a Null-terminated Unicode string
+                           plus some additional data whose format is defined by ErrorType.  
+                           Buffer is allocated by this function with AllocatePool(), and 
+                           it is the caller's responsibility to free it with a call to FreePool().
+
+  @retval  EFI_SUCCESS           The controller specified by ControllerHandle and ChildHandle passed 
+                                 the diagnostic.
+  @retval  EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+  @retval  EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+  @retval  EFI_INVALID_PARAMETER Language is NULL.
+  @retval  EFI_INVALID_PARAMETER ErrorType is NULL.
+  @retval  EFI_INVALID_PARAMETER BufferType is NULL.
+  @retval  EFI_INVALID_PARAMETER Buffer is NULL.
+  @retval  EFI_UNSUPPORTED       The driver specified by This does not support running 
+                                 diagnostics for the controller specified by ControllerHandle 
+                                 and ChildHandle.
+  @retval  EFI_UNSUPPORTED       The driver specified by This does not support the
+                                 type of diagnostic specified by DiagnosticType.
+  @retval  EFI_UNSUPPORTED       The driver specified by This does not support the language 
+                                 specified by Language.
+  @retval  EFI_OUT_OF_RESOURCES  There are not enough resources available to complete the 
+                                 diagnostics.
+  @retval  EFI_OUT_OF_RESOURCES  There are not enough resources available to return the 
+                                 status information in ErrorType, BufferSize,and Buffer.
+  @retval  EFI_DEVICE_ERROR      The controller specified by ControllerHandle and ChildHandle 
+                                 did not pass the diagnostic.
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverDiagnosticsRunDiagnostics (
+  IN  EFI_DRIVER_DIAGNOSTICS_PROTOCOL               *This,
+  IN  EFI_HANDLE                                    ControllerHandle,
+  IN  EFI_HANDLE                                    ChildHandle  OPTIONAL,
+  IN  EFI_DRIVER_DIAGNOSTIC_TYPE                    DiagnosticType,
+  IN  CHAR8                                         *Language,
+  OUT EFI_GUID                                      **ErrorType,
+  OUT UINTN                                         *BufferSize,
+  OUT CHAR16                                        **Buffer
+  );
+
+/**
+  issue ATA or ATAPI command to reset a block IO device.
+  @param  This                  Block IO protocol instance pointer.
+  @param  ExtendedVerification  If FALSE,for ATAPI device, driver will only invoke ATAPI reset method
+                                If TRUE, for ATAPI device, driver need invoke ATA reset method after
+                                invoke ATAPI reset method
+
+  @retval EFI_DEVICE_ERROR      When the device is neighther ATA device or ATAPI device.
+  @retval EFI_SUCCESS           The device reset successfully
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoReset (
+  IN  EFI_BLOCK_IO_PROTOCOL       *This,
+  IN  BOOLEAN                     ExtendedVerification
+  );
+
+/**
+  Read data from a block IO device.
+
+  @param  This       Block IO protocol instance pointer.
+  @param  MediaId    The media ID of the device
+  @param  Lba        Starting LBA address to read data
+  @param  BufferSize The size of data to be read
+  @param  Buffer     Caller supplied buffer to save data
+
+  @retval EFI_DEVICE_ERROR  unknown device type
+  @retval EFI_SUCCESS       read the data successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoReadBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL       *This,
+  IN  UINT32                      MediaId,
+  IN  EFI_LBA                     Lba,
+  IN  UINTN                       BufferSize,
+  OUT VOID                        *Buffer
+  );
+
+/**
+  Write data to block io device
+
+  @param  This       Protocol instance pointer.
+  @param  MediaId    The media ID of the device
+  @param  Lba        Starting LBA address to write data
+  @param  BufferSize The size of data to be written
+  @param  Buffer     Caller supplied buffer to save data
+
+  @retval EFI_DEVICE_ERROR  unknown device type
+  @retval other             write data status
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoWriteBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL       *This,
+  IN  UINT32                      MediaId,
+  IN  EFI_LBA                     Lba,
+  IN  UINTN                       BufferSize,
+  IN  VOID                        *Buffer
+  );
+
+/**
+  Flushes all modified data to a physical block devices
+
+  @param  This  Indicates a pointer to the calling context which to sepcify a 
+                sepcific block device
+
+  @retval EFI_SUCCESS   Always return success.
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoFlushBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL       *This
+  );
+/**
+  This function is used by the IDE bus driver to get inquiry data. 
+  Data format of Identify data is defined by the Interface GUID.
+
+  @param  This                  Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+  @param  InquiryData           Pointer to a buffer for the inquiry data.
+  @param  InquiryDataSize       Pointer to the value for the inquiry data size.
+
+  @retval EFI_SUCCESS           The command was accepted without any errors.
+  @retval EFI_NOT_FOUND         Device does not support this data class 
+  @retval EFI_DEVICE_ERROR      Error reading InquiryData from device 
+  @retval EFI_BUFFER_TOO_SMALL  IntquiryDataSize not big enough 
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoInquiry (
+  IN EFI_DISK_INFO_PROTOCOL       *This,
+  IN OUT VOID                     *InquiryData,
+  IN OUT UINT32                   *InquiryDataSize
+  );
+
+/**
+  This function is used by the IDE bus driver to get identify data. 
+  Data format of Identify data is defined by the Interface GUID.
+
+  @param  This                  Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+  @param  IdentifyData          Pointer to a buffer for the identify data.
+  @param  IdentifyDataSize      Pointer to the value for the identify data size.
+
+  @retval EFI_SUCCESS           The command was accepted without any errors.
+  @retval EFI_NOT_FOUND         Device does not support this data class 
+  @retval EFI_DEVICE_ERROR      Error reading IdentifyData from device 
+  @retval EFI_BUFFER_TOO_SMALL  IdentifyDataSize not big enough 
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoIdentify (
+  IN EFI_DISK_INFO_PROTOCOL       *This,
+  IN OUT VOID                     *IdentifyData,
+  IN OUT UINT32                   *IdentifyDataSize
+  );
+
+/**
+  This function is used by the IDE bus driver to get sense data. 
+  Data format of Sense data is defined by the Interface GUID.
+
+  @param  This                  Pointer to the EFI_DISK_INFO_PROTOCOL instance. 
+  @param  SenseData             Pointer to the SenseData. 
+  @param  SenseDataSize         Size of SenseData in bytes. 
+  @param  SenseDataNumber       Pointer to the value for the identify data size.
+
+  @retval EFI_SUCCESS           The command was accepted without any errors.
+  @retval EFI_NOT_FOUND         Device does not support this data class 
+  @retval EFI_DEVICE_ERROR      Error reading InquiryData from device 
+  @retval EFI_BUFFER_TOO_SMALL  SenseDataSize not big enough 
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoSenseData (
+  IN EFI_DISK_INFO_PROTOCOL       *This,
+  IN OUT VOID                     *SenseData,
+  IN OUT UINT32                   *SenseDataSize,
+  OUT UINT8                       *SenseDataNumber
+  );
+
+/**
+  This function is used by the IDE bus driver to get controller information.
+
+  @param  This                  Pointer to the EFI_DISK_INFO_PROTOCOL instance. 
+  @param  IdeChannel            Pointer to the Ide Channel number. Primary or secondary.
+  @param  IdeDevice             Pointer to the Ide Device number. Master or slave.
+
+  @retval EFI_SUCCESS           IdeChannel and IdeDevice are valid 
+  @retval EFI_UNSUPPORTED       This is not an IDE device 
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoWhichIde (
+  IN EFI_DISK_INFO_PROTOCOL       *This,
+  OUT UINT32                      *IdeChannel,
+  OUT UINT32                      *IdeDevice
+  );
+/**
+  The is an event(generally the event is exitBootService event) call back function. 
+  Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.
+
+  @param  Event   Pointer to this event
+  @param  Context Event hanlder private data
+
+**/
+VOID
+EFIAPI
+ClearInterrupt (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  );
+#endif
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/IdeData.h
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/IdeData.h	(revision 33024)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/IdeData.h	(revision 33024)
@@ -0,0 +1,311 @@
+/** @file
+  Header file for IDE Bus Driver's Data Structures
+
+  Copyright (c) 2006 - 2007 Intel Corporation. <BR>
+  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.             
+
+**/
+
+#ifndef _IDE_DATA_H_
+#define _IDE_DATA_H_
+
+#include <IndustryStandard/Atapi.h>
+
+//
+// common constants
+//
+#define STALL_1_MILLI_SECOND  1000    // stall 1 ms
+#define STALL_1_SECOND        1000000 // stall 1 second
+typedef enum {
+  IdePrimary    = 0,
+  IdeSecondary  = 1,
+  IdeMaxChannel = 2
+} EFI_IDE_CHANNEL;
+
+typedef enum {
+  IdeMaster     = 0,
+  IdeSlave      = 1,
+  IdeMaxDevice  = 2
+} EFI_IDE_DEVICE;
+
+typedef enum {
+  IdeMagnetic,                        /* ZIP Drive or LS120 Floppy Drive */
+  IdeCdRom,                           /* ATAPI CDROM */
+  IdeHardDisk,                        /* Hard Disk */
+  Ide48bitAddressingHardDisk,         /* Hard Disk larger than 120GB */
+  IdeUnknown
+} IDE_DEVICE_TYPE;
+
+typedef enum {
+  SenseNoSenseKey,
+  SenseDeviceNotReadyNoRetry,
+  SenseDeviceNotReadyNeedRetry,
+  SenseNoMedia,
+  SenseMediaChange,
+  SenseMediaError,
+  SenseOtherSense
+} SENSE_RESULT;
+
+typedef enum {
+  AtaUdmaReadOp,
+  AtaUdmaReadExtOp,
+  AtaUdmaWriteOp,
+  AtaUdmaWriteExtOp
+} ATA_UDMA_OPERATION;
+
+//
+// IDE Registers
+//
+typedef union {
+  UINT16  Command;        /* when write */
+  UINT16  Status;         /* when read */
+} IDE_CMD_OR_STATUS;
+
+typedef union {
+  UINT16  Error;          /* when read */
+  UINT16  Feature;        /* when write */
+} IDE_ERROR_OR_FEATURE;
+
+typedef union {
+  UINT16  AltStatus;      /* when read */
+  UINT16  DeviceControl;  /* when write */
+} IDE_ALTSTATUS_OR_DEVICECONTROL;
+
+//
+// IDE registers set
+//
+typedef struct {
+  UINT16                          Data;
+  IDE_ERROR_OR_FEATURE            Reg1;
+  UINT16                          SectorCount;
+  UINT16                          SectorNumber;
+  UINT16                          CylinderLsb;
+  UINT16                          CylinderMsb;
+  UINT16                          Head;
+  IDE_CMD_OR_STATUS               Reg;
+
+  IDE_ALTSTATUS_OR_DEVICECONTROL  Alt;
+  UINT16                          DriveAddress;
+
+  UINT16                          MasterSlave;
+  UINT16                          BusMasterBaseAddr;
+} IDE_BASE_REGISTERS;
+
+//
+// IDE registers' base addresses
+//
+typedef struct {
+  UINT16  CommandBlockBaseAddr;
+  UINT16  ControlBlockBaseAddr;
+  UINT16  BusMasterBaseAddr;
+} IDE_REGISTERS_BASE_ADDR;
+
+//
+// Bit definitions in Programming Interface byte of the Class Code field
+// in PCI IDE controller's Configuration Space
+//
+#define IDE_PRIMARY_OPERATING_MODE            BIT0
+#define IDE_PRIMARY_PROGRAMMABLE_INDICATOR    BIT1
+#define IDE_SECONDARY_OPERATING_MODE          BIT2
+#define IDE_SECONDARY_PROGRAMMABLE_INDICATOR  BIT3
+
+
+//
+// Bus Master Reg
+//
+#define BMIC_NREAD      BIT3
+#define BMIC_START      BIT0
+#define BMIS_INTERRUPT  BIT2
+#define BMIS_ERROR      BIT1
+
+#define BMICP_OFFSET    0x00
+#define BMISP_OFFSET    0x02
+#define BMIDP_OFFSET    0x04
+#define BMICS_OFFSET    0x08
+#define BMISS_OFFSET    0x0A
+#define BMIDS_OFFSET    0x0C
+
+//
+// Time Out Value For IDE Device Polling
+//
+
+//
+// ATATIMEOUT is used for waiting time out for ATA device
+//
+
+//
+// 1 second
+//
+#define ATATIMEOUT  1000  
+
+//
+// ATAPITIMEOUT is used for waiting operation
+// except read and write time out for ATAPI device
+//
+
+//
+// 1 second
+//
+#define ATAPITIMEOUT  1000 
+
+//
+// ATAPILONGTIMEOUT is used for waiting read and
+// write operation timeout for ATAPI device
+//
+
+//
+// 2 seconds
+//
+#define CDROMLONGTIMEOUT  2000  
+
+//
+// 5 seconds
+//
+#define ATAPILONGTIMEOUT  5000  
+
+//
+// 10 seconds
+//
+#define ATASMARTTIMEOUT   10000
+
+
+//
+// ATAPI6 related data structure definition
+//
+
+//
+// The maximum sectors count in 28 bit addressing mode
+//
+#define MAX_28BIT_ADDRESSING_CAPACITY 0xfffffff
+
+#pragma pack(1)
+
+typedef struct {
+  UINT32  RegionBaseAddr;
+  UINT16  ByteCount;
+  UINT16  EndOfTable;
+} IDE_DMA_PRD;
+
+#pragma pack()
+
+#define SETFEATURE        TRUE
+#define CLEARFEATURE      FALSE
+
+///
+/// PIO mode definition
+///
+typedef enum _ATA_PIO_MODE_ {
+  AtaPioModeBelow2,
+  AtaPioMode2,
+  AtaPioMode3,
+  AtaPioMode4
+} ATA_PIO_MODE;
+
+//
+// Multi word DMA definition
+//
+typedef enum _ATA_MDMA_MODE_ {
+  AtaMdmaMode0,
+  AtaMdmaMode1,
+  AtaMdmaMode2
+} ATA_MDMA_MODE;
+
+//
+// UDMA mode definition
+//
+typedef enum _ATA_UDMA_MODE_ {
+  AtaUdmaMode0,
+  AtaUdmaMode1,
+  AtaUdmaMode2,
+  AtaUdmaMode3,
+  AtaUdmaMode4,
+  AtaUdmaMode5
+} ATA_UDMA_MODE;
+
+#define ATA_MODE_CATEGORY_DEFAULT_PIO 0x00
+#define ATA_MODE_CATEGORY_FLOW_PIO    0x01
+#define ATA_MODE_CATEGORY_MDMA        0x04
+#define ATA_MODE_CATEGORY_UDMA        0x08
+
+#pragma pack(1)
+
+typedef struct {
+  UINT8 ModeNumber : 3;
+  UINT8 ModeCategory : 5;
+} ATA_TRANSFER_MODE;
+
+typedef struct {
+  UINT8 Sector;
+  UINT8 Heads;
+  UINT8 MultipleSector;
+} ATA_DRIVE_PARMS;
+
+#pragma pack()
+//
+// IORDY Sample Point field value
+//
+#define ISP_5_CLK 0
+#define ISP_4_CLK 1
+#define ISP_3_CLK 2
+#define ISP_2_CLK 3
+
+//
+// Recovery Time field value
+//
+#define RECVY_4_CLK 0
+#define RECVY_3_CLK 1
+#define RECVY_2_CLK 2
+#define RECVY_1_CLK 3
+
+//
+// Slave IDE Timing Register Enable
+//
+#define SITRE BIT14
+
+//
+// DMA Timing Enable Only Select 1
+//
+#define DTE1  BIT7
+
+//
+// Pre-fetch and Posting Enable Select 1
+//
+#define PPE1  BIT6
+
+//
+// IORDY Sample Point Enable Select 1
+//
+#define IE1 BIT5
+
+//
+// Fast Timing Bank Drive Select 1
+//
+#define TIME1 BIT4
+
+//
+// DMA Timing Enable Only Select 0
+//
+#define DTE0  BIT3
+
+//
+// Pre-fetch and Posting Enable Select 0
+//
+#define PPE0  BIT2
+
+//
+// IOREY Sample Point Enable Select 0
+//
+#define IE0 BIT1
+
+//
+// Fast Timing Bank Drive Select 0
+//
+#define TIME0 BIT0
+
+#endif
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/VBoxIdeBusDxe.inf
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/VBoxIdeBusDxe.inf	(revision 33024)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/VBoxIdeBusDxe.inf	(revision 33024)
@@ -0,0 +1,85 @@
+#/** @file
+# Component description file for IdeBus module.
+#
+# IDE bus driver. This driver will enumerate IDE device and export the blockIo
+#  protocol for every device.
+# Copyright (c) 2006 - 2009, Intel Corporation
+#
+#  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.
+#
+#
+#**/
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = IdeBusDxe
+  FILE_GUID                      = 69FD8E47-A161-4550-B01A-5594CEB2B2B2
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  EFI_SPECIFICATION_VERSION      = 0x00020000
+  ENTRY_POINT                    = InitializeIdeBus
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+#  DRIVER_BINDING                =  gIDEBusDriverBinding                         
+#  COMPONENT_NAME                =  gIDEBusComponentName
+#  COMPONENT_NAME2               =  gIDEBusComponentName2                         
+#  Variable Guid C Name: gConfigurationGuid Variable Name: L"Configuration"
+#
+#
+
+[Sources.common]
+  DriverDiagnostics.c
+  DriverConfiguration.c
+  ComponentName.h
+  ComponentName.c
+  Atapi.c
+  Ata.c
+  Ide.c
+  IdeBus.c
+  IdeData.h
+  Ide.h
+  IdeBus.h
+
+
+[Packages]
+  MdePkg/MdePkg.dec
+  IntelFrameworkPkg/IntelFrameworkPkg.dec
+  IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec  
+
+
+[LibraryClasses]
+  DevicePathLib
+  UefiRuntimeServicesTableLib
+  UefiBootServicesTableLib
+  PerformanceLib
+  MemoryAllocationLib
+  ReportStatusCodeLib
+  BaseMemoryLib
+  UefiLib
+  BaseLib
+  UefiDriverEntryPoint
+  DebugLib
+
+
+[Guids]
+  gEfiDiskInfoIdeInterfaceGuid                  # CONSUMES  ## GUID
+  gEfiEventExitBootServicesGuid                 # CONSUMES  ## Event
+
+
+[Protocols]
+  gEfiDiskInfoProtocolGuid                      # BY_START
+  gEfiBlockIoProtocolGuid                       # BY_START
+  gEfiIdeControllerInitProtocolGuid             # TO_START
+  gEfiPciIoProtocolGuid                         # TO_START
+  gEfiDevicePathProtocolGuid                    # TO_START
+
+
