NULL\r
},\r
{ // SerialMode\r
- SERIAL_PORT_DEFAULT_CONTROL_MASK,\r
+ SERIAL_PORT_SUPPORT_CONTROL_MASK,\r
SERIAL_PORT_DEFAULT_TIMEOUT,\r
FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate\r
SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH,\r
NULL\r
};\r
\r
+/**\r
+ Check the device path node whether it's the Flow Control node or not.\r
+\r
+ @param[in] FlowControl The device path node to be checked.\r
+ \r
+ @retval TRUE It's the Flow Control node.\r
+ @retval FALSE It's not.\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
+ Check the device path node whether it contains Flow Control node or not.\r
+\r
+ @param[in] DevicePath The device path to be checked.\r
+ \r
+ @retval TRUE It contains the Flow Control node.\r
+ @retval FALSE It doesn't.\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
+\r
+ return FALSE;\r
+}\r
+\r
/**\r
The user Entry Point for module IsaSerial. The user code starts with this function.\r
\r
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
EFI_ISA_IO_PROTOCOL *IsaIo;\r
UART_DEVICE_PATH *UartNode;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControlNode;\r
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
+ UINTN EntryCount;\r
+ UINTN Index;\r
\r
//\r
// Check RemainingDevicePath validation\r
if ((UartNode->DataBits >= 6) && (UartNode->DataBits <= 8) && (UartNode->StopBits == OneFiveStopBits)) {\r
goto Error;\r
}\r
- \r
- Status = EFI_SUCCESS;\r
+\r
+ FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (UartNode);\r
+ if (IsUartFlowControlNode (FlowControlNode)) {\r
+ //\r
+ // If the second node is Flow Control Node,\r
+ // return error when it request other than hardware flow control.\r
+ //\r
+ if ((ReadUnaligned32 (&FlowControlNode->FlowControlMap) & ~UART_FLOW_CONTROL_HARDWARE) != 0) {\r
+ goto Error;\r
+ }\r
+ }\r
}\r
}\r
\r
EFI_OPEN_PROTOCOL_BY_DRIVER\r
);\r
if (Status == EFI_ALREADY_STARTED) {\r
- return EFI_SUCCESS;\r
+ if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {\r
+ //\r
+ // If RemainingDevicePath is NULL or is the End of Device Path Node\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // When the driver has produced device path with flow control node but RemainingDevicePath only contains UART node,\r
+ // return unsupported, and vice versa.\r
+ //\r
+ Status = gBS->OpenProtocolInformation (\r
+ Controller,\r
+ &gEfiIsaIoProtocolGuid,\r
+ &OpenInfoBuffer,\r
+ &EntryCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ 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
+ (ContainsFlowControl (RemainingDevicePath) ^ ContainsFlowControl (DevicePath))) {\r
+ Status = EFI_UNSUPPORTED;\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ FreePool (OpenInfoBuffer);\r
+ return Status;\r
}\r
\r
if (EFI_ERROR (Status)) {\r
EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
UINTN EntryCount;\r
EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
- UART_DEVICE_PATH *UartNode;\r
+ UART_DEVICE_PATH *Uart;\r
+ UINT32 FlowControlMap;\r
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;\r
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
+ UINT32 Control;\r
\r
SerialDevice = NULL;\r
//\r
EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
);\r
if (!EFI_ERROR (Status)) {\r
- UartNode = (UART_DEVICE_PATH *) RemainingDevicePath;\r
+ Uart = (UART_DEVICE_PATH *) RemainingDevicePath;\r
Status = SerialIo->SetAttributes (\r
SerialIo,\r
- UartNode->BaudRate,\r
+ Uart->BaudRate,\r
SerialIo->Mode->ReceiveFifoDepth,\r
SerialIo->Mode->Timeout,\r
- (EFI_PARITY_TYPE) UartNode->Parity,\r
- UartNode->DataBits,\r
- (EFI_STOP_BITS_TYPE) UartNode->StopBits\r
+ (EFI_PARITY_TYPE) Uart->Parity,\r
+ Uart->DataBits,\r
+ (EFI_STOP_BITS_TYPE) Uart->StopBits\r
);\r
+\r
+ FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);\r
+ if (!EFI_ERROR (Status) && IsUartFlowControlNode (FlowControl)) {\r
+ Status = SerialIo->GetControl (SerialIo, &Control);\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 the bits that are not allowed to pass to SetControl\r
+ //\r
+ Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |\r
+ EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | 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
SerialDevice->SerialIo.Mode = &(SerialDevice->SerialMode);\r
SerialDevice->IsaIo = IsaIo;\r
SerialDevice->ParentDevicePath = ParentDevicePath;\r
+ FlowControl = NULL;\r
+ FlowControlMap = 0;\r
\r
//\r
// Check if RemainingDevicePath is NULL, \r
// that we can support.\r
//\r
CopyMem (&SerialDevice->UartDevicePath, RemainingDevicePath, sizeof (UART_DEVICE_PATH));\r
+ FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (RemainingDevicePath);\r
+ if (IsUartFlowControlNode (FlowControl)) {\r
+ FlowControlMap = ReadUnaligned32 (&FlowControl->FlowControlMap);\r
+ } else {\r
+ FlowControl = NULL;\r
+ }\r
}\r
\r
AddName (SerialDevice, IsaIo);\r
SerialDevice->BaseAddress = (UINT16) SerialDevice->IsaIo->ResourceList->ResourceItem[Index].StartRange;\r
}\r
}\r
+ \r
+ SerialDevice->HardwareFlowControl = (BOOLEAN) (FlowControlMap == UART_FLOW_CONTROL_HARDWARE);\r
+\r
//\r
// Report status code the serial present\r
//\r
\r
//\r
// Build the device path by appending the UART node to the ParentDevicePath.\r
- //The Uart setings are zero here, since SetAttribute() will update them to match \r
+ // The Uart setings are zero here, since SetAttribute() will update them to match \r
// the default setings.\r
//\r
SerialDevice->DevicePath = AppendDevicePathNode (\r
ParentDevicePath,\r
- (EFI_DEVICE_PATH_PROTOCOL *)&SerialDevice->UartDevicePath\r
+ (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath\r
);\r
+ //\r
+ // Only produce the Flow Control node when remaining device path has it\r
+ //\r
+ if (FlowControl != NULL) {\r
+ TempDevicePath = SerialDevice->DevicePath;\r
+ if (TempDevicePath != NULL) {\r
+ SerialDevice->DevicePath = AppendDevicePathNode (\r
+ TempDevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) FlowControl\r
+ );\r
+ FreePool (TempDevicePath);\r
+ }\r
+ }\r
if (SerialDevice->DevicePath == NULL) {\r
- Status = EFI_DEVICE_ERROR;\r
+ Status = EFI_OUT_OF_RESOURCES;\r
goto Error;\r
}\r
\r
SERIAL_PORT_MCR Mcr;\r
SERIAL_PORT_FCR Fcr;\r
EFI_TPL Tpl;\r
+ UINT32 Control;\r
\r
SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
\r
//\r
// Go set the current control bits\r
//\r
+ Control = 0;\r
+ if (SerialDevice->HardwareFlowControl) {\r
+ Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
+ }\r
+ if (SerialDevice->SoftwareLoopbackEnable) {\r
+ Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;\r
+ }\r
Status = This->SetControl (\r
This,\r
- This->Mode->ControlMask\r
+ Control\r
);\r
\r
if (EFI_ERROR (Status)) {\r
UINT32 Divisor;\r
UINT32 Remained;\r
SERIAL_PORT_LCR Lcr;\r
- EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
+ UART_DEVICE_PATH *Uart;\r
EFI_TPL Tpl;\r
\r
SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
SerialDevice->UartDevicePath.Parity = (UINT8) Parity;\r
SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits;\r
\r
- NewDevicePath = AppendDevicePathNode (\r
- SerialDevice->ParentDevicePath,\r
- (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath\r
- );\r
- if (NewDevicePath == NULL) {\r
- gBS->RestoreTPL (Tpl);\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
+ Status = EFI_SUCCESS;\r
if (SerialDevice->Handle != NULL) {\r
+ Uart = (UART_DEVICE_PATH *) (\r
+ (UINTN) SerialDevice->DevicePath\r
+ + GetDevicePathSize (SerialDevice->ParentDevicePath)\r
+ - END_DEVICE_PATH_LENGTH\r
+ );\r
+ CopyMem (Uart, &SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH));\r
Status = gBS->ReinstallProtocolInterface (\r
SerialDevice->Handle,\r
&gEfiDevicePathProtocolGuid,\r
SerialDevice->DevicePath,\r
- NewDevicePath\r
+ SerialDevice->DevicePath\r
);\r
- if (EFI_ERROR (Status)) {\r
- gBS->RestoreTPL (Tpl);\r
- return Status;\r
- }\r
- }\r
-\r
- if (SerialDevice->DevicePath != NULL) {\r
- gBS->FreePool (SerialDevice->DevicePath);\r
}\r
\r
- SerialDevice->DevicePath = NewDevicePath;\r
-\r
gBS->RestoreTPL (Tpl);\r
\r
- return EFI_SUCCESS;\r
+ return Status;\r
}\r
\r
/**\r
IN UINT32 Control\r
)\r
{\r
- SERIAL_DEV *SerialDevice;\r
- SERIAL_PORT_MCR Mcr;\r
- EFI_TPL Tpl;\r
+ SERIAL_DEV *SerialDevice;\r
+ SERIAL_PORT_MCR Mcr;\r
+ EFI_TPL Tpl;\r
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;\r
+ EFI_STATUS Status;\r
\r
//\r
// The control bits that can be set are :\r
// EFI_SERIAL_REQUEST_TO_SEND: 0x0002 // WO\r
// EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000 // RW\r
// EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000 // RW\r
+ // EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE: 0x4000 // RW\r
//\r
SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
\r
//\r
// first determine the parameter is invalid\r
//\r
- if ((Control & 0xffff8ffc) != 0) {\r
+ if (Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |\r
+ EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE | \r
+ EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) {\r
return EFI_UNSUPPORTED;\r
}\r
\r
SerialDevice->SoftwareLoopbackEnable = TRUE;\r
}\r
\r
+ Status = EFI_SUCCESS;\r
+ if (SerialDevice->Handle != NULL) {\r
+ FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) (\r
+ (UINTN) SerialDevice->DevicePath\r
+ + GetDevicePathSize (SerialDevice->ParentDevicePath)\r
+ - END_DEVICE_PATH_LENGTH\r
+ + sizeof (UART_DEVICE_PATH)\r
+ );\r
+ if (IsUartFlowControlNode (FlowControl) &&\r
+ ((ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) ^ SerialDevice->HardwareFlowControl)) {\r
+ //\r
+ // Flow Control setting is changed, need to reinstall device path protocol\r
+ //\r
+ WriteUnaligned32 (&FlowControl->FlowControlMap, SerialDevice->HardwareFlowControl ? UART_FLOW_CONTROL_HARDWARE : 0);\r
+ Status = gBS->ReinstallProtocolInterface (\r
+ SerialDevice->Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ SerialDevice->DevicePath,\r
+ SerialDevice->DevicePath\r
+ );\r
+ }\r
+ }\r
+\r
gBS->RestoreTPL (Tpl);\r
\r
- return EFI_SUCCESS;\r
+ return Status;\r
}\r
\r
/**\r