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