+/** @file\r
+ Serial driver for PCI or SIO UARTS.\r
+\r
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Serial.h"\r
+\r
+//\r
+// ISA Serial Driver Global Variables\r
+//\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = {\r
+ SerialControllerDriverSupported,\r
+ SerialControllerDriverStart,\r
+ SerialControllerDriverStop,\r
+ 0xa,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+CONTROLLER_DEVICE_PATH mControllerDevicePathTemplate = {\r
+ {\r
+ HARDWARE_DEVICE_PATH,\r
+ HW_CONTROLLER_DP,\r
+ sizeof (CONTROLLER_DEVICE_PATH),\r
+ 0\r
+ },\r
+ 0\r
+};\r
+\r
+SERIAL_DEV gSerialDevTemplate = {\r
+ SERIAL_DEV_SIGNATURE,\r
+ NULL,\r
+ {\r
+ SERIAL_IO_INTERFACE_REVISION,\r
+ SerialReset,\r
+ SerialSetAttributes,\r
+ SerialSetControl,\r
+ SerialGetControl,\r
+ SerialWrite,\r
+ SerialRead,\r
+ NULL\r
+ }, // SerialIo\r
+ {\r
+ SERIAL_PORT_SUPPORT_CONTROL_MASK,\r
+ SERIAL_PORT_DEFAULT_TIMEOUT,\r
+ 0,\r
+ 16,\r
+ 0,\r
+ 0,\r
+ 0\r
+ }, // SerialMode\r
+ NULL, // DevicePath\r
+ NULL, // ParentDevicePath\r
+ {\r
+ {\r
+ MESSAGING_DEVICE_PATH,\r
+ MSG_UART_DP,\r
+ {\r
+ (UINT8) (sizeof (UART_DEVICE_PATH)),\r
+ (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)\r
+ }\r
+ },\r
+ 0, 0, 0, 0, 0\r
+ }, // UartDevicePath\r
+ 0, // BaseAddress\r
+ FALSE, // MmioAccess\r
+ 1, // RegisterStride\r
+ 0, // ClockRate\r
+ 16, // ReceiveFifoDepth\r
+ { 0, 0 }, // Receive;\r
+ 16, // TransmitFifoDepth\r
+ { 0, 0 }, // Transmit;\r
+ FALSE, // SoftwareLoopbackEnable;\r
+ FALSE, // HardwareFlowControl;\r
+ NULL, // *ControllerNameTable;\r
+ FALSE, // ContainsControllerNode;\r
+ 0, // Instance;\r
+ NULL // *PciDeviceInfo;\r
+};\r
+\r
+/**\r
+ Check the device path node whether it's the Flow Control node or not.\r
+\r
+ @param[in] FlowControl The device path node to be checked.\r
+ \r
+ @retval TRUE It's the Flow Control node.\r
+ @retval FALSE It's not.\r
+\r
+**/\r
+BOOLEAN\r
+IsUartFlowControlDevicePathNode (\r
+ IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl\r
+ )\r
+{\r
+ return (BOOLEAN) (\r
+ (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) &&\r
+ (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) &&\r
+ (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid))\r
+ );\r
+}\r
+\r
+/**\r
+ The user Entry Point for module PciSioSerial. The user code starts with this function.\r
+\r
+ @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
+ @param[in] SystemTable A pointer to the EFI System Table.\r
+ \r
+ @retval EFI_SUCCESS The entry point is executed successfully.\r
+ @retval other Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializePciSioSerial (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Install driver model protocol(s).\r
+ //\r
+ Status = EfiLibInstallDriverBindingComponentName2 (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gSerialControllerDriver,\r
+ ImageHandle,\r
+ &gPciSioSerialComponentName,\r
+ &gPciSioSerialComponentName2\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Initialize UART default setting in gSerialDevTempate\r
+ //\r
+ gSerialDevTemplate.SerialMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);\r
+ gSerialDevTemplate.SerialMode.DataBits = PcdGet8 (PcdUartDefaultDataBits);\r
+ gSerialDevTemplate.SerialMode.Parity = PcdGet8 (PcdUartDefaultParity);\r
+ gSerialDevTemplate.SerialMode.StopBits = PcdGet8 (PcdUartDefaultStopBits);\r
+ gSerialDevTemplate.UartDevicePath.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);\r
+ gSerialDevTemplate.UartDevicePath.DataBits = PcdGet8 (PcdUartDefaultDataBits);\r
+ gSerialDevTemplate.UartDevicePath.Parity = PcdGet8 (PcdUartDefaultParity);\r
+ gSerialDevTemplate.UartDevicePath.StopBits = PcdGet8 (PcdUartDefaultStopBits);\r
+ gSerialDevTemplate.ClockRate = PcdGet32 (PcdSerialClockRate);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Return whether the controller is a SIO serial controller.\r
+\r
+ @param Controller The controller handle.\r
+\r
+ @retval EFI_SUCCESS The controller is a SIO serial controller.\r
+ @retval others The controller is not a SIO serial controller.\r
+**/\r
+EFI_STATUS\r
+IsSioSerialController (\r
+ EFI_HANDLE Controller\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SIO_PROTOCOL *Sio;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ ACPI_HID_DEVICE_PATH *Acpi;\r
+\r
+ //\r
+ // Open the IO Abstraction(s) needed to perform the supported test\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSioProtocolGuid,\r
+ (VOID **) &Sio,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Close the I/O Abstraction(s) used to perform the supported test\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSioProtocolGuid,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &DevicePath,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ ASSERT (Status != EFI_ALREADY_STARTED);\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ do {\r
+ Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath;\r
+ DevicePath = NextDevicePathNode (DevicePath);\r
+ } while (!IsDevicePathEnd (DevicePath));\r
+\r
+ if (DevicePathType (Acpi) != ACPI_DEVICE_PATH ||\r
+ (DevicePathSubType (Acpi) != ACPI_DP && DevicePathSubType (Acpi) != ACPI_EXTENDED_DP) ||\r
+ Acpi->HID != EISA_PNP_ID (0x501)\r
+ ) {\r
+ Status = EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Close protocol, don't use device path protocol in the Support() function\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller\r
+ );\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Return whether the controller is a PCI serial controller.\r
+\r
+ @param Controller The controller handle.\r
+\r
+ @retval EFI_SUCCESS The controller is a PCI serial controller.\r
+ @retval others The controller is not a PCI serial controller.\r
+**/\r
+EFI_STATUS\r
+IsPciSerialController (\r
+ EFI_HANDLE Controller\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ PCI_TYPE00 Pci;\r
+ PCI_SERIAL_PARAMETER *PciSerialParameter;\r
+\r
+ //\r
+ // Open the IO Abstraction(s) needed to perform the supported test\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);\r
+ if (!EFI_ERROR (Status)) {\r
+ if (!IS_PCI_16550_SERIAL (&Pci)) {\r
+ for (PciSerialParameter = (PCI_SERIAL_PARAMETER *) PcdGetPtr (PcdPciSerialParameters)\r
+ ; PciSerialParameter->VendorId != 0xFFFF\r
+ ; PciSerialParameter++\r
+ ) {\r
+ if ((Pci.Hdr.VendorId == PciSerialParameter->VendorId) &&\r
+ (Pci.Hdr.DeviceId == PciSerialParameter->DeviceId)\r
+ ) {\r
+ break;\r
+ }\r
+ }\r
+ if (PciSerialParameter->VendorId == 0xFFFF) {\r
+ Status = EFI_UNSUPPORTED;\r
+ } else {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Close the I/O Abstraction(s) used to perform the supported test\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller\r
+ );\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Open the EFI Device Path protocol needed to perform the supported test\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &DevicePath,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ ASSERT (Status != EFI_ALREADY_STARTED);\r
+\r
+ //\r
+ // Close protocol, don't use device path protocol in the Support() function\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Check to see if this driver supports the given controller\r
+\r
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param Controller The handle of the controller to test.\r
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.\r
+\r
+ @return EFI_SUCCESS This driver can support the given controller\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialControllerDriverSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+\r
+{\r
+ EFI_STATUS Status;\r
+ UART_DEVICE_PATH *Uart;\r
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;\r
+\r
+ //\r
+ // Test RemainingDevicePath\r
+ //\r
+ if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {\r
+ Status = EFI_UNSUPPORTED;\r
+\r
+ Uart = SkipControllerDevicePathNode (RemainingDevicePath, NULL, NULL);\r
+ if (DevicePathType (Uart) != MESSAGING_DEVICE_PATH ||\r
+ DevicePathSubType (Uart) != MSG_UART_DP ||\r
+ DevicePathNodeLength (Uart) != sizeof (UART_DEVICE_PATH)\r
+ ) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Do a rough check because Clock Rate is unknown until DriverBindingStart()\r
+ //\r
+ if (!VerifyUartParameters (0, Uart->BaudRate, Uart->DataBits, Uart->Parity, Uart->StopBits, NULL, NULL)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);\r
+ if (IsUartFlowControlDevicePathNode (FlowControl)) {\r
+ //\r
+ // If the second node is Flow Control Node,\r
+ // return error when it request other than hardware flow control.\r
+ //\r
+ if ((ReadUnaligned32 (&FlowControl->FlowControlMap) & ~UART_FLOW_CONTROL_HARDWARE) != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+ }\r
+\r
+ Status = IsSioSerialController (Controller);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = IsPciSerialController (Controller);\r
+ }\r
+ return Status; \r
+}\r
+\r
+/**\r
+ Create the child serial device instance.\r
+\r
+ @param Controller The parent controller handle.\r
+ @param Uart Pointer to the UART device path node in RemainingDevicePath,\r
+ or NULL if RemainingDevicePath is NULL.\r
+ @param ParentDevicePath Pointer to the parent device path.\r
+ @param CreateControllerNode TRUE to create the controller node.\r
+ @param Instance Instance number of the serial device.\r
+ The value will be set to the controller node\r
+ if CreateControllerNode is TRUE.\r
+ @param ParentIo A union type pointer to either Sio or PciIo.\r
+ @param PciSerialParameter The PCI serial parameter to be used by current serial device.\r
+ NULL for SIO serial device.\r
+ @param PciDeviceInfo The PCI device info for the current serial device.\r
+ NULL for SIO serial device.\r
+\r
+ @retval EFI_SUCCESS The serial device was created successfully.\r
+ @retval others The serial device wasn't created.\r
+**/\r
+EFI_STATUS\r
+CreateSerialDevice (\r
+ IN EFI_HANDLE Controller,\r
+ IN UART_DEVICE_PATH *Uart,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
+ IN BOOLEAN CreateControllerNode,\r
+ IN UINT32 Instance,\r
+ IN PARENT_IO_PROTOCOL_PTR ParentIo,\r
+ IN PCI_SERIAL_PARAMETER *PciSerialParameter, OPTIONAL\r
+ IN PCI_DEVICE_INFO *PciDeviceInfo OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SERIAL_DEV *SerialDevice;\r
+ UINT8 BarIndex;\r
+ UINT64 Offset;\r
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;\r
+ UINT32 FlowControlMap;\r
+ ACPI_RESOURCE_HEADER_PTR Resources;\r
+ EFI_ACPI_IO_PORT_DESCRIPTOR *Io;\r
+ EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIo;\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AddressSpace;\r
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
+\r
+ BarIndex = 0;\r
+ Offset = 0;\r
+ FlowControl = NULL;\r
+ FlowControlMap = 0;\r
+\r
+ //\r
+ // Initialize the serial device instance\r
+ //\r
+ SerialDevice = AllocateCopyPool (sizeof (SERIAL_DEV), &gSerialDevTemplate);\r
+ ASSERT (SerialDevice != NULL);\r
+\r
+ SerialDevice->SerialIo.Mode = &(SerialDevice->SerialMode);\r
+ SerialDevice->ParentDevicePath = ParentDevicePath;\r
+ SerialDevice->PciDeviceInfo = PciDeviceInfo;\r
+ SerialDevice->Instance = Instance;\r
+\r
+ if (Uart != NULL) {\r
+ CopyMem (&SerialDevice->UartDevicePath, Uart, sizeof (UART_DEVICE_PATH));\r
+ FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);\r
+ if (IsUartFlowControlDevicePathNode (FlowControl)) {\r
+ FlowControlMap = ReadUnaligned32 (&FlowControl->FlowControlMap);\r
+ } else {\r
+ FlowControl = NULL;\r
+ }\r
+ }\r
+\r
+ //\r
+ // For PCI serial device, use the information from PCD\r
+ //\r
+ if (PciSerialParameter != NULL) {\r
+ BarIndex = (PciSerialParameter->BarIndex == PCI_BAR_ALL) ? 0 : PciSerialParameter->BarIndex;\r
+ Offset = PciSerialParameter->Offset;\r
+ if (PciSerialParameter->RegisterStride != 0) {\r
+ SerialDevice->RegisterStride = PciSerialParameter->RegisterStride;\r
+ }\r
+ if (PciSerialParameter->ClockRate != 0) {\r
+ SerialDevice->ClockRate = PciSerialParameter->ClockRate;\r
+ }\r
+ if (PciSerialParameter->ReceiveFifoDepth != 0) {\r
+ SerialDevice->ReceiveFifoDepth = PciSerialParameter->ReceiveFifoDepth;\r
+ }\r
+ if (PciSerialParameter->TransmitFifoDepth != 0) {\r
+ SerialDevice->TransmitFifoDepth = PciSerialParameter->TransmitFifoDepth;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade.\r
+ // DriverBindingStart() shouldn't create a handle with different UART device path.\r
+ //\r
+ if (!VerifyUartParameters (SerialDevice->ClockRate, SerialDevice->UartDevicePath.BaudRate, SerialDevice->UartDevicePath.DataBits,\r
+ SerialDevice->UartDevicePath.Parity, SerialDevice->UartDevicePath.StopBits, NULL, NULL\r
+ )) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto CreateError;\r
+ }\r
+\r
+ if (PciSerialParameter == NULL) {\r
+ Status = ParentIo.Sio->GetResources (ParentIo.Sio, &Resources);\r
+ } else {\r
+ Status = ParentIo.PciIo->GetBarAttributes (ParentIo.PciIo, BarIndex, NULL, (VOID **) &Resources);\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Get the base address information from ACPI resource descriptor.\r
+ // ACPI_IO_PORT_DESCRIPTOR and ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR are returned from Sio;\r
+ // ACPI_ADDRESS_SPACE_DESCRIPTOR is returned from PciIo.\r
+ //\r
+ while ((Resources.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) && (SerialDevice->BaseAddress == 0)) {\r
+ switch (Resources.SmallHeader->Byte) {\r
+ case ACPI_IO_PORT_DESCRIPTOR:\r
+ Io = (EFI_ACPI_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;\r
+ if (Io->Length != 0) {\r
+ SerialDevice->BaseAddress = Io->BaseAddressMin;\r
+ }\r
+ break;\r
+\r
+ case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR:\r
+ FixedIo = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;\r
+ if (FixedIo->Length != 0) {\r
+ SerialDevice->BaseAddress = FixedIo->BaseAddress;\r
+ }\r
+ break;\r
+\r
+ case ACPI_ADDRESS_SPACE_DESCRIPTOR:\r
+ AddressSpace = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Resources.SmallHeader;\r
+ if (AddressSpace->AddrLen != 0) {\r
+ if (AddressSpace->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {\r
+ SerialDevice->MmioAccess = TRUE;\r
+ }\r
+ SerialDevice->BaseAddress = AddressSpace->AddrRangeMin + Offset;\r
+ }\r
+ break;\r
+ }\r
+\r
+ if (Resources.SmallHeader->Bits.Type == 0) {\r
+ Resources.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) Resources.SmallHeader\r
+ + Resources.SmallHeader->Bits.Length\r
+ + sizeof (*Resources.SmallHeader));\r
+ } else {\r
+ Resources.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) Resources.LargeHeader\r
+ + Resources.LargeHeader->Length\r
+ + sizeof (*Resources.LargeHeader));\r
+ }\r
+ }\r
+ }\r
+\r
+ if (SerialDevice->BaseAddress == 0) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto CreateError;\r
+ }\r
+\r
+ SerialDevice->HardwareFlowControl = (BOOLEAN) (FlowControlMap == UART_FLOW_CONTROL_HARDWARE);\r
+\r
+ //\r
+ // Report status code the serial present\r
+ //\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_PROGRESS_CODE,\r
+ EFI_P_PC_PRESENCE_DETECT | EFI_PERIPHERAL_SERIAL_PORT,\r
+ SerialDevice->ParentDevicePath\r
+ );\r
+\r
+ if (!SerialPresent (SerialDevice)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_ERROR_CODE,\r
+ EFI_P_EC_NOT_DETECTED | EFI_PERIPHERAL_SERIAL_PORT,\r
+ SerialDevice->ParentDevicePath\r
+ );\r
+ goto CreateError;\r
+ }\r
+\r
+ //\r
+ // 1. Append Controller device path node.\r
+ //\r
+ if (CreateControllerNode) {\r
+ mControllerDevicePathTemplate.ControllerNumber = SerialDevice->Instance;\r
+ SerialDevice->DevicePath = AppendDevicePathNode (\r
+ SerialDevice->ParentDevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) &mControllerDevicePathTemplate\r
+ );\r
+ SerialDevice->ContainsControllerNode = TRUE;\r
+ }\r
+\r
+ //\r
+ // 2. Append UART device path node.\r
+ // The Uart setings are zero here.\r
+ // SetAttribute() will update them to match the default setings.\r
+ //\r
+ TempDevicePath = SerialDevice->DevicePath;\r
+ if (TempDevicePath != NULL) {\r
+ SerialDevice->DevicePath = AppendDevicePathNode (\r
+ TempDevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath\r
+ );\r
+ FreePool (TempDevicePath);\r
+ } else {\r
+ SerialDevice->DevicePath = AppendDevicePathNode (\r
+ SerialDevice->ParentDevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath\r
+ );\r
+ }\r
+ //\r
+ // 3. Append the Flow Control device path node.\r
+ // Only produce the Flow Control node when remaining device path has it\r
+ //\r
+ if (FlowControl != NULL) {\r
+ TempDevicePath = SerialDevice->DevicePath;\r
+ if (TempDevicePath != NULL) {\r
+ SerialDevice->DevicePath = AppendDevicePathNode (\r
+ TempDevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) FlowControl\r
+ );\r
+ FreePool (TempDevicePath);\r
+ }\r
+ }\r
+ ASSERT (SerialDevice->DevicePath != NULL);\r
+\r
+ //\r
+ // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.\r
+ //\r
+ SerialDevice->SerialMode.BaudRate = SerialDevice->UartDevicePath.BaudRate;\r
+ SerialDevice->SerialMode.DataBits = SerialDevice->UartDevicePath.DataBits;\r
+ SerialDevice->SerialMode.Parity = SerialDevice->UartDevicePath.Parity;\r
+ SerialDevice->SerialMode.StopBits = SerialDevice->UartDevicePath.StopBits;\r
+\r
+ //\r
+ // Issue a reset to initialize the COM port\r
+ //\r
+ Status = SerialDevice->SerialIo.Reset (&SerialDevice->SerialIo);\r
+ if (EFI_ERROR (Status)) {\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_ERROR_CODE,\r
+ EFI_P_EC_CONTROLLER_ERROR | EFI_PERIPHERAL_SERIAL_PORT,\r
+ SerialDevice->DevicePath\r
+ );\r
+ goto CreateError;\r
+ }\r
+\r
+ AddName (SerialDevice, Instance);\r
+ //\r
+ // Install protocol interfaces for the serial device.\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &SerialDevice->Handle,\r
+ &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,\r
+ &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto CreateError;\r
+ }\r
+ //\r
+ // Open For Child Device\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ PciSerialParameter != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,\r
+ (VOID **) &ParentIo,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ SerialDevice->Handle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ &SerialDevice->Handle,\r
+ &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,\r
+ &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,\r
+ NULL\r
+ );\r
+ }\r
+\r
+CreateError:\r
+ if (EFI_ERROR (Status)) {\r
+ if (SerialDevice->DevicePath != NULL) {\r
+ FreePool (SerialDevice->DevicePath);\r
+ }\r
+ if (SerialDevice->ControllerNameTable != NULL) {\r
+ FreeUnicodeStringTable (SerialDevice->ControllerNameTable);\r
+ }\r
+ FreePool (SerialDevice);\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Returns an array of pointers containing all the child serial device pointers.\r
+\r
+ @param Controller The parent controller handle.\r
+ @param IoProtocolGuid The protocol GUID, either equals to gEfiSioProtocolGuid\r
+ or equals to gEfiPciIoProtocolGuid.\r
+ @param Count Count of the serial devices.\r
+\r
+ @return An array of pointers containing all the child serial device pointers.\r
+**/\r
+SERIAL_DEV **\r
+GetChildSerialDevices (\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_GUID *IoProtocolGuid,\r
+ OUT UINTN *Count\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
+ UINTN EntryCount;\r
+ SERIAL_DEV **SerialDevices;\r
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
+ BOOLEAN OpenByDriver;\r
+\r
+ *Count = 0;\r
+ //\r
+ // If the SerialIo instance specified by RemainingDevicePath is already created,\r
+ // update the attributes/control.\r
+ //\r
+ Status = gBS->OpenProtocolInformation (\r
+ Controller,\r
+ IoProtocolGuid,\r
+ &OpenInfoBuffer,\r
+ &EntryCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ SerialDevices = AllocatePool (EntryCount * sizeof (SERIAL_DEV *));\r
+ ASSERT (SerialDevices != NULL);\r
+\r
+ *Count = 0;\r
+ OpenByDriver = FALSE;\r
+ for (Index = 0; Index < EntryCount; Index++) {\r
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
+ Status = gBS->OpenProtocol (\r
+ OpenInfoBuffer[Index].ControllerHandle,\r
+ &gEfiSerialIoProtocolGuid,\r
+ (VOID **) &SerialIo,\r
+ gSerialControllerDriver.DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ SerialDevices[(*Count)++] = SERIAL_DEV_FROM_THIS (SerialIo);\r
+ }\r
+ }\r
+\r
+\r
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {\r
+ ASSERT (OpenInfoBuffer[Index].AgentHandle == gSerialControllerDriver.DriverBindingHandle);\r
+ OpenByDriver = TRUE;\r
+ }\r
+ }\r
+ if (OpenInfoBuffer != NULL) {\r
+ FreePool (OpenInfoBuffer);\r
+ }\r
+\r
+ ASSERT ((*Count == 0) || (OpenByDriver));\r
+\r
+ return SerialDevices;\r
+}\r
+\r
+/**\r
+ Start to management the controller passed in\r
+\r
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param Controller The handle of the controller to test.\r
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.\r
+\r
+ @return EFI_SUCCESS Driver is started successfully\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialControllerDriverStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *Node;\r
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
+ UINT32 ControllerNumber;\r
+ UART_DEVICE_PATH *Uart;\r
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;\r
+ UINT32 Control;\r
+ PARENT_IO_PROTOCOL_PTR ParentIo;\r
+ ACPI_HID_DEVICE_PATH *Acpi;\r
+ EFI_GUID *IoProtocolGuid;\r
+ PCI_SERIAL_PARAMETER *PciSerialParameter;\r
+ PCI_SERIAL_PARAMETER DefaultPciSerialParameter;\r
+ PCI_TYPE00 Pci;\r
+ UINT32 PciSerialCount;\r
+ SERIAL_DEV **SerialDevices;\r
+ UINTN SerialDeviceCount;\r
+ PCI_DEVICE_INFO *PciDeviceInfo;\r
+ UINT64 Supports;\r
+ BOOLEAN ContainsControllerNode;\r
+\r
+ //\r
+ // Get the Parent Device Path\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &ParentDevicePath,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Report status code enable the serial\r
+ //\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_PROGRESS_CODE,\r
+ EFI_P_PC_ENABLE | EFI_PERIPHERAL_SERIAL_PORT,\r
+ ParentDevicePath\r
+ );\r
+\r
+ //\r
+ // Grab the IO abstraction we need to get any work done\r
+ //\r
+ IoProtocolGuid = &gEfiSioProtocolGuid;\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ IoProtocolGuid,\r
+ (VOID **) &ParentIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
+ IoProtocolGuid = &gEfiPciIoProtocolGuid;\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ IoProtocolGuid,\r
+ (VOID **) &ParentIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ }\r
+ ASSERT (!EFI_ERROR (Status) || Status == EFI_ALREADY_STARTED);\r
+\r
+ //\r
+ // Do nothing for END device path node\r
+ //\r
+ if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+\r
+ SerialDevices = GetChildSerialDevices (Controller, IoProtocolGuid, &SerialDeviceCount);\r
+ //\r
+ // If the SerialIo instance specified by RemainingDevicePath is already created,\r
+ // update the attributes/control.\r
+ //\r
+ if ((SerialDeviceCount != 0) && (RemainingDevicePath != NULL)) {\r
+ Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);\r
+ for (Index = 0; Index < SerialDeviceCount; Index++) {\r
+ if ((!SerialDevices[Index]->ContainsControllerNode && !ContainsControllerNode) ||\r
+ (SerialDevices[Index]->ContainsControllerNode && ContainsControllerNode && SerialDevices[Index]->Instance == ControllerNumber)\r
+ ) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ //\r
+ // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade.\r
+ // DriverBindingStart() shouldn't create a handle with different UART device path.\r
+ //\r
+ if (VerifyUartParameters (SerialDevices[Index]->ClockRate, Uart->BaudRate, Uart->DataBits,\r
+ (EFI_PARITY_TYPE) Uart->Parity, (EFI_STOP_BITS_TYPE) Uart->StopBits, NULL, NULL)) {\r
+ SerialIo = &SerialDevices[Index]->SerialIo;\r
+ Status = SerialIo->SetAttributes (\r
+ SerialIo,\r
+ Uart->BaudRate,\r
+ SerialIo->Mode->ReceiveFifoDepth,\r
+ SerialIo->Mode->Timeout,\r
+ (EFI_PARITY_TYPE) Uart->Parity,\r
+ Uart->DataBits,\r
+ (EFI_STOP_BITS_TYPE) Uart->StopBits\r
+ );\r
+ }\r
+ FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);\r
+ if (!EFI_ERROR (Status) && IsUartFlowControlDevicePathNode (FlowControl)) {\r
+ Status = SerialIo->GetControl (SerialIo, &Control);\r
+ if (!EFI_ERROR (Status)) {\r
+ if (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) {\r
+ Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
+ } else {\r
+ Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
+ }\r
+ //\r
+ // Clear the bits that are not allowed to pass to SetControl\r
+ //\r
+ Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |\r
+ EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |\r
+ EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE);\r
+ Status = SerialIo->SetControl (SerialIo, Control);\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ if (Index != SerialDeviceCount) {\r
+ //\r
+ // Directly return if the SerialIo instance specified by RemainingDevicePath is found and updated.\r
+ // Otherwise continue to create the instance specified by RemainingDevicePath.\r
+ //\r
+ if (SerialDevices != NULL) {\r
+ FreePool (SerialDevices);\r
+ }\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ if (RemainingDevicePath != NULL) {\r
+ Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);\r
+ } else {\r
+ Uart = NULL;\r
+ }\r
+\r
+ PciDeviceInfo = NULL;\r
+ if (IoProtocolGuid == &gEfiSioProtocolGuid) {\r
+ Status = EFI_NOT_FOUND;\r
+ if (RemainingDevicePath == NULL || !ContainsControllerNode) {\r
+ Node = ParentDevicePath;\r
+ do {\r
+ Acpi = (ACPI_HID_DEVICE_PATH *) Node;\r
+ Node = NextDevicePathNode (Node);\r
+ } while (!IsDevicePathEnd (Node));\r
+ Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, Acpi->UID, ParentIo, NULL, NULL);\r
+ DEBUG ((EFI_D_INFO, "PciSioSerial: Create SIO child serial device - %r\n", Status));\r
+ }\r
+ } else {\r
+ Status = ParentIo.PciIo->Pci.Read (ParentIo.PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // PcdPciSerialParameters takes the higher priority.\r
+ //\r
+ PciSerialCount = 0;\r
+ for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {\r
+ if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&\r
+ (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId)\r
+ ) {\r
+ PciSerialCount++;\r
+ }\r
+ }\r
+\r
+ if (SerialDeviceCount == 0) {\r
+ //\r
+ // Enable the IO & MEM decoding when creating the first child.\r
+ // Restore the PCI attributes when all children is destroyed (PciDeviceInfo->ChildCount == 0).\r
+ //\r
+ PciDeviceInfo = AllocatePool (sizeof (PCI_DEVICE_INFO));\r
+ PciDeviceInfo->ChildCount = 0;\r
+ PciDeviceInfo->PciIo = ParentIo.PciIo;\r
+ Status = ParentIo.PciIo->Attributes (\r
+ ParentIo.PciIo,\r
+ EfiPciIoAttributeOperationGet,\r
+ 0,\r
+ &PciDeviceInfo->PciAttributes\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = ParentIo.PciIo->Attributes (\r
+ ParentIo.PciIo,\r
+ EfiPciIoAttributeOperationSupported,\r
+ 0,\r
+ &Supports\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Supports &= EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY;\r
+ Status = ParentIo.PciIo->Attributes (\r
+ ParentIo.PciIo,\r
+ EfiPciIoAttributeOperationEnable,\r
+ Supports,\r
+ NULL\r
+ );\r
+ }\r
+ }\r
+ } else {\r
+ //\r
+ // Re-use the PciDeviceInfo stored in existing children.\r
+ //\r
+ PciDeviceInfo = SerialDevices[0]->PciDeviceInfo;\r
+ ASSERT (PciDeviceInfo != NULL);\r
+ }\r
+\r
+ Status = EFI_NOT_FOUND;\r
+ if (PciSerialCount <= 1) {\r
+ //\r
+ // PCI serial device contains only one UART\r
+ //\r
+ if (RemainingDevicePath == NULL || !ContainsControllerNode) {\r
+ //\r
+ // This PCI serial device is matched by class code in Supported()\r
+ //\r
+ if (PciSerialCount == 0) {\r
+ DefaultPciSerialParameter.VendorId = Pci.Hdr.VendorId;\r
+ DefaultPciSerialParameter.DeviceId = Pci.Hdr.DeviceId;\r
+ DefaultPciSerialParameter.BarIndex = 0;\r
+ DefaultPciSerialParameter.Offset = 0;\r
+ DefaultPciSerialParameter.RegisterStride = 0;\r
+ DefaultPciSerialParameter.ClockRate = 0;\r
+ PciSerialParameter = &DefaultPciSerialParameter;\r
+ } else if (PciSerialCount == 1) {\r
+ PciSerialParameter = PcdGetPtr (PcdPciSerialParameters);\r
+ }\r
+\r
+ Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, 0, ParentIo, PciSerialParameter, PciDeviceInfo);\r
+ DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (single) - %r\n", Status));\r
+ if (!EFI_ERROR (Status)) {\r
+ PciDeviceInfo->ChildCount++;\r
+ }\r
+ }\r
+ } else {\r
+ //\r
+ // PCI serial device contains multiple UARTs\r
+ //\r
+ if (RemainingDevicePath == NULL || ContainsControllerNode) {\r
+ PciSerialCount = 0;\r
+ for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {\r
+ if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&\r
+ (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId) &&\r
+ ((RemainingDevicePath == NULL) || (ControllerNumber == PciSerialCount))\r
+ ) {\r
+ //\r
+ // Create controller node when PCI serial device contains multiple UARTs\r
+ //\r
+ Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, TRUE, PciSerialCount, ParentIo, PciSerialParameter, PciDeviceInfo);\r
+ PciSerialCount++;\r
+ DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (multiple) - %r\n", Status));\r
+ if (!EFI_ERROR (Status)) {\r
+ PciDeviceInfo->ChildCount++;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if (SerialDevices != NULL) {\r
+ FreePool (SerialDevices);\r
+ }\r
+\r
+ //\r
+ // For multiple PCI serial devices, set Status to SUCCESS if one child is created successfully\r
+ //\r
+ if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount != 0)) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ if (EFI_ERROR (Status) && (SerialDeviceCount == 0)) {\r
+ if (PciDeviceInfo != NULL) {\r
+ Status = ParentIo.PciIo->Attributes (\r
+ ParentIo.PciIo,\r
+ EfiPciIoAttributeOperationSet,\r
+ PciDeviceInfo->PciAttributes,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ FreePool (PciDeviceInfo);\r
+ }\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ IoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Disconnect this driver with the controller, uninstall related protocol instance\r
+\r
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param Controller The handle of the controller to test.\r
+ @param NumberOfChildren Number of child device.\r
+ @param ChildHandleBuffer A pointer to the remaining portion of a device path.\r
+\r
+ @retval EFI_SUCCESS Operation successfully\r
+ @retval EFI_DEVICE_ERROR Cannot stop the driver successfully\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SerialControllerDriverStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ BOOLEAN AllChildrenStopped;\r
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
+ SERIAL_DEV *SerialDevice;\r
+ VOID *IoProtocol;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ PCI_DEVICE_INFO *PciDeviceInfo;\r
+\r
+ PciDeviceInfo = NULL;\r
+\r
+ Status = gBS->HandleProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &DevicePath\r
+ );\r
+\r
+ //\r
+ // Report the status code disable the serial\r
+ //\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_PROGRESS_CODE,\r
+ EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT,\r
+ DevicePath\r
+ );\r
+\r
+ if (NumberOfChildren == 0) {\r
+ //\r
+ // Close the bus driver\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ &IoProtocol,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ !EFI_ERROR (Status) ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ AllChildrenStopped = TRUE;\r
+\r
+ for (Index = 0; Index < NumberOfChildren; Index++) {\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiSerialIoProtocolGuid,\r
+ (VOID **) &SerialIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);\r
+ ASSERT ((PciDeviceInfo == NULL) || (PciDeviceInfo == SerialDevice->PciDeviceInfo));\r
+ PciDeviceInfo = SerialDevice->PciDeviceInfo;\r
+\r
+ Status = gBS->CloseProtocol (\r
+ Controller,\r
+ PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index]\r
+ );\r
+\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,\r
+ &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->OpenProtocol (\r
+ Controller,\r
+ PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,\r
+ &IoProtocol,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index],\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ } else {\r
+ FreePool (SerialDevice->DevicePath);\r
+ FreeUnicodeStringTable (SerialDevice->ControllerNameTable);\r
+ FreePool (SerialDevice);\r
+\r
+ if (PciDeviceInfo != NULL) {\r
+ ASSERT (PciDeviceInfo->ChildCount != 0);\r
+ PciDeviceInfo->ChildCount--;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ AllChildrenStopped = FALSE;\r
+ }\r
+ }\r
+\r
+ if (!AllChildrenStopped) {\r
+ return EFI_DEVICE_ERROR;\r
+ } else {\r
+ //\r
+ // If all children are destroyed, restore the PCI attributes.\r
+ //\r
+ if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount == 0)) {\r
+ ASSERT (PciDeviceInfo->PciIo != NULL);\r
+ Status = PciDeviceInfo->PciIo->Attributes (\r
+ PciDeviceInfo->PciIo,\r
+ EfiPciIoAttributeOperationSet,\r
+ PciDeviceInfo->PciAttributes,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ FreePool (PciDeviceInfo);\r
+ }\r
+ return EFI_SUCCESS;\r
+ }\r
+}\r