65ddf5dc2ba70fc7ac3c0f3c21466b3033ce6518
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciSioSerialDxe / Serial.c
1 /** @file
2 Serial driver for PCI or SIO UARTS.
3
4 Copyright (c) 2006 - 2016, 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
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
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
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
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
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
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 **
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
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 (SerialDeviceCount != 0) {
868 if (RemainingDevicePath == NULL) {
869 //
870 // If the SerialIo instance is already created, NULL as RemainingDevicePath is treated
871 // as to create the same SerialIo instance.
872 //
873 return EFI_SUCCESS;
874 } else {
875 //
876 // Update the attributes/control of the SerialIo instance specified by RemainingDevicePath.
877 //
878 Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);
879 for (Index = 0; Index < SerialDeviceCount; Index++) {
880 ASSERT ((SerialDevices != NULL) && (SerialDevices[Index] != NULL));
881 if ((!SerialDevices[Index]->ContainsControllerNode && !ContainsControllerNode) ||
882 (SerialDevices[Index]->ContainsControllerNode && ContainsControllerNode && SerialDevices[Index]->Instance == ControllerNumber)
883 ) {
884 SerialIo = &SerialDevices[Index]->SerialIo;
885 Status = EFI_INVALID_PARAMETER;
886 //
887 // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade.
888 // DriverBindingStart() shouldn't create a handle with different UART device path.
889 //
890 if (VerifyUartParameters (SerialDevices[Index]->ClockRate, Uart->BaudRate, Uart->DataBits,
891 (EFI_PARITY_TYPE) Uart->Parity, (EFI_STOP_BITS_TYPE) Uart->StopBits, NULL, NULL)) {
892 Status = SerialIo->SetAttributes (
893 SerialIo,
894 Uart->BaudRate,
895 SerialIo->Mode->ReceiveFifoDepth,
896 SerialIo->Mode->Timeout,
897 (EFI_PARITY_TYPE) Uart->Parity,
898 Uart->DataBits,
899 (EFI_STOP_BITS_TYPE) Uart->StopBits
900 );
901 }
902 FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
903 if (!EFI_ERROR (Status) && IsUartFlowControlDevicePathNode (FlowControl)) {
904 Status = SerialIo->GetControl (SerialIo, &Control);
905 if (!EFI_ERROR (Status)) {
906 if (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) {
907 Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
908 } else {
909 Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
910 }
911 //
912 // Clear the bits that are not allowed to pass to SetControl
913 //
914 Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
915 EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
916 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE);
917 Status = SerialIo->SetControl (SerialIo, Control);
918 }
919 }
920 break;
921 }
922 }
923 if (Index != SerialDeviceCount) {
924 //
925 // Directly return if the SerialIo instance specified by RemainingDevicePath is found and updated.
926 // Otherwise continue to create the instance specified by RemainingDevicePath.
927 //
928 if (SerialDevices != NULL) {
929 FreePool (SerialDevices);
930 }
931 return Status;
932 }
933 }
934 }
935
936 if (RemainingDevicePath != NULL) {
937 Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);
938 } else {
939 Uart = NULL;
940 }
941
942 PciDeviceInfo = NULL;
943 if (IoProtocolGuid == &gEfiSioProtocolGuid) {
944 Status = EFI_NOT_FOUND;
945 if (RemainingDevicePath == NULL || !ContainsControllerNode) {
946 Node = ParentDevicePath;
947 do {
948 Acpi = (ACPI_HID_DEVICE_PATH *) Node;
949 Node = NextDevicePathNode (Node);
950 } while (!IsDevicePathEnd (Node));
951 Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, Acpi->UID, ParentIo, NULL, NULL);
952 DEBUG ((EFI_D_INFO, "PciSioSerial: Create SIO child serial device - %r\n", Status));
953 }
954 } else {
955 Status = ParentIo.PciIo->Pci.Read (ParentIo.PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);
956 if (!EFI_ERROR (Status)) {
957 //
958 // PcdPciSerialParameters takes the higher priority.
959 //
960 PciSerialCount = 0;
961 for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {
962 if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&
963 (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId)
964 ) {
965 PciSerialCount++;
966 }
967 }
968
969 if (SerialDeviceCount == 0) {
970 //
971 // Enable the IO & MEM decoding when creating the first child.
972 // Restore the PCI attributes when all children is destroyed (PciDeviceInfo->ChildCount == 0).
973 //
974 PciDeviceInfo = AllocatePool (sizeof (PCI_DEVICE_INFO));
975 ASSERT (PciDeviceInfo != NULL);
976 PciDeviceInfo->ChildCount = 0;
977 PciDeviceInfo->PciIo = ParentIo.PciIo;
978 Status = ParentIo.PciIo->Attributes (
979 ParentIo.PciIo,
980 EfiPciIoAttributeOperationGet,
981 0,
982 &PciDeviceInfo->PciAttributes
983 );
984
985 if (!EFI_ERROR (Status)) {
986 Status = ParentIo.PciIo->Attributes (
987 ParentIo.PciIo,
988 EfiPciIoAttributeOperationSupported,
989 0,
990 &Supports
991 );
992 if (!EFI_ERROR (Status)) {
993 Supports &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY);
994 Status = ParentIo.PciIo->Attributes (
995 ParentIo.PciIo,
996 EfiPciIoAttributeOperationEnable,
997 Supports,
998 NULL
999 );
1000 }
1001 }
1002 } else {
1003 //
1004 // Re-use the PciDeviceInfo stored in existing children.
1005 //
1006 ASSERT ((SerialDevices != NULL) && (SerialDevices[0] != NULL));
1007 PciDeviceInfo = SerialDevices[0]->PciDeviceInfo;
1008 ASSERT (PciDeviceInfo != NULL);
1009 }
1010
1011 Status = EFI_NOT_FOUND;
1012 if (PciSerialCount <= 1) {
1013 //
1014 // PCI serial device contains only one UART
1015 //
1016 if (RemainingDevicePath == NULL || !ContainsControllerNode) {
1017 //
1018 // This PCI serial device is matched by class code in Supported()
1019 //
1020 if (PciSerialCount == 0) {
1021 DefaultPciSerialParameter.VendorId = Pci.Hdr.VendorId;
1022 DefaultPciSerialParameter.DeviceId = Pci.Hdr.DeviceId;
1023 DefaultPciSerialParameter.BarIndex = 0;
1024 DefaultPciSerialParameter.Offset = 0;
1025 DefaultPciSerialParameter.RegisterStride = 0;
1026 DefaultPciSerialParameter.ClockRate = 0;
1027 PciSerialParameter = &DefaultPciSerialParameter;
1028 } else if (PciSerialCount == 1) {
1029 PciSerialParameter = PcdGetPtr (PcdPciSerialParameters);
1030 }
1031
1032 Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, 0, ParentIo, PciSerialParameter, PciDeviceInfo);
1033 DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (single) - %r\n", Status));
1034 if (!EFI_ERROR (Status)) {
1035 PciDeviceInfo->ChildCount++;
1036 }
1037 }
1038 } else {
1039 //
1040 // PCI serial device contains multiple UARTs
1041 //
1042 if (RemainingDevicePath == NULL || ContainsControllerNode) {
1043 PciSerialCount = 0;
1044 for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {
1045 if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&
1046 (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId) &&
1047 ((RemainingDevicePath == NULL) || (ControllerNumber == PciSerialCount))
1048 ) {
1049 //
1050 // Create controller node when PCI serial device contains multiple UARTs
1051 //
1052 Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, TRUE, PciSerialCount, ParentIo, PciSerialParameter, PciDeviceInfo);
1053 PciSerialCount++;
1054 DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (multiple) - %r\n", Status));
1055 if (!EFI_ERROR (Status)) {
1056 PciDeviceInfo->ChildCount++;
1057 }
1058 }
1059 }
1060 }
1061 }
1062 }
1063 }
1064
1065 if (SerialDevices != NULL) {
1066 FreePool (SerialDevices);
1067 }
1068
1069 //
1070 // For multiple PCI serial devices, set Status to SUCCESS if one child is created successfully
1071 //
1072 if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount != 0)) {
1073 Status = EFI_SUCCESS;
1074 }
1075
1076 if (EFI_ERROR (Status) && (SerialDeviceCount == 0)) {
1077 if (PciDeviceInfo != NULL) {
1078 Status = ParentIo.PciIo->Attributes (
1079 ParentIo.PciIo,
1080 EfiPciIoAttributeOperationSet,
1081 PciDeviceInfo->PciAttributes,
1082 NULL
1083 );
1084 ASSERT_EFI_ERROR (Status);
1085 FreePool (PciDeviceInfo);
1086 }
1087 gBS->CloseProtocol (
1088 Controller,
1089 &gEfiDevicePathProtocolGuid,
1090 This->DriverBindingHandle,
1091 Controller
1092 );
1093 gBS->CloseProtocol (
1094 Controller,
1095 IoProtocolGuid,
1096 This->DriverBindingHandle,
1097 Controller
1098 );
1099 }
1100
1101 return Status;
1102 }
1103
1104 /**
1105 Disconnect this driver with the controller, uninstall related protocol instance
1106
1107 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1108 @param Controller The handle of the controller to test.
1109 @param NumberOfChildren Number of child device.
1110 @param ChildHandleBuffer A pointer to the remaining portion of a device path.
1111
1112 @retval EFI_SUCCESS Operation successfully
1113 @retval EFI_DEVICE_ERROR Cannot stop the driver successfully
1114
1115 **/
1116 EFI_STATUS
1117 EFIAPI
1118 SerialControllerDriverStop (
1119 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1120 IN EFI_HANDLE Controller,
1121 IN UINTN NumberOfChildren,
1122 IN EFI_HANDLE *ChildHandleBuffer
1123 )
1124
1125 {
1126 EFI_STATUS Status;
1127 UINTN Index;
1128 BOOLEAN AllChildrenStopped;
1129 EFI_SERIAL_IO_PROTOCOL *SerialIo;
1130 SERIAL_DEV *SerialDevice;
1131 VOID *IoProtocol;
1132 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1133 PCI_DEVICE_INFO *PciDeviceInfo;
1134
1135 PciDeviceInfo = NULL;
1136
1137 Status = gBS->HandleProtocol (
1138 Controller,
1139 &gEfiDevicePathProtocolGuid,
1140 (VOID **) &DevicePath
1141 );
1142
1143 //
1144 // Report the status code disable the serial
1145 //
1146 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1147 EFI_PROGRESS_CODE,
1148 EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT,
1149 DevicePath
1150 );
1151
1152 if (NumberOfChildren == 0) {
1153 //
1154 // Close the bus driver
1155 //
1156 Status = gBS->OpenProtocol (
1157 Controller,
1158 &gEfiPciIoProtocolGuid,
1159 &IoProtocol,
1160 This->DriverBindingHandle,
1161 Controller,
1162 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1163 );
1164 gBS->CloseProtocol (
1165 Controller,
1166 !EFI_ERROR (Status) ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
1167 This->DriverBindingHandle,
1168 Controller
1169 );
1170
1171 gBS->CloseProtocol (
1172 Controller,
1173 &gEfiDevicePathProtocolGuid,
1174 This->DriverBindingHandle,
1175 Controller
1176 );
1177 return EFI_SUCCESS;
1178 }
1179
1180 AllChildrenStopped = TRUE;
1181
1182 for (Index = 0; Index < NumberOfChildren; Index++) {
1183
1184 Status = gBS->OpenProtocol (
1185 ChildHandleBuffer[Index],
1186 &gEfiSerialIoProtocolGuid,
1187 (VOID **) &SerialIo,
1188 This->DriverBindingHandle,
1189 Controller,
1190 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1191 );
1192 if (!EFI_ERROR (Status)) {
1193
1194 SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);
1195 ASSERT ((PciDeviceInfo == NULL) || (PciDeviceInfo == SerialDevice->PciDeviceInfo));
1196 PciDeviceInfo = SerialDevice->PciDeviceInfo;
1197
1198 Status = gBS->CloseProtocol (
1199 Controller,
1200 PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
1201 This->DriverBindingHandle,
1202 ChildHandleBuffer[Index]
1203 );
1204
1205 Status = gBS->UninstallMultipleProtocolInterfaces (
1206 ChildHandleBuffer[Index],
1207 &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,
1208 &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,
1209 NULL
1210 );
1211 if (EFI_ERROR (Status)) {
1212 gBS->OpenProtocol (
1213 Controller,
1214 PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
1215 &IoProtocol,
1216 This->DriverBindingHandle,
1217 ChildHandleBuffer[Index],
1218 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1219 );
1220 } else {
1221 FreePool (SerialDevice->DevicePath);
1222 FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
1223 FreePool (SerialDevice);
1224
1225 if (PciDeviceInfo != NULL) {
1226 ASSERT (PciDeviceInfo->ChildCount != 0);
1227 PciDeviceInfo->ChildCount--;
1228 }
1229 }
1230 }
1231
1232 if (EFI_ERROR (Status)) {
1233 AllChildrenStopped = FALSE;
1234 }
1235 }
1236
1237 if (!AllChildrenStopped) {
1238 return EFI_DEVICE_ERROR;
1239 } else {
1240 //
1241 // If all children are destroyed, restore the PCI attributes.
1242 //
1243 if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount == 0)) {
1244 ASSERT (PciDeviceInfo->PciIo != NULL);
1245 Status = PciDeviceInfo->PciIo->Attributes (
1246 PciDeviceInfo->PciIo,
1247 EfiPciIoAttributeOperationSet,
1248 PciDeviceInfo->PciAttributes,
1249 NULL
1250 );
1251 ASSERT_EFI_ERROR (Status);
1252 FreePool (PciDeviceInfo);
1253 }
1254 return EFI_SUCCESS;
1255 }
1256 }