• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Serial driver for PCI or SIO UARTS.
3 
4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "Serial.h"
16 
17 //
18 // ISA Serial Driver Global Variables
19 //
20 
21 EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = {
22   SerialControllerDriverSupported,
23   SerialControllerDriverStart,
24   SerialControllerDriverStop,
25   0xa,
26   NULL,
27   NULL
28 };
29 
30 CONTROLLER_DEVICE_PATH mControllerDevicePathTemplate = {
31   {
32     HARDWARE_DEVICE_PATH,
33     HW_CONTROLLER_DP,
34     {
35       (UINT8) (sizeof (CONTROLLER_DEVICE_PATH)),
36       (UINT8) ((sizeof (CONTROLLER_DEVICE_PATH)) >> 8)
37     }
38   },
39   0
40 };
41 
42 SERIAL_DEV  gSerialDevTemplate = {
43   SERIAL_DEV_SIGNATURE,
44   NULL,
45   {
46     SERIAL_IO_INTERFACE_REVISION,
47     SerialReset,
48     SerialSetAttributes,
49     SerialSetControl,
50     SerialGetControl,
51     SerialWrite,
52     SerialRead,
53     NULL
54   },                                       // SerialIo
55   {
56     SERIAL_PORT_SUPPORT_CONTROL_MASK,
57     SERIAL_PORT_DEFAULT_TIMEOUT,
58     0,
59     16,
60     0,
61     0,
62     0
63   },                                       // SerialMode
64   NULL,                                    // DevicePath
65   NULL,                                    // ParentDevicePath
66   {
67     {
68       MESSAGING_DEVICE_PATH,
69       MSG_UART_DP,
70       {
71         (UINT8) (sizeof (UART_DEVICE_PATH)),
72         (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)
73       }
74     },
75     0, 0, 0, 0, 0
76   },                                       // UartDevicePath
77   0,                                       // BaseAddress
78   FALSE,                                   // MmioAccess
79   1,                                       // RegisterStride
80   0,                                       // ClockRate
81   16,                                      // ReceiveFifoDepth
82   { 0, 0 },                                // Receive;
83   16,                                      // TransmitFifoDepth
84   { 0, 0 },                                // Transmit;
85   FALSE,                                   // SoftwareLoopbackEnable;
86   FALSE,                                   // HardwareFlowControl;
87   NULL,                                    // *ControllerNameTable;
88   FALSE,                                   // ContainsControllerNode;
89   0,                                       // Instance;
90   NULL                                     // *PciDeviceInfo;
91 };
92 
93 /**
94   Check the device path node whether it's the Flow Control node or not.
95 
96   @param[in] FlowControl    The device path node to be checked.
97 
98   @retval TRUE              It's the Flow Control node.
99   @retval FALSE             It's not.
100 
101 **/
102 BOOLEAN
IsUartFlowControlDevicePathNode(IN UART_FLOW_CONTROL_DEVICE_PATH * FlowControl)103 IsUartFlowControlDevicePathNode (
104   IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl
105   )
106 {
107   return (BOOLEAN) (
108            (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) &&
109            (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) &&
110            (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid))
111            );
112 }
113 
114 /**
115   The user Entry Point for module PciSioSerial. The user code starts with this function.
116 
117   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
118   @param[in] SystemTable    A pointer to the EFI System Table.
119 
120   @retval EFI_SUCCESS       The entry point is executed successfully.
121   @retval other             Some error occurs when executing this entry point.
122 
123 **/
124 EFI_STATUS
125 EFIAPI
InitializePciSioSerial(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)126 InitializePciSioSerial (
127   IN EFI_HANDLE           ImageHandle,
128   IN EFI_SYSTEM_TABLE     *SystemTable
129   )
130 {
131   EFI_STATUS              Status;
132 
133   //
134   // Install driver model protocol(s).
135   //
136   Status = EfiLibInstallDriverBindingComponentName2 (
137              ImageHandle,
138              SystemTable,
139              &gSerialControllerDriver,
140              ImageHandle,
141              &gPciSioSerialComponentName,
142              &gPciSioSerialComponentName2
143              );
144   ASSERT_EFI_ERROR (Status);
145 
146   //
147   // Initialize UART default setting in gSerialDevTempate
148   //
149   gSerialDevTemplate.SerialMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
150   gSerialDevTemplate.SerialMode.DataBits = PcdGet8 (PcdUartDefaultDataBits);
151   gSerialDevTemplate.SerialMode.Parity   = PcdGet8 (PcdUartDefaultParity);
152   gSerialDevTemplate.SerialMode.StopBits = PcdGet8 (PcdUartDefaultStopBits);
153   gSerialDevTemplate.UartDevicePath.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
154   gSerialDevTemplate.UartDevicePath.DataBits = PcdGet8 (PcdUartDefaultDataBits);
155   gSerialDevTemplate.UartDevicePath.Parity   = PcdGet8 (PcdUartDefaultParity);
156   gSerialDevTemplate.UartDevicePath.StopBits = PcdGet8 (PcdUartDefaultStopBits);
157   gSerialDevTemplate.ClockRate = PcdGet32 (PcdSerialClockRate);
158 
159   return Status;
160 }
161 
162 /**
163   Return whether the controller is a SIO serial controller.
164 
165   @param  Controller   The controller handle.
166 
167   @retval EFI_SUCCESS  The controller is a SIO serial controller.
168   @retval others       The controller is not a SIO serial controller.
169 **/
170 EFI_STATUS
IsSioSerialController(EFI_HANDLE Controller)171 IsSioSerialController (
172   EFI_HANDLE               Controller
173   )
174 {
175   EFI_STATUS               Status;
176   EFI_SIO_PROTOCOL         *Sio;
177   EFI_DEVICE_PATH_PROTOCOL *DevicePath;
178   ACPI_HID_DEVICE_PATH     *Acpi;
179 
180   //
181   // Open the IO Abstraction(s) needed to perform the supported test
182   //
183   Status = gBS->OpenProtocol (
184                   Controller,
185                   &gEfiSioProtocolGuid,
186                   (VOID **) &Sio,
187                   gSerialControllerDriver.DriverBindingHandle,
188                   Controller,
189                   EFI_OPEN_PROTOCOL_BY_DRIVER
190                   );
191   if (Status == EFI_ALREADY_STARTED) {
192     return EFI_SUCCESS;
193   }
194 
195   if (!EFI_ERROR (Status)) {
196     //
197     // Close the I/O Abstraction(s) used to perform the supported test
198     //
199     gBS->CloseProtocol (
200            Controller,
201            &gEfiSioProtocolGuid,
202            gSerialControllerDriver.DriverBindingHandle,
203            Controller
204            );
205 
206     Status = gBS->OpenProtocol (
207       Controller,
208       &gEfiDevicePathProtocolGuid,
209       (VOID **) &DevicePath,
210       gSerialControllerDriver.DriverBindingHandle,
211       Controller,
212       EFI_OPEN_PROTOCOL_BY_DRIVER
213       );
214     ASSERT (Status != EFI_ALREADY_STARTED);
215 
216     if (!EFI_ERROR (Status)) {
217       do {
218         Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath;
219         DevicePath = NextDevicePathNode (DevicePath);
220       } while (!IsDevicePathEnd (DevicePath));
221 
222       if (DevicePathType (Acpi) != ACPI_DEVICE_PATH ||
223           (DevicePathSubType (Acpi) != ACPI_DP && DevicePathSubType (Acpi) != ACPI_EXTENDED_DP) ||
224           Acpi->HID != EISA_PNP_ID (0x501)
225           ) {
226         Status = EFI_UNSUPPORTED;
227       }
228     }
229 
230     //
231     // Close protocol, don't use device path protocol in the Support() function
232     //
233     gBS->CloseProtocol (
234       Controller,
235       &gEfiDevicePathProtocolGuid,
236       gSerialControllerDriver.DriverBindingHandle,
237       Controller
238       );
239   }
240   return Status;
241 }
242 
243 /**
244   Return whether the controller is a PCI serial controller.
245 
246   @param  Controller   The controller handle.
247 
248   @retval EFI_SUCCESS  The controller is a PCI serial controller.
249   @retval others       The controller is not a PCI serial controller.
250 **/
251 EFI_STATUS
IsPciSerialController(EFI_HANDLE Controller)252 IsPciSerialController (
253   EFI_HANDLE               Controller
254   )
255 {
256   EFI_STATUS               Status;
257   EFI_PCI_IO_PROTOCOL      *PciIo;
258   EFI_DEVICE_PATH_PROTOCOL *DevicePath;
259   PCI_TYPE00               Pci;
260   PCI_SERIAL_PARAMETER     *PciSerialParameter;
261 
262   //
263   // Open the IO Abstraction(s) needed to perform the supported test
264   //
265   Status = gBS->OpenProtocol (
266     Controller,
267     &gEfiPciIoProtocolGuid,
268     (VOID **) &PciIo,
269     gSerialControllerDriver.DriverBindingHandle,
270     Controller,
271     EFI_OPEN_PROTOCOL_BY_DRIVER
272     );
273   if (Status == EFI_ALREADY_STARTED) {
274     return EFI_SUCCESS;
275   }
276 
277   if (!EFI_ERROR (Status)) {
278     Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);
279     if (!EFI_ERROR (Status)) {
280       if (!IS_PCI_16550_SERIAL (&Pci)) {
281         for (PciSerialParameter = (PCI_SERIAL_PARAMETER *) PcdGetPtr (PcdPciSerialParameters)
282              ; PciSerialParameter->VendorId != 0xFFFF
283              ; PciSerialParameter++
284              ) {
285           if ((Pci.Hdr.VendorId == PciSerialParameter->VendorId) &&
286               (Pci.Hdr.DeviceId == PciSerialParameter->DeviceId)
287               ) {
288             break;
289           }
290         }
291         if (PciSerialParameter->VendorId == 0xFFFF) {
292           Status = EFI_UNSUPPORTED;
293         } else {
294           Status = EFI_SUCCESS;
295         }
296       }
297     }
298 
299     //
300     // Close the I/O Abstraction(s) used to perform the supported test
301     //
302     gBS->CloseProtocol (
303       Controller,
304       &gEfiPciIoProtocolGuid,
305       gSerialControllerDriver.DriverBindingHandle,
306       Controller
307       );
308   }
309   if (EFI_ERROR (Status)) {
310     return Status;
311   }
312 
313   //
314   // Open the EFI Device Path protocol needed to perform the supported test
315   //
316   Status = gBS->OpenProtocol (
317     Controller,
318     &gEfiDevicePathProtocolGuid,
319     (VOID **) &DevicePath,
320     gSerialControllerDriver.DriverBindingHandle,
321     Controller,
322     EFI_OPEN_PROTOCOL_BY_DRIVER
323     );
324   ASSERT (Status != EFI_ALREADY_STARTED);
325 
326   //
327   // Close protocol, don't use device path protocol in the Support() function
328   //
329   gBS->CloseProtocol (
330     Controller,
331     &gEfiDevicePathProtocolGuid,
332     gSerialControllerDriver.DriverBindingHandle,
333     Controller
334     );
335 
336   return Status;
337 }
338 
339 /**
340   Check to see if this driver supports the given controller
341 
342   @param  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
343   @param  Controller           The handle of the controller to test.
344   @param  RemainingDevicePath  A pointer to the remaining portion of a device path.
345 
346   @return EFI_SUCCESS          This driver can support the given controller
347 
348 **/
349 EFI_STATUS
350 EFIAPI
SerialControllerDriverSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)351 SerialControllerDriverSupported (
352   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
353   IN EFI_HANDLE                     Controller,
354   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
355   )
356 
357 {
358   EFI_STATUS                                Status;
359   UART_DEVICE_PATH                          *Uart;
360   UART_FLOW_CONTROL_DEVICE_PATH             *FlowControl;
361 
362   //
363   // Test RemainingDevicePath
364   //
365   if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {
366     Status = EFI_UNSUPPORTED;
367 
368     Uart = SkipControllerDevicePathNode (RemainingDevicePath, NULL, NULL);
369     if (DevicePathType (Uart) != MESSAGING_DEVICE_PATH ||
370         DevicePathSubType (Uart) != MSG_UART_DP ||
371         DevicePathNodeLength (Uart) != sizeof (UART_DEVICE_PATH)
372         ) {
373       return EFI_UNSUPPORTED;
374     }
375 
376     //
377     // Do a rough check because Clock Rate is unknown until DriverBindingStart()
378     //
379     if (!VerifyUartParameters (0, Uart->BaudRate, Uart->DataBits, Uart->Parity, Uart->StopBits, NULL, NULL)) {
380       return EFI_UNSUPPORTED;
381     }
382 
383     FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
384     if (IsUartFlowControlDevicePathNode (FlowControl)) {
385       //
386       // If the second node is Flow Control Node,
387       //   return error when it request other than hardware flow control.
388       //
389       if ((ReadUnaligned32 (&FlowControl->FlowControlMap) & ~UART_FLOW_CONTROL_HARDWARE) != 0) {
390         return EFI_UNSUPPORTED;
391       }
392     }
393   }
394 
395   Status = IsSioSerialController (Controller);
396   if (EFI_ERROR (Status)) {
397     Status = IsPciSerialController (Controller);
398   }
399   return Status;
400 }
401 
402 /**
403   Create the child serial device instance.
404 
405   @param Controller           The parent controller handle.
406   @param Uart                 Pointer to the UART device path node in RemainingDevicePath,
407                               or NULL if RemainingDevicePath is NULL.
408   @param ParentDevicePath     Pointer to the parent device path.
409   @param CreateControllerNode TRUE to create the controller node.
410   @param Instance             Instance number of the serial device.
411                               The value will be set to the controller node
412                               if CreateControllerNode is TRUE.
413   @param ParentIo             A union type pointer to either Sio or PciIo.
414   @param PciSerialParameter   The PCI serial parameter to be used by current serial device.
415                               NULL for SIO serial device.
416   @param PciDeviceInfo        The PCI device info for the current serial device.
417                               NULL for SIO serial device.
418 
419   @retval EFI_SUCCESS         The serial device was created successfully.
420   @retval others              The serial device wasn't created.
421 **/
422 EFI_STATUS
CreateSerialDevice(IN EFI_HANDLE Controller,IN UART_DEVICE_PATH * Uart,IN EFI_DEVICE_PATH_PROTOCOL * ParentDevicePath,IN BOOLEAN CreateControllerNode,IN UINT32 Instance,IN PARENT_IO_PROTOCOL_PTR ParentIo,IN PCI_SERIAL_PARAMETER * PciSerialParameter,OPTIONAL IN PCI_DEVICE_INFO * PciDeviceInfo OPTIONAL)423 CreateSerialDevice (
424   IN EFI_HANDLE                     Controller,
425   IN UART_DEVICE_PATH               *Uart,
426   IN EFI_DEVICE_PATH_PROTOCOL       *ParentDevicePath,
427   IN BOOLEAN                        CreateControllerNode,
428   IN UINT32                         Instance,
429   IN PARENT_IO_PROTOCOL_PTR         ParentIo,
430   IN PCI_SERIAL_PARAMETER           *PciSerialParameter, OPTIONAL
431   IN PCI_DEVICE_INFO                *PciDeviceInfo       OPTIONAL
432   )
433 {
434   EFI_STATUS                                 Status;
435   SERIAL_DEV                                 *SerialDevice;
436   UINT8                                      BarIndex;
437   UINT64                                     Offset;
438   UART_FLOW_CONTROL_DEVICE_PATH              *FlowControl;
439   UINT32                                     FlowControlMap;
440   ACPI_RESOURCE_HEADER_PTR                   Resources;
441   EFI_ACPI_IO_PORT_DESCRIPTOR                *Io;
442   EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIo;
443   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR          *AddressSpace;
444   EFI_DEVICE_PATH_PROTOCOL                   *TempDevicePath;
445 
446   BarIndex = 0;
447   Offset = 0;
448   FlowControl = NULL;
449   FlowControlMap = 0;
450 
451   //
452   // Initialize the serial device instance
453   //
454   SerialDevice = AllocateCopyPool (sizeof (SERIAL_DEV), &gSerialDevTemplate);
455   ASSERT (SerialDevice != NULL);
456 
457   SerialDevice->SerialIo.Mode    = &(SerialDevice->SerialMode);
458   SerialDevice->ParentDevicePath = ParentDevicePath;
459   SerialDevice->PciDeviceInfo    = PciDeviceInfo;
460   SerialDevice->Instance         = Instance;
461 
462   if (Uart != NULL) {
463     CopyMem (&SerialDevice->UartDevicePath, Uart, sizeof (UART_DEVICE_PATH));
464     FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
465     if (IsUartFlowControlDevicePathNode (FlowControl)) {
466       FlowControlMap = ReadUnaligned32 (&FlowControl->FlowControlMap);
467     } else {
468       FlowControl = NULL;
469     }
470   }
471 
472   //
473   // For PCI serial device, use the information from PCD
474   //
475   if (PciSerialParameter != NULL) {
476     BarIndex = (PciSerialParameter->BarIndex == PCI_BAR_ALL) ? 0 : PciSerialParameter->BarIndex;
477     Offset = PciSerialParameter->Offset;
478     if (PciSerialParameter->RegisterStride != 0) {
479       SerialDevice->RegisterStride = PciSerialParameter->RegisterStride;
480     }
481     if (PciSerialParameter->ClockRate != 0) {
482       SerialDevice->ClockRate = PciSerialParameter->ClockRate;
483     }
484     if (PciSerialParameter->ReceiveFifoDepth != 0) {
485       SerialDevice->ReceiveFifoDepth = PciSerialParameter->ReceiveFifoDepth;
486     }
487     if (PciSerialParameter->TransmitFifoDepth != 0) {
488       SerialDevice->TransmitFifoDepth = PciSerialParameter->TransmitFifoDepth;
489     }
490   }
491 
492   //
493   // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade.
494   // DriverBindingStart() shouldn't create a handle with different UART device path.
495   //
496   if (!VerifyUartParameters (SerialDevice->ClockRate, SerialDevice->UartDevicePath.BaudRate, SerialDevice->UartDevicePath.DataBits,
497                             SerialDevice->UartDevicePath.Parity, SerialDevice->UartDevicePath.StopBits, NULL, NULL
498                             )) {
499     Status = EFI_INVALID_PARAMETER;
500     goto CreateError;
501   }
502 
503   if (PciSerialParameter == NULL) {
504     Status = ParentIo.Sio->GetResources (ParentIo.Sio, &Resources);
505   } else {
506     Status = ParentIo.PciIo->GetBarAttributes (ParentIo.PciIo, BarIndex, NULL, (VOID **) &Resources);
507   }
508 
509   if (!EFI_ERROR (Status)) {
510     //
511     // Get the base address information from ACPI resource descriptor.
512     // ACPI_IO_PORT_DESCRIPTOR and ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR are returned from Sio;
513     // ACPI_ADDRESS_SPACE_DESCRIPTOR is returned from PciIo.
514     //
515     while ((Resources.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) && (SerialDevice->BaseAddress == 0)) {
516       switch (Resources.SmallHeader->Byte) {
517       case ACPI_IO_PORT_DESCRIPTOR:
518         Io = (EFI_ACPI_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;
519         if (Io->Length != 0) {
520           SerialDevice->BaseAddress = Io->BaseAddressMin;
521         }
522         break;
523 
524       case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR:
525         FixedIo = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;
526         if (FixedIo->Length != 0) {
527           SerialDevice->BaseAddress = FixedIo->BaseAddress;
528         }
529         break;
530 
531       case ACPI_ADDRESS_SPACE_DESCRIPTOR:
532         AddressSpace = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Resources.SmallHeader;
533         if (AddressSpace->AddrLen != 0) {
534           if (AddressSpace->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
535             SerialDevice->MmioAccess = TRUE;
536           }
537           SerialDevice->BaseAddress = AddressSpace->AddrRangeMin + Offset;
538         }
539         break;
540       }
541 
542       if (Resources.SmallHeader->Bits.Type == 0) {
543         Resources.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) Resources.SmallHeader
544                                                                 + Resources.SmallHeader->Bits.Length
545                                                                 + sizeof (*Resources.SmallHeader));
546       } else {
547         Resources.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) Resources.LargeHeader
548                                                                 + Resources.LargeHeader->Length
549                                                                 + sizeof (*Resources.LargeHeader));
550       }
551     }
552   }
553 
554   if (SerialDevice->BaseAddress == 0) {
555     Status = EFI_INVALID_PARAMETER;
556     goto CreateError;
557   }
558 
559   SerialDevice->HardwareFlowControl = (BOOLEAN) (FlowControlMap == UART_FLOW_CONTROL_HARDWARE);
560 
561   //
562   // Report status code the serial present
563   //
564   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
565     EFI_PROGRESS_CODE,
566     EFI_P_PC_PRESENCE_DETECT | EFI_PERIPHERAL_SERIAL_PORT,
567     SerialDevice->ParentDevicePath
568     );
569 
570   if (!SerialPresent (SerialDevice)) {
571     Status = EFI_DEVICE_ERROR;
572     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
573       EFI_ERROR_CODE,
574       EFI_P_EC_NOT_DETECTED | EFI_PERIPHERAL_SERIAL_PORT,
575       SerialDevice->ParentDevicePath
576       );
577     goto CreateError;
578   }
579 
580   //
581   // 1. Append Controller device path node.
582   //
583   if (CreateControllerNode) {
584     mControllerDevicePathTemplate.ControllerNumber = SerialDevice->Instance;
585     SerialDevice->DevicePath = AppendDevicePathNode (
586                                  SerialDevice->ParentDevicePath,
587                                  (EFI_DEVICE_PATH_PROTOCOL *) &mControllerDevicePathTemplate
588                                  );
589     SerialDevice->ContainsControllerNode = TRUE;
590   }
591 
592   //
593   // 2. Append UART device path node.
594   //    The Uart setings are zero here.
595   //    SetAttribute() will update them to match the default setings.
596   //
597   TempDevicePath = SerialDevice->DevicePath;
598   if (TempDevicePath != NULL) {
599     SerialDevice->DevicePath = AppendDevicePathNode (
600                                  TempDevicePath,
601                                  (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath
602                                  );
603     FreePool (TempDevicePath);
604   } else {
605     SerialDevice->DevicePath = AppendDevicePathNode (
606                                  SerialDevice->ParentDevicePath,
607                                  (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath
608                                  );
609   }
610   //
611   // 3. Append the Flow Control device path node.
612   //    Only produce the Flow Control node when remaining device path has it
613   //
614   if (FlowControl != NULL) {
615     TempDevicePath = SerialDevice->DevicePath;
616     if (TempDevicePath != NULL) {
617       SerialDevice->DevicePath = AppendDevicePathNode (
618                                    TempDevicePath,
619                                    (EFI_DEVICE_PATH_PROTOCOL *) FlowControl
620                                    );
621       FreePool (TempDevicePath);
622     }
623   }
624   ASSERT (SerialDevice->DevicePath != NULL);
625 
626   //
627   // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
628   //
629   SerialDevice->SerialMode.BaudRate = SerialDevice->UartDevicePath.BaudRate;
630   SerialDevice->SerialMode.DataBits = SerialDevice->UartDevicePath.DataBits;
631   SerialDevice->SerialMode.Parity   = SerialDevice->UartDevicePath.Parity;
632   SerialDevice->SerialMode.StopBits = SerialDevice->UartDevicePath.StopBits;
633 
634   //
635   // Issue a reset to initialize the COM port
636   //
637   Status = SerialDevice->SerialIo.Reset (&SerialDevice->SerialIo);
638   if (EFI_ERROR (Status)) {
639     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
640       EFI_ERROR_CODE,
641       EFI_P_EC_CONTROLLER_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
642       SerialDevice->DevicePath
643       );
644     goto CreateError;
645   }
646 
647   AddName (SerialDevice, Instance);
648   //
649   // Install protocol interfaces for the serial device.
650   //
651   Status = gBS->InstallMultipleProtocolInterfaces (
652                   &SerialDevice->Handle,
653                   &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,
654                   &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,
655                   NULL
656                   );
657   if (EFI_ERROR (Status)) {
658     goto CreateError;
659   }
660   //
661   // Open For Child Device
662   //
663   Status = gBS->OpenProtocol (
664                   Controller,
665                   PciSerialParameter != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
666                   (VOID **) &ParentIo,
667                   gSerialControllerDriver.DriverBindingHandle,
668                   SerialDevice->Handle,
669                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
670                   );
671 
672   if (EFI_ERROR (Status)) {
673     gBS->UninstallMultipleProtocolInterfaces (
674            &SerialDevice->Handle,
675            &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,
676            &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,
677            NULL
678            );
679   }
680 
681 CreateError:
682   if (EFI_ERROR (Status)) {
683     if (SerialDevice->DevicePath != NULL) {
684       FreePool (SerialDevice->DevicePath);
685     }
686     if (SerialDevice->ControllerNameTable != NULL) {
687       FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
688     }
689     FreePool (SerialDevice);
690   }
691   return Status;
692 }
693 
694 /**
695   Returns an array of pointers containing all the child serial device pointers.
696 
697   @param Controller      The parent controller handle.
698   @param IoProtocolGuid  The protocol GUID, either equals to gEfiSioProtocolGuid
699                          or equals to gEfiPciIoProtocolGuid.
700   @param Count           Count of the serial devices.
701 
702   @return  An array of pointers containing all the child serial device pointers.
703 **/
704 SERIAL_DEV **
GetChildSerialDevices(IN EFI_HANDLE Controller,IN EFI_GUID * IoProtocolGuid,OUT UINTN * Count)705 GetChildSerialDevices (
706   IN EFI_HANDLE                       Controller,
707   IN EFI_GUID                         *IoProtocolGuid,
708   OUT UINTN                           *Count
709   )
710 {
711   EFI_STATUS                                 Status;
712   UINTN                                      Index;
713   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY        *OpenInfoBuffer;
714   UINTN                                      EntryCount;
715   SERIAL_DEV                                 **SerialDevices;
716   EFI_SERIAL_IO_PROTOCOL                     *SerialIo;
717   BOOLEAN                                    OpenByDriver;
718 
719   *Count = 0;
720   //
721   // If the SerialIo instance specified by RemainingDevicePath is already created,
722   // update the attributes/control.
723   //
724   Status = gBS->OpenProtocolInformation (
725     Controller,
726     IoProtocolGuid,
727     &OpenInfoBuffer,
728     &EntryCount
729     );
730   if (EFI_ERROR (Status)) {
731     return NULL;
732   }
733 
734   SerialDevices = AllocatePool (EntryCount * sizeof (SERIAL_DEV *));
735   ASSERT (SerialDevices != NULL);
736 
737   *Count = 0;
738   OpenByDriver = FALSE;
739   for (Index = 0; Index < EntryCount; Index++) {
740     if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
741       Status = gBS->OpenProtocol (
742         OpenInfoBuffer[Index].ControllerHandle,
743         &gEfiSerialIoProtocolGuid,
744         (VOID **) &SerialIo,
745         gSerialControllerDriver.DriverBindingHandle,
746         Controller,
747         EFI_OPEN_PROTOCOL_GET_PROTOCOL
748         );
749       if (!EFI_ERROR (Status)) {
750         SerialDevices[(*Count)++] = SERIAL_DEV_FROM_THIS (SerialIo);
751       }
752     }
753 
754 
755     if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
756       ASSERT (OpenInfoBuffer[Index].AgentHandle == gSerialControllerDriver.DriverBindingHandle);
757       OpenByDriver = TRUE;
758     }
759   }
760   if (OpenInfoBuffer != NULL) {
761     FreePool (OpenInfoBuffer);
762   }
763 
764   ASSERT ((*Count == 0) || (OpenByDriver));
765 
766   return SerialDevices;
767 }
768 
769 /**
770   Start to management the controller passed in
771 
772   @param  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
773   @param  Controller           The handle of the controller to test.
774   @param  RemainingDevicePath  A pointer to the remaining portion of a device path.
775 
776   @return EFI_SUCCESS   Driver is started successfully
777 **/
778 EFI_STATUS
779 EFIAPI
SerialControllerDriverStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)780 SerialControllerDriverStart (
781   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
782   IN EFI_HANDLE                     Controller,
783   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
784   )
785 {
786   EFI_STATUS                                 Status;
787   UINTN                                      Index;
788   EFI_DEVICE_PATH_PROTOCOL                   *ParentDevicePath;
789   EFI_DEVICE_PATH_PROTOCOL                   *Node;
790   EFI_SERIAL_IO_PROTOCOL                     *SerialIo;
791   UINT32                                     ControllerNumber;
792   UART_DEVICE_PATH                           *Uart;
793   UART_FLOW_CONTROL_DEVICE_PATH              *FlowControl;
794   UINT32                                     Control;
795   PARENT_IO_PROTOCOL_PTR                     ParentIo;
796   ACPI_HID_DEVICE_PATH                       *Acpi;
797   EFI_GUID                                   *IoProtocolGuid;
798   PCI_SERIAL_PARAMETER                       *PciSerialParameter;
799   PCI_SERIAL_PARAMETER                       DefaultPciSerialParameter;
800   PCI_TYPE00                                 Pci;
801   UINT32                                     PciSerialCount;
802   SERIAL_DEV                                 **SerialDevices;
803   UINTN                                      SerialDeviceCount;
804   PCI_DEVICE_INFO                            *PciDeviceInfo;
805   UINT64                                     Supports;
806   BOOLEAN                                    ContainsControllerNode;
807 
808   //
809   // Get the Parent Device Path
810   //
811   Status = gBS->OpenProtocol (
812                   Controller,
813                   &gEfiDevicePathProtocolGuid,
814                   (VOID **) &ParentDevicePath,
815                   This->DriverBindingHandle,
816                   Controller,
817                   EFI_OPEN_PROTOCOL_BY_DRIVER
818                   );
819   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
820     return Status;
821   }
822   //
823   // Report status code enable the serial
824   //
825   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
826     EFI_PROGRESS_CODE,
827     EFI_P_PC_ENABLE | EFI_PERIPHERAL_SERIAL_PORT,
828     ParentDevicePath
829     );
830 
831   //
832   // Grab the IO abstraction we need to get any work done
833   //
834   IoProtocolGuid = &gEfiSioProtocolGuid;
835   Status = gBS->OpenProtocol (
836                   Controller,
837                   IoProtocolGuid,
838                   (VOID **) &ParentIo,
839                   This->DriverBindingHandle,
840                   Controller,
841                   EFI_OPEN_PROTOCOL_BY_DRIVER
842                   );
843   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
844     IoProtocolGuid = &gEfiPciIoProtocolGuid;
845     Status = gBS->OpenProtocol (
846                     Controller,
847                     IoProtocolGuid,
848                     (VOID **) &ParentIo,
849                     This->DriverBindingHandle,
850                     Controller,
851                     EFI_OPEN_PROTOCOL_BY_DRIVER
852                     );
853   }
854   ASSERT (!EFI_ERROR (Status) || Status == EFI_ALREADY_STARTED);
855 
856   //
857   // Do nothing for END device path node
858   //
859   if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
860     return EFI_SUCCESS;
861   }
862 
863   ControllerNumber = 0;
864   ContainsControllerNode = FALSE;
865   SerialDevices = GetChildSerialDevices (Controller, IoProtocolGuid, &SerialDeviceCount);
866   //
867   // If the SerialIo instance specified by RemainingDevicePath is already created,
868   // update the attributes/control.
869   //
870   if ((SerialDeviceCount != 0) && (RemainingDevicePath != NULL)) {
871     Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);
872     for (Index = 0; Index < SerialDeviceCount; Index++) {
873       ASSERT ((SerialDevices != NULL) && (SerialDevices[Index] != NULL));
874       if ((!SerialDevices[Index]->ContainsControllerNode && !ContainsControllerNode) ||
875           (SerialDevices[Index]->ContainsControllerNode && ContainsControllerNode && SerialDevices[Index]->Instance == ControllerNumber)
876           ) {
877         SerialIo = &SerialDevices[Index]->SerialIo;
878         Status = EFI_INVALID_PARAMETER;
879         //
880         // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade.
881         // DriverBindingStart() shouldn't create a handle with different UART device path.
882         //
883         if (VerifyUartParameters (SerialDevices[Index]->ClockRate, Uart->BaudRate, Uart->DataBits,
884                                   (EFI_PARITY_TYPE) Uart->Parity, (EFI_STOP_BITS_TYPE) Uart->StopBits, NULL, NULL)) {
885           Status = SerialIo->SetAttributes (
886                                SerialIo,
887                                Uart->BaudRate,
888                                SerialIo->Mode->ReceiveFifoDepth,
889                                SerialIo->Mode->Timeout,
890                                (EFI_PARITY_TYPE) Uart->Parity,
891                                Uart->DataBits,
892                                (EFI_STOP_BITS_TYPE) Uart->StopBits
893                                );
894         }
895         FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
896         if (!EFI_ERROR (Status) && IsUartFlowControlDevicePathNode (FlowControl)) {
897           Status = SerialIo->GetControl (SerialIo, &Control);
898           if (!EFI_ERROR (Status)) {
899             if (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) {
900               Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
901             } else {
902               Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
903             }
904             //
905             // Clear the bits that are not allowed to pass to SetControl
906             //
907             Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
908                         EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
909                         EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE);
910             Status = SerialIo->SetControl (SerialIo, Control);
911           }
912         }
913         break;
914       }
915     }
916     if (Index != SerialDeviceCount) {
917       //
918       // Directly return if the SerialIo instance specified by RemainingDevicePath is found and updated.
919       // Otherwise continue to create the instance specified by RemainingDevicePath.
920       //
921       if (SerialDevices != NULL) {
922         FreePool (SerialDevices);
923       }
924       return Status;
925     }
926   }
927 
928   if (RemainingDevicePath != NULL) {
929     Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);
930   } else {
931     Uart = NULL;
932   }
933 
934   PciDeviceInfo = NULL;
935   if (IoProtocolGuid == &gEfiSioProtocolGuid) {
936     Status = EFI_NOT_FOUND;
937     if (RemainingDevicePath == NULL || !ContainsControllerNode) {
938       Node = ParentDevicePath;
939       do {
940         Acpi = (ACPI_HID_DEVICE_PATH *) Node;
941         Node = NextDevicePathNode (Node);
942       } while (!IsDevicePathEnd (Node));
943       Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, Acpi->UID, ParentIo, NULL, NULL);
944       DEBUG ((EFI_D_INFO, "PciSioSerial: Create SIO child serial device - %r\n", Status));
945     }
946   } else {
947     Status = ParentIo.PciIo->Pci.Read (ParentIo.PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);
948     if (!EFI_ERROR (Status)) {
949       //
950       // PcdPciSerialParameters takes the higher priority.
951       //
952       PciSerialCount = 0;
953       for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {
954         if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&
955             (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId)
956             ) {
957           PciSerialCount++;
958         }
959       }
960 
961       if (SerialDeviceCount == 0) {
962         //
963         // Enable the IO & MEM decoding when creating the first child.
964         // Restore the PCI attributes when all children is destroyed (PciDeviceInfo->ChildCount == 0).
965         //
966         PciDeviceInfo = AllocatePool (sizeof (PCI_DEVICE_INFO));
967         ASSERT (PciDeviceInfo != NULL);
968         PciDeviceInfo->ChildCount = 0;
969         PciDeviceInfo->PciIo = ParentIo.PciIo;
970         Status = ParentIo.PciIo->Attributes (
971           ParentIo.PciIo,
972           EfiPciIoAttributeOperationGet,
973           0,
974           &PciDeviceInfo->PciAttributes
975           );
976 
977         if (!EFI_ERROR (Status)) {
978           Status = ParentIo.PciIo->Attributes (
979             ParentIo.PciIo,
980             EfiPciIoAttributeOperationSupported,
981             0,
982             &Supports
983             );
984           if (!EFI_ERROR (Status)) {
985             Supports &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY);
986             Status = ParentIo.PciIo->Attributes (
987               ParentIo.PciIo,
988               EfiPciIoAttributeOperationEnable,
989               Supports,
990               NULL
991               );
992           }
993         }
994       } else {
995         //
996         // Re-use the PciDeviceInfo stored in existing children.
997         //
998         ASSERT ((SerialDevices != NULL) && (SerialDevices[0] != NULL));
999         PciDeviceInfo = SerialDevices[0]->PciDeviceInfo;
1000         ASSERT (PciDeviceInfo != NULL);
1001       }
1002 
1003       Status = EFI_NOT_FOUND;
1004       if (PciSerialCount <= 1) {
1005         //
1006         // PCI serial device contains only one UART
1007         //
1008         if (RemainingDevicePath == NULL || !ContainsControllerNode) {
1009           //
1010           // This PCI serial device is matched by class code in Supported()
1011           //
1012           if (PciSerialCount == 0) {
1013             DefaultPciSerialParameter.VendorId = Pci.Hdr.VendorId;
1014             DefaultPciSerialParameter.DeviceId = Pci.Hdr.DeviceId;
1015             DefaultPciSerialParameter.BarIndex = 0;
1016             DefaultPciSerialParameter.Offset = 0;
1017             DefaultPciSerialParameter.RegisterStride = 0;
1018             DefaultPciSerialParameter.ClockRate = 0;
1019             PciSerialParameter = &DefaultPciSerialParameter;
1020           } else if (PciSerialCount == 1) {
1021             PciSerialParameter = PcdGetPtr (PcdPciSerialParameters);
1022           }
1023 
1024           Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, 0, ParentIo, PciSerialParameter, PciDeviceInfo);
1025           DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (single) - %r\n", Status));
1026           if (!EFI_ERROR (Status)) {
1027             PciDeviceInfo->ChildCount++;
1028           }
1029         }
1030       } else {
1031         //
1032         // PCI serial device contains multiple UARTs
1033         //
1034         if (RemainingDevicePath == NULL || ContainsControllerNode) {
1035           PciSerialCount = 0;
1036           for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {
1037             if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&
1038                 (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId) &&
1039                 ((RemainingDevicePath == NULL) || (ControllerNumber == PciSerialCount))
1040                 ) {
1041               //
1042               // Create controller node when PCI serial device contains multiple UARTs
1043               //
1044               Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, TRUE, PciSerialCount, ParentIo, PciSerialParameter, PciDeviceInfo);
1045               PciSerialCount++;
1046               DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (multiple) - %r\n", Status));
1047               if (!EFI_ERROR (Status)) {
1048                 PciDeviceInfo->ChildCount++;
1049               }
1050             }
1051           }
1052         }
1053       }
1054     }
1055   }
1056 
1057   if (SerialDevices != NULL) {
1058     FreePool (SerialDevices);
1059   }
1060 
1061   //
1062   // For multiple PCI serial devices, set Status to SUCCESS if one child is created successfully
1063   //
1064   if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount != 0)) {
1065     Status = EFI_SUCCESS;
1066   }
1067 
1068   if (EFI_ERROR (Status) && (SerialDeviceCount == 0)) {
1069     if (PciDeviceInfo != NULL) {
1070       Status = ParentIo.PciIo->Attributes (
1071         ParentIo.PciIo,
1072         EfiPciIoAttributeOperationSet,
1073         PciDeviceInfo->PciAttributes,
1074         NULL
1075         );
1076       ASSERT_EFI_ERROR (Status);
1077       FreePool (PciDeviceInfo);
1078     }
1079     gBS->CloseProtocol (
1080            Controller,
1081            &gEfiDevicePathProtocolGuid,
1082            This->DriverBindingHandle,
1083            Controller
1084            );
1085     gBS->CloseProtocol (
1086            Controller,
1087            IoProtocolGuid,
1088            This->DriverBindingHandle,
1089            Controller
1090            );
1091   }
1092 
1093   return Status;
1094 }
1095 
1096 /**
1097   Disconnect this driver with the controller, uninstall related protocol instance
1098 
1099   @param  This                  A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1100   @param  Controller            The handle of the controller to test.
1101   @param  NumberOfChildren      Number of child device.
1102   @param  ChildHandleBuffer     A pointer to the remaining portion of a device path.
1103 
1104   @retval EFI_SUCCESS           Operation successfully
1105   @retval EFI_DEVICE_ERROR      Cannot stop the driver successfully
1106 
1107 **/
1108 EFI_STATUS
1109 EFIAPI
SerialControllerDriverStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)1110 SerialControllerDriverStop (
1111   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
1112   IN  EFI_HANDLE                     Controller,
1113   IN  UINTN                          NumberOfChildren,
1114   IN  EFI_HANDLE                     *ChildHandleBuffer
1115   )
1116 
1117 {
1118   EFI_STATUS                          Status;
1119   UINTN                               Index;
1120   BOOLEAN                             AllChildrenStopped;
1121   EFI_SERIAL_IO_PROTOCOL              *SerialIo;
1122   SERIAL_DEV                          *SerialDevice;
1123   VOID                                *IoProtocol;
1124   EFI_DEVICE_PATH_PROTOCOL            *DevicePath;
1125   PCI_DEVICE_INFO                     *PciDeviceInfo;
1126 
1127   PciDeviceInfo = NULL;
1128 
1129   Status = gBS->HandleProtocol (
1130                   Controller,
1131                   &gEfiDevicePathProtocolGuid,
1132                   (VOID **) &DevicePath
1133                   );
1134 
1135   //
1136   // Report the status code disable the serial
1137   //
1138   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1139     EFI_PROGRESS_CODE,
1140     EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT,
1141     DevicePath
1142     );
1143 
1144   if (NumberOfChildren == 0) {
1145     //
1146     // Close the bus driver
1147     //
1148     Status = gBS->OpenProtocol (
1149                     Controller,
1150                     &gEfiPciIoProtocolGuid,
1151                     &IoProtocol,
1152                     This->DriverBindingHandle,
1153                     Controller,
1154                     EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1155                     );
1156     gBS->CloseProtocol (
1157            Controller,
1158            !EFI_ERROR (Status) ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
1159            This->DriverBindingHandle,
1160            Controller
1161            );
1162 
1163     gBS->CloseProtocol (
1164            Controller,
1165            &gEfiDevicePathProtocolGuid,
1166            This->DriverBindingHandle,
1167            Controller
1168            );
1169     return EFI_SUCCESS;
1170   }
1171 
1172   AllChildrenStopped = TRUE;
1173 
1174   for (Index = 0; Index < NumberOfChildren; Index++) {
1175 
1176     Status = gBS->OpenProtocol (
1177                     ChildHandleBuffer[Index],
1178                     &gEfiSerialIoProtocolGuid,
1179                     (VOID **) &SerialIo,
1180                     This->DriverBindingHandle,
1181                     Controller,
1182                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
1183                     );
1184     if (!EFI_ERROR (Status)) {
1185 
1186       SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);
1187       ASSERT ((PciDeviceInfo == NULL) || (PciDeviceInfo == SerialDevice->PciDeviceInfo));
1188       PciDeviceInfo = SerialDevice->PciDeviceInfo;
1189 
1190       Status = gBS->CloseProtocol (
1191                       Controller,
1192                       PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
1193                       This->DriverBindingHandle,
1194                       ChildHandleBuffer[Index]
1195                       );
1196 
1197       Status = gBS->UninstallMultipleProtocolInterfaces (
1198                       ChildHandleBuffer[Index],
1199                       &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,
1200                       &gEfiSerialIoProtocolGuid,   &SerialDevice->SerialIo,
1201                       NULL
1202                       );
1203       if (EFI_ERROR (Status)) {
1204         gBS->OpenProtocol (
1205                Controller,
1206                PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
1207                &IoProtocol,
1208                This->DriverBindingHandle,
1209                ChildHandleBuffer[Index],
1210                EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1211                );
1212       } else {
1213         FreePool (SerialDevice->DevicePath);
1214         FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
1215         FreePool (SerialDevice);
1216 
1217         if (PciDeviceInfo != NULL) {
1218           ASSERT (PciDeviceInfo->ChildCount != 0);
1219           PciDeviceInfo->ChildCount--;
1220         }
1221       }
1222     }
1223 
1224     if (EFI_ERROR (Status)) {
1225       AllChildrenStopped = FALSE;
1226     }
1227   }
1228 
1229   if (!AllChildrenStopped) {
1230     return EFI_DEVICE_ERROR;
1231   } else {
1232     //
1233     // If all children are destroyed, restore the PCI attributes.
1234     //
1235     if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount == 0)) {
1236       ASSERT (PciDeviceInfo->PciIo != NULL);
1237       Status = PciDeviceInfo->PciIo->Attributes (
1238         PciDeviceInfo->PciIo,
1239         EfiPciIoAttributeOperationSet,
1240         PciDeviceInfo->PciAttributes,
1241         NULL
1242         );
1243       ASSERT_EFI_ERROR (Status);
1244       FreePool (PciDeviceInfo);
1245     }
1246     return EFI_SUCCESS;
1247   }
1248 }
1249