]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg BaseSerialPortLib16550:Implement Get(Set)Control/SetAttributes
authorStar Zeng <star.zeng@intel.com>
Thu, 26 Nov 2015 08:47:44 +0000 (08:47 +0000)
committerlzeng14 <lzeng14@Edk2>
Thu, 26 Nov 2015 08:47:44 +0000 (08:47 +0000)
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Star Zeng <star.zeng@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18965 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c

index 5b6608d4008270c75c297e15494ee3b33ef5b11e..f4fc31913bea7dca3d25ef5b14f343b07562bff5 100644 (file)
@@ -40,6 +40,7 @@
 #define R_UART_LCR            3\r
 #define   B_UART_LCR_DLAB     BIT7\r
 #define R_UART_MCR            4\r
+#define   B_UART_MCR_DTRC     BIT0\r
 #define   B_UART_MCR_RTS      BIT1\r
 #define R_UART_LSR            5\r
 #define   B_UART_LSR_RXRDY    BIT0\r
@@ -48,6 +49,8 @@
 #define R_UART_MSR            6\r
 #define   B_UART_MSR_CTS      BIT4\r
 #define   B_UART_MSR_DSR      BIT5\r
+#define   B_UART_MSR_RI       BIT6\r
+#define   B_UART_MSR_DCD      BIT7\r
 \r
 //\r
 // 4-byte structure for each PCI node in PcdSerialPciDeviceInfo\r
@@ -761,3 +764,337 @@ SerialPortPoll (
   \r
   return FALSE;\r
 }\r
+\r
+/**\r
+  Sets the control bits on a serial device.\r
+\r
+  @param Control                Sets the bits of Control that are settable.\r
+\r
+  @retval RETURN_SUCCESS        The new control bits were set on the serial device.\r
+  @retval RETURN_UNSUPPORTED    The serial device does not support this operation.\r
+  @retval RETURN_DEVICE_ERROR   The serial device is not functioning correctly.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+SerialPortSetControl (\r
+  IN UINT32 Control\r
+  )\r
+{\r
+  UINTN SerialRegisterBase;\r
+  UINT8 Mcr;\r
+\r
+  //\r
+  // First determine the parameter is invalid.\r
+  //\r
+  if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |\r
+                    EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  SerialRegisterBase = GetSerialRegisterBase ();\r
+  if (SerialRegisterBase ==0) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Read the Modem Control Register.\r
+  //\r
+  Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);\r
+  Mcr &= (~(B_UART_MCR_DTRC | B_UART_MCR_RTS));\r
+\r
+  if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {\r
+    Mcr |= B_UART_MCR_DTRC;\r
+  }\r
+\r
+  if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {\r
+    Mcr |= B_UART_MCR_RTS;\r
+  }\r
+\r
+  //\r
+  // Write the Modem Control Register.\r
+  //\r
+  SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+  Retrieve the status of the control bits on a serial device.\r
+\r
+  @param Control                A pointer to return the current control signals from the serial device.\r
+\r
+  @retval RETURN_SUCCESS        The control bits were read from the serial device.\r
+  @retval RETURN_UNSUPPORTED    The serial device does not support this operation.\r
+  @retval RETURN_DEVICE_ERROR   The serial device is not functioning correctly.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+SerialPortGetControl (\r
+  OUT UINT32 *Control\r
+  )\r
+{\r
+  UINTN SerialRegisterBase;\r
+  UINT8 Msr;\r
+  UINT8 Mcr;\r
+  UINT8 Lsr;\r
+\r
+  SerialRegisterBase = GetSerialRegisterBase ();\r
+  if (SerialRegisterBase ==0) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  *Control = 0;\r
+\r
+  //\r
+  // Read the Modem Status Register.\r
+  //\r
+  Msr = SerialPortReadRegister (SerialRegisterBase, R_UART_MSR);\r
+\r
+  if ((Msr & B_UART_MSR_CTS) == B_UART_MSR_CTS) {\r
+    *Control |= EFI_SERIAL_CLEAR_TO_SEND;\r
+  }\r
+\r
+  if ((Msr & B_UART_MSR_DSR) == B_UART_MSR_DSR) {\r
+    *Control |= EFI_SERIAL_DATA_SET_READY;\r
+  }\r
+\r
+  if ((Msr & B_UART_MSR_RI) == B_UART_MSR_RI) {\r
+    *Control |= EFI_SERIAL_RING_INDICATE;\r
+  }\r
+\r
+  if ((Msr & B_UART_MSR_DCD) == B_UART_MSR_DCD) {\r
+    *Control |= EFI_SERIAL_CARRIER_DETECT;\r
+  }\r
+\r
+  //\r
+  // Read the Modem Control Register.\r
+  //\r
+  Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);\r
+\r
+  if ((Mcr & B_UART_MCR_DTRC) == B_UART_MCR_DTRC) {\r
+    *Control |= EFI_SERIAL_DATA_TERMINAL_READY;\r
+  }\r
+\r
+  if ((Mcr & B_UART_MCR_RTS) == B_UART_MCR_RTS) {\r
+    *Control |= EFI_SERIAL_REQUEST_TO_SEND;\r
+  }\r
+\r
+  if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
+    *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
+  }\r
+\r
+  //\r
+  // Read the Line Status Register.\r
+  //\r
+  Lsr = SerialPortReadRegister (SerialRegisterBase, R_UART_LSR);\r
+\r
+  if ((Lsr & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) == (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) {\r
+    *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;\r
+  }\r
+\r
+  if ((Lsr & B_UART_LSR_RXRDY) == 0) {\r
+    *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;\r
+  }\r
+\r
+  return RETURN_SUCCESS;\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 BaudRate           The requested baud rate. A BaudRate value of 0 will use the\r
+                            device's default interface speed.\r
+                            On output, the value actually set.\r
+  @param ReveiveFifoDepth   The requested depth of the FIFO on the receive side of the\r
+                            serial interface. A ReceiveFifoDepth value of 0 will use\r
+                            the device's default FIFO depth.\r
+                            On output, the value actually set.\r
+  @param Timeout            The requested time out for a single character in microseconds.\r
+                            This timeout applies to both the transmit and receive side of the\r
+                            interface. A Timeout value of 0 will use the device's default time\r
+                            out value.\r
+                            On output, the value actually set.\r
+  @param Parity             The type of parity to use on this serial device. A Parity value of\r
+                            DefaultParity will use the device's default parity value.\r
+                            On output, the value actually set.\r
+  @param DataBits           The number of data bits to use on the serial device. A DataBits\r
+                            vaule of 0 will use the device's default data bit setting.\r
+                            On output, the value actually set.\r
+  @param StopBits           The number of stop bits to use on this serial device. A StopBits\r
+                            value of DefaultStopBits will use the device's default number of\r
+                            stop bits.\r
+                            On output, the value actually set.\r
+\r
+  @retval RETURN_SUCCESS            The new attributes were set on the serial device.\r
+  @retval RETURN_UNSUPPORTED        The serial device does not support this operation.\r
+  @retval RETURN_INVALID_PARAMETER  One or more of the attributes has an unsupported value.\r
+  @retval RETURN_DEVICE_ERROR       The serial device is not functioning correctly.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+SerialPortSetAttributes (\r
+  IN OUT UINT64             *BaudRate,\r
+  IN OUT UINT32             *ReceiveFifoDepth,\r
+  IN OUT UINT32             *Timeout,\r
+  IN OUT EFI_PARITY_TYPE    *Parity,\r
+  IN OUT UINT8              *DataBits,\r
+  IN OUT EFI_STOP_BITS_TYPE *StopBits\r
+  )\r
+{\r
+  UINTN     SerialRegisterBase;\r
+  UINT32    SerialBaudRate;\r
+  UINTN     Divisor;\r
+  UINT8     Lcr;\r
+  UINT8     LcrData;\r
+  UINT8     LcrParity;\r
+  UINT8     LcrStop;\r
+\r
+  SerialRegisterBase = GetSerialRegisterBase ();\r
+  if (SerialRegisterBase ==0) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Check for default settings and fill in actual values.\r
+  //\r
+  if (*BaudRate == 0) {\r
+    *BaudRate = PcdGet32 (PcdSerialBaudRate);\r
+  }\r
+  SerialBaudRate = (UINT32) *BaudRate;\r
+\r
+  if (*DataBits == 0) {\r
+    LcrData = (UINT8) (PcdGet8 (PcdSerialLineControl) & 0x3);\r
+    *DataBits = LcrData + 5;\r
+  } else {\r
+    if ((*DataBits < 5) || (*DataBits > 8)) {\r
+      return RETURN_INVALID_PARAMETER;\r
+    }\r
+    //\r
+    // Map 5..8 to 0..3\r
+    //\r
+    LcrData = (UINT8) (*DataBits - (UINT8) 5);\r
+  }\r
+\r
+  if (*Parity == DefaultParity) {\r
+    LcrParity = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 3) & 0x7);\r
+    switch (LcrParity) {\r
+      case 0:\r
+        *Parity = NoParity;\r
+        break;\r
+\r
+      case 3:\r
+        *Parity = EvenParity;\r
+        break;\r
+\r
+      case 1:\r
+        *Parity = OddParity;\r
+        break;\r
+\r
+      case 7:\r
+        *Parity = SpaceParity;\r
+        break;\r
+\r
+      case 5:\r
+        *Parity = MarkParity;\r
+        break;\r
+\r
+      default:\r
+        break;\r
+    }\r
+  } else {\r
+    if ((*Parity < NoParity) || (*Parity > SpaceParity)) {\r
+      return RETURN_INVALID_PARAMETER;\r
+    }\r
+    switch (*Parity) {\r
+      case NoParity:\r
+        LcrParity = 0;\r
+        break;\r
+\r
+      case EvenParity:\r
+        LcrParity = 3;\r
+        break;\r
+\r
+      case OddParity:\r
+        LcrParity = 1;\r
+        break;\r
+\r
+      case SpaceParity:\r
+        LcrParity = 7;\r
+        break;\r
+\r
+      case MarkParity:\r
+        LcrParity = 5;\r
+        break;\r
+\r
+      default:\r
+        break;\r
+    }\r
+  }\r
+\r
+  if (*StopBits == DefaultStopBits) {\r
+    LcrStop = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 2) & 0x1);\r
+    switch (LcrStop) {\r
+      case 0:\r
+        *StopBits = OneStopBit;\r
+        break;\r
+\r
+      case 1:\r
+        if (*DataBits == 5) {\r
+          *StopBits = OneFiveStopBits;\r
+        } else {\r
+          *StopBits = TwoStopBits;\r
+        }\r
+        break;\r
+\r
+      default:\r
+        break;\r
+    }\r
+  } else {\r
+    if ((*StopBits < OneStopBit) || (*StopBits > TwoStopBits)) {\r
+      return RETURN_INVALID_PARAMETER;\r
+    }\r
+    switch (*StopBits) {\r
+      case OneStopBit:\r
+        LcrStop = 0;\r
+        break;\r
+\r
+      case OneFiveStopBits:\r
+      case TwoStopBits:\r
+        LcrStop = 1;\r
+        break;\r
+\r
+      default:\r
+        break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Calculate divisor for baud generator\r
+  //    Ref_Clk_Rate / Baud_Rate / 16\r
+  //\r
+  Divisor = PcdGet32 (PcdSerialClockRate) / (SerialBaudRate * 16);\r
+  if ((PcdGet32 (PcdSerialClockRate) % (SerialBaudRate * 16)) >= SerialBaudRate * 8) {\r
+    Divisor++;\r
+  }\r
+\r
+  //\r
+  // Configure baud rate\r
+  //\r
+  SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);\r
+  SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8));\r
+  SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff));\r
+\r
+  //\r
+  // Clear DLAB and configure Data Bits, Parity, and Stop Bits.\r
+  // Strip reserved bits from line control value\r
+  //\r
+  Lcr = (UINT8) ((LcrParity << 3) | (LcrStop << 2) | LcrData);\r
+  SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8) (Lcr & 0x3F));\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
+\r