+/**@file\r
+ Serial driver for standard UARTS on an ISA bus.\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved. <BR>\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+**/\r
+\r
+#include "Serial.h"\r
+\r
+//\r
+// ISA Serial Driver Global Variables\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = {\r
+ SerialControllerDriverSupported,\r
+ SerialControllerDriverStart,\r
+ SerialControllerDriverStop,\r
+ 0xa,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+\r
+/**\r
+ The user Entry Point for module IsaSerial. 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
+InitializeIsaSerial(\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 = EfiLibInstallAllDriverProtocols (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gSerialControllerDriver,\r
+ ImageHandle,\r
+ &gIsaSerialComponentName,\r
+ NULL,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+\r
+ return Status;\r
+}\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
+ Routine Description:\r
+\r
+ Check to see if this driver supports the given controller\r
+\r
+ Arguments:\r
+\r
+ This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ Controller - The handle of the controller to test.\r
+ RemainingDevicePath - A pointer to the remaining portion of a device path.\r
+\r
+ Returns:\r
+\r
+ EFI_SUCCESS - This driver can support the given controller\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EFI_ISA_IO_PROTOCOL *IsaIo;\r
+ UART_DEVICE_PATH UartNode;\r
+\r
+ //\r
+ // Ignore the RemainingDevicePath\r
+ //\r
+ //\r
+ // Open the IO Abstraction(s) needed to perform the supported test\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 (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiIsaIoProtocolGuid,\r
+ (VOID **) &IsaIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Use the ISA I/O Protocol to see if Controller is standard ISA UART that\r
+ // can be managed by this driver.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x501)) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Error;\r
+ }\r
+ //\r
+ // Make sure RemainingDevicePath is valid\r
+ //\r
+ if (RemainingDevicePath != NULL) {\r
+ Status = EFI_UNSUPPORTED;\r
+ CopyMem (\r
+ &UartNode,\r
+ (UART_DEVICE_PATH *) RemainingDevicePath,\r
+ sizeof (UART_DEVICE_PATH)\r
+ );\r
+ if (UartNode.Header.Type != MESSAGING_DEVICE_PATH ||\r
+ UartNode.Header.SubType != MSG_UART_DP ||\r
+ sizeof (UART_DEVICE_PATH) != DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) &UartNode)\r
+ ) {\r
+ goto Error;\r
+ }\r
+\r
+ if (UartNode.BaudRate > SERIAL_PORT_MAX_BAUD_RATE) {\r
+ goto Error;\r
+ }\r
+\r
+ if (UartNode.Parity < NoParity || UartNode.Parity > SpaceParity) {\r
+ goto Error;\r
+ }\r
+\r
+ if (UartNode.DataBits < 5 || UartNode.DataBits > 8) {\r
+ goto Error;\r
+ }\r
+\r
+ if (UartNode.StopBits < OneStopBit || UartNode.StopBits > TwoStopBits) {\r
+ goto Error;\r
+ }\r
+\r
+ if ((UartNode.DataBits == 5) && (UartNode.StopBits == TwoStopBits)) {\r
+ goto Error;\r
+ }\r
+\r
+ if ((UartNode.DataBits >= 6) && (UartNode.DataBits <= 8) && (UartNode.StopBits == OneFiveStopBits)) {\r
+ goto Error;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+Error:\r
+ //\r
+ // Close the I/O Abstraction(s) used to perform the supported test\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiIsaIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return Status;\r
+}\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
+\r
+ Routine Description:\r
+\r
+ Start to management the controller passed in\r
+\r
+ Arguments:\r
+\r
+ This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ Controller - The handle of the controller to test.\r
+ RemainingDevicePath - A pointer to the remaining portion of a device path.\r
+\r
+ Returns:\r
+\r
+ EFI_SUCCESS - Driver is started successfully\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ISA_IO_PROTOCOL *IsaIo;\r
+ SERIAL_DEV *SerialDevice;\r
+ UINTN Index;\r
+ UART_DEVICE_PATH Node;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
+ UINTN EntryCount;\r
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
+\r
+ SerialDevice = NULL;\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
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiIsaIoProtocolGuid,\r
+ (VOID **) &IsaIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
+ goto Error;\r
+ }\r
+\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+\r
+ if (RemainingDevicePath == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // Make sure a child handle does not already exist. This driver can only\r
+ // produce one child per serial port.\r
+ //\r
+ Status = gBS->OpenProtocolInformation (\r
+ Controller,\r
+ &gEfiIsaIoProtocolGuid,\r
+ &OpenInfoBuffer,\r
+ &EntryCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = EFI_ALREADY_STARTED;\r
+ for (Index = 0; Index < EntryCount; Index++) {\r
+ if (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {\r
+ Status = gBS->OpenProtocol (\r
+ OpenInfoBuffer[Index].ControllerHandle,\r
+ &gEfiSerialIoProtocolGuid,\r
+ (VOID **) &SerialIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ CopyMem (&Node, RemainingDevicePath, sizeof (UART_DEVICE_PATH));\r
+ Status = SerialIo->SetAttributes (\r
+ SerialIo,\r
+ Node.BaudRate,\r
+ SerialIo->Mode->ReceiveFifoDepth,\r
+ SerialIo->Mode->Timeout,\r
+ (EFI_PARITY_TYPE) Node.Parity,\r
+ Node.DataBits,\r
+ (EFI_STOP_BITS_TYPE) Node.StopBits\r
+ );\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ gBS->FreePool (OpenInfoBuffer);\r
+ return Status;\r
+ }\r
+ //\r
+ // Initialize the serial device instance\r
+ //\r
+ SerialDevice = AllocatePool (sizeof (SERIAL_DEV));\r
+ if (SerialDevice == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ ZeroMem (SerialDevice, sizeof (SERIAL_DEV));\r
+\r
+ SerialDevice->IsaIo = IsaIo;\r
+ SerialDevice->ParentDevicePath = ParentDevicePath;\r
+ SerialDevice->ControllerNameTable = NULL;\r
+\r
+ ADD_SERIAL_NAME (SerialDevice, IsaIo);\r
+\r
+ for (Index = 0; SerialDevice->IsaIo->ResourceList->ResourceItem[Index].Type != EfiIsaAcpiResourceEndOfList; Index++) {\r
+ if (SerialDevice->IsaIo->ResourceList->ResourceItem[Index].Type == EfiIsaAcpiResourceIo) {\r
+ SerialDevice->BaseAddress = (UINT16) SerialDevice->IsaIo->ResourceList->ResourceItem[Index].StartRange;\r
+ }\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
+ ParentDevicePath\r
+ );\r
+\r
+ if (!IsaSerialPortPresent (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
+ ParentDevicePath\r
+ );\r
+ goto Error;\r
+ }\r
+\r
+ SerialDevice->Signature = SERIAL_DEV_SIGNATURE;\r
+ SerialDevice->Type = UART16550A;\r
+ SerialDevice->SoftwareLoopbackEnable = FALSE;\r
+ SerialDevice->HardwareFlowControl = FALSE;\r
+ SerialDevice->Handle = NULL;\r
+ SerialDevice->Receive.First = 0;\r
+ SerialDevice->Receive.Last = 0;\r
+ SerialDevice->Receive.Surplus = SERIAL_MAX_BUFFER_SIZE;\r
+ SerialDevice->Transmit.First = 0;\r
+ SerialDevice->Transmit.Last = 0;\r
+ SerialDevice->Transmit.Surplus = SERIAL_MAX_BUFFER_SIZE;\r
+\r
+ //\r
+ // Serial I/O\r
+ //\r
+ SerialDevice->SerialIo.Revision = SERIAL_IO_INTERFACE_REVISION;\r
+ SerialDevice->SerialIo.Reset = IsaSerialReset;\r
+ SerialDevice->SerialIo.SetAttributes = IsaSerialSetAttributes;\r
+ SerialDevice->SerialIo.SetControl = IsaSerialSetControl;\r
+ SerialDevice->SerialIo.GetControl = IsaSerialGetControl;\r
+ SerialDevice->SerialIo.Write = IsaSerialWrite;\r
+ SerialDevice->SerialIo.Read = IsaSerialRead;\r
+ SerialDevice->SerialIo.Mode = &(SerialDevice->SerialMode);\r
+\r
+ if (RemainingDevicePath != NULL) {\r
+ //\r
+ // Match the configuration of the RemainingDevicePath. IsHandleSupported()\r
+ // already checked to make sure the RemainingDevicePath contains settings\r
+ // that we can support.\r
+ //\r
+ CopyMem (&SerialDevice->UartDevicePath, RemainingDevicePath, sizeof (UART_DEVICE_PATH));\r
+ } else {\r
+ //\r
+ // Build the device path by appending the UART node to the ParentDevicePath\r
+ // from the WinNtIo handle. The Uart setings are zero here, since\r
+ // SetAttribute() will update them to match the default setings.\r
+ //\r
+ ZeroMem (&SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH));\r
+ SerialDevice->UartDevicePath.Header.Type = MESSAGING_DEVICE_PATH;\r
+ SerialDevice->UartDevicePath.Header.SubType = MSG_UART_DP;\r
+ SetDevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH));\r
+ }\r
+ //\r
+ // Build the device path by appending the UART node to the ParentDevicePath\r
+ // from the WinNtIo handle. The Uart setings are zero here, since\r
+ // SetAttribute() will update them to match the current setings.\r
+ //\r
+ SerialDevice->DevicePath = AppendDevicePathNode (\r
+ ParentDevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath\r
+ );\r
+\r
+ if (SerialDevice->DevicePath == NULL) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Error;\r
+ }\r
+ //\r
+ // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.\r
+ //\r
+ SerialDevice->SerialMode.ControlMask = SERIAL_PORT_DEFAULT_CONTROL_MASK;\r
+ SerialDevice->SerialMode.Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;\r
+ SerialDevice->SerialMode.BaudRate = SerialDevice->UartDevicePath.BaudRate;\r
+ SerialDevice->SerialMode.ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH;\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
+ ParentDevicePath\r
+ );\r
+ goto Error;\r
+ }\r
+ //\r
+ // Install protocol interfaces for the serial device.\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &SerialDevice->Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ SerialDevice->DevicePath,\r
+ &gEfiSerialIoProtocolGuid,\r
+ &SerialDevice->SerialIo,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ //\r
+ // Open For Child Device\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiIsaIoProtocolGuid,\r
+ (VOID **) &IsaIo,\r
+ This->DriverBindingHandle,\r
+ SerialDevice->Handle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+\r
+Error:\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiIsaIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ if (SerialDevice) {\r
+ if (SerialDevice->DevicePath) {\r
+ gBS->FreePool (SerialDevice->DevicePath);\r
+ }\r
+\r
+ FreeUnicodeStringTable (SerialDevice->ControllerNameTable);\r
+ gBS->FreePool (SerialDevice);\r
+ }\r
+ }\r
+\r
+ return Status;\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
+ Routine Description:\r
+\r
+ Disconnect this driver with the controller, uninstall related protocol instance\r
+\r
+ Arguments:\r
+\r
+ This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ Controller - The handle of the controller to test.\r
+ NumberOfChildren - Number of child device.\r
+ RemainingDevicePath - A pointer to the remaining portion of a device path.\r
+\r
+ Returns:\r
+\r
+ EFI_SUCCESS - Operation successfully\r
+ EFI_DEVICE_ERROR - Cannot stop the driver successfully\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ BOOLEAN AllChildrenStopped;\r
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
+ SERIAL_DEV *SerialDevice;\r
+ EFI_ISA_IO_PROTOCOL *IsaIo;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\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
+ //\r
+ // Complete all outstanding transactions to Controller.\r
+ // Don't allow any new transaction to Controller to be started.\r
+ //\r
+ if (NumberOfChildren == 0) {\r
+ //\r
+ // Close the bus driver\r
+ //\r
+ Status = gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiIsaIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ Status = gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ return Status;\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
+\r
+ Status = gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiIsaIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index]\r
+ );\r
+\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiDevicePathProtocolGuid,\r
+ SerialDevice->DevicePath,\r
+ &gEfiSerialIoProtocolGuid,\r
+ &SerialDevice->SerialIo,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiIsaIoProtocolGuid,\r
+ (VOID **) &IsaIo,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index],\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ } else {\r
+ if (SerialDevice->DevicePath) {\r
+ gBS->FreePool (SerialDevice->DevicePath);\r
+ }\r
+\r
+ FreeUnicodeStringTable (SerialDevice->ControllerNameTable);\r
+ gBS->FreePool (SerialDevice);\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ AllChildrenStopped = FALSE;\r
+ }\r
+ }\r
+\r
+ if (!AllChildrenStopped) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+IsaSerialFifoFull (\r
+ IN SERIAL_DEV_FIFO *Fifo\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Detect whether specific FIFO is full or not\r
+\r
+ Arguments:\r
+\r
+ Fifo - A pointer to the Data Structure SERIAL_DEV_FIFO\r
+\r
+ Returns:\r
+\r
+ TRUE - the FIFO is full\r
+ FALSE - the FIFO is not full\r
+\r
+--*/\r
+{\r
+ if (Fifo->Surplus == 0) {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+BOOLEAN\r
+IsaSerialFifoEmpty (\r
+ IN SERIAL_DEV_FIFO *Fifo\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Detect whether specific FIFO is empty or not\r
+\r
+ Arguments:\r
+\r
+ Fifo - A pointer to the Data Structure SERIAL_DEV_FIFO\r
+\r
+ Returns:\r
+\r
+ TRUE - the FIFO is empty\r
+ FALSE - the FIFO is not empty\r
+\r
+--*/\r
+{\r
+ if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+EFI_STATUS\r
+IsaSerialFifoAdd (\r
+ IN SERIAL_DEV_FIFO *Fifo,\r
+ IN UINT8 Data\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Add data to specific FIFO\r
+\r
+ Arguments:\r
+\r
+ Fifo - A pointer to the Data Structure SERIAL_DEV_FIFO\r
+ Data - the data added to FIFO\r
+\r
+ Returns:\r
+\r
+ EFI_SUCCESS - Add data to specific FIFO successfully\r
+ EFI_OUT_OF_RESOURCE - Failed to add data because FIFO is already full\r
+\r
+--*/\r
+{\r
+ //\r
+ // if FIFO full can not add data\r
+ //\r
+ if (IsaSerialFifoFull (Fifo)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // FIFO is not full can add data\r
+ //\r
+ Fifo->Data[Fifo->Last] = Data;\r
+ Fifo->Surplus--;\r
+ Fifo->Last++;\r
+ if (Fifo->Last == SERIAL_MAX_BUFFER_SIZE) {\r
+ Fifo->Last = 0;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+IsaSerialFifoRemove (\r
+ IN SERIAL_DEV_FIFO *Fifo,\r
+ OUT UINT8 *Data\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Remove data from specific FIFO\r
+\r
+ Arguments:\r
+\r
+ Fifo - A pointer to the Data Structure SERIAL_DEV_FIFO\r
+ Data - the data removed from FIFO\r
+\r
+ Returns:\r
+ EFI_SUCCESS - Remove data from specific FIFO successfully\r
+ EFI_OUT_OF_RESOURCE - Failed to remove data because FIFO is empty\r
+\r
+--*/\r
+{\r
+ //\r
+ // if FIFO is empty, no data can remove\r
+ //\r
+ if (IsaSerialFifoEmpty (Fifo)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // FIFO is not empty, can remove data\r
+ //\r
+ *Data = Fifo->Data[Fifo->First];\r
+ Fifo->Surplus++;\r
+ Fifo->First++;\r
+ if (Fifo->First == SERIAL_MAX_BUFFER_SIZE) {\r
+ Fifo->First = 0;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+IsaSerialReceiveTransmit (\r
+ IN SERIAL_DEV *SerialDevice\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Reads and writes all avaliable data.\r
+\r
+ Arguments:\r
+\r
+ SerialDevice - The device to flush\r
+\r
+ Returns:\r
+\r
+ EFI_SUCCESS - Data was read/written successfully.\r
+ EFI_OUT_OF_RESOURCE - Failed because software receive FIFO is full. Note, when\r
+ this happens, pending writes are not done.\r
+\r
+--*/\r
+{\r
+ SERIAL_PORT_LSR Lsr;\r
+ UINT8 Data;\r
+ BOOLEAN ReceiveFifoFull;\r
+ SERIAL_PORT_MSR Msr;\r
+ SERIAL_PORT_MCR Mcr;\r
+ UINTN TimeOut;\r
+\r
+ Data = 0;\r
+\r
+ //\r
+ // Begin the read or write\r
+ //\r
+ if (SerialDevice->SoftwareLoopbackEnable) {\r
+ do {\r
+ ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);\r
+ if (!IsaSerialFifoEmpty (&SerialDevice->Transmit)) {\r
+ IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);\r
+ if (ReceiveFifoFull) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ IsaSerialFifoAdd (&SerialDevice->Receive, Data);\r
+ }\r
+ } while (!IsaSerialFifoEmpty (&SerialDevice->Transmit));\r
+ } else {\r
+ ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);\r
+ do {\r
+ Lsr.Data = READ_LSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+\r
+ if (FeaturePcdGet (PcdNtEmulatorEnable)) {\r
+ //\r
+ // This is required for NT to avoid a forever-spin...\r
+ // This would be better if READ_LSR was a polling operation\r
+ // that would timeout.\r
+ //\r
+ Lsr.Bits.THRE = 1;\r
+ }\r
+ //\r
+ // Flush incomming data to prevent a an overrun during a long write\r
+ //\r
+ if (Lsr.Bits.DR && !ReceiveFifoFull) {\r
+ ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);\r
+ if (!ReceiveFifoFull) {\r
+ if (Lsr.Bits.FIFOE || Lsr.Bits.OE || Lsr.Bits.PE || Lsr.Bits.FE || Lsr.Bits.BI) {\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_ERROR_CODE,\r
+ EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,\r
+ SerialDevice->DevicePath\r
+ );\r
+ if (Lsr.Bits.FIFOE || Lsr.Bits.PE || Lsr.Bits.FE || Lsr.Bits.BI) {\r
+ Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+ continue;\r
+ }\r
+ }\r
+ //\r
+ // Make sure the receive data will not be missed, Assert DTR\r
+ //\r
+ if (SerialDevice->HardwareFlowControl) {\r
+ Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+ Mcr.Bits.DTRC &= 0;\r
+ WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);\r
+ }\r
+\r
+ Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+\r
+ //\r
+ // Deassert DTR\r
+ //\r
+ if (SerialDevice->HardwareFlowControl) {\r
+ Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+ Mcr.Bits.DTRC |= 1;\r
+ WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);\r
+ }\r
+\r
+ IsaSerialFifoAdd (&SerialDevice->Receive, Data);\r
+\r
+ continue;\r
+ } else {\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_PROGRESS_CODE,\r
+ EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT,\r
+ SerialDevice->DevicePath\r
+ );\r
+ }\r
+ }\r
+ //\r
+ // Do the write\r
+ //\r
+ if (Lsr.Bits.THRE && !IsaSerialFifoEmpty (&SerialDevice->Transmit)) {\r
+ //\r
+ // Make sure the transmit data will not be missed\r
+ //\r
+ if (SerialDevice->HardwareFlowControl) {\r
+ //\r
+ // Send RTS\r
+ //\r
+ Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+ Mcr.Bits.RTS |= 1;\r
+ WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);\r
+ //\r
+ // Wait for CTS\r
+ //\r
+ TimeOut = 0;\r
+ Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+ while (!Msr.Bits.CTS) {\r
+ gBS->Stall (TIMEOUT_STALL_INTERVAL);\r
+ TimeOut++;\r
+ if (TimeOut > 5) {\r
+ break;\r
+ }\r
+\r
+ Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+ }\r
+\r
+ if (Msr.Bits.CTS) {\r
+ IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);\r
+ WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data);\r
+ }\r
+ }\r
+ //\r
+ // write the data out\r
+ //\r
+ if (!SerialDevice->HardwareFlowControl) {\r
+ IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);\r
+ WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data);\r
+ }\r
+ //\r
+ // Make sure the transmit data will not be missed\r
+ //\r
+ if (SerialDevice->HardwareFlowControl) {\r
+ //\r
+ // Assert RTS\r
+ //\r
+ Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+ Mcr.Bits.RTS &= 0;\r
+ WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);\r
+ }\r
+ }\r
+ } while (Lsr.Bits.THRE && !IsaSerialFifoEmpty (&SerialDevice->Transmit));\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+//\r
+// Interface Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+IsaSerialReset (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Reset serial device\r
+\r
+ Arguments:\r
+\r
+ This - Pointer to EFI_SERIAL_IO_PROTOCOL\r
+\r
+ Returns:\r
+\r
+ EFI_SUCCESS - Reset successfully\r
+ EFI_DEVICE_ERROR - Failed to reset\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ SERIAL_DEV *SerialDevice;\r
+ SERIAL_PORT_LCR Lcr;\r
+ SERIAL_PORT_IER Ier;\r
+ SERIAL_PORT_MCR Mcr;\r
+ SERIAL_PORT_FCR Fcr;\r
+ EFI_TPL Tpl;\r
+\r
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
+\r
+ //\r
+ // Report the status code reset the serial\r
+ //\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_PROGRESS_CODE,\r
+ EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT,\r
+ SerialDevice->DevicePath\r
+ );\r
+\r
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ //\r
+ // Make sure DLAB is 0.\r
+ //\r
+ Lcr.Data = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+ Lcr.Bits.DLAB = 0;\r
+ WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);\r
+\r
+ //\r
+ // Turn off all interrupts\r
+ //\r
+ Ier.Data = READ_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+ Ier.Bits.RAVIE = 0;\r
+ Ier.Bits.THEIE = 0;\r
+ Ier.Bits.RIE = 0;\r
+ Ier.Bits.MIE = 0;\r
+ WRITE_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress, Ier.Data);\r
+\r
+ //\r
+ // Disable the FIFO.\r
+ //\r
+ Fcr.Bits.TRFIFOE = 0;\r
+ WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data);\r
+\r
+ //\r
+ // Turn off loopback and disable device interrupt.\r
+ //\r
+ Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+ Mcr.Bits.OUT1 = 0;\r
+ Mcr.Bits.OUT2 = 0;\r
+ Mcr.Bits.LME = 0;\r
+ WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);\r
+\r
+ //\r
+ // Clear the scratch pad register\r
+ //\r
+ WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0);\r
+\r
+ //\r
+ // Go set the current attributes\r
+ //\r
+ Status = This->SetAttributes (\r
+ This,\r
+ This->Mode->BaudRate,\r
+ This->Mode->ReceiveFifoDepth,\r
+ This->Mode->Timeout,\r
+ (EFI_PARITY_TYPE) This->Mode->Parity,\r
+ (UINT8) This->Mode->DataBits,\r
+ (EFI_STOP_BITS_TYPE) This->Mode->StopBits\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->RestoreTPL (Tpl);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Go set the current control bits\r
+ //\r
+ Status = This->SetControl (\r
+ This,\r
+ This->Mode->ControlMask\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->RestoreTPL (Tpl);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // for 16550A enable FIFO, 16550 disable FIFO\r
+ //\r
+ Fcr.Bits.TRFIFOE = 1;\r
+ Fcr.Bits.RESETRF = 1;\r
+ Fcr.Bits.RESETTF = 1;\r
+ WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data);\r
+\r
+ //\r
+ // Reset the software FIFO\r
+ //\r
+ SerialDevice->Receive.First = 0;\r
+ SerialDevice->Receive.Last = 0;\r
+ SerialDevice->Receive.Surplus = SERIAL_MAX_BUFFER_SIZE;\r
+ SerialDevice->Transmit.First = 0;\r
+ SerialDevice->Transmit.Last = 0;\r
+ SerialDevice->Transmit.Surplus = SERIAL_MAX_BUFFER_SIZE;\r
+\r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ //\r
+ // Device reset is complete\r
+ //\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaSerialSetAttributes (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN UINT64 BaudRate,\r
+ IN UINT32 ReceiveFifoDepth,\r
+ IN UINT32 Timeout,\r
+ IN EFI_PARITY_TYPE Parity,\r
+ IN UINT8 DataBits,\r
+ IN EFI_STOP_BITS_TYPE StopBits\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Set new attributes to a serial device\r
+\r
+ Arguments:\r
+\r
+ This - Pointer to EFI_SERIAL_IO_PROTOCOL\r
+ BaudRate - The baudrate of the serial device\r
+ ReceiveFifoDepth - The depth of receive FIFO buffer\r
+ Timeout - The request timeout for a single char\r
+ Parity - The type of parity used in serial device\r
+ DataBits - Number of databits used in serial device\r
+ StopBits - Number of stopbits used in serial device\r
+\r
+ Returns:\r
+\r
+ EFI_SUCCESS - The new attributes were set\r
+ EFI_INVALID_PARAMETERS - One or more attributes have an unsupported value\r
+ EFI_UNSUPPORTED - Data Bits can not set to 5 or 6\r
+ EFI_DEVICE_ERROR - The serial device is not functioning correctly (no return)\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ SERIAL_DEV *SerialDevice;\r
+ UINT32 Divisor;\r
+ UINT32 Remained;\r
+ SERIAL_PORT_LCR Lcr;\r
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
+ EFI_TPL Tpl;\r
+\r
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
+\r
+ //\r
+ // Check for default settings and fill in actual values.\r
+ //\r
+ if (BaudRate == 0) {\r
+ BaudRate = SERIAL_PORT_DEFAULT_BAUD_RATE;\r
+ }\r
+\r
+ if (ReceiveFifoDepth == 0) {\r
+ ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH;\r
+ }\r
+\r
+ if (Timeout == 0) {\r
+ Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;\r
+ }\r
+\r
+ if (Parity == DefaultParity) {\r
+ Parity = SERIAL_PORT_DEFAULT_PARITY;\r
+ }\r
+\r
+ if (DataBits == 0) {\r
+ DataBits = SERIAL_PORT_DEFAULT_DATA_BITS;\r
+ }\r
+\r
+ if (StopBits == DefaultStopBits) {\r
+ StopBits = (EFI_STOP_BITS_TYPE) SERIAL_PORT_DEFAULT_STOP_BITS;\r
+ }\r
+ //\r
+ // 5 and 6 data bits can not be verified on a 16550A UART\r
+ // Return EFI_INVALID_PARAMETER if an attempt is made to use these settings.\r
+ //\r
+ if ((DataBits == 5) || (DataBits == 6)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Make sure all parameters are valid\r
+ //\r
+ if ((BaudRate > SERIAL_PORT_MAX_BAUD_RATE) || (BaudRate < SERIAL_PORT_MIN_BAUD_RATE)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // 50,75,110,134,150,300,600,1200,1800,2000,2400,3600,4800,7200,9600,19200,\r
+ // 38400,57600,115200\r
+ //\r
+ if (BaudRate < 75) {\r
+ BaudRate = 50;\r
+ } else if (BaudRate < 110) {\r
+ BaudRate = 75;\r
+ } else if (BaudRate < 134) {\r
+ BaudRate = 110;\r
+ } else if (BaudRate < 150) {\r
+ BaudRate = 134;\r
+ } else if (BaudRate < 300) {\r
+ BaudRate = 150;\r
+ } else if (BaudRate < 600) {\r
+ BaudRate = 300;\r
+ } else if (BaudRate < 1200) {\r
+ BaudRate = 600;\r
+ } else if (BaudRate < 1800) {\r
+ BaudRate = 1200;\r
+ } else if (BaudRate < 2000) {\r
+ BaudRate = 1800;\r
+ } else if (BaudRate < 2400) {\r
+ BaudRate = 2000;\r
+ } else if (BaudRate < 3600) {\r
+ BaudRate = 2400;\r
+ } else if (BaudRate < 4800) {\r
+ BaudRate = 3600;\r
+ } else if (BaudRate < 7200) {\r
+ BaudRate = 4800;\r
+ } else if (BaudRate < 9600) {\r
+ BaudRate = 7200;\r
+ } else if (BaudRate < 19200) {\r
+ BaudRate = 9600;\r
+ } else if (BaudRate < 38400) {\r
+ BaudRate = 19200;\r
+ } else if (BaudRate < 57600) {\r
+ BaudRate = 38400;\r
+ } else if (BaudRate < 115200) {\r
+ BaudRate = 57600;\r
+ } else if (BaudRate <= SERIAL_PORT_MAX_BAUD_RATE) {\r
+ BaudRate = 115200;\r
+ }\r
+\r
+ if ((ReceiveFifoDepth < 1) || (ReceiveFifoDepth > SERIAL_PORT_MAX_RECEIVE_FIFO_DEPTH)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Parity < NoParity) || (Parity > SpaceParity)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((DataBits < 5) || (DataBits > 8)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((StopBits < OneStopBit) || (StopBits > TwoStopBits)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // for DataBits = 5, StopBits can not set TwoStopBits\r
+ //\r
+ // if ((DataBits == 5) && (StopBits == TwoStopBits)) {\r
+ // return EFI_INVALID_PARAMETER;\r
+ // }\r
+ //\r
+ // for DataBits = 6,7,8, StopBits can not set OneFiveStopBits\r
+ //\r
+ if ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Compute divisor use to program the baud rate using a round determination\r
+ //\r
+ Divisor = (UINT32) DivU64x32Remainder (\r
+ SERIAL_PORT_INPUT_CLOCK,\r
+ ((UINT32) BaudRate * 16),\r
+ &Remained\r
+ );\r
+ if (Remained) {\r
+ Divisor += 1;\r
+ }\r
+\r
+ if ((Divisor == 0) || (Divisor & 0xffff0000)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ //\r
+ // Compute the actual baud rate that the serial port will be programmed for.\r
+ //\r
+ BaudRate = SERIAL_PORT_INPUT_CLOCK / Divisor / 16;\r
+\r
+ //\r
+ // Put serial port on Divisor Latch Mode\r
+ //\r
+ Lcr.Data = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+ Lcr.Bits.DLAB = 1;\r
+ WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);\r
+\r
+ //\r
+ // Write the divisor to the serial port\r
+ //\r
+ WRITE_DLL (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) (Divisor & 0xff));\r
+ WRITE_DLM (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) ((Divisor >> 8) & 0xff));\r
+\r
+ //\r
+ // Put serial port back in normal mode and set remaining attributes.\r
+ //\r
+ Lcr.Bits.DLAB = 0;\r
+\r
+ switch (Parity) {\r
+ case NoParity:\r
+ Lcr.Bits.PAREN = 0;\r
+ Lcr.Bits.EVENPAR = 0;\r
+ Lcr.Bits.STICPAR = 0;\r
+ break;\r
+\r
+ case EvenParity:\r
+ Lcr.Bits.PAREN = 1;\r
+ Lcr.Bits.EVENPAR = 1;\r
+ Lcr.Bits.STICPAR = 0;\r
+ break;\r
+\r
+ case OddParity:\r
+ Lcr.Bits.PAREN = 1;\r
+ Lcr.Bits.EVENPAR = 0;\r
+ Lcr.Bits.STICPAR = 0;\r
+ break;\r
+\r
+ case SpaceParity:\r
+ Lcr.Bits.PAREN = 1;\r
+ Lcr.Bits.EVENPAR = 1;\r
+ Lcr.Bits.STICPAR = 1;\r
+ break;\r
+\r
+ case MarkParity:\r
+ Lcr.Bits.PAREN = 1;\r
+ Lcr.Bits.EVENPAR = 0;\r
+ Lcr.Bits.STICPAR = 1;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ switch (StopBits) {\r
+ case OneStopBit:\r
+ Lcr.Bits.STOPB = 0;\r
+ break;\r
+\r
+ case OneFiveStopBits:\r
+ case TwoStopBits:\r
+ Lcr.Bits.STOPB = 1;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ //\r
+ // DataBits\r
+ //\r
+ Lcr.Bits.SERIALDB = (UINT8) ((DataBits - 5) & 0x03);\r
+ WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);\r
+\r
+ //\r
+ // Set the Serial I/O mode\r
+ //\r
+ This->Mode->BaudRate = BaudRate;\r
+ This->Mode->ReceiveFifoDepth = ReceiveFifoDepth;\r
+ This->Mode->Timeout = Timeout;\r
+ This->Mode->Parity = Parity;\r
+ This->Mode->DataBits = DataBits;\r
+ This->Mode->StopBits = StopBits;\r
+\r
+ //\r
+ // See if Device Path Node has actually changed\r
+ //\r
+ if (SerialDevice->UartDevicePath.BaudRate == BaudRate &&\r
+ SerialDevice->UartDevicePath.DataBits == DataBits &&\r
+ SerialDevice->UartDevicePath.Parity == Parity &&\r
+ SerialDevice->UartDevicePath.StopBits == StopBits\r
+ ) {\r
+ gBS->RestoreTPL (Tpl);\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // Update the device path\r
+ //\r
+ SerialDevice->UartDevicePath.BaudRate = BaudRate;\r
+ SerialDevice->UartDevicePath.DataBits = DataBits;\r
+ SerialDevice->UartDevicePath.Parity = (UINT8) Parity;\r
+ SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits;\r
+\r
+ NewDevicePath = AppendDevicePathNode (\r
+ SerialDevice->ParentDevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath\r
+ );\r
+ if (NewDevicePath == NULL) {\r
+ gBS->RestoreTPL (Tpl);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (SerialDevice->Handle != NULL) {\r
+ Status = gBS->ReinstallProtocolInterface (\r
+ SerialDevice->Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ SerialDevice->DevicePath,\r
+ NewDevicePath\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->RestoreTPL (Tpl);\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ if (SerialDevice->DevicePath) {\r
+ gBS->FreePool (SerialDevice->DevicePath);\r
+ }\r
+\r
+ SerialDevice->DevicePath = NewDevicePath;\r
+\r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaSerialSetControl (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN UINT32 Control\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Set Control Bits\r
+\r
+ Arguments:\r
+\r
+ This - Pointer to EFI_SERIAL_IO_PROTOCOL\r
+ Control - Control bits that can be settable\r
+\r
+ Returns:\r
+\r
+ EFI_SUCCESS - New Control bits were set successfully\r
+ EFI_UNSUPPORTED - The Control bits wanted to set are not supported\r
+\r
+--*/\r
+{\r
+ SERIAL_DEV *SerialDevice;\r
+ SERIAL_PORT_MCR Mcr;\r
+ EFI_TPL Tpl;\r
+\r
+ //\r
+ // The control bits that can be set are :\r
+ // EFI_SERIAL_DATA_TERMINAL_READY: 0x0001 // WO\r
+ // EFI_SERIAL_REQUEST_TO_SEND: 0x0002 // WO\r
+ // EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000 // RW\r
+ // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000 // RW\r
+ //\r
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
+\r
+ //\r
+ // first determine the parameter is invalid\r
+ //\r
+ if (Control & 0xffff8ffc) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+ Mcr.Bits.DTRC = 0;\r
+ Mcr.Bits.RTS = 0;\r
+ Mcr.Bits.LME = 0;\r
+ SerialDevice->SoftwareLoopbackEnable = FALSE;\r
+ SerialDevice->HardwareFlowControl = FALSE;\r
+\r
+ if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {\r
+ Mcr.Bits.DTRC = 1;\r
+ }\r
+\r
+ if (Control & EFI_SERIAL_REQUEST_TO_SEND) {\r
+ Mcr.Bits.RTS = 1;\r
+ }\r
+\r
+ if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {\r
+ Mcr.Bits.LME = 1;\r
+ }\r
+\r
+ if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {\r
+ SerialDevice->HardwareFlowControl = TRUE;\r
+ }\r
+\r
+ WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);\r
+\r
+ if (Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {\r
+ SerialDevice->SoftwareLoopbackEnable = TRUE;\r
+ }\r
+\r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaSerialGetControl (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ OUT UINT32 *Control\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Get ControlBits\r
+\r
+ Arguments:\r
+\r
+ This - Pointer to EFI_SERIAL_IO_PROTOCOL\r
+ Control - Control signals of the serial device\r
+\r
+ Returns:\r
+\r
+ EFI_SUCCESS - Get Control signals successfully\r
+\r
+--*/\r
+{\r
+ SERIAL_DEV *SerialDevice;\r
+ SERIAL_PORT_MSR Msr;\r
+ SERIAL_PORT_MCR Mcr;\r
+ EFI_TPL Tpl;\r
+\r
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
+\r
+ *Control = 0;\r
+\r
+ //\r
+ // Read the Modem Status Register\r
+ //\r
+ Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+\r
+ if (Msr.Bits.CTS) {\r
+ *Control |= EFI_SERIAL_CLEAR_TO_SEND;\r
+ }\r
+\r
+ if (Msr.Bits.DSR) {\r
+ *Control |= EFI_SERIAL_DATA_SET_READY;\r
+ }\r
+\r
+ if (Msr.Bits.RI) {\r
+ *Control |= EFI_SERIAL_RING_INDICATE;\r
+ }\r
+\r
+ if (Msr.Bits.DCD) {\r
+ *Control |= EFI_SERIAL_CARRIER_DETECT;\r
+ }\r
+ //\r
+ // Read the Modem Control Register\r
+ //\r
+ Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+\r
+ if (Mcr.Bits.DTRC) {\r
+ *Control |= EFI_SERIAL_DATA_TERMINAL_READY;\r
+ }\r
+\r
+ if (Mcr.Bits.RTS) {\r
+ *Control |= EFI_SERIAL_REQUEST_TO_SEND;\r
+ }\r
+\r
+ if (Mcr.Bits.LME) {\r
+ *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;\r
+ }\r
+\r
+ if (SerialDevice->HardwareFlowControl) {\r
+ *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
+ }\r
+ //\r
+ // See if the Transmit FIFO is empty\r
+ //\r
+ IsaSerialReceiveTransmit (SerialDevice);\r
+\r
+ if (IsaSerialFifoEmpty (&SerialDevice->Transmit)) {\r
+ *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;\r
+ }\r
+ //\r
+ // See if the Receive FIFO is empty.\r
+ //\r
+ IsaSerialReceiveTransmit (SerialDevice);\r
+\r
+ if (IsaSerialFifoEmpty (&SerialDevice->Receive)) {\r
+ *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;\r
+ }\r
+\r
+ if (SerialDevice->SoftwareLoopbackEnable) {\r
+ *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;\r
+ }\r
+\r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaSerialWrite (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Write the specified number of bytes to serial device\r
+\r
+ Arguments:\r
+\r
+ This - Pointer to EFI_SERIAL_IO_PROTOCOL\r
+ BufferSize - On input the size of Buffer, on output the amount of\r
+ data actually written\r
+ Buffer - The buffer of data to write\r
+\r
+ Returns:\r
+\r
+ EFI_SUCCESS - The data were written successfully\r
+ EFI_DEVICE_ERROR - The device reported an error\r
+ EFI_TIMEOUT - The write operation was stopped due to timeout\r
+\r
+--*/\r
+{\r
+ SERIAL_DEV *SerialDevice;\r
+ UINT8 *CharBuffer;\r
+ UINT32 Index;\r
+ UINTN Elapsed;\r
+ UINTN ActualWrite;\r
+ EFI_TPL Tpl;\r
+\r
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
+ Elapsed = 0;\r
+ ActualWrite = 0;\r
+\r
+ if (*BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (!Buffer) {\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_ERROR_CODE,\r
+ EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,\r
+ SerialDevice->DevicePath\r
+ );\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ CharBuffer = (UINT8 *) Buffer;\r
+\r
+ for (Index = 0; Index < *BufferSize; Index++) {\r
+ IsaSerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]);\r
+\r
+ while (IsaSerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !IsaSerialFifoEmpty (&SerialDevice->Transmit)) {\r
+ //\r
+ // Unsuccessful write so check if timeout has expired, if not,\r
+ // stall for a bit, increment time elapsed, and try again\r
+ //\r
+ if (Elapsed >= This->Mode->Timeout) {\r
+ *BufferSize = ActualWrite;\r
+ gBS->RestoreTPL (Tpl);\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ gBS->Stall (TIMEOUT_STALL_INTERVAL);\r
+\r
+ Elapsed += TIMEOUT_STALL_INTERVAL;\r
+ }\r
+\r
+ ActualWrite++;\r
+ //\r
+ // Successful write so reset timeout\r
+ //\r
+ Elapsed = 0;\r
+ }\r
+\r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaSerialRead (\r
+ IN EFI_SERIAL_IO_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Read the specified number of bytes from serial device\r
+\r
+ Arguments:\r
+\r
+ This - Pointer to EFI_SERIAL_IO_PROTOCOL\r
+ BufferSize - On input the size of Buffer, on output the amount of\r
+ data returned in buffer\r
+ Buffer - The buffer to return the data into\r
+\r
+ Returns:\r
+\r
+ EFI_SUCCESS - The data were read successfully\r
+ EFI_DEVICE_ERROR - The device reported an error\r
+ EFI_TIMEOUT - The read operation was stopped due to timeout\r
+\r
+--*/\r
+{\r
+ SERIAL_DEV *SerialDevice;\r
+ UINT32 Index;\r
+ UINT8 *CharBuffer;\r
+ UINTN Elapsed;\r
+ EFI_STATUS Status;\r
+ EFI_TPL Tpl;\r
+\r
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
+ Elapsed = 0;\r
+\r
+ if (*BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (!Buffer) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ Status = IsaSerialReceiveTransmit (SerialDevice);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ *BufferSize = 0;\r
+\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_ERROR_CODE,\r
+ EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,\r
+ SerialDevice->DevicePath\r
+ );\r
+\r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ CharBuffer = (UINT8 *) Buffer;\r
+ for (Index = 0; Index < *BufferSize; Index++) {\r
+ while (IsaSerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) {\r
+ //\r
+ // Unsuccessful read so check if timeout has expired, if not,\r
+ // stall for a bit, increment time elapsed, and try again\r
+ // Need this time out to get conspliter to work.\r
+ //\r
+ if (Elapsed >= This->Mode->Timeout) {\r
+ *BufferSize = Index;\r
+ gBS->RestoreTPL (Tpl);\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ gBS->Stall (TIMEOUT_STALL_INTERVAL);\r
+ Elapsed += TIMEOUT_STALL_INTERVAL;\r
+\r
+ Status = IsaSerialReceiveTransmit (SerialDevice);\r
+ if (Status == EFI_DEVICE_ERROR) {\r
+ *BufferSize = Index;\r
+ gBS->RestoreTPL (Tpl);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+ //\r
+ // Successful read so reset timeout\r
+ //\r
+ Elapsed = 0;\r
+ }\r
+\r
+ IsaSerialReceiveTransmit (SerialDevice);\r
+\r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+IsaSerialPortPresent (\r
+ IN SERIAL_DEV *SerialDevice\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Use scratchpad register to test if this serial port is present\r
+\r
+ Arguments:\r
+\r
+ SerialDevice - Pointer to serial device structure\r
+\r
+ Returns:\r
+\r
+ TRUE - The serial port is present\r
+ FALSE - The serial port is NOT present\r
+\r
+--*/\r
+{\r
+ UINT8 Temp;\r
+ BOOLEAN Status;\r
+\r
+ Status = TRUE;\r
+\r
+ //\r
+ // Save SCR reg\r
+ //\r
+ Temp = READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
+ WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0xAA);\r
+\r
+ if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0xAA)\r
+ {\r
+ if (!FeaturePcdGet (PcdNtEmulatorEnable)) {\r
+ Status = FALSE;\r
+ }\r
+ }\r
+\r
+ WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0x55);\r
+\r
+ if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0x55)\r
+ {\r
+ if (!FeaturePcdGet (PcdNtEmulatorEnable)) {\r
+ Status = FALSE;\r
+ }\r
+ }\r
+ //\r
+ // Restore SCR\r
+ //\r
+ WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Temp);\r
+ return Status;\r
+}\r
+\r
+UINT8\r
+IsaSerialReadPort (\r
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,\r
+ IN UINT16 BaseAddress,\r
+ IN UINT32 Offset\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Use IsaIo protocol to read serial port\r
+\r
+ Arguments:\r
+\r
+ IsaIo - Pointer to EFI_ISA_IO_PROTOCOL instance\r
+ BaseAddress - Serial port register group base address\r
+ Offset - Offset in register group\r
+\r
+ Returns:\r
+\r
+ Data read from serial port\r
+\r
+--*/\r
+{\r
+ UINT8 Data;\r
+\r
+ //\r
+ // Use IsaIo to access IO\r
+ //\r
+ IsaIo->Io.Read (\r
+ IsaIo,\r
+ EfiIsaIoWidthUint8,\r
+ BaseAddress + Offset,\r
+ 1,\r
+ &Data\r
+ );\r
+ return Data;\r
+}\r
+\r
+VOID\r
+IsaSerialWritePort (\r
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,\r
+ IN UINT16 BaseAddress,\r
+ IN UINT32 Offset,\r
+ IN UINT8 Data\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Use IsaIo protocol to write serial port\r
+\r
+ Arguments:\r
+\r
+ IsaIo - Pointer to EFI_ISA_IO_PROTOCOL instance\r
+ BaseAddress - Serial port register group base address\r
+ Offset - Offset in register group\r
+ Data - data which is to be written to some serial port register\r
+\r
+ Returns:\r
+\r
+ None\r
+\r
+--*/\r
+{\r
+ //\r
+ // Use IsaIo to access IO\r
+ //\r
+ IsaIo->Io.Write (\r
+ IsaIo,\r
+ EfiIsaIoWidthUint8,\r
+ BaseAddress + Offset,\r
+ 1,\r
+ &Data\r
+ );\r
+}\r
+\r