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
InitializeIsaBus(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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
IsaBusControllerDriverSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)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
IsaBusControllerDriverStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)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
IsaBusControllerDriverStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)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
IsaCreateDevice(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_PCI_IO_PROTOCOL * PciIo,IN EFI_DEVICE_PATH_PROTOCOL * ParentDevicePath,IN EFI_ISA_ACPI_RESOURCE_LIST * IsaDeviceResourceList,OUT EFI_DEVICE_PATH_PROTOCOL ** ChildDevicePath)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