]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c
MdeModulePkg/PciSioSerialDxe:add non-null pointer dereference assertion
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciSioSerialDxe / Serial.c
1 /** @file
2 Serial driver for PCI or SIO UARTS.
3
4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "Serial.h"
16
17 //
18 // ISA Serial Driver Global Variables
19 //
20
21 EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = {
22 SerialControllerDriverSupported,
23 SerialControllerDriverStart,
24 SerialControllerDriverStop,
25 0xa,
26 NULL,
27 NULL
28 };
29
30 CONTROLLER_DEVICE_PATH mControllerDevicePathTemplate = {
31 {
32 HARDWARE_DEVICE_PATH,
33 HW_CONTROLLER_DP,
34 {
35 (UINT8) (sizeof (CONTROLLER_DEVICE_PATH)),
36 (UINT8) ((sizeof (CONTROLLER_DEVICE_PATH)) >> 8)
37 }
38 },
39 0
40 };
41
42 SERIAL_DEV gSerialDevTemplate = {
43 SERIAL_DEV_SIGNATURE,
44 NULL,
45 {
46 SERIAL_IO_INTERFACE_REVISION,
47 SerialReset,
48 SerialSetAttributes,
49 SerialSetControl,
50 SerialGetControl,
51 SerialWrite,
52 SerialRead,
53 NULL
54 }, // SerialIo
55 {
56 SERIAL_PORT_SUPPORT_CONTROL_MASK,
57 SERIAL_PORT_DEFAULT_TIMEOUT,
58 0,
59 16,
60 0,
61 0,
62 0
63 }, // SerialMode
64 NULL, // DevicePath
65 NULL, // ParentDevicePath
66 {
67 {
68 MESSAGING_DEVICE_PATH,
69 MSG_UART_DP,
70 {
71 (UINT8) (sizeof (UART_DEVICE_PATH)),
72 (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)
73 }
74 },
75 0, 0, 0, 0, 0
76 }, // UartDevicePath
77 0, // BaseAddress
78 FALSE, // MmioAccess
79 1, // RegisterStride
80 0, // ClockRate
81 16, // ReceiveFifoDepth
82 { 0, 0 }, // Receive;
83 16, // TransmitFifoDepth
84 { 0, 0 }, // Transmit;
85 FALSE, // SoftwareLoopbackEnable;
86 FALSE, // HardwareFlowControl;
87 NULL, // *ControllerNameTable;
88 FALSE, // ContainsControllerNode;
89 0, // Instance;
90 NULL // *PciDeviceInfo;
91 };
92
93 /**
94 Check the device path node whether it's the Flow Control node or not.
95
96 @param[in] FlowControl The device path node to be checked.
97
98 @retval TRUE It's the Flow Control node.
99 @retval FALSE It's not.
100
101 **/
102 BOOLEAN
103 IsUartFlowControlDevicePathNode (
104 IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl
105 )
106 {
107 return (BOOLEAN) (
108 (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) &&
109 (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) &&
110 (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid))
111 );
112 }
113
114 /**
115 The user Entry Point for module PciSioSerial. The user code starts with this function.
116
117 @param[in] ImageHandle The firmware allocated handle for the EFI image.
118 @param[in] SystemTable A pointer to the EFI System Table.
119
120 @retval EFI_SUCCESS The entry point is executed successfully.
121 @retval other Some error occurs when executing this entry point.
122
123 **/
124 EFI_STATUS
125 EFIAPI
126 InitializePciSioSerial (
127 IN EFI_HANDLE ImageHandle,
128 IN EFI_SYSTEM_TABLE *SystemTable
129 )
130 {
131 EFI_STATUS Status;
132
133 //
134 // Install driver model protocol(s).
135 //
136 Status = EfiLibInstallDriverBindingComponentName2 (
137 ImageHandle,
138 SystemTable,
139 &gSerialControllerDriver,
140 ImageHandle,
141 &gPciSioSerialComponentName,
142 &gPciSioSerialComponentName2
143 );
144 ASSERT_EFI_ERROR (Status);
145
146 //
147 // Initialize UART default setting in gSerialDevTempate
148 //
149 gSerialDevTemplate.SerialMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
150 gSerialDevTemplate.SerialMode.DataBits = PcdGet8 (PcdUartDefaultDataBits);
151 gSerialDevTemplate.SerialMode.Parity = PcdGet8 (PcdUartDefaultParity);
152 gSerialDevTemplate.SerialMode.StopBits = PcdGet8 (PcdUartDefaultStopBits);
153 gSerialDevTemplate.UartDevicePath.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
154 gSerialDevTemplate.UartDevicePath.DataBits = PcdGet8 (PcdUartDefaultDataBits);
155 gSerialDevTemplate.UartDevicePath.Parity = PcdGet8 (PcdUartDefaultParity);
156 gSerialDevTemplate.UartDevicePath.StopBits = PcdGet8 (PcdUartDefaultStopBits);
157 gSerialDevTemplate.ClockRate = PcdGet32 (PcdSerialClockRate);
158
159 return Status;
160 }
161
162 /**
163 Return whether the controller is a SIO serial controller.
164
165 @param Controller The controller handle.
166
167 @retval EFI_SUCCESS The controller is a SIO serial controller.
168 @retval others The controller is not a SIO serial controller.
169 **/
170 EFI_STATUS
171 IsSioSerialController (
172 EFI_HANDLE Controller
173 )
174 {
175 EFI_STATUS Status;
176 EFI_SIO_PROTOCOL *Sio;
177 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
178 ACPI_HID_DEVICE_PATH *Acpi;
179
180 //
181 // Open the IO Abstraction(s) needed to perform the supported test
182 //
183 Status = gBS->OpenProtocol (
184 Controller,
185 &gEfiSioProtocolGuid,
186 (VOID **) &Sio,
187 gSerialControllerDriver.DriverBindingHandle,
188 Controller,
189 EFI_OPEN_PROTOCOL_BY_DRIVER
190 );
191 if (Status == EFI_ALREADY_STARTED) {
192 return EFI_SUCCESS;
193 }
194
195 if (!EFI_ERROR (Status)) {
196 //
197 // Close the I/O Abstraction(s) used to perform the supported test
198 //
199 gBS->CloseProtocol (
200 Controller,
201 &gEfiSioProtocolGuid,
202 gSerialControllerDriver.DriverBindingHandle,
203 Controller
204 );
205
206 Status = gBS->OpenProtocol (
207 Controller,
208 &gEfiDevicePathProtocolGuid,
209 (VOID **) &DevicePath,
210 gSerialControllerDriver.DriverBindingHandle,
211 Controller,
212 EFI_OPEN_PROTOCOL_BY_DRIVER
213 );
214 ASSERT (Status != EFI_ALREADY_STARTED);
215
216 if (!EFI_ERROR (Status)) {
217 do {
218 Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath;
219 DevicePath = NextDevicePathNode (DevicePath);
220 } while (!IsDevicePathEnd (DevicePath));
221
222 if (DevicePathType (Acpi) != ACPI_DEVICE_PATH ||
223 (DevicePathSubType (Acpi) != ACPI_DP && DevicePathSubType (Acpi) != ACPI_EXTENDED_DP) ||
224 Acpi->HID != EISA_PNP_ID (0x501)
225 ) {
226 Status = EFI_UNSUPPORTED;
227 }
228 }
229
230 //
231 // Close protocol, don't use device path protocol in the Support() function
232 //
233 gBS->CloseProtocol (
234 Controller,
235 &gEfiDevicePathProtocolGuid,
236 gSerialControllerDriver.DriverBindingHandle,
237 Controller
238 );
239 }
240 return Status;
241 }
242
243 /**
244 Return whether the controller is a PCI serial controller.
245
246 @param Controller The controller handle.
247
248 @retval EFI_SUCCESS The controller is a PCI serial controller.
249 @retval others The controller is not a PCI serial controller.
250 **/
251 EFI_STATUS
252 IsPciSerialController (
253 EFI_HANDLE Controller
254 )
255 {
256 EFI_STATUS Status;
257 EFI_PCI_IO_PROTOCOL *PciIo;
258 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
259 PCI_TYPE00 Pci;
260 PCI_SERIAL_PARAMETER *PciSerialParameter;
261
262 //
263 // Open the IO Abstraction(s) needed to perform the supported test
264 //
265 Status = gBS->OpenProtocol (
266 Controller,
267 &gEfiPciIoProtocolGuid,
268 (VOID **) &PciIo,
269 gSerialControllerDriver.DriverBindingHandle,
270 Controller,
271 EFI_OPEN_PROTOCOL_BY_DRIVER
272 );
273 if (Status == EFI_ALREADY_STARTED) {
274 return EFI_SUCCESS;
275 }
276
277 if (!EFI_ERROR (Status)) {
278 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);
279 if (!EFI_ERROR (Status)) {
280 if (!IS_PCI_16550_SERIAL (&Pci)) {
281 for (PciSerialParameter = (PCI_SERIAL_PARAMETER *) PcdGetPtr (PcdPciSerialParameters)
282 ; PciSerialParameter->VendorId != 0xFFFF
283 ; PciSerialParameter++
284 ) {
285 if ((Pci.Hdr.VendorId == PciSerialParameter->VendorId) &&
286 (Pci.Hdr.DeviceId == PciSerialParameter->DeviceId)
287 ) {
288 break;
289 }
290 }
291 if (PciSerialParameter->VendorId == 0xFFFF) {
292 Status = EFI_UNSUPPORTED;
293 } else {
294 Status = EFI_SUCCESS;
295 }
296 }
297 }
298
299 //
300 // Close the I/O Abstraction(s) used to perform the supported test
301 //
302 gBS->CloseProtocol (
303 Controller,
304 &gEfiPciIoProtocolGuid,
305 gSerialControllerDriver.DriverBindingHandle,
306 Controller
307 );
308 }
309 if (EFI_ERROR (Status)) {
310 return Status;
311 }
312
313 //
314 // Open the EFI Device Path protocol needed to perform the supported test
315 //
316 Status = gBS->OpenProtocol (
317 Controller,
318 &gEfiDevicePathProtocolGuid,
319 (VOID **) &DevicePath,
320 gSerialControllerDriver.DriverBindingHandle,
321 Controller,
322 EFI_OPEN_PROTOCOL_BY_DRIVER
323 );
324 ASSERT (Status != EFI_ALREADY_STARTED);
325
326 //
327 // Close protocol, don't use device path protocol in the Support() function
328 //
329 gBS->CloseProtocol (
330 Controller,
331 &gEfiDevicePathProtocolGuid,
332 gSerialControllerDriver.DriverBindingHandle,
333 Controller
334 );
335
336 return Status;
337 }
338
339 /**
340 Check to see if this driver supports the given controller
341
342 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
343 @param Controller The handle of the controller to test.
344 @param RemainingDevicePath A pointer to the remaining portion of a device path.
345
346 @return EFI_SUCCESS This driver can support the given controller
347
348 **/
349 EFI_STATUS
350 EFIAPI
351 SerialControllerDriverSupported (
352 IN EFI_DRIVER_BINDING_PROTOCOL *This,
353 IN EFI_HANDLE Controller,
354 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
355 )
356
357 {
358 EFI_STATUS Status;
359 UART_DEVICE_PATH *Uart;
360 UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
361
362 //
363 // Test RemainingDevicePath
364 //
365 if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {
366 Status = EFI_UNSUPPORTED;
367
368 Uart = SkipControllerDevicePathNode (RemainingDevicePath, NULL, NULL);
369 if (DevicePathType (Uart) != MESSAGING_DEVICE_PATH ||
370 DevicePathSubType (Uart) != MSG_UART_DP ||
371 DevicePathNodeLength (Uart) != sizeof (UART_DEVICE_PATH)
372 ) {
373 return EFI_UNSUPPORTED;
374 }
375
376 //
377 // Do a rough check because Clock Rate is unknown until DriverBindingStart()
378 //
379 if (!VerifyUartParameters (0, Uart->BaudRate, Uart->DataBits, Uart->Parity, Uart->StopBits, NULL, NULL)) {
380 return EFI_UNSUPPORTED;
381 }
382
383 FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
384 if (IsUartFlowControlDevicePathNode (FlowControl)) {
385 //
386 // If the second node is Flow Control Node,
387 // return error when it request other than hardware flow control.
388 //
389 if ((ReadUnaligned32 (&FlowControl->FlowControlMap) & ~UART_FLOW_CONTROL_HARDWARE) != 0) {
390 return EFI_UNSUPPORTED;
391 }
392 }
393 }
394
395 Status = IsSioSerialController (Controller);
396 if (EFI_ERROR (Status)) {
397 Status = IsPciSerialController (Controller);
398 }
399 return Status;
400 }
401
402 /**
403 Create the child serial device instance.
404
405 @param Controller The parent controller handle.
406 @param Uart Pointer to the UART device path node in RemainingDevicePath,
407 or NULL if RemainingDevicePath is NULL.
408 @param ParentDevicePath Pointer to the parent device path.
409 @param CreateControllerNode TRUE to create the controller node.
410 @param Instance Instance number of the serial device.
411 The value will be set to the controller node
412 if CreateControllerNode is TRUE.
413 @param ParentIo A union type pointer to either Sio or PciIo.
414 @param PciSerialParameter The PCI serial parameter to be used by current serial device.
415 NULL for SIO serial device.
416 @param PciDeviceInfo The PCI device info for the current serial device.
417 NULL for SIO serial device.
418
419 @retval EFI_SUCCESS The serial device was created successfully.
420 @retval others The serial device wasn't created.
421 **/
422 EFI_STATUS
423 CreateSerialDevice (
424 IN EFI_HANDLE Controller,
425 IN UART_DEVICE_PATH *Uart,
426 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
427 IN BOOLEAN CreateControllerNode,
428 IN UINT32 Instance,
429 IN PARENT_IO_PROTOCOL_PTR ParentIo,
430 IN PCI_SERIAL_PARAMETER *PciSerialParameter, OPTIONAL
431 IN PCI_DEVICE_INFO *PciDeviceInfo OPTIONAL
432 )
433 {
434 EFI_STATUS Status;
435 SERIAL_DEV *SerialDevice;
436 UINT8 BarIndex;
437 UINT64 Offset;
438 UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
439 UINT32 FlowControlMap;
440 ACPI_RESOURCE_HEADER_PTR Resources;
441 EFI_ACPI_IO_PORT_DESCRIPTOR *Io;
442 EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIo;
443 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AddressSpace;
444 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
445
446 BarIndex = 0;
447 Offset = 0;
448 FlowControl = NULL;
449 FlowControlMap = 0;
450
451 //
452 // Initialize the serial device instance
453 //
454 SerialDevice = AllocateCopyPool (sizeof (SERIAL_DEV), &gSerialDevTemplate);
455 ASSERT (SerialDevice != NULL);
456
457 SerialDevice->SerialIo.Mode = &(SerialDevice->SerialMode);
458 SerialDevice->ParentDevicePath = ParentDevicePath;
459 SerialDevice->PciDeviceInfo = PciDeviceInfo;
460 SerialDevice->Instance = Instance;
461
462 if (Uart != NULL) {
463 CopyMem (&SerialDevice->UartDevicePath, Uart, sizeof (UART_DEVICE_PATH));
464 FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
465 if (IsUartFlowControlDevicePathNode (FlowControl)) {
466 FlowControlMap = ReadUnaligned32 (&FlowControl->FlowControlMap);
467 } else {
468 FlowControl = NULL;
469 }
470 }
471
472 //
473 // For PCI serial device, use the information from PCD
474 //
475 if (PciSerialParameter != NULL) {
476 BarIndex = (PciSerialParameter->BarIndex == PCI_BAR_ALL) ? 0 : PciSerialParameter->BarIndex;
477 Offset = PciSerialParameter->Offset;
478 if (PciSerialParameter->RegisterStride != 0) {
479 SerialDevice->RegisterStride = PciSerialParameter->RegisterStride;
480 }
481 if (PciSerialParameter->ClockRate != 0) {
482 SerialDevice->ClockRate = PciSerialParameter->ClockRate;
483 }
484 if (PciSerialParameter->ReceiveFifoDepth != 0) {
485 SerialDevice->ReceiveFifoDepth = PciSerialParameter->ReceiveFifoDepth;
486 }
487 if (PciSerialParameter->TransmitFifoDepth != 0) {
488 SerialDevice->TransmitFifoDepth = PciSerialParameter->TransmitFifoDepth;
489 }
490 }
491
492 //
493 // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade.
494 // DriverBindingStart() shouldn't create a handle with different UART device path.
495 //
496 if (!VerifyUartParameters (SerialDevice->ClockRate, SerialDevice->UartDevicePath.BaudRate, SerialDevice->UartDevicePath.DataBits,
497 SerialDevice->UartDevicePath.Parity, SerialDevice->UartDevicePath.StopBits, NULL, NULL
498 )) {
499 Status = EFI_INVALID_PARAMETER;
500 goto CreateError;
501 }
502
503 if (PciSerialParameter == NULL) {
504 Status = ParentIo.Sio->GetResources (ParentIo.Sio, &Resources);
505 } else {
506 Status = ParentIo.PciIo->GetBarAttributes (ParentIo.PciIo, BarIndex, NULL, (VOID **) &Resources);
507 }
508
509 if (!EFI_ERROR (Status)) {
510 //
511 // Get the base address information from ACPI resource descriptor.
512 // ACPI_IO_PORT_DESCRIPTOR and ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR are returned from Sio;
513 // ACPI_ADDRESS_SPACE_DESCRIPTOR is returned from PciIo.
514 //
515 while ((Resources.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) && (SerialDevice->BaseAddress == 0)) {
516 switch (Resources.SmallHeader->Byte) {
517 case ACPI_IO_PORT_DESCRIPTOR:
518 Io = (EFI_ACPI_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;
519 if (Io->Length != 0) {
520 SerialDevice->BaseAddress = Io->BaseAddressMin;
521 }
522 break;
523
524 case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR:
525 FixedIo = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;
526 if (FixedIo->Length != 0) {
527 SerialDevice->BaseAddress = FixedIo->BaseAddress;
528 }
529 break;
530
531 case ACPI_ADDRESS_SPACE_DESCRIPTOR:
532 AddressSpace = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Resources.SmallHeader;
533 if (AddressSpace->AddrLen != 0) {
534 if (AddressSpace->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
535 SerialDevice->MmioAccess = TRUE;
536 }
537 SerialDevice->BaseAddress = AddressSpace->AddrRangeMin + Offset;
538 }
539 break;
540 }
541
542 if (Resources.SmallHeader->Bits.Type == 0) {
543 Resources.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) Resources.SmallHeader
544 + Resources.SmallHeader->Bits.Length
545 + sizeof (*Resources.SmallHeader));
546 } else {
547 Resources.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) Resources.LargeHeader
548 + Resources.LargeHeader->Length
549 + sizeof (*Resources.LargeHeader));
550 }
551 }
552 }
553
554 if (SerialDevice->BaseAddress == 0) {
555 Status = EFI_INVALID_PARAMETER;
556 goto CreateError;
557 }
558
559 SerialDevice->HardwareFlowControl = (BOOLEAN) (FlowControlMap == UART_FLOW_CONTROL_HARDWARE);
560
561 //
562 // Report status code the serial present
563 //
564 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
565 EFI_PROGRESS_CODE,
566 EFI_P_PC_PRESENCE_DETECT | EFI_PERIPHERAL_SERIAL_PORT,
567 SerialDevice->ParentDevicePath
568 );
569
570 if (!SerialPresent (SerialDevice)) {
571 Status = EFI_DEVICE_ERROR;
572 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
573 EFI_ERROR_CODE,
574 EFI_P_EC_NOT_DETECTED | EFI_PERIPHERAL_SERIAL_PORT,
575 SerialDevice->ParentDevicePath
576 );
577 goto CreateError;
578 }
579
580 //
581 // 1. Append Controller device path node.
582 //
583 if (CreateControllerNode) {
584 mControllerDevicePathTemplate.ControllerNumber = SerialDevice->Instance;
585 SerialDevice->DevicePath = AppendDevicePathNode (
586 SerialDevice->ParentDevicePath,
587 (EFI_DEVICE_PATH_PROTOCOL *) &mControllerDevicePathTemplate
588 );
589 SerialDevice->ContainsControllerNode = TRUE;
590 }
591
592 //
593 // 2. Append UART device path node.
594 // The Uart setings are zero here.
595 // SetAttribute() will update them to match the default setings.
596 //
597 TempDevicePath = SerialDevice->DevicePath;
598 if (TempDevicePath != NULL) {
599 SerialDevice->DevicePath = AppendDevicePathNode (
600 TempDevicePath,
601 (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath
602 );
603 FreePool (TempDevicePath);
604 } else {
605 SerialDevice->DevicePath = AppendDevicePathNode (
606 SerialDevice->ParentDevicePath,
607 (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath
608 );
609 }
610 //
611 // 3. Append the Flow Control device path node.
612 // Only produce the Flow Control node when remaining device path has it
613 //
614 if (FlowControl != NULL) {
615 TempDevicePath = SerialDevice->DevicePath;
616 if (TempDevicePath != NULL) {
617 SerialDevice->DevicePath = AppendDevicePathNode (
618 TempDevicePath,
619 (EFI_DEVICE_PATH_PROTOCOL *) FlowControl
620 );
621 FreePool (TempDevicePath);
622 }
623 }
624 ASSERT (SerialDevice->DevicePath != NULL);
625
626 //
627 // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
628 //
629 SerialDevice->SerialMode.BaudRate = SerialDevice->UartDevicePath.BaudRate;
630 SerialDevice->SerialMode.DataBits = SerialDevice->UartDevicePath.DataBits;
631 SerialDevice->SerialMode.Parity = SerialDevice->UartDevicePath.Parity;
632 SerialDevice->SerialMode.StopBits = SerialDevice->UartDevicePath.StopBits;
633
634 //
635 // Issue a reset to initialize the COM port
636 //
637 Status = SerialDevice->SerialIo.Reset (&SerialDevice->SerialIo);
638 if (EFI_ERROR (Status)) {
639 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
640 EFI_ERROR_CODE,
641 EFI_P_EC_CONTROLLER_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
642 SerialDevice->DevicePath
643 );
644 goto CreateError;
645 }
646
647 AddName (SerialDevice, Instance);
648 //
649 // Install protocol interfaces for the serial device.
650 //
651 Status = gBS->InstallMultipleProtocolInterfaces (
652 &SerialDevice->Handle,
653 &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,
654 &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,
655 NULL
656 );
657 if (EFI_ERROR (Status)) {
658 goto CreateError;
659 }
660 //
661 // Open For Child Device
662 //
663 Status = gBS->OpenProtocol (
664 Controller,
665 PciSerialParameter != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
666 (VOID **) &ParentIo,
667 gSerialControllerDriver.DriverBindingHandle,
668 SerialDevice->Handle,
669 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
670 );
671
672 if (EFI_ERROR (Status)) {
673 gBS->UninstallMultipleProtocolInterfaces (
674 &SerialDevice->Handle,
675 &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,
676 &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,
677 NULL
678 );
679 }
680
681 CreateError:
682 if (EFI_ERROR (Status)) {
683 if (SerialDevice->DevicePath != NULL) {
684 FreePool (SerialDevice->DevicePath);
685 }
686 if (SerialDevice->ControllerNameTable != NULL) {
687 FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
688 }
689 FreePool (SerialDevice);
690 }
691 return Status;
692 }
693
694 /**
695 Returns an array of pointers containing all the child serial device pointers.
696
697 @param Controller The parent controller handle.
698 @param IoProtocolGuid The protocol GUID, either equals to gEfiSioProtocolGuid
699 or equals to gEfiPciIoProtocolGuid.
700 @param Count Count of the serial devices.
701
702 @return An array of pointers containing all the child serial device pointers.
703 **/
704 SERIAL_DEV **
705 GetChildSerialDevices (
706 IN EFI_HANDLE Controller,
707 IN EFI_GUID *IoProtocolGuid,
708 OUT UINTN *Count
709 )
710 {
711 EFI_STATUS Status;
712 UINTN Index;
713 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
714 UINTN EntryCount;
715 SERIAL_DEV **SerialDevices;
716 EFI_SERIAL_IO_PROTOCOL *SerialIo;
717 BOOLEAN OpenByDriver;
718
719 *Count = 0;
720 //
721 // If the SerialIo instance specified by RemainingDevicePath is already created,
722 // update the attributes/control.
723 //
724 Status = gBS->OpenProtocolInformation (
725 Controller,
726 IoProtocolGuid,
727 &OpenInfoBuffer,
728 &EntryCount
729 );
730 if (EFI_ERROR (Status)) {
731 return NULL;
732 }
733
734 SerialDevices = AllocatePool (EntryCount * sizeof (SERIAL_DEV *));
735 ASSERT (SerialDevices != NULL);
736
737 *Count = 0;
738 OpenByDriver = FALSE;
739 for (Index = 0; Index < EntryCount; Index++) {
740 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
741 Status = gBS->OpenProtocol (
742 OpenInfoBuffer[Index].ControllerHandle,
743 &gEfiSerialIoProtocolGuid,
744 (VOID **) &SerialIo,
745 gSerialControllerDriver.DriverBindingHandle,
746 Controller,
747 EFI_OPEN_PROTOCOL_GET_PROTOCOL
748 );
749 if (!EFI_ERROR (Status)) {
750 SerialDevices[(*Count)++] = SERIAL_DEV_FROM_THIS (SerialIo);
751 }
752 }
753
754
755 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
756 ASSERT (OpenInfoBuffer[Index].AgentHandle == gSerialControllerDriver.DriverBindingHandle);
757 OpenByDriver = TRUE;
758 }
759 }
760 if (OpenInfoBuffer != NULL) {
761 FreePool (OpenInfoBuffer);
762 }
763
764 ASSERT ((*Count == 0) || (OpenByDriver));
765
766 return SerialDevices;
767 }
768
769 /**
770 Start to management the controller passed in
771
772 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
773 @param Controller The handle of the controller to test.
774 @param RemainingDevicePath A pointer to the remaining portion of a device path.
775
776 @return EFI_SUCCESS Driver is started successfully
777 **/
778 EFI_STATUS
779 EFIAPI
780 SerialControllerDriverStart (
781 IN EFI_DRIVER_BINDING_PROTOCOL *This,
782 IN EFI_HANDLE Controller,
783 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
784 )
785 {
786 EFI_STATUS Status;
787 UINTN Index;
788 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
789 EFI_DEVICE_PATH_PROTOCOL *Node;
790 EFI_SERIAL_IO_PROTOCOL *SerialIo;
791 UINT32 ControllerNumber;
792 UART_DEVICE_PATH *Uart;
793 UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
794 UINT32 Control;
795 PARENT_IO_PROTOCOL_PTR ParentIo;
796 ACPI_HID_DEVICE_PATH *Acpi;
797 EFI_GUID *IoProtocolGuid;
798 PCI_SERIAL_PARAMETER *PciSerialParameter;
799 PCI_SERIAL_PARAMETER DefaultPciSerialParameter;
800 PCI_TYPE00 Pci;
801 UINT32 PciSerialCount;
802 SERIAL_DEV **SerialDevices;
803 UINTN SerialDeviceCount;
804 PCI_DEVICE_INFO *PciDeviceInfo;
805 UINT64 Supports;
806 BOOLEAN ContainsControllerNode;
807
808 //
809 // Get the Parent Device Path
810 //
811 Status = gBS->OpenProtocol (
812 Controller,
813 &gEfiDevicePathProtocolGuid,
814 (VOID **) &ParentDevicePath,
815 This->DriverBindingHandle,
816 Controller,
817 EFI_OPEN_PROTOCOL_BY_DRIVER
818 );
819 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
820 return Status;
821 }
822 //
823 // Report status code enable the serial
824 //
825 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
826 EFI_PROGRESS_CODE,
827 EFI_P_PC_ENABLE | EFI_PERIPHERAL_SERIAL_PORT,
828 ParentDevicePath
829 );
830
831 //
832 // Grab the IO abstraction we need to get any work done
833 //
834 IoProtocolGuid = &gEfiSioProtocolGuid;
835 Status = gBS->OpenProtocol (
836 Controller,
837 IoProtocolGuid,
838 (VOID **) &ParentIo,
839 This->DriverBindingHandle,
840 Controller,
841 EFI_OPEN_PROTOCOL_BY_DRIVER
842 );
843 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
844 IoProtocolGuid = &gEfiPciIoProtocolGuid;
845 Status = gBS->OpenProtocol (
846 Controller,
847 IoProtocolGuid,
848 (VOID **) &ParentIo,
849 This->DriverBindingHandle,
850 Controller,
851 EFI_OPEN_PROTOCOL_BY_DRIVER
852 );
853 }
854 ASSERT (!EFI_ERROR (Status) || Status == EFI_ALREADY_STARTED);
855
856 //
857 // Do nothing for END device path node
858 //
859 if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
860 return EFI_SUCCESS;
861 }
862
863 ControllerNumber = 0;
864 ContainsControllerNode = FALSE;
865 SerialDevices = GetChildSerialDevices (Controller, IoProtocolGuid, &SerialDeviceCount);
866 //
867 // If the SerialIo instance specified by RemainingDevicePath is already created,
868 // update the attributes/control.
869 //
870 if ((SerialDeviceCount != 0) && (RemainingDevicePath != NULL)) {
871 Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);
872 for (Index = 0; Index < SerialDeviceCount; Index++) {
873 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 &= 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 **/
1108 EFI_STATUS
1109 EFIAPI
1110 SerialControllerDriverStop (
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 }