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