]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/Serial.c
1. IsaSerialIo driver was changed to produce the flow control device path node when...
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / IsaSerialDxe / Serial.c
index 04d6373592d41393bb9555d195baa0cc4860bc66..b8421122307e31aef795a042a285ea893b2658fd 100644 (file)
@@ -41,7 +41,7 @@ SERIAL_DEV  gSerialDevTempate = {
     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
@@ -86,6 +86,51 @@ SERIAL_DEV  gSerialDevTempate = {
   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
@@ -145,6 +190,11 @@ SerialControllerDriverSupported (
   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
@@ -192,8 +242,17 @@ SerialControllerDriverSupported (
       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
@@ -209,7 +268,45 @@ SerialControllerDriverSupported (
                   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
@@ -295,7 +392,11 @@ SerialControllerDriverStart (
   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
@@ -371,16 +472,35 @@ SerialControllerDriverStart (
                         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
@@ -412,6 +532,8 @@ SerialControllerDriverStart (
   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
@@ -426,6 +548,12 @@ SerialControllerDriverStart (
     // 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
@@ -435,6 +563,9 @@ SerialControllerDriverStart (
       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
@@ -456,15 +587,28 @@ SerialControllerDriverStart (
 \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
@@ -968,6 +1112,7 @@ IsaSerialReset (
   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
@@ -1039,9 +1184,16 @@ IsaSerialReset (
   //\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
@@ -1108,7 +1260,7 @@ IsaSerialSetAttributes (
   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
@@ -1347,37 +1499,25 @@ IsaSerialSetAttributes (
   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
@@ -1397,9 +1537,11 @@ IsaSerialSetControl (
   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
@@ -1407,13 +1549,16 @@ IsaSerialSetControl (
   //     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
@@ -1448,9 +1593,32 @@ IsaSerialSetControl (
     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