mirror of https://github.com/acidanthera/audk.git
2587 lines
80 KiB
C
2587 lines
80 KiB
C
/** @file
|
|
USB Serial Driver that manages USB to Serial and produces Serial IO Protocol.
|
|
|
|
Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.
|
|
Portions Copyright 2012 Ashley DeSimone
|
|
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.
|
|
|
|
**/
|
|
|
|
//
|
|
|
|
// Tested with VEND_ID 0x0403, DEVICE_ID 0x6001
|
|
//
|
|
// Driver starts the device with the following values:
|
|
// 115200, No parity, 8 data bits, 1 stop bit, No Flow control
|
|
//
|
|
|
|
#include "FtdiUsbSerialDriver.h"
|
|
|
|
//
|
|
// Table of supported devices. This is the device information that this
|
|
// driver was developed with. Add other FTDI devices as needed.
|
|
//
|
|
USB_DEVICE gUSBDeviceList[] = {
|
|
{VID_FTDI, DID_FTDI_FT232},
|
|
{0,0}
|
|
};
|
|
|
|
//
|
|
// USB Serial Driver Global Variables
|
|
//
|
|
EFI_DRIVER_BINDING_PROTOCOL gUsbSerialDriverBinding = {
|
|
UsbSerialDriverBindingSupported,
|
|
UsbSerialDriverBindingStart,
|
|
UsbSerialDriverBindingStop,
|
|
0xa,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
//
|
|
// Table with the nearest power of 2 for the numbers 0-15
|
|
//
|
|
UINT8 gRoundedPowersOf2[16] = { 0, 2, 2, 4, 4, 4, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16 };
|
|
|
|
/**
|
|
Check to see if the device path node is the Flow control node
|
|
|
|
@param[in] FlowControl The device path node to be checked
|
|
|
|
@retval TRUE It is the flow control node
|
|
@retval FALSE It is not the flow control node
|
|
|
|
**/
|
|
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))
|
|
);
|
|
}
|
|
|
|
/**
|
|
Checks the device path to see if it contains flow control.
|
|
|
|
@param[in] DevicePath The device path to be checked
|
|
|
|
@retval TRUE It contains flow control
|
|
@retval FALSE It does not contain flow control
|
|
|
|
**/
|
|
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;
|
|
}
|
|
|
|
/**
|
|
Transfer the data between the device and host.
|
|
|
|
This function transfers the data between the device and host.
|
|
BOT transfer is composed of three phases: Command, Data, and Status.
|
|
This is the Data phase.
|
|
|
|
@param UsbBot[in] The USB BOT device
|
|
@param DataDir[in] The direction of the data
|
|
@param Data[in, out] The buffer to hold data
|
|
@param TransLen[in, out] The expected length of the data
|
|
@param Timeout[in] The time to wait the command to complete
|
|
|
|
@retval EFI_SUCCESS The data is transferred
|
|
@retval EFI_SUCCESS No data to transfer
|
|
@retval EFI_NOT_READY The device return NAK to the transfer
|
|
@retval Others Failed to transfer data
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UsbSerialDataTransfer (
|
|
IN USB_SER_DEV *UsbBot,
|
|
IN EFI_USB_DATA_DIRECTION DataDir,
|
|
IN OUT VOID *Data,
|
|
IN OUT UINTN *TransLen,
|
|
IN UINT32 Timeout
|
|
)
|
|
{
|
|
EFI_USB_ENDPOINT_DESCRIPTOR *Endpoint;
|
|
EFI_STATUS Status;
|
|
UINT32 Result;
|
|
|
|
//
|
|
// If no data to transfer, just return EFI_SUCCESS.
|
|
//
|
|
if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Select the endpoint then issue the transfer
|
|
//
|
|
if (DataDir == EfiUsbDataIn) {
|
|
Endpoint = &UsbBot->InEndpointDescriptor;
|
|
} else {
|
|
Endpoint = &UsbBot->OutEndpointDescriptor;
|
|
}
|
|
|
|
Result = 0;
|
|
Status = UsbBot->UsbIo->UsbBulkTransfer (
|
|
UsbBot->UsbIo,
|
|
Endpoint->EndpointAddress,
|
|
Data,
|
|
TransLen,
|
|
Timeout,
|
|
&Result
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) {
|
|
Status = EFI_NOT_READY;
|
|
} else {
|
|
UsbBot->Shutdown = TRUE; // Fixes infinite loop in older EFI
|
|
}
|
|
return Status;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Sets the status values of the Usb Serial Device.
|
|
|
|
@param UsbSerialDevice[in] Handle to the Usb Serial Device to set the status
|
|
for
|
|
@param StatusBuffer[in] Buffer holding the status values
|
|
|
|
@retval EFI_SUCCESS The status values were read and set correctly
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetStatusInternal (
|
|
IN USB_SER_DEV *UsbSerialDevice,
|
|
IN UINT8 *StatusBuffer
|
|
)
|
|
{
|
|
UINT8 Msr;
|
|
|
|
Msr = (StatusBuffer[0] & MSR_MASK);
|
|
|
|
//
|
|
// set the Status values to disabled
|
|
//
|
|
UsbSerialDevice->StatusValues.CtsState = FALSE;
|
|
UsbSerialDevice->StatusValues.DsrState = FALSE;
|
|
UsbSerialDevice->StatusValues.RiState = FALSE;
|
|
UsbSerialDevice->StatusValues.SdState = FALSE;
|
|
|
|
//
|
|
// Check the values from the status buffer and set the appropriate status
|
|
// values to enabled
|
|
//
|
|
if ((Msr & CTS_MASK) == CTS_MASK) {
|
|
UsbSerialDevice->StatusValues.CtsState = TRUE;
|
|
}
|
|
if ((Msr & DSR_MASK) == DSR_MASK) {
|
|
UsbSerialDevice->StatusValues.DsrState = TRUE;
|
|
}
|
|
if ((Msr & RI_MASK) == RI_MASK) {
|
|
UsbSerialDevice->StatusValues.RiState = TRUE;
|
|
}
|
|
if ((Msr & SD_MASK) == SD_MASK) {
|
|
UsbSerialDevice->StatusValues.SdState = TRUE;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Initiates a read operation on the Usb Serial Device.
|
|
|
|
@param UsbSerialDevice[in] Handle to the USB device to read
|
|
@param BufferSize[in, out] On input, the size of the Buffer. On output,
|
|
the amount of data returned in Buffer.
|
|
Setting this to zero will initiate a read
|
|
and store all data returned in the internal
|
|
buffer.
|
|
@param Buffer [out] The buffer to return the data into.
|
|
|
|
@retval EFI_SUCCESS The data was read.
|
|
@retval EFI_DEVICE_ERROR The device reported an error.
|
|
@retval EFI_TIMEOUT The data write was stopped due to a timeout.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ReadDataFromUsb (
|
|
IN USB_SER_DEV *UsbSerialDevice,
|
|
IN OUT UINTN *BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN ReadBufferSize;
|
|
UINT8 *ReadBuffer;
|
|
UINTN Index;
|
|
EFI_TPL Tpl;
|
|
UINT8 StatusBuffer[2]; // buffer to store the status bytes
|
|
|
|
ReadBufferSize = 512;
|
|
ReadBuffer = &(UsbSerialDevice->ReadBuffer[0]);
|
|
|
|
if (UsbSerialDevice->Shutdown) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Tpl = gBS->RaiseTPL (TPL_NOTIFY);
|
|
|
|
Status = UsbSerialDataTransfer (
|
|
UsbSerialDevice,
|
|
EfiUsbDataIn,
|
|
ReadBuffer,
|
|
&ReadBufferSize,
|
|
FTDI_TIMEOUT*2 //Padded because timers won't be exactly aligned
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->RestoreTPL (Tpl);
|
|
if (Status == EFI_TIMEOUT) {
|
|
return EFI_TIMEOUT;
|
|
} else {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Store the status bytes in the status buffer
|
|
//
|
|
for (Index = 0; Index < 2; Index++) {//only the first 2 bytes are status bytes
|
|
StatusBuffer[Index] = ReadBuffer[Index];
|
|
}
|
|
//
|
|
// update the statusvalue field of the usbserialdevice
|
|
//
|
|
Status = SetStatusInternal (UsbSerialDevice, StatusBuffer);
|
|
if (Status != EFI_SUCCESS) {
|
|
}
|
|
|
|
//
|
|
// Store the read data in the read buffer, start at 2 to ignore status bytes
|
|
//
|
|
for (Index = 2; Index < ReadBufferSize; Index++) {
|
|
if (((UsbSerialDevice->DataBufferTail + 1) % SW_FIFO_DEPTH) == UsbSerialDevice->DataBufferHead) {
|
|
break;
|
|
}
|
|
if (ReadBuffer[Index] == 0x00) {
|
|
//
|
|
// This is null, do not add
|
|
//
|
|
} else {
|
|
UsbSerialDevice->DataBuffer[UsbSerialDevice->DataBufferTail] = ReadBuffer[Index];
|
|
UsbSerialDevice->DataBufferTail = (UsbSerialDevice->DataBufferTail + 1) % SW_FIFO_DEPTH;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Read characters out of the buffer to satisfy caller's request.
|
|
//
|
|
for (Index = 0; Index < *BufferSize; Index++) {
|
|
if (UsbSerialDevice->DataBufferHead == UsbSerialDevice->DataBufferTail) {
|
|
break;
|
|
}
|
|
//
|
|
// Still have characters in the buffer to return
|
|
//
|
|
((UINT8 *)Buffer)[Index] = UsbSerialDevice->DataBuffer[UsbSerialDevice->DataBufferHead];
|
|
UsbSerialDevice->DataBufferHead = (UsbSerialDevice->DataBufferHead + 1) % SW_FIFO_DEPTH;
|
|
}
|
|
//
|
|
// Return actual number of bytes returned.
|
|
//
|
|
*BufferSize = Index;
|
|
gBS->RestoreTPL (Tpl);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Sets the initial status values of the Usb Serial Device by reading the status
|
|
bytes from the device.
|
|
|
|
@param UsbSerialDevice[in] Handle to the Usb Serial Device that needs its
|
|
initial status values set
|
|
|
|
@retval EFI_SUCCESS The status bytes were read successfully and the
|
|
initial status values were set correctly
|
|
@retval EFI_TIMEOUT The read of the status bytes was stopped due to a
|
|
timeout
|
|
@retval EFI_DEVICE_ERROR The device reported an error during the read of
|
|
the status bytes
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetInitialStatus (
|
|
IN USB_SER_DEV *UsbSerialDevice
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN BufferSize;
|
|
EFI_TPL Tpl;
|
|
UINT8 StatusBuffer[2];
|
|
|
|
Status = EFI_UNSUPPORTED;
|
|
BufferSize = sizeof (StatusBuffer);
|
|
|
|
if (UsbSerialDevice->Shutdown) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Tpl = gBS->RaiseTPL (TPL_NOTIFY);
|
|
|
|
Status = UsbSerialDataTransfer (
|
|
UsbSerialDevice,
|
|
EfiUsbDataIn,
|
|
StatusBuffer,
|
|
&BufferSize,
|
|
40 //Slightly more than 2x the FTDI polling frequency to make sure that data will be returned
|
|
);
|
|
|
|
Status = SetStatusInternal (UsbSerialDevice, StatusBuffer);
|
|
|
|
gBS->RestoreTPL (Tpl);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
UsbSerialDriverCheckInput.
|
|
attempts to read data in from the device periodically, stores any read data
|
|
and updates the control attributes.
|
|
|
|
@param Event[in]
|
|
@param Context[in]....The current instance of the USB serial device
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
UsbSerialDriverCheckInput (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
UINTN BufferSize;
|
|
USB_SER_DEV *UsbSerialDevice;
|
|
|
|
UsbSerialDevice = (USB_SER_DEV*)Context;
|
|
|
|
if (UsbSerialDevice->DataBufferHead == UsbSerialDevice->DataBufferTail) {
|
|
//
|
|
// Data buffer is empty, try to read from device
|
|
//
|
|
BufferSize = 0;
|
|
ReadDataFromUsb (UsbSerialDevice, &BufferSize, NULL);
|
|
if (UsbSerialDevice->DataBufferHead == UsbSerialDevice->DataBufferTail) {
|
|
//
|
|
// Data buffer still has no data, set the EFI_SERIAL_INPUT_BUFFER_EMPTY
|
|
// flag
|
|
//
|
|
UsbSerialDevice->ControlBits |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
|
|
} else {
|
|
//
|
|
// Read has returned some data, clear the EFI_SERIAL_INPUT_BUFFER_EMPTY
|
|
// flag
|
|
//
|
|
UsbSerialDevice->ControlBits &= ~(EFI_SERIAL_INPUT_BUFFER_EMPTY);
|
|
}
|
|
} else {
|
|
//
|
|
// Data buffer has data, no read attempt required
|
|
//
|
|
UsbSerialDevice->ControlBits &= ~(EFI_SERIAL_INPUT_BUFFER_EMPTY);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Encodes the baud rate into the format expected by the Ftdi device.
|
|
|
|
@param BaudRate[in] The baudrate to be set on the device
|
|
@param EncodedBaudRate[out] The baud rate encoded in the format
|
|
expected by the Ftdi device
|
|
|
|
@return EFI_SUCCESS Baudrate encoding was calculated
|
|
successfully
|
|
@return EFI_INVALID_PARAMETER An invalid value of BaudRate was received
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EncodeBaudRateForFtdi (
|
|
IN UINT64 BaudRate,
|
|
OUT UINT16 *EncodedBaudRate
|
|
)
|
|
{
|
|
UINT32 Divisor;
|
|
UINT32 AdjustedFrequency;
|
|
UINT16 Result;
|
|
|
|
//
|
|
// Check to make sure we won't get an integer overflow
|
|
//
|
|
if ((BaudRate < 178) || ( BaudRate > ((FTDI_UART_FREQUENCY * 100) / 97))) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Baud Rates of 2000000 and 3000000 are special cases
|
|
//
|
|
if ((BaudRate >= FTDI_SPECIAL_CASE_300_MIN) && (BaudRate <= FTDI_SPECIAL_CASE_300_MAX)) {
|
|
*EncodedBaudRate = 0;
|
|
return EFI_SUCCESS;
|
|
}
|
|
if ((BaudRate >= FTDI_SPECIAL_CASE_200_MIN) && (BaudRate <= FTDI_SPECIAL_CASE_200_MAX)) {
|
|
*EncodedBaudRate = 1;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Compute divisor
|
|
//
|
|
Divisor = (FTDI_UART_FREQUENCY << 4) / (UINT32)BaudRate;
|
|
|
|
//
|
|
// Round the last 4 bits to the nearest power of 2
|
|
//
|
|
Divisor = (Divisor & ~(0xF)) + (gRoundedPowersOf2[Divisor & 0xF]);
|
|
|
|
//
|
|
// Check to make sure computed divisor is within
|
|
// the min and max that FTDI controller will accept
|
|
//
|
|
if (Divisor < FTDI_MIN_DIVISOR) {
|
|
Divisor = FTDI_MIN_DIVISOR;
|
|
} else if (Divisor > FTDI_MAX_DIVISOR) {
|
|
Divisor = FTDI_MAX_DIVISOR;
|
|
}
|
|
|
|
//
|
|
// Check to make sure the frequency that the FTDI chip will need to
|
|
// generate to attain the requested Baud Rate is within 3% of the
|
|
// 3MHz clock frequency that the FTDI chip runs at.
|
|
//
|
|
// (3MHz * 1600) / 103 = 46601941
|
|
// (3MHz * 1600) / 97 = 49484536
|
|
//
|
|
AdjustedFrequency = (((UINT32)BaudRate) * Divisor);
|
|
if ((AdjustedFrequency < FTDI_MIN_FREQUENCY) || (AdjustedFrequency > FTDI_MAX_FREQUENCY)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Encode the Divisor into the format FTDI expects
|
|
//
|
|
Result = (UINT16)(Divisor >> 4);
|
|
if ((Divisor & 0x8) != 0) {
|
|
Result |= 0x4000;
|
|
} else if ((Divisor & 0x4) != 0) {
|
|
Result |= 0x8000;
|
|
} else if ((Divisor & 0x2) != 0) {
|
|
Result |= 0xC000;
|
|
}
|
|
|
|
*EncodedBaudRate = Result;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Uses USB I/O to check whether the device is a USB Serial device.
|
|
|
|
@param UsbIo[in] Pointer to a USB I/O protocol instance.
|
|
|
|
@retval TRUE Device is a USB Serial device.
|
|
@retval FALSE Device is a not USB Serial device.
|
|
|
|
**/
|
|
BOOLEAN
|
|
IsUsbSerial (
|
|
IN EFI_USB_IO_PROTOCOL *UsbIo
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor;
|
|
CHAR16 *StrMfg;
|
|
BOOLEAN Found;
|
|
UINT32 Index;
|
|
|
|
//
|
|
// Get the default device descriptor
|
|
//
|
|
Status = UsbIo->UsbGetDeviceDescriptor (
|
|
UsbIo,
|
|
&DeviceDescriptor
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return FALSE;
|
|
}
|
|
|
|
Found = FALSE;
|
|
Index = 0;
|
|
while (gUSBDeviceList[Index].VendorId != 0 &&
|
|
gUSBDeviceList[Index].DeviceId != 0 &&
|
|
!Found ) {
|
|
if (DeviceDescriptor.IdProduct == gUSBDeviceList[Index].DeviceId &&
|
|
DeviceDescriptor.IdVendor == gUSBDeviceList[Index].VendorId ){
|
|
//
|
|
// Checks to see if a string descriptor can be pulled from the device in
|
|
// the selected language. If not False is returned indicating that this
|
|
// is not a Usb Serial Device that can be managegd by this driver
|
|
//
|
|
StrMfg = NULL;
|
|
Status = UsbIo->UsbGetStringDescriptor (
|
|
UsbIo,
|
|
USB_US_LANG_ID, // LANGID selector, should make this
|
|
// more robust to verify lang support
|
|
// for device
|
|
DeviceDescriptor.StrManufacturer,
|
|
&StrMfg
|
|
);
|
|
if (StrMfg != NULL) {
|
|
FreePool (StrMfg);
|
|
}
|
|
if (EFI_ERROR (Status)) {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
Index++;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Internal function that sets the Data Bits, Stop Bits and Parity values on the
|
|
Usb Serial Device with a single usb control transfer.
|
|
|
|
@param UsbIo[in] Usb Io Protocol instance pointer
|
|
@param DataBits[in] The data bits value to be set on the Usb
|
|
Serial Device
|
|
@param Parity[in] The parity type that will be set on the Usb
|
|
Serial Device
|
|
@param StopBits[in] The stop bits type that will be set on the
|
|
Usb Serial Device
|
|
@param LastSettings[in] A pointer to the Usb Serial Device's
|
|
PREVIOUS_ATTRIBUTES item
|
|
|
|
@retval EFI_SUCCESS The data items were correctly set on the
|
|
USB Serial Device
|
|
@retval EFI_INVALID_PARAMETER An invalid data parameter or an invalid
|
|
combination or parameters was used
|
|
@retval EFI_DEVICE_ERROR The device is not functioning correctly and
|
|
the data values were unable to be set
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetDataInternal (
|
|
IN EFI_USB_IO_PROTOCOL *UsbIo,
|
|
IN UINT8 DataBits,
|
|
IN EFI_PARITY_TYPE Parity,
|
|
IN EFI_STOP_BITS_TYPE StopBits,
|
|
IN PREVIOUS_ATTRIBUTES *LastSettings
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_USB_DEVICE_REQUEST DevReq;
|
|
UINT32 ReturnValue;
|
|
UINT8 ConfigurationValue;
|
|
|
|
//
|
|
// Since data bits settings of 6,7,8 cannot be set with a stop bits setting of
|
|
// 1.5 check to see if this happens when the values of last settings are used
|
|
//
|
|
if ((DataBits == 0) && (StopBits == OneFiveStopBits)) {
|
|
if ((LastSettings->DataBits == 6) || (LastSettings->DataBits == 7) || (LastSettings->DataBits == 8)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
} else if ((StopBits == DefaultStopBits) && ((DataBits == 6) || (DataBits == 7) || (DataBits == 8))) {
|
|
if (LastSettings->StopBits == OneFiveStopBits) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
} else if ((DataBits == 0) && (StopBits == DefaultStopBits)) {
|
|
if (LastSettings->StopBits == OneFiveStopBits) {
|
|
if ((LastSettings->DataBits == 6) || (LastSettings->DataBits == 7) || (LastSettings->DataBits == 8)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// set the DevReq.Value for the usb control transfer to the correct value
|
|
// based on the seleceted number of data bits if there is an invalid number of
|
|
// data bits requested return EFI_INVALID_PARAMETER
|
|
//
|
|
if (((DataBits < 5 ) || (DataBits > 8)) && (DataBits != 0)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (DataBits == 0) {
|
|
//
|
|
// use the value of LastDataBits
|
|
//
|
|
DevReq.Value = SET_DATA_BITS (LastSettings->DataBits);
|
|
} else {
|
|
//
|
|
// use the value of DataBits
|
|
//
|
|
DevReq.Value = SET_DATA_BITS (DataBits);
|
|
}
|
|
|
|
//
|
|
// Set Parity
|
|
//
|
|
if (Parity == DefaultParity) {
|
|
Parity = LastSettings->Parity;
|
|
}
|
|
|
|
if (Parity == NoParity) {
|
|
DevReq.Value |= SET_PARITY_NONE;
|
|
} else if (Parity == EvenParity) {
|
|
DevReq.Value |= SET_PARITY_EVEN;
|
|
} else if (Parity == OddParity){
|
|
DevReq.Value |= SET_PARITY_ODD;
|
|
} else if (Parity == MarkParity) {
|
|
DevReq.Value |= SET_PARITY_MARK;
|
|
} else if (Parity == SpaceParity) {
|
|
DevReq.Value |= SET_PARITY_SPACE;
|
|
}
|
|
|
|
//
|
|
// Set Stop Bits
|
|
//
|
|
if (StopBits == DefaultStopBits) {
|
|
StopBits = LastSettings->StopBits;
|
|
}
|
|
|
|
if (StopBits == OneStopBit) {
|
|
DevReq.Value |= SET_STOP_BITS_1;
|
|
} else if (StopBits == OneFiveStopBits) {
|
|
DevReq.Value |= SET_STOP_BITS_15;
|
|
} else if (StopBits == TwoStopBits) {
|
|
DevReq.Value |= SET_STOP_BITS_2;
|
|
}
|
|
|
|
//
|
|
// set the rest of the DevReq parameters and perform the usb control transfer
|
|
// to set the data bits on the device
|
|
//
|
|
DevReq.Request = FTDI_COMMAND_SET_DATA;
|
|
DevReq.RequestType = USB_REQ_TYPE_VENDOR;
|
|
DevReq.Index = FTDI_PORT_IDENTIFIER;
|
|
DevReq.Length = 0; // indicates that there is no data phase in this request
|
|
|
|
Status = UsbIo->UsbControlTransfer (
|
|
UsbIo,
|
|
&DevReq,
|
|
EfiUsbDataOut,
|
|
WDR_SHORT_TIMEOUT,
|
|
&ConfigurationValue,
|
|
1,
|
|
&ReturnValue
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto StatusError;
|
|
}
|
|
return Status;
|
|
|
|
StatusError:
|
|
if ((Status != EFI_INVALID_PARAMETER) || (Status != EFI_DEVICE_ERROR)) {
|
|
return EFI_DEVICE_ERROR;
|
|
} else {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Internal function that sets the baudrate on the Usb Serial Device.
|
|
|
|
@param UsbIo[in] Usb Io Protocol instance pointer
|
|
@param BaudRate[in] The baudrate value to be set on the device.
|
|
If this value is 0 the value of LastBaudRate
|
|
will be used instead
|
|
@param LastBaudRate[in] The baud rate value that was previously set
|
|
on the Usb Serial Device
|
|
|
|
@retval EFI_SUCCESS The baudrate was set succesfully
|
|
@retval EFI_INVALID_PARAMETER An invalid baudrate was used
|
|
@retval EFI_DEVICE_ERROR The device is not functioning correctly and
|
|
the baudrate was unable to be set
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetBaudRateInternal (
|
|
IN EFI_USB_IO_PROTOCOL *UsbIo,
|
|
IN UINT64 BaudRate,
|
|
IN UINT64 LastBaudRate
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_USB_DEVICE_REQUEST DevReq;
|
|
UINT32 ReturnValue;
|
|
UINT8 ConfigurationValue;
|
|
UINT16 EncodedBaudRate;
|
|
EFI_TPL Tpl;
|
|
|
|
Tpl = gBS->RaiseTPL(TPL_NOTIFY);
|
|
|
|
//
|
|
// set the value of DevReq.Value based on the value of BaudRate
|
|
// if 0 is selected as baud rate use the value of LastBaudRate
|
|
//
|
|
if (BaudRate == 0) {
|
|
Status = EncodeBaudRateForFtdi (LastBaudRate, &EncodedBaudRate);
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->RestoreTPL (Tpl);
|
|
//
|
|
// EncodeBaudRateForFtdi returns EFI_INVALID_PARAMETER when not
|
|
// succesfull
|
|
//
|
|
return Status;
|
|
}
|
|
DevReq.Value = EncodedBaudRate;
|
|
} else {
|
|
Status = EncodeBaudRateForFtdi (BaudRate, &EncodedBaudRate);
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->RestoreTPL (Tpl);
|
|
//
|
|
// EncodeBaudRateForFtdi returns EFI_INVALID_PARAMETER when not
|
|
// successfull
|
|
//
|
|
return Status;
|
|
}
|
|
DevReq.Value = EncodedBaudRate;
|
|
}
|
|
|
|
//
|
|
// set the remaining parameters of DevReq and perform the usb control transfer
|
|
// to set the device
|
|
//
|
|
DevReq.Request = FTDI_COMMAND_SET_BAUDRATE;
|
|
DevReq.RequestType = USB_REQ_TYPE_VENDOR;
|
|
DevReq.Index = FTDI_PORT_IDENTIFIER;
|
|
DevReq.Length = 0; // indicates that there is no data phase in this request
|
|
|
|
Status = UsbIo->UsbControlTransfer (
|
|
UsbIo,
|
|
&DevReq,
|
|
EfiUsbDataOut,
|
|
WDR_SHORT_TIMEOUT,
|
|
&ConfigurationValue,
|
|
1,
|
|
&ReturnValue
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto StatusError;
|
|
}
|
|
gBS->RestoreTPL (Tpl);
|
|
return Status;
|
|
|
|
StatusError:
|
|
gBS->RestoreTPL (Tpl);
|
|
if ((Status != EFI_INVALID_PARAMETER) || (Status != EFI_DEVICE_ERROR)) {
|
|
return EFI_DEVICE_ERROR;
|
|
} else {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,
|
|
data bits, and stop bits on a serial device.
|
|
|
|
@param UsbSerialDevice[in] Pointer to the current instance of the USB Serial
|
|
Device.
|
|
@param BaudRate[in] The requested baud rate. A BaudRate value of 0
|
|
will use the device's default interface speed.
|
|
@param ReveiveFifoDepth[in] The requested depth of the FIFO on the receive
|
|
side of the serial interface. A ReceiveFifoDepth
|
|
value of 0 will use the device's default FIFO
|
|
depth.
|
|
@param Timeout[in] The requested time out for a single character in
|
|
microseconds.This timeout applies to both the
|
|
transmit and receive side of the interface.A
|
|
Timeout value of 0 will use the device's default
|
|
time out value.
|
|
@param Parity[in] The type of parity to use on this serial device.
|
|
A Parity value of DefaultParity will use the
|
|
device's default parity value.
|
|
@param DataBits[in] The number of data bits to use on the serial
|
|
device. A DataBits value of 0 will use the
|
|
device's default data bit setting.
|
|
@param StopBits[in] The number of stop bits to use on this serial
|
|
device. A StopBits value of DefaultStopBits will
|
|
use the device's default number of stop bits.
|
|
|
|
@retval EFI_SUCCESS The attributes were set
|
|
@retval EFI_DEVICE_ERROR The attributes were not able to be set
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetAttributesInternal (
|
|
IN USB_SER_DEV *UsbSerialDevice,
|
|
IN UINT64 BaudRate,
|
|
IN UINT32 ReceiveFifoDepth,
|
|
IN UINT32 Timeout,
|
|
IN EFI_PARITY_TYPE Parity,
|
|
IN UINT8 DataBits,
|
|
IN EFI_STOP_BITS_TYPE StopBits
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_TPL Tpl;
|
|
UART_DEVICE_PATH *Uart;
|
|
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
|
|
|
|
Status = EFI_UNSUPPORTED;
|
|
Tpl = gBS->RaiseTPL(TPL_NOTIFY);
|
|
Uart = NULL;
|
|
|
|
//
|
|
// check for invalid combinations of parameters
|
|
//
|
|
if (((DataBits >= 6) && (DataBits <= 8)) && (StopBits == OneFiveStopBits)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// set data bits, parity and stop bits
|
|
//
|
|
Status = SetDataInternal (
|
|
UsbSerialDevice->UsbIo,
|
|
DataBits,
|
|
Parity,
|
|
StopBits,
|
|
&(UsbSerialDevice->LastSettings)
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto StatusError;
|
|
}
|
|
//
|
|
// set baudrate
|
|
//
|
|
Status = SetBaudRateInternal (
|
|
UsbSerialDevice->UsbIo,
|
|
BaudRate,
|
|
UsbSerialDevice->LastSettings.BaudRate
|
|
);
|
|
if (EFI_ERROR (Status)){
|
|
goto StatusError;
|
|
}
|
|
|
|
//
|
|
// update the values of UsbSerialDevice->LastSettings and UsbSerialDevice->SerialIo.Mode
|
|
//
|
|
if (BaudRate == 0) {
|
|
UsbSerialDevice->LastSettings.BaudRate = UsbSerialDevice->LastSettings.BaudRate;
|
|
UsbSerialDevice->SerialIo.Mode->BaudRate = UsbSerialDevice->LastSettings.BaudRate;
|
|
} else {
|
|
UsbSerialDevice->LastSettings.BaudRate = BaudRate;
|
|
UsbSerialDevice->SerialIo.Mode->BaudRate = BaudRate;
|
|
}
|
|
|
|
UsbSerialDevice->LastSettings.Timeout = FTDI_TIMEOUT;
|
|
UsbSerialDevice->LastSettings.ReceiveFifoDepth = FTDI_MAX_RECEIVE_FIFO_DEPTH;
|
|
|
|
if (Parity == DefaultParity) {
|
|
UsbSerialDevice->LastSettings.Parity = UsbSerialDevice->LastSettings.Parity;
|
|
UsbSerialDevice->SerialIo.Mode->Parity = UsbSerialDevice->LastSettings.Parity;
|
|
} else {
|
|
UsbSerialDevice->LastSettings.Parity = Parity;
|
|
UsbSerialDevice->SerialIo.Mode->Parity = Parity;
|
|
}
|
|
if (DataBits == 0) {
|
|
UsbSerialDevice->LastSettings.DataBits = UsbSerialDevice->LastSettings.DataBits;
|
|
UsbSerialDevice->SerialIo.Mode->DataBits = UsbSerialDevice->LastSettings.DataBits;
|
|
} else {
|
|
UsbSerialDevice->LastSettings.DataBits = DataBits;
|
|
UsbSerialDevice->SerialIo.Mode->DataBits = DataBits;
|
|
}
|
|
if (StopBits == DefaultStopBits) {
|
|
UsbSerialDevice->LastSettings.StopBits = UsbSerialDevice->LastSettings.StopBits;
|
|
UsbSerialDevice->SerialIo.Mode->StopBits = UsbSerialDevice->LastSettings.StopBits;
|
|
} else {
|
|
UsbSerialDevice->LastSettings.StopBits = StopBits;
|
|
UsbSerialDevice->SerialIo.Mode->StopBits = StopBits;
|
|
}
|
|
|
|
//
|
|
// See if the device path node has changed
|
|
//
|
|
if (UsbSerialDevice->UartDevicePath.BaudRate == BaudRate &&
|
|
UsbSerialDevice->UartDevicePath.DataBits == DataBits &&
|
|
UsbSerialDevice->UartDevicePath.StopBits == StopBits &&
|
|
UsbSerialDevice->UartDevicePath.Parity == Parity
|
|
) {
|
|
gBS->RestoreTPL (Tpl);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Update the device path
|
|
//
|
|
UsbSerialDevice->UartDevicePath.BaudRate = BaudRate;
|
|
UsbSerialDevice->UartDevicePath.DataBits = DataBits;
|
|
UsbSerialDevice->UartDevicePath.StopBits = (UINT8) StopBits;
|
|
UsbSerialDevice->UartDevicePath.Parity = (UINT8) Parity;
|
|
|
|
Status = EFI_SUCCESS;
|
|
if (UsbSerialDevice->ControllerHandle != NULL) {
|
|
RemainingDevicePath = UsbSerialDevice->DevicePath;
|
|
while (!IsDevicePathEnd (RemainingDevicePath)) {
|
|
Uart = (UART_DEVICE_PATH *) NextDevicePathNode (RemainingDevicePath);
|
|
if (Uart->Header.Type == MESSAGING_DEVICE_PATH &&
|
|
Uart->Header.SubType == MSG_UART_DP &&
|
|
sizeof (UART_DEVICE_PATH) == DevicePathNodeLength ((EFI_DEVICE_PATH *) Uart)) {
|
|
Uart->BaudRate = BaudRate;
|
|
Uart->DataBits = DataBits;
|
|
Uart->StopBits = (UINT8)StopBits;
|
|
Uart->Parity = (UINT8) Parity;
|
|
break;
|
|
}
|
|
RemainingDevicePath = NextDevicePathNode (RemainingDevicePath);
|
|
}
|
|
}
|
|
|
|
gBS->RestoreTPL (Tpl);
|
|
return Status;
|
|
|
|
StatusError:
|
|
gBS->RestoreTPL (Tpl);
|
|
if ((Status != EFI_INVALID_PARAMETER) || (Status != EFI_DEVICE_ERROR)) {
|
|
return EFI_DEVICE_ERROR;
|
|
} else {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Internal function that performs a Usb Control Transfer to set the flow control
|
|
on the Usb Serial Device.
|
|
|
|
@param UsbIo[in] Usb Io Protocol instance pointer
|
|
@param FlowControlEnable[in] Data on the Enable/Disable status of Flow
|
|
Control on the Usb Serial Device
|
|
|
|
@retval EFI_SUCCESS The flow control was set on the Usb Serial
|
|
device
|
|
@retval EFI_INVALID_PARAMETER An invalid flow control value was used
|
|
@retval EFI_EFI_UNSUPPORTED The operation is not supported
|
|
@retval EFI_DEVICE_ERROR The device is not functioning correctly
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetFlowControlInternal (
|
|
IN EFI_USB_IO_PROTOCOL *UsbIo,
|
|
IN BOOLEAN FlowControlEnable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_USB_DEVICE_REQUEST DevReq;
|
|
UINT32 ReturnValue;
|
|
UINT8 ConfigurationValue;
|
|
|
|
//
|
|
// set DevReq.Value based on the value of FlowControlEnable
|
|
//
|
|
if (!FlowControlEnable) {
|
|
DevReq.Value = NO_FLOW_CTRL;
|
|
}
|
|
if (FlowControlEnable) {
|
|
DevReq.Value = XON_XOFF_CTRL;
|
|
}
|
|
//
|
|
// set the remaining DevReq parameters and perform the usb control transfer to
|
|
// set the flow control on the device
|
|
//
|
|
DevReq.Request = FTDI_COMMAND_SET_FLOW_CTRL;
|
|
DevReq.RequestType = USB_REQ_TYPE_VENDOR;
|
|
DevReq.Index = FTDI_PORT_IDENTIFIER;
|
|
DevReq.Length = 0; // indicates that this transfer has no data phase
|
|
Status = UsbIo->UsbControlTransfer (
|
|
UsbIo,
|
|
&DevReq,
|
|
EfiUsbDataOut,
|
|
WDR_TIMEOUT,
|
|
&ConfigurationValue,
|
|
1,
|
|
&ReturnValue
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto StatusError;
|
|
}
|
|
|
|
return Status;
|
|
|
|
StatusError:
|
|
if ((Status != EFI_INVALID_PARAMETER) ||
|
|
(Status != EFI_DEVICE_ERROR) ||
|
|
(Status != EFI_UNSUPPORTED) ) {
|
|
return EFI_DEVICE_ERROR;
|
|
} else {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Internal function that performs a Usb Control Transfer to set the Dtr value on
|
|
the Usb Serial Device.
|
|
|
|
@param UsbIo[in] Usb Io Protocol instance pointer
|
|
@param DtrEnable[in] Data on the Enable/Disable status of the
|
|
Dtr for the Usb Serial Device
|
|
|
|
@retval EFI_SUCCESS The Dtr value was set on the Usb Serial
|
|
Device
|
|
@retval EFI_INVALID_PARAMETER An invalid Dtr value was used
|
|
@retval EFI_UNSUPPORTED The operation is not supported
|
|
@retval EFI_DEVICE_ERROR The device is not functioning correctly
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetDtrInternal (
|
|
IN EFI_USB_IO_PROTOCOL *UsbIo,
|
|
IN BOOLEAN DtrEnable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_USB_DEVICE_REQUEST DevReq;
|
|
UINT32 ReturnValue;
|
|
UINT8 ConfigurationValue;
|
|
|
|
//
|
|
// set the value of DevReq.Value based on the value of DtrEnable
|
|
//
|
|
if (!DtrEnable) {
|
|
DevReq.Value = SET_DTR_LOW;
|
|
}
|
|
if (DtrEnable) {
|
|
DevReq.Value = SET_DTR_HIGH;
|
|
}
|
|
//
|
|
// set the remaining attributes of DevReq and perform the usb control transfer
|
|
// to set the device
|
|
//
|
|
DevReq.Request = FTDI_COMMAND_MODEM_CTRL;
|
|
DevReq.RequestType = USB_REQ_TYPE_VENDOR;
|
|
DevReq.Index = FTDI_PORT_IDENTIFIER;
|
|
DevReq.Length = 0; // indicates that there is no data phase in this transfer
|
|
|
|
Status = UsbIo->UsbControlTransfer (
|
|
UsbIo,
|
|
&DevReq,
|
|
EfiUsbDataOut,
|
|
WDR_TIMEOUT,
|
|
&ConfigurationValue,
|
|
1,
|
|
&ReturnValue
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto StatusError;
|
|
}
|
|
return Status;
|
|
|
|
StatusError:
|
|
if ((Status != EFI_INVALID_PARAMETER) ||
|
|
(Status != EFI_DEVICE_ERROR) ||
|
|
(Status != EFI_UNSUPPORTED) ) {
|
|
return EFI_DEVICE_ERROR;
|
|
} else {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Internal function that performs a Usb Control Transfer to set the Dtr value on
|
|
the Usb Serial Device.
|
|
|
|
@param UsbIo[in] Usb Io Protocol instance pointer
|
|
@param RtsEnable[in] Data on the Enable/Disable status of the
|
|
Rts for the Usb Serial Device
|
|
|
|
@retval EFI_SUCCESS The Rts value was set on the Usb Serial
|
|
Device
|
|
@retval EFI_INVALID_PARAMETER An invalid Rts value was used
|
|
@retval EFI_UNSUPPORTED The operation is not supported
|
|
@retval EFI_DEVICE_ERROR The device is not functioning correctly
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetRtsInternal (
|
|
IN EFI_USB_IO_PROTOCOL *UsbIo,
|
|
IN BOOLEAN RtsEnable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_USB_DEVICE_REQUEST DevReq;
|
|
UINT32 ReturnValue;
|
|
UINT8 ConfigurationValue;
|
|
|
|
//
|
|
// set DevReq.Value based on the value of RtsEnable
|
|
//
|
|
if (!RtsEnable) {
|
|
DevReq.Value = SET_RTS_LOW;
|
|
}
|
|
if (RtsEnable) {
|
|
DevReq.Value = SET_RTS_HIGH;
|
|
}
|
|
|
|
//
|
|
// set the remaining parameters of DevReq and perform the usb control transfer
|
|
// to set the values on the device
|
|
//
|
|
DevReq.Request = FTDI_COMMAND_MODEM_CTRL;
|
|
DevReq.RequestType = USB_REQ_TYPE_VENDOR;
|
|
DevReq.Index = FTDI_PORT_IDENTIFIER;
|
|
DevReq.Length = 0; // indicates that there is no data phase in this request
|
|
|
|
Status = UsbIo->UsbControlTransfer (
|
|
UsbIo,
|
|
&DevReq,
|
|
EfiUsbDataOut,
|
|
WDR_TIMEOUT,
|
|
&ConfigurationValue,
|
|
1,
|
|
&ReturnValue
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto StatusError;
|
|
}
|
|
|
|
return Status;
|
|
|
|
StatusError:
|
|
if ((Status != EFI_INVALID_PARAMETER) ||
|
|
(Status != EFI_DEVICE_ERROR) ||
|
|
(Status != EFI_UNSUPPORTED) ) {
|
|
return EFI_DEVICE_ERROR;
|
|
} else {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Internal function that checks for valid control values and sets the control
|
|
bits on the Usb Serial Device.
|
|
|
|
@param UsbSerialDevice[in] Handle to the Usb Serial Device whose
|
|
control bits are being set
|
|
@param Control[in] The control value passed to the function
|
|
that contains the values of the control
|
|
bits that are being set
|
|
|
|
@retval EFI_SUCCESS The control bits were set on the Usb Serial
|
|
Device
|
|
@retval EFI_INVALID_PARAMETER An invalid control value was encountered
|
|
@retval EFI_EFI_UNSUPPORTED The operation is not supported
|
|
@retval EFI_DEVICE_ERROR The device is not functioning correctly
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetControlBitsInternal (
|
|
IN USB_SER_DEV *UsbSerialDevice,
|
|
IN CONTROL_BITS *Control
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
|
|
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
|
|
|
|
//
|
|
// check for invalid control parameters hardware and software loopback enabled
|
|
// must always be set to FALSE
|
|
//
|
|
Control->HardwareLoopBack = FALSE;
|
|
Control->SoftwareLoopBack = FALSE;
|
|
|
|
//
|
|
// set hardware flow control
|
|
//
|
|
Status = SetFlowControlInternal (
|
|
UsbSerialDevice->UsbIo,
|
|
Control->HardwareFlowControl
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto StatusError;
|
|
}
|
|
|
|
//
|
|
// set Dtr state
|
|
//
|
|
Status = SetDtrInternal (UsbSerialDevice->UsbIo, Control->DtrState);
|
|
if (EFI_ERROR (Status)) {
|
|
goto StatusError;
|
|
}
|
|
|
|
//
|
|
// set Rts state
|
|
//
|
|
Status = SetRtsInternal (UsbSerialDevice->UsbIo, Control->RtsState);
|
|
if (EFI_ERROR (Status)){
|
|
goto StatusError;
|
|
}
|
|
|
|
//
|
|
// update the remaining control values for UsbSerialDevice->ControlValues
|
|
//
|
|
UsbSerialDevice->ControlValues.DtrState = Control->DtrState;
|
|
UsbSerialDevice->ControlValues.RtsState = Control->RtsState;
|
|
UsbSerialDevice->ControlValues.HardwareFlowControl = Control->HardwareFlowControl;
|
|
UsbSerialDevice->ControlValues.HardwareLoopBack = FALSE;
|
|
UsbSerialDevice->ControlValues.SoftwareLoopBack = FALSE;
|
|
|
|
Status = EFI_SUCCESS;
|
|
//
|
|
// Update the device path to have the correct flow control values
|
|
//
|
|
if (UsbSerialDevice->ControllerHandle != NULL) {
|
|
RemainingDevicePath = UsbSerialDevice->DevicePath;
|
|
while (!IsDevicePathEnd (RemainingDevicePath)) {
|
|
FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (RemainingDevicePath);
|
|
if (FlowControl->Header.Type == MESSAGING_DEVICE_PATH &&
|
|
FlowControl->Header.SubType == MSG_VENDOR_DP &&
|
|
sizeof (UART_FLOW_CONTROL_DEVICE_PATH) == DevicePathNodeLength ((EFI_DEVICE_PATH *) FlowControl)){
|
|
if (UsbSerialDevice->ControlValues.HardwareFlowControl == TRUE) {
|
|
FlowControl->FlowControlMap = UART_FLOW_CONTROL_HARDWARE;
|
|
} else if (UsbSerialDevice->ControlValues.HardwareFlowControl == FALSE) {
|
|
FlowControl->FlowControlMap = 0;
|
|
}
|
|
break;
|
|
}
|
|
RemainingDevicePath = NextDevicePathNode (RemainingDevicePath);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
|
|
StatusError:
|
|
if ((Status != EFI_INVALID_PARAMETER) ||
|
|
(Status != EFI_DEVICE_ERROR) ||
|
|
(Status != EFI_UNSUPPORTED) ) {
|
|
return EFI_DEVICE_ERROR;
|
|
} else {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Internal function that calculates the Control value used by GetControlBits()
|
|
based on the status and control values of the Usb Serial Device.
|
|
|
|
@param UsbSerialDevice[in] Handle to the Usb Serial Devie whose status
|
|
and control values are being used to set
|
|
Control
|
|
@param Control[out] On output the formated value of Control
|
|
that has been calculated based on the
|
|
control and status values of the Usb Serial
|
|
Device
|
|
|
|
@retval EFI_SUCCESS The value of Control was successfully
|
|
calculated
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetControlBitsInternal (
|
|
IN USB_SER_DEV *UsbSerialDevice,
|
|
OUT UINT32 *Control
|
|
)
|
|
{
|
|
*Control = 0;
|
|
|
|
//
|
|
// Check the values of UsbSerialDevice->Status Values and modify control
|
|
// accordingly these values correspond to the modem status register
|
|
//
|
|
if (UsbSerialDevice->StatusValues.CtsState) {
|
|
*Control |= EFI_SERIAL_CLEAR_TO_SEND;
|
|
}
|
|
if (UsbSerialDevice->StatusValues.DsrState) {
|
|
*Control |= EFI_SERIAL_DATA_SET_READY;
|
|
}
|
|
if (UsbSerialDevice->StatusValues.RiState) {
|
|
*Control |= EFI_SERIAL_RING_INDICATE;
|
|
}
|
|
if (UsbSerialDevice->StatusValues.SdState) {
|
|
*Control |= EFI_SERIAL_CARRIER_DETECT;
|
|
}
|
|
|
|
//
|
|
// check the values of UsbSerialDevice->ControlValues and modify control
|
|
// accordingly these values correspond to the values of the Modem Control
|
|
// Register
|
|
//
|
|
if (UsbSerialDevice->ControlValues.DtrState) {
|
|
*Control |= EFI_SERIAL_DATA_TERMINAL_READY;
|
|
}
|
|
if (UsbSerialDevice->ControlValues.RtsState) {
|
|
*Control |= EFI_SERIAL_REQUEST_TO_SEND;
|
|
}
|
|
if (UsbSerialDevice->ControlValues.HardwareLoopBack) {
|
|
*Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
|
|
}
|
|
if (UsbSerialDevice->ControlValues.HardwareFlowControl) {
|
|
*Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
|
|
}
|
|
//
|
|
// check if the buffer is empty since only one is being used if it is empty
|
|
// set both the receive and transmit buffers to empty
|
|
//
|
|
if (UsbSerialDevice->DataBufferHead == UsbSerialDevice->DataBufferTail) {
|
|
*Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
|
|
*Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
|
|
}
|
|
//
|
|
// check for software loopback enable in UsbSerialDevice->ControlValues
|
|
//
|
|
if (UsbSerialDevice->ControlValues.SoftwareLoopBack) {
|
|
*Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Resets the USB Serial Device
|
|
|
|
This function is the internal method for resetting the device and is called by
|
|
SerialReset()
|
|
|
|
@param UsbSerialDevice[in] A pointer to the USB Serial device
|
|
|
|
@retval EFI_SUCCESS The device was reset
|
|
@retval EFI_DEVICE_ERROR The device could not be reset
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ResetInternal (
|
|
IN USB_SER_DEV *UsbSerialDevice
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_USB_DEVICE_REQUEST DevReq;
|
|
UINT8 ConfigurationValue;
|
|
UINT32 ReturnValue;
|
|
|
|
DevReq.Request = FTDI_COMMAND_RESET_PORT;
|
|
DevReq.RequestType = USB_REQ_TYPE_VENDOR;
|
|
DevReq.Value = RESET_PORT_PURGE_RX;
|
|
DevReq.Index = FTDI_PORT_IDENTIFIER;
|
|
DevReq.Length = 0; //indicates that there is not data phase in this request
|
|
|
|
Status = UsbSerialDevice->UsbIo->UsbControlTransfer (
|
|
UsbSerialDevice->UsbIo,
|
|
&DevReq,
|
|
EfiUsbDataIn,
|
|
WDR_TIMEOUT,
|
|
&ConfigurationValue,
|
|
1,
|
|
&ReturnValue
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
DevReq.Request = FTDI_COMMAND_RESET_PORT;
|
|
DevReq.RequestType = USB_REQ_TYPE_VENDOR;
|
|
DevReq.Value = RESET_PORT_PURGE_TX;
|
|
DevReq.Index = FTDI_PORT_IDENTIFIER;
|
|
DevReq.Length = 0; //indicates that there is no data phase in this request
|
|
|
|
Status = UsbSerialDevice->UsbIo->UsbControlTransfer (
|
|
UsbSerialDevice->UsbIo,
|
|
&DevReq,
|
|
EfiUsbDataIn,
|
|
WDR_TIMEOUT,
|
|
&ConfigurationValue,
|
|
1,
|
|
&ReturnValue
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Entrypoint of USB Serial Driver.
|
|
|
|
This function is the entrypoint of USB Serial Driver. It installs
|
|
Driver Binding Protocols together with Component Name Protocols.
|
|
|
|
@param ImageHandle[in] The firmware allocated handle for the EFI image.
|
|
@param SystemTable[in] A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The entry point is executed successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FtdiUsbSerialEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EfiLibInstallDriverBindingComponentName2 (
|
|
ImageHandle,
|
|
SystemTable,
|
|
&gUsbSerialDriverBinding,
|
|
ImageHandle,
|
|
&gUsbSerialComponentName,
|
|
&gUsbSerialComponentName2
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Unload function for the Usb Serial Driver.
|
|
|
|
@param ImageHandle[in] The allocated handle for the EFI image
|
|
|
|
@retval EFI_SUCCESS The driver was unloaded successfully
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FtdiUsbSerialUnload (
|
|
IN EFI_HANDLE ImageHandle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN HandleCount;
|
|
UINTN Index;
|
|
|
|
//
|
|
// Retrieve all handles in the handle database
|
|
//
|
|
Status = gBS->LocateHandleBuffer (
|
|
AllHandles,
|
|
NULL,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Disconnect the driver from the handles in the handle database
|
|
//
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
Status = gBS->DisconnectController (
|
|
HandleBuffer[Index],
|
|
gImageHandle,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
//
|
|
// Free the handle array
|
|
//
|
|
FreePool (HandleBuffer);
|
|
|
|
//
|
|
// Uninstall protocols installed by the driver in its entrypoint
|
|
//
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
|
ImageHandle,
|
|
&gEfiDriverBindingProtocolGuid,
|
|
&gUsbSerialDriverBinding,
|
|
&gEfiComponentNameProtocolGuid,
|
|
&gUsbSerialComponentName,
|
|
&gEfiComponentName2ProtocolGuid,
|
|
&gUsbSerialComponentName2,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Check whether USB Serial driver supports this device.
|
|
|
|
@param This[in] The USB Serial driver binding protocol.
|
|
@param Controller[in] The controller handle to check.
|
|
@param RemainingDevicePath[in] The remaining device path.
|
|
|
|
@retval EFI_SUCCESS The driver supports this controller.
|
|
@retval other This device isn't supported.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbSerialDriverBindingSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_USB_IO_PROTOCOL *UsbIo;
|
|
UART_DEVICE_PATH *UartNode;
|
|
UART_FLOW_CONTROL_DEVICE_PATH *FlowControlNode;
|
|
UINTN Index;
|
|
UINTN EntryCount;
|
|
EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
|
|
BOOLEAN HasFlowControl;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
|
|
|
|
if (RemainingDevicePath != NULL) {
|
|
if (!IsDevicePathEnd (RemainingDevicePath)) {
|
|
Status = EFI_UNSUPPORTED;
|
|
UartNode = (UART_DEVICE_PATH *) NextDevicePathNode (RemainingDevicePath);
|
|
if (UartNode->Header.Type != MESSAGING_DEVICE_PATH ||
|
|
UartNode->Header.SubType != MSG_UART_DP ||
|
|
sizeof (UART_DEVICE_PATH) != DevicePathNodeLength ((EFI_DEVICE_PATH *) UartNode)) {
|
|
goto Error;
|
|
}
|
|
FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (UartNode);
|
|
if ((ReadUnaligned32 (&FlowControlNode->FlowControlMap) & ~UART_FLOW_CONTROL_HARDWARE) != 0) {
|
|
goto Error;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check if USB I/O Protocol is attached on the controller handle.
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiUsbIoProtocolGuid,
|
|
(VOID **) &UsbIo,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (Status == EFI_ALREADY_STARTED) {
|
|
if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
Status = gBS->OpenProtocolInformation (
|
|
Controller,
|
|
&gEfiUsbIoProtocolGuid,
|
|
&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,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
HasFlowControl = ContainsFlowControl (RemainingDevicePath);
|
|
if (HasFlowControl ^ ContainsFlowControl (DevicePath)) {
|
|
Status = EFI_UNSUPPORTED;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
FreePool (OpenInfoBuffer);
|
|
return Status;
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiUsbIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
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;
|
|
}
|
|
|
|
//
|
|
// Use the USB I/O Protocol interface to check whether Controller is
|
|
// a USB Serial device that can be managed by this driver.
|
|
//
|
|
Status = EFI_SUCCESS;
|
|
|
|
if (!IsUsbSerial (UsbIo)) {
|
|
Status = EFI_UNSUPPORTED;
|
|
goto Error;
|
|
}
|
|
|
|
Error:
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiDevicePathProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Starts the USB Serial device with this driver.
|
|
|
|
This function produces initializes the USB Serial device and
|
|
produces the Serial IO Protocol.
|
|
|
|
@param This[in] The USB Serial driver binding instance.
|
|
@param Controller[in] Handle of device to bind driver to.
|
|
@param RemainingDevicePath[in] Optional parameter use to pick a specific
|
|
child device to start.
|
|
|
|
@retval EFI_SUCCESS The controller is controlled by the usb USB
|
|
Serial driver.
|
|
@retval EFI_UNSUPPORTED No interrupt endpoint can be found.
|
|
@retval Other This controller cannot be started.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbSerialDriverBindingStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_USB_IO_PROTOCOL *UsbIo;
|
|
USB_SER_DEV *UsbSerialDevice;
|
|
UINT8 EndpointNumber;
|
|
EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
|
|
UINT8 Index;
|
|
BOOLEAN FoundIn;
|
|
BOOLEAN FoundOut;
|
|
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
|
|
EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
|
|
UINTN EntryCount;
|
|
EFI_SERIAL_IO_PROTOCOL *SerialIo;
|
|
UART_DEVICE_PATH *Uart;
|
|
UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
|
|
UINT32 Control;
|
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
|
|
|
UsbSerialDevice = AllocateZeroPool (sizeof (USB_SER_DEV));
|
|
ASSERT (UsbSerialDevice != 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) {
|
|
goto ErrorExit1;
|
|
}
|
|
|
|
//
|
|
// Open USB I/O Protocol
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiUsbIoProtocolGuid,
|
|
(VOID **) &UsbIo,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
|
|
goto ErrorExit1;
|
|
}
|
|
|
|
if (Status == EFI_ALREADY_STARTED) {
|
|
if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {
|
|
FreePool (UsbSerialDevice);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Check to see if a child handle exists
|
|
//
|
|
Status = gBS->OpenProtocolInformation (
|
|
Controller,
|
|
&gEfiSerialIoProtocolGuid,
|
|
&OpenInfoBuffer,
|
|
&EntryCount
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto ErrorExit1;
|
|
}
|
|
|
|
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,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
}
|
|
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 (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) {
|
|
Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
|
|
} else {
|
|
Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
|
|
}
|
|
//
|
|
// Clear bits that are not allowed to be passed 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;
|
|
}
|
|
|
|
if (RemainingDevicePath != NULL) {
|
|
if (IsDevicePathEnd (RemainingDevicePath)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
UsbSerialDevice->UsbIo = UsbIo;
|
|
|
|
//
|
|
// Get interface & endpoint descriptor
|
|
//
|
|
UsbIo->UsbGetInterfaceDescriptor (
|
|
UsbIo,
|
|
&UsbSerialDevice->InterfaceDescriptor
|
|
);
|
|
|
|
EndpointNumber = UsbSerialDevice->InterfaceDescriptor.NumEndpoints;
|
|
|
|
//
|
|
// Traverse endpoints to find the IN and OUT endpoints that will send and
|
|
// receive data.
|
|
//
|
|
FoundIn = FALSE;
|
|
FoundOut = FALSE;
|
|
for (Index = 0; Index < EndpointNumber; Index++) {
|
|
|
|
Status = UsbIo->UsbGetEndpointDescriptor (
|
|
UsbIo,
|
|
Index,
|
|
&EndpointDescriptor
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (EndpointDescriptor.EndpointAddress == FTDI_ENDPOINT_ADDRESS_OUT) {
|
|
//
|
|
// Set the Out endpoint device
|
|
//
|
|
CopyMem (
|
|
&UsbSerialDevice->OutEndpointDescriptor,
|
|
&EndpointDescriptor,
|
|
sizeof(EndpointDescriptor)
|
|
);
|
|
FoundOut = TRUE;
|
|
}
|
|
|
|
if (EndpointDescriptor.EndpointAddress == FTDI_ENDPOINT_ADDRESS_IN) {
|
|
//
|
|
// Set the In endpoint device
|
|
//
|
|
CopyMem (
|
|
&UsbSerialDevice->InEndpointDescriptor,
|
|
&EndpointDescriptor,
|
|
sizeof(EndpointDescriptor)
|
|
);
|
|
FoundIn = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!FoundIn || !FoundOut) {
|
|
//
|
|
// No interrupt endpoint found, then return unsupported.
|
|
//
|
|
Status = EFI_UNSUPPORTED;
|
|
goto ErrorExit;
|
|
}
|
|
//
|
|
// set the initial values of UsbSerialDevice->LastSettings to the default
|
|
// values
|
|
//
|
|
UsbSerialDevice->LastSettings.BaudRate = 115200;
|
|
UsbSerialDevice->LastSettings.DataBits = 8;
|
|
UsbSerialDevice->LastSettings.Parity = NoParity;
|
|
UsbSerialDevice->LastSettings.ReceiveFifoDepth = FTDI_MAX_RECEIVE_FIFO_DEPTH;
|
|
UsbSerialDevice->LastSettings.StopBits = OneStopBit;
|
|
UsbSerialDevice->LastSettings.Timeout = FTDI_TIMEOUT;
|
|
|
|
//
|
|
// set the initial values of UsbSerialDevice->ControlValues
|
|
//
|
|
UsbSerialDevice->ControlValues.DtrState = FALSE;
|
|
UsbSerialDevice->ControlValues.RtsState = FALSE;
|
|
UsbSerialDevice->ControlValues.HardwareFlowControl = FALSE;
|
|
UsbSerialDevice->ControlValues.HardwareLoopBack = FALSE;
|
|
UsbSerialDevice->ControlValues.SoftwareLoopBack = FALSE;
|
|
|
|
//
|
|
// set the values of UsbSerialDevice->UartDevicePath
|
|
//
|
|
UsbSerialDevice->UartDevicePath.Header.Type = MESSAGING_DEVICE_PATH;
|
|
UsbSerialDevice->UartDevicePath.Header.SubType = MSG_UART_DP;
|
|
UsbSerialDevice->UartDevicePath.Header.Length[0] = (UINT8) (sizeof (UART_DEVICE_PATH));
|
|
UsbSerialDevice->UartDevicePath.Header.Length[1] = (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8);
|
|
|
|
//
|
|
// set the values of UsbSerialDevice->FlowControlDevicePath
|
|
UsbSerialDevice->FlowControlDevicePath.Header.Type = MESSAGING_DEVICE_PATH;
|
|
UsbSerialDevice->FlowControlDevicePath.Header.SubType = MSG_VENDOR_DP;
|
|
UsbSerialDevice->FlowControlDevicePath.Header.Length[0] = (UINT8) (sizeof (UART_FLOW_CONTROL_DEVICE_PATH));
|
|
UsbSerialDevice->FlowControlDevicePath.Header.Length[1] = (UINT8) ((sizeof (UART_FLOW_CONTROL_DEVICE_PATH)) >> 8);
|
|
UsbSerialDevice->FlowControlDevicePath.FlowControlMap = 0;
|
|
|
|
Status = SetAttributesInternal (
|
|
UsbSerialDevice,
|
|
UsbSerialDevice->LastSettings.BaudRate,
|
|
UsbSerialDevice->LastSettings.ReceiveFifoDepth,
|
|
UsbSerialDevice->LastSettings.Timeout,
|
|
UsbSerialDevice->LastSettings.Parity,
|
|
UsbSerialDevice->LastSettings.DataBits,
|
|
UsbSerialDevice->LastSettings.StopBits
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Status = SetControlBitsInternal (
|
|
UsbSerialDevice,
|
|
&(UsbSerialDevice->ControlValues)
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// Publish Serial GUID and protocol
|
|
//
|
|
|
|
UsbSerialDevice->Signature = USB_SER_DEV_SIGNATURE;
|
|
UsbSerialDevice->SerialIo.Reset = SerialReset;
|
|
UsbSerialDevice->SerialIo.SetControl = SetControlBits;
|
|
UsbSerialDevice->SerialIo.SetAttributes = SetAttributes;
|
|
UsbSerialDevice->SerialIo.GetControl = GetControlBits;
|
|
UsbSerialDevice->SerialIo.Read = ReadSerialIo;
|
|
UsbSerialDevice->SerialIo.Write = WriteSerialIo;
|
|
|
|
//
|
|
// Set the static Serial IO modes that will display when running
|
|
// "sermode" within the UEFI shell.
|
|
//
|
|
|
|
UsbSerialDevice->SerialIo.Mode->Timeout = 0;
|
|
UsbSerialDevice->SerialIo.Mode->BaudRate = 115200;
|
|
UsbSerialDevice->SerialIo.Mode->DataBits = 8;
|
|
UsbSerialDevice->SerialIo.Mode->Parity = 1;
|
|
UsbSerialDevice->SerialIo.Mode->StopBits = 1;
|
|
|
|
UsbSerialDevice->ParentDevicePath = ParentDevicePath;
|
|
UsbSerialDevice->ControllerHandle = NULL;
|
|
FlowControl = NULL;
|
|
|
|
//
|
|
// Allocate space for the receive buffer
|
|
//
|
|
UsbSerialDevice->DataBuffer = AllocateZeroPool (SW_FIFO_DEPTH);
|
|
|
|
//
|
|
// Initialize data buffer pointers.
|
|
// Head==Tail = true means buffer is empty.
|
|
//
|
|
UsbSerialDevice->DataBufferHead = 0;
|
|
UsbSerialDevice->DataBufferTail = 0;
|
|
|
|
UsbSerialDevice->ControllerNameTable = NULL;
|
|
AddUnicodeString2 (
|
|
"eng",
|
|
gUsbSerialComponentName.SupportedLanguages,
|
|
&UsbSerialDevice->ControllerNameTable,
|
|
L"FTDI USB Serial Adapter",
|
|
TRUE
|
|
);
|
|
AddUnicodeString2 (
|
|
"en",
|
|
gUsbSerialComponentName2.SupportedLanguages,
|
|
&UsbSerialDevice->ControllerNameTable,
|
|
L"FTDI USB Serial Adapter",
|
|
FALSE
|
|
);
|
|
|
|
Status = SetInitialStatus (UsbSerialDevice);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// Create a polling loop to check for input
|
|
//
|
|
|
|
gBS->CreateEvent (
|
|
EVT_TIMER | EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
UsbSerialDriverCheckInput,
|
|
UsbSerialDevice,
|
|
&(UsbSerialDevice->PollingLoop)
|
|
);
|
|
//
|
|
// add code to set trigger time based on baud rate
|
|
// setting to 0.5s for now
|
|
//
|
|
gBS->SetTimer (
|
|
UsbSerialDevice->PollingLoop,
|
|
TimerPeriodic,
|
|
EFI_TIMER_PERIOD_MILLISECONDS (500)
|
|
);
|
|
|
|
//
|
|
// Check if the remaining device path is null. If it is not null change the settings
|
|
// of the device to match those on the device path
|
|
//
|
|
if (RemainingDevicePath != NULL) {
|
|
CopyMem (
|
|
&UsbSerialDevice->UartDevicePath,
|
|
RemainingDevicePath,
|
|
sizeof (UART_DEVICE_PATH)
|
|
);
|
|
FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (RemainingDevicePath);
|
|
if (IsUartFlowControlNode (FlowControl)) {
|
|
UsbSerialDevice->FlowControlDevicePath.FlowControlMap = ReadUnaligned32 (&FlowControl->FlowControlMap);
|
|
} else {
|
|
FlowControl = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Build the device path by appending the UART node to the parent device path
|
|
//
|
|
UsbSerialDevice->DevicePath = AppendDevicePathNode (
|
|
ParentDevicePath,
|
|
(EFI_DEVICE_PATH_PROTOCOL *) &UsbSerialDevice->UartDevicePath
|
|
);
|
|
//
|
|
// Continue building the device path by appending the flow control node
|
|
//
|
|
TempDevicePath = UsbSerialDevice->DevicePath;
|
|
UsbSerialDevice->DevicePath = AppendDevicePathNode (
|
|
TempDevicePath,
|
|
(EFI_DEVICE_PATH_PROTOCOL *) &UsbSerialDevice->FlowControlDevicePath
|
|
);
|
|
FreePool (TempDevicePath);
|
|
|
|
if (UsbSerialDevice->DevicePath == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Install protocol interfaces for the device
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&UsbSerialDevice->ControllerHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
UsbSerialDevice->DevicePath,
|
|
&gEfiSerialIoProtocolGuid,
|
|
&UsbSerialDevice->SerialIo,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)){
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Open for child device
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiUsbIoProtocolGuid,
|
|
(VOID **) &UsbIo,
|
|
This->DriverBindingHandle,
|
|
UsbSerialDevice->ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
|
);
|
|
|
|
UsbSerialDevice->Shutdown = FALSE;
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Error handler
|
|
//
|
|
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
|
Controller,
|
|
&gEfiSerialIoProtocolGuid,
|
|
&UsbSerialDevice->SerialIo,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto ErrorExit1;
|
|
}
|
|
|
|
FreePool (UsbSerialDevice->DataBuffer);
|
|
FreePool (UsbSerialDevice);
|
|
|
|
UsbSerialDevice = NULL;
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiUsbIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
ErrorExit1:
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Stop the USB Serial device handled by this driver.
|
|
|
|
@param This[in] The USB Serial driver binding protocol.
|
|
@param Controller[in] The controller to release.
|
|
@param NumberOfChildren[in] The number of handles in ChildHandleBuffer.
|
|
@param ChildHandleBuffer[in] The array of child handle.
|
|
|
|
@retval EFI_SUCCESS The device was stopped.
|
|
@retval EFI_UNSUPPORTED Serial IO Protocol is not installed on
|
|
Controller.
|
|
@retval EFI_DEVICE_ERROR The device could not be stopped due to a
|
|
device error.
|
|
@retval Others Fail to uninstall protocols attached on the
|
|
device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbSerialDriverBindingStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_SERIAL_IO_PROTOCOL *SerialIo;
|
|
EFI_USB_IO_PROTOCOL *UsbIo;
|
|
USB_SER_DEV *UsbSerialDevice;
|
|
UINTN Index;
|
|
BOOLEAN AllChildrenStopped;
|
|
|
|
Status = EFI_SUCCESS;
|
|
UsbSerialDevice = NULL;
|
|
|
|
if (NumberOfChildren == 0) {
|
|
//
|
|
// Close the driver
|
|
//
|
|
Status = gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiUsbIoProtocolGuid,
|
|
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 (Status == EFI_SUCCESS) {//!EFI_ERROR (Status)) {
|
|
UsbSerialDevice = USB_SER_DEV_FROM_THIS (SerialIo);
|
|
Status = gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiUsbIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
ChildHandleBuffer[Index]
|
|
);
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
|
ChildHandleBuffer[Index],
|
|
&gEfiDevicePathProtocolGuid,
|
|
UsbSerialDevice->DevicePath,
|
|
&gEfiSerialIoProtocolGuid,
|
|
&UsbSerialDevice->SerialIo,
|
|
NULL
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiUsbIoProtocolGuid,
|
|
(VOID **) &UsbIo,
|
|
This->DriverBindingHandle,
|
|
ChildHandleBuffer[Index],
|
|
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
|
);
|
|
} else {
|
|
if (UsbSerialDevice->DevicePath != NULL) {
|
|
gBS->FreePool (UsbSerialDevice->DevicePath);
|
|
}
|
|
gBS->SetTimer (
|
|
UsbSerialDevice->PollingLoop,
|
|
TimerCancel,
|
|
0
|
|
);
|
|
gBS->CloseEvent (UsbSerialDevice->PollingLoop);
|
|
UsbSerialDevice->Shutdown = TRUE;
|
|
FreeUnicodeStringTable (UsbSerialDevice->ControllerNameTable);
|
|
FreePool (UsbSerialDevice->DataBuffer);
|
|
FreePool (UsbSerialDevice);
|
|
}
|
|
}
|
|
if (EFI_ERROR (Status)) {
|
|
AllChildrenStopped = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!AllChildrenStopped) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Serial IO Member Functions
|
|
//
|
|
|
|
/**
|
|
Reset the serial device.
|
|
|
|
@param This[in] Protocol instance pointer.
|
|
|
|
@retval EFI_SUCCESS The device was reset.
|
|
@retval EFI_DEVICE_ERROR The serial device could not be reset.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SerialReset (
|
|
IN EFI_SERIAL_IO_PROTOCOL *This
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USB_SER_DEV *UsbSerialDevice;
|
|
|
|
UsbSerialDevice = USB_SER_DEV_FROM_THIS (This);
|
|
Status = ResetInternal (UsbSerialDevice);
|
|
if (EFI_ERROR (Status)){
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Set the control bits on a serial device.
|
|
|
|
@param This[in] Protocol instance pointer.
|
|
@param Control[in] Set the bits of Control that are settable.
|
|
|
|
@retval EFI_SUCCESS The new control bits were set on the serial device.
|
|
@retval EFI_UNSUPPORTED The serial device does not support this operation.
|
|
@retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetControlBits (
|
|
IN EFI_SERIAL_IO_PROTOCOL *This,
|
|
IN UINT32 Control
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USB_SER_DEV *UsbSerialDevice;
|
|
CONTROL_BITS ControlBits;
|
|
|
|
UsbSerialDevice = USB_SER_DEV_FROM_THIS (This);
|
|
|
|
//
|
|
// check for invalid control parameters
|
|
//
|
|
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))) != 0 ) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// check the control parameters and set the correct setting for
|
|
// the paramerts of ControlBits
|
|
// both loopback enables are always set to FALSE
|
|
//
|
|
ControlBits.HardwareLoopBack = FALSE;
|
|
ControlBits.SoftwareLoopBack = FALSE;
|
|
//
|
|
// check for hardware flow control
|
|
//
|
|
if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
|
|
ControlBits.HardwareFlowControl = TRUE;
|
|
} else {
|
|
ControlBits.HardwareFlowControl = FALSE;
|
|
}
|
|
//
|
|
// check for DTR enabled
|
|
//
|
|
if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
|
|
ControlBits.DtrState = TRUE;
|
|
} else {
|
|
ControlBits.DtrState = FALSE;
|
|
}
|
|
//
|
|
// check for RTS enabled
|
|
//
|
|
if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
|
|
ControlBits.RtsState = TRUE;
|
|
} else {
|
|
ControlBits.RtsState = FALSE;
|
|
}
|
|
|
|
//
|
|
// set the control values with a call to SetControlBitsInternal()
|
|
//
|
|
Status = SetControlBitsInternal (UsbSerialDevice, &ControlBits);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
calls SetAttributesInternal() to set the baud rate, receive FIFO depth,
|
|
transmit/receive time out, parity, data buts, and stop bits on a serial
|
|
device.
|
|
|
|
@param This[in] Protocol instance pointer.
|
|
@param BaudRate[in] The requested baud rate. A BaudRate value of 0
|
|
will use the device's default interface speed.
|
|
@param ReveiveFifoDepth[in] The requested depth of the FIFO on the receive
|
|
side of the serial interface. A ReceiveFifoDepth
|
|
value of 0 will use the device's default FIFO
|
|
depth.
|
|
@param Timeout[in] The requested time out for a single character in
|
|
microseconds.This timeout applies to both the
|
|
transmit and receive side of the interface. A
|
|
Timeout value of 0 will use the device's default
|
|
time out value.
|
|
@param Parity[in] The type of parity to use on this serial device.
|
|
A Parity value of DefaultParity will use the
|
|
device's default parity value.
|
|
@param DataBits[in] The number of data bits to use on the serial
|
|
device. A DataBit vaule of 0 will use the
|
|
device's default data bit setting.
|
|
@param StopBits[in] The number of stop bits to use on this serial
|
|
device. A StopBits value of DefaultStopBits will
|
|
use the device's default number of stop bits.
|
|
|
|
@retval EFI_SUCCESS The attributes were set
|
|
@retval EFI_DEVICE_ERROR The attributes were not able to be
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetAttributes (
|
|
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
|
|
)
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
USB_SER_DEV *UsbSerialDevice;
|
|
|
|
UsbSerialDevice = USB_SER_DEV_FROM_THIS (This);
|
|
|
|
Status = SetAttributesInternal (
|
|
UsbSerialDevice,
|
|
BaudRate,
|
|
ReceiveFifoDepth,
|
|
Timeout,
|
|
Parity,
|
|
DataBits,
|
|
StopBits
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Retrieves the status of the control bits on a serial device.
|
|
|
|
@param This[in] Protocol instance pointer.
|
|
@param Control[out] A pointer to return the current Control signals
|
|
from the serial device.
|
|
|
|
@retval EFI_SUCCESS The control bits were read from the serial
|
|
device.
|
|
@retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetControlBits (
|
|
IN EFI_SERIAL_IO_PROTOCOL *This,
|
|
OUT UINT32 *Control
|
|
)
|
|
{
|
|
USB_SER_DEV *UsbSerialDevice;
|
|
EFI_STATUS Status;
|
|
|
|
UsbSerialDevice = USB_SER_DEV_FROM_THIS (This);
|
|
|
|
*Control = 0;
|
|
|
|
Status = GetControlBitsInternal (UsbSerialDevice, Control);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Reads data from a serial device.
|
|
|
|
@param This[in] Protocol instance pointer.
|
|
@param BufferSize[in, out] On input, the size of the Buffer. On output,
|
|
the amount of data returned in Buffer.
|
|
@param Buffer[out] The buffer to return the data into.
|
|
|
|
@retval EFI_SUCCESS The data was read.
|
|
@retval EFI_DEVICE_ERROR The device reported an error.
|
|
@retval EFI_TIMEOUT The data write was stopped due to a timeout.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ReadSerialIo (
|
|
IN EFI_SERIAL_IO_PROTOCOL *This,
|
|
IN OUT UINTN *BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINTN RemainingCallerBufferSize;
|
|
USB_SER_DEV *UsbSerialDevice;
|
|
EFI_STATUS Status;
|
|
|
|
|
|
if (*BufferSize == 0) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (Buffer == NULL) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Status = EFI_SUCCESS;
|
|
UsbSerialDevice = USB_SER_DEV_FROM_THIS (This);
|
|
|
|
//
|
|
// Clear out any data that we already have in our internal buffer
|
|
//
|
|
for (Index = 0; Index < *BufferSize; Index++) {
|
|
if (UsbSerialDevice->DataBufferHead == UsbSerialDevice->DataBufferTail) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Still have characters in the buffer to return
|
|
//
|
|
((UINT8 *)Buffer)[Index] = UsbSerialDevice->DataBuffer[UsbSerialDevice->DataBufferHead];
|
|
UsbSerialDevice->DataBufferHead = (UsbSerialDevice->DataBufferHead + 1) % SW_FIFO_DEPTH;
|
|
}
|
|
|
|
//
|
|
// If we haven't filled the caller's buffer using data that we already had on
|
|
// hand We need to generate an additional USB request to try and fill the
|
|
// caller's buffer
|
|
//
|
|
if (Index != *BufferSize) {
|
|
RemainingCallerBufferSize = *BufferSize - Index;
|
|
Status = ReadDataFromUsb (
|
|
UsbSerialDevice,
|
|
&RemainingCallerBufferSize,
|
|
(VOID *)(((CHAR8 *)Buffer) + Index)
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
*BufferSize = RemainingCallerBufferSize + Index;
|
|
} else {
|
|
*BufferSize = Index;
|
|
}
|
|
}
|
|
|
|
if (UsbSerialDevice->DataBufferHead == UsbSerialDevice->DataBufferTail) {
|
|
//
|
|
// Data buffer has no data, set the EFI_SERIAL_INPUT_BUFFER_EMPTY flag
|
|
//
|
|
UsbSerialDevice->ControlBits |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
|
|
} else {
|
|
//
|
|
// There is some leftover data, clear EFI_SERIAL_INPUT_BUFFER_EMPTY flag
|
|
//
|
|
UsbSerialDevice->ControlBits &= ~(EFI_SERIAL_INPUT_BUFFER_EMPTY);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Writes data to a serial device.
|
|
|
|
@param This[in] Protocol instance pointer.
|
|
@param BufferSize[in, out] On input, the size of the Buffer. On output,
|
|
the amount of data actually written.
|
|
@param Buffer[in] The buffer of data to write
|
|
|
|
@retval EFI_SUCCESS The data was written.
|
|
@retval EFI_DEVICE_ERROR The device reported an error.
|
|
@retval EFI_TIMEOUT The data write was stopped due to a timeout.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WriteSerialIo (
|
|
IN EFI_SERIAL_IO_PROTOCOL *This,
|
|
IN OUT UINTN *BufferSize,
|
|
IN VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USB_SER_DEV *UsbSerialDevice;
|
|
EFI_TPL Tpl;
|
|
|
|
UsbSerialDevice = USB_SER_DEV_FROM_THIS (This);
|
|
|
|
if (UsbSerialDevice->Shutdown) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Tpl = gBS->RaiseTPL (TPL_NOTIFY);
|
|
|
|
Status = UsbSerialDataTransfer (
|
|
UsbSerialDevice,
|
|
EfiUsbDataOut,
|
|
Buffer,
|
|
BufferSize,
|
|
FTDI_TIMEOUT
|
|
);
|
|
|
|
gBS->RestoreTPL (Tpl);
|
|
if (EFI_ERROR (Status)) {
|
|
if (Status == EFI_TIMEOUT){
|
|
return Status;
|
|
} else {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|