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