Home | History | Annotate | Download | only in IsaBusDxe
      1 /** @file
      2   ISA Bus UEFI driver.
      3 
      4   Discovers all the ISA Controllers and their resources by using the ISA ACPI
      5   Protocol, produces an instance of the ISA I/O Protocol for every ISA
      6   Controller found. This driver is designed to manage a PCI-to-ISA bridge Device
      7   such as LPC bridge.
      8 
      9 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
     10 This program and the accompanying materials
     11 are licensed and made available under the terms and conditions of the BSD License
     12 which accompanies this distribution.  The full text of the license may be found at
     13 http://opensource.org/licenses/bsd-license.php
     14 
     15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     16 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     17 
     18 **/
     19 
     20 #include "InternalIsaBus.h"
     21 
     22 //
     23 // ISA Bus Driver Global Variables
     24 //
     25 EFI_DRIVER_BINDING_PROTOCOL gIsaBusControllerDriver = {
     26   IsaBusControllerDriverSupported,
     27   IsaBusControllerDriverStart,
     28   IsaBusControllerDriverStop,
     29   0xa,
     30   NULL,
     31   NULL
     32 };
     33 
     34 /**
     35   The main entry point for the ISA Bus driver.
     36 
     37   @param[in] ImageHandle        The firmware allocated handle for the EFI image.
     38   @param[in] SystemTable        A pointer to the EFI System Table.
     39 
     40   @retval EFI_SUCCESS           The entry point is executed successfully.
     41   @retval EFI_OUT_OF_RESOURCES  There was not enough memory in pool to install all the protocols.
     42 **/
     43 EFI_STATUS
     44 EFIAPI
     45 InitializeIsaBus(
     46   IN EFI_HANDLE           ImageHandle,
     47   IN EFI_SYSTEM_TABLE     *SystemTable
     48   )
     49 {
     50   EFI_STATUS              Status;
     51 
     52   //
     53   // Install driver model protocol(s).
     54   //
     55   Status = EfiLibInstallDriverBindingComponentName2 (
     56              ImageHandle,
     57              SystemTable,
     58              &gIsaBusControllerDriver,
     59              ImageHandle,
     60              &gIsaBusComponentName,
     61              &gIsaBusComponentName2
     62              );
     63   ASSERT_EFI_ERROR (Status);
     64 
     65   return Status;
     66 }
     67 
     68 /**
     69   Tests to see if a controller can be managed by the ISA Bus Driver. If a child device is provided,
     70   it further tests to see if this driver supports creating a handle for the specified child device.
     71 
     72   Note that the ISA Bus driver always creates all of its child handles on the first call to Start().
     73   How the Start() function of a driver is implemented can affect how the Supported() function is implemented.
     74 
     75   @param[in] This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
     76   @param[in] Controller           The handle of the controller to test.
     77   @param[in] RemainingDevicePath  A pointer to the remaining portion of a device path.
     78 
     79   @retval EFI_SUCCESS             The device is supported by this driver.
     80   @retval EFI_ALREADY_STARTED     The device is already being managed by this driver.
     81   @retval EFI_ACCESS_DENIED       The device is already being managed by a different driver
     82                                   or an application that requires exclusive access.
     83   @retval EFI_UNSUPPORTED         The device is is not supported by this driver.
     84 
     85 **/
     86 EFI_STATUS
     87 EFIAPI
     88 IsaBusControllerDriverSupported (
     89   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
     90   IN EFI_HANDLE                   Controller,
     91   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
     92   )
     93 {
     94   EFI_STATUS                Status;
     95   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
     96   EFI_ISA_ACPI_PROTOCOL     *IsaAcpi;
     97 
     98   //
     99   // If RemainingDevicePath is not NULL, it should verify that the first device
    100   // path node in RemainingDevicePath is an ACPI Device path node which is a
    101   // legal Device Path Node for this bus driver's children.
    102   //
    103   if (RemainingDevicePath != NULL) {
    104     if (RemainingDevicePath->Type != ACPI_DEVICE_PATH) {
    105       return EFI_UNSUPPORTED;
    106     } else if (RemainingDevicePath->SubType == ACPI_DP) {
    107       if (DevicePathNodeLength (RemainingDevicePath) != sizeof (ACPI_HID_DEVICE_PATH)) {
    108         return EFI_UNSUPPORTED;
    109       }
    110     } else if (RemainingDevicePath->SubType == ACPI_EXTENDED_DP) {
    111       if (DevicePathNodeLength (RemainingDevicePath) != sizeof (ACPI_EXTENDED_HID_DEVICE_PATH)) {
    112         return EFI_UNSUPPORTED;
    113       }
    114     } else {
    115       return EFI_UNSUPPORTED;
    116     }
    117   }
    118   //
    119   // Try to open EFI DEVICE PATH protocol on the controller
    120   //
    121   Status = gBS->OpenProtocol (
    122                   Controller,
    123                   &gEfiDevicePathProtocolGuid,
    124                   (VOID **) &ParentDevicePath,
    125                   This->DriverBindingHandle,
    126                   Controller,
    127                   EFI_OPEN_PROTOCOL_BY_DRIVER
    128                   );
    129   //
    130   // Although this driver creates all child handles at one time,
    131   // but because all child handles may be not stopped at one time in EFI Driver Binding.Stop(),
    132   // So it is allowed to create child handles again in successive calls to EFI Driver Binding.Start().
    133   //
    134   if (Status == EFI_ALREADY_STARTED) {
    135     return EFI_SUCCESS;
    136   }
    137 
    138   if (EFI_ERROR (Status)) {
    139     return Status;
    140   }
    141 
    142   gBS->CloseProtocol (
    143          Controller,
    144          &gEfiDevicePathProtocolGuid,
    145          This->DriverBindingHandle,
    146          Controller
    147          );
    148 
    149   //
    150   // Try to get Pci IO Protocol because it is assumed
    151   // to have been opened by ISA ACPI driver
    152   //
    153   Status = gBS->OpenProtocol (
    154                   Controller,
    155                   &gEfiPciIoProtocolGuid,
    156                   NULL,
    157                   This->DriverBindingHandle,
    158                   Controller,
    159                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    160                   );
    161   if (EFI_ERROR (Status)) {
    162     return Status;
    163   }
    164 
    165   //
    166   // Try to open the Isa Acpi protocol on the controller
    167   //
    168   Status = gBS->OpenProtocol (
    169                   Controller,
    170                   &gEfiIsaAcpiProtocolGuid,
    171                   (VOID **) &IsaAcpi,
    172                   This->DriverBindingHandle,
    173                   Controller,
    174                   EFI_OPEN_PROTOCOL_BY_DRIVER
    175                   );
    176   if (EFI_ERROR (Status)) {
    177     return Status;
    178   }
    179 
    180   //
    181   // Add more check to see if the child device is valid by calling IsaAcpi->DeviceEnumerate?
    182   //
    183 
    184   gBS->CloseProtocol (
    185          Controller,
    186          &gEfiIsaAcpiProtocolGuid,
    187          This->DriverBindingHandle,
    188          Controller
    189          );
    190 
    191   return Status;
    192 }
    193 
    194 /**
    195   Start this driver on ControllerHandle.
    196 
    197   Note that the ISA Bus driver always creates all of its child handles on the first call to Start().
    198   The Start() function is designed to be invoked from the EFI boot service ConnectController().
    199   As a result, much of the error checking on the parameters to Start() has been moved into this
    200   common boot service. It is legal to call Start() from other locations, but the following calling
    201   restrictions must be followed or the system behavior will not be deterministic.
    202   1. ControllerHandle must be a valid EFI_HANDLE.
    203   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
    204      EFI_DEVICE_PATH_PROTOCOL.
    205   3. Prior to calling Start(), the Supported() function for the driver specified by This must
    206      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
    207 
    208   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    209   @param[in]  ControllerHandle     The handle of the controller to start. This handle
    210                                    must support a protocol interface that supplies
    211                                    an I/O abstraction to the driver.
    212   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.
    213                                    This parameter is ignored by device drivers, and is optional for bus drivers.
    214 
    215   @retval EFI_SUCCESS              The device was started.
    216   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.
    217                                    Currently not implemented.
    218   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
    219   @retval Others                   The driver failded to start the device.
    220 **/
    221 EFI_STATUS
    222 EFIAPI
    223 IsaBusControllerDriverStart (
    224   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    225   IN EFI_HANDLE                   Controller,
    226   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
    227   )
    228 {
    229   EFI_STATUS                            Status;
    230   EFI_PCI_IO_PROTOCOL                   *PciIo;
    231   EFI_DEVICE_PATH_PROTOCOL              *ParentDevicePath;
    232   EFI_ISA_ACPI_PROTOCOL                 *IsaAcpi;
    233   EFI_ISA_ACPI_DEVICE_ID                *IsaDevice;
    234   EFI_ISA_ACPI_RESOURCE_LIST            *ResourceList;
    235   EFI_GENERIC_MEMORY_TEST_PROTOCOL      *GenMemoryTest;
    236 
    237   //
    238   // Local variables declaration for StatusCode reporting
    239   //
    240   EFI_DEVICE_PATH_PROTOCOL              *DevicePathData;
    241 
    242   DevicePathData = NULL;
    243 
    244   //
    245   // Get Pci IO Protocol
    246   //
    247   Status = gBS->OpenProtocol (
    248                   Controller,
    249                   &gEfiPciIoProtocolGuid,
    250                   (VOID **) &PciIo,
    251                   This->DriverBindingHandle,
    252                   Controller,
    253                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    254                   );
    255   if (EFI_ERROR (Status)) {
    256     return Status;
    257   }
    258 
    259   //
    260   // Open Device Path Protocol
    261   //
    262   Status = gBS->OpenProtocol (
    263                   Controller,
    264                   &gEfiDevicePathProtocolGuid,
    265                   (VOID **) &ParentDevicePath,
    266                   This->DriverBindingHandle,
    267                   Controller,
    268                   EFI_OPEN_PROTOCOL_BY_DRIVER
    269                   );
    270   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
    271     return Status;
    272   }
    273 
    274   //
    275   // Open ISA Acpi Protocol
    276   //
    277   Status = gBS->OpenProtocol (
    278                   Controller,
    279                   &gEfiIsaAcpiProtocolGuid,
    280                   (VOID **) &IsaAcpi,
    281                   This->DriverBindingHandle,
    282                   Controller,
    283                   EFI_OPEN_PROTOCOL_BY_DRIVER
    284                   );
    285   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
    286     //
    287     // Close opened protocol
    288     //
    289     gBS->CloseProtocol (
    290            Controller,
    291            &gEfiDevicePathProtocolGuid,
    292            This->DriverBindingHandle,
    293            Controller
    294            );
    295     return Status;
    296   }
    297   //
    298   // The IsaBus driver will use memory below 16M, which is not tested yet,
    299   // so call CompatibleRangeTest to test them. Since memory below 1M should
    300   // be reserved to CSM, and 15M~16M might be reserved for Isa hole, test 1M
    301   // ~15M here
    302   //
    303   Status = gBS->LocateProtocol (
    304                   &gEfiGenericMemTestProtocolGuid,
    305                   NULL,
    306                   (VOID **) &GenMemoryTest
    307                   );
    308 
    309   if (!EFI_ERROR (Status)) {
    310     Status = GenMemoryTest->CompatibleRangeTest (
    311                               GenMemoryTest,
    312                               0x100000,
    313                               0xE00000
    314                               );
    315   }
    316   //
    317   // Report Status Code here since we will initialize the host controller
    318   //
    319   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    320     EFI_PROGRESS_CODE,
    321     (EFI_IO_BUS_LPC | EFI_IOB_PC_INIT),
    322     ParentDevicePath
    323     );
    324 
    325   //
    326   // first init ISA interface
    327   //
    328   IsaAcpi->InterfaceInit (IsaAcpi);
    329 
    330   //
    331   // Report Status Code here since we will enable the host controller
    332   //
    333   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    334     EFI_PROGRESS_CODE,
    335     (EFI_IO_BUS_LPC | EFI_IOB_PC_ENABLE),
    336     ParentDevicePath
    337     );
    338 
    339   //
    340   // Create each ISA device handle in this ISA bus
    341   //
    342   IsaDevice = NULL;
    343   do {
    344     Status = IsaAcpi->DeviceEnumerate (IsaAcpi, &IsaDevice);
    345     if (EFI_ERROR (Status)) {
    346       break;
    347     }
    348     //
    349     // Get current resource of this ISA device
    350     //
    351     ResourceList  = NULL;
    352     Status        = IsaAcpi->GetCurResource (IsaAcpi, IsaDevice, &ResourceList);
    353     if (EFI_ERROR (Status)) {
    354       continue;
    355     }
    356 
    357     //
    358     // Create handle for this ISA device
    359     //
    360     // If any child device handle was created in previous call to Start() and not stopped
    361     // in previous call to Stop(), it will not be created again because the
    362     // InstallMultipleProtocolInterfaces() boot service will reject same device path.
    363     //
    364     Status = IsaCreateDevice (
    365                This,
    366                Controller,
    367                PciIo,
    368                ParentDevicePath,
    369                ResourceList,
    370                &DevicePathData
    371                );
    372 
    373     if (EFI_ERROR (Status)) {
    374       continue;
    375     }
    376     //
    377     // Initialize ISA device
    378     //
    379     IsaAcpi->InitDevice (IsaAcpi, IsaDevice);
    380 
    381     //
    382     // Set resources for this ISA device
    383     //
    384     Status = IsaAcpi->SetResource (IsaAcpi, IsaDevice, ResourceList);
    385 
    386     //
    387     // Report Status Code here when failed to resource conflicts
    388     //
    389     if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
    390       //
    391       // It's hard to tell which resource conflicts
    392       //
    393       REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    394          EFI_ERROR_CODE,
    395          (EFI_IO_BUS_LPC | EFI_IOB_EC_RESOURCE_CONFLICT),
    396          DevicePathData
    397          );
    398 
    399     }
    400     //
    401     // Set power for this ISA device
    402     //
    403     IsaAcpi->SetPower (IsaAcpi, IsaDevice, TRUE);
    404 
    405     //
    406     // Enable this ISA device
    407     //
    408     IsaAcpi->EnableDevice (IsaAcpi, IsaDevice, TRUE);
    409 
    410   } while (TRUE);
    411 
    412   return EFI_SUCCESS;
    413 }
    414 
    415 /**
    416   Stop this driver on ControllerHandle.
    417 
    418   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
    419   As a result, much of the error checking on the parameters to Stop() has been moved
    420   into this common boot service. It is legal to call Stop() from other locations,
    421   but the following calling restrictions must be followed or the system behavior will not be deterministic.
    422   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
    423      same driver's Start() function.
    424   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
    425      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
    426      Start() function, and the Start() function must have called OpenProtocol() on
    427      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
    428 
    429   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    430   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
    431                                 support a bus specific I/O protocol for the driver
    432                                 to use to stop the device.
    433   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
    434   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
    435                                 if NumberOfChildren is 0.
    436 
    437   @retval EFI_SUCCESS           The device was stopped.
    438   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
    439 **/
    440 EFI_STATUS
    441 EFIAPI
    442 IsaBusControllerDriverStop (
    443   IN  EFI_DRIVER_BINDING_PROTOCOL  * This,
    444   IN  EFI_HANDLE                   Controller,
    445   IN  UINTN                        NumberOfChildren,
    446   IN  EFI_HANDLE                   * ChildHandleBuffer OPTIONAL
    447   )
    448 {
    449   EFI_STATUS                          Status;
    450   UINTN                               Index;
    451   BOOLEAN                             AllChildrenStopped;
    452   ISA_IO_DEVICE                       *IsaIoDevice;
    453   EFI_ISA_IO_PROTOCOL                 *IsaIo;
    454   EFI_PCI_IO_PROTOCOL                 *PciIo;
    455 
    456   if (NumberOfChildren == 0) {
    457     //
    458     // Close the bus driver
    459     //
    460     Status = gBS->CloseProtocol (
    461                     Controller,
    462                     &gEfiDevicePathProtocolGuid,
    463                     This->DriverBindingHandle,
    464                     Controller
    465                     );
    466     if (EFI_ERROR (Status)) {
    467       return Status;
    468     }
    469 
    470     Status = gBS->CloseProtocol (
    471                     Controller,
    472                     &gEfiIsaAcpiProtocolGuid,
    473                     This->DriverBindingHandle,
    474                     Controller
    475                     );
    476     if (EFI_ERROR (Status)) {
    477       return Status;
    478     }
    479 
    480     return EFI_SUCCESS;
    481   }
    482   //
    483   // Complete all outstanding transactions to Controller.
    484   // Don't allow any new transaction to Controller to be started.
    485   //
    486   //
    487   // Stop all the children
    488   // Find all the ISA devices that were discovered on this PCI to ISA Bridge
    489   // with the Start() function.
    490   //
    491   AllChildrenStopped = TRUE;
    492 
    493   for (Index = 0; Index < NumberOfChildren; Index++) {
    494 
    495     Status = gBS->OpenProtocol (
    496                     ChildHandleBuffer[Index],
    497                     &gEfiIsaIoProtocolGuid,
    498                     (VOID **) &IsaIo,
    499                     This->DriverBindingHandle,
    500                     Controller,
    501                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    502                     );
    503     if (!EFI_ERROR (Status)) {
    504 
    505       IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (IsaIo);
    506 
    507       //
    508       // Close the child handle
    509       //
    510 
    511       Status = gBS->CloseProtocol (
    512                       Controller,
    513                       &gEfiPciIoProtocolGuid,
    514                       This->DriverBindingHandle,
    515                       ChildHandleBuffer[Index]
    516                       );
    517       Status = gBS->UninstallMultipleProtocolInterfaces (
    518                       ChildHandleBuffer[Index],
    519                       &gEfiDevicePathProtocolGuid,
    520                       IsaIoDevice->DevicePath,
    521                       &gEfiIsaIoProtocolGuid,
    522                       &IsaIoDevice->IsaIo,
    523                       NULL
    524                       );
    525 
    526       if (!EFI_ERROR (Status)) {
    527         FreePool (IsaIoDevice->DevicePath);
    528         FreePool (IsaIoDevice);
    529       } else {
    530         //
    531         // Re-open PCI IO Protocol on behalf of the child device
    532         // because of failure of destroying the child device handle
    533         //
    534         gBS->OpenProtocol (
    535                Controller,
    536                &gEfiPciIoProtocolGuid,
    537                (VOID **) &PciIo,
    538                This->DriverBindingHandle,
    539                ChildHandleBuffer[Index],
    540                EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    541                );
    542       }
    543     }
    544 
    545     if (EFI_ERROR (Status)) {
    546       AllChildrenStopped = FALSE;
    547     }
    548   }
    549 
    550   if (!AllChildrenStopped) {
    551     return EFI_DEVICE_ERROR;
    552   }
    553 
    554   return EFI_SUCCESS;
    555 }
    556 
    557 //
    558 // Internal Function
    559 //
    560 
    561 /**
    562   Create EFI Handle for a ISA device found via ISA ACPI Protocol
    563 
    564   @param[in] This                   The EFI_DRIVER_BINDING_PROTOCOL instance.
    565   @param[in] Controller             The handle of ISA bus controller(PCI to ISA bridge)
    566   @param[in] PciIo                  The Pointer to the PCI protocol
    567   @param[in] ParentDevicePath       Device path of the ISA bus controller
    568   @param[in] IsaDeviceResourceList  The resource list of the ISA device
    569   @param[out] ChildDevicePath       The pointer to the child device.
    570 
    571   @retval EFI_SUCCESS               The handle for the child device was created.
    572   @retval EFI_OUT_OF_RESOURCES      The request could not be completed due to a lack of resources.
    573   @retval EFI_DEVICE_ERROR          The handle for the child device can not be created.
    574 **/
    575 EFI_STATUS
    576 IsaCreateDevice (
    577   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    578   IN EFI_HANDLE                   Controller,
    579   IN EFI_PCI_IO_PROTOCOL          *PciIo,
    580   IN EFI_DEVICE_PATH_PROTOCOL     *ParentDevicePath,
    581   IN EFI_ISA_ACPI_RESOURCE_LIST   *IsaDeviceResourceList,
    582   OUT EFI_DEVICE_PATH_PROTOCOL    **ChildDevicePath
    583   )
    584 {
    585   EFI_STATUS    Status;
    586   ISA_IO_DEVICE *IsaIoDevice;
    587   EFI_DEV_PATH  Node;
    588 
    589   //
    590   // Initialize the PCI_IO_DEVICE structure
    591   //
    592   IsaIoDevice = AllocateZeroPool (sizeof (ISA_IO_DEVICE));
    593   if (IsaIoDevice == NULL) {
    594     return EFI_OUT_OF_RESOURCES;
    595   }
    596 
    597   IsaIoDevice->Signature  = ISA_IO_DEVICE_SIGNATURE;
    598   IsaIoDevice->Handle     = NULL;
    599   IsaIoDevice->PciIo      = PciIo;
    600 
    601   //
    602   // Initialize the ISA I/O instance structure
    603   //
    604   InitializeIsaIoInstance (IsaIoDevice, IsaDeviceResourceList);
    605 
    606   //
    607   // Build the child device path
    608   //
    609   Node.DevPath.Type     = ACPI_DEVICE_PATH;
    610   Node.DevPath.SubType  = ACPI_DP;
    611   SetDevicePathNodeLength (&Node.DevPath, sizeof (ACPI_HID_DEVICE_PATH));
    612   Node.Acpi.HID = IsaDeviceResourceList->Device.HID;
    613   Node.Acpi.UID = IsaDeviceResourceList->Device.UID;
    614 
    615   IsaIoDevice->DevicePath = AppendDevicePathNode (
    616                               ParentDevicePath,
    617                               &Node.DevPath
    618                               );
    619 
    620   if (IsaIoDevice->DevicePath == NULL) {
    621     Status = EFI_OUT_OF_RESOURCES;
    622     goto Done;
    623   }
    624 
    625   *ChildDevicePath = IsaIoDevice->DevicePath;
    626 
    627   //
    628   // Create a child handle and install Device Path and ISA I/O protocols
    629   //
    630   Status = gBS->InstallMultipleProtocolInterfaces (
    631                   &IsaIoDevice->Handle,
    632                   &gEfiDevicePathProtocolGuid,
    633                   IsaIoDevice->DevicePath,
    634                   &gEfiIsaIoProtocolGuid,
    635                   &IsaIoDevice->IsaIo,
    636                   NULL
    637                   );
    638   if (EFI_ERROR (Status)) {
    639     goto Done;
    640   }
    641 
    642   Status = gBS->OpenProtocol (
    643                   Controller,
    644                   &gEfiPciIoProtocolGuid,
    645                   (VOID **) &PciIo,
    646                   This->DriverBindingHandle,
    647                   IsaIoDevice->Handle,
    648                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    649                   );
    650   if (EFI_ERROR (Status)) {
    651     gBS->UninstallMultipleProtocolInterfaces (
    652            IsaIoDevice->Handle,
    653            &gEfiDevicePathProtocolGuid,
    654            IsaIoDevice->DevicePath,
    655            &gEfiIsaIoProtocolGuid,
    656            &IsaIoDevice->IsaIo,
    657            NULL
    658            );
    659   }
    660 
    661 Done:
    662 
    663   if (EFI_ERROR (Status)) {
    664     if (IsaIoDevice->DevicePath != NULL) {
    665       FreePool (IsaIoDevice->DevicePath);
    666     }
    667 
    668     FreePool (IsaIoDevice);
    669   }
    670 
    671   return Status;
    672 }
    673 
    674