Home | History | Annotate | Download | only in SerialIoLib
      1 /** @file
      2   UART Serial Port library functions
      3 
      4   Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include <Base.h>
     16 #include <Library/IoLib.h>
     17 #include <Library/SerialPortLib.h>
     18 
     19 //---------------------------------------------
     20 // UART Register Offsets
     21 //---------------------------------------------
     22 #define BAUD_LOW_OFFSET         0x00
     23 #define BAUD_HIGH_OFFSET        0x01
     24 #define IER_OFFSET              0x01
     25 #define LCR_SHADOW_OFFSET       0x01
     26 #define FCR_SHADOW_OFFSET       0x02
     27 #define IR_CONTROL_OFFSET       0x02
     28 #define FCR_OFFSET              0x02
     29 #define EIR_OFFSET              0x02
     30 #define BSR_OFFSET              0x03
     31 #define LCR_OFFSET              0x03
     32 #define MCR_OFFSET              0x04
     33 #define LSR_OFFSET              0x05
     34 #define MSR_OFFSET              0x06
     35 
     36 //---------------------------------------------
     37 // UART Register Bit Defines
     38 //---------------------------------------------
     39 #define LSR_TXRDY               0x20
     40 #define LSR_RXDA                0x01
     41 #define DLAB                    0x01
     42 #define MCR_DTRC                0x01
     43 #define MCR_RTS                 0x02
     44 #define MSR_CTS                 0x10
     45 #define MSR_DSR                 0x20
     46 #define MSR_RI                  0x40
     47 #define MSR_DCD                 0x80
     48 
     49 //---------------------------------------------
     50 // UART Settings
     51 //---------------------------------------------
     52 UINT16  gUartBase = 0x3F8;
     53 UINTN   gBps      = 115200;
     54 UINT8   gData     = 8;
     55 UINT8   gStop     = 1;
     56 UINT8   gParity   = 0;
     57 UINT8   gBreakSet = 0;
     58 
     59 /**
     60   Initialize the serial device hardware.
     61 
     62   If no initialization is required, then return RETURN_SUCCESS.
     63   If the serial device was successfuly initialized, then return RETURN_SUCCESS.
     64   If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
     65 
     66   @retval RETURN_SUCCESS        The serial device was initialized.
     67   @retval RETURN_DEVICE_ERROR   The serail device could not be initialized.
     68 
     69 **/
     70 RETURN_STATUS
     71 EFIAPI
     72 SerialPortInitialize (
     73   VOID
     74   )
     75 {
     76   UINTN  Divisor;
     77   UINT8  OutputData;
     78   UINT8  Data;
     79 
     80   //
     81   // Map 5..8 to 0..3
     82   //
     83   Data = (UINT8) (gData - (UINT8) 5);
     84 
     85   //
     86   // Calculate divisor for baud generator
     87   //
     88   Divisor = 115200 / gBps;
     89 
     90   //
     91   // Set communications format
     92   //
     93   OutputData = (UINT8) ((DLAB << 7) | (gBreakSet << 6) | (gParity << 3) | (gStop << 2) | Data);
     94   IoWrite8 ((UINTN) (gUartBase + LCR_OFFSET), OutputData);
     95 
     96   //
     97   // Configure baud rate
     98   //
     99   IoWrite8 ((UINTN) (gUartBase + BAUD_HIGH_OFFSET), (UINT8) (Divisor >> 8));
    100   IoWrite8 ((UINTN) (gUartBase + BAUD_LOW_OFFSET), (UINT8) (Divisor & 0xff));
    101 
    102   //
    103   // Switch back to bank 0
    104   //
    105   OutputData = (UINT8) ((~DLAB << 7) | (gBreakSet << 6) | (gParity << 3) | (gStop << 2) | Data);
    106   IoWrite8 ((UINTN) (gUartBase + LCR_OFFSET), OutputData);
    107 
    108   return RETURN_SUCCESS;
    109 }
    110 
    111 /**
    112   Write data from buffer to serial device.
    113 
    114   Writes NumberOfBytes data bytes from Buffer to the serial device.
    115   The number of bytes actually written to the serial device is returned.
    116   If the return value is less than NumberOfBytes, then the write operation failed.
    117 
    118   If Buffer is NULL, then ASSERT().
    119 
    120   If NumberOfBytes is zero, then return 0.
    121 
    122   @param  Buffer           Pointer to the data buffer to be written.
    123   @param  NumberOfBytes    Number of bytes to written to the serial device.
    124 
    125   @retval 0                NumberOfBytes is 0.
    126   @retval >0               The number of bytes written to the serial device.
    127                            If this value is less than NumberOfBytes, then the write operation failed.
    128 
    129 **/
    130 UINTN
    131 EFIAPI
    132 SerialPortWrite (
    133   IN UINT8     *Buffer,
    134   IN UINTN     NumberOfBytes
    135 )
    136 {
    137   UINTN  Result;
    138   UINT8  Data;
    139 
    140   if (Buffer == NULL) {
    141     return 0;
    142   }
    143 
    144   Result = NumberOfBytes;
    145 
    146   while ((NumberOfBytes--) != 0) {
    147     //
    148     // Wait for the serail port to be ready.
    149     //
    150     do {
    151       Data = IoRead8 ((UINT16) gUartBase + LSR_OFFSET);
    152     } while ((Data & LSR_TXRDY) == 0);
    153     IoWrite8 ((UINT16) gUartBase, *Buffer++);
    154   }
    155 
    156   return Result;
    157 }
    158 
    159 
    160 /**
    161   Reads data from a serial device into a buffer.
    162 
    163   @param  Buffer           Pointer to the data buffer to store the data read from the serial device.
    164   @param  NumberOfBytes    Number of bytes to read from the serial device.
    165 
    166   @retval 0                NumberOfBytes is 0.
    167   @retval >0               The number of bytes read from the serial device.
    168                            If this value is less than NumberOfBytes, then the read operation failed.
    169 
    170 **/
    171 UINTN
    172 EFIAPI
    173 SerialPortRead (
    174   OUT UINT8     *Buffer,
    175   IN  UINTN     NumberOfBytes
    176 )
    177 {
    178   UINTN  Result;
    179   UINT8  Data;
    180 
    181   if (NULL == Buffer) {
    182     return 0;
    183   }
    184 
    185   Result = NumberOfBytes;
    186 
    187   while ((NumberOfBytes--) != 0) {
    188     //
    189     // Wait for the serail port to be ready.
    190     //
    191     do {
    192       Data = IoRead8 ((UINT16) gUartBase + LSR_OFFSET);
    193     } while ((Data & LSR_RXDA) == 0);
    194 
    195     *Buffer++ = IoRead8 ((UINT16) gUartBase);
    196   }
    197 
    198   return Result;
    199 }
    200 
    201 /**
    202   Polls a serial device to see if there is any data waiting to be read.
    203 
    204   Polls aserial device to see if there is any data waiting to be read.
    205   If there is data waiting to be read from the serial device, then TRUE is returned.
    206   If there is no data waiting to be read from the serial device, then FALSE is returned.
    207 
    208   @retval TRUE             Data is waiting to be read from the serial device.
    209   @retval FALSE            There is no data waiting to be read from the serial device.
    210 
    211 **/
    212 BOOLEAN
    213 EFIAPI
    214 SerialPortPoll (
    215   VOID
    216   )
    217 {
    218   UINT8  Data;
    219 
    220   //
    221   // Read the serial port status.
    222   //
    223   Data = IoRead8 ((UINT16) gUartBase + LSR_OFFSET);
    224 
    225   return (BOOLEAN) ((Data & LSR_RXDA) != 0);
    226 }
    227 
    228 /**
    229   Sets the control bits on a serial device.
    230 
    231   @param Control                Sets the bits of Control that are settable.
    232 
    233   @retval RETURN_SUCCESS        The new control bits were set on the serial device.
    234   @retval RETURN_UNSUPPORTED    The serial device does not support this operation.
    235   @retval RETURN_DEVICE_ERROR   The serial device is not functioning correctly.
    236 
    237 **/
    238 RETURN_STATUS
    239 EFIAPI
    240 SerialPortSetControl (
    241   IN UINT32 Control
    242   )
    243 {
    244   UINT8 Mcr;
    245 
    246   //
    247   // First determine the parameter is invalid.
    248   //
    249   if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY))) != 0) {
    250     return RETURN_UNSUPPORTED;
    251   }
    252 
    253   //
    254   // Read the Modem Control Register.
    255   //
    256   Mcr = IoRead8 ((UINT16) gUartBase + MCR_OFFSET);
    257   Mcr &= (~(MCR_DTRC | MCR_RTS));
    258 
    259   if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
    260     Mcr |= MCR_DTRC;
    261   }
    262 
    263   if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
    264     Mcr |= MCR_RTS;
    265   }
    266 
    267   //
    268   // Write the Modem Control Register.
    269   //
    270   IoWrite8 ((UINT16) gUartBase + MCR_OFFSET, Mcr);
    271 
    272   return RETURN_SUCCESS;
    273 }
    274 
    275 /**
    276   Retrieve the status of the control bits on a serial device.
    277 
    278   @param Control                A pointer to return the current control signals from the serial device.
    279 
    280   @retval RETURN_SUCCESS        The control bits were read from the serial device.
    281   @retval RETURN_UNSUPPORTED    The serial device does not support this operation.
    282   @retval RETURN_DEVICE_ERROR   The serial device is not functioning correctly.
    283 
    284 **/
    285 RETURN_STATUS
    286 EFIAPI
    287 SerialPortGetControl (
    288   OUT UINT32 *Control
    289   )
    290 {
    291   UINT8 Msr;
    292   UINT8 Mcr;
    293   UINT8 Lsr;
    294 
    295   *Control = 0;
    296 
    297   //
    298   // Read the Modem Status Register.
    299   //
    300   Msr = IoRead8 ((UINT16) gUartBase + MSR_OFFSET);
    301 
    302   if ((Msr & MSR_CTS) == MSR_CTS) {
    303     *Control |= EFI_SERIAL_CLEAR_TO_SEND;
    304   }
    305 
    306   if ((Msr & MSR_DSR) == MSR_DSR) {
    307     *Control |= EFI_SERIAL_DATA_SET_READY;
    308   }
    309 
    310   if ((Msr & MSR_RI) == MSR_RI) {
    311     *Control |= EFI_SERIAL_RING_INDICATE;
    312   }
    313 
    314   if ((Msr & MSR_DCD) == MSR_DCD) {
    315     *Control |= EFI_SERIAL_CARRIER_DETECT;
    316   }
    317 
    318   //
    319   // Read the Modem Control Register.
    320   //
    321   Mcr = IoRead8 ((UINT16) gUartBase + MCR_OFFSET);
    322 
    323   if ((Mcr & MCR_DTRC) == MCR_DTRC) {
    324     *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
    325   }
    326 
    327   if ((Mcr & MCR_RTS) == MCR_RTS) {
    328     *Control |= EFI_SERIAL_REQUEST_TO_SEND;
    329   }
    330 
    331   //
    332   // Read the Line Status Register.
    333   //
    334   Lsr = IoRead8 ((UINT16) gUartBase + LSR_OFFSET);
    335 
    336   if ((Lsr & LSR_TXRDY) == LSR_TXRDY) {
    337     *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
    338   }
    339 
    340   if ((Lsr & LSR_RXDA) == 0) {
    341     *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
    342   }
    343 
    344   return RETURN_SUCCESS;
    345 }
    346 
    347 /**
    348   Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,
    349   data bits, and stop bits on a serial device.
    350 
    351   @param BaudRate           The requested baud rate. A BaudRate value of 0 will use the
    352                             device's default interface speed.
    353                             On output, the value actually set.
    354   @param ReveiveFifoDepth   The requested depth of the FIFO on the receive side of the
    355                             serial interface. A ReceiveFifoDepth value of 0 will use
    356                             the device's default FIFO depth.
    357                             On output, the value actually set.
    358   @param Timeout            The requested time out for a single character in microseconds.
    359                             This timeout applies to both the transmit and receive side of the
    360                             interface. A Timeout value of 0 will use the device's default time
    361                             out value.
    362                             On output, the value actually set.
    363   @param Parity             The type of parity to use on this serial device. A Parity value of
    364                             DefaultParity will use the device's default parity value.
    365                             On output, the value actually set.
    366   @param DataBits           The number of data bits to use on the serial device. A DataBits
    367                             vaule of 0 will use the device's default data bit setting.
    368                             On output, the value actually set.
    369   @param StopBits           The number of stop bits to use on this serial device. A StopBits
    370                             value of DefaultStopBits will use the device's default number of
    371                             stop bits.
    372                             On output, the value actually set.
    373 
    374   @retval RETURN_SUCCESS            The new attributes were set on the serial device.
    375   @retval RETURN_UNSUPPORTED        The serial device does not support this operation.
    376   @retval RETURN_INVALID_PARAMETER  One or more of the attributes has an unsupported value.
    377   @retval RETURN_DEVICE_ERROR       The serial device is not functioning correctly.
    378 
    379 **/
    380 RETURN_STATUS
    381 EFIAPI
    382 SerialPortSetAttributes (
    383   IN OUT UINT64             *BaudRate,
    384   IN OUT UINT32             *ReceiveFifoDepth,
    385   IN OUT UINT32             *Timeout,
    386   IN OUT EFI_PARITY_TYPE    *Parity,
    387   IN OUT UINT8              *DataBits,
    388   IN OUT EFI_STOP_BITS_TYPE *StopBits
    389   )
    390 {
    391   UINTN Divisor;
    392   UINT8 OutputData;
    393   UINT8 LcrData;
    394   UINT8 LcrParity;
    395   UINT8 LcrStop;
    396 
    397   //
    398   // Check for default settings and fill in actual values.
    399   //
    400   if (*BaudRate == 0) {
    401     *BaudRate = gBps;
    402   }
    403 
    404   if (*DataBits == 0) {
    405     *DataBits = gData;
    406   }
    407 
    408   if (*Parity == DefaultParity) {
    409     *Parity = NoParity;
    410   }
    411 
    412   if (*StopBits == DefaultStopBits) {
    413     *StopBits = OneStopBit;
    414   }
    415 
    416   if ((*DataBits < 5) || (*DataBits > 8)) {
    417     return RETURN_INVALID_PARAMETER;
    418   }
    419 
    420   //
    421   // Map 5..8 to 0..3
    422   //
    423   LcrData = (UINT8) (*DataBits - (UINT8) 5);
    424 
    425   switch (*Parity) {
    426     case NoParity:
    427       LcrParity = 0;
    428       break;
    429 
    430     case EvenParity:
    431       LcrParity = 3;
    432       break;
    433 
    434     case OddParity:
    435       LcrParity = 1;
    436       break;
    437 
    438     case SpaceParity:
    439       LcrParity = 7;
    440       break;
    441 
    442     case MarkParity:
    443       LcrParity = 5;
    444       break;
    445 
    446     default:
    447       return RETURN_INVALID_PARAMETER;
    448   }
    449 
    450   switch (*StopBits) {
    451     case OneStopBit:
    452       LcrStop = 0;
    453       break;
    454 
    455     case OneFiveStopBits:
    456     case TwoStopBits:
    457       LcrStop = 1;
    458       break;
    459 
    460     default:
    461       return RETURN_INVALID_PARAMETER;
    462   }
    463 
    464   //
    465   // Calculate divisor for baud generator
    466   //
    467   Divisor = 115200 / (UINTN) *BaudRate;
    468 
    469   //
    470   // Set communications format
    471   //
    472   OutputData = (UINT8) ((DLAB << 7) | (gBreakSet << 6) | (LcrParity << 3) | (LcrStop << 2) | LcrData);
    473   IoWrite8 ((UINTN) (gUartBase + LCR_OFFSET), OutputData);
    474 
    475   //
    476   // Configure baud rate
    477   //
    478   IoWrite8 ((UINTN) (gUartBase + BAUD_HIGH_OFFSET), (UINT8) (Divisor >> 8));
    479   IoWrite8 ((UINTN) (gUartBase + BAUD_LOW_OFFSET), (UINT8) (Divisor & 0xff));
    480 
    481   //
    482   // Switch back to bank 0
    483   //
    484   OutputData = (UINT8) ((~DLAB << 7) | (gBreakSet << 6) | (LcrParity << 3) | (LcrStop << 2) | LcrData);
    485   IoWrite8 ((UINTN) (gUartBase + LCR_OFFSET), OutputData);
    486 
    487   return RETURN_SUCCESS;
    488 }
    489 
    490