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