]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBus.c
Add DxeBootScriptLibNull in IntelFrameworkPkg.
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / IsaBusDxe / IsaBus.c
diff --git a/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBus.c b/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBus.c
new file mode 100644 (file)
index 0000000..daee1fb
--- /dev/null
@@ -0,0 +1,653 @@
+/*++\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved. <BR> \r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IsaBus.c\r
+  \r
+Abstract:\r
+\r
+  Discovers all the ISA Controllers and their resources by using the ISA PnP \r
+  Protocol, produces an instance of the ISA I/O Protocol for every ISA \r
+  Controller found, loads and initializes all ISA Device Drivers, matches ISA\r
+  Device Drivers with their respective ISA Controllers in a deterministic \r
+  manner, and informs a ISA Device Driver when it is to start managing an ISA\r
+  Controller. \r
+\r
+Revision History:\r
+\r
+--*/\r
+\r
+#include "InternalIsaBus.h"\r
+\r
+//\r
+// ISA Bus Driver Global Variables\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gIsaBusControllerDriver = {\r
+  IsaBusControllerDriverSupported,\r
+  IsaBusControllerDriverStart,\r
+  IsaBusControllerDriverStop,\r
+  0xa,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaBusControllerDriverSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  * This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+  \r
+    This function checks to see if a controller can be managed by the ISA Bus \r
+    Driver. This is done by checking to see if the controller supports the \r
+    EFI_PCI_IO_PROTOCOL protocol, and then looking at the PCI Configuration \r
+    Header to see if the device is a PCI to ISA bridge. The class code of \r
+    PCI to ISA bridge: Base class 06h, Sub class 01h Interface 00h \r
+  \r
+  Arguments:\r
+  \r
+    This                 - The EFI_DRIVER_BINDING_PROTOCOL instance.\r
+    Controller           - The handle of the device to check.\r
+    RemainingDevicePath  - A pointer to the remaining portion of a device path.\r
+\r
+  Returns:\r
+  \r
+    EFI_SUCCESS          - The device is supported by this driver.\r
+    EFI_UNSUPPORTED      - The device is not supported by this driver.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_ISA_ACPI_PROTOCOL *IsaAcpi;\r
+\r
+  //\r
+  // If RemainingDevicePath is not NULL, it should verify that the first device\r
+  // path node in RemainingDevicePath is an ACPI Device path node\r
+  //\r
+  if (RemainingDevicePath != NULL) {\r
+    if (RemainingDevicePath->Type != ACPI_DEVICE_PATH) {\r
+      return EFI_UNSUPPORTED;\r
+    } else if (RemainingDevicePath->SubType == ACPI_DP) {\r
+      if (DevicePathNodeLength (RemainingDevicePath) != sizeof (ACPI_HID_DEVICE_PATH)) {\r
+        return EFI_UNSUPPORTED;\r
+      }\r
+    } else if (RemainingDevicePath->SubType == ACPI_EXTENDED_DP) {\r
+      if (DevicePathNodeLength (RemainingDevicePath) != sizeof (ACPI_EXTENDED_HID_DEVICE_PATH)) {\r
+        return EFI_UNSUPPORTED;\r
+      }\r
+    } else {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+  }\r
+  //\r
+  // Test the existence of DEVICE_PATH protocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Get the Isa Acpi protocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiIsaAcpiProtocolGuid,\r
+                  (VOID **) &IsaAcpi,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (Status == EFI_ALREADY_STARTED) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiIsaAcpiProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaBusControllerDriverStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  * This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+  \r
+    This function tells the ISA Bus Driver to start managing a PCI to ISA \r
+    Bridge controller. \r
+  \r
+  Arguments:\r
+  \r
+    This                  - The EFI_DRIVER_BINDING_PROTOCOL instance.\r
+    Controller            - A handle to the device being started. \r
+    RemainingDevicePath   - A pointer to the remaining portion of a device path.\r
+\r
+  Returns:\r
+  \r
+    EFI_SUCCESS           - The device was started.\r
+    EFI_UNSUPPORTED       - The device is not supported.\r
+    EFI_DEVICE_ERROR      - The device could not be started due to a device error.\r
+    EFI_ALREADY_STARTED   - The device has already been started.\r
+    EFI_INVALID_PARAMETER - One of the parameters has an invalid value.\r
+    EFI_OUT_OF_RESOURCES  - The request could not be completed due to a lack of \r
+                            resources.\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS                            Status;\r
+  EFI_PCI_IO_PROTOCOL                   *PciIo;\r
+  EFI_DEVICE_PATH_PROTOCOL              *ParentDevicePath;\r
+  EFI_ISA_ACPI_PROTOCOL                 *IsaAcpi;\r
+  EFI_ISA_ACPI_DEVICE_ID                *IsaDevice;\r
+  EFI_ISA_ACPI_RESOURCE_LIST            *ResourceList;\r
+  EFI_GENERIC_MEMORY_TEST_PROTOCOL      *GenMemoryTest;\r
+\r
+  //\r
+  // Local variables declaration for StatusCode reporting\r
+  //\r
+  EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA AllocFailExtendedData;\r
+  EFI_DEVICE_PATH_PROTOCOL              *DevicePathData;\r
+\r
+  BootScriptSaveInformationAsciiString (\r
+    EFI_ACPI_S3_RESUME_SCRIPT_TABLE,\r
+    "IsaBusBindingStartBegin"\r
+    );\r
+\r
+  //\r
+  // Initialize status code structure\r
+  //\r
+  AllocFailExtendedData.DataHeader.HeaderSize = sizeof (EFI_STATUS_CODE_DATA);\r
+  AllocFailExtendedData.DataHeader.Size = sizeof (EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA) - sizeof (EFI_STATUS_CODE_DATA);\r
+  CopyMem (\r
+    &AllocFailExtendedData.DataHeader.Type,\r
+    &gEfiStatusCodeSpecificDataGuid,\r
+    sizeof (EFI_GUID)\r
+    );\r
+\r
+  //\r
+  // Open Device Path Protocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &ParentDevicePath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Open Pci IO Protocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Close opened protocol\r
+    //\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiDevicePathProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+    return Status;\r
+  }\r
+  //\r
+  // Open ISA Acpi Protocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiIsaAcpiProtocolGuid,\r
+                  (VOID **) &IsaAcpi,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
+    //\r
+    // Close opened protocol\r
+    //\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiDevicePathProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiPciIoProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+    return Status;\r
+  }\r
+  //\r
+  // The IsaBus driver will use memory below 16M, which is not tested yet,\r
+  // so call CompatibleRangeTest to test them. Since memory below 1M should\r
+  // be reserved to CSM, and 15M~16M might be reserved for Isa hole, test 1M\r
+  // ~15M here\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiGenericMemTestProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &GenMemoryTest\r
+                  );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = GenMemoryTest->CompatibleRangeTest (\r
+                              GenMemoryTest,\r
+                              0x100000,\r
+                              0xE00000\r
+                              );\r
+  }\r
+  //\r
+  // Report Status Code here since we will initialize the host controller\r
+  //\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    (EFI_IO_BUS_LPC | EFI_IOB_PC_INIT),\r
+    ParentDevicePath\r
+    );\r
+\r
+  //\r
+  // first init ISA interface\r
+  //\r
+  IsaAcpi->InterfaceInit (IsaAcpi);\r
+\r
+  //\r
+  // Report Status Code here since we will enable the host controller\r
+  //\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    (EFI_IO_BUS_LPC | EFI_IOB_PC_ENABLE),\r
+    ParentDevicePath\r
+    );\r
+\r
+  //\r
+  // Create each ISA device handle in this ISA bus\r
+  //\r
+  IsaDevice = NULL;\r
+  do {\r
+    Status = IsaAcpi->DeviceEnumerate (IsaAcpi, &IsaDevice);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    //\r
+    // Get current resource of this ISA device\r
+    //\r
+    ResourceList  = NULL;\r
+    Status        = IsaAcpi->GetCurResource (IsaAcpi, IsaDevice, &ResourceList);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Create handle for this ISA device\r
+    //\r
+    Status = IsaCreateDevice (\r
+               This,\r
+               Controller,\r
+               PciIo,\r
+               ParentDevicePath,\r
+               ResourceList,\r
+               &DevicePathData\r
+               //&AllocFailExtendedData.DevicePath\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+    //\r
+    // Initialize ISA device\r
+    //\r
+    IsaAcpi->InitDevice (IsaAcpi, IsaDevice);\r
+\r
+    //\r
+    // Set resources for this ISA device\r
+    //\r
+    Status = IsaAcpi->SetResource (IsaAcpi, IsaDevice, ResourceList);\r
+\r
+    //\r
+    // Report Status Code here when failed to resource conflicts\r
+    //\r
+    if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {\r
+      //\r
+      // It's hard to tell which resource conflicts\r
+      //\r
+      AllocFailExtendedData.Bar       = 0;\r
+      AllocFailExtendedData.ReqRes    = NULL;\r
+      AllocFailExtendedData.AllocRes  = NULL;\r
+      REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+         EFI_ERROR_CODE,\r
+         (EFI_IO_BUS_LPC | EFI_IOB_EC_RESOURCE_CONFLICT),\r
+         DevicePathData\r
+         );\r
+\r
+    }\r
+    //\r
+    // Set power for this ISA device\r
+    //\r
+    IsaAcpi->SetPower (IsaAcpi, IsaDevice, TRUE);\r
+\r
+    //\r
+    // Enable this ISA device\r
+    //\r
+    IsaAcpi->EnableDevice (IsaAcpi, IsaDevice, TRUE);\r
+\r
+  } while (TRUE);\r
+\r
+  BootScriptSaveInformationAsciiString (\r
+    EFI_ACPI_S3_RESUME_SCRIPT_TABLE,\r
+    "IsaBusBindingStartEnd"\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaBusControllerDriverStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  * This,\r
+  IN  EFI_HANDLE                   Controller,\r
+  IN  UINTN                        NumberOfChildren,\r
+  IN  EFI_HANDLE                   * ChildHandleBuffer OPTIONAL\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+  \r
+    This function tells the ISA Bus Driver to stop managing a PCI to ISA \r
+    Bridge controller. \r
+     \r
+  Arguments:\r
+  \r
+    This                   - The EFI_DRIVER_BINDING_PROTOCOL instance.\r
+    Controller             - A handle to the device being stopped.\r
+    NumberOfChindren       - The number of child device handles in ChildHandleBuffer.\r
+    ChildHandleBuffer      - An array of child handles to be freed.\r
+\r
+  \r
+  Returns:\r
+  \r
+    EFI_SUCCESS            - The device was stopped.\r
+    EFI_DEVICE_ERROR       - The device could not be stopped due to a device error.\r
+    EFI_NOT_STARTED        - The device has not been started.\r
+    EFI_INVALID_PARAMETER  - One of the parameters has an invalid value.\r
+    EFI_OUT_OF_RESOURCES   - The request could not be completed due to a lack of \r
+                             resources.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                          Status;\r
+  UINTN                               Index;\r
+  BOOLEAN                             AllChildrenStopped;\r
+  ISA_IO_DEVICE                       *IsaIoDevice;\r
+  EFI_ISA_IO_PROTOCOL                 *IsaIo;\r
+\r
+  if (NumberOfChildren == 0) {\r
+    //\r
+    // Close the bus driver\r
+    //\r
+    Status = gBS->CloseProtocol (\r
+                    Controller,\r
+                    &gEfiPciIoProtocolGuid,\r
+                    This->DriverBindingHandle,\r
+                    Controller\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Status = gBS->CloseProtocol (\r
+                    Controller,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    This->DriverBindingHandle,\r
+                    Controller\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Status = gBS->CloseProtocol (\r
+                    Controller,\r
+                    &gEfiIsaAcpiProtocolGuid,\r
+                    This->DriverBindingHandle,\r
+                    Controller\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // Complete all outstanding transactions to Controller.\r
+  // Don't allow any new transaction to Controller to be started.\r
+  //\r
+  //\r
+  // Stop all the children\r
+  // Find all the ISA devices that were discovered on this PCI to ISA Bridge\r
+  // with the Start() function.\r
+  //\r
+  AllChildrenStopped = TRUE;\r
+\r
+  for (Index = 0; Index < NumberOfChildren; Index++) {\r
+\r
+    Status = gBS->OpenProtocol (\r
+                    ChildHandleBuffer[Index],\r
+                    &gEfiIsaIoProtocolGuid,\r
+                    (VOID **) &IsaIo,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (!EFI_ERROR (Status)) {\r
+\r
+      IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (IsaIo);\r
+\r
+      Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                      ChildHandleBuffer[Index],\r
+                      &gEfiDevicePathProtocolGuid,\r
+                      IsaIoDevice->DevicePath,\r
+                      &gEfiIsaIoProtocolGuid,\r
+                      &IsaIoDevice->IsaIo,\r
+                      NULL\r
+                      );\r
+\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // Close the child handle\r
+        //\r
+        Status = gBS->CloseProtocol (\r
+                        Controller,\r
+                        &gEfiPciIoProtocolGuid,\r
+                        This->DriverBindingHandle,\r
+                        ChildHandleBuffer[Index]\r
+                        );\r
+\r
+        gBS->FreePool (IsaIoDevice->DevicePath);\r
+        gBS->FreePool (IsaIoDevice);\r
+      }\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      AllChildrenStopped = FALSE;\r
+    }\r
+  }\r
+\r
+  if (!AllChildrenStopped) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+//\r
+// Internal Function\r
+//\r
+EFI_STATUS\r
+IsaCreateDevice (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_PCI_IO_PROTOCOL          *PciIo,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *ParentDevicePath,\r
+  IN EFI_ISA_ACPI_RESOURCE_LIST   *IsaDeviceResourceList,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL    **ChildDevicePath\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+  \r
+    Create ISA device found by IsaPnpProtocol \r
+\r
+  Arguments:\r
+  \r
+    This                   - The EFI_DRIVER_BINDING_PROTOCOL instance.\r
+    Controller             - The handle of ISA bus controller(PCI to ISA bridge)\r
+    PciIo                  - The Pointer to the PCI protocol \r
+    ParentDevicePath       - Device path of the ISA bus controller\r
+    IsaDeviceResourceList  - The resource list of the ISA device\r
+    ChildDevicePath        - The pointer to the child device.\r
+\r
+  Returns:\r
+  \r
+    EFI_SUCCESS            - Create the child device.\r
+    EFI_OUT_OF_RESOURCES   - The request could not be completed due to a lack of \r
+                             resources.\r
+    EFI_DEVICE_ERROR       - Can not create child device.\r
+    \r
+--*/\r
+{\r
+  EFI_STATUS    Status;\r
+  ISA_IO_DEVICE *IsaIoDevice;\r
+  EFI_DEV_PATH  Node;\r
+\r
+  //\r
+  // Initialize the PCI_IO_DEVICE structure\r
+  //\r
+  IsaIoDevice = AllocateZeroPool (sizeof (ISA_IO_DEVICE));\r
+  if (IsaIoDevice == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  IsaIoDevice->Signature  = ISA_IO_DEVICE_SIGNATURE;\r
+  IsaIoDevice->Handle     = NULL;\r
+  IsaIoDevice->PciIo      = PciIo;\r
+\r
+  //\r
+  // Initialize the ISA I/O instance structure\r
+  //\r
+  Status = InitializeIsaIoInstance (IsaIoDevice, IsaDeviceResourceList);\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->FreePool (IsaIoDevice);\r
+    return Status;\r
+  }\r
+  //\r
+  // Build the child device path\r
+  //\r
+  Node.DevPath.Type     = ACPI_DEVICE_PATH;\r
+  Node.DevPath.SubType  = ACPI_DP;\r
+  SetDevicePathNodeLength (&Node.DevPath, sizeof (ACPI_HID_DEVICE_PATH));\r
+  Node.Acpi.HID = IsaDeviceResourceList->Device.HID;\r
+  Node.Acpi.UID = IsaDeviceResourceList->Device.UID;\r
+\r
+  IsaIoDevice->DevicePath = AppendDevicePathNode (\r
+                              ParentDevicePath,\r
+                              &Node.DevPath\r
+                              );\r
+\r
+  if (IsaIoDevice->DevicePath == NULL) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Done;\r
+  }\r
+\r
+  *ChildDevicePath = IsaIoDevice->DevicePath;\r
+\r
+  //\r
+  // Create a child handle and attach the DevicePath,\r
+  // PCI I/O, and Controller State\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &IsaIoDevice->Handle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  IsaIoDevice->DevicePath,\r
+                  &gEfiIsaIoProtocolGuid,\r
+                  &IsaIoDevice->IsaIo,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  IsaIoDevice->Handle,\r
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->UninstallMultipleProtocolInterfaces (\r
+           IsaIoDevice->Handle,\r
+           &gEfiDevicePathProtocolGuid,\r
+           IsaIoDevice->DevicePath,\r
+           &gEfiIsaIoProtocolGuid,\r
+           &IsaIoDevice->IsaIo,\r
+           NULL\r
+           );\r
+  }\r
+\r
+Done:\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    if (IsaIoDevice->DevicePath != NULL) {\r
+      gBS->FreePool (IsaIoDevice->DevicePath);\r
+    }\r
+\r
+    gBS->FreePool (IsaIoDevice);\r
+  }\r
+\r
+  return Status;\r
+}\r