mirror of https://github.com/acidanthera/audk.git
1701 lines
49 KiB
C
1701 lines
49 KiB
C
/**@file
|
|
|
|
Copyright (c) 2006 - 2010, Intel Corporation
|
|
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.
|
|
|
|
Module Name:
|
|
|
|
WinNtSerialIo.c
|
|
|
|
Abstract:
|
|
|
|
Our DriverBinding member functions operate on the handles
|
|
created by the NT Bus driver.
|
|
|
|
Handle(1) - WinNtIo - DevicePath(1)
|
|
|
|
If a serial port is added to the system this driver creates a new handle.
|
|
The new handle is required, since the serial device must add an UART device
|
|
pathnode.
|
|
|
|
Handle(2) - SerialIo - DevicePath(1)\UART
|
|
|
|
The driver then adds a gEfiWinNtSerialPortGuid as a protocol to Handle(1).
|
|
The instance data for this protocol is the private data used to create
|
|
Handle(2).
|
|
|
|
Handle(1) - WinNtIo - DevicePath(1) - WinNtSerialPort
|
|
|
|
If the driver is unloaded Handle(2) is removed from the system and
|
|
gEfiWinNtSerialPortGuid is removed from Handle(1).
|
|
|
|
Note: Handle(1) is any handle created by the Win NT Bus driver that is passed
|
|
into the DriverBinding member functions of this driver. This driver requires
|
|
a Handle(1) to contain a WinNtIo protocol, a DevicePath protocol, and
|
|
the TypeGuid in the WinNtIo must be gEfiWinNtSerialPortGuid.
|
|
|
|
If Handle(1) contains a gEfiWinNtSerialPortGuid protocol then the driver is
|
|
loaded on the device.
|
|
|
|
**/
|
|
|
|
#include "WinNtSerialIo.h"
|
|
|
|
EFI_DRIVER_BINDING_PROTOCOL gWinNtSerialIoDriverBinding = {
|
|
WinNtSerialIoDriverBindingSupported,
|
|
WinNtSerialIoDriverBindingStart,
|
|
WinNtSerialIoDriverBindingStop,
|
|
0xa,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
//
|
|
// List of supported baud rate
|
|
//
|
|
UINT64 mBaudRateCurrentSupport[] = {50, 75, 110, 134, 150, 300, 600, 1200, 1800, 2000, 2400, 3600, 4800, 7200, 9600, 19200, 38400, 57600, 115200, SERIAL_PORT_MAX_BAUD_RATE + 1};
|
|
|
|
/**
|
|
Check the device path node whether it's the Flow Control node or not.
|
|
|
|
@param[in] FlowControl The device path node to be checked.
|
|
|
|
@retval TRUE It's the Flow Control node.
|
|
@retval FALSE It's not.
|
|
|
|
**/
|
|
BOOLEAN
|
|
IsUartFlowControlNode (
|
|
IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl
|
|
)
|
|
{
|
|
return (BOOLEAN) (
|
|
(DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) &&
|
|
(DevicePathSubType (FlowControl) == MSG_VENDOR_DP) &&
|
|
(CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid))
|
|
);
|
|
}
|
|
|
|
/**
|
|
Check the device path node whether it contains Flow Control node or not.
|
|
|
|
@param[in] DevicePath The device path to be checked.
|
|
|
|
@retval TRUE It contains the Flow Control node.
|
|
@retval FALSE It doesn't.
|
|
|
|
**/
|
|
BOOLEAN
|
|
ContainsFlowControl (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
)
|
|
{
|
|
while (!IsDevicePathEnd (DevicePath)) {
|
|
if (IsUartFlowControlNode ((UART_FLOW_CONTROL_DEVICE_PATH *) DevicePath)) {
|
|
return TRUE;
|
|
}
|
|
DevicePath = NextDevicePathNode (DevicePath);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
The user Entry Point for module WinNtSerialIo. 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
|
|
InitializeWinNtSerialIo(
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Install driver model protocol(s).
|
|
//
|
|
Status = EfiLibInstallDriverBindingComponentName2 (
|
|
ImageHandle,
|
|
SystemTable,
|
|
&gWinNtSerialIoDriverBinding,
|
|
ImageHandle,
|
|
&gWinNtSerialIoComponentName,
|
|
&gWinNtSerialIoComponentName2
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WinNtSerialIoDriverBindingSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Handle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: This - add argument and description to function comment
|
|
// TODO: Handle - add argument and description to function comment
|
|
// TODO: RemainingDevicePath - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
|
|
EFI_WIN_NT_IO_PROTOCOL *WinNtIo;
|
|
UART_DEVICE_PATH *UartNode;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
UART_FLOW_CONTROL_DEVICE_PATH *FlowControlNode;
|
|
EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
|
|
UINTN EntryCount;
|
|
UINTN Index;
|
|
|
|
//
|
|
// Check RemainingDevicePath validation
|
|
//
|
|
if (RemainingDevicePath != NULL) {
|
|
//
|
|
// Check if RemainingDevicePath is the End of Device Path Node,
|
|
// if yes, go on checking other conditions
|
|
//
|
|
if (!IsDevicePathEnd (RemainingDevicePath)) {
|
|
//
|
|
// If RemainingDevicePath isn't the End of Device Path Node,
|
|
// check its validation
|
|
//
|
|
Status = EFI_UNSUPPORTED;
|
|
|
|
UartNode = (UART_DEVICE_PATH *) RemainingDevicePath;
|
|
if (UartNode->Header.Type != MESSAGING_DEVICE_PATH ||
|
|
UartNode->Header.SubType != MSG_UART_DP ||
|
|
DevicePathNodeLength((EFI_DEVICE_PATH_PROTOCOL *)UartNode) != sizeof(UART_DEVICE_PATH)) {
|
|
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;
|
|
}
|
|
|
|
FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (UartNode);
|
|
if (IsUartFlowControlNode (FlowControlNode)) {
|
|
//
|
|
// If the second node is Flow Control Node,
|
|
// return error when it request other than hardware flow control.
|
|
//
|
|
if ((FlowControlNode->FlowControlMap & ~UART_FLOW_CONTROL_HARDWARE) != 0) {
|
|
goto Error;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Open the IO Abstraction(s) needed to perform the supported test
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Handle,
|
|
&gEfiWinNtIoProtocolGuid,
|
|
(VOID **) &WinNtIo,
|
|
This->DriverBindingHandle,
|
|
Handle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (Status == EFI_ALREADY_STARTED) {
|
|
if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {
|
|
//
|
|
// If RemainingDevicePath is NULL or is the End of Device Path Node
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// When the driver has produced device path with flow control node but RemainingDevicePath only contains UART node,
|
|
// return unsupported, and vice versa.
|
|
//
|
|
Status = gBS->OpenProtocolInformation (
|
|
Handle,
|
|
&gEfiWinNtIoProtocolGuid,
|
|
&OpenInfoBuffer,
|
|
&EntryCount
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
for (Index = 0; Index < EntryCount; Index++) {
|
|
if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
|
|
Status = gBS->OpenProtocol (
|
|
OpenInfoBuffer[Index].ControllerHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **) &DevicePath,
|
|
This->DriverBindingHandle,
|
|
Handle,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (!EFI_ERROR (Status) &&
|
|
(ContainsFlowControl (RemainingDevicePath) ^ ContainsFlowControl (DevicePath))) {
|
|
Status = EFI_UNSUPPORTED;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
FreePool (OpenInfoBuffer);
|
|
return Status;
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Close the I/O Abstraction(s) used to perform the supported test
|
|
//
|
|
gBS->CloseProtocol (
|
|
Handle,
|
|
&gEfiWinNtIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Handle
|
|
);
|
|
|
|
//
|
|
// Open the EFI Device Path protocol needed to perform the supported test
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Handle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **) &ParentDevicePath,
|
|
This->DriverBindingHandle,
|
|
Handle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (Status == EFI_ALREADY_STARTED) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Close protocol, don't use device path protocol in the Support() function
|
|
//
|
|
gBS->CloseProtocol (
|
|
Handle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Handle
|
|
);
|
|
|
|
//
|
|
// Make sure that the WinNt Thunk Protocol is valid
|
|
//
|
|
if (WinNtIo->WinNtThunk->Signature != EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) {
|
|
Status = EFI_UNSUPPORTED;
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Check the GUID to see if this is a handle type the driver supports
|
|
//
|
|
if (!CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtSerialPortGuid)) {
|
|
Status = EFI_UNSUPPORTED;
|
|
goto Error;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
Error:
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WinNtSerialIoDriverBindingStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Handle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: This - add argument and description to function comment
|
|
// TODO: Handle - add argument and description to function comment
|
|
// TODO: RemainingDevicePath - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_WIN_NT_IO_PROTOCOL *WinNtIo;
|
|
WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
|
|
HANDLE NtHandle;
|
|
UART_DEVICE_PATH UartNode;
|
|
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
|
|
EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
|
|
UINTN EntryCount;
|
|
UINTN Index;
|
|
EFI_SERIAL_IO_PROTOCOL *SerialIo;
|
|
UART_DEVICE_PATH *Uart;
|
|
UINT32 FlowControlMap;
|
|
UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
|
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
|
UINT32 Control;
|
|
|
|
Private = NULL;
|
|
NtHandle = INVALID_HANDLE_VALUE;
|
|
|
|
//
|
|
// Get the Parent Device Path
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Handle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **) &ParentDevicePath,
|
|
This->DriverBindingHandle,
|
|
Handle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Grab the IO abstraction we need to get any work done
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Handle,
|
|
&gEfiWinNtIoProtocolGuid,
|
|
(VOID **) &WinNtIo,
|
|
This->DriverBindingHandle,
|
|
Handle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
|
|
gBS->CloseProtocol (
|
|
Handle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Handle
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
if (Status == EFI_ALREADY_STARTED) {
|
|
|
|
if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {
|
|
//
|
|
// If RemainingDevicePath is NULL or is the End of Device Path Node
|
|
//
|
|
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 (
|
|
Handle,
|
|
&gEfiWinNtIoProtocolGuid,
|
|
&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) != 0) {
|
|
Status = gBS->OpenProtocol (
|
|
OpenInfoBuffer[Index].ControllerHandle,
|
|
&gEfiSerialIoProtocolGuid,
|
|
(VOID **) &SerialIo,
|
|
This->DriverBindingHandle,
|
|
Handle,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Uart = (UART_DEVICE_PATH *) RemainingDevicePath;
|
|
Status = SerialIo->SetAttributes (
|
|
SerialIo,
|
|
Uart->BaudRate,
|
|
SerialIo->Mode->ReceiveFifoDepth,
|
|
SerialIo->Mode->Timeout,
|
|
(EFI_PARITY_TYPE) Uart->Parity,
|
|
Uart->DataBits,
|
|
(EFI_STOP_BITS_TYPE) Uart->StopBits
|
|
);
|
|
FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
|
|
if (!EFI_ERROR (Status) && IsUartFlowControlNode (FlowControl)) {
|
|
Status = SerialIo->GetControl (SerialIo, &Control);
|
|
if (!EFI_ERROR (Status)) {
|
|
if (FlowControl->FlowControlMap == UART_FLOW_CONTROL_HARDWARE) {
|
|
Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
|
|
} else {
|
|
Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
|
|
}
|
|
//
|
|
// Clear the bits that are not allowed to pass to SetControl
|
|
//
|
|
Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
|
|
EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
|
|
EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE);
|
|
Status = SerialIo->SetControl (SerialIo, Control);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
FreePool (OpenInfoBuffer);
|
|
return Status;
|
|
}
|
|
|
|
FlowControl = NULL;
|
|
FlowControlMap = 0;
|
|
if (RemainingDevicePath == NULL) {
|
|
//
|
|
// 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 default setings.
|
|
//
|
|
ZeroMem (&UartNode, sizeof (UART_DEVICE_PATH));
|
|
UartNode.Header.Type = MESSAGING_DEVICE_PATH;
|
|
UartNode.Header.SubType = MSG_UART_DP;
|
|
SetDevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) &UartNode, sizeof (UART_DEVICE_PATH));
|
|
|
|
} else if (!IsDevicePathEnd (RemainingDevicePath)) {
|
|
//
|
|
// If RemainingDevicePath isn't the End of Device Path Node,
|
|
// only scan the specified device by RemainingDevicePath
|
|
//
|
|
//
|
|
// Match the configuration of the RemainingDevicePath. IsHandleSupported()
|
|
// already checked to make sure the RemainingDevicePath contains settings
|
|
// that we can support.
|
|
//
|
|
CopyMem (&UartNode, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
|
|
FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (RemainingDevicePath);
|
|
if (IsUartFlowControlNode (FlowControl)) {
|
|
FlowControlMap = FlowControl->FlowControlMap;
|
|
} else {
|
|
FlowControl = NULL;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// If RemainingDevicePath is the End of Device Path Node,
|
|
// skip enumerate any device and return EFI_SUCESSS
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Check to see if we can access the hardware device. If it's Open in NT we
|
|
// will not get access.
|
|
//
|
|
NtHandle = WinNtIo->WinNtThunk->CreateFile (
|
|
WinNtIo->EnvString,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL
|
|
);
|
|
if (NtHandle == INVALID_HANDLE_VALUE) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Construct Private data
|
|
//
|
|
Private = AllocatePool (sizeof (WIN_NT_SERIAL_IO_PRIVATE_DATA));
|
|
if (Private == NULL) {
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// This signature must be valid before any member function is called
|
|
//
|
|
Private->Signature = WIN_NT_SERIAL_IO_PRIVATE_DATA_SIGNATURE;
|
|
Private->NtHandle = NtHandle;
|
|
Private->ControllerHandle = Handle;
|
|
Private->Handle = NULL;
|
|
Private->WinNtThunk = WinNtIo->WinNtThunk;
|
|
Private->ParentDevicePath = ParentDevicePath;
|
|
Private->ControllerNameTable = NULL;
|
|
|
|
Private->SoftwareLoopbackEnable = FALSE;
|
|
Private->HardwareLoopbackEnable = FALSE;
|
|
Private->HardwareFlowControl = (BOOLEAN) (FlowControlMap == UART_FLOW_CONTROL_HARDWARE);
|
|
Private->Fifo.First = 0;
|
|
Private->Fifo.Last = 0;
|
|
Private->Fifo.Surplus = SERIAL_MAX_BUFFER_SIZE;
|
|
|
|
CopyMem (&Private->UartDevicePath, &UartNode, sizeof (UART_DEVICE_PATH));
|
|
|
|
AddUnicodeString2 (
|
|
"eng",
|
|
gWinNtSerialIoComponentName.SupportedLanguages,
|
|
&Private->ControllerNameTable,
|
|
WinNtIo->EnvString,
|
|
TRUE
|
|
);
|
|
AddUnicodeString2 (
|
|
"en",
|
|
gWinNtSerialIoComponentName2.SupportedLanguages,
|
|
&Private->ControllerNameTable,
|
|
WinNtIo->EnvString,
|
|
FALSE
|
|
);
|
|
|
|
|
|
Private->SerialIo.Revision = SERIAL_IO_INTERFACE_REVISION;
|
|
Private->SerialIo.Reset = WinNtSerialIoReset;
|
|
Private->SerialIo.SetAttributes = WinNtSerialIoSetAttributes;
|
|
Private->SerialIo.SetControl = WinNtSerialIoSetControl;
|
|
Private->SerialIo.GetControl = WinNtSerialIoGetControl;
|
|
Private->SerialIo.Write = WinNtSerialIoWrite;
|
|
Private->SerialIo.Read = WinNtSerialIoRead;
|
|
Private->SerialIo.Mode = &Private->SerialIoMode;
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
Private->DevicePath = AppendDevicePathNode (
|
|
ParentDevicePath,
|
|
(EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath
|
|
);
|
|
//
|
|
// Only produce the FlowControl node when remaining device path has it
|
|
//
|
|
if (FlowControl != NULL) {
|
|
TempDevicePath = Private->DevicePath;
|
|
if (TempDevicePath != NULL) {
|
|
Private->DevicePath = AppendDevicePathNode (
|
|
TempDevicePath,
|
|
(EFI_DEVICE_PATH_PROTOCOL *) FlowControl
|
|
);
|
|
FreePool (TempDevicePath);
|
|
}
|
|
}
|
|
if (Private->DevicePath == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
|
|
//
|
|
Private->SerialIoMode.ControlMask = SERIAL_CONTROL_MASK;
|
|
Private->SerialIoMode.Timeout = SERIAL_TIMEOUT_DEFAULT;
|
|
Private->SerialIoMode.BaudRate = Private->UartDevicePath.BaudRate;
|
|
Private->SerialIoMode.ReceiveFifoDepth = SERIAL_FIFO_DEFAULT;
|
|
Private->SerialIoMode.DataBits = Private->UartDevicePath.DataBits;
|
|
Private->SerialIoMode.Parity = Private->UartDevicePath.Parity;
|
|
Private->SerialIoMode.StopBits = Private->UartDevicePath.StopBits;
|
|
|
|
//
|
|
// Issue a reset to initialize the COM port
|
|
//
|
|
Status = Private->SerialIo.Reset (&Private->SerialIo);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Create new child handle
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&Private->Handle,
|
|
&gEfiSerialIoProtocolGuid,
|
|
&Private->SerialIo,
|
|
&gEfiDevicePathProtocolGuid,
|
|
Private->DevicePath,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Open For Child Device
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Handle,
|
|
&gEfiWinNtIoProtocolGuid,
|
|
(VOID **) &WinNtIo,
|
|
This->DriverBindingHandle,
|
|
Private->Handle,
|
|
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
Error:
|
|
//
|
|
// Use the Stop() function to free all resources allocated in Start()
|
|
//
|
|
if (Private != NULL) {
|
|
if (Private->Handle != NULL) {
|
|
This->Stop (This, Handle, 1, &Private->Handle);
|
|
} else {
|
|
if (NtHandle != INVALID_HANDLE_VALUE) {
|
|
Private->WinNtThunk->CloseHandle (NtHandle);
|
|
}
|
|
|
|
if (Private->DevicePath != NULL) {
|
|
FreePool (Private->DevicePath);
|
|
}
|
|
|
|
FreeUnicodeStringTable (Private->ControllerNameTable);
|
|
|
|
FreePool (Private);
|
|
}
|
|
}
|
|
|
|
This->Stop (This, Handle, 0, NULL);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WinNtSerialIoDriverBindingStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Handle,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
This - TODO: add argument description
|
|
Handle - TODO: add argument description
|
|
NumberOfChildren - TODO: add argument description
|
|
ChildHandleBuffer - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
BOOLEAN AllChildrenStopped;
|
|
EFI_SERIAL_IO_PROTOCOL *SerialIo;
|
|
WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
|
|
EFI_WIN_NT_IO_PROTOCOL *WinNtIo;
|
|
|
|
//
|
|
// 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 (
|
|
Handle,
|
|
&gEfiWinNtIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Handle
|
|
);
|
|
Status = gBS->CloseProtocol (
|
|
Handle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Handle
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
AllChildrenStopped = TRUE;
|
|
|
|
for (Index = 0; Index < NumberOfChildren; Index++) {
|
|
Status = gBS->OpenProtocol (
|
|
ChildHandleBuffer[Index],
|
|
&gEfiSerialIoProtocolGuid,
|
|
(VOID **) &SerialIo,
|
|
This->DriverBindingHandle,
|
|
Handle,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (SerialIo);
|
|
|
|
ASSERT (Private->Handle == ChildHandleBuffer[Index]);
|
|
|
|
Status = gBS->CloseProtocol (
|
|
Handle,
|
|
&gEfiWinNtIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
ChildHandleBuffer[Index]
|
|
);
|
|
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
|
ChildHandleBuffer[Index],
|
|
&gEfiSerialIoProtocolGuid,
|
|
&Private->SerialIo,
|
|
&gEfiDevicePathProtocolGuid,
|
|
Private->DevicePath,
|
|
NULL
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->OpenProtocol (
|
|
Handle,
|
|
&gEfiWinNtIoProtocolGuid,
|
|
(VOID **) &WinNtIo,
|
|
This->DriverBindingHandle,
|
|
ChildHandleBuffer[Index],
|
|
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
|
);
|
|
} else {
|
|
Private->WinNtThunk->CloseHandle (Private->NtHandle);
|
|
|
|
FreePool (Private->DevicePath);
|
|
|
|
FreeUnicodeStringTable (Private->ControllerNameTable);
|
|
|
|
FreePool (Private);
|
|
}
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
AllChildrenStopped = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!AllChildrenStopped) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Serial IO Protocol member functions
|
|
//
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WinNtSerialIoReset (
|
|
IN EFI_SERIAL_IO_PROTOCOL *This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
This - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
|
|
EFI_TPL Tpl;
|
|
|
|
Tpl = gBS->RaiseTPL (TPL_NOTIFY);
|
|
|
|
Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
Private->WinNtThunk->PurgeComm (
|
|
Private->NtHandle,
|
|
PURGE_TXCLEAR | PURGE_RXCLEAR
|
|
);
|
|
|
|
gBS->RestoreTPL (Tpl);
|
|
|
|
return 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
|
|
);
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WinNtSerialIoSetAttributes (
|
|
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:
|
|
|
|
This function is used to set the attributes.
|
|
|
|
Arguments:
|
|
|
|
This - A pointer to the EFI_SERIAL_IO_PROTOCOL structrue.
|
|
BaudRate - The Baud rate of the serial device.
|
|
ReceiveFifoDepth - The request depth of fifo on receive side.
|
|
Timeout - the request timeout for a single charact.
|
|
Parity - The type of parity used in serial device.
|
|
DataBits - Number of deata bits used in serial device.
|
|
StopBits - Number of stop bits used in serial device.
|
|
|
|
Returns:
|
|
Status code
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
// TODO: EFI_DEVICE_ERROR - add return value to function comment
|
|
// TODO: EFI_DEVICE_ERROR - add return value to function comment
|
|
// TODO: EFI_DEVICE_ERROR - add return value to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
// TODO: EFI_DEVICE_ERROR - add return value to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
|
|
COMMTIMEOUTS PortTimeOuts;
|
|
DWORD ConvertedTime;
|
|
BOOL Result;
|
|
UART_DEVICE_PATH *Uart;
|
|
EFI_TPL Tpl;
|
|
|
|
Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
//
|
|
// Some of our arguments have defaults if a null value is passed in, and
|
|
// we must set the default values if a null argument is passed in.
|
|
//
|
|
if (BaudRate == 0) {
|
|
BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
|
|
}
|
|
|
|
if (ReceiveFifoDepth == 0) {
|
|
ReceiveFifoDepth = SERIAL_FIFO_DEFAULT;
|
|
}
|
|
|
|
if (Timeout == 0) {
|
|
Timeout = SERIAL_TIMEOUT_DEFAULT;
|
|
}
|
|
|
|
if (Parity == DefaultParity) {
|
|
Parity = (EFI_PARITY_TYPE) (PcdGet8 (PcdUartDefaultParity));
|
|
}
|
|
|
|
if (DataBits == 0) {
|
|
DataBits = PcdGet8 (PcdUartDefaultDataBits);
|
|
}
|
|
|
|
if (StopBits == DefaultStopBits) {
|
|
StopBits = (EFI_STOP_BITS_TYPE) PcdGet8 (PcdUartDefaultStopBits);
|
|
}
|
|
|
|
//
|
|
// Make sure all parameters are valid
|
|
//
|
|
if ((BaudRate > SERIAL_PORT_MAX_BAUD_RATE) || (BaudRate < SERIAL_PORT_MIN_BAUD_RATE)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
//The lower baud rate supported by the serial device will be selected without exceeding the unsupported BaudRate parameter
|
|
//
|
|
|
|
for (Index = 1; Index < (sizeof (mBaudRateCurrentSupport) / sizeof (mBaudRateCurrentSupport[0])); Index++) {
|
|
if (BaudRate < mBaudRateCurrentSupport[Index]) {
|
|
BaudRate = mBaudRateCurrentSupport[Index-1];
|
|
break;
|
|
}
|
|
}
|
|
|
|
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 ((StopBits < OneStopBit) || (StopBits > TwoStopBits)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Now we only support DataBits=7,8.
|
|
//
|
|
if ((DataBits < 7) || (DataBits > 8)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Now we only support DataBits=7,8.
|
|
// for DataBits = 6,7,8, StopBits can not set OneFiveStopBits.
|
|
//
|
|
if (StopBits == OneFiveStopBits) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// See if the new attributes already match the current attributes
|
|
//
|
|
if (Private->UartDevicePath.BaudRate == BaudRate &&
|
|
Private->UartDevicePath.DataBits == DataBits &&
|
|
Private->UartDevicePath.Parity == Parity &&
|
|
Private->UartDevicePath.StopBits == StopBits &&
|
|
Private->SerialIoMode.ReceiveFifoDepth == ReceiveFifoDepth &&
|
|
Private->SerialIoMode.Timeout == Timeout ) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
Tpl = gBS->RaiseTPL (TPL_NOTIFY);
|
|
|
|
//
|
|
// Get current values from NT
|
|
//
|
|
ZeroMem (&Private->NtDCB, sizeof (DCB));
|
|
Private->NtDCB.DCBlength = sizeof (DCB);
|
|
|
|
if (!Private->WinNtThunk->GetCommState (Private->NtHandle, &Private->NtDCB)) {
|
|
Private->NtError = Private->WinNtThunk->GetLastError ();
|
|
DEBUG ((EFI_D_ERROR, "SerialSetAttributes: GetCommState %d\n", Private->NtError));
|
|
gBS->RestoreTPL (Tpl);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
//
|
|
// Map EFI com setting to NT
|
|
//
|
|
Private->NtDCB.BaudRate = ConvertBaud2Nt (BaudRate);
|
|
Private->NtDCB.ByteSize = ConvertData2Nt (DataBits);
|
|
Private->NtDCB.Parity = ConvertParity2Nt (Parity);
|
|
Private->NtDCB.StopBits = ConvertStop2Nt (StopBits);
|
|
|
|
Private->NtDCB.fBinary = TRUE;
|
|
Private->NtDCB.fParity = Private->NtDCB.Parity == NOPARITY ? FALSE : TRUE;
|
|
Private->NtDCB.fOutxCtsFlow = FALSE;
|
|
Private->NtDCB.fOutxDsrFlow = FALSE;
|
|
Private->NtDCB.fDtrControl = DTR_CONTROL_ENABLE;
|
|
Private->NtDCB.fDsrSensitivity = FALSE;
|
|
Private->NtDCB.fOutX = FALSE;
|
|
Private->NtDCB.fInX = FALSE;
|
|
Private->NtDCB.fRtsControl = RTS_CONTROL_ENABLE;
|
|
Private->NtDCB.fNull = FALSE;
|
|
|
|
//
|
|
// Set new values
|
|
//
|
|
Result = Private->WinNtThunk->SetCommState (Private->NtHandle, &Private->NtDCB);
|
|
if (!Result) {
|
|
Private->NtError = Private->WinNtThunk->GetLastError ();
|
|
DEBUG ((EFI_D_ERROR, "SerialSetAttributes: SetCommState %d\n", Private->NtError));
|
|
gBS->RestoreTPL (Tpl);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
//
|
|
// Set com port read/write timeout values
|
|
//
|
|
ConvertedTime = ConvertTime2Nt (Timeout);
|
|
PortTimeOuts.ReadIntervalTimeout = MAXDWORD;
|
|
PortTimeOuts.ReadTotalTimeoutMultiplier = 0;
|
|
PortTimeOuts.ReadTotalTimeoutConstant = ConvertedTime;
|
|
PortTimeOuts.WriteTotalTimeoutMultiplier = ConvertedTime == 0 ? 1 : ConvertedTime;
|
|
PortTimeOuts.WriteTotalTimeoutConstant = 0;
|
|
|
|
if (!Private->WinNtThunk->SetCommTimeouts (Private->NtHandle, &PortTimeOuts)) {
|
|
Private->NtError = Private->WinNtThunk->GetLastError ();
|
|
DEBUG ((EFI_D_ERROR, "SerialSetAttributes: SetCommTimeouts %d\n", Private->NtError));
|
|
gBS->RestoreTPL (Tpl);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
//
|
|
// Update mode
|
|
//
|
|
Private->SerialIoMode.BaudRate = BaudRate;
|
|
Private->SerialIoMode.ReceiveFifoDepth = ReceiveFifoDepth;
|
|
Private->SerialIoMode.Timeout = Timeout;
|
|
Private->SerialIoMode.Parity = Parity;
|
|
Private->SerialIoMode.DataBits = DataBits;
|
|
Private->SerialIoMode.StopBits = StopBits;
|
|
|
|
//
|
|
// See if Device Path Node has actually changed
|
|
//
|
|
if (Private->UartDevicePath.BaudRate == BaudRate &&
|
|
Private->UartDevicePath.DataBits == DataBits &&
|
|
Private->UartDevicePath.Parity == Parity &&
|
|
Private->UartDevicePath.StopBits == StopBits ) {
|
|
gBS->RestoreTPL(Tpl);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Update the device path
|
|
//
|
|
Private->UartDevicePath.BaudRate = BaudRate;
|
|
Private->UartDevicePath.DataBits = DataBits;
|
|
Private->UartDevicePath.Parity = (UINT8) Parity;
|
|
Private->UartDevicePath.StopBits = (UINT8) StopBits;
|
|
|
|
Status = EFI_SUCCESS;
|
|
if (Private->Handle != NULL) {
|
|
Uart = (UART_DEVICE_PATH *) (
|
|
(UINTN) Private->DevicePath
|
|
+ GetDevicePathSize (Private->ParentDevicePath)
|
|
- END_DEVICE_PATH_LENGTH
|
|
);
|
|
CopyMem (Uart, &Private->UartDevicePath, sizeof (UART_DEVICE_PATH));
|
|
Status = gBS->ReinstallProtocolInterface (
|
|
Private->Handle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
Private->DevicePath,
|
|
Private->DevicePath
|
|
);
|
|
}
|
|
|
|
gBS->RestoreTPL (Tpl);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WinNtSerialIoSetControl (
|
|
IN EFI_SERIAL_IO_PROTOCOL *This,
|
|
IN UINT32 Control
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
This - TODO: add argument description
|
|
Control - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
|
|
BOOL Result;
|
|
DCB Dcb;
|
|
EFI_TPL Tpl;
|
|
UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// first determine the parameter is invalid
|
|
//
|
|
if (Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
|
|
EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
|
|
EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Tpl = gBS->RaiseTPL (TPL_NOTIFY);
|
|
|
|
Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
Result = Private->WinNtThunk->GetCommState (Private->NtHandle, &Dcb);
|
|
|
|
if (!Result) {
|
|
Private->NtError = Private->WinNtThunk->GetLastError ();
|
|
DEBUG ((EFI_D_ERROR, "SerialSetControl: GetCommState %d\n", Private->NtError));
|
|
gBS->RestoreTPL (Tpl);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
|
Dcb.fDtrControl = DTR_CONTROL_DISABLE;
|
|
Private->HardwareFlowControl = FALSE;
|
|
Private->SoftwareLoopbackEnable = FALSE;
|
|
Private->HardwareLoopbackEnable = FALSE;
|
|
|
|
if (Control & EFI_SERIAL_REQUEST_TO_SEND) {
|
|
Dcb.fRtsControl = RTS_CONTROL_ENABLE;
|
|
}
|
|
|
|
if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {
|
|
Dcb.fDtrControl = DTR_CONTROL_ENABLE;
|
|
}
|
|
|
|
if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
|
|
Private->HardwareFlowControl = TRUE;
|
|
}
|
|
|
|
if (Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
|
|
Private->SoftwareLoopbackEnable = TRUE;
|
|
}
|
|
|
|
if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
|
|
Private->HardwareLoopbackEnable = TRUE;
|
|
}
|
|
|
|
Result = Private->WinNtThunk->SetCommState (
|
|
Private->NtHandle,
|
|
&Dcb
|
|
);
|
|
|
|
if (!Result) {
|
|
Private->NtError = Private->WinNtThunk->GetLastError ();
|
|
DEBUG ((EFI_D_ERROR, "SerialSetControl: SetCommState %d\n", Private->NtError));
|
|
gBS->RestoreTPL (Tpl);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Status = EFI_SUCCESS;
|
|
if (Private->Handle != NULL) {
|
|
FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) (
|
|
(UINTN) Private->DevicePath
|
|
+ GetDevicePathSize (Private->ParentDevicePath)
|
|
- END_DEVICE_PATH_LENGTH
|
|
+ sizeof (UART_DEVICE_PATH)
|
|
);
|
|
if (IsUartFlowControlNode (FlowControl) &&
|
|
((FlowControl->FlowControlMap == UART_FLOW_CONTROL_HARDWARE) ^ Private->HardwareFlowControl)) {
|
|
//
|
|
// Flow Control setting is changed, need to reinstall device path protocol
|
|
//
|
|
FlowControl->FlowControlMap = Private->HardwareFlowControl ? UART_FLOW_CONTROL_HARDWARE : 0;
|
|
Status = gBS->ReinstallProtocolInterface (
|
|
Private->Handle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
Private->DevicePath,
|
|
Private->DevicePath
|
|
);
|
|
}
|
|
}
|
|
|
|
gBS->RestoreTPL (Tpl);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WinNtSerialIoGetControl (
|
|
IN EFI_SERIAL_IO_PROTOCOL *This,
|
|
OUT UINT32 *Control
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
This - TODO: add argument description
|
|
Control - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
|
|
DWORD ModemStatus;
|
|
DWORD Errors;
|
|
UINT32 Bits;
|
|
DCB Dcb;
|
|
EFI_TPL Tpl;
|
|
|
|
Tpl = gBS->RaiseTPL (TPL_NOTIFY);
|
|
|
|
Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
//
|
|
// Get modem status
|
|
//
|
|
if (!Private->WinNtThunk->GetCommModemStatus (Private->NtHandle, &ModemStatus)) {
|
|
Private->NtError = Private->WinNtThunk->GetLastError ();
|
|
gBS->RestoreTPL (Tpl);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Bits = 0;
|
|
if (ModemStatus & MS_CTS_ON) {
|
|
Bits |= EFI_SERIAL_CLEAR_TO_SEND;
|
|
}
|
|
|
|
if (ModemStatus & MS_DSR_ON) {
|
|
Bits |= EFI_SERIAL_DATA_SET_READY;
|
|
}
|
|
|
|
if (ModemStatus & MS_RING_ON) {
|
|
Bits |= EFI_SERIAL_RING_INDICATE;
|
|
}
|
|
|
|
if (ModemStatus & MS_RLSD_ON) {
|
|
Bits |= EFI_SERIAL_CARRIER_DETECT;
|
|
}
|
|
|
|
//
|
|
// Get ctrl status
|
|
//
|
|
if (!Private->WinNtThunk->GetCommState (Private->NtHandle, &Dcb)) {
|
|
Private->NtError = Private->WinNtThunk->GetLastError ();
|
|
DEBUG ((EFI_D_ERROR, "SerialGetControl: GetCommState %d\n", Private->NtError));
|
|
gBS->RestoreTPL (Tpl);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
if (Dcb.fDtrControl == DTR_CONTROL_ENABLE) {
|
|
Bits |= EFI_SERIAL_DATA_TERMINAL_READY;
|
|
}
|
|
|
|
if (Dcb.fRtsControl == RTS_CONTROL_ENABLE) {
|
|
Bits |= EFI_SERIAL_REQUEST_TO_SEND;
|
|
}
|
|
|
|
if (Private->HardwareFlowControl) {
|
|
Bits |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
|
|
}
|
|
|
|
if (Private->SoftwareLoopbackEnable) {
|
|
Bits |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
|
|
}
|
|
|
|
if (Private->HardwareLoopbackEnable) {
|
|
Bits |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
|
|
}
|
|
|
|
//
|
|
// Get input buffer status
|
|
//
|
|
if (!Private->WinNtThunk->ClearCommError (Private->NtHandle, &Errors, &Private->NtComStatus)) {
|
|
Private->NtError = Private->WinNtThunk->GetLastError ();
|
|
DEBUG ((EFI_D_ERROR, "SerialGetControl: ClearCommError %d\n", Private->NtError));
|
|
gBS->RestoreTPL (Tpl);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
if (Private->NtComStatus.cbInQue == 0) {
|
|
Bits |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
|
|
}
|
|
|
|
*Control = Bits;
|
|
|
|
gBS->RestoreTPL (Tpl);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WinNtSerialIoWrite (
|
|
IN EFI_SERIAL_IO_PROTOCOL *This,
|
|
IN OUT UINTN *BufferSize,
|
|
IN VOID *Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
This - TODO: add argument description
|
|
BufferSize - TODO: add argument description
|
|
Buffer - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
|
|
UINT8 *ByteBuffer;
|
|
UINTN TotalBytesWritten;
|
|
DWORD BytesToGo;
|
|
DWORD BytesWritten;
|
|
BOOL Result;
|
|
UINT32 Index;
|
|
UINT32 Control;
|
|
EFI_TPL Tpl;
|
|
|
|
Tpl = gBS->RaiseTPL (TPL_NOTIFY);
|
|
|
|
Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
ByteBuffer = (UINT8 *) Buffer;
|
|
TotalBytesWritten = 0;
|
|
|
|
if (Private->SoftwareLoopbackEnable || Private->HardwareLoopbackEnable) {
|
|
for (Index = 0; Index < *BufferSize; Index++) {
|
|
if (IsaSerialFifoAdd (&Private->Fifo, ByteBuffer[Index]) == EFI_SUCCESS) {
|
|
TotalBytesWritten++;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
BytesToGo = (DWORD) (*BufferSize);
|
|
|
|
do {
|
|
if (Private->HardwareFlowControl) {
|
|
//
|
|
// Send RTS
|
|
//
|
|
WinNtSerialIoGetControl (&Private->SerialIo, &Control);
|
|
Control |= EFI_SERIAL_REQUEST_TO_SEND;
|
|
WinNtSerialIoSetControl (&Private->SerialIo, Control);
|
|
}
|
|
|
|
//
|
|
// Do the write
|
|
//
|
|
Result = Private->WinNtThunk->WriteFile (
|
|
Private->NtHandle,
|
|
&ByteBuffer[TotalBytesWritten],
|
|
BytesToGo,
|
|
&BytesWritten,
|
|
NULL
|
|
);
|
|
|
|
if (Private->HardwareFlowControl) {
|
|
//
|
|
// Assert RTS
|
|
//
|
|
WinNtSerialIoGetControl (&Private->SerialIo, &Control);
|
|
Control &= ~ (UINT32) EFI_SERIAL_REQUEST_TO_SEND;
|
|
WinNtSerialIoSetControl (&Private->SerialIo, Control);
|
|
}
|
|
|
|
TotalBytesWritten += BytesWritten;
|
|
BytesToGo -= BytesWritten;
|
|
if (!Result) {
|
|
Private->NtError = Private->WinNtThunk->GetLastError ();
|
|
DEBUG ((EFI_D_ERROR, "SerialWrite: FileWrite %d\n", Private->NtError));
|
|
*BufferSize = TotalBytesWritten;
|
|
gBS->RestoreTPL (Tpl);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
} while (BytesToGo > 0);
|
|
}
|
|
|
|
*BufferSize = TotalBytesWritten;
|
|
|
|
gBS->RestoreTPL (Tpl);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WinNtSerialIoRead (
|
|
IN EFI_SERIAL_IO_PROTOCOL *This,
|
|
IN OUT UINTN *BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
This - TODO: add argument description
|
|
BufferSize - TODO: add argument description
|
|
Buffer - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
|
|
BOOL Result;
|
|
DWORD BytesRead;
|
|
EFI_STATUS Status;
|
|
UINT32 Index;
|
|
UINT8 Data;
|
|
UINT32 Control;
|
|
EFI_TPL Tpl;
|
|
|
|
Tpl = gBS->RaiseTPL (TPL_NOTIFY);
|
|
|
|
Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
//
|
|
// Do the read
|
|
//
|
|
if (Private->SoftwareLoopbackEnable || Private->HardwareLoopbackEnable) {
|
|
for (Index = 0, BytesRead = 0; Index < *BufferSize; Index++) {
|
|
if (IsaSerialFifoRemove (&Private->Fifo, &Data) == EFI_SUCCESS) {
|
|
((UINT8 *) Buffer)[Index] = Data;
|
|
BytesRead++;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if (Private->HardwareFlowControl) {
|
|
WinNtSerialIoGetControl (&Private->SerialIo, &Control);
|
|
Control |= EFI_SERIAL_DATA_TERMINAL_READY;
|
|
WinNtSerialIoSetControl (&Private->SerialIo, Control);
|
|
}
|
|
|
|
Result = Private->WinNtThunk->ReadFile (
|
|
Private->NtHandle,
|
|
Buffer,
|
|
(DWORD) *BufferSize,
|
|
&BytesRead,
|
|
NULL
|
|
);
|
|
|
|
if (Private->HardwareFlowControl) {
|
|
WinNtSerialIoGetControl (&Private->SerialIo, &Control);
|
|
Control &= ~ (UINT32) EFI_SERIAL_DATA_TERMINAL_READY;
|
|
WinNtSerialIoSetControl (&Private->SerialIo, Control);
|
|
}
|
|
|
|
if (!Result) {
|
|
Private->NtError = Private->WinNtThunk->GetLastError ();
|
|
gBS->RestoreTPL (Tpl);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
}
|
|
|
|
if (BytesRead != *BufferSize) {
|
|
Status = EFI_TIMEOUT;
|
|
} else {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
|
|
*BufferSize = (UINTN) BytesRead;
|
|
|
|
gBS->RestoreTPL (Tpl);
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
IsaSerialFifoFull (
|
|
IN SERIAL_DEV_FIFO *Fifo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Detect whether specific FIFO is full or not
|
|
|
|
Arguments:
|
|
Fifo SERIAL_DEV_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 SERIAL_DEV_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 SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
|
|
Data UINT8: the data added to FIFO
|
|
|
|
Returns:
|
|
EFI_SUCCESS: Add data to specific FIFO successfully
|
|
EFI_OUT_RESOURCE: Failed to add data because FIFO is already full
|
|
|
|
--*/
|
|
// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
|
|
{
|
|
//
|
|
// 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 SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
|
|
Data UINT8*: the data removed from FIFO
|
|
|
|
Returns:
|
|
EFI_SUCCESS: Remove data from specific FIFO successfully
|
|
EFI_OUT_RESOURCE: Failed to remove data because FIFO is empty
|
|
|
|
--*/
|
|
// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
|
|
{
|
|
//
|
|
// 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;
|
|
}
|