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