]> git.proxmox.com Git - mirror_edk2.git/blame - CorebootModulePkg/PciSioSerialDxe/Serial.c
MdeModulePkg: Refine the code for DxeHttpLib
[mirror_edk2.git] / CorebootModulePkg / PciSioSerialDxe / Serial.c
CommitLineData
7cac40ba
LL
1/** @file
2 Serial driver for PCI or SIO UARTS.
3
4Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT 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
21EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = {
22 SerialControllerDriverSupported,
23 SerialControllerDriverStart,
24 SerialControllerDriverStop,
25 0xa,
26 NULL,
27 NULL
28};
29
30CONTROLLER_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
42SERIAL_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**/
102BOOLEAN
103IsUartFlowControlDevicePathNode (
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**/
124EFI_STATUS
125EFIAPI
126InitializePciSioSerial (
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**/
170EFI_STATUS
171IsSioSerialController (
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**/
251EFI_STATUS
252IsPciSerialController (
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**/
349EFI_STATUS
350EFIAPI
351SerialControllerDriverSupported (
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**/
422EFI_STATUS
423CreateSerialDevice (
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
681CreateError:
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**/
704SERIAL_DEV **
705GetChildSerialDevices (
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**/
778EFI_STATUS
779EFIAPI
780SerialControllerDriverStart (
781 IN EFI_DRIVER_BINDING_PROTOCOL *This,
782 IN EFI_HANDLE Controller,
783 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
784 )
785{
786 EFI_STATUS Status;
787 UINTN Index;
788 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
789 EFI_DEVICE_PATH_PROTOCOL *Node;
790 EFI_SERIAL_IO_PROTOCOL *SerialIo;
791 UINT32 ControllerNumber;
792 UART_DEVICE_PATH *Uart;
793 UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
794 UINT32 Control;
795 PARENT_IO_PROTOCOL_PTR ParentIo;
796 ACPI_HID_DEVICE_PATH *Acpi;
797 EFI_GUID *IoProtocolGuid;
798 PCI_SERIAL_PARAMETER *PciSerialParameter;
799 PCI_SERIAL_PARAMETER DefaultPciSerialParameter;
800 PCI_TYPE00 Pci;
801 UINT32 PciSerialCount;
802 SERIAL_DEV **SerialDevices;
803 UINTN SerialDeviceCount;
804 PCI_DEVICE_INFO *PciDeviceInfo;
805 UINT64 Supports;
806 BOOLEAN ContainsControllerNode;
807
808 //
809 // Get the Parent Device Path
810 //
811 Status = gBS->OpenProtocol (
812 Controller,
813 &gEfiDevicePathProtocolGuid,
814 (VOID **) &ParentDevicePath,
815 This->DriverBindingHandle,
816 Controller,
817 EFI_OPEN_PROTOCOL_BY_DRIVER
818 );
819 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
820 return Status;
821 }
822 //
823 // Report status code enable the serial
824 //
825 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
826 EFI_PROGRESS_CODE,
827 EFI_P_PC_ENABLE | EFI_PERIPHERAL_SERIAL_PORT,
828 ParentDevicePath
829 );
830
831 //
832 // Grab the IO abstraction we need to get any work done
833 //
834 IoProtocolGuid = &gEfiSioProtocolGuid;
835 Status = gBS->OpenProtocol (
836 Controller,
837 IoProtocolGuid,
838 (VOID **) &ParentIo,
839 This->DriverBindingHandle,
840 Controller,
841 EFI_OPEN_PROTOCOL_BY_DRIVER
842 );
843 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
844 IoProtocolGuid = &gEfiPciIoProtocolGuid;
845 Status = gBS->OpenProtocol (
846 Controller,
847 IoProtocolGuid,
848 (VOID **) &ParentIo,
849 This->DriverBindingHandle,
850 Controller,
851 EFI_OPEN_PROTOCOL_BY_DRIVER
852 );
853 }
854 ASSERT (!EFI_ERROR (Status) || Status == EFI_ALREADY_STARTED);
855
856 //
857 // Do nothing for END device path node
858 //
859 if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
860 return EFI_SUCCESS;
861 }
862
863 ControllerNumber = 0;
864 ContainsControllerNode = FALSE;
865 SerialDevices = GetChildSerialDevices (Controller, IoProtocolGuid, &SerialDeviceCount);
866 //
867 // If the SerialIo instance specified by RemainingDevicePath is already created,
868 // update the attributes/control.
869 //
870 if ((SerialDeviceCount != 0) && (RemainingDevicePath != NULL)) {
871 Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);
872 for (Index = 0; Index < SerialDeviceCount; Index++) {
873 ASSERT ((SerialDevices != NULL) && (SerialDevices[Index] != NULL));
874 if ((!SerialDevices[Index]->ContainsControllerNode && !ContainsControllerNode) ||
875 (SerialDevices[Index]->ContainsControllerNode && ContainsControllerNode && SerialDevices[Index]->Instance == ControllerNumber)
876 ) {
877 SerialIo = &SerialDevices[Index]->SerialIo;
878 Status = EFI_INVALID_PARAMETER;
879 //
880 // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade.
881 // DriverBindingStart() shouldn't create a handle with different UART device path.
882 //
883 if (VerifyUartParameters (SerialDevices[Index]->ClockRate, Uart->BaudRate, Uart->DataBits,
884 (EFI_PARITY_TYPE) Uart->Parity, (EFI_STOP_BITS_TYPE) Uart->StopBits, NULL, NULL)) {
885 Status = SerialIo->SetAttributes (
886 SerialIo,
887 Uart->BaudRate,
888 SerialIo->Mode->ReceiveFifoDepth,
889 SerialIo->Mode->Timeout,
890 (EFI_PARITY_TYPE) Uart->Parity,
891 Uart->DataBits,
892 (EFI_STOP_BITS_TYPE) Uart->StopBits
893 );
894 }
895 FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
896 if (!EFI_ERROR (Status) && IsUartFlowControlDevicePathNode (FlowControl)) {
897 Status = SerialIo->GetControl (SerialIo, &Control);
898 if (!EFI_ERROR (Status)) {
899 if (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) {
900 Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
901 } else {
902 Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
903 }
904 //
905 // Clear the bits that are not allowed to pass to SetControl
906 //
907 Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
908 EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
909 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE);
910 Status = SerialIo->SetControl (SerialIo, Control);
911 }
912 }
913 break;
914 }
915 }
916 if (Index != SerialDeviceCount) {
917 //
918 // Directly return if the SerialIo instance specified by RemainingDevicePath is found and updated.
919 // Otherwise continue to create the instance specified by RemainingDevicePath.
920 //
921 if (SerialDevices != NULL) {
922 FreePool (SerialDevices);
923 }
924 return Status;
925 }
926 }
927
928 if (RemainingDevicePath != NULL) {
929 Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);
930 } else {
931 Uart = NULL;
932 }
933
934 PciDeviceInfo = NULL;
935 if (IoProtocolGuid == &gEfiSioProtocolGuid) {
936 Status = EFI_NOT_FOUND;
937 if (RemainingDevicePath == NULL || !ContainsControllerNode) {
938 Node = ParentDevicePath;
939 do {
940 Acpi = (ACPI_HID_DEVICE_PATH *) Node;
941 Node = NextDevicePathNode (Node);
942 } while (!IsDevicePathEnd (Node));
943 Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, Acpi->UID, ParentIo, NULL, NULL);
944 DEBUG ((EFI_D_INFO, "PciSioSerial: Create SIO child serial device - %r\n", Status));
945 }
946 } else {
947 Status = ParentIo.PciIo->Pci.Read (ParentIo.PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);
948 if (!EFI_ERROR (Status)) {
949 //
950 // PcdPciSerialParameters takes the higher priority.
951 //
952 PciSerialCount = 0;
953 for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {
954 if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&
955 (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId)
956 ) {
957 PciSerialCount++;
958 }
959 }
960
961 if (SerialDeviceCount == 0) {
962 //
963 // Enable the IO & MEM decoding when creating the first child.
964 // Restore the PCI attributes when all children is destroyed (PciDeviceInfo->ChildCount == 0).
965 //
966 PciDeviceInfo = AllocatePool (sizeof (PCI_DEVICE_INFO));
967 ASSERT (PciDeviceInfo != NULL);
968 PciDeviceInfo->ChildCount = 0;
969 PciDeviceInfo->PciIo = ParentIo.PciIo;
970 Status = ParentIo.PciIo->Attributes (
971 ParentIo.PciIo,
972 EfiPciIoAttributeOperationGet,
973 0,
974 &PciDeviceInfo->PciAttributes
975 );
976
977 if (!EFI_ERROR (Status)) {
978 Status = ParentIo.PciIo->Attributes (
979 ParentIo.PciIo,
980 EfiPciIoAttributeOperationSupported,
981 0,
982 &Supports
983 );
984 if (!EFI_ERROR (Status)) {
985 Supports &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY);
986 Status = ParentIo.PciIo->Attributes (
987 ParentIo.PciIo,
988 EfiPciIoAttributeOperationEnable,
989 Supports,
990 NULL
991 );
992 }
993 }
994 } else {
995 //
996 // Re-use the PciDeviceInfo stored in existing children.
997 //
998 ASSERT ((SerialDevices != NULL) && (SerialDevices[0] != NULL));
999 PciDeviceInfo = SerialDevices[0]->PciDeviceInfo;
1000 ASSERT (PciDeviceInfo != NULL);
1001 }
1002
1003 Status = EFI_NOT_FOUND;
1004 if (PciSerialCount <= 1) {
1005 //
1006 // PCI serial device contains only one UART
1007 //
1008 if (RemainingDevicePath == NULL || !ContainsControllerNode) {
1009 //
1010 // This PCI serial device is matched by class code in Supported()
1011 //
1012 if (PciSerialCount == 0) {
1013 DefaultPciSerialParameter.VendorId = Pci.Hdr.VendorId;
1014 DefaultPciSerialParameter.DeviceId = Pci.Hdr.DeviceId;
1015 DefaultPciSerialParameter.BarIndex = 0;
1016 DefaultPciSerialParameter.Offset = 0;
1017 DefaultPciSerialParameter.RegisterStride = 0;
1018 DefaultPciSerialParameter.ClockRate = 0;
1019 PciSerialParameter = &DefaultPciSerialParameter;
1020 } else if (PciSerialCount == 1) {
1021 PciSerialParameter = PcdGetPtr (PcdPciSerialParameters);
1022 }
1023
1024 Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, 0, ParentIo, PciSerialParameter, PciDeviceInfo);
1025 DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (single) - %r\n", Status));
1026 if (!EFI_ERROR (Status)) {
1027 PciDeviceInfo->ChildCount++;
1028 }
1029 }
1030 } else {
1031 //
1032 // PCI serial device contains multiple UARTs
1033 //
1034 if (RemainingDevicePath == NULL || ContainsControllerNode) {
1035 PciSerialCount = 0;
1036 for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {
1037 if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&
1038 (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId) &&
1039 ((RemainingDevicePath == NULL) || (ControllerNumber == PciSerialCount))
1040 ) {
1041 //
1042 // Create controller node when PCI serial device contains multiple UARTs
1043 //
1044 Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, TRUE, PciSerialCount, ParentIo, PciSerialParameter, PciDeviceInfo);
1045 PciSerialCount++;
1046 DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (multiple) - %r\n", Status));
1047 if (!EFI_ERROR (Status)) {
1048 PciDeviceInfo->ChildCount++;
1049 }
1050 }
1051 }
1052 }
1053 }
1054 }
1055 }
1056
1057 if (SerialDevices != NULL) {
1058 FreePool (SerialDevices);
1059 }
1060
1061 //
1062 // For multiple PCI serial devices, set Status to SUCCESS if one child is created successfully
1063 //
1064 if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount != 0)) {
1065 Status = EFI_SUCCESS;
1066 }
1067
1068 if (EFI_ERROR (Status) && (SerialDeviceCount == 0)) {
1069 if (PciDeviceInfo != NULL) {
1070 Status = ParentIo.PciIo->Attributes (
1071 ParentIo.PciIo,
1072 EfiPciIoAttributeOperationSet,
1073 PciDeviceInfo->PciAttributes,
1074 NULL
1075 );
1076 ASSERT_EFI_ERROR (Status);
1077 FreePool (PciDeviceInfo);
1078 }
1079 gBS->CloseProtocol (
1080 Controller,
1081 &gEfiDevicePathProtocolGuid,
1082 This->DriverBindingHandle,
1083 Controller
1084 );
1085 gBS->CloseProtocol (
1086 Controller,
1087 IoProtocolGuid,
1088 This->DriverBindingHandle,
1089 Controller
1090 );
1091 }
1092
1093 return Status;
1094}
1095
1096/**
1097 Disconnect this driver with the controller, uninstall related protocol instance
1098
1099 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1100 @param Controller The handle of the controller to test.
1101 @param NumberOfChildren Number of child device.
1102 @param ChildHandleBuffer A pointer to the remaining portion of a device path.
1103
1104 @retval EFI_SUCCESS Operation successfully
1105 @retval EFI_DEVICE_ERROR Cannot stop the driver successfully
1106
1107**/
1108EFI_STATUS
1109EFIAPI
1110SerialControllerDriverStop (
1111 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1112 IN EFI_HANDLE Controller,
1113 IN UINTN NumberOfChildren,
1114 IN EFI_HANDLE *ChildHandleBuffer
1115 )
1116
1117{
1118 EFI_STATUS Status;
1119 UINTN Index;
1120 BOOLEAN AllChildrenStopped;
1121 EFI_SERIAL_IO_PROTOCOL *SerialIo;
1122 SERIAL_DEV *SerialDevice;
1123 VOID *IoProtocol;
1124 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1125 PCI_DEVICE_INFO *PciDeviceInfo;
1126
1127 PciDeviceInfo = NULL;
1128
1129 Status = gBS->HandleProtocol (
1130 Controller,
1131 &gEfiDevicePathProtocolGuid,
1132 (VOID **) &DevicePath
1133 );
1134
1135 //
1136 // Report the status code disable the serial
1137 //
1138 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1139 EFI_PROGRESS_CODE,
1140 EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT,
1141 DevicePath
1142 );
1143
1144 if (NumberOfChildren == 0) {
1145 //
1146 // Close the bus driver
1147 //
1148 Status = gBS->OpenProtocol (
1149 Controller,
1150 &gEfiPciIoProtocolGuid,
1151 &IoProtocol,
1152 This->DriverBindingHandle,
1153 Controller,
1154 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1155 );
1156 gBS->CloseProtocol (
1157 Controller,
1158 !EFI_ERROR (Status) ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
1159 This->DriverBindingHandle,
1160 Controller
1161 );
1162
1163 gBS->CloseProtocol (
1164 Controller,
1165 &gEfiDevicePathProtocolGuid,
1166 This->DriverBindingHandle,
1167 Controller
1168 );
1169 return EFI_SUCCESS;
1170 }
1171
1172 AllChildrenStopped = TRUE;
1173
1174 for (Index = 0; Index < NumberOfChildren; Index++) {
1175
1176 Status = gBS->OpenProtocol (
1177 ChildHandleBuffer[Index],
1178 &gEfiSerialIoProtocolGuid,
1179 (VOID **) &SerialIo,
1180 This->DriverBindingHandle,
1181 Controller,
1182 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1183 );
1184 if (!EFI_ERROR (Status)) {
1185
1186 SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);
1187 ASSERT ((PciDeviceInfo == NULL) || (PciDeviceInfo == SerialDevice->PciDeviceInfo));
1188 PciDeviceInfo = SerialDevice->PciDeviceInfo;
1189
1190 Status = gBS->CloseProtocol (
1191 Controller,
1192 PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
1193 This->DriverBindingHandle,
1194 ChildHandleBuffer[Index]
1195 );
1196
1197 Status = gBS->UninstallMultipleProtocolInterfaces (
1198 ChildHandleBuffer[Index],
1199 &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,
1200 &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,
1201 NULL
1202 );
1203 if (EFI_ERROR (Status)) {
1204 gBS->OpenProtocol (
1205 Controller,
1206 PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
1207 &IoProtocol,
1208 This->DriverBindingHandle,
1209 ChildHandleBuffer[Index],
1210 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1211 );
1212 } else {
1213 FreePool (SerialDevice->DevicePath);
1214 FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
1215 FreePool (SerialDevice);
1216
1217 if (PciDeviceInfo != NULL) {
1218 ASSERT (PciDeviceInfo->ChildCount != 0);
1219 PciDeviceInfo->ChildCount--;
1220 }
1221 }
1222 }
1223
1224 if (EFI_ERROR (Status)) {
1225 AllChildrenStopped = FALSE;
1226 }
1227 }
1228
1229 if (!AllChildrenStopped) {
1230 return EFI_DEVICE_ERROR;
1231 } else {
1232 //
1233 // If all children are destroyed, restore the PCI attributes.
1234 //
1235 if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount == 0)) {
1236 ASSERT (PciDeviceInfo->PciIo != NULL);
1237 Status = PciDeviceInfo->PciIo->Attributes (
1238 PciDeviceInfo->PciIo,
1239 EfiPciIoAttributeOperationSet,
1240 PciDeviceInfo->PciAttributes,
1241 NULL
1242 );
1243 ASSERT_EFI_ERROR (Status);
1244 FreePool (PciDeviceInfo);
1245 }
1246 return EFI_SUCCESS;
1247 }
1248}