Add PciBus & IdeBus
authorqhuang8 <qhuang8@6f19259b-4bc3-4df7-8a09-765794883524>
Thu, 28 Jun 2007 14:02:17 +0000 (14:02 +0000)
committerqhuang8 <qhuang8@6f19259b-4bc3-4df7-8a09-765794883524>
Thu, 28 Jun 2007 14:02:17 +0000 (14:02 +0000)
PciBus cannot build for now for some definition missing.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2852 6f19259b-4bc3-4df7-8a09-765794883524

44 files changed:
IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/DriverConfiguration.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.inf [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.msa [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/idedata.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/ComponentName.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/ComponentName.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciBus.inf [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciBus.msa [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciCommand.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciCommand.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciDeviceSupport.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciDeviceSupport.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciDriverOverride.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciDriverOverride.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumerator.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumerator.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumeratorSupport.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumeratorSupport.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciHotPlugSupport.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciHotPlugSupport.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciIo.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciIo.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciLib.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciLib.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciOptionRomSupport.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciOptionRomSupport.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciPowerManagement.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciPowerManagement.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciResourceSupport.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciResourceSupport.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciRomTable.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciRomTable.h [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/pcibus.c [new file with mode: 0644]
IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/pcibus.h [new file with mode: 0644]
IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc

diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.c b/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.c
new file mode 100644 (file)
index 0000000..12673c9
--- /dev/null
@@ -0,0 +1,210 @@
+/** @file\r
+  Copyright (c) 2006, Intel Corporation                                                         \r
+  All rights reserved. This program and the accompanying materials                          \r
+  are licensed and made available under the terms and conditions of the BSD License         \r
+  which accompanies this distribution.  The full text of the license may be found at        \r
+  http://opensource.org/licenses/bsd-license.php                                            \r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+**/\r
+\r
+#include "idebus.h"\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL     gIDEBusComponentName = {\r
+  IDEBusComponentNameGetDriverName,\r
+  IDEBusComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+STATIC EFI_UNICODE_STRING_TABLE mIDEBusDriverNameTable[] = {\r
+  { "eng", (CHAR16 *) L"PCI IDE/ATAPI Bus Driver" },\r
+  { NULL , NULL }\r
+};\r
+\r
+STATIC EFI_UNICODE_STRING_TABLE mIDEBusControllerNameTable[] = {\r
+  { "eng", (CHAR16 *) L"PCI IDE/ATAPI Controller" },\r
+  { NULL , NULL }\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+  @param  This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  @param  Language A pointer to a three character ISO 639-2 language identifier.\r
+  This is the language of the driver name that that the caller\r
+  is requesting, and it must match one of the languages specified\r
+  in SupportedLanguages.  The number of languages supported by a\r
+  driver is up to the driver writer.\r
+  @param  DriverName A pointer to the Unicode string to return.  This Unicode string\r
+  is the name of the driver specified by This in the language\r
+  specified by Language.\r
+\r
+  @retval  EFI_SUCCESS The Unicode string for the Driver specified by This\r
+  and the language specified by Language was returned\r
+  in DriverName.\r
+  @retval  EFI_INVALID_PARAMETER Language is NULL.\r
+  @retval  EFI_INVALID_PARAMETER DriverName is NULL.\r
+  @retval  EFI_UNSUPPORTED The driver specified by This does not support the\r
+  language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IDEBusComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString (\r
+          Language,\r
+          gIDEBusComponentName.SupportedLanguages,\r
+          mIDEBusDriverNameTable,\r
+          DriverName\r
+          );\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by an EFI Driver.\r
+\r
+  @param  This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  @param  ControllerHandle The handle of a controller that the driver specified by\r
+  This is managing.  This handle specifies the controller\r
+  whose name is to be returned.\r
+  @param  ChildHandle The handle of the child controller to retrieve the name\r
+  of.  This is an optional parameter that may be NULL.  It\r
+  will be NULL for device drivers.  It will also be NULL\r
+  for a bus drivers that wish to retrieve the name of the\r
+  bus controller.  It will not be NULL for a bus driver\r
+  that wishes to retrieve the name of a child controller.\r
+  @param  Language A pointer to a three character ISO 639-2 language\r
+  identifier.  This is the language of the controller name\r
+  that that the caller is requesting, and it must match one\r
+  of the languages specified in SupportedLanguages.  The\r
+  number of languages supported by a driver is up to the\r
+  driver writer.\r
+  @param  ControllerName A pointer to the Unicode string to return.  This Unicode\r
+  string is the name of the controller specified by\r
+  ControllerHandle and ChildHandle in the language\r
+  specified by Language from the point of view of the\r
+  driver specified by This.\r
+\r
+  @retval  EFI_SUCCESS The Unicode string for the user readable name in the\r
+  language specified by Language for the driver\r
+  specified by This was returned in DriverName.\r
+  @retval  EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+  @retval  EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+  EFI_HANDLE.\r
+  @retval  EFI_INVALID_PARAMETER Language is NULL.\r
+  @retval  EFI_INVALID_PARAMETER ControllerName is NULL.\r
+  @retval  EFI_UNSUPPORTED The driver specified by This is not currently\r
+  managing the controller specified by\r
+  ControllerHandle and ChildHandle.\r
+  @retval  EFI_UNSUPPORTED The driver specified by This does not support the\r
+  language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IDEBusComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+  IDE_BLK_IO_DEV        *IdeBlkIoDevice;\r
+\r
+  //\r
+  // Make sure this driver is currently managing ControllHandle\r
+  //\r
+  Status = EfiTestManagedDevice (\r
+             ControllerHandle,\r
+             gIDEBusDriverBinding.DriverBindingHandle,\r
+             &gEfiIdeControllerInitProtocolGuid\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (ChildHandle == NULL) {\r
+    return LookupUnicodeString (\r
+            Language,\r
+            gIDEBusComponentName.SupportedLanguages,\r
+            mIDEBusControllerNameTable,\r
+            ControllerName\r
+            );\r
+  }\r
+\r
+  Status = EfiTestChildHandle (\r
+             ControllerHandle,\r
+             ChildHandle,\r
+             &gEfiPciIoProtocolGuid\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Get the child context\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ChildHandle,\r
+                  &gEfiBlockIoProtocolGuid,\r
+                  (VOID **) &BlockIo,\r
+                  gIDEBusDriverBinding.DriverBindingHandle,\r
+                  ChildHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlockIo);\r
+\r
+  return LookupUnicodeString (\r
+          Language,\r
+          gIDEBusComponentName.SupportedLanguages,\r
+          IdeBlkIoDevice->ControllerNameTable,\r
+          ControllerName\r
+          );\r
+}\r
+\r
+/**\r
+  Add the component name for the IDE/ATAPI device\r
+\r
+  @param  IdeBlkIoDevicePtr A pointer to the IDE_BLK_IO_DEV instance.\r
+\r
+**/\r
+VOID\r
+AddName (\r
+  IN  IDE_BLK_IO_DEV               *IdeBlkIoDevicePtr\r
+  )\r
+{\r
+  UINTN   StringIndex;\r
+  CHAR16  ModelName[41];\r
+\r
+  //\r
+  // Add Component Name for the IDE/ATAPI device that was discovered.\r
+  //\r
+  IdeBlkIoDevicePtr->ControllerNameTable = NULL;\r
+  for (StringIndex = 0; StringIndex < 41; StringIndex++) {\r
+    ModelName[StringIndex] = IdeBlkIoDevicePtr->ModelName[StringIndex];\r
+  }\r
+\r
+  AddUnicodeString (\r
+    "eng",\r
+    gIDEBusComponentName.SupportedLanguages,\r
+    &IdeBlkIoDevicePtr->ControllerNameTable,\r
+    ModelName\r
+    );\r
+}\r
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.h b/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.h
new file mode 100644 (file)
index 0000000..e6bf11f
--- /dev/null
@@ -0,0 +1,80 @@
+/** @file\r
+  Copyright (c) 2006, Intel Corporation\r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _IDE_BUS_COMPONENT_NAME_H\r
+#define _IDE_BUS_COMPONENT_NAME_H\r
+\r
+#define ADD_NAME(x) AddName ((x));\r
+\r
+extern EFI_COMPONENT_NAME_PROTOCOL  gIDEBusComponentName;\r
+\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  This TODO: add argument description\r
+  @param  Language TODO: add argument description\r
+  @param  DriverName TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IDEBusComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  This TODO: add argument description\r
+  @param  ControllerHandle TODO: add argument description\r
+  @param  ChildHandle TODO: add argument description\r
+  @param  Language TODO: add argument description\r
+  @param  ControllerName TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IDEBusComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeBlkIoDevicePtr TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+VOID\r
+AddName (\r
+  IN  IDE_BLK_IO_DEV               *IdeBlkIoDevicePtr\r
+  )\r
+;\r
+\r
+#endif\r
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/DriverConfiguration.c b/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/DriverConfiguration.c
new file mode 100644 (file)
index 0000000..47288ac
--- /dev/null
@@ -0,0 +1,322 @@
+/** @file\r
+  Copyright (c) 2006, Intel Corporation                                                         \r
+  All rights reserved. This program and the accompanying materials                          \r
+  are licensed and made available under the terms and conditions of the BSD License         \r
+  which accompanies this distribution.  The full text of the license may be found at        \r
+  http://opensource.org/licenses/bsd-license.php                                            \r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+**/\r
+\r
+\r
+#include "idebus.h"\r
+\r
+CHAR16 *OptionString[4] = {\r
+  L"Enable Primary Master    (Y/N)? -->",\r
+  L"Enable Primary Slave     (Y/N)? -->",\r
+  L"Enable Secondary Master  (Y/N)? -->",\r
+  L"Enable Secondary Slave   (Y/N)? -->"\r
+};\r
+\r
+//\r
+// EFI Driver Configuration Protocol\r
+//\r
+EFI_DRIVER_CONFIGURATION_PROTOCOL gIDEBusDriverConfiguration = {\r
+  IDEBusDriverConfigurationSetOptions,\r
+  IDEBusDriverConfigurationOptionsValid,\r
+  IDEBusDriverConfigurationForceDefaults,\r
+  "eng"\r
+};\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @retval  EFI_ABORTED TODO: Add description for return value\r
+  @retval  EFI_SUCCESS TODO: Add description for return value\r
+  @retval  EFI_NOT_FOUND TODO: Add description for return value\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+GetResponse (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  EFI_INPUT_KEY Key;\r
+\r
+  while (TRUE) {\r
+    Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+    if (!EFI_ERROR (Status)) {\r
+      if (Key.ScanCode == SCAN_ESC) {\r
+        return EFI_ABORTED;\r
+      }\r
+\r
+      switch (Key.UnicodeChar) {\r
+\r
+      //\r
+      // fall through\r
+      //\r
+      case L'y':\r
+      case L'Y':\r
+        gST->ConOut->OutputString (gST->ConOut, L"Y\n");\r
+        return EFI_SUCCESS;\r
+\r
+      //\r
+      // fall through\r
+      //\r
+      case L'n':\r
+      case L'N':\r
+        gST->ConOut->OutputString (gST->ConOut, L"N\n");\r
+        return EFI_NOT_FOUND;\r
+      }\r
+\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Allows the user to set controller specific options for a controller that a \r
+  driver is currently managing.\r
+\r
+  @param  This A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL\r
+  instance.\r
+  @param  ControllerHandle The handle of the controller to set options on.\r
+  @param  ChildHandle The handle of the child controller to set options on.\r
+  This is an optional parameter that may be NULL.\r
+  It will be NULL for device drivers, and for a bus drivers\r
+  that wish to set options for the bus controller.\r
+  It will not be NULL for a bus driver that wishes to set\r
+  options for one of its child controllers.\r
+  @param  Language A pointer to a three character ISO 639-2 language\r
+  identifier. This is the language of the user interface\r
+  that should be presented to the user, and it must match\r
+  one of the languages specified in SupportedLanguages.\r
+  The number of languages supported by a driver is up to\r
+  the driver writer.\r
+  @param  ActionRequired A pointer to the action that the calling agent is\r
+  required to perform when this function returns.\r
+  See "Related Definitions" for a list of the actions that\r
+  the calling agent is required to perform prior to\r
+  accessing ControllerHandle again.\r
+\r
+  @retval  EFI_SUCCESS The driver specified by This successfully set the\r
+  configuration options for the controller specified\r
+  by ControllerHandle..\r
+  @retval  EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+  @retval  EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a\r
+  valid EFI_HANDLE.\r
+  @retval  EFI_INVALID_PARAMETER ActionRequired is NULL.\r
+  @retval  EFI_UNSUPPORTED The driver specified by This does not support\r
+  setting configuration options for the controller\r
+  specified by ControllerHandle and ChildHandle.\r
+  @retval  EFI_UNSUPPORTED The driver specified by This does not support the\r
+  language specified by Language.\r
+  @retval  EFI_DEVICE_ERROR A device error occurred while attempt to set the\r
+  configuration options for the controller specified\r
+  by ControllerHandle and ChildHandle.\r
+  @retval  EFI_OUT_RESOURCES There are not enough resources available to set the\r
+  configuration options for the controller specified\r
+  by ControllerHandle and ChildHandle.\r
+\r
+**/\r
+EFI_STATUS\r
+IDEBusDriverConfigurationSetOptions (\r
+  IN  EFI_DRIVER_CONFIGURATION_PROTOCOL                      *This,\r
+  IN  EFI_HANDLE                                             ControllerHandle,\r
+  IN  EFI_HANDLE                                             ChildHandle  OPTIONAL,\r
+  IN  CHAR8                                                  *Language,\r
+  OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED               *ActionRequired\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       Value;\r
+  UINT8       NewValue;\r
+  UINTN       DataSize;\r
+  UINTN       Index;\r
+\r
+  if (ChildHandle != NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  *ActionRequired = EfiDriverConfigurationActionNone;\r
+\r
+  DataSize        = sizeof (Value);\r
+  Status = gRT->GetVariable (\r
+                  L"Configuration",\r
+                  &gEfiCallerIdGuid,\r
+                  NULL,\r
+                  &DataSize,\r
+                  &Value\r
+                  );\r
+\r
+  gST->ConOut->OutputString (gST->ConOut, L"IDE Bus Driver Configuration\n");\r
+  gST->ConOut->OutputString (gST->ConOut, L"===============================\n");\r
+\r
+  NewValue = 0;\r
+  for (Index = 0; Index < 4; Index++) {\r
+    gST->ConOut->OutputString (gST->ConOut, OptionString[Index]);\r
+\r
+    Status = GetResponse ();\r
+    if (Status == EFI_ABORTED) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      NewValue = (UINT8) (NewValue | (1 << Index));\r
+    }\r
+  }\r
+\r
+  if (EFI_ERROR (Status) || (NewValue != Value)) {\r
+    gRT->SetVariable (\r
+          L"Configuration",\r
+          &gEfiCallerIdGuid,\r
+          EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+          sizeof (NewValue),\r
+          &NewValue\r
+          );\r
+\r
+    *ActionRequired = EfiDriverConfigurationActionRestartController;\r
+  } else {\r
+    *ActionRequired = EfiDriverConfigurationActionNone;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Tests to see if a controller's current configuration options are valid.\r
+\r
+  @param  This A pointer to the EFI_DRIVER_CONFIGURATION_PROTOCOL\r
+  instance.\r
+  @param  ControllerHandle The handle of the controller to test if it's current\r
+  configuration options are valid.\r
+  @param  ChildHandle The handle of the child controller to test if it's\r
+  current\r
+  configuration options are valid.  This is an optional\r
+  parameter that may be NULL.  It will be NULL for device\r
+  drivers.  It will also be NULL for a bus drivers that\r
+  wish to test the configuration options for the bus\r
+  controller. It will not be NULL for a bus driver that\r
+  wishes to test configuration options for one of\r
+  its child controllers.\r
+\r
+  @retval  EFI_SUCCESS The controller specified by ControllerHandle and\r
+  ChildHandle that is being managed by the driver\r
+  specified by This has a valid set of  configuration\r
+  options.\r
+  @retval  EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+  @retval  EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+  EFI_HANDLE.\r
+  @retval  EFI_UNSUPPORTED The driver specified by This is not currently\r
+  managing the controller specified by\r
+  ControllerHandle and ChildHandle.\r
+  @retval  EFI_DEVICE_ERROR The controller specified by ControllerHandle and\r
+  ChildHandle that is being managed by the driver\r
+  specified by This has an invalid set of\r
+  configuration options.\r
+\r
+**/\r
+EFI_STATUS\r
+IDEBusDriverConfigurationOptionsValid (\r
+  IN  EFI_DRIVER_CONFIGURATION_PROTOCOL               *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       Value;\r
+  UINTN       DataSize;\r
+\r
+  if (ChildHandle != NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  DataSize = sizeof (Value);\r
+  Status = gRT->GetVariable (\r
+                  L"Configuration",\r
+                  &gEfiCallerIdGuid,\r
+                  NULL,\r
+                  &DataSize,\r
+                  &Value\r
+                  );\r
+  if (EFI_ERROR (Status) || Value > 0x0f) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Forces a driver to set the default configuration options for a controller.\r
+\r
+  @param  This A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL\r
+  instance.\r
+  @param  ControllerHandle The handle of the controller to force default\r
+  configuration options on.\r
+  @param  ChildHandle The handle of the child controller to force default\r
+  configuration options on  This is an optional parameter\r
+  that may be NULL.  It will be NULL for device drivers.\r
+  It will also be NULL for a bus drivers that wish to\r
+  force default configuration options for the bus\r
+  controller.  It will not be NULL for a bus driver that\r
+  wishes to force default configuration options for one\r
+  of its child controllers.\r
+  @param  DefaultType The type of default configuration options to force on\r
+  the controller specified by ControllerHandle and\r
+  ChildHandle.  See Table 9-1 for legal values.\r
+  A DefaultType of 0x00000000 must be supported\r
+  by this protocol.\r
+  @param  ActionRequired A pointer to the action that the calling agent\r
+  is required to perform when this function returns.\r
+\r
+  @retval  EFI_SUCCESS The driver specified by This successfully forced\r
+  the default configuration options on the\r
+  controller specified by ControllerHandle and\r
+  ChildHandle.\r
+  @retval  EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+  @retval  EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a\r
+  valid EFI_HANDLE.\r
+  @retval  EFI_INVALID_PARAMETER ActionRequired is NULL.\r
+  @retval  EFI_UNSUPPORTED The driver specified by This does not support\r
+  forcing the default configuration options on\r
+  the controller specified by ControllerHandle\r
+  and ChildHandle.\r
+  @retval  EFI_UNSUPPORTED The driver specified by This does not support\r
+  the configuration type specified by DefaultType.\r
+  @retval  EFI_DEVICE_ERROR A device error occurred while attempt to force\r
+  the default configuration options on the controller\r
+  specified by  ControllerHandle and ChildHandle.\r
+  @retval  EFI_OUT_RESOURCES There are not enough resources available to force\r
+  the default configuration options on the controller\r
+  specified by ControllerHandle and ChildHandle.\r
+\r
+**/\r
+EFI_STATUS\r
+IDEBusDriverConfigurationForceDefaults (\r
+  IN  EFI_DRIVER_CONFIGURATION_PROTOCOL                      *This,\r
+  IN  EFI_HANDLE                                             ControllerHandle,\r
+  IN  EFI_HANDLE                                             ChildHandle  OPTIONAL,\r
+  IN  UINT32                                                 DefaultType,\r
+  OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED               *ActionRequired\r
+  )\r
+{\r
+  UINT8 Value;\r
+\r
+  if (ChildHandle != NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Value = 0x0f;\r
+  gRT->SetVariable (\r
+        L"Configuration",\r
+        &gEfiCallerIdGuid,\r
+        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+        sizeof (Value),\r
+        &Value\r
+        );\r
+  *ActionRequired = EfiDriverConfigurationActionRestartController;\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c b/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c
new file mode 100644 (file)
index 0000000..8aa6d05
--- /dev/null
@@ -0,0 +1,200 @@
+/** @file\r
+  Copyright (c) 2006, Intel Corporation                                                         \r
+  All rights reserved. This program and the accompanying materials                          \r
+  are licensed and made available under the terms and conditions of the BSD License         \r
+  which accompanies this distribution.  The full text of the license may be found at        \r
+  http://opensource.org/licenses/bsd-license.php                                            \r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+**/\r
+\r
+\r
+#include "idebus.h"\r
+\r
+#define IDE_BUS_DIAGNOSTIC_ERROR  L"PCI IDE/ATAPI Driver Diagnostics Failed"\r
+\r
+//\r
+// EFI Driver Diagnostics Protocol\r
+//\r
+EFI_DRIVER_DIAGNOSTICS_PROTOCOL gIDEBusDriverDiagnostics = {\r
+  IDEBusDriverDiagnosticsRunDiagnostics,\r
+  "eng"\r
+};\r
+\r
+/**\r
+  Runs diagnostics on a controller.\r
+\r
+  @param  This A pointer to the EFI_DRIVER_DIAGNOSTICS_PROTOCOL\r
+  instance.\r
+  @param  ControllerHandle The handle of the controller to run diagnostics on.\r
+  @param  ChildHandle The handle of the child controller to run diagnostics on\r
+  This is an optional parameter that may be NULL.  It will\r
+  be NULL for device drivers.  It will also be NULL for a\r
+  bus drivers that wish to run diagnostics on the bus\r
+  controller.  It will not be NULL for a bus driver that\r
+  wishes to run diagnostics on one of its child\r
+  controllers.\r
+  @param  DiagnosticType Indicates type of diagnostics to perform on the\r
+  controller specified by ControllerHandle and ChildHandle.\r
+  See "Related Definitions" for the list of supported\r
+  types.\r
+  @param  Language A pointer to a three character ISO 639-2 language\r
+  identifier.  This is the language in which the optional\r
+  error message should be returned in Buffer, and it must\r
+  match one of the languages specified in\r
+  SupportedLanguages. The number of languages supported by\r
+  a driver is up to the driver writer.\r
+  @param  ErrorType A GUID that defines the format of the data returned in\r
+  Buffer.\r
+  @param  BufferSize The size, in bytes, of the data returned in Buffer.\r
+  @param  Buffer A buffer that contains a Null-terminated Unicode string\r
+  plus some additional data whose format is defined by\r
+  ErrorType.  Buffer is allocated by this function with\r
+  AllocatePool(), and it is the caller's responsibility\r
+  to free it with a call to FreePool().\r
+\r
+  @retval  EFI_SUCCESS The controller specified by ControllerHandle and\r
+  ChildHandle passed the diagnostic.\r
+  @retval  EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+  @retval  EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+  EFI_HANDLE.\r
+  @retval  EFI_INVALID_PARAMETER Language is NULL.\r
+  @retval  EFI_INVALID_PARAMETER ErrorType is NULL.\r
+  @retval  EFI_INVALID_PARAMETER BufferType is NULL.\r
+  @retval  EFI_INVALID_PARAMETER Buffer is NULL.\r
+  @retval  EFI_UNSUPPORTED The driver specified by This does not support\r
+  running diagnostics for the controller specified\r
+  by ControllerHandle and ChildHandle.\r
+  @retval  EFI_UNSUPPORTED The driver specified by This does not support the\r
+  type of diagnostic specified by DiagnosticType.\r
+  @retval  EFI_UNSUPPORTED The driver specified by This does not support the\r
+  language specified by Language.\r
+  @retval  EFI_OUT_OF_RESOURCES There are not enough resources available to complete\r
+  the diagnostics.\r
+  @retval  EFI_OUT_OF_RESOURCES There are not enough resources available to return\r
+  the status information in ErrorType, BufferSize,\r
+  and Buffer.\r
+  @retval  EFI_DEVICE_ERROR The controller specified by ControllerHandle and\r
+  ChildHandle did not pass the diagnostic.\r
+\r
+**/\r
+EFI_STATUS\r
+IDEBusDriverDiagnosticsRunDiagnostics (\r
+  IN  EFI_DRIVER_DIAGNOSTICS_PROTOCOL               *This,\r
+  IN  EFI_HANDLE                                    ControllerHandle,\r
+  IN  EFI_HANDLE                                    ChildHandle  OPTIONAL,\r
+  IN  EFI_DRIVER_DIAGNOSTIC_TYPE                    DiagnosticType,\r
+  IN  CHAR8                                         *Language,\r
+  OUT EFI_GUID                                      **ErrorType,\r
+  OUT UINTN                                         *BufferSize,\r
+  OUT CHAR16                                        **Buffer\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PCI_IO_PROTOCOL   *PciIo;\r
+  EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
+  IDE_BLK_IO_DEV        *IdeBlkIoDevice;\r
+  UINT32                VendorDeviceId;\r
+  VOID                  *BlockBuffer;\r
+\r
+  *ErrorType  = NULL;\r
+  *BufferSize = 0;\r
+\r
+  if (ChildHandle == NULL) {\r
+    Status = gBS->OpenProtocol (\r
+                    ControllerHandle,\r
+                    &gEfiCallerIdGuid,\r
+                    NULL,\r
+                    gIDEBusDriverBinding.DriverBindingHandle,\r
+                    ControllerHandle,\r
+                    EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    Status = gBS->OpenProtocol (\r
+                    ControllerHandle,\r
+                    &gEfiPciIoProtocolGuid,\r
+                    (VOID **) &PciIo,\r
+                    gIDEBusDriverBinding.DriverBindingHandle,\r
+                    ControllerHandle,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    //\r
+    // Use services of PCI I/O Protocol to test the PCI IDE/ATAPI Controller\r
+    // The following test simply reads the Device ID and Vendor ID.\r
+    // It should never fail.  A real test would perform more advanced\r
+    // diagnostics.\r
+    //\r
+\r
+    Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, 1, &VendorDeviceId);\r
+    if (EFI_ERROR (Status) || VendorDeviceId == 0xffffffff) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  ChildHandle,\r
+                  &gEfiBlockIoProtocolGuid,\r
+                  (VOID **) &BlkIo,\r
+                  gIDEBusDriverBinding.DriverBindingHandle,\r
+                  ChildHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlkIo);\r
+\r
+  //\r
+  // Use services available from IdeBlkIoDevice to test the IDE/ATAPI device\r
+  //\r
+  Status = gBS->AllocatePool (\r
+                  EfiBootServicesData,\r
+                  IdeBlkIoDevice->BlkMedia.BlockSize,\r
+                  (VOID **) &BlockBuffer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = IdeBlkIoDevice->BlkIo.ReadBlocks (\r
+                                  &IdeBlkIoDevice->BlkIo,\r
+                                  IdeBlkIoDevice->BlkMedia.MediaId,\r
+                                  0,\r
+                                  IdeBlkIoDevice->BlkMedia.BlockSize,\r
+                                  BlockBuffer\r
+                                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    *ErrorType  = &gEfiCallerIdGuid;\r
+    *BufferSize = sizeof (IDE_BUS_DIAGNOSTIC_ERROR);\r
+\r
+    Status = gBS->AllocatePool (\r
+                    EfiBootServicesData,\r
+                    (UINTN) (*BufferSize),\r
+                    (VOID **) Buffer\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    CopyMem (*Buffer, IDE_BUS_DIAGNOSTIC_ERROR, *BufferSize);\r
+\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  gBS->FreePool (BlockBuffer);\r
+\r
+  return Status;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c b/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c
new file mode 100644 (file)
index 0000000..3c94c87
--- /dev/null
@@ -0,0 +1,2624 @@
+/** @file\r
+  Copyright (c) 2006 - 2007 Intel Corporation. <BR>\r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+  @par Revision Reference:\r
+  2002-6: Add Atapi6 enhancement, support >120GB hard disk, including\r
+  update - ATAIdentity() func\r
+  update - AtaBlockIoReadBlocks() func\r
+  update - AtaBlockIoWriteBlocks() func\r
+  add    - AtaAtapi6Identify() func\r
+  add    - AtaReadSectorsExt() func\r
+  add    - AtaWriteSectorsExt() func\r
+  add    - AtaPioDataInExt() func\r
+  add    - AtaPioDataOutExt() func\r
+\r
+**/\r
+\r
+#include "idebus.h"\r
+\r
+/**\r
+  Sends out an ATA Identify Command to the specified device.\r
+\r
+  This function is called by DiscoverIdeDevice() during its device\r
+  identification. It sends out the ATA Identify Command to the\r
+  specified device. Only ATA device responses to this command. If\r
+  the command succeeds, it returns the Identify data structure which\r
+  contains information about the device. This function extracts the\r
+  information it needs to fill the IDE_BLK_IO_DEV data structure,\r
+  including device type, media block size, media capacity, and etc.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure,used\r
+  to record all the information of the IDE device.\r
+\r
+  @retval EFI_SUCCESS Identify ATA device successfully.\r
+\r
+  @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or\r
+  device is not ATA device.\r
+\r
+  @note\r
+  parameter IdeDev will be updated in this function.\r
+\r
+**/\r
+EFI_STATUS\r
+ATAIdentify (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  EFI_IDENTIFY_DATA *AtaIdentifyPointer;\r
+  UINT32            Capacity;\r
+  UINT8             DeviceSelect;\r
+\r
+  //\r
+  //  AtaIdentifyPointer is used for accommodating returned IDENTIFY data of\r
+  //  the ATA Identify command\r
+  //\r
+  AtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));\r
+\r
+  //\r
+  //  use ATA PIO Data In protocol to send ATA Identify command\r
+  //  and receive data from device\r
+  //\r
+  DeviceSelect  = (UINT8) ((IdeDev->Device) << 4);\r
+  Status = AtaPioDataIn (\r
+            IdeDev,\r
+            (VOID *) AtaIdentifyPointer,\r
+            sizeof (EFI_IDENTIFY_DATA),\r
+            IDENTIFY_DRIVE_CMD,\r
+            DeviceSelect,\r
+            0,\r
+            0,\r
+            0,\r
+            0\r
+            );\r
+  //\r
+  // If ATA Identify command succeeds, then according to the received\r
+  // IDENTIFY data,\r
+  // identify the device type ( ATA or not ).\r
+  // If ATA device, fill the information in IdeDev.\r
+  // If not ATA device, return IDE_DEVICE_ERROR\r
+  //\r
+  if (!EFI_ERROR (Status)) {\r
+\r
+    IdeDev->pIdData = AtaIdentifyPointer;\r
+\r
+    //\r
+    // Print ATA Module Name\r
+    //\r
+    PrintAtaModuleName (IdeDev);\r
+\r
+    //\r
+    // bit 15 of pAtaIdentify->config is used to identify whether device is\r
+    // ATA device or ATAPI device.\r
+    // if 0, means ATA device; if 1, means ATAPI device.\r
+    //\r
+    if ((AtaIdentifyPointer->AtaData.config & 0x8000) == 0x00) {\r
+      //\r
+      // Detect if support S.M.A.R.T. If yes, enable it as default\r
+      //\r
+      AtaSMARTSupport (IdeDev);\r
+\r
+      //\r
+      // Check whether this device needs 48-bit addressing (ATAPI-6 ata device)\r
+      //\r
+      Status = AtaAtapi6Identify (IdeDev);\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // It's a disk with >120GB capacity, initialized in AtaAtapi6Identify()\r
+        //\r
+        return EFI_SUCCESS;\r
+      }\r
+      //\r
+      // This is a hard disk <= 120GB capacity, treat it as normal hard disk\r
+      //\r
+      IdeDev->Type = IdeHardDisk;\r
+\r
+      //\r
+      // Block Media Information:\r
+      // Media->LogicalPartition , Media->WriteCaching will be filled\r
+      // in the DiscoverIdeDevcie() function.\r
+      //\r
+      IdeDev->BlkIo.Media->IoAlign        = 4;\r
+      IdeDev->BlkIo.Media->MediaId        = 1;\r
+      IdeDev->BlkIo.Media->RemovableMedia = FALSE;\r
+      IdeDev->BlkIo.Media->MediaPresent   = TRUE;\r
+      IdeDev->BlkIo.Media->ReadOnly       = FALSE;\r
+      IdeDev->BlkIo.Media->BlockSize      = 0x200;\r
+\r
+      //\r
+      // Calculate device capacity\r
+      //\r
+      Capacity = ((UINT32)AtaIdentifyPointer->AtaData.user_addressable_sectors_hi << 16) |\r
+                  AtaIdentifyPointer->AtaData.user_addressable_sectors_lo ;\r
+      IdeDev->BlkIo.Media->LastBlock = Capacity - 1;\r
+\r
+      return EFI_SUCCESS;\r
+\r
+    }\r
+  }\r
+\r
+  gBS->FreePool (AtaIdentifyPointer);\r
+  //\r
+  // Make sure the pIdData will not be freed again.\r
+  //\r
+  IdeDev->pIdData = NULL;\r
+\r
+  return EFI_DEVICE_ERROR;\r
+}\r
+\r
+\r
+/**\r
+  This function is called by ATAIdentify() to identity whether this disk\r
+  supports ATA/ATAPI6 48bit addressing, ie support >120G capacity\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @retval  EFI_SUCCESS The disk specified by IdeDev is a Atapi6 supported one\r
+  and 48-bit addressing must be used\r
+\r
+  @retval  EFI_UNSUPPORTED The disk dosn't not support Atapi6 or it supports but\r
+  the capacity is below 120G, 48bit addressing is not\r
+  needed\r
+\r
+  @note\r
+  This function must be called after DEVICE_IDENTITY command has been\r
+  successfully returned\r
+\r
+**/\r
+EFI_STATUS\r
+AtaAtapi6Identify (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+{\r
+  UINT8             Index;\r
+  EFI_LBA           TmpLba;\r
+  EFI_LBA           Capacity;\r
+  EFI_IDENTIFY_DATA *Atapi6IdentifyStruct;\r
+\r
+  if (IdeDev->pIdData == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Atapi6IdentifyStruct = IdeDev->pIdData;\r
+\r
+  if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & bit10) == 0) {\r
+    //\r
+    // The device dosn't support 48 bit addressing\r
+    //\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // 48 bit address feature set is supported, get maximum capacity\r
+  //\r
+  Capacity = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[0];\r
+  for (Index = 1; Index < 4; Index++) {\r
+    //\r
+    // Lower byte goes first: word[100] is the lowest word, word[103] is highest\r
+    //\r
+    TmpLba = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[Index];\r
+    Capacity |= LShiftU64 (TmpLba, 16 * Index);\r
+  }\r
+\r
+  if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {\r
+    //\r
+    // Capacity exceeds 120GB. 48-bit addressing is really needed\r
+    //\r
+    IdeDev->Type = Ide48bitAddressingHardDisk;\r
+\r
+    //\r
+    // Fill block media information:Media->LogicalPartition ,\r
+    // Media->WriteCaching will be filledin the DiscoverIdeDevcie() function.\r
+    //\r
+    IdeDev->BlkIo.Media->IoAlign        = 4;\r
+    IdeDev->BlkIo.Media->MediaId        = 1;\r
+    IdeDev->BlkIo.Media->RemovableMedia = FALSE;\r
+    IdeDev->BlkIo.Media->MediaPresent   = TRUE;\r
+    IdeDev->BlkIo.Media->ReadOnly       = FALSE;\r
+    IdeDev->BlkIo.Media->BlockSize      = 0x200;\r
+    IdeDev->BlkIo.Media->LastBlock      = Capacity - 1;\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  This function is called by ATAIdentify() or ATAPIIdentify()\r
+  to print device's module name.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+**/\r
+VOID\r
+PrintAtaModuleName (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+{\r
+  if (IdeDev->pIdData == NULL) {\r
+    return ;\r
+  }\r
+\r
+  SwapStringChars (IdeDev->ModelName, IdeDev->pIdData->AtaData.ModelName, 40);\r
+  IdeDev->ModelName[40] = 0x00;\r
+}\r
+\r
+/**\r
+  This function is used to send out ATA commands conforms to the\r
+  PIO Data In Protocol.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *Buffer\r
+  buffer contained data transferred from device to host.\r
+\r
+  @param[in] ByteCount\r
+  data size in byte unit of the buffer.\r
+\r
+  @param[in] AtaCommand\r
+  value of the Command Register\r
+\r
+  @param[in] Head\r
+  value of the Head/Device Register\r
+\r
+  @param[in] SectorCount\r
+  value of the Sector Count Register\r
+\r
+  @param[in] SectorNumber\r
+  value of the Sector Number Register\r
+\r
+  @param[in] CylinderLsb\r
+  value of the low byte of the Cylinder Register\r
+\r
+  @param[in] CylinderMsb\r
+  value of the high byte of the Cylinder Register\r
+\r
+  @retval EFI_SUCCESS send out the ATA command and device send required\r
+  data successfully.\r
+\r
+  @retval EFI_DEVICE_ERROR command sent failed.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPioDataIn (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *Buffer,\r
+  IN  UINT32          ByteCount,\r
+  IN  UINT8           AtaCommand,\r
+  IN  UINT8           Head,\r
+  IN  UINT8           SectorCount,\r
+  IN  UINT8           SectorNumber,\r
+  IN  UINT8           CylinderLsb,\r
+  IN  UINT8           CylinderMsb\r
+  )\r
+{\r
+  UINTN       WordCount;\r
+  UINTN       Increment;\r
+  UINT16      *Buffer16;\r
+  EFI_STATUS  Status;\r
+\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  //  e0:1110,0000-- bit7 and bit5 are reserved bits.\r
+  //           bit6 set means LBA mode\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head)\r
+    );\r
+\r
+  //\r
+  // All ATAPI device's ATA commands can be issued regardless of the\r
+  // state of the DRDY\r
+  //\r
+  if (IdeDev->Type == IdeHardDisk) {\r
+\r
+    Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+  //\r
+  // set all the command parameters\r
+  // Before write to all the following registers, BSY and DRQ must be 0.\r
+  //\r
+  Status = DRQClear2 (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (AtaCommand == SET_FEATURES_CMD) {\r
+    IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r
+  }\r
+\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb);\r
+\r
+  //\r
+  // send command via Command Register\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+  Buffer16 = (UINT16 *) Buffer;\r
+\r
+  //\r
+  // According to PIO data in protocol, host can perform a series of reads to\r
+  // the data register after each time device set DRQ ready;\r
+  // The data size of "a series of read" is command specific.\r
+  // For most ATA command, data size received from device will not exceed\r
+  // 1 sector, hence the data size for "a series of read" can be the whole data\r
+  // size of one command request.\r
+  // For ATA command such as Read Sector command, the data size of one ATA\r
+  // command request is often larger than 1 sector, according to the\r
+  // Read Sector command, the data size of "a series of read" is exactly 1\r
+  // sector.\r
+  // Here for simplification reason, we specify the data size for\r
+  // "a series of read" to 1 sector (256 words) if data size of one ATA command\r
+  // request is larger than 256 words.\r
+  //\r
+  Increment = 256;\r
+\r
+  //\r
+  // used to record bytes of currently transfered data\r
+  //\r
+  WordCount = 0;\r
+\r
+  while (WordCount < ByteCount / 2) {\r
+    //\r
+    // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
+    //\r
+    Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    Status = CheckErrorStatus (IdeDev);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    //\r
+    // Get the byte count for one series of read\r
+    //\r
+    if ((WordCount + Increment) > ByteCount / 2) {\r
+      Increment = ByteCount / 2 - WordCount;\r
+    }\r
+\r
+    IDEReadPortWMultiple (\r
+      IdeDev->PciIo,\r
+      IdeDev->IoPort->Data,\r
+      Increment,\r
+      Buffer16\r
+      );\r
+\r
+    WordCount += Increment;\r
+    Buffer16 += Increment;\r
+\r
+  }\r
+\r
+  DRQClear (IdeDev, ATATIMEOUT);\r
+\r
+  return CheckErrorStatus (IdeDev);\r
+}\r
+\r
+/**\r
+  This function is used to send out ATA commands conforms to the\r
+  PIO Data Out Protocol.\r
+\r
+  @param *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param *Buffer      buffer contained data transferred from host to device.\r
+  @param ByteCount    data size in byte unit of the buffer.\r
+  @param AtaCommand   value of the Command Register\r
+  @param Head         value of the Head/Device Register\r
+  @param SectorCount  value of the Sector Count Register\r
+  @param SectorNumber value of the Sector Number Register\r
+  @param CylinderLsb  value of the low byte of the Cylinder Register\r
+  @param CylinderMsb  value of the high byte of the Cylinder Register\r
+\r
+  @retval EFI_SUCCESS send out the ATA command and device received required\r
+  data successfully.\r
+\r
+  @retval EFI_DEVICE_ERROR command sent failed.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPioDataOut (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *Buffer,\r
+  IN  UINT32          ByteCount,\r
+  IN  UINT8           AtaCommand,\r
+  IN  UINT8           Head,\r
+  IN  UINT8           SectorCount,\r
+  IN  UINT8           SectorNumber,\r
+  IN  UINT8           CylinderLsb,\r
+  IN  UINT8           CylinderMsb\r
+  )\r
+{\r
+  UINTN       WordCount;\r
+  UINTN       Increment;\r
+  UINT16      *Buffer16;\r
+  EFI_STATUS  Status;\r
+\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // select device via Head/Device register.\r
+  // Before write Head/Device register, BSY and DRQ must be 0.\r
+  //\r
+  Status = DRQClear2 (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // e0:1110,0000-- bit7 and bit5 are reserved bits.\r
+  //          bit6 set means LBA mode\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head)\r
+    );\r
+\r
+  Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // set all the command parameters\r
+  // Before write to all the following registers, BSY and DRQ must be 0.\r
+  //\r
+  Status = DRQClear2 (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb);\r
+\r
+  //\r
+  // send command via Command Register\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+  Buffer16 = (UINT16 *) Buffer;\r
+\r
+  //\r
+  // According to PIO data out protocol, host can perform a series of\r
+  // writes to the data register after each time device set DRQ ready;\r
+  // The data size of "a series of read" is command specific.\r
+  // For most ATA command, data size written to device will not exceed 1 sector,\r
+  // hence the data size for "a series of write" can be the data size of one\r
+  // command request.\r
+  // For ATA command such as Write Sector command, the data size of one\r
+  // ATA command request is often larger than 1 sector, according to the\r
+  // Write Sector command, the data size of "a series of read" is exactly\r
+  // 1 sector.\r
+  // Here for simplification reason, we specify the data size for\r
+  // "a series of write" to 1 sector (256 words) if data size of one ATA command\r
+  // request is larger than 256 words.\r
+  //\r
+  Increment = 256;\r
+  WordCount = 0;\r
+\r
+  while (WordCount < ByteCount / 2) {\r
+\r
+    //\r
+    // DRQReady2-- read Alternate Status Register to determine the DRQ bit\r
+    // data transfer can be performed only when DRQ is ready.\r
+    //\r
+    Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    Status = CheckErrorStatus (IdeDev);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+   //\r
+   // Check the remaining byte count is less than 512 bytes\r
+   //\r
+   if ((WordCount + Increment) > ByteCount / 2) {\r
+      Increment = ByteCount / 2 - WordCount;\r
+    }\r
+    //\r
+    // perform a series of write without check DRQ ready\r
+    //\r
+\r
+    IDEWritePortWMultiple (\r
+      IdeDev->PciIo,\r
+      IdeDev->IoPort->Data,\r
+      Increment,\r
+      Buffer16\r
+      );\r
+    WordCount += Increment;\r
+    Buffer16 += Increment;\r
+\r
+  }\r
+\r
+  DRQClear (IdeDev, ATATIMEOUT);\r
+\r
+  return CheckErrorStatus (IdeDev);\r
+}\r
+\r
+/**\r
+  This function is used to analyze the Status Register and print out\r
+  some debug information and if there is ERR bit set in the Status\r
+  Register, the Error Register's value is also be parsed and print out.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @retval EFI_SUCCESS       No err information in the Status Register.\r
+  @retval EFI_DEVICE_ERROR  Any err information in the Status Register.\r
+\r
+**/\r
+EFI_STATUS\r
+CheckErrorStatus (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+{\r
+  UINT8 StatusRegister;\r
+  UINT8 ErrorRegister;\r
+\r
+  StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+\r
+  DEBUG_CODE_BEGIN ();\r
+\r
+    if (StatusRegister & DWF) {\r
+      DEBUG (\r
+        (EFI_D_BLKIO,\r
+        "CheckErrorStatus()-- %02x : Error : Write Fault\n",\r
+        StatusRegister)\r
+        );\r
+    }\r
+\r
+    if (StatusRegister & CORR) {\r
+      DEBUG (\r
+        (EFI_D_BLKIO,\r
+        "CheckErrorStatus()-- %02x : Error : Corrected Data\n",\r
+        StatusRegister)\r
+        );\r
+    }\r
+\r
+    if (StatusRegister & ERR) {\r
+      ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+\r
+      if (ErrorRegister & BBK_ERR) {\r
+      DEBUG (\r
+        (EFI_D_BLKIO,\r
+        "CheckErrorStatus()-- %02x : Error : Bad Block Detected\n",\r
+        ErrorRegister)\r
+        );\r
+      }\r
+\r
+      if (ErrorRegister & UNC_ERR) {\r
+        DEBUG (\r
+          (EFI_D_BLKIO,\r
+          "CheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",\r
+          ErrorRegister)\r
+          );\r
+      }\r
+\r
+      if (ErrorRegister & MC_ERR) {\r
+        DEBUG (\r
+          (EFI_D_BLKIO,\r
+          "CheckErrorStatus()-- %02x : Error : Media Change\n",\r
+          ErrorRegister)\r
+          );\r
+      }\r
+\r
+      if (ErrorRegister & ABRT_ERR) {\r
+        DEBUG (\r
+          (EFI_D_BLKIO,\r
+          "CheckErrorStatus()-- %02x : Error : Abort\n",\r
+          ErrorRegister)\r
+          );\r
+      }\r
+\r
+      if (ErrorRegister & TK0NF_ERR) {\r
+        DEBUG (\r
+          (EFI_D_BLKIO,\r
+          "CheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",\r
+          ErrorRegister)\r
+          );\r
+      }\r
+\r
+      if (ErrorRegister & AMNF_ERR) {\r
+        DEBUG (\r
+          (EFI_D_BLKIO,\r
+          "CheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",\r
+          ErrorRegister)\r
+          );\r
+      }\r
+    }\r
+\r
+  DEBUG_CODE_END ();\r
+\r
+  if ((StatusRegister & (ERR | DWF | CORR)) == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_DEVICE_ERROR;\r
+\r
+}\r
+\r
+/**\r
+  This function is called by the AtaBlkIoReadBlocks() to perform\r
+  reading from media in block unit.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *DataBuffer\r
+  A pointer to the destination buffer for the data.\r
+\r
+  @param[in] Lba\r
+  The starting logical block address to read from\r
+  on the device media.\r
+\r
+  @param[in] NumberOfBlocks\r
+  The number of transfer data blocks.\r
+\r
+  @return return status is fully dependent on the return status\r
+  of AtaPioDataIn() function.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaReadSectors (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         Lba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       BlocksRemaining;\r
+  UINT32      Lba32;\r
+  UINT8       Lba0;\r
+  UINT8       Lba1;\r
+  UINT8       Lba2;\r
+  UINT8       Lba3;\r
+  UINT8       AtaCommand;\r
+  UINT8       SectorCount8;\r
+  UINT16      SectorCount;\r
+  UINTN       ByteCount;\r
+  VOID        *Buffer;\r
+\r
+  Buffer = DataBuffer;\r
+\r
+  //\r
+  // Using ATA Read Sector(s) command (opcode=0x20) with PIO DATA IN protocol\r
+  //\r
+  AtaCommand      = READ_SECTORS_CMD;\r
+\r
+\r
+  BlocksRemaining = NumberOfBlocks;\r
+\r
+  Lba32           = (UINT32) Lba;\r
+\r
+  Status          = EFI_SUCCESS;\r
+\r
+  while (BlocksRemaining > 0) {\r
+\r
+    //\r
+    // in ATA-3 spec, LBA is in 28 bit width\r
+    //\r
+    Lba0  = (UINT8) Lba32;\r
+    Lba1  = (UINT8) (Lba32 >> 8);\r
+    Lba2  = (UINT8) (Lba32 >> 16);\r
+    //\r
+    // low 4 bit of Lba3 stands for LBA bit24~bit27.\r
+    //\r
+    Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f);\r
+\r
+    if (BlocksRemaining >= 0x100) {\r
+\r
+      //\r
+      //  SectorCount8 is sent to Sector Count register, 0x00 means 256\r
+      //  sectors to be read\r
+      //\r
+      SectorCount8 = 0x00;\r
+      //\r
+      //  SectorCount is used to record the number of sectors to be read\r
+      //\r
+      SectorCount = 256;\r
+    } else {\r
+\r
+      SectorCount8  = (UINT8) BlocksRemaining;\r
+      SectorCount   = (UINT16) BlocksRemaining;\r
+    }\r
+\r
+    //\r
+    // ByteCount is the number of bytes that will be read\r
+    //\r
+    ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
+\r
+    //\r
+    // call AtaPioDataIn() to send Read Sector Command and receive data read\r
+    //\r
+    Status = AtaPioDataIn (\r
+              IdeDev,\r
+              Buffer,\r
+              (UINT32) ByteCount,\r
+              AtaCommand,\r
+              Lba3,\r
+              SectorCount8,\r
+              Lba0,\r
+              Lba1,\r
+              Lba2\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Lba32 += SectorCount;\r
+    Buffer = ((UINT8 *) Buffer + ByteCount);\r
+    BlocksRemaining -= SectorCount;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function is called by the AtaBlkIoWriteBlocks() to perform\r
+  writing onto media in block unit.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure,used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *BufferData\r
+  A pointer to the source buffer for the data.\r
+\r
+  @param[in] Lba\r
+  The starting logical block address to write onto\r
+  the device media.\r
+\r
+  @param[in] NumberOfBlocks\r
+  The number of transfer data blocks.\r
+\r
+  @return return status is fully dependent on the return status\r
+  of AtaPioDataOut() function.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaWriteSectors (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *BufferData,\r
+  IN  EFI_LBA         Lba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       BlocksRemaining;\r
+  UINT32      Lba32;\r
+  UINT8       Lba0;\r
+  UINT8       Lba1;\r
+  UINT8       Lba2;\r
+  UINT8       Lba3;\r
+  UINT8       AtaCommand;\r
+  UINT8       SectorCount8;\r
+  UINT16      SectorCount;\r
+  UINTN       ByteCount;\r
+  VOID        *Buffer;\r
+\r
+  Buffer = BufferData;\r
+\r
+  //\r
+  // Using Write Sector(s) command (opcode=0x30) with PIO DATA OUT protocol\r
+  //\r
+  AtaCommand      = WRITE_SECTORS_CMD;\r
+\r
+  BlocksRemaining = NumberOfBlocks;\r
+\r
+  Lba32           = (UINT32) Lba;\r
+\r
+  Status          = EFI_SUCCESS;\r
+\r
+  while (BlocksRemaining > 0) {\r
+\r
+    Lba0  = (UINT8) Lba32;\r
+    Lba1  = (UINT8) (Lba32 >> 8);\r
+    Lba2  = (UINT8) (Lba32 >> 16);\r
+    Lba3  = (UINT8) ((Lba32 >> 24) & 0x0f);\r
+\r
+    if (BlocksRemaining >= 0x100) {\r
+\r
+      //\r
+      //  SectorCount8 is sent to Sector Count register, 0x00 means 256 sectors\r
+      //  to be written\r
+      //\r
+      SectorCount8 = 0x00;\r
+      //\r
+      //  SectorCount is used to record the number of sectors to be written\r
+      //\r
+      SectorCount = 256;\r
+    } else {\r
+\r
+      SectorCount8  = (UINT8) BlocksRemaining;\r
+      SectorCount   = (UINT16) BlocksRemaining;\r
+    }\r
+\r
+    ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
+\r
+    Status = AtaPioDataOut (\r
+              IdeDev,\r
+              Buffer,\r
+              (UINT32) ByteCount,\r
+              AtaCommand,\r
+              Lba3,\r
+              SectorCount8,\r
+              Lba0,\r
+              Lba1,\r
+              Lba2\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Lba32 += SectorCount;\r
+    Buffer = ((UINT8 *) Buffer + ByteCount);\r
+    BlocksRemaining -= SectorCount;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function is used to implement the Soft Reset on the specified\r
+  device. But, the ATA Soft Reset mechanism is so strong a reset method\r
+  that it will force resetting on both devices connected to the\r
+  same cable.\r
+\r
+  It is called by IdeBlkIoReset(), a interface function of Block\r
+  I/O protocol.\r
+\r
+  This function can also be used by the ATAPI device to perform reset when\r
+  ATAPI Reset command is failed.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @retval EFI_SUCCESS       Soft reset completes successfully.\r
+  @retval EFI_DEVICE_ERROR  Any step during the reset process is failed.\r
+\r
+  @note\r
+  The registers initial values after ATA soft reset are different\r
+  to the ATA device and ATAPI device.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaSoftReset (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+{\r
+\r
+  UINT8 DeviceControl;\r
+\r
+  DeviceControl = 0;\r
+  //\r
+  // set SRST bit to initiate soft reset\r
+  //\r
+  DeviceControl |= SRST;\r
+\r
+  //\r
+  // disable Interrupt\r
+  //\r
+  DeviceControl |= bit1;\r
+\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
+\r
+  //\r
+  // SRST should assert for at least 5 us, we use 10 us for\r
+  // better compatibility\r
+  //\r
+  gBS->Stall (10);\r
+\r
+  //\r
+  // Enable interrupt to support UDMA, and clear SRST bit\r
+  //\r
+  DeviceControl = 0;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
+\r
+  //\r
+  // Wait for at least 2 ms to check BSY status, we use 10 ms\r
+  // for better compatibility\r
+  //\r
+  gBS->Stall(10000);\r
+  //\r
+  // slave device needs at most 31s to clear BSY\r
+  //\r
+  if (WaitForBSYClear (IdeDev, 31000) == EFI_TIMEOUT) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is the ATA implementation for ReadBlocks in the\r
+  Block I/O Protocol interface.\r
+\r
+  @param[in] *IdeBlkIoDevice\r
+  Indicates the calling context.\r
+\r
+  @param[in] MediaId\r
+  The media id that the read request is for.\r
+\r
+  @param[in] LBA\r
+  The starting logical block address to read from\r
+  on the device.\r
+\r
+  @param[in] BufferSize\r
+  The size of the Buffer in bytes. This must be a\r
+  multiple of the intrinsic block size of the device.\r
+\r
+  @param[out] *Buffer\r
+  A pointer to the destination buffer for the data.\r
+  The caller is responsible for either having implicit\r
+  or explicit ownership of the memory that data is read into.\r
+\r
+  @retval EFI_SUCCESS       Read Blocks successfully.\r
+  @retval EFI_DEVICE_ERROR  Read Blocks failed.\r
+  @retval EFI_NO_MEDIA      There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGE  The MediaId is not for the current media.\r
+\r
+  @retval EFI_BAD_BUFFER_SIZE\r
+  The BufferSize parameter is not a multiple of the\r
+  intrinsic block size of the device.\r
+\r
+  @retval EFI_INVALID_PARAMETER\r
+  The read request contains LBAs that are not valid,\r
+  or the data buffer is not valid.\r
+\r
+  @note\r
+  If Read Block error because of device error, this function will call\r
+  AtaSoftReset() function to reset device.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaBlkIoReadBlocks (\r
+  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,\r
+  IN UINT32           MediaId,\r
+  IN EFI_LBA          LBA,\r
+  IN UINTN            BufferSize,\r
+  OUT VOID            *Buffer\r
+  )\r
+{\r
+  EFI_BLOCK_IO_MEDIA  *Media;\r
+  UINTN               BlockSize;\r
+  UINTN               NumberOfBlocks;\r
+  EFI_STATUS          Status;\r
+\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  //  Get the intrinsic block size\r
+  //\r
+  Media           = IdeBlkIoDevice->BlkIo.Media;\r
+  BlockSize       = Media->BlockSize;\r
+\r
+  NumberOfBlocks  = BufferSize / BlockSize;\r
+\r
+  if (MediaId != Media->MediaId) {\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  if (BufferSize % BlockSize != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (!(Media->MediaPresent)) {\r
+    return EFI_NO_MEDIA;\r
+  }\r
+\r
+  if (LBA > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+  if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
+    //\r
+    // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism\r
+    //\r
+    if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+      Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+    } else {\r
+      Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+    }\r
+  } else {\r
+    //\r
+    // For ATA-3 compatible device, use ATA-3 read block mechanism\r
+    //\r
+    if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+      Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+    } else {\r
+      Status = AtaReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+    }\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    AtaSoftReset (IdeBlkIoDevice);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+  This function is the ATA implementation for WriteBlocks in the\r
+  Block I/O Protocol interface.\r
+\r
+  @param[in] *IdeBlkIoDevice\r
+  Indicates the calling context.\r
+\r
+  @param[in] MediaId\r
+  The media id that the write request is for.\r
+\r
+  @param[in] LBA\r
+  The starting logical block address to write onto\r
+  the device.\r
+\r
+  @param[in] BufferSize\r
+  The size of the Buffer in bytes. This must be a\r
+  multiple of the intrinsic block size of the device.\r
+\r
+  @param[out] *Buffer\r
+  A pointer to the source buffer for the data.\r
+  The caller is responsible for either having implicit\r
+  or explicit ownership of the memory that data is\r
+  written from.\r
+\r
+  @retval EFI_SUCCESS       Write Blocks successfully.\r
+  @retval EFI_DEVICE_ERROR  Write Blocks failed.\r
+  @retval EFI_NO_MEDIA      There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGE  The MediaId is not for the current media.\r
+\r
+  @retval EFI_BAD_BUFFER_SIZE\r
+  The BufferSize parameter is not a multiple of the\r
+  intrinsic block size of the device.\r
+\r
+  @retval EFI_INVALID_PARAMETER\r
+  The write request contains LBAs that are not valid,\r
+  or the data buffer is not valid.\r
+\r
+  @note\r
+  If Write Block error because of device error, this function will call\r
+  AtaSoftReset() function to reset device.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaBlkIoWriteBlocks (\r
+  IN  IDE_BLK_IO_DEV   *IdeBlkIoDevice,\r
+  IN  UINT32           MediaId,\r
+  IN  EFI_LBA          LBA,\r
+  IN  UINTN            BufferSize,\r
+  OUT VOID             *Buffer\r
+  )\r
+{\r
+\r
+  EFI_BLOCK_IO_MEDIA  *Media;\r
+  UINTN               BlockSize;\r
+  UINTN               NumberOfBlocks;\r
+  EFI_STATUS          Status;\r
+\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // Get the intrinsic block size\r
+  //\r
+  Media           = IdeBlkIoDevice->BlkIo.Media;\r
+  BlockSize       = Media->BlockSize;\r
+  NumberOfBlocks  = BufferSize / BlockSize;\r
+\r
+  if (MediaId != Media->MediaId) {\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  if (BufferSize % BlockSize != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (LBA > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+  if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
+    //\r
+    // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism\r
+    //\r
+    if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+      Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+    } else {\r
+      Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+    }\r
+  } else {\r
+    //\r
+    // For ATA-3 compatible device, use ATA-3 write block mechanism\r
+    //\r
+    if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+      Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+    } else {\r
+      Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+    }\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    AtaSoftReset (IdeBlkIoDevice);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is called by the AtaBlkIoReadBlocks() to perform\r
+  reading from media in block unit. The function has been enhanced to\r
+  support >120GB access and transfer at most 65536 blocks per command\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *DataBuffer    A pointer to the destination buffer for the data.\r
+  @param[in] StartLba       The starting logical block address to read from\r
+  on the device media.\r
+  @param[in] NumberOfBlocks The number of transfer data blocks.\r
+\r
+  @return return status is fully dependent on the return status\r
+  of AtaPioDataInExt() function.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaReadSectorsExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       BlocksRemaining;\r
+  EFI_LBA     Lba64;\r
+  UINT8       AtaCommand;\r
+  UINT16      SectorCount;\r
+  UINT32      ByteCount;\r
+  VOID        *Buffer;\r
+\r
+  //\r
+  // Using ATA "Read Sectors Ext" command(opcode=0x24) with PIO DATA IN protocol\r
+  //\r
+  AtaCommand      = READ_SECTORS_EXT_CMD;\r
+  Buffer          = DataBuffer;\r
+  BlocksRemaining = NumberOfBlocks;\r
+  Lba64           = StartLba;\r
+  Status          = EFI_SUCCESS;\r
+\r
+  while (BlocksRemaining > 0) {\r
+\r
+    if (BlocksRemaining >= 0x10000) {\r
+      //\r
+      //  SectorCount is used to record the number of sectors to be read\r
+      //  Max 65536 sectors can be transfered at a time.\r
+      //\r
+      SectorCount = 0xffff;\r
+    } else {\r
+      SectorCount = (UINT16) BlocksRemaining;\r
+    }\r
+\r
+    //\r
+    // ByteCount is the number of bytes that will be read\r
+    //\r
+    ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
+\r
+    //\r
+    // call AtaPioDataInExt() to send Read Sector Command and receive data read\r
+    //\r
+    Status = AtaPioDataInExt (\r
+              IdeDev,\r
+              Buffer,\r
+              ByteCount,\r
+              AtaCommand,\r
+              Lba64,\r
+              SectorCount\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Lba64 += SectorCount;\r
+    Buffer = ((UINT8 *) Buffer + ByteCount);\r
+    BlocksRemaining -= SectorCount;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function is called by the AtaBlkIoWriteBlocks() to perform\r
+  writing onto media in block unit. The function has been enhanced to\r
+  support >120GB access and transfer at most 65536 blocks per command\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure,used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *DataBuffer\r
+  A pointer to the source buffer for the data.\r
+\r
+  @param[in] Lba\r
+  The starting logical block address to write onto\r
+  the device media.\r
+\r
+  @param[in] NumberOfBlocks\r
+  The number of transfer data blocks.\r
+\r
+  @return status is fully dependent on the return status\r
+  of AtaPioDataOutExt() function.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaWriteSectorsExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_LBA     Lba64;\r
+  UINTN       BlocksRemaining;\r
+  UINT8       AtaCommand;\r
+  UINT16      SectorCount;\r
+  UINT32      ByteCount;\r
+  VOID        *Buffer;\r
+\r
+  //\r
+  // Using ATA "Write Sectors Ext" cmd(opcode=0x24) with PIO DATA OUT protocol\r
+  //\r
+  AtaCommand      = WRITE_SECTORS_EXT_CMD;\r
+  Lba64           = StartLba;\r
+  Buffer          = DataBuffer;\r
+  BlocksRemaining = NumberOfBlocks;\r
+\r
+  Status          = EFI_SUCCESS;\r
+\r
+  while (BlocksRemaining > 0) {\r
+\r
+    if (BlocksRemaining >= 0x10000) {\r
+      //\r
+      //  SectorCount is used to record the number of sectors to be written.\r
+      //  Max 65536 sectors can be transfered at a time.\r
+      //\r
+      SectorCount = 0xffff;\r
+    } else {\r
+      SectorCount = (UINT16) BlocksRemaining;\r
+    }\r
+\r
+    //\r
+    // ByteCount is the number of bytes that will be written\r
+    //\r
+    ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
+\r
+    //\r
+    // Call AtaPioDataOutExt() to send "Write Sectors Ext" Command\r
+    //\r
+    Status = AtaPioDataOutExt (\r
+              IdeDev,\r
+              Buffer,\r
+              ByteCount,\r
+              AtaCommand,\r
+              Lba64,\r
+              SectorCount\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Lba64 += SectorCount;\r
+    Buffer = ((UINT8 *) Buffer + ByteCount);\r
+    BlocksRemaining -= SectorCount;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function is used to send out ATA commands conforms to the\r
+  PIO Data In Protocol, supporting ATA/ATAPI-6 standard\r
+\r
+  Comparing with ATA-3 data in protocol, we have two differents here:<BR>\r
+  1. Do NOT wait for DRQ clear before sending command into IDE device.(the\r
+  wait will frequently fail... cause writing function return error)\r
+\r
+  2. Do NOT wait for DRQ clear after all data readed.(the wait greatly\r
+  slow down writing performance by 100 times!)\r
+\r
+  @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in,out] *Buffer  buffer contained data transferred from device to host.\r
+  @param[in] ByteCount    data size in byte unit of the buffer.\r
+  @param[in] AtaCommand   value of the Command Register\r
+  @param[in] StartLba     the start LBA of this transaction\r
+  @param[in] SectorCount  the count of sectors to be transfered\r
+\r
+  @retval EFI_SUCCESS send out the ATA command and device send required\r
+  data successfully.\r
+\r
+  @retval EFI_DEVICE_ERROR command sent failed.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPioDataInExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  OUT VOID        *Buffer,\r
+  IN  UINT32          ByteCount,\r
+  IN  UINT8           AtaCommand,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINT16          SectorCount\r
+  )\r
+{\r
+  UINT8       DevSel;\r
+  UINT8       SectorCount8;\r
+  UINT8       LbaLow;\r
+  UINT8       LbaMid;\r
+  UINT8       LbaHigh;\r
+  UINTN       WordCount;\r
+  UINTN       Increment;\r
+  UINT16      *Buffer16;\r
+  EFI_STATUS  Status;\r
+\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Select device, set bit6 as 1 to indicate LBA mode is used\r
+  //\r
+  DevSel = (UINT8) (IdeDev->Device << 4);\r
+  DevSel |= 0x40;\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    DevSel\r
+    );\r
+\r
+  //\r
+  // Wait for DRDY singnal asserting. ATAPI device needn't wait\r
+  //\r
+  if ( (IdeDev->Type == IdeHardDisk)  ||\r
+        (IdeDev->Type == Ide48bitAddressingHardDisk)) {\r
+\r
+    Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Fill feature register if needed\r
+  //\r
+  if (AtaCommand == SET_FEATURES_CMD) {\r
+    IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r
+  }\r
+\r
+  //\r
+  // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+  //\r
+  SectorCount8 = (UINT8) (SectorCount >> 8);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+  SectorCount8 = (UINT8) SectorCount;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+  //\r
+  // Fill the start LBA registers, which are also two-byte FIFO\r
+  //\r
+  LbaLow  = (UINT8) RShiftU64 (StartLba, 24);\r
+  LbaMid  = (UINT8) RShiftU64 (StartLba, 32);\r
+  LbaHigh = (UINT8) RShiftU64 (StartLba, 40);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+  LbaLow  = (UINT8) StartLba;\r
+  LbaMid  = (UINT8) RShiftU64 (StartLba, 8);\r
+  LbaHigh = (UINT8) RShiftU64 (StartLba, 16);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+  //\r
+  // Send command via Command Register, invoking the processing of this command\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+  Buffer16 = (UINT16 *) Buffer;\r
+\r
+  //\r
+  // According to PIO data in protocol, host can perform a series of reads to\r
+  // the data register after each time device set DRQ ready;\r
+  //\r
+\r
+  //\r
+  // 256 words\r
+  //\r
+  Increment = 256;\r
+\r
+  //\r
+  // used to record bytes of currently transfered data\r
+  //\r
+  WordCount = 0;\r
+\r
+  while (WordCount < ByteCount / 2) {\r
+    //\r
+    // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
+    //\r
+    Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    Status = CheckErrorStatus (IdeDev);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    //\r
+    // Get the byte count for one series of read\r
+    //\r
+    if ((WordCount + Increment) > ByteCount / 2) {\r
+      Increment = ByteCount / 2 - WordCount;\r
+    }\r
+\r
+    IDEReadPortWMultiple (\r
+      IdeDev->PciIo,\r
+      IdeDev->IoPort->Data,\r
+      Increment,\r
+      Buffer16\r
+      );\r
+\r
+    WordCount += Increment;\r
+    Buffer16 += Increment;\r
+\r
+  }\r
+\r
+  return CheckErrorStatus (IdeDev);\r
+}\r
+\r
+/**\r
+  This function is used to send out ATA commands conforms to the\r
+  PIO Data Out Protocol, supporting ATA/ATAPI-6 standard\r
+\r
+  Comparing with ATA-3 data out protocol, we have two differents here:<BR>\r
+  1. Do NOT wait for DRQ clear before sending command into IDE device.(the\r
+  wait will frequently fail... cause writing function return error)\r
+\r
+  2. Do NOT wait for DRQ clear after all data readed.(the wait greatly\r
+  slow down writing performance by 100 times!)\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *Buffer      buffer contained data transferred from host to device.\r
+  @param[in] ByteCount    data size in byte unit of the buffer.\r
+  @param[in] AtaCommand   value of the Command Register\r
+  @param[in] StartLba     the start LBA of this transaction\r
+  @param[in] SectorCount  the count of sectors to be transfered\r
+\r
+  @retval EFI_SUCCESS send out the ATA command and device receive required\r
+  data successfully.\r
+\r
+  @retval EFI_DEVICE_ERROR command sent failed.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPioDataOutExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *Buffer,\r
+  IN  UINT32          ByteCount,\r
+  IN  UINT8           AtaCommand,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINT16          SectorCount\r
+  )\r
+{\r
+  UINT8       DevSel;\r
+  UINT8       SectorCount8;\r
+  UINT8       LbaLow;\r
+  UINT8       LbaMid;\r
+  UINT8       LbaHigh;\r
+  UINTN       WordCount;\r
+  UINTN       Increment;\r
+  UINT16      *Buffer16;\r
+  EFI_STATUS  Status;\r
+\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Select device. Set bit6 as 1 to indicate LBA mode is used\r
+  //\r
+  DevSel = (UINT8) (IdeDev->Device << 4);\r
+  DevSel |= 0x40;\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    DevSel\r
+    );\r
+\r
+  //\r
+  // Wait for DRDY singnal asserting.\r
+  //\r
+  Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Fill feature register if needed\r
+  //\r
+  if (AtaCommand == SET_FEATURES_CMD) {\r
+    IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r
+  }\r
+\r
+  //\r
+  // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+  //\r
+  SectorCount8 = (UINT8) (SectorCount >> 8);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+  SectorCount8 = (UINT8) SectorCount;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+  //\r
+  // Fill the start LBA registers, which are also two-byte FIFO\r
+  //\r
+  LbaLow  = (UINT8) RShiftU64 (StartLba, 24);\r
+  LbaMid  = (UINT8) RShiftU64 (StartLba, 32);\r
+  LbaHigh = (UINT8) RShiftU64 (StartLba, 40);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+  LbaLow  = (UINT8) StartLba;\r
+  LbaMid  = (UINT8) RShiftU64 (StartLba, 8);\r
+  LbaHigh = (UINT8) RShiftU64 (StartLba, 16);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+  //\r
+  // Send command via Command Register, invoking the processing of this command\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+  Buffer16 = (UINT16 *) Buffer;\r
+\r
+  //\r
+  // According to PIO Data Out protocol, host can perform a series of writes to\r
+  // the data register after each time device set DRQ ready;\r
+  //\r
+  Increment = 256;\r
+\r
+  //\r
+  // used to record bytes of currently transfered data\r
+  //\r
+  WordCount = 0;\r
+\r
+  while (WordCount < ByteCount / 2) {\r
+    //\r
+    // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
+    //\r
+    Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    Status = CheckErrorStatus (IdeDev);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    //\r
+    // Write data into device by one series of writing to data register\r
+    //\r
+    if ((WordCount + Increment) > ByteCount / 2) {\r
+      Increment = ByteCount / 2 - WordCount;\r
+    }\r
+\r
+    IDEWritePortWMultiple (\r
+      IdeDev->PciIo,\r
+      IdeDev->IoPort->Data,\r
+      Increment,\r
+      Buffer16\r
+      );\r
+\r
+    WordCount += Increment;\r
+    Buffer16 += Increment;\r
+\r
+  }\r
+  //\r
+  // while\r
+  //\r
+\r
+  return CheckErrorStatus (IdeDev);\r
+}\r
+\r
+\r
+/**\r
+  Enable SMART of the disk if supported\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure,used\r
+  to record all the information of the IDE device.\r
+\r
+**/\r
+VOID\r
+AtaSMARTSupport (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  BOOLEAN           SMARTSupported;\r
+  UINT8             Device;\r
+  EFI_IDENTIFY_DATA *TmpAtaIdentifyPointer;\r
+  UINT8             DeviceSelect;\r
+  UINT8             LBAMid;\r
+  UINT8             LBAHigh;\r
+\r
+  //\r
+  // Detect if the device supports S.M.A.R.T.\r
+  //\r
+  if ((IdeDev->pIdData->AtaData.command_set_supported_83 & 0xc000) != 0x4000) {\r
+    //\r
+    // Data in word 82 is not valid (bit15 shall be zero and bit14 shall be to one)\r
+    //\r
+    return ;\r
+  } else {\r
+    if ((IdeDev->pIdData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
+      //\r
+      // S.M.A.R.T is not supported by the device\r
+      //\r
+      SMARTSupported = FALSE;\r
+    } else {\r
+      SMARTSupported = TRUE;\r
+    }\r
+  }\r
+\r
+  if (!SMARTSupported) {\r
+    //\r
+    // Report nonsupport status code\r
+    //\r
+    REPORT_STATUS_CODE (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)\r
+      );\r
+  } else {\r
+    //\r
+    // Enable this feature\r
+    //\r
+    REPORT_STATUS_CODE (\r
+      EFI_PROGRESS_CODE,\r
+      (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)\r
+      );\r
+\r
+    Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
+    Status = AtaNonDataCommandIn (\r
+              IdeDev,\r
+              ATA_SMART_CMD,\r
+              Device,\r
+              ATA_SMART_ENABLE_OPERATION,\r
+              0,\r
+              0,\r
+              ATA_CONSTANT_4F,\r
+              ATA_CONSTANT_C2\r
+              );\r
+    //\r
+    // Detect if this feature is enabled\r
+    //\r
+    TmpAtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));\r
+\r
+    DeviceSelect          = (UINT8) ((IdeDev->Device) << 4);\r
+    Status = AtaPioDataIn (\r
+              IdeDev,\r
+              (VOID *) TmpAtaIdentifyPointer,\r
+              sizeof (EFI_IDENTIFY_DATA),\r
+              IDENTIFY_DRIVE_CMD,\r
+              DeviceSelect,\r
+              0,\r
+              0,\r
+              0,\r
+              0\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      gBS->FreePool (TmpAtaIdentifyPointer);\r
+      return ;\r
+    }\r
+\r
+    //\r
+    // Check if the feature is enabled\r
+    //\r
+    if ((TmpAtaIdentifyPointer->AtaData.command_set_feature_enb_85 & 0x0001) == 0x0001) {\r
+      //\r
+      // Read status data\r
+      //\r
+      AtaNonDataCommandIn (\r
+        IdeDev,\r
+        ATA_SMART_CMD,\r
+        Device,\r
+        ATA_SMART_RETURN_STATUS,\r
+        0,\r
+        0,\r
+        ATA_CONSTANT_4F,\r
+        ATA_CONSTANT_C2\r
+        );\r
+      LBAMid  = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);\r
+      LBAHigh = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb);\r
+\r
+      if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
+        //\r
+        // The threshold exceeded condition is not detected by the device\r
+        //\r
+        REPORT_STATUS_CODE (\r
+              EFI_PROGRESS_CODE,\r
+              (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)\r
+              );\r
+\r
+      } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
+        //\r
+        // The threshold exceeded condition is  detected by the device\r
+        //\r
+        REPORT_STATUS_CODE (\r
+              EFI_PROGRESS_CODE,\r
+              (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)\r
+              );\r
+      }\r
+\r
+    } else {\r
+      //\r
+      // Report disabled status code\r
+      //\r
+      REPORT_STATUS_CODE (\r
+            EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+            (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)\r
+            );\r
+    }\r
+\r
+    gBS->FreePool (TmpAtaIdentifyPointer);\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Send ATA Ext command into device with NON_DATA protocol\r
+\r
+  @param  IdeDev Standard IDE device private data structure\r
+  @param  AtaCommand The ATA command to be sent\r
+  @param  Device The value in Device register\r
+  @param  Feature The value in Feature register\r
+  @param  SectorCount The value in SectorCount register\r
+  @param  LbaAddress The LBA address in 48-bit mode\r
+\r
+  @retval  EFI_SUCCESS Reading succeed\r
+  @retval  EFI_DEVICE_ERROR Error executing commands on this device\r
+\r
+**/\r
+EFI_STATUS\r
+AtaCommandIssueExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINT8           AtaCommand,\r
+  IN  UINT8           Device,\r
+  IN  UINT16          Feature,\r
+  IN  UINT16          SectorCount,\r
+  IN  EFI_LBA         LbaAddress\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       SectorCount8;\r
+  UINT8       Feature8;\r
+  UINT8       LbaLow;\r
+  UINT8       LbaMid;\r
+  UINT8       LbaHigh;\r
+\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+    );\r
+\r
+  //\r
+  // ATA commands for ATA device must be issued when DRDY is set\r
+  //\r
+  Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Pass parameter into device register block\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+\r
+  //\r
+  // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
+  //\r
+  Feature8 = (UINT8) (Feature >> 8);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+\r
+  Feature8 = (UINT8) Feature;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+\r
+  //\r
+  // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+  //\r
+  SectorCount8 = (UINT8) (SectorCount >> 8);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+  SectorCount8 = (UINT8) SectorCount;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+  //\r
+  // Fill the start LBA registers, which are also two-byte FIFO\r
+  //\r
+  LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+  LbaLow = (UINT8) LbaAddress;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+\r
+  LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+  LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+\r
+  LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+  LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+  //\r
+  // Work around for Segate 160G disk writing\r
+  //\r
+  gBS->Stall (1800);\r
+\r
+  //\r
+  // Send command via Command Register\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+  //\r
+  // Stall at least 400ns\r
+  //\r
+  gBS->Stall (100);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Send ATA Ext command into device with NON_DATA protocol\r
+\r
+  @param  IdeDev Standard IDE device private data structure\r
+  @param  AtaCommand The ATA command to be sent\r
+  @param  Device The value in Device register\r
+  @param  Feature The value in Feature register\r
+  @param  SectorCount The value in SectorCount register\r
+  @param  LbaAddress The LBA address in 48-bit mode\r
+\r
+  @retval  EFI_SUCCESS Reading succeed\r
+  @retval  EFI_DEVICE_ERROR Error executing commands on this device\r
+\r
+**/\r
+EFI_STATUS\r
+AtaCommandIssue (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINT8           AtaCommand,\r
+  IN  UINT8           Device,\r
+  IN  UINT16          Feature,\r
+  IN  UINT16          SectorCount,\r
+  IN  EFI_LBA         LbaAddress\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       SectorCount8;\r
+  UINT8       Feature8;\r
+  UINT8       Lba0;\r
+  UINT8       Lba1;\r
+  UINT8       Lba2;\r
+  UINT8       Lba3;\r
+\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+    );\r
+\r
+  //\r
+  // ATA commands for ATA device must be issued when DRDY is set\r
+  //\r
+  Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Lba0  = (UINT8) LbaAddress;\r
+  Lba1  = (UINT8) RShiftU64 (LbaAddress, 8);\r
+  Lba2  = (UINT8) RShiftU64 (LbaAddress, 16);\r
+  Lba3  = (UINT8) RShiftU64 (LbaAddress, 24);\r
+  Device = (UINT8) (Device | Lba3);\r
+\r
+  //\r
+  // Pass parameter into device register block\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+\r
+  //\r
+  // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
+  //\r
+  Feature8 = (UINT8) Feature;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+\r
+  //\r
+  // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+  //\r
+  SectorCount8 = (UINT8) SectorCount;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+  //\r
+  // Fill the start LBA registers, which are also two-byte FIFO\r
+  //\r
+\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, Lba0);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, Lba1);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, Lba2);\r
+\r
+  //\r
+  // Send command via Command Register\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+  //\r
+  // Stall at least 400ns\r
+  //\r
+  gBS->Stall (100);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is called by the AtaBlkIoReadBlocks() to perform\r
+  reading from media in block unit. The function has been enhanced to\r
+  support >120GB access and transfer at most 65536 blocks per command\r
+\r
+  @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *DataBuffer A pointer to the destination buffer for the data.\r
+\r
+  @param[in] StartLba The starting logical block address to read from\r
+  on the device media.\r
+\r
+  @param[in] NumberOfBlocks The number of transfer data blocks.\r
+\r
+  @return The device status of UDMA operation. If the operation is\r
+  successful, return EFI_SUCCESS.\r
+\r
+  TODO:    EFI_UNSUPPORTED - add return value to function comment\r
+  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
+  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
+  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+AtaUdmaReadExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+{\r
+  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadExtOp);\r
+}\r
+\r
+/**\r
+  This function is called by the AtaBlkIoReadBlocks() to perform\r
+  reading from media in block unit. The function has been enhanced to\r
+  support >120GB access and transfer at most 65536 blocks per command\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *DataBuffer    A pointer to the destination buffer for the data.\r
+  @param[in] StartLba       The starting logical block address to read from\r
+  on the device media.\r
+  @param[in] NumberOfBlocks The number of transfer data blocks.\r
+\r
+  @return The device status of UDMA operation. If the operation is\r
+  successful, return EFI_SUCCESS.\r
+\r
+  TODO:    EFI_UNSUPPORTED - add return value to function comment\r
+  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
+  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
+  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+AtaUdmaRead (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+{\r
+  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadOp);\r
+}\r
+\r
+/**\r
+  This function is called by the AtaBlkIoWriteBlocks() to perform\r
+  writing to media in block unit. The function has been enhanced to\r
+  support >120GB access and transfer at most 65536 blocks per command\r
+\r
+  @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *DataBuffer A pointer to the source buffer for the data.\r
+\r
+  @param[in] StartLba The starting logical block address to write to\r
+  on the device media.\r
+\r
+  @param[in] NumberOfBlocks The number of transfer data blocks.\r
+\r
+  @return The device status of UDMA operation. If the operation is\r
+  successful, return EFI_SUCCESS.\r
+\r
+  TODO:    EFI_UNSUPPORTED - add return value to function comment\r
+  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
+  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+AtaUdmaWriteExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+{\r
+  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteExtOp);\r
+}\r
+\r
+/**\r
+  This function is called by the AtaBlkIoWriteBlocks() to perform\r
+  writing to media in block unit. The function has been enhanced to\r
+  support >120GB access and transfer at most 65536 blocks per command\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *DataBuffer\r
+  A pointer to the source buffer for the data.\r
+\r
+  @param[in] StartLba\r
+  The starting logical block address to write to\r
+  on the device media.\r
+\r
+  @param[in] NumberOfBlocks\r
+  The number of transfer data blocks.\r
+\r
+  @return The device status of UDMA operation. If the operation is\r
+  successful, return EFI_SUCCESS.\r
+\r
+  TODO:    EFI_UNSUPPORTED - add return value to function comment\r
+  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
+  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+AtaUdmaWrite (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+{\r
+  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteOp);\r
+}\r
+\r
+/**\r
+  Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *DataBuffer\r
+  A pointer to the source buffer for the data.\r
+\r
+  @param[in] StartLba\r
+  The starting logical block address to write to\r
+  on the device media.\r
+\r
+  @param[in] NumberOfBlocks\r
+  The number of transfer data blocks.\r
+\r
+  @param[in] UdmaOp\r
+  The perform operations could be AtaUdmaReadOp, AtaUdmaReadExOp,\r
+  AtaUdmaWriteOp, AtaUdmaWriteExOp\r
+\r
+  @return The device status of UDMA operation. If the operation is\r
+  successful, return EFI_SUCCESS.\r
+\r
+**/\r
+EFI_STATUS\r
+DoAtaUdma (\r
+  IN  IDE_BLK_IO_DEV      *IdeDev,\r
+  IN  VOID                *DataBuffer,\r
+  IN  EFI_LBA             StartLba,\r
+  IN  UINTN               NumberOfBlocks,\r
+  IN  ATA_UDMA_OPERATION  UdmaOp\r
+  )\r
+{\r
+  IDE_DMA_PRD                   *PrdAddr;\r
+  IDE_DMA_PRD                   *UsedPrdAddr;\r
+  IDE_DMA_PRD                   *TempPrdAddr;\r
+  UINT8                         RegisterValue;\r
+  UINT8                         Device;\r
+  UINT64                        IoPortForBmic;\r
+  UINT64                        IoPortForBmis;\r
+  UINT64                        IoPortForBmid;\r
+  EFI_STATUS                    Status;\r
+  UINTN                         PrdTableNum;\r
+  UINTN                         ByteCount;\r
+  UINTN                         ByteAvailable;\r
+  UINT8                         *PrdBuffer;\r
+  UINTN                         RemainBlockNum;\r
+  UINT8                         DeviceControl;\r
+  UINT32                        Count;\r
+  UINTN                         PageCount;\r
+  VOID                          *Map;\r
+  VOID                          *MemPage;\r
+  EFI_PHYSICAL_ADDRESS          DeviceAddress;\r
+  UINTN                         MaxDmaCommandSectors;\r
+  EFI_PCI_IO_PROTOCOL_OPERATION PciIoProtocolOp;\r
+  UINT8                         AtaCommand;\r
+\r
+  switch (UdmaOp) {\r
+  case AtaUdmaReadOp:\r
+    MaxDmaCommandSectors = MAX_DMA_COMMAND_SECTORS;\r
+    PciIoProtocolOp      = EfiPciIoOperationBusMasterWrite;\r
+    AtaCommand           = READ_DMA_CMD;\r
+    break;\r
+  case AtaUdmaReadExtOp:\r
+    MaxDmaCommandSectors = MAX_DMA_EXT_COMMAND_SECTORS;\r
+    PciIoProtocolOp      = EfiPciIoOperationBusMasterWrite;\r
+    AtaCommand           = READ_DMA_EXT_CMD;\r
+    break;\r
+  case AtaUdmaWriteOp:\r
+    MaxDmaCommandSectors = MAX_DMA_COMMAND_SECTORS;\r
+    PciIoProtocolOp      = EfiPciIoOperationBusMasterRead;\r
+    AtaCommand           = WRITE_DMA_CMD;\r
+    break;\r
+  case AtaUdmaWriteExtOp:\r
+    MaxDmaCommandSectors = MAX_DMA_EXT_COMMAND_SECTORS;\r
+    PciIoProtocolOp      = EfiPciIoOperationBusMasterRead;\r
+    AtaCommand           = WRITE_DMA_EXT_CMD;\r
+    break;\r
+  default:\r
+    return EFI_UNSUPPORTED;\r
+    break;\r
+  }\r
+\r
+  //\r
+  // Channel and device differential\r
+  //\r
+  Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
+\r
+  //\r
+  // Enable interrupt to support UDMA and Select device\r
+  //\r
+  DeviceControl = 0;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
+\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+\r
+  if (IdePrimary == IdeDev->Channel) {\r
+    IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;\r
+    IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
+    IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;\r
+  } else {\r
+    if (IdeSecondary == IdeDev->Channel) {\r
+      IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;\r
+      IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
+      IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;\r
+    } else {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+  }\r
+\r
+  RemainBlockNum = NumberOfBlocks;\r
+  while (RemainBlockNum > 0) {\r
+\r
+    if (RemainBlockNum >= MaxDmaCommandSectors) {\r
+      //\r
+      //  SectorCount is used to record the number of sectors to be read\r
+      //  Max 65536 sectors can be transfered at a time.\r
+      //\r
+      NumberOfBlocks = MaxDmaCommandSectors;\r
+      RemainBlockNum -= MaxDmaCommandSectors;\r
+    } else {\r
+      NumberOfBlocks  = (UINT16) RemainBlockNum;\r
+      RemainBlockNum  = 0;\r
+    }\r
+\r
+    //\r
+    // Calculate the number of PRD table to make sure the memory region\r
+    // not cross 64K boundary\r
+    //\r
+    ByteCount   = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
+    PrdTableNum = ((ByteCount >> 16) + 1) + 1;\r
+\r
+    //\r
+    // Build PRD table\r
+    //\r
+    PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));\r
+    Status = IdeDev->PciIo->AllocateBuffer (\r
+                    IdeDev->PciIo,\r
+                    AllocateAnyPages,\r
+                    EfiBootServicesData,\r
+                    PageCount,\r
+                    &MemPage,\r
+                    0\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));\r
+\r
+    PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);\r
+    //\r
+    // To make sure PRD is allocated in one 64K page\r
+    //\r
+    if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {\r
+      UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);\r
+    } else {\r
+      if ((UINTN) PrdAddr & 0x03) {\r
+        UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);\r
+      } else {\r
+        UsedPrdAddr = PrdAddr;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Build the PRD table\r
+    //\r
+    Status = IdeDev->PciIo->Map (\r
+                       IdeDev->PciIo,\r
+                       PciIoProtocolOp,\r
+                       DataBuffer,\r
+                       &ByteCount,\r
+                       &DeviceAddress,\r
+                       &Map\r
+                       );\r
+    if (EFI_ERROR (Status)) {\r
+      IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    PrdBuffer   = (VOID *) ((UINTN) DeviceAddress);\r
+    TempPrdAddr = UsedPrdAddr;\r
+    while (TRUE) {\r
+\r
+      ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);\r
+\r
+      if (ByteCount <= ByteAvailable) {\r
+        TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
+        TempPrdAddr->ByteCount      = (UINT16) ByteCount;\r
+        TempPrdAddr->EndOfTable     = 0x8000;\r
+        break;\r
+      }\r
+\r
+      TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
+      TempPrdAddr->ByteCount      = (UINT16) ByteAvailable;\r
+\r
+      ByteCount -= ByteAvailable;\r
+      PrdBuffer += ByteAvailable;\r
+      TempPrdAddr++;\r
+    }\r
+\r
+    //\r
+    // Set the base address to BMID register\r
+    //\r
+    IdeDev->PciIo->Io.Write (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint32,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmid,\r
+                        1,\r
+                        &UsedPrdAddr\r
+                        );\r
+\r
+    //\r
+    // Set BMIC register to identify the operation direction\r
+    //\r
+    IdeDev->PciIo->Io.Read (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmic,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
+\r
+    if (UdmaOp == AtaUdmaReadExtOp || UdmaOp == AtaUdmaReadOp) {\r
+      RegisterValue |= BMIC_nREAD;\r
+    } else {\r
+      RegisterValue &= ~((UINT8) BMIC_nREAD);\r
+    }\r
+\r
+    IdeDev->PciIo->Io.Write (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmic,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
+\r
+    //\r
+    // Read BMIS register and clear ERROR and INTR bit\r
+    //\r
+    IdeDev->PciIo->Io.Read (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmis,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
+\r
+    RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+\r
+    IdeDev->PciIo->Io.Write (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmis,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
+\r
+    if (UdmaOp == AtaUdmaWriteExtOp || UdmaOp == AtaUdmaReadExtOp) {\r
+      Status = AtaCommandIssueExt (\r
+                 IdeDev,\r
+                 AtaCommand,\r
+                 Device,\r
+                 0,\r
+                 (UINT16) NumberOfBlocks,\r
+                 StartLba\r
+                 );\r
+    } else {\r
+      Status = AtaCommandIssue (\r
+                 IdeDev,\r
+                 AtaCommand,\r
+                 Device,\r
+                 0,\r
+                 (UINT16) NumberOfBlocks,\r
+                 StartLba\r
+                 );\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
+      IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    //\r
+    // Set START bit of BMIC register\r
+    //\r
+    IdeDev->PciIo->Io.Read (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmic,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
+\r
+    RegisterValue |= BMIC_START;\r
+\r
+    IdeDev->PciIo->Io.Write (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmic,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
+\r
+    //\r
+    // Check the INTERRUPT and ERROR bit of BMIS\r
+    // Max transfer number of sectors for one command is 65536(32Mbyte),\r
+    // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r
+    // So set the variable Count to 2000, for about 2 second timeout time.\r
+    //\r
+    Count = 2000;\r
+    while (TRUE) {\r
+\r
+      IdeDev->PciIo->Io.Read (\r
+                          IdeDev->PciIo,\r
+                          EfiPciIoWidthUint8,\r
+                          EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                          IoPortForBmis,\r
+                          1,\r
+                          &RegisterValue\r
+                          );\r
+      if ((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) || (Count == 0)) {\r
+        if ((RegisterValue & BMIS_ERROR) || (Count == 0)) {\r
+          //\r
+          // Clear START bit of BMIC register before return EFI_DEVICE_ERROR\r
+          //\r
+          IdeDev->PciIo->Io.Read (\r
+                              IdeDev->PciIo,\r
+                              EfiPciIoWidthUint8,\r
+                              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                              IoPortForBmic,\r
+                              1,\r
+                              &RegisterValue\r
+                              );\r
+\r
+          RegisterValue &= ~((UINT8)BMIC_START);\r
+\r
+          IdeDev->PciIo->Io.Write (\r
+                              IdeDev->PciIo,\r
+                              EfiPciIoWidthUint8,\r
+                              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                              IoPortForBmic,\r
+                              1,\r
+                              &RegisterValue\r
+                              );\r
+          IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
+          IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
+          return EFI_DEVICE_ERROR;\r
+        }\r
+        break;\r
+      }\r
+\r
+      gBS->Stall (1000);\r
+      Count --;\r
+    }\r
+\r
+    IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
+    IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
+    //\r
+    // Read Status Register of IDE device to clear interrupt\r
+    //\r
+    RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);\r
+    //\r
+    // Clear START bit of BMIC register\r
+    //\r
+    IdeDev->PciIo->Io.Read (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmic,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
+\r
+    RegisterValue &= ~((UINT8) BMIC_START);\r
+\r
+    IdeDev->PciIo->Io.Write (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmic,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
+\r
+    if (RegisterValue & BMIS_ERROR) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
+    StartLba += NumberOfBlocks;\r
+  }\r
+\r
+  //\r
+  // Disable interrupt of Select device\r
+  //\r
+  IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);\r
+  DeviceControl |= IEN_L;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c b/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c
new file mode 100644 (file)
index 0000000..27f7f99
--- /dev/null
@@ -0,0 +1,2140 @@
+/** @file\r
+  Copyright (c) 2006 - 2007, Intel Corporation                                                         \r
+  All rights reserved. This program and the accompanying materials                          \r
+  are licensed and made available under the terms and conditions of the BSD License         \r
+  which accompanies this distribution.  The full text of the license may be found at        \r
+  http://opensource.org/licenses/bsd-license.php                                            \r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+**/\r
+\r
+#include "idebus.h"\r
+\r
+/**\r
+  This function is used to get the current status of the media residing\r
+  in the LS-120 drive or ZIP drive. The media status is returned in the \r
+  Error Status.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @retval EFI_SUCCESS\r
+  The media status is achieved successfully and the media\r
+  can be read/written.\r
+  \r
+  @retval EFI_DEVICE_ERROR\r
+  Get Media Status Command is failed.\r
+  \r
+  @retval EFI_NO_MEDIA\r
+  There is no media in the drive.\r
+  \r
+  @retval EFI_WRITE_PROTECTED\r
+  The media is writing protected.\r
+\r
+  @note\r
+  This function must be called after the LS120EnableMediaStatus() \r
+  with second parameter set to TRUE \r
+  (means enable media status notification) is called.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+LS120GetMediaStatus (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+{\r
+  UINT8       DeviceSelect;\r
+  UINT8       StatusValue;\r
+  EFI_STATUS  EfiStatus;\r
+  //\r
+  // Poll Alternate Register for BSY clear within timeout.\r
+  //\r
+  EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (EfiStatus)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Select device via Device/Head Register.\r
+  //\r
+  DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);\r
+\r
+  //\r
+  // Poll Alternate Register for DRDY set within timeout.\r
+  // After device is selected, DRDY set indicates the device is ready to\r
+  // accept command.\r
+  //\r
+  EfiStatus = DRDYReady2 (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (EfiStatus)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Get Media Status Command is sent\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xDA);\r
+\r
+  //\r
+  // BSY bit will clear after command is complete.\r
+  //\r
+  EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (EfiStatus)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // the media status is returned by the command in the ERROR register\r
+  //\r
+  StatusValue = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+\r
+  if (StatusValue & bit1) {\r
+    return EFI_NO_MEDIA;\r
+  }\r
+\r
+  if (StatusValue & bit6) {\r
+    return EFI_WRITE_PROTECTED;\r
+  } else {\r
+    return EFI_SUCCESS;\r
+  }\r
+}\r
+\r
+/**\r
+  This function is used to send Enable Media Status Notification Command\r
+  or Disable Media Status Notification Command.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] Enable\r
+  a flag that indicates whether enable or disable media\r
+  status notification.\r
+\r
+  @retval EFI_SUCCESS\r
+  If command completes successfully.\r
+  \r
+  @retval EFI_DEVICE_ERROR\r
+  If command failed.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+LS120EnableMediaStatus (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  BOOLEAN         Enable\r
+  )\r
+{\r
+  UINT8       DeviceSelect;\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Poll Alternate Register for BSY clear within timeout.\r
+  //\r
+  Status = WaitForBSYClear2 (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Select device via Device/Head Register.\r
+  //\r
+  DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);\r
+\r
+  //\r
+  // Poll Alternate Register for DRDY set within timeout.\r
+  // After device is selected, DRDY set indicates the device is ready to\r
+  // accept command.\r
+  //\r
+  Status = DRDYReady2 (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (Enable) {\r
+    //\r
+    // 0x95: Enable media status notification\r
+    //\r
+    IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x95);\r
+  } else {\r
+    //\r
+    // 0x31: Disable media status notification\r
+    //\r
+    IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x31);\r
+  }\r
+  //\r
+  // Set Feature Command is sent\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xEF);\r
+\r
+  //\r
+  // BSY bit will clear after command is complete.\r
+  //\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is called by DiscoverIdeDevice() during its device\r
+  identification.\r
+\r
+  Its main purpose is to get enough information for the device media\r
+  to fill in the Media data structure of the Block I/O Protocol interface.\r
+\r
+  There are 5 steps to reach such objective:\r
+\r
+  1. Sends out the ATAPI Identify Command to the specified device. \r
+  Only ATAPI device responses to this command. If the command succeeds,\r
+  it returns the Identify data structure which filled with information \r
+  about the device. Since the ATAPI device contains removable media, \r
+  the only meaningful information is the device module name.\r
+\r
+  2. Sends out ATAPI Inquiry Packet Command to the specified device.\r
+  This command will return inquiry data of the device, which contains\r
+  the device type information.\r
+\r
+  3. Allocate sense data space for future use. We don't detect the media\r
+  presence here to improvement boot performance, especially when CD \r
+  media is present. The media detection will be performed just before\r
+  each BLK_IO read/write\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @retval EFI_SUCCESS\r
+  Identify ATAPI device successfully.\r
+  \r
+  @retval EFI_DEVICE_ERROR\r
+  ATAPI Identify Device Command failed or device type\r
+  is not supported by this IDE driver.\r
+\r
+  @note\r
+  Parameter "IdeDev" will be updated in this function.\r
+\r
+  TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment\r
+  TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+ATAPIIdentify (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+{\r
+  EFI_IDENTIFY_DATA *AtapiIdentifyPointer;\r
+  UINT8             DeviceSelect;\r
+  EFI_STATUS        Status;\r
+\r
+  //\r
+  // device select bit\r
+  //\r
+  DeviceSelect          = (UINT8) ((IdeDev->Device) << 4);\r
+\r
+  AtapiIdentifyPointer  = AllocatePool (sizeof (EFI_IDENTIFY_DATA));\r
+  if (AtapiIdentifyPointer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Send ATAPI Identify Command to get IDENTIFY data.\r
+  //\r
+  Status = AtaPioDataIn (\r
+            IdeDev,\r
+            (VOID *) AtapiIdentifyPointer,\r
+            sizeof (EFI_IDENTIFY_DATA),\r
+            ATAPI_IDENTIFY_DEVICE_CMD,\r
+            DeviceSelect,\r
+            0,\r
+            0,\r
+            0,\r
+            0\r
+            );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->FreePool (AtapiIdentifyPointer);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  IdeDev->pIdData = AtapiIdentifyPointer;\r
+  PrintAtaModuleName (IdeDev);\r
+\r
+  //\r
+  // Send ATAPI Inquiry Packet Command to get INQUIRY data.\r
+  //\r
+  Status = AtapiInquiry (IdeDev);\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->FreePool (IdeDev->pIdData);\r
+    //\r
+    // Make sure the pIdData will not be freed again.\r
+    //\r
+    IdeDev->pIdData = NULL;\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Get media removable info from INQUIRY data.\r
+  //\r
+  IdeDev->BlkIo.Media->RemovableMedia = (UINT8) ((IdeDev->pInquiryData->RMB & 0x80) == 0x80);\r
+\r
+  //\r
+  // Identify device type via INQUIRY data.\r
+  //\r
+  switch (IdeDev->pInquiryData->peripheral_type & 0x1f) {\r
+\r
+  //\r
+  // Magnetic Disk\r
+  //\r
+  case 0x00:\r
+\r
+    //\r
+    // device is LS120 or ZIP drive.\r
+    //\r
+    IdeDev->Type = IdeMagnetic;\r
+\r
+    IdeDev->BlkIo.Media->MediaId      = 0;\r
+    //\r
+    // Give initial value\r
+    //\r
+    IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+\r
+    IdeDev->BlkIo.Media->LastBlock  = 0;\r
+    IdeDev->BlkIo.Media->BlockSize  = 0x200;\r
+    break;\r
+\r
+  //\r
+  // CD-ROM\r
+  //\r
+  case 0x05:\r
+\r
+    IdeDev->Type                      = IdeCdRom;\r
+    IdeDev->BlkIo.Media->MediaId      = 0;\r
+    //\r
+    // Give initial value\r
+    //\r
+    IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+\r
+    IdeDev->BlkIo.Media->LastBlock  = 0;\r
+    IdeDev->BlkIo.Media->BlockSize  = 0x800;\r
+    IdeDev->BlkIo.Media->ReadOnly   = TRUE;\r
+    break;\r
+\r
+  //\r
+  // Tape\r
+  //\r
+  case 0x01:\r
+\r
+  //\r
+  // WORM\r
+  //\r
+  case 0x04:\r
+  \r
+  //\r
+  // Optical\r
+  //\r
+  case 0x07:\r
+\r
+  default:\r
+    IdeDev->Type = IdeUnknown;\r
+    gBS->FreePool (IdeDev->pIdData);\r
+    gBS->FreePool (IdeDev->pInquiryData);\r
+    //\r
+    // Make sure the pIdData and pInquiryData will not be freed again.\r
+    //\r
+    IdeDev->pIdData       = NULL;\r
+    IdeDev->pInquiryData  = NULL;\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // original sense data numbers\r
+  //\r
+  IdeDev->SenseDataNumber = 20;\r
+\r
+  IdeDev->SenseData = AllocatePool (IdeDev->SenseDataNumber * sizeof (REQUEST_SENSE_DATA));\r
+  if (IdeDev->SenseData == NULL) {\r
+    gBS->FreePool (IdeDev->pIdData);\r
+    gBS->FreePool (IdeDev->pInquiryData);\r
+    //\r
+    // Make sure the pIdData and pInquiryData will not be freed again.\r
+    //\r
+    IdeDev->pIdData       = NULL;\r
+    IdeDev->pInquiryData  = NULL;\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Sends out ATAPI Inquiry Packet Command to the specified device.\r
+  This command will return INQUIRY data of the device.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @retval EFI_SUCCESS\r
+  Inquiry command completes successfully.\r
+  \r
+  @retval EFI_DEVICE_ERROR\r
+  Inquiry command failed.\r
+\r
+  @note\r
+  Parameter "IdeDev" will be updated in this function.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiInquiry (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+{\r
+  ATAPI_PACKET_COMMAND  Packet;\r
+  EFI_STATUS            Status;\r
+  INQUIRY_DATA          *InquiryData;\r
+\r
+  //\r
+  // prepare command packet for the ATAPI Inquiry Packet Command.\r
+  //\r
+  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+  Packet.Inquiry.opcode             = INQUIRY;\r
+  Packet.Inquiry.page_code          = 0;\r
+  Packet.Inquiry.allocation_length  = sizeof (INQUIRY_DATA);\r
+\r
+  InquiryData                       = AllocatePool (sizeof (INQUIRY_DATA));\r
+  if (InquiryData == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Send command packet and get requested Inquiry data.\r
+  //\r
+  Status = AtapiPacketCommandIn (\r
+            IdeDev,\r
+            &Packet,\r
+            (UINT16 *) InquiryData,\r
+            sizeof (INQUIRY_DATA),\r
+            ATAPITIMEOUT\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->FreePool (InquiryData);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  IdeDev->pInquiryData = InquiryData;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is used to send out ATAPI commands conforms to the \r
+  Packet Command with PIO Data In Protocol.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *Packet\r
+  pointer pointing to ATAPI_PACKET_COMMAND data structure\r
+  which contains the contents of the command.     \r
+\r
+  @param[in] *Buffer\r
+  buffer contained data transferred from device to host.\r
+\r
+  @param[in] ByteCount\r
+  data size in byte unit of the buffer.\r
+\r
+  @param[in] TimeOut\r
+  this parameter is used to specify the timeout \r
+  value for the PioReadWriteData() function. \r
+\r
+  @retval EFI_SUCCESS\r
+  send out the ATAPI packet command successfully\r
+  and device sends data successfully.\r
+  \r
+  @retval EFI_DEVICE_ERROR\r
+  the device failed to send data.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiPacketCommandIn (\r
+  IN  IDE_BLK_IO_DEV        *IdeDev,\r
+  IN  ATAPI_PACKET_COMMAND  *Packet,\r
+  IN  UINT16                *Buffer,\r
+  IN  UINT32                ByteCount,\r
+  IN  UINTN                 TimeOut\r
+  )\r
+{\r
+  UINT16      *CommandIndex;\r
+  EFI_STATUS  Status;\r
+  UINT32      Count;\r
+\r
+  //\r
+  // Set all the command parameters by fill related registers.\r
+  // Before write to all the following registers, BSY and DRQ must be 0.\r
+  //\r
+  Status = DRQClear2 (IdeDev, ATAPITIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Select device via Device/Head Register.\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((IdeDev->Device << 4) | DEFAULT_CMD)  // DEFAULT_CMD: 0xa0 (1010,0000)\r
+    );\r
+\r
+  //\r
+  // No OVL; No DMA\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);\r
+\r
+  //\r
+  // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device\r
+  // determine how many data should be transferred.\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->CylinderLsb,\r
+    (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)\r
+    );\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->CylinderMsb,\r
+    (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)\r
+    );\r
+\r
+  //\r
+  //  DEFAULT_CTL:0x0a (0000,1010)\r
+  //  Disable interrupt\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DEFAULT_CTL);\r
+\r
+  //\r
+  // Send Packet command to inform device\r
+  // that the following data bytes are command packet.\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, PACKET_CMD);\r
+\r
+  Status = DRQReady (IdeDev, ATAPITIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Send out command packet\r
+  //\r
+  CommandIndex = Packet->Data16;\r
+  for (Count = 0; Count < 6; Count++, CommandIndex++) {\r
+\r
+    IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex);\r
+    gBS->Stall (10);\r
+  }\r
+\r
+  //\r
+  // call PioReadWriteData() function to get\r
+  // requested transfer data form device.\r
+  //\r
+  return PioReadWriteData (IdeDev, Buffer, ByteCount, 1, TimeOut);\r
+}\r
+\r
+/**\r
+  This function is used to send out ATAPI commands conforms to the \r
+  Packet Command with PIO Data Out Protocol.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *Packet\r
+  pointer pointing to ATAPI_PACKET_COMMAND data structure\r
+  which contains the contents of the command.\r
+\r
+  @param[in] *Buffer\r
+  buffer contained data transferred from host to device.\r
+\r
+  @param[in] ByteCount\r
+  data size in byte unit of the buffer.\r
+\r
+  @param[in] TimeOut\r
+  this parameter is used to specify the timeout \r
+  value for the PioReadWriteData() function. \r
+\r
+  @retval EFI_SUCCESS\r
+  send out the ATAPI packet command successfully\r
+  and device received data successfully.\r
+  \r
+  @retval EFI_DEVICE_ERROR\r
+  the device failed to send data.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiPacketCommandOut (\r
+  IN  IDE_BLK_IO_DEV        *IdeDev,\r
+  IN  ATAPI_PACKET_COMMAND  *Packet,\r
+  IN  UINT16                *Buffer,\r
+  IN  UINT32                ByteCount,\r
+  IN  UINTN                 TimeOut\r
+  )\r
+{\r
+  UINT16      *CommandIndex;\r
+  EFI_STATUS  Status;\r
+  UINT32      Count;\r
+\r
+  //\r
+  // set all the command parameters\r
+  // Before write to all the following registers, BSY and DRQ must be 0.\r
+  //\r
+  Status = DRQClear2 (IdeDev, ATAPITIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Select device via Device/Head Register.\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((IdeDev->Device << 4) | DEFAULT_CMD)   // DEFAULT_CMD: 0xa0 (1010,0000)\r
+    );\r
+\r
+  //\r
+  // No OVL; No DMA\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);\r
+\r
+  //\r
+  // set the transfersize to MAX_ATAPI_BYTE_COUNT to\r
+  // let the device determine how many data should be transferred.\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->CylinderLsb,\r
+    (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)\r
+    );\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->CylinderMsb,\r
+    (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)\r
+    );\r
+\r
+  //\r
+  //  DEFAULT_CTL:0x0a (0000,1010)\r
+  //  Disable interrupt\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DEFAULT_CTL);\r
+\r
+  //\r
+  // Send Packet command to inform device\r
+  // that the following data bytes are command packet.\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, PACKET_CMD);\r
+\r
+  Status = DRQReady2 (IdeDev, ATAPITIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Send out command packet\r
+  //\r
+  CommandIndex = Packet->Data16;\r
+  for (Count = 0; Count < 6; Count++, CommandIndex++) {\r
+    IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex);\r
+    gBS->Stall (10);\r
+  }\r
+\r
+  //\r
+  // call PioReadWriteData() function to send requested transfer data to device.\r
+  //\r
+  return PioReadWriteData (IdeDev, Buffer, ByteCount, 0, TimeOut);\r
+}\r
+\r
+/**\r
+  This function is called by either AtapiPacketCommandIn() or \r
+  AtapiPacketCommandOut(). It is used to transfer data between\r
+  host and device. The data direction is specified by the fourth\r
+  parameter.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *Buffer\r
+  buffer contained data transferred between host and device.\r
+\r
+  @param[in] ByteCount\r
+  data size in byte unit of the buffer.\r
+\r
+  @param[in] Read\r
+  flag used to determine the data transfer direction.\r
+  Read equals 1, means data transferred from device to host;\r
+  Read equals 0, means data transferred from host to device.\r
+\r
+  @param[in] TimeOut\r
+  timeout value for wait DRQ ready before each data \r
+  stream's transfer.\r
+\r
+  @retval EFI_SUCCESS\r
+  data is transferred successfully.\r
+  \r
+  @retval EFI_DEVICE_ERROR\r
+  the device failed to transfer data.\r
+\r
+**/\r
+EFI_STATUS\r
+PioReadWriteData (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINT16          *Buffer,\r
+  IN  UINT32          ByteCount,\r
+  IN  BOOLEAN         Read,\r
+  IN  UINTN           TimeOut\r
+  )\r
+{\r
+  //\r
+  // required transfer data in word unit.\r
+  //\r
+  UINT32      RequiredWordCount;\r
+\r
+  //\r
+  // actual transfer data in word unit.\r
+  //\r
+  UINT32      ActualWordCount;\r
+  UINT32      WordCount;\r
+  EFI_STATUS  Status;\r
+  UINT16      *PtrBuffer;\r
+\r
+  //\r
+  // No data transfer is premitted.\r
+  //\r
+  if (ByteCount == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // for performance, we assert the ByteCount is an even number\r
+  // which is actually a resonable assumption  \r
+  ASSERT((ByteCount%2) == 0);\r
+  \r
+  PtrBuffer         = Buffer;\r
+  RequiredWordCount = ByteCount / 2;\r
+  //\r
+  // ActuralWordCount means the word count of data really transferred.\r
+  //\r
+  ActualWordCount = 0;\r
+\r
+  while (ActualWordCount < RequiredWordCount) {\r
+    \r
+    //\r
+    // before each data transfer stream, the host should poll DRQ bit ready,\r
+    // to see whether indicates device is ready to transfer data.\r
+    //\r
+    Status = DRQReady2 (IdeDev, TimeOut);\r
+    if (EFI_ERROR (Status)) {\r
+      return CheckErrorStatus (IdeDev);\r
+    }\r
+    \r
+    //\r
+    // read Status Register will clear interrupt\r
+    //\r
+    IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+\r
+    //\r
+    // get current data transfer size from Cylinder Registers.\r
+    //\r
+    WordCount = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) << 8;\r
+    WordCount = WordCount | IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);\r
+    WordCount = WordCount & 0xffff;\r
+    WordCount /= 2;\r
+\r
+    WordCount = EFI_MIN (WordCount, (RequiredWordCount - ActualWordCount));\r
+\r
+    if (Read) {\r
+      IDEReadPortWMultiple (\r
+        IdeDev->PciIo,\r
+        IdeDev->IoPort->Data,\r
+        WordCount,\r
+        PtrBuffer\r
+        );\r
+    } else {\r
+      IDEWritePortWMultiple (\r
+        IdeDev->PciIo,\r
+        IdeDev->IoPort->Data,\r
+        WordCount,\r
+        PtrBuffer\r
+        );\r
+    }\r
+\r
+    PtrBuffer += WordCount;\r
+    ActualWordCount += WordCount;\r
+  }\r
+  \r
+  if (Read) {\r
+    //\r
+    // In the case where the drive wants to send more data than we need to read,\r
+    // the DRQ bit will be set and cause delays from DRQClear2().\r
+    // We need to read data from the drive until it clears DRQ so we can move on.\r
+    //\r
+    AtapiReadPendingData (IdeDev);\r
+  }\r
+\r
+  //\r
+  // After data transfer is completed, normally, DRQ bit should clear.\r
+  //\r
+  Status = DRQClear2 (IdeDev, ATAPITIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // read status register to check whether error happens.\r
+  //\r
+  return CheckErrorStatus (IdeDev);\r
+}\r
+\r
+/**\r
+  Sends out ATAPI Test Unit Ready Packet Command to the specified device\r
+  to find out whether device is accessible.\r
+\r
+  @param[in] *IdeDev     Pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+                         to record all the information of the IDE device.\r
+  @param[in] *SenseCount Sense count for this packet command\r
+\r
+  @retval EFI_SUCCESS      Device is accessible.\r
+  @retval EFI_DEVICE_ERROR Device is not accessible.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiTestUnitReady (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  OUT UINTN           *SenseCount\r
+  )\r
+{\r
+  ATAPI_PACKET_COMMAND  Packet;\r
+  EFI_STATUS            Status;\r
+\r
+  *SenseCount = 0;\r
+\r
+  //\r
+  // fill command packet\r
+  //\r
+  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+  Packet.TestUnitReady.opcode = TEST_UNIT_READY;\r
+\r
+  //\r
+  // send command packet\r
+  //\r
+  Status = AtapiPacketCommandIn (IdeDev, &Packet, NULL, 0, ATAPITIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = AtapiRequestSense (IdeDev, SenseCount);\r
+  if (EFI_ERROR (Status)) {\r
+    *SenseCount = 0;\r
+    return Status;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Sends out ATAPI Request Sense Packet Command to the specified device.\r
+  This command will return all the current Sense data in the device. \r
+  This function will pack all the Sense data in one single buffer.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[out] **SenseBuffers\r
+  allocated in this function, and freed by the calling function.\r
+  This buffer is used to accommodate all the sense data returned \r
+  by the device.\r
+\r
+  @param[out] *BufUnit\r
+  record the unit size of the sense data block in the SenseBuffers,\r
+\r
+  @param[out] *BufNumbers\r
+  record the number of units in the SenseBuffers.\r
+\r
+  @retval EFI_SUCCESS\r
+  Request Sense command completes successfully.\r
+  \r
+  @retval EFI_DEVICE_ERROR\r
+  Request Sense command failed.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiRequestSense (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  OUT UINTN           *SenseCounts\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  REQUEST_SENSE_DATA    *Sense;\r
+  UINT16                *Ptr;\r
+  BOOLEAN               FetchSenseData;\r
+  ATAPI_PACKET_COMMAND  Packet;\r
+\r
+  *SenseCounts = 0;\r
+\r
+  ZeroMem (IdeDev->SenseData, sizeof (REQUEST_SENSE_DATA) * (IdeDev->SenseDataNumber));\r
+  //\r
+  // fill command packet for Request Sense Packet Command\r
+  //\r
+  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+  Packet.RequestSence.opcode            = REQUEST_SENSE;\r
+  Packet.RequestSence.allocation_length = sizeof (REQUEST_SENSE_DATA);\r
+\r
+  //\r
+  // initialize pointer\r
+  //\r
+  Ptr = (UINT16 *) IdeDev->SenseData;\r
+  //\r
+  //  request sense data from device continuously until no sense data\r
+  //  exists in the device.\r
+  //\r
+  for (FetchSenseData = TRUE; FetchSenseData;) {\r
+\r
+    Sense = (REQUEST_SENSE_DATA *) Ptr;\r
+\r
+    //\r
+    // send out Request Sense Packet Command and get one Sense data form device\r
+    //\r
+    Status = AtapiPacketCommandIn (\r
+              IdeDev,\r
+              &Packet,\r
+              Ptr,\r
+              sizeof (REQUEST_SENSE_DATA),\r
+              ATAPITIMEOUT\r
+              );\r
+    //\r
+    // failed to get Sense data\r
+    //\r
+    if (EFI_ERROR (Status)) {\r
+      if (*SenseCounts == 0) {\r
+        return EFI_DEVICE_ERROR;\r
+      } else {\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+\r
+    (*SenseCounts)++;\r
+    //\r
+    // We limit MAX sense data count to 20 in order to avoid dead loop. Some\r
+    // incompatible ATAPI devices don't retrive NO_SENSE when there is no media.\r
+    // In this case, dead loop occurs if we don't have a gatekeeper. 20 is\r
+    // supposed to be large enough for any ATAPI device.\r
+    //\r
+    if ((Sense->sense_key != SK_NO_SENSE) && ((*SenseCounts) < 20)) {\r
+      //\r
+      // Ptr is word-based pointer\r
+      //\r
+      Ptr += (sizeof (REQUEST_SENSE_DATA) + 1) >> 1;\r
+\r
+    } else {\r
+      //\r
+      // when no sense key, skip out the loop\r
+      //\r
+      FetchSenseData = FALSE;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Sends out ATAPI Read Capacity Packet Command to the specified device.\r
+  This command will return the information regarding the capacity of the\r
+  media in the device.\r
+\r
+  Current device status will impact device's response to the Read Capacity\r
+  Command. For example, if the device once reset, the Read Capacity\r
+  Command will fail. The Sense data record the current device status, so \r
+  if the Read Capacity Command failed, the Sense data must be requested\r
+  and be analyzed to determine if the Read Capacity Command should retry.\r
+\r
+  @param[in] *IdeDev    Pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+                        to record all the information of the IDE device.\r
+  @param[in] SenseCount Sense count for this packet command\r
+\r
+  @retval EFI_SUCCESS      Read Capacity Command finally completes successfully.\r
+  @retval EFI_DEVICE_ERROR Read Capacity Command failed because of device error.\r
+\r
+  @note Parameter "IdeDev" will be updated in this function.\r
+\r
+  TODO:    EFI_NOT_READY - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+AtapiReadCapacity (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  OUT UINTN               *SenseCount\r
+  )\r
+{\r
+  //\r
+  // status returned by Read Capacity Packet Command\r
+  //\r
+  EFI_STATUS                Status;\r
+  EFI_STATUS                SenseStatus;\r
+  ATAPI_PACKET_COMMAND      Packet;\r
+\r
+  //\r
+  // used for capacity data returned from ATAPI device\r
+  //\r
+  READ_CAPACITY_DATA        Data;\r
+  READ_FORMAT_CAPACITY_DATA FormatData;\r
+\r
+  *SenseCount = 0;\r
+\r
+  ZeroMem (&Data, sizeof (Data));\r
+  ZeroMem (&FormatData, sizeof (FormatData));\r
+\r
+  if (IdeDev->Type == IdeCdRom) {\r
+\r
+    ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+    Packet.Inquiry.opcode = READ_CAPACITY;\r
+    Status = AtapiPacketCommandIn (\r
+               IdeDev,\r
+               &Packet,\r
+               (UINT16 *) &Data,\r
+               sizeof (READ_CAPACITY_DATA),\r
+               ATAPITIMEOUT\r
+               );\r
+\r
+  } else {\r
+    //\r
+    // Type == IdeMagnetic\r
+    //\r
+    ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+    Packet.ReadFormatCapacity.opcode                = READ_FORMAT_CAPACITY;\r
+    Packet.ReadFormatCapacity.allocation_length_lo  = 12;\r
+    Status = AtapiPacketCommandIn (\r
+               IdeDev,\r
+               &Packet,\r
+               (UINT16 *) &FormatData,\r
+               sizeof (READ_FORMAT_CAPACITY_DATA),\r
+               ATAPITIMEOUT\r
+               );\r
+  }\r
+\r
+  if (Status == EFI_TIMEOUT) {\r
+    *SenseCount = 0;\r
+    return Status;\r
+  }\r
+\r
+  SenseStatus = AtapiRequestSense (IdeDev, SenseCount);\r
+\r
+  if (!EFI_ERROR (SenseStatus)) {\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+\r
+      if (IdeDev->Type == IdeCdRom) {\r
+\r
+        IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) |\r
+          (Data.LastLba2 << 16) |\r
+          (Data.LastLba1 << 8) |\r
+          Data.LastLba0;\r
+\r
+        if (IdeDev->BlkIo.Media->LastBlock != 0) {\r
+\r
+          IdeDev->BlkIo.Media->BlockSize = (Data.BlockSize3 << 24) |\r
+            (Data.BlockSize2 << 16) |\r
+            (Data.BlockSize1 << 8) |\r
+            Data.BlockSize0;\r
+\r
+          IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
+        } else {\r
+          IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+          return EFI_DEVICE_ERROR;\r
+        }\r
+\r
+        IdeDev->BlkIo.Media->ReadOnly = TRUE;\r
+\r
+        //\r
+        // Because the user data portion in the sector of the Data CD supported\r
+        // is always 0x800\r
+        //\r
+        IdeDev->BlkIo.Media->BlockSize = 0x800;\r
+      }\r
+\r
+      if (IdeDev->Type == IdeMagnetic) {\r
+\r
+        if (FormatData.DesCode == 3) {\r
+          IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+          IdeDev->BlkIo.Media->LastBlock    = 0;\r
+        } else {\r
+\r
+          IdeDev->BlkIo.Media->LastBlock =  (FormatData.LastLba3 << 24) |\r
+            (FormatData.LastLba2 << 16) | \r
+            (FormatData.LastLba1 << 8)  |\r
+            FormatData.LastLba0;\r
+          if (IdeDev->BlkIo.Media->LastBlock != 0) {\r
+            IdeDev->BlkIo.Media->LastBlock--;\r
+\r
+            IdeDev->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) |\r
+              (FormatData.BlockSize1 << 8) |\r
+              FormatData.BlockSize0;\r
+\r
+            IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
+          } else {\r
+            IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+            //\r
+            // Return EFI_NOT_READY operation succeeds but returned capacity is 0\r
+            //\r
+            return EFI_NOT_READY;\r
+          }\r
+\r
+          IdeDev->BlkIo.Media->BlockSize = 0x200;\r
+\r
+        }\r
+      }\r
+    }\r
+\r
+    return EFI_SUCCESS;\r
+\r
+  } else {\r
+    *SenseCount = 0;\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+}\r
+\r
+/**\r
+  Used before read/write blocks from/to ATAPI device media. \r
+  Since ATAPI device media is removable, it is necessary to detect\r
+  whether media is present and get current present media's\r
+  information, and if media has been changed, Block I/O Protocol\r
+  need to be reinstalled.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[out] *MediaChange\r
+  return value that indicates if the media of the device has been\r
+  changed.\r
+\r
+  @retval EFI_SUCCESS\r
+  media found successfully.\r
+  \r
+  @retval EFI_DEVICE_ERROR\r
+  any error encounters during media detection.\r
+  \r
+  @retval EFI_NO_MEDIA\r
+  media not found.\r
+\r
+  @note\r
+  parameter IdeDev may be updated in this function.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiDetectMedia (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  OUT BOOLEAN         *MediaChange\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_STATUS                    CleanStateStatus;\r
+  EFI_BLOCK_IO_MEDIA            OldMediaInfo;\r
+  UINTN                         RetryTimes;\r
+  UINTN                         RetryNotReady;\r
+  UINTN                         SenseCount;\r
+  SENSE_RESULT                  SResult;\r
+  BOOLEAN                       WriteProtected;\r
+\r
+  CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (EFI_BLOCK_IO_MEDIA));\r
+  *MediaChange  = FALSE;\r
+  //\r
+  // Retry for SenseDeviceNotReadyNeedRetry.\r
+  // Each retry takes 1s and we limit the upper boundary to\r
+  // 120 times about 2 min.\r
+  //\r
+  RetryNotReady = 120;\r
+\r
+  //\r
+  // Do Test Unit Ready\r
+  //\r
+ DoTUR:\r
+  //\r
+  // Retry 5 times\r
+  //\r
+  RetryTimes = 5;\r
+  while (RetryTimes != 0) {\r
+\r
+    Status = AtapiTestUnitReady (IdeDev, &SenseCount);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Test Unit Ready error without sense data.\r
+      // For some devices, this means there's extra data\r
+      // that has not been read, so we read these extra\r
+      // data out before going on.\r
+      //\r
+      CleanStateStatus = AtapiReadPendingData (IdeDev);\r
+      if (EFI_ERROR (CleanStateStatus)) {\r
+        //\r
+        // Busy wait failed, try again\r
+        //\r
+        RetryTimes--;\r
+      }\r
+      //\r
+      // Try again without counting down RetryTimes\r
+      //\r
+      continue;\r
+    } else {\r
+\r
+      ParseSenseData (IdeDev, SenseCount, &SResult);\r
+\r
+      switch (SResult) {\r
+      case SenseNoSenseKey:\r
+        if (IdeDev->BlkIo.Media->MediaPresent) {\r
+          goto Done;\r
+        } else {\r
+          //\r
+          // Media present but the internal structure need refreshed.\r
+          // Try Read Capacity\r
+          //\r
+          goto DoRC;\r
+        }\r
+        break;\r
+\r
+      case SenseDeviceNotReadyNeedRetry:\r
+        if (--RetryNotReady == 0) {\r
+          return EFI_DEVICE_ERROR;\r
+        }\r
+        gBS->Stall (1000 * STALL_1_MILLI_SECOND);\r
+        continue;\r
+        break;\r
+\r
+      case SenseNoMedia:\r
+        IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+        IdeDev->BlkIo.Media->LastBlock    = 0;\r
+        goto Done;\r
+        break;\r
+\r
+      case SenseDeviceNotReadyNoRetry:\r
+      case SenseMediaError:\r
+        return EFI_DEVICE_ERROR;\r
+\r
+      case SenseMediaChange:\r
+        IdeDev->BlkIo.Media->MediaId++;\r
+        goto DoRC;\r
+        break;\r
+\r
+      default:\r
+        RetryTimes--;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  return EFI_DEVICE_ERROR;\r
+\r
+  //\r
+  // Do Read Capacity\r
+  //\r
+ DoRC:\r
+    RetryTimes = 5;\r
+\r
+    while (RetryTimes != 0) {\r
+\r
+      Status = AtapiReadCapacity (IdeDev, &SenseCount);\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        RetryTimes--;\r
+        continue;\r
+      } else {\r
+\r
+        ParseSenseData (IdeDev, SenseCount, &SResult);\r
+\r
+        switch (SResult) {\r
+        case SenseNoSenseKey:\r
+          goto Done;\r
+          break;\r
+\r
+        case SenseDeviceNotReadyNeedRetry:\r
+          //\r
+          // We use Test Unit Ready to retry which\r
+          // is faster.\r
+          //\r
+          goto DoTUR;\r
+          break;\r
+\r
+        case SenseNoMedia:\r
+          IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+          IdeDev->BlkIo.Media->LastBlock    = 0;\r
+          goto Done;\r
+          break;\r
+\r
+        case SenseDeviceNotReadyNoRetry:\r
+        case SenseMediaError:\r
+          return EFI_DEVICE_ERROR;\r
+\r
+        case SenseMediaChange:\r
+          IdeDev->BlkIo.Media->MediaId++;\r
+          continue;\r
+          break;\r
+\r
+        default:\r
+          RetryTimes--;\r
+          break;\r
+        }\r
+      }\r
+    }\r
+\r
+  return EFI_DEVICE_ERROR;\r
+\r
+ Done:\r
+  //\r
+  // the following code is to check the write-protected for LS120 media\r
+  //\r
+  if ((IdeDev->BlkIo.Media->MediaPresent) && (IdeDev->Type == IdeMagnetic)) {\r
+\r
+    Status = IsLS120orZipWriteProtected (IdeDev, &WriteProtected);\r
+    if (!EFI_ERROR (Status)) {\r
+\r
+      if (WriteProtected) {\r
+\r
+        IdeDev->BlkIo.Media->ReadOnly = TRUE;\r
+      } else {\r
+\r
+        IdeDev->BlkIo.Media->ReadOnly = FALSE;\r
+      }\r
+\r
+    }\r
+  }\r
+\r
+  if (IdeDev->BlkIo.Media->MediaId != OldMediaInfo.MediaId) {\r
+    //\r
+    // Media change information got from the device\r
+    //\r
+    *MediaChange = TRUE;\r
+  }\r
+\r
+  if (IdeDev->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) {\r
+    *MediaChange = TRUE;\r
+    IdeDev->BlkIo.Media->MediaId += 1;\r
+  }\r
+\r
+  if (IdeDev->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) {\r
+    *MediaChange = TRUE;\r
+    IdeDev->BlkIo.Media->MediaId += 1;\r
+  }\r
+\r
+  if (IdeDev->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) {\r
+    *MediaChange = TRUE;\r
+    IdeDev->BlkIo.Media->MediaId += 1;\r
+  }\r
+\r
+  if (IdeDev->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) {\r
+    if (IdeDev->BlkIo.Media->MediaPresent) {\r
+      //\r
+      // when change from no media to media present, reset the MediaId to 1.\r
+      //\r
+      IdeDev->BlkIo.Media->MediaId = 1;\r
+    } else {\r
+      //\r
+      // when no media, reset the MediaId to zero.\r
+      //\r
+      IdeDev->BlkIo.Media->MediaId = 0;\r
+    }\r
+\r
+    *MediaChange = TRUE;\r
+  }\r
+\r
+  //\r
+  // if any change on current existing media,\r
+  // the Block I/O protocol need to be reinstalled.\r
+  //\r
+  if (*MediaChange) {\r
+    gBS->ReinstallProtocolInterface (\r
+          IdeDev->Handle,\r
+          &gEfiBlockIoProtocolGuid,\r
+          &IdeDev->BlkIo,\r
+          &IdeDev->BlkIo\r
+          );\r
+  }\r
+\r
+  if (IdeDev->BlkIo.Media->MediaPresent) {\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_NO_MEDIA;\r
+  }\r
+}\r
+\r
+/**\r
+  This function is called by the AtapiBlkIoReadBlocks() to perform\r
+  read from media in block unit.\r
+\r
+  The main command used to access media here is READ(10) Command. \r
+  READ(10) Command requests that the ATAPI device media transfer \r
+  specified data to the host. Data is transferred in block(sector) \r
+  unit. The maximum number of blocks that can be transferred once is\r
+  65536. This is the main difference between READ(10) and READ(12) \r
+  Command. The maximum number of blocks in READ(12) is 2 power 32.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *Buffer\r
+  A pointer to the destination buffer for the data. \r
+\r
+  @param[in] Lba\r
+  The starting logical block address to read from \r
+  on the device media.\r
+\r
+  @param[in] NumberOfBlocks\r
+  The number of transfer data blocks.\r
+\r
+  @return status is fully dependent on the return status\r
+  of AtapiPacketCommandIn() function.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiReadSectors (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *Buffer,\r
+  IN  EFI_LBA         Lba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+{\r
+\r
+  ATAPI_PACKET_COMMAND  Packet;\r
+  READ10_CMD            *Read10Packet;\r
+  EFI_STATUS            Status;\r
+  UINTN                 BlocksRemaining;\r
+  UINT32                Lba32;\r
+  UINT32                BlockSize;\r
+  UINT32                ByteCount;\r
+  UINT16                SectorCount;\r
+  VOID                  *PtrBuffer;\r
+  UINT16                MaxBlock;\r
+  UINTN                 TimeOut;\r
+\r
+  //\r
+  // fill command packet for Read(10) command\r
+  //\r
+  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+  Read10Packet  = &Packet.Read10;\r
+  Lba32         = (UINT32) Lba;\r
+  PtrBuffer     = Buffer;\r
+\r
+  BlockSize     = IdeDev->BlkIo.Media->BlockSize;\r
+\r
+  //\r
+  // limit the data bytes that can be transferred by one Read(10) Command\r
+  //\r
+  MaxBlock        = 65535;\r
+\r
+  BlocksRemaining = NumberOfBlocks;\r
+\r
+  Status          = EFI_SUCCESS;\r
+  while (BlocksRemaining > 0) {\r
+\r
+    if (BlocksRemaining <= MaxBlock) {\r
+\r
+      SectorCount = (UINT16) BlocksRemaining;\r
+    } else {\r
+\r
+      SectorCount = MaxBlock;\r
+    }\r
+\r
+    //\r
+    // fill the Packet data structure\r
+    //\r
+\r
+    Read10Packet->opcode = READ_10;\r
+\r
+    //\r
+    // Lba0 ~ Lba3 specify the start logical block address of the data transfer.\r
+    // Lba0 is MSB, Lba3 is LSB\r
+    //\r
+    Read10Packet->Lba3  = (UINT8) (Lba32 & 0xff);\r
+    Read10Packet->Lba2  = (UINT8) (Lba32 >> 8);\r
+    Read10Packet->Lba1  = (UINT8) (Lba32 >> 16);\r
+    Read10Packet->Lba0  = (UINT8) (Lba32 >> 24);\r
+\r
+    //\r
+    // TranLen0 ~ TranLen1 specify the transfer length in block unit.\r
+    // TranLen0 is MSB, TranLen is LSB\r
+    //\r
+    Read10Packet->TranLen1  = (UINT8) (SectorCount & 0xff);\r
+    Read10Packet->TranLen0  = (UINT8) (SectorCount >> 8);\r
+\r
+    ByteCount               = SectorCount * BlockSize;\r
+\r
+    if (IdeDev->Type == IdeCdRom) {\r
+      TimeOut = CDROMLONGTIMEOUT;\r
+    } else {\r
+      TimeOut = ATAPILONGTIMEOUT;\r
+    }\r
+\r
+    Status = AtapiPacketCommandIn (\r
+              IdeDev,\r
+              &Packet,\r
+              (UINT16 *) PtrBuffer,\r
+              ByteCount,\r
+              TimeOut\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Lba32 += SectorCount;\r
+    PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;\r
+    BlocksRemaining -= SectorCount;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function is called by the AtapiBlkIoWriteBlocks() to perform\r
+  write onto media in block unit.\r
+  The main command used to access media here is Write(10) Command. \r
+  Write(10) Command requests that the ATAPI device media transfer \r
+  specified data to the host. Data is transferred in block (sector) \r
+  unit. The maximum number of blocks that can be transferred once is\r
+  65536. \r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *Buffer\r
+  A pointer to the source buffer for the data. \r
+\r
+  @param[in] Lba\r
+  The starting logical block address to write onto \r
+  the device media.\r
+\r
+  @param[in] NumberOfBlocks\r
+  The number of transfer data blocks.\r
+\r
+  @return status is fully dependent on the return status\r
+  of AtapiPacketCommandOut() function.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiWriteSectors (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *Buffer,\r
+  IN  EFI_LBA         Lba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+{\r
+\r
+  ATAPI_PACKET_COMMAND  Packet;\r
+  READ10_CMD            *Read10Packet;\r
+\r
+  EFI_STATUS            Status;\r
+  UINTN                 BlocksRemaining;\r
+  UINT32                Lba32;\r
+  UINT32                BlockSize;\r
+  UINT32                ByteCount;\r
+  UINT16                SectorCount;\r
+  VOID                  *PtrBuffer;\r
+  UINT16                MaxBlock;\r
+\r
+  //\r
+  // fill command packet for Write(10) command\r
+  // Write(10) command packet has the same data structure as\r
+  // Read(10) command packet,\r
+  // so here use the Read10Packet data structure\r
+  // for the Write(10) command packet.\r
+  //\r
+  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+  Read10Packet  = &Packet.Read10;\r
+\r
+  Lba32         = (UINT32) Lba;\r
+  PtrBuffer     = Buffer;\r
+\r
+  BlockSize     = IdeDev->BlkIo.Media->BlockSize;\r
+\r
+  //\r
+  // limit the data bytes that can be transferred by one Read(10) Command\r
+  //\r
+  MaxBlock        = (UINT16) (65536 / BlockSize);\r
+\r
+  BlocksRemaining = NumberOfBlocks;\r
+\r
+  Status          = EFI_SUCCESS;\r
+  while (BlocksRemaining > 0) {\r
+\r
+    if (BlocksRemaining >= MaxBlock) {\r
+      SectorCount = MaxBlock;\r
+    } else {\r
+      SectorCount = (UINT16) BlocksRemaining;\r
+    }\r
+  \r
+    //\r
+    // Command code is WRITE_10.\r
+    //\r
+    Read10Packet->opcode = WRITE_10;\r
+\r
+    //\r
+    // Lba0 ~ Lba3 specify the start logical block address of the data transfer.\r
+    // Lba0 is MSB, Lba3 is LSB\r
+    //\r
+    Read10Packet->Lba3  = (UINT8) (Lba32 & 0xff);\r
+    Read10Packet->Lba2  = (UINT8) (Lba32 >> 8);\r
+    Read10Packet->Lba1  = (UINT8) (Lba32 >> 16);\r
+    Read10Packet->Lba0  = (UINT8) (Lba32 >> 24);\r
+\r
+    //\r
+    // TranLen0 ~ TranLen1 specify the transfer length in block unit.\r
+    // TranLen0 is MSB, TranLen is LSB\r
+    //\r
+    Read10Packet->TranLen1  = (UINT8) (SectorCount & 0xff);\r
+    Read10Packet->TranLen0  = (UINT8) (SectorCount >> 8);\r
+\r
+    ByteCount               = SectorCount * BlockSize;\r
+\r
+    Status = AtapiPacketCommandOut (\r
+              IdeDev,\r
+              &Packet,\r
+              (UINT16 *) PtrBuffer,\r
+              ByteCount,\r
+              ATAPILONGTIMEOUT\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Lba32 += SectorCount;\r
+    PtrBuffer = ((UINT8 *) PtrBuffer + SectorCount * BlockSize);\r
+    BlocksRemaining -= SectorCount;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function is used to implement the Soft Reset on the specified\r
+  ATAPI device. Different from the AtaSoftReset(), here reset is a ATA\r
+  Soft Reset Command special for ATAPI device, and it only take effects\r
+  on the specified ATAPI device, not on the whole IDE bus.\r
+  Since the ATAPI soft reset is needed when device is in exceptional\r
+  condition (such as BSY bit is always set ), I think the Soft Reset\r
+  command should be sent without waiting for the BSY clear and DRDY\r
+  set.\r
+  This function is called by IdeBlkIoReset(), \r
+  a interface function of Block I/O protocol.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @retval EFI_SUCCESS\r
+  Soft reset completes successfully.\r
+  \r
+  @retval EFI_DEVICE_ERROR\r
+  Any step during the reset process is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiSoftReset (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+{\r
+  UINT8       Command;\r
+  UINT8       DeviceSelect;\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // for ATAPI device, no need to wait DRDY ready after device selecting.\r
+  // (bit7 and bit5 are both set to 1 for backward compatibility)\r
+  //\r
+  DeviceSelect = (UINT8) (((bit7 | bit5) | (IdeDev->Device << 4)));\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);\r
+\r
+  Command = ATAPI_SOFT_RESET_CMD;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, Command);\r
+\r
+  //\r
+  // BSY cleared is the only status return to the host by the device\r
+  // when reset is completed.\r
+  // slave device needs at most 31s to clear BSY\r
+  //\r
+  Status = WaitForBSYClear (IdeDev, 31000);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  \r
+  //\r
+  // stall 5 seconds to make the device status stable\r
+  //\r
+  gBS->Stall (5000000);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is the ATAPI implementation for ReadBlocks in the\r
+  Block I/O Protocol interface.\r
+\r
+  @param[in] *IdeBlkIoDev\r
+  Indicates the calling context.\r
+\r
+  @param[in] MediaId\r
+  The media id that the read request is for.\r
+\r
+  @param[in] LBA\r
+  The starting logical block address to read from \r
+  on the device.\r
+\r
+  @param[in] BufferSize\r
+  The size of the Buffer in bytes. This must be a\r
+  multiple of the intrinsic block size of the device.\r
+\r
+  @param[out] *Buffer\r
+  A pointer to the destination buffer for the data. \r
+  The caller is responsible for either having implicit\r
+  or explicit ownership of the memory that data is read into.\r
+\r
+  @retval EFI_SUCCESS\r
+  Read Blocks successfully.\r
+  \r
+  @retval EFI_DEVICE_ERROR\r
+  Read Blocks failed.\r
+  \r
+  @retval EFI_NO_MEDIA\r
+  There is no media in the device.\r
+  \r
+  @retval EFI_MEDIA_CHANGED\r
+  The MediaId is not for the current media.\r
+  \r
+  @retval EFI_BAD_BUFFER_SIZE\r
+  The BufferSize parameter is not a multiple of the\r
+  intrinsic block size of the device.\r
+  \r
+  @retval EFI_INVALID_PARAMETER\r
+  The read request contains LBAs that are not valid,\r
+  or the data buffer is not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiBlkIoReadBlocks (\r
+  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,\r
+  IN UINT32           MediaId,\r
+  IN EFI_LBA          LBA,\r
+  IN UINTN            BufferSize,\r
+  OUT VOID            *Buffer\r
+  )\r
+{\r
+  EFI_BLOCK_IO_MEDIA  *Media;\r
+  UINTN               BlockSize;\r
+  UINTN               NumberOfBlocks;\r
+  EFI_STATUS          Status;\r
+\r
+  BOOLEAN             MediaChange;\r
+\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // ATAPI device media is removable, so it is a must\r
+  // to detect media first before read operation\r
+  //\r
+  MediaChange = FALSE;\r
+  Status      = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    if (IdeBlkIoDevice->Cache != NULL) {\r
+      gBS->FreePool (IdeBlkIoDevice->Cache);\r
+      IdeBlkIoDevice->Cache = NULL;\r
+    }\r
+\r
+    return Status;\r
+  }\r
+  //\r
+  // Get the intrinsic block size\r
+  //\r
+  Media           = IdeBlkIoDevice->BlkIo.Media;\r
+  BlockSize       = Media->BlockSize;\r
+\r
+  NumberOfBlocks  = BufferSize / BlockSize;\r
+\r
+  if (!(Media->MediaPresent)) {\r
+\r
+    if (IdeBlkIoDevice->Cache != NULL) {\r
+      gBS->FreePool (IdeBlkIoDevice->Cache);\r
+      IdeBlkIoDevice->Cache = NULL;\r
+    }\r
+    return EFI_NO_MEDIA;\r
+\r
+  }\r
+\r
+  if ((MediaId != Media->MediaId) || MediaChange) {\r
+\r
+    if (IdeBlkIoDevice->Cache != NULL) {\r
+      gBS->FreePool (IdeBlkIoDevice->Cache);\r
+      IdeBlkIoDevice->Cache = NULL;\r
+    }\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  if (BufferSize % BlockSize != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (LBA > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // if all the parameters are valid, then perform read sectors command\r
+  // to transfer data from device to host.\r
+  //\r
+  Status = AtapiReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  \r
+  //\r
+  // Read blocks succeeded\r
+  //\r
+  \r
+  //\r
+  // save the first block to the cache for performance\r
+  //\r
+  if (LBA == 0 && !IdeBlkIoDevice->Cache) {\r
+    IdeBlkIoDevice->Cache = AllocatePool (BlockSize);\r
+    if (IdeBlkIoDevice != NULL) {\r
+      CopyMem ((UINT8 *) IdeBlkIoDevice->Cache, (UINT8 *) Buffer, BlockSize);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+  This function is the ATAPI implementation for WriteBlocks in the\r
+  Block I/O Protocol interface.\r
+\r
+  @param[in] *This\r
+  Indicates the calling context.\r
+\r
+  @param[in] MediaId\r
+  The media id that the write request is for.\r
+\r
+  @param[in] LBA\r
+  The starting logical block address to write onto \r
+  the device.\r
+\r
+  @param[in] BufferSize\r
+  The size of the Buffer in bytes. This must be a\r
+  multiple of the intrinsic block size of the device.\r
+\r
+  @param[out] *Buffer\r
+  A pointer to the source buffer for the data. \r
+  The caller is responsible for either having implicit\r
+  or explicit ownership of the memory that data is \r
+  written from.\r
+\r
+  @retval EFI_SUCCESS\r
+  Write Blocks successfully.\r
+  \r
+  @retval EFI_DEVICE_ERROR\r
+  Write Blocks failed.\r
+  \r
+  @retval EFI_NO_MEDIA\r
+  There is no media in the device.\r
+  \r
+  @retval EFI_MEDIA_CHANGE\r
+  The MediaId is not for the current media.\r
+  \r
+  @retval EFI_BAD_BUFFER_SIZE\r
+  The BufferSize parameter is not a multiple of the\r
+  intrinsic block size of the device.\r
+  \r
+  @retval EFI_INVALID_PARAMETER\r
+  The write request contains LBAs that are not valid,\r
+  or the data buffer is not valid.\r
+\r
+  TODO:    EFI_MEDIA_CHANGED - add return value to function comment\r
+  TODO:    EFI_WRITE_PROTECTED - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+AtapiBlkIoWriteBlocks (\r
+  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,\r
+  IN UINT32           MediaId,\r
+  IN EFI_LBA          LBA,\r
+  IN UINTN            BufferSize,\r
+  OUT VOID            *Buffer\r
+  )\r
+{\r
+\r
+  EFI_BLOCK_IO_MEDIA  *Media;\r
+  UINTN               BlockSize;\r
+  UINTN               NumberOfBlocks;\r
+  EFI_STATUS          Status;\r
+  BOOLEAN             MediaChange;\r
+\r
+  if (LBA == 0 && IdeBlkIoDevice->Cache) {\r
+    gBS->FreePool (IdeBlkIoDevice->Cache);\r
+    IdeBlkIoDevice->Cache = NULL;\r
+  }\r
+\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // ATAPI device media is removable,\r
+  // so it is a must to detect media first before write operation\r
+  //\r
+  MediaChange = FALSE;\r
+  Status      = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    if (LBA == 0 && IdeBlkIoDevice->Cache) {\r
+      gBS->FreePool (IdeBlkIoDevice->Cache);\r
+      IdeBlkIoDevice->Cache = NULL;\r
+    }\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Get the intrinsic block size\r
+  //\r
+  Media           = IdeBlkIoDevice->BlkIo.Media;\r
+  BlockSize       = Media->BlockSize;\r
+  NumberOfBlocks  = BufferSize / BlockSize;\r
+\r
+  if (!(Media->MediaPresent)) {\r
+\r
+    if (LBA == 0 && IdeBlkIoDevice->Cache) {\r
+      gBS->FreePool (IdeBlkIoDevice->Cache);\r
+      IdeBlkIoDevice->Cache = NULL;\r
+    }\r
+    return EFI_NO_MEDIA;\r
+  }\r
+\r
+  if ((MediaId != Media->MediaId) || MediaChange) {\r
+\r
+    if (LBA == 0 && IdeBlkIoDevice->Cache) {\r
+      gBS->FreePool (IdeBlkIoDevice->Cache);\r
+      IdeBlkIoDevice->Cache = NULL;\r
+    }\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  if (Media->ReadOnly) {\r
+    return EFI_WRITE_PROTECTED;\r
+  }\r
+\r
+  if (BufferSize % BlockSize != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (LBA > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // if all the parameters are valid,\r
+  // then perform write sectors command to transfer data from host to device.\r
+  //\r
+  Status = AtapiWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+  This function is used to parse sense data. Only the first\r
+  sense data is honoured.\r
+\r
+  @param[in] IdeDev     Indicates the calling context.\r
+  @param[in] SenseCount Count of sense data.\r
+  @param[out] Result    The parsed result.\r
+\r
+  @retval EFI_SUCCESS           Successfully parsed.\r
+  @retval EFI_INVALID_PARAMETER Count of sense data is zero.\r
+\r
+**/\r
+EFI_STATUS\r
+ParseSenseData (\r
+  IN IDE_BLK_IO_DEV     *IdeDev,\r
+  IN UINTN              SenseCount,\r
+  OUT SENSE_RESULT      *Result\r
+  )\r
+{\r
+  REQUEST_SENSE_DATA      *SenseData;\r
+\r
+  if (SenseCount == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Only use the first sense data\r
+  //\r
+  SenseData = IdeDev->SenseData;\r
+  *Result   = SenseOtherSense;\r
+\r
+  switch (SenseData->sense_key) {\r
+  case SK_NO_SENSE:\r
+    *Result = SenseNoSenseKey;\r
+    break;\r
+  case SK_NOT_READY:\r
+    switch (SenseData->addnl_sense_code) {\r
+    case ASC_NO_MEDIA:\r
+      *Result = SenseNoMedia;\r
+      break;\r
+    case ASC_MEDIA_UPSIDE_DOWN:\r
+      *Result = SenseMediaError;\r
+      break;\r
+    case ASC_NOT_READY:\r
+      if (SenseData->addnl_sense_code_qualifier == ASCQ_IN_PROGRESS) {\r
+        *Result = SenseDeviceNotReadyNeedRetry;\r
+      } else {\r
+        *Result = SenseDeviceNotReadyNoRetry;\r
+      }\r
+      break;\r
+    }\r
+    break;\r
+  case SK_UNIT_ATTENTION:\r
+    if (SenseData->addnl_sense_code == ASC_MEDIA_CHANGE) {\r
+      *Result = SenseMediaChange;\r
+    }\r
+    break;\r
+  case SK_MEDIUM_ERROR:\r
+    switch (SenseData->addnl_sense_code) {\r
+    case ASC_MEDIA_ERR1:\r
+    case ASC_MEDIA_ERR2:\r
+    case ASC_MEDIA_ERR3:\r
+    case ASC_MEDIA_ERR4:\r
+      *Result = SenseMediaError;\r
+      break;\r
+    }\r
+    break;\r
+  default:\r
+    break;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function reads the pending data in the device.\r
+\r
+  @param[in] IdeDev   Indicates the calling context.\r
+\r
+  @retval EFI_SUCCESS   Successfully read.\r
+  @retval EFI_NOT_READY The BSY is set avoiding reading.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiReadPendingData (\r
+  IN IDE_BLK_IO_DEV     *IdeDev\r
+  )\r
+{\r
+  UINT8     AltRegister;\r
+  UINT16    TempWordBuffer;\r
+\r
+  AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
+  if ((AltRegister & BSY) == BSY) {\r
+    return EFI_NOT_READY;\r
+  }\r
+  if ((AltRegister & (BSY | DRQ)) == DRQ) {\r
+    TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);\r
+    while ((TempWordBuffer & (BSY | DRQ)) == DRQ) {\r
+      IDEReadPortWMultiple (\r
+        IdeDev->PciIo,\r
+        IdeDev->IoPort->Data, \r
+        1, \r
+        &TempWordBuffer\r
+        );\r
+      TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);\r
+    }\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  WriteProtected TODO: add argument description\r
+\r
+  @retval  EFI_DEVICE_ERROR TODO: Add description for return value\r
+  @retval  EFI_DEVICE_ERROR TODO: Add description for return value\r
+  @retval  EFI_SUCCESS TODO: Add description for return value\r
+\r
+**/\r
+EFI_STATUS\r
+IsLS120orZipWriteProtected (\r
+  IN  IDE_BLK_IO_DEV    *IdeDev,\r
+  OUT BOOLEAN           *WriteProtected\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  *WriteProtected = FALSE;\r
+\r
+  Status          = LS120EnableMediaStatus (IdeDev, TRUE);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // the Get Media Status Command is only valid\r
+  // if a Set Features/Enable Media Status Command has been priviously issued.\r
+  //\r
+  if (LS120GetMediaStatus (IdeDev) == EFI_WRITE_PROTECTED) {\r
+\r
+    *WriteProtected = TRUE;\r
+  } else {\r
+\r
+    *WriteProtected = FALSE;\r
+  }\r
+\r
+  //\r
+  // After Get Media Status Command completes,\r
+  // Set Features/Disable Media Command should be sent.\r
+  //\r
+  Status = LS120EnableMediaStatus (IdeDev, FALSE);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c b/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c
new file mode 100644 (file)
index 0000000..4b4a8ef
--- /dev/null
@@ -0,0 +1,1824 @@
+/** @file\r
+  Copyright (c) 2006, Intel Corporation\r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "idebus.h"\r
+\r
+BOOLEAN ChannelDeviceDetected = FALSE;\r
+BOOLEAN SlaveDeviceExist      = FALSE;\r
+UINT8   SlaveDeviceType       = INVALID_DEVICE_TYPE;\r
+BOOLEAN MasterDeviceExist     = FALSE;\r
+UINT8   MasterDeviceType      = INVALID_DEVICE_TYPE;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  PciIo TODO: add argument description\r
+  @param  Port TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+UINT8\r
+IDEReadPortB (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port\r
+  )\r
+{\r
+  UINT8 Data;\r
+\r
+  Data = 0;\r
+  //\r
+  // perform 1-byte data read from register\r
+  //\r
+  PciIo->Io.Read (\r
+              PciIo,\r
+              EfiPciIoWidthUint8,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              (UINT64) Port,\r
+              1,\r
+              &Data\r
+              );\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Reads multiple words of data from the IDE data port.\r
+  Call the IO abstraction once to do the complete read,\r
+  not one word at a time\r
+\r
+  @param  PciIo Pointer to the EFI_PCI_IO instance\r
+  @param  Port IO port to read\r
+  @param  Count No. of UINT16's to read\r
+  @param  Buffer Pointer to the data buffer for read\r
+\r
+**/\r
+VOID\r
+IDEReadPortWMultiple (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINTN                 Count,\r
+  IN  VOID                  *Buffer\r
+  )\r
+{\r
+  UINT16  *AlignedBuffer;\r
+  UINT16  *WorkingBuffer;\r
+  UINTN   Size;\r
+\r
+  //\r
+  // Prepare an 16-bit alligned working buffer. CpuIo will return failure and\r
+  // not perform actual I/O operations if buffer pointer passed in is not at\r
+  // natural boundary. The "Buffer" argument is passed in by user and may not\r
+  // at 16-bit natural boundary.\r
+  //\r
+  Size = sizeof (UINT16) * Count;\r
+\r
+  gBS->AllocatePool (\r
+        EfiBootServicesData,\r
+        Size + 1,\r
+        (VOID**)&WorkingBuffer\r
+        );\r
+\r
+  AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));\r
+\r
+  //\r
+  // Perform UINT16 data read from FIFO\r
+  //\r
+  PciIo->Io.Read (\r
+              PciIo,\r
+              EfiPciIoWidthFifoUint16,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              (UINT64) Port,\r
+              Count,\r
+              (UINT16*)AlignedBuffer\r
+              );\r
+\r
+  //\r
+  // Copy data to user buffer\r
+  //\r
+  CopyMem (Buffer, (UINT16*)AlignedBuffer, Size);\r
+  gBS->FreePool (WorkingBuffer);\r
+}\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  PciIo TODO: add argument description\r
+  @param  Port TODO: add argument description\r
+  @param  Data TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+VOID\r
+IDEWritePortB (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINT8                 Data\r
+  )\r
+{\r
+  //\r
+  // perform 1-byte data write to register\r
+  //\r
+  PciIo->Io.Write (\r
+              PciIo,\r
+              EfiPciIoWidthUint8,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              (UINT64) Port,\r
+              1,\r
+              &Data\r
+              );\r
+\r
+}\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  PciIo TODO: add argument description\r
+  @param  Port TODO: add argument description\r
+  @param  Data TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+VOID\r
+IDEWritePortW (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINT16                Data\r
+  )\r
+{\r
+  //\r
+  // perform 1-word data write to register\r
+  //\r
+  PciIo->Io.Write (\r
+              PciIo,\r
+              EfiPciIoWidthUint16,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              (UINT64) Port,\r
+              1,\r
+              &Data\r
+              );\r
+}\r
+\r
+/**\r
+  Write multiple words of data to the IDE data port.\r
+  Call the IO abstraction once to do the complete read,\r
+  not one word at a time\r
+\r
+  @param  PciIo Pointer to the EFI_PCI_IO instance\r
+  @param  Port IO port to read\r
+  @param  Count No. of UINT16's to read\r
+  @param  Buffer Pointer to the data buffer for read\r
+\r
+**/\r
+VOID\r
+IDEWritePortWMultiple (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINTN                 Count,\r
+  IN  VOID                  *Buffer\r
+  )\r
+{\r
+  UINT16  *AlignedBuffer;\r
+  UINT32  *WorkingBuffer;\r
+  UINTN   Size;\r
+\r
+  //\r
+  // Prepare an 16-bit alligned working buffer. CpuIo will return failure and\r
+  // not perform actual I/O operations if buffer pointer passed in is not at\r
+  // natural boundary. The "Buffer" argument is passed in by user and may not\r
+  // at 16-bit natural boundary.\r
+  //\r
+  Size = sizeof (UINT16) * Count;\r
+\r
+  gBS->AllocatePool (\r
+        EfiBootServicesData,\r
+        Size + 1,\r
+        (VOID **) &WorkingBuffer\r
+        );\r
+\r
+  AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));\r
+\r
+  //\r
+  // Copy data from user buffer to working buffer\r
+  //\r
+  CopyMem ((UINT16 *) AlignedBuffer, Buffer, Size);\r
+\r
+  //\r
+  // perform UINT16 data write to the FIFO\r
+  //\r
+  PciIo->Io.Write (\r
+              PciIo,\r
+              EfiPciIoWidthFifoUint16,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              (UINT64) Port,\r
+              Count,\r
+              (UINT16 *) AlignedBuffer\r
+              );\r
+\r
+  gBS->FreePool (WorkingBuffer);\r
+}\r
+\r
+//\r
+// GetIdeRegistersBaseAddr\r
+//\r
+/**\r
+  Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,\r
+  use fixed addresses. In Native-PCI mode, get base addresses from BARs in\r
+  the PCI IDE controller's Configuration Space.\r
+\r
+  The steps to get IDE IO port registers' base addresses for each channel\r
+  as follows:\r
+\r
+  1. Examine the Programming Interface byte of the Class Code fields in PCI IDE\r
+  controller's Configuration Space to determine the operating mode.\r
+\r
+  2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.\r
+  <pre>\r
+  ___________________________________________\r
+  |           | Command Block | Control Block |\r
+  |  Channel  |   Registers   |   Registers   |\r
+  |___________|_______________|_______________|\r
+  |  Primary  |  1F0h - 1F7h  |  3F6h - 3F7h  |\r
+  |___________|_______________|_______________|\r
+  | Secondary |  170h - 177h  |  376h - 377h  |\r
+  |___________|_______________|_______________|\r
+\r
+  Table 1. Compatibility resource mappings\r
+  </pre>\r
+\r
+  b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs\r
+  in IDE controller's PCI Configuration Space, shown in the Table 2 below.\r
+  <pre>\r
+  ___________________________________________________\r
+  |           |   Command Block   |   Control Block   |\r
+  |  Channel  |     Registers     |     Registers     |\r
+  |___________|___________________|___________________|\r
+  |  Primary  | BAR at offset 0x10| BAR at offset 0x14|\r
+  |___________|___________________|___________________|\r
+  | Secondary | BAR at offset 0x18| BAR at offset 0x1C|\r
+  |___________|___________________|___________________|\r
+\r
+  Table 2. BARs for Register Mapping\r
+  </pre>\r
+  @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for\r
+  primary, 0374h for secondary. So 2 bytes extra offset should be\r
+  added to the base addresses read from BARs.\r
+\r
+  For more details, please refer to PCI IDE Controller Specification and Intel\r
+  ICH4 Datasheet.\r
+\r
+  @param  PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance\r
+  @param  IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to\r
+  receive IDE IO port registers' base addresses\r
+\r
+**/\r
+EFI_STATUS\r
+GetIdeRegistersBaseAddr (\r
+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,\r
+  OUT IDE_REGISTERS_BASE_ADDR     *IdeRegsBaseAddr\r
+  )\r
+// TODO:    EFI_UNSUPPORTED - add return value to function comment\r
+// TODO:    EFI_UNSUPPORTED - add return value to function comment\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+{\r
+  EFI_STATUS  Status;\r
+  PCI_TYPE00  PciData;\r
+\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        0,\r
+                        sizeof (PciData),\r
+                        &PciData\r
+                        );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {\r
+    IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr  = 0x1f0;\r
+    IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr  = 0x3f6;\r
+    IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr     =\r
+    (UINT16)((PciData.Device.Bar[4] & 0x0000fff0));\r
+  } else {\r
+    //\r
+    // The BARs should be of IO type\r
+    //\r
+    if ((PciData.Device.Bar[0] & bit0) == 0 ||\r
+        (PciData.Device.Bar[1] & bit0) == 0) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr  =\r
+    (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);\r
+    IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr  =\r
+    (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);\r
+    IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr     =\r
+    (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
+  }\r
+\r
+  if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {\r
+    IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr  = 0x170;\r
+    IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr  = 0x376;\r
+    IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr     =\r
+    (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
+  } else {\r
+    //\r
+    // The BARs should be of IO type\r
+    //\r
+    if ((PciData.Device.Bar[2] & bit0) == 0 ||\r
+        (PciData.Device.Bar[3] & bit0) == 0) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr  =\r
+    (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);\r
+    IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr  =\r
+    (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);\r
+    IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr     =\r
+    (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is used to requery IDE resources. The IDE controller will\r
+  probably switch between native and legacy modes during the EFI->CSM->OS\r
+  transfer. We do this everytime before an BlkIo operation to ensure its\r
+  succeess.\r
+\r
+  @param  IdeDev The BLK_IO private data which specifies the IDE device\r
+\r
+**/\r
+EFI_STATUS\r
+ReassignIdeResources (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+{\r
+  EFI_STATUS              Status;\r
+  IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel];\r
+  UINT16                  CommandBlockBaseAddr;\r
+  UINT16                  ControlBlockBaseAddr;\r
+\r
+  //\r
+  // Requery IDE IO port registers' base addresses in case of the switch of\r
+  // native and legacy modes\r
+  //\r
+  Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS));\r
+  CommandBlockBaseAddr                = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr;\r
+  ControlBlockBaseAddr                = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr;\r
+\r
+  IdeDev->IoPort->Data                = CommandBlockBaseAddr;\r
+  (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);\r
+  IdeDev->IoPort->SectorCount         = (UINT16) (CommandBlockBaseAddr + 0x02);\r
+  IdeDev->IoPort->SectorNumber        = (UINT16) (CommandBlockBaseAddr + 0x03);\r
+  IdeDev->IoPort->CylinderLsb         = (UINT16) (CommandBlockBaseAddr + 0x04);\r
+  IdeDev->IoPort->CylinderMsb         = (UINT16) (CommandBlockBaseAddr + 0x05);\r
+  IdeDev->IoPort->Head                = (UINT16) (CommandBlockBaseAddr + 0x06);\r
+\r
+  (*(UINT16 *) &IdeDev->IoPort->Reg)  = (UINT16) (CommandBlockBaseAddr + 0x07);\r
+  (*(UINT16 *) &IdeDev->IoPort->Alt)  = ControlBlockBaseAddr;\r
+  IdeDev->IoPort->DriveAddress        = (UINT16) (ControlBlockBaseAddr + 0x01);\r
+  IdeDev->IoPort->MasterSlave         = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0);\r
+\r
+  IdeDev->IoPort->BusMasterBaseAddr   = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// DiscoverIdeDevice\r
+//\r
+/**\r
+  Detect if there is disk connected to this port\r
+\r
+  @param  IdeDev The BLK_IO private data which specifies the IDE device\r
+\r
+**/\r
+EFI_STATUS\r
+DiscoverIdeDevice (\r
+  IN IDE_BLK_IO_DEV *IdeDev\r
+  )\r
+// TODO:    EFI_NOT_FOUND - add return value to function comment\r
+// TODO:    EFI_NOT_FOUND - add return value to function comment\r
+// TODO:    EFI_SUCCESS - add return value to function comment\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // If a channel has not been checked, check it now. Then set it to "checked" state\r
+  // After this step, all devices in this channel have been checked.\r
+  //\r
+  if (ChannelDeviceDetected == FALSE) {\r
+    Status = DetectIDEController (IdeDev);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+  }\r
+\r
+  Status = EFI_NOT_FOUND;\r
+\r
+  //\r
+  // Device exists. test if it is an ATA device.\r
+  // Prefer the result from DetectIDEController,\r
+  // if failed, try another device type to handle\r
+  // devices that not follow the spec.\r
+  //\r
+  if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {\r
+    if (MasterDeviceType == ATA_DEVICE_TYPE) {\r
+      Status = ATAIdentify (IdeDev);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = ATAPIIdentify (IdeDev);\r
+        if (!EFI_ERROR (Status)) {\r
+          MasterDeviceType = ATAPI_DEVICE_TYPE;\r
+        }\r
+      }\r
+    } else {\r
+      Status = ATAPIIdentify (IdeDev);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = ATAIdentify (IdeDev);\r
+        if (!EFI_ERROR (Status)) {\r
+          MasterDeviceType = ATA_DEVICE_TYPE;\r
+        }\r
+      }\r
+    }\r
+  }\r
+  if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {\r
+    if (SlaveDeviceType == ATA_DEVICE_TYPE) {\r
+      Status = ATAIdentify (IdeDev);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = ATAPIIdentify (IdeDev);\r
+        if (!EFI_ERROR (Status)) {\r
+          SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
+        }\r
+      }\r
+    } else {\r
+      Status = ATAPIIdentify (IdeDev);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = ATAIdentify (IdeDev);\r
+        if (!EFI_ERROR (Status)) {\r
+          SlaveDeviceType = ATA_DEVICE_TYPE;\r
+        }\r
+      }\r
+    }\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  //\r
+  // Init Block I/O interface\r
+  //\r
+  IdeDev->BlkIo.Revision            = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
+  IdeDev->BlkIo.Reset               = IDEBlkIoReset;\r
+  IdeDev->BlkIo.ReadBlocks          = IDEBlkIoReadBlocks;\r
+  IdeDev->BlkIo.WriteBlocks         = IDEBlkIoWriteBlocks;\r
+  IdeDev->BlkIo.FlushBlocks         = IDEBlkIoFlushBlocks;\r
+\r
+  IdeDev->BlkMedia.LogicalPartition = FALSE;\r
+  IdeDev->BlkMedia.WriteCaching     = FALSE;\r
+\r
+  //\r
+  // Init Disk Info interface\r
+  //\r
+  gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID));\r
+  IdeDev->DiskInfo.Inquiry    = IDEDiskInfoInquiry;\r
+  IdeDev->DiskInfo.Identify   = IDEDiskInfoIdentify;\r
+  IdeDev->DiskInfo.SenseData  = IDEDiskInfoSenseData;\r
+  IdeDev->DiskInfo.WhichIde   = IDEDiskInfoWhichIde;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This interface is used to initialize all state data related to the detection of one\r
+  channel.\r
+\r
+  @retval EFI_SUCCESS Completed Successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeIDEChannelData (\r
+  VOID\r
+  )\r
+{\r
+  ChannelDeviceDetected = FALSE;\r
+  MasterDeviceExist = FALSE;\r
+  MasterDeviceType  = 0xff;\r
+  SlaveDeviceExist  = FALSE;\r
+  SlaveDeviceType   = 0xff;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is called by DiscoverIdeDevice(). It is used for detect\r
+  whether the IDE device exists in the specified Channel as the specified\r
+  Device Number.\r
+\r
+  There is two IDE channels: one is Primary Channel, the other is\r
+  Secondary Channel.(Channel is the logical name for the physical "Cable".)\r
+  Different channel has different register group.\r
+\r
+  On each IDE channel, at most two IDE devices attach,\r
+  one is called Device 0 (Master device), the other is called Device 1\r
+  (Slave device). The devices on the same channel co-use the same register\r
+  group, so before sending out a command for a specified device via command\r
+  register, it is a must to select the current device to accept the command\r
+  by set the device number in the Head/Device Register.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @retval TRUE\r
+  successfully detects device.\r
+\r
+  @retval FALSE\r
+  any failure during detection process will return this\r
+  value.\r
+\r
+  @note\r
+  TODO:    EFI_SUCCESS - add return value to function comment\r
+  TODO:    EFI_NOT_FOUND - add return value to function comment\r
+\r
+**/\r
+EFI_STATUS\r
+DetectIDEController (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       SectorCountReg;\r
+  UINT8       LBALowReg;\r
+  UINT8       LBAMidReg;\r
+  UINT8       LBAHighReg;\r
+  UINT8       InitStatusReg;\r
+  UINT8       StatusReg;\r
+\r
+  //\r
+  // Select slave device\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((1 << 4) | 0xe0)\r
+    );\r
+  gBS->Stall (100);\r
+\r
+  //\r
+  // Save the init slave status register\r
+  //\r
+  InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+\r
+  //\r
+  // Select Master back\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((0 << 4) | 0xe0)\r
+    );\r
+  gBS->Stall (100);\r
+\r
+  //\r
+  // Send ATA Device Execut Diagnostic command.\r
+  // This command should work no matter DRDY is ready or not\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);\r
+\r
+  Status    = WaitForBSYClear (IdeDev, 3500);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Read device signature\r
+  //\r
+  //\r
+  // Select Master\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((0 << 4) | 0xe0)\r
+    );\r
+  gBS->Stall (100);\r
+  SectorCountReg = IDEReadPortB (\r
+                     IdeDev->PciIo,\r
+                     IdeDev->IoPort->SectorCount\r
+                     );\r
+  LBALowReg      = IDEReadPortB (\r
+                     IdeDev->PciIo,\r
+                     IdeDev->IoPort->SectorNumber\r
+                     );\r
+  LBAMidReg      = IDEReadPortB (\r
+                     IdeDev->PciIo,\r
+                     IdeDev->IoPort->CylinderLsb\r
+                     );\r
+  LBAHighReg     = IDEReadPortB (\r
+                     IdeDev->PciIo,\r
+                     IdeDev->IoPort->CylinderMsb\r
+                     );\r
+  if ((SectorCountReg == 0x1) &&\r
+      (LBALowReg      == 0x1) &&\r
+      (LBAMidReg      == 0x0) &&\r
+      (LBAHighReg     == 0x0)) {\r
+    MasterDeviceExist = TRUE;\r
+    MasterDeviceType  = ATA_DEVICE_TYPE;\r
+  } else {\r
+    if ((LBAMidReg      == 0x14) &&\r
+        (LBAHighReg     == 0xeb)) {\r
+      MasterDeviceExist = TRUE;\r
+      MasterDeviceType  = ATAPI_DEVICE_TYPE;\r
+    }\r
+  }\r
+\r
+  //\r
+  // For some Hard Drive, it takes some time to get\r
+  // the right signature when operating in single slave mode.\r
+  // We stall 20ms to work around this.\r
+  //\r
+  if (!MasterDeviceExist) {\r
+    gBS->Stall (20000);\r
+  }\r
+\r
+  //\r
+  // Select Slave\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((1 << 4) | 0xe0)\r
+    );\r
+  gBS->Stall (100);\r
+  SectorCountReg = IDEReadPortB (\r
+                     IdeDev->PciIo,\r
+                     IdeDev->IoPort->SectorCount\r
+                     );\r
+  LBALowReg  = IDEReadPortB (\r
+                 IdeDev->PciIo,\r
+                 IdeDev->IoPort->SectorNumber\r
+                 );\r
+  LBAMidReg  = IDEReadPortB (\r
+                 IdeDev->PciIo,\r
+                 IdeDev->IoPort->CylinderLsb\r
+                 );\r
+  LBAHighReg = IDEReadPortB (\r
+                 IdeDev->PciIo,\r
+                 IdeDev->IoPort->CylinderMsb\r
+                 );\r
+  StatusReg  = IDEReadPortB (\r
+                 IdeDev->PciIo,\r
+                 IdeDev->IoPort->Reg.Status\r
+                 );\r
+  if ((SectorCountReg == 0x1) &&\r
+      (LBALowReg      == 0x1) &&\r
+      (LBAMidReg      == 0x0) &&\r
+      (LBAHighReg     == 0x0)) {\r
+    SlaveDeviceExist = TRUE;\r
+    SlaveDeviceType  = ATA_DEVICE_TYPE;\r
+  } else {\r
+    if ((LBAMidReg     == 0x14) &&\r
+        (LBAHighReg    == 0xeb)) {\r
+      SlaveDeviceExist = TRUE;\r
+      SlaveDeviceType  = ATAPI_DEVICE_TYPE;\r
+    }\r
+  }\r
+\r
+  //\r
+  // When single master is plugged, slave device\r
+  // will be wrongly detected. Here's the workaround\r
+  // for ATA devices by detecting DRY bit in status\r
+  // register.\r
+  // NOTE: This workaround doesn't apply to ATAPI.\r
+  //\r
+  if (MasterDeviceExist && SlaveDeviceExist &&\r
+      (StatusReg & DRDY) == 0               &&\r
+      (InitStatusReg & DRDY) == 0           &&\r
+      MasterDeviceType == SlaveDeviceType   &&\r
+      SlaveDeviceType != ATAPI_DEVICE_TYPE) {\r
+    SlaveDeviceExist = FALSE;\r
+  }\r
+\r
+  //\r
+  // Indicate this channel has been detected\r
+  //\r
+  ChannelDeviceDetected = TRUE;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is used to poll for the DRQ bit clear in the Status\r
+  Register. DRQ is cleared when the device is finished transferring data.\r
+  So this function is called after data transfer is finished.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] TimeoutInMilliSeconds\r
+  used to designate the timeout for the DRQ clear.\r
+\r
+  @retval EFI_SUCCESS\r
+  DRQ bit clear within the time out.\r
+\r
+  @retval EFI_TIMEOUT\r
+  DRQ bit not clear within the time out.\r
+\r
+  @note\r
+  Read Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRQClear (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO:    IdeDev - add argument and description to function comment\r
+// TODO:    TimeoutInMilliSeconds - add argument and description to function comment\r
+// TODO:    EFI_ABORTED - add return value to function comment\r
+{\r
+  UINT32  Delay;\r
+  UINT8   StatusRegister;\r
+  UINT8   ErrorRegister;\r
+\r
+  Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+  do {\r
+\r
+    StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+\r
+    //\r
+    // wait for BSY == 0 and DRQ == 0\r
+    //\r
+    if ((StatusRegister & (DRQ | BSY)) == 0) {\r
+      break;\r
+    }\r
+\r
+    if ((StatusRegister & (BSY | ERR)) == ERR) {\r
+\r
+      ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+      if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    //\r
+    //  Stall for 30 us\r
+    //\r
+    gBS->Stall (30);\r
+\r
+    Delay--;\r
+\r
+  } while (Delay);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is used to poll for the DRQ bit clear in the Alternate\r
+  Status Register. DRQ is cleared when the device is finished\r
+  transferring data. So this function is called after data transfer\r
+  is finished.\r
+\r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] TimeoutInMilliSeconds\r
+  used to designate the timeout for the DRQ clear.\r
+\r
+  @retval EFI_SUCCESS\r
+  DRQ bit clear within the time out.\r
+\r
+  @retval EFI_TIMEOUT\r
+  DRQ bit not clear within the time out.\r
+\r
+  @note\r
+  Read Alternate Status Register will not clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRQClear2 (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO:    IdeDev - add argument and description to function comment\r
+// TODO:    TimeoutInMilliSeconds - add argument and description to function comment\r
+// TODO:    EFI_ABORTED - add return value to function comment\r
+{\r
+  UINT32  Delay;\r
+  UINT8   AltRegister;\r
+  UINT8   ErrorRegister;\r
+\r
+  Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+  do {\r
+\r
+    AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
+\r
+    //\r
+    //  wait for BSY == 0 and DRQ == 0\r
+    //\r
+    if ((AltRegister & (DRQ | BSY)) == 0) {\r
+      break;\r
+    }\r
+\r
+    if ((AltRegister & (BSY | ERR)) == ERR) {\r
+\r
+      ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+      if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Stall for 30 us\r
+    //\r
+    gBS->Stall (30);\r
+\r
+    Delay--;\r
+\r
+  } while (Delay);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is used to poll for the DRQ bit set in the\r
+  Status Register.\r
+  DRQ is set when the device is ready to transfer data. So this function\r
+  is called after the command is sent to the device and before required\r
+  data is transferred.\r
+\r
+  @param[in] IDE_BLK_IO_DEV  IN    *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure,used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] UINTN     IN    TimeoutInMilliSeconds\r
+  used to designate the timeout for the DRQ ready.\r
+\r
+  @retval EFI_SUCCESS\r
+  DRQ bit set within the time out.\r
+\r
+  @retval EFI_TIMEOUT\r
+  DRQ bit not set within the time out.\r
+\r
+  @retval EFI_ABORTED\r
+  DRQ bit not set caused by the command abort.\r
+\r
+  @note\r
+  Read Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRQReady (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO:    IdeDev - add argument and description to function comment\r
+// TODO:    TimeoutInMilliSeconds - add argument and description to function comment\r
+{\r
+  UINT32  Delay;\r
+  UINT8   StatusRegister;\r
+  UINT8   ErrorRegister;\r
+\r
+  Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+  do {\r
+    //\r
+    //  read Status Register will clear interrupt\r
+    //\r
+    StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+\r
+    //\r
+    //  BSY==0,DRQ==1\r
+    //\r
+    if ((StatusRegister & (BSY | DRQ)) == DRQ) {\r
+      break;\r
+    }\r
+\r
+    if ((StatusRegister & (BSY | ERR)) == ERR) {\r
+\r
+      ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+      if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Stall for 30 us\r
+    //\r
+    gBS->Stall (30);\r
+\r
+    Delay--;\r
+  } while (Delay);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is used to poll for the DRQ bit set in the\r
+  Alternate Status Register. DRQ is set when the device is ready to\r
+  transfer data. So this function is called after the command\r
+  is sent to the device and before required data is transferred.\r
+\r
+  @param[in] IDE_BLK_IO_DEV  IN    *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] UINTN     IN    TimeoutInMilliSeconds\r
+  used to designate the timeout for the DRQ ready.\r
+\r
+  @retval EFI_SUCCESS\r
+  DRQ bit set within the time out.\r
+\r
+  @retval EFI_TIMEOUT\r
+  DRQ bit not set within the time out.\r
+\r
+  @retval EFI_ABORTED\r
+  DRQ bit not set caused by the command abort.\r
+\r
+  @note\r
+  Read Alternate Status Register will not clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRQReady2 (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO:    IdeDev - add argument and description to function comment\r
+// TODO:    TimeoutInMilliSeconds - add argument and description to function comment\r
+{\r
+  UINT32  Delay;\r
+  UINT8   AltRegister;\r
+  UINT8   ErrorRegister;\r
+\r
+  Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+\r
+  do {\r
+    //\r
+    //  Read Alternate Status Register will not clear interrupt status\r
+    //\r
+    AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
+    //\r
+    // BSY == 0 , DRQ == 1\r
+    //\r
+    if ((AltRegister & (BSY | DRQ)) == DRQ) {\r
+      break;\r
+    }\r
+\r
+    if ((AltRegister & (BSY | ERR)) == ERR) {\r
+\r
+      ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+      if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Stall for 30 us\r
+    //\r
+    gBS->Stall (30);\r
+\r
+    Delay--;\r
+  } while (Delay);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is used to poll for the BSY bit clear in the\r
+  Status Register. BSY is clear when the device is not busy.\r
+  Every command must be sent after device is not busy.\r
+\r
+  @param[in] IDE_BLK_IO_DEV  IN    *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] UINTN     IN    TimeoutInMilliSeconds\r
+  used to designate the timeout for the DRQ ready.\r
+\r
+  @retval EFI_SUCCESS\r
+  BSY bit clear within the time out.\r
+\r
+  @retval EFI_TIMEOUT\r
+  BSY bit not clear within the time out.\r
+\r
+  @note\r
+  Read Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForBSYClear (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO:    IdeDev - add argument and description to function comment\r
+// TODO:    TimeoutInMilliSeconds - add argument and description to function comment\r
+{\r
+  UINT32  Delay;\r
+  UINT8   StatusRegister;\r
+\r
+  Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+  do {\r
+\r
+    StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+    if ((StatusRegister & BSY) == 0x00) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Stall for 30 us\r
+    //\r
+    gBS->Stall (30);\r
+\r
+    Delay--;\r
+\r
+  } while (Delay);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+//\r
+// WaitForBSYClear2\r
+//\r
+/**\r
+  This function is used to poll for the BSY bit clear in the\r
+  Alternate Status Register. BSY is clear when the device is not busy.\r
+  Every command must be sent after device is not busy.\r
+\r
+  @param[in] IDE_BLK_IO_DEV  IN    *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] UINTN     IN    TimeoutInMilliSeconds\r
+  used to designate the timeout for the DRQ ready.\r
+\r
+  @retval EFI_SUCCESS\r
+  BSY bit clear within the time out.\r
+\r
+  @retval EFI_TIMEOUT\r
+  BSY bit not clear within the time out.\r
+\r
+  @note\r
+  Read Alternate Status Register will not clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForBSYClear2 (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO:    IdeDev - add argument and description to function comment\r
+// TODO:    TimeoutInMilliSeconds - add argument and description to function comment\r
+{\r
+  UINT32  Delay;\r
+  UINT8   AltRegister;\r
+\r
+  Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+  do {\r
+    AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
+    if ((AltRegister & BSY) == 0x00) {\r
+      break;\r
+    }\r
+\r
+    gBS->Stall (30);\r
+\r
+    Delay--;\r
+\r
+  } while (Delay);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// DRDYReady\r
+//\r
+/**\r
+  This function is used to poll for the DRDY bit set in the\r
+  Status Register. DRDY bit is set when the device is ready\r
+  to accept command. Most ATA commands must be sent after\r
+  DRDY set except the ATAPI Packet Command.\r
+\r
+  @param[in] IDE_BLK_IO_DEV  IN    *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] UINTN     IN    TimeoutInMilliSeconds\r
+  used to designate the timeout for the DRQ ready.\r
+\r
+  @retval EFI_SUCCESS\r
+  DRDY bit set within the time out.\r
+\r
+  @retval EFI_TIMEOUT\r
+  DRDY bit not set within the time out.\r
+\r
+  @note\r
+  Read Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRDYReady (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           DelayInMilliSeconds\r
+  )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO:    IdeDev - add argument and description to function comment\r
+// TODO:    DelayInMilliSeconds - add argument and description to function comment\r
+// TODO:    EFI_ABORTED - add return value to function comment\r
+{\r
+  UINT32  Delay;\r
+  UINT8   StatusRegister;\r
+  UINT8   ErrorRegister;\r
+\r
+  Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+  do {\r
+    StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+    //\r
+    //  BSY == 0 , DRDY == 1\r
+    //\r
+    if ((StatusRegister & (DRDY | BSY)) == DRDY) {\r
+      break;\r
+    }\r
+\r
+    if ((StatusRegister & (BSY | ERR)) == ERR) {\r
+\r
+      ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+      if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    gBS->Stall (30);\r
+\r
+    Delay--;\r
+  } while (Delay);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// DRDYReady2\r
+//\r
+/**\r
+  This function is used to poll for the DRDY bit set in the\r
+  Alternate Status Register. DRDY bit is set when the device is ready\r
+  to accept command. Most ATA commands must be sent after\r
+  DRDY set except the ATAPI Packet Command.\r
+\r
+  @param[in] IDE_BLK_IO_DEV  IN    *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] UINTN     IN    TimeoutInMilliSeconds\r
+  used to designate the timeout for the DRQ ready.\r
+\r
+  @retval EFI_SUCCESS\r
+  DRDY bit set within the time out.\r
+\r
+  @retval EFI_TIMEOUT\r
+  DRDY bit not set within the time out.\r
+\r
+  @note\r
+  Read Alternate Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRDYReady2 (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           DelayInMilliSeconds\r
+  )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO:    IdeDev - add argument and description to function comment\r
+// TODO:    DelayInMilliSeconds - add argument and description to function comment\r
+// TODO:    EFI_ABORTED - add return value to function comment\r
+{\r
+  UINT32  Delay;\r
+  UINT8   AltRegister;\r
+  UINT8   ErrorRegister;\r
+\r
+  Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+  do {\r
+    AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
+    //\r
+    //  BSY == 0 , DRDY == 1\r
+    //\r
+    if ((AltRegister & (DRDY | BSY)) == DRDY) {\r
+      break;\r
+    }\r
+\r
+    if ((AltRegister & (BSY | ERR)) == ERR) {\r
+\r
+      ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+      if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    gBS->Stall (30);\r
+\r
+    Delay--;\r
+  } while (Delay);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// SwapStringChars\r
+//\r
+/**\r
+  This function is a helper function used to change the char order in a\r
+  string. It is designed specially for the PrintAtaModuleName() function.\r
+  After the IDE device is detected, the IDE driver gets the device module\r
+  name by sending ATA command called ATA Identify Command or ATAPI\r
+  Identify Command to the specified IDE device. The module name returned\r
+  is a string of ASCII characters: the first character is bit8--bit15\r
+  of the first word, the second character is bit0--bit7 of the first word\r
+  and so on. Thus the string can not be print directly before it is\r
+  preprocessed by this func to change the order of characters in\r
+  each word in the string.\r
+\r
+  @param[in] CHAR8 IN    *Destination\r
+  Indicates the destination string.\r
+\r
+  @param[in] CHAR8 IN    *Source\r
+  Indicates the source string.\r
+\r
+  @param[in] UINT8 IN    Size\r
+  the length of the string\r
+\r
+**/\r
+VOID\r
+SwapStringChars (\r
+  IN CHAR8  *Destination,\r
+  IN CHAR8  *Source,\r
+  IN UINT32 Size\r
+  )\r
+{\r
+  UINT32  Index;\r
+  CHAR8   Temp;\r
+\r
+  for (Index = 0; Index < Size; Index += 2) {\r
+\r
+    Temp                    = Source[Index + 1];\r
+    Destination[Index + 1]  = Source[Index];\r
+    Destination[Index]      = Temp;\r
+  }\r
+}\r
+\r
+//\r
+// ReleaseIdeResources\r
+//\r
+/**\r
+  Release resources of an IDE device before stopping it.\r
+\r
+  @param[in] *IdeBlkIoDevice  Standard IDE device private data structure\r
+\r
+**/\r
+VOID\r
+ReleaseIdeResources (\r
+  IN  IDE_BLK_IO_DEV  *IdeBlkIoDevice\r
+  )\r
+{\r
+  if (IdeBlkIoDevice == NULL) {\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Release all the resourses occupied by the IDE_BLK_IO_DEV\r
+  //\r
+\r
+  if (IdeBlkIoDevice->SenseData != NULL) {\r
+    gBS->FreePool (IdeBlkIoDevice->SenseData);\r
+    IdeBlkIoDevice->SenseData = NULL;\r
+  }\r
+\r
+  if (IdeBlkIoDevice->Cache != NULL) {\r
+    gBS->FreePool (IdeBlkIoDevice->Cache);\r
+    IdeBlkIoDevice->Cache = NULL;\r
+  }\r
+\r
+  if (IdeBlkIoDevice->pIdData != NULL) {\r
+    gBS->FreePool (IdeBlkIoDevice->pIdData);\r
+    IdeBlkIoDevice->pIdData = NULL;\r
+  }\r
+\r
+  if (IdeBlkIoDevice->pInquiryData != NULL) {\r
+    gBS->FreePool (IdeBlkIoDevice->pInquiryData);\r
+    IdeBlkIoDevice->pInquiryData = NULL;\r
+  }\r
+\r
+  if (IdeBlkIoDevice->ControllerNameTable != NULL) {\r
+    FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);\r
+    IdeBlkIoDevice->ControllerNameTable = NULL;\r
+  }\r
+\r
+  if (IdeBlkIoDevice->IoPort != NULL) {\r
+    gBS->FreePool (IdeBlkIoDevice->IoPort);\r
+  }\r
+\r
+  if (IdeBlkIoDevice->DevicePath != NULL) {\r
+    gBS->FreePool (IdeBlkIoDevice->DevicePath);\r
+  }\r
+\r
+  if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {\r
+    gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);\r
+    IdeBlkIoDevice->ExitBootServiceEvent = NULL;\r
+  }\r
+\r
+  gBS->FreePool (IdeBlkIoDevice);\r
+  IdeBlkIoDevice = NULL;\r
+\r
+  return ;\r
+}\r
+\r
+//\r
+// SetDeviceTransferMode\r
+//\r
+/**\r
+  Set the calculated Best transfer mode to a detected device\r
+\r
+  @param[in] *IdeDev       Standard IDE device private data structure\r
+  @param[in] *TransferMode The device transfer mode to be set\r
+\r
+  @return Set transfer mode Command execute status\r
+\r
+**/\r
+EFI_STATUS\r
+SetDeviceTransferMode (\r
+  IN IDE_BLK_IO_DEV       *IdeDev,\r
+  IN ATA_TRANSFER_MODE    *TransferMode\r
+  )\r
+// TODO: function comment is missing 'Routine Description:'\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       DeviceSelect;\r
+  UINT8       SectorCount;\r
+\r
+  DeviceSelect  = 0;\r
+  DeviceSelect  = (UINT8) ((IdeDev->Device) << 4);\r
+  SectorCount   = *((UINT8 *) TransferMode);\r
+\r
+  //\r
+  // Send SET FEATURE command (sub command 0x03) to set pio mode.\r
+  //\r
+  Status = AtaNonDataCommandIn (\r
+            IdeDev,\r
+            SET_FEATURES_CMD,\r
+            DeviceSelect,\r
+            0x03,\r
+            SectorCount,\r
+            0,\r
+            0,\r
+            0\r
+            );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send ATA command into device with NON_DATA protocol\r
+\r
+  @param  IdeDev Standard IDE device private data structure\r
+  @param  AtaCommand The ATA command to be sent\r
+  @param  Device The value in Device register\r
+  @param  Feature The value in Feature register\r
+  @param  SectorCount The value in SectorCount register\r
+  @param  LbaLow The value in LBA_LOW register\r
+  @param  LbaMiddle The value in LBA_MIDDLE register\r
+  @param  LbaHigh The value in LBA_HIGH register\r
+\r
+  @retval  EFI_SUCCESS Reading succeed\r
+  @retval  EFI_ABORTED Command failed\r
+  @retval  EFI_DEVICE_ERROR Device status error\r
+\r
+**/\r
+EFI_STATUS\r
+AtaNonDataCommandIn (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINT8           AtaCommand,\r
+  IN  UINT8           Device,\r
+  IN  UINT8           Feature,\r
+  IN  UINT8           SectorCount,\r
+  IN  UINT8           LbaLow,\r
+  IN  UINT8           LbaMiddle,\r
+  IN  UINT8           LbaHigh\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       StatusRegister;\r
+\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+    );\r
+\r
+  //\r
+  // ATA commands for ATA device must be issued when DRDY is set\r
+  //\r
+  Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Pass parameter into device register block\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMiddle);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+  //\r
+  // Send command via Command Register\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+  //\r
+  // Wait for command completion\r
+  // For ATA_SMART_CMD, we may need more timeout to let device\r
+  // adjust internal states.\r
+  //\r
+  if (AtaCommand == ATA_SMART_CMD) {\r
+    Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT);\r
+  } else {\r
+    Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+  if ((StatusRegister & ERR) == ERR) {\r
+    //\r
+    // Failed to execute command, abort operation\r
+    //\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Send ATA Ext command into device with NON_DATA protocol\r
+\r
+  @param  IdeDev Standard IDE device private data structure\r
+  @param  AtaCommand The ATA command to be sent\r
+  @param  Device The value in Device register\r
+  @param  Feature The value in Feature register\r
+  @param  SectorCount The value in SectorCount register\r
+  @param  LbaAddress The LBA address in 48-bit mode\r
+\r
+  @retval  EFI_SUCCESS Reading succeed\r
+  @retval  EFI_ABORTED Command failed\r
+  @retval  EFI_DEVICE_ERROR Device status error\r
+\r
+**/\r
+EFI_STATUS\r
+AtaNonDataCommandInExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINT8           AtaCommand,\r
+  IN  UINT8           Device,\r
+  IN  UINT16          Feature,\r
+  IN  UINT16          SectorCount,\r
+  IN  EFI_LBA         LbaAddress\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       StatusRegister;\r
+  UINT8       SectorCount8;\r
+  UINT8       Feature8;\r
+  UINT8       LbaLow;\r
+  UINT8       LbaMid;\r
+  UINT8       LbaHigh;\r
+\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+    );\r
+\r
+  //\r
+  // ATA commands for ATA device must be issued when DRDY is set\r
+  //\r
+  Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Pass parameter into device register block\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+\r
+  //\r
+  // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
+  //\r
+  Feature8 = (UINT8) (Feature >> 8);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+\r
+  Feature8 = (UINT8) Feature;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+\r
+  //\r
+  // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+  //\r
+  SectorCount8 = (UINT8) (SectorCount >> 8);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+  SectorCount8 = (UINT8) SectorCount;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+  //\r
+  // Fill the start LBA registers, which are also two-byte FIFO\r
+  //\r
+  LbaLow  = (UINT8) RShiftU64 (LbaAddress, 24);\r
+  LbaMid  = (UINT8) RShiftU64 (LbaAddress, 32);\r
+  LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+  LbaLow  = (UINT8) LbaAddress;\r
+  LbaMid  = (UINT8) RShiftU64 (LbaAddress, 8);\r
+  LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+  //\r
+  // Send command via Command Register\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+  //\r
+  // Wait for command completion\r
+  //\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+  if ((StatusRegister & ERR) == ERR) {\r
+    //\r
+    // Failed to execute command, abort operation\r
+    //\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// SetDriveParameters\r
+//\r
+/**\r
+  Set drive parameters for devices not support PACKETS command\r
+\r
+  @param[in] IdeDev       Standard IDE device private data structure\r
+  @param[in] DriveParameters The device parameters to be set into the disk\r
+\r
+  @return SetParameters Command execute status\r
+\r
+**/\r
+EFI_STATUS\r
+SetDriveParameters (\r
+  IN IDE_BLK_IO_DEV       *IdeDev,\r
+  IN ATA_DRIVE_PARMS      *DriveParameters\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       DeviceSelect;\r
+\r
+  DeviceSelect  = 0;\r
+  DeviceSelect  = (UINT8) ((IdeDev->Device) << 4);\r
+\r
+  //\r
+  // Send Init drive parameters\r
+  //\r
+  Status = AtaNonDataCommandIn (\r
+            IdeDev,\r
+            INIT_DRIVE_PARAM_CMD,\r
+            (UINT8) (DeviceSelect + DriveParameters->Heads),\r
+            0,\r
+            DriveParameters->Sector,\r
+            0,\r
+            0,\r
+            0\r
+            );\r
+\r
+  //\r
+  // Send Set Multiple parameters\r
+  //\r
+  Status = AtaNonDataCommandIn (\r
+            IdeDev,\r
+            SET_MULTIPLE_MODE_CMD,\r
+            DeviceSelect,\r
+            0,\r
+            DriveParameters->MultipleSector,\r
+            0,\r
+            0,\r
+            0\r
+            );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  @retval  EFI_SUCCESS TODO: Add description for return value\r
+\r
+**/\r
+EFI_STATUS\r
+EnableInterrupt (\r
+  IN IDE_BLK_IO_DEV       *IdeDev\r
+  )\r
+{\r
+  UINT8 DeviceControl;\r
+\r
+  //\r
+  // Enable interrupt for DMA operation\r
+  //\r
+  DeviceControl = 0;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.\r
+\r
+  @param[in]  Event   Pointer to this event\r
+  @param[in]  Context Event hanlder private data\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ClearInterrupt (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  UINT64          IoPortForBmis;\r
+  UINT8           RegisterValue;\r
+  IDE_BLK_IO_DEV  *IdeDev;\r
+\r
+  //\r
+  // Get our context\r
+  //\r
+  IdeDev = (IDE_BLK_IO_DEV *) Context;\r
+\r
+  //\r
+  // Obtain IDE IO port registers' base addresses\r
+  //\r
+  Status = ReassignIdeResources (IdeDev);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Check whether interrupt is pending\r
+  //\r
+\r
+  //\r
+  // Reset IDE device to force it de-assert interrupt pin\r
+  // Note: this will reset all devices on this IDE channel\r
+  //\r
+  AtaSoftReset (IdeDev);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Get base address of IDE Bus Master Status Regsiter\r
+  //\r
+  if (IdePrimary == IdeDev->Channel) {\r
+    IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
+  } else {\r
+    if (IdeSecondary == IdeDev->Channel) {\r
+      IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
+    } else {\r
+      return;\r
+    }\r
+  }\r
+  //\r
+  // Read BMIS register and clear ERROR and INTR bit\r
+  //\r
+  IdeDev->PciIo->Io.Read (\r
+                      IdeDev->PciIo,\r
+                      EfiPciIoWidthUint8,\r
+                      EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                      IoPortForBmis,\r
+                      1,\r
+                      &RegisterValue\r
+                      );\r
+\r
+  RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+\r
+  IdeDev->PciIo->Io.Write (\r
+                      IdeDev->PciIo,\r
+                      EfiPciIoWidthUint8,\r
+                      EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                      IoPortForBmis,\r
+                      1,\r
+                      &RegisterValue\r
+                      );\r
+\r
+  //\r
+  // Select the other device on this channel to ensure this device to release the interrupt pin\r
+  //\r
+  if (IdeDev->Device == 0) {\r
+    RegisterValue = (1 << 4) | 0xe0;\r
+  } else {\r
+    RegisterValue = (0 << 4) | 0xe0;\r
+  }\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    RegisterValue\r
+    );\r
+\r
+}\r
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h b/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h
new file mode 100644 (file)
index 0000000..ec1f9e0
--- /dev/null
@@ -0,0 +1,1328 @@
+/** @file\r
+  Header file for IDE Bus Driver, containing the helper functions'\r
+  entire prototype.\r
+\r
+  Copyright (c) 2006 - 2007 Intel Corporation. <BR>\r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+  @par Revision Reference:\r
+  2002-6: Add Atapi6 enhancement, support >120GB hard disk, including\r
+  Add - IDEBlkIoReadBlocksExt() func definition\r
+  Add - IDEBlkIoWriteBlocksExt() func definition\r
+\r
+**/\r
+\r
+#ifndef _IDE_H\r
+#define _IDE_H\r
+\r
+//\r
+// Helper functions Prototype\r
+//\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  This TODO: add argument description\r
+  @param  Controller TODO: add argument description\r
+  @param  Handle TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DeRegisterIdeDevice (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL    *This,\r
+  IN  EFI_HANDLE                     Controller,\r
+  IN  EFI_HANDLE                     Handle\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  Controller TODO: add argument description\r
+  @param  PciIo TODO: add argument description\r
+  @param  ParentDevicePath TODO: add argument description\r
+  @param  RemainingDevicePath TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+EnableIdeDevice (\r
+  IN EFI_HANDLE                          Controller,\r
+  IN EFI_PCI_IO_PROTOCOL                 *PciIo,\r
+  IN EFI_DEVICE_PATH_PROTOCOL            *ParentDevicePath,\r
+  IN EFI_DEVICE_PATH_PROTOCOL            *RemainingDevicePath\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  PciIo TODO: add argument description\r
+  @param  Port TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+UINT8\r
+IDEReadPortB (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  PciIo TODO: add argument description\r
+  @param  Port TODO: add argument description\r
+  @param  Count TODO: add argument description\r
+  @param  Buffer TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+VOID\r
+IDEReadPortWMultiple (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINTN                 Count,\r
+  OUT  VOID                 *Buffer\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  PciIo TODO: add argument description\r
+  @param  Port TODO: add argument description\r
+  @param  Data TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+VOID\r
+IDEWritePortB (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINT8                 Data\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  PciIo TODO: add argument description\r
+  @param  Port TODO: add argument description\r
+  @param  Data TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+VOID\r
+IDEWritePortW (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINT16                Data\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  PciIo TODO: add argument description\r
+  @param  Port TODO: add argument description\r
+  @param  Count TODO: add argument description\r
+  @param  Buffer TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+VOID\r
+IDEWritePortWMultiple (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINTN                 Count,\r
+  IN  VOID                  *Buffer\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  PciIo TODO: add argument description\r
+  @param  IdeRegsBaseAddr TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+GetIdeRegistersBaseAddr (\r
+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,\r
+  OUT IDE_REGISTERS_BASE_ADDR     *IdeRegsBaseAddr\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+ReassignIdeResources (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DiscoverIdeDevice (\r
+  IN IDE_BLK_IO_DEV *IdeDev\r
+  )\r
+;\r
+\r
+/**\r
+  This interface is used to initialize all state data related to the\r
+  detection of one channel.\r
+\r
+  @retval EFI_SUCCESS Completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeIDEChannelData (\r
+  VOID\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DetectIDEController (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  TimeoutInMilliSeconds TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DRQClear (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  TimeoutInMilliSeconds TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DRQClear2 (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  TimeoutInMilliSeconds TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DRQReady (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  TimeoutInMilliSeconds TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DRQReady2 (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  TimeoutInMilliSeconds TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForBSYClear (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  TimeoutInMilliSeconds TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForBSYClear2 (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  DelayInMilliSeconds TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DRDYReady (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           DelayInMilliSeconds\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  DelayInMilliSeconds TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DRDYReady2 (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           DelayInMilliSeconds\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  Destination TODO: add argument description\r
+  @param  Source TODO: add argument description\r
+  @param  Size TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+VOID\r
+SwapStringChars (\r
+  IN CHAR8  *Destination,\r
+  IN CHAR8  *Source,\r
+  IN UINT32 Size\r
+  )\r
+;\r
+\r
+//\r
+//  ATA device functions' prototype\r
+//\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+ATAIdentify (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+VOID\r
+PrintAtaModuleName (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  Buffer TODO: add argument description\r
+  @param  ByteCount TODO: add argument description\r
+  @param  AtaCommand TODO: add argument description\r
+  @param  Head TODO: add argument description\r
+  @param  SectorCount TODO: add argument description\r
+  @param  SectorNumber TODO: add argument description\r
+  @param  CylinderLsb TODO: add argument description\r
+  @param  CylinderMsb TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPioDataIn (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *Buffer,\r
+  IN  UINT32          ByteCount,\r
+  IN  UINT8           AtaCommand,\r
+  IN  UINT8           Head,\r
+  IN  UINT8           SectorCount,\r
+  IN  UINT8           SectorNumber,\r
+  IN  UINT8           CylinderLsb,\r
+  IN  UINT8           CylinderMsb\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  Buffer TODO: add argument description\r
+  @param  ByteCount TODO: add argument description\r
+  @param  AtaCommand TODO: add argument description\r
+  @param  Head TODO: add argument description\r
+  @param  SectorCount TODO: add argument description\r
+  @param  SectorNumber TODO: add argument description\r
+  @param  CylinderLsb TODO: add argument description\r
+  @param  CylinderMsb TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPioDataOut (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *Buffer,\r
+  IN  UINT32          ByteCount,\r
+  IN  UINT8           AtaCommand,\r
+  IN  UINT8           Head,\r
+  IN  UINT8           SectorCount,\r
+  IN  UINT8           SectorNumber,\r
+  IN  UINT8           CylinderLsb,\r
+  IN  UINT8           CylinderMsb\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+CheckErrorStatus (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  DataBuffer TODO: add argument description\r
+  @param  Lba TODO: add argument description\r
+  @param  NumberOfBlocks TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaReadSectors (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         Lba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  BufferData TODO: add argument description\r
+  @param  Lba TODO: add argument description\r
+  @param  NumberOfBlocks TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaWriteSectors (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *BufferData,\r
+  IN  EFI_LBA         Lba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaSoftReset (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeBlkIoDevice TODO: add argument description\r
+  @param  MediaId TODO: add argument description\r
+  @param  LBA TODO: add argument description\r
+  @param  BufferSize TODO: add argument description\r
+  @param  Buffer TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaBlkIoReadBlocks (\r
+  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,\r
+  IN UINT32           MediaId,\r
+  IN EFI_LBA          LBA,\r
+  IN UINTN            BufferSize,\r
+  OUT VOID            *Buffer\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeBlkIoDevice TODO: add argument description\r
+  @param  MediaId TODO: add argument description\r
+  @param  LBA TODO: add argument description\r
+  @param  BufferSize TODO: add argument description\r
+  @param  Buffer TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaBlkIoWriteBlocks (\r
+  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,\r
+  IN UINT32           MediaId,\r
+  IN EFI_LBA          LBA,\r
+  IN UINTN            BufferSize,\r
+  OUT VOID            *Buffer\r
+  )\r
+;\r
+\r
+//\r
+// ATAPI device functions' prototype\r
+//\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+ATAPIIdentify (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiInquiry (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  Packet TODO: add argument description\r
+  @param  Buffer TODO: add argument description\r
+  @param  ByteCount TODO: add argument description\r
+  @param  TimeOut TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiPacketCommandIn (\r
+  IN  IDE_BLK_IO_DEV        *IdeDev,\r
+  IN  ATAPI_PACKET_COMMAND  *Packet,\r
+  IN  UINT16                *Buffer,\r
+  IN  UINT32                ByteCount,\r
+  IN  UINTN                 TimeOut\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  Packet TODO: add argument description\r
+  @param  Buffer TODO: add argument description\r
+  @param  ByteCount TODO: add argument description\r
+  @param  TimeOut TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiPacketCommandOut (\r
+  IN  IDE_BLK_IO_DEV        *IdeDev,\r
+  IN  ATAPI_PACKET_COMMAND  *Packet,\r
+  IN  UINT16                *Buffer,\r
+  IN  UINT32                ByteCount,\r
+  IN  UINTN                 TimeOut\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  Buffer TODO: add argument description\r
+  @param  ByteCount TODO: add argument description\r
+  @param  Read TODO: add argument description\r
+  @param  TimeOut TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+PioReadWriteData (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINT16          *Buffer,\r
+  IN  UINT32          ByteCount,\r
+  IN  BOOLEAN         Read,\r
+  IN  UINTN           TimeOut\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiTestUnitReady (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  OUT UINTN           *SenseCount\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  SenseCounts TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiRequestSense (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  OUT UINTN           *SenseCounts\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiReadCapacity (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  OUT UINTN           *SenseCount\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  MediaChange TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiDetectMedia (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  OUT BOOLEAN         *MediaChange\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  Buffer TODO: add argument description\r
+  @param  Lba TODO: add argument description\r
+  @param  NumberOfBlocks TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiReadSectors (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *Buffer,\r
+  IN  EFI_LBA         Lba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  Buffer TODO: add argument description\r
+  @param  Lba TODO: add argument description\r
+  @param  NumberOfBlocks TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiWriteSectors (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *Buffer,\r
+  IN  EFI_LBA         Lba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiSoftReset (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeBlkIoDevice TODO: add argument description\r
+  @param  MediaId TODO: add argument description\r
+  @param  LBA TODO: add argument description\r
+  @param  BufferSize TODO: add argument description\r
+  @param  Buffer TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiBlkIoReadBlocks (\r
+  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,\r
+  IN UINT32           MediaId,\r
+  IN EFI_LBA          LBA,\r
+  IN UINTN            BufferSize,\r
+  OUT VOID            *Buffer\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeBlkIoDevice TODO: add argument description\r
+  @param  MediaId TODO: add argument description\r
+  @param  LBA TODO: add argument description\r
+  @param  BufferSize TODO: add argument description\r
+  @param  Buffer TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiBlkIoWriteBlocks (\r
+  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,\r
+  IN UINT32           MediaId,\r
+  IN EFI_LBA          LBA,\r
+  IN UINTN            BufferSize,\r
+  OUT VOID            *Buffer\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  SenseCount TODO: add argument description\r
+  @param  Result TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+ParseSenseData (\r
+  IN IDE_BLK_IO_DEV     *IdeDev,\r
+  IN UINTN              SenseCount,\r
+  OUT SENSE_RESULT      *Result\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiReadPendingData (\r
+  IN IDE_BLK_IO_DEV     *IdeDev\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  WriteProtected TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+IsLS120orZipWriteProtected (\r
+  IN  IDE_BLK_IO_DEV    *IdeDev,\r
+  OUT BOOLEAN           *WriteProtected\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeBlkIoDevice TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+VOID\r
+ReleaseIdeResources (\r
+  IN  IDE_BLK_IO_DEV  *IdeBlkIoDevice\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  TransferMode TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+SetDeviceTransferMode (\r
+  IN IDE_BLK_IO_DEV       *IdeDev,\r
+  IN ATA_TRANSFER_MODE    *TransferMode\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  NativeMaxAddress TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+ReadNativeMaxAddress (\r
+  IN  IDE_BLK_IO_DEV                *IdeDev,\r
+  OUT EFI_LBA                       *NativeMaxAddress\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  MaxAddress TODO: add argument description\r
+  @param  bVolatile TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+SetMaxAddress (\r
+  IN  IDE_BLK_IO_DEV                *IdeDev,\r
+  IN  EFI_LBA                       MaxAddress,\r
+  IN  BOOLEAN                       bVolatile\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  AtaCommand TODO: add argument description\r
+  @param  Device TODO: add argument description\r
+  @param  Feature TODO: add argument description\r
+  @param  SectorCount TODO: add argument description\r
+  @param  LbaLow TODO: add argument description\r
+  @param  LbaMiddle TODO: add argument description\r
+  @param  LbaHigh TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaNonDataCommandIn (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINT8           AtaCommand,\r
+  IN  UINT8           Device,\r
+  IN  UINT8           Feature,\r
+  IN  UINT8           SectorCount,\r
+  IN  UINT8           LbaLow,\r
+  IN  UINT8           LbaMiddle,\r
+  IN  UINT8           LbaHigh\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  AtaCommand TODO: add argument description\r
+  @param  Device TODO: add argument description\r
+  @param  Feature TODO: add argument description\r
+  @param  SectorCount TODO: add argument description\r
+  @param  LbaAddress TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaNonDataCommandInExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINT8           AtaCommand,\r
+  IN  UINT8           Device,\r
+  IN  UINT16          Feature,\r
+  IN  UINT16          SectorCount,\r
+  IN  EFI_LBA         LbaAddress\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  DataBuffer TODO: add argument description\r
+  @param  StartLba TODO: add argument description\r
+  @param  NumberOfBlocks TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaReadSectorsExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  DataBuffer TODO: add argument description\r
+  @param  StartLba TODO: add argument description\r
+  @param  NumberOfBlocks TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaWriteSectorsExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  DataBuffer TODO: add argument description\r
+  @param  StartLba TODO: add argument description\r
+  @param  NumberOfBlocks TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaUdmaReadExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  DataBuffer TODO: add argument description\r
+  @param  StartLba TODO: add argument description\r
+  @param  NumberOfBlocks TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaUdmaRead (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  DataBuffer TODO: add argument description\r
+  @param  StartLba TODO: add argument description\r
+  @param  NumberOfBlocks TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaUdmaWriteExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+;\r
+\r
+/**\r
+  Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).\r
+  \r
+  @param[in] *IdeDev\r
+  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+  to record all the information of the IDE device.\r
+\r
+  @param[in] *DataBuffer\r
+  A pointer to the source buffer for the data.\r
+\r
+  @param[in] StartLba\r
+  The starting logical block address to write to\r
+  on the device media.\r
+\r
+  @param[in] NumberOfBlocks\r
+  The number of transfer data blocks.\r
+  \r
+  @param[in] UdmaOp\r
+  The perform operations could be AtaUdmaReadOp, AtaUdmaReadExOp,\r
+  AtaUdmaWriteOp, AtaUdmaWriteExOp\r
+\r
+  @return The device status of UDMA operation. If the operation is\r
+  successful, return EFI_SUCCESS.\r
+\r
+**/\r
+EFI_STATUS\r
+DoAtaUdma (\r
+  IN  IDE_BLK_IO_DEV      *IdeDev,\r
+  IN  VOID                *DataBuffer,\r
+  IN  EFI_LBA             StartLba,\r
+  IN  UINTN               NumberOfBlocks,\r
+  IN  ATA_UDMA_OPERATION  UdmaOp\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  DataBuffer TODO: add argument description\r
+  @param  StartLba TODO: add argument description\r
+  @param  NumberOfBlocks TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaUdmaWrite (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  AtaCommand TODO: add argument description\r
+  @param  Device TODO: add argument description\r
+  @param  Feature TODO: add argument description\r
+  @param  SectorCount TODO: add argument description\r
+  @param  LbaAddress TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaCommandIssueExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINT8           AtaCommand,\r
+  IN  UINT8           Device,\r
+  IN  UINT16          Feature,\r
+  IN  UINT16          SectorCount,\r
+  IN  EFI_LBA         LbaAddress\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  AtaCommand TODO: add argument description\r
+  @param  Device TODO: add argument description\r
+  @param  Feature TODO: add argument description\r
+  @param  SectorCount TODO: add argument description\r
+  @param  LbaAddress TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaCommandIssue (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINT8           AtaCommand,\r
+  IN  UINT8           Device,\r
+  IN  UINT16          Feature,\r
+  IN  UINT16          SectorCount,\r
+  IN  EFI_LBA         LbaAddress\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaAtapi6Identify (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+VOID\r
+AtaSMARTSupport (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+;\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+  @param  Buffer TODO: add argument description\r
+  @param  ByteCount TODO: add argument description\r
+  @param  AtaCommand TODO: add argument description\r
+  @param  StartLba TODO: add argument description\r
+  @param  SectorCount TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPioDataInExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r