Home | History | Annotate | Download | only in PciSioSerialDxe
      1 /** @file
      2   SerialIo implementation for PCI or SIO UARTs.
      3 
      4 Copyright (c) 2006 - 2015, 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 "Serial.h"
     16 
     17 /**
     18   Skip the optional Controller device path node and return the
     19   pointer to the next device path node.
     20 
     21   @param DevicePath             Pointer to the device path.
     22   @param ContainsControllerNode Returns TRUE if the Controller device path exists.
     23   @param ControllerNumber       Returns the Controller Number if Controller device path exists.
     24 
     25   @return     Pointer to the next device path node.
     26 **/
     27 UART_DEVICE_PATH *
     28 SkipControllerDevicePathNode (
     29   EFI_DEVICE_PATH_PROTOCOL          *DevicePath,
     30   BOOLEAN                           *ContainsControllerNode,
     31   UINT32                            *ControllerNumber
     32   )
     33 {
     34   if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) &&
     35       (DevicePathSubType (DevicePath) == HW_CONTROLLER_DP)
     36       ) {
     37     if (ContainsControllerNode != NULL) {
     38       *ContainsControllerNode = TRUE;
     39     }
     40     if (ControllerNumber != NULL) {
     41       *ControllerNumber = ((CONTROLLER_DEVICE_PATH *) DevicePath)->ControllerNumber;
     42     }
     43     DevicePath = NextDevicePathNode (DevicePath);
     44   } else {
     45     if (ContainsControllerNode != NULL) {
     46       *ContainsControllerNode = FALSE;
     47     }
     48   }
     49   return (UART_DEVICE_PATH *) DevicePath;
     50 }
     51 
     52 /**
     53   Checks whether the UART parameters are valid and computes the Divisor.
     54 
     55   @param  ClockRate      The clock rate of the serial device used to verify
     56                          the BaudRate. Do not verify the BaudRate if it's 0.
     57   @param  BaudRate       The requested baudrate of the serial device.
     58   @param  DataBits       Number of databits used in serial device.
     59   @param  Parity         The type of parity used in serial device.
     60   @param  StopBits       Number of stopbits used in serial device.
     61   @param  Divisor        Return the divisor if ClockRate is not 0.
     62   @param  ActualBaudRate Return the actual supported baudrate without
     63                          exceeding BaudRate. NULL means baudrate degradation
     64                          is not allowed.
     65                          If the requested BaudRate is not supported, the routine
     66                          returns TRUE and the Actual Baud Rate when ActualBaudRate
     67                          is not NULL, returns FALSE when ActualBaudRate is NULL.
     68 
     69   @retval TRUE   The UART parameters are valid.
     70   @retval FALSE  The UART parameters are not valid.
     71 **/
     72 BOOLEAN
     73 VerifyUartParameters (
     74   IN     UINT32                  ClockRate,
     75   IN     UINT64                  BaudRate,
     76   IN     UINT8                   DataBits,
     77   IN     EFI_PARITY_TYPE         Parity,
     78   IN     EFI_STOP_BITS_TYPE      StopBits,
     79      OUT UINT64                  *Divisor,
     80      OUT UINT64                  *ActualBaudRate
     81   )
     82 {
     83   UINT64                     Remainder;
     84   UINT32                     ComputedBaudRate;
     85   UINT64                     ComputedDivisor;
     86   UINT64                     Percent;
     87 
     88   if ((DataBits < 5) || (DataBits > 8) ||
     89       (Parity < NoParity) || (Parity > SpaceParity) ||
     90       (StopBits < OneStopBit) || (StopBits > TwoStopBits) ||
     91       ((DataBits == 5) && (StopBits == TwoStopBits)) ||
     92       ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits))
     93       ) {
     94     return FALSE;
     95   }
     96 
     97   //
     98   // Do not verify the baud rate if clock rate is unknown (0).
     99   //
    100   if (ClockRate == 0) {
    101     return TRUE;
    102   }
    103 
    104   //
    105   // Compute divisor use to program the baud rate using a round determination
    106   // Divisor = ClockRate / 16 / BaudRate = ClockRate / (16 * BaudRate)
    107   //         = ClockRate / (BaudRate << 4)
    108   //
    109   ComputedDivisor = DivU64x64Remainder (ClockRate, LShiftU64 (BaudRate, 4), &Remainder);
    110   //
    111   // Round Divisor up by 1 if the Remainder is more than half (16 * BaudRate)
    112   // BaudRate * 16 / 2 = BaudRate * 8 = (BaudRate << 3)
    113   //
    114   if (Remainder >= LShiftU64 (BaudRate, 3)) {
    115     ComputedDivisor++;
    116   }
    117   //
    118   // If the computed divisor is larger than the maximum value that can be programmed
    119   // into the UART, then the requested baud rate can not be supported.
    120   //
    121   if (ComputedDivisor > MAX_UINT16) {
    122     return FALSE;
    123   }
    124 
    125   //
    126   // If the computed divisor is 0, then use a computed divisor of 1, which will select
    127   // the maximum supported baud rate.
    128   //
    129   if (ComputedDivisor == 0) {
    130     ComputedDivisor = 1;
    131   }
    132 
    133   //
    134   // Actual baud rate that the serial port will be programmed for
    135   // should be with in 4% of requested one.
    136   //
    137   ComputedBaudRate = ClockRate / ((UINT16) ComputedDivisor << 4);
    138   if (ComputedBaudRate == 0) {
    139     return FALSE;
    140   }
    141 
    142   Percent = DivU64x32 (MultU64x32 (BaudRate, 100), ComputedBaudRate);
    143   DEBUG ((EFI_D_INFO, "ClockRate = %d\n",  ClockRate));
    144   DEBUG ((EFI_D_INFO, "Divisor   = %ld\n", ComputedDivisor));
    145   DEBUG ((EFI_D_INFO, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate, ComputedBaudRate, Percent));
    146 
    147   //
    148   // If the requested BaudRate is not supported:
    149   //  Returns TRUE and the Actual Baud Rate when ActualBaudRate is not NULL;
    150   //  Returns FALSE when ActualBaudRate is NULL.
    151   //
    152   if ((Percent >= 96) && (Percent <= 104)) {
    153     if (ActualBaudRate != NULL) {
    154       *ActualBaudRate = BaudRate;
    155     }
    156     if (Divisor != NULL) {
    157       *Divisor = ComputedDivisor;
    158     }
    159     return TRUE;
    160   }
    161   if (ComputedBaudRate < BaudRate) {
    162     if (ActualBaudRate != NULL) {
    163       *ActualBaudRate = ComputedBaudRate;
    164     }
    165     if (Divisor != NULL) {
    166       *Divisor = ComputedDivisor;
    167     }
    168     return TRUE;
    169   }
    170 
    171   //
    172   // ActualBaudRate is higher than requested baud rate and more than 4%
    173   // higher than the requested value.  Increment Divisor if it is less
    174   // than MAX_UINT16 and computed baud rate with new divisor.
    175   //
    176   if (ComputedDivisor == MAX_UINT16) {
    177     return FALSE;
    178   }
    179   ComputedDivisor++;
    180   ComputedBaudRate = ClockRate / ((UINT16) ComputedDivisor << 4);
    181   if (ComputedBaudRate == 0) {
    182     return FALSE;
    183   }
    184 
    185   DEBUG ((EFI_D_INFO, "ClockRate = %d\n",  ClockRate));
    186   DEBUG ((EFI_D_INFO, "Divisor   = %ld\n", ComputedDivisor));
    187   DEBUG ((EFI_D_INFO, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate, ComputedBaudRate, Percent));
    188 
    189   if (ActualBaudRate != NULL) {
    190     *ActualBaudRate = ComputedBaudRate;
    191   }
    192   if (Divisor != NULL) {
    193     *Divisor = ComputedDivisor;
    194   }
    195   return TRUE;
    196 }
    197 
    198 /**
    199   Detect whether specific FIFO is full or not.
    200 
    201   @param Fifo    A pointer to the Data Structure SERIAL_DEV_FIFO
    202 
    203   @return whether specific FIFO is full or not
    204 **/
    205 BOOLEAN
    206 SerialFifoFull (
    207   IN SERIAL_DEV_FIFO *Fifo
    208   )
    209 {
    210   return (BOOLEAN) (((Fifo->Tail + 1) % SERIAL_MAX_FIFO_SIZE) == Fifo->Head);
    211 }
    212 
    213 /**
    214   Detect whether specific FIFO is empty or not.
    215 
    216   @param  Fifo    A pointer to the Data Structure SERIAL_DEV_FIFO
    217 
    218   @return whether specific FIFO is empty or not
    219 **/
    220 BOOLEAN
    221 SerialFifoEmpty (
    222   IN SERIAL_DEV_FIFO *Fifo
    223   )
    224 
    225 {
    226   return (BOOLEAN) (Fifo->Head == Fifo->Tail);
    227 }
    228 
    229 /**
    230   Add data to specific FIFO.
    231 
    232   @param Fifo                  A pointer to the Data Structure SERIAL_DEV_FIFO
    233   @param Data                  the data added to FIFO
    234 
    235   @retval EFI_SUCCESS           Add data to specific FIFO successfully
    236   @retval EFI_OUT_OF_RESOURCE   Failed to add data because FIFO is already full
    237 **/
    238 EFI_STATUS
    239 SerialFifoAdd (
    240   IN OUT SERIAL_DEV_FIFO *Fifo,
    241   IN     UINT8           Data
    242   )
    243 {
    244   //
    245   // if FIFO full can not add data
    246   //
    247   if (SerialFifoFull (Fifo)) {
    248     return EFI_OUT_OF_RESOURCES;
    249   }
    250   //
    251   // FIFO is not full can add data
    252   //
    253   Fifo->Data[Fifo->Tail] = Data;
    254   Fifo->Tail = (Fifo->Tail + 1) % SERIAL_MAX_FIFO_SIZE;
    255   return EFI_SUCCESS;
    256 }
    257 
    258 /**
    259   Remove data from specific FIFO.
    260 
    261   @param Fifo                  A pointer to the Data Structure SERIAL_DEV_FIFO
    262   @param Data                  the data removed from FIFO
    263 
    264   @retval EFI_SUCCESS           Remove data from specific FIFO successfully
    265   @retval EFI_OUT_OF_RESOURCE   Failed to remove data because FIFO is empty
    266 
    267 **/
    268 EFI_STATUS
    269 SerialFifoRemove (
    270   IN OUT SERIAL_DEV_FIFO *Fifo,
    271   OUT    UINT8           *Data
    272   )
    273 {
    274   //
    275   // if FIFO is empty, no data can remove
    276   //
    277   if (SerialFifoEmpty (Fifo)) {
    278     return EFI_OUT_OF_RESOURCES;
    279   }
    280   //
    281   // FIFO is not empty, can remove data
    282   //
    283   *Data = Fifo->Data[Fifo->Head];
    284   Fifo->Head = (Fifo->Head + 1) % SERIAL_MAX_FIFO_SIZE;
    285   return EFI_SUCCESS;
    286 }
    287 
    288 /**
    289   Reads and writes all avaliable data.
    290 
    291   @param SerialDevice           The device to transmit.
    292 
    293   @retval EFI_SUCCESS           Data was read/written successfully.
    294   @retval EFI_OUT_OF_RESOURCE   Failed because software receive FIFO is full.  Note, when
    295                                 this happens, pending writes are not done.
    296 
    297 **/
    298 EFI_STATUS
    299 SerialReceiveTransmit (
    300   IN SERIAL_DEV *SerialDevice
    301   )
    302 
    303 {
    304   SERIAL_PORT_LSR Lsr;
    305   UINT8           Data;
    306   BOOLEAN         ReceiveFifoFull;
    307   SERIAL_PORT_MSR Msr;
    308   SERIAL_PORT_MCR Mcr;
    309   UINTN           TimeOut;
    310 
    311   Data = 0;
    312 
    313   //
    314   // Begin the read or write
    315   //
    316   if (SerialDevice->SoftwareLoopbackEnable) {
    317     do {
    318       ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive);
    319       if (!SerialFifoEmpty (&SerialDevice->Transmit)) {
    320         SerialFifoRemove (&SerialDevice->Transmit, &Data);
    321         if (ReceiveFifoFull) {
    322           return EFI_OUT_OF_RESOURCES;
    323         }
    324 
    325         SerialFifoAdd (&SerialDevice->Receive, Data);
    326       }
    327     } while (!SerialFifoEmpty (&SerialDevice->Transmit));
    328   } else {
    329     ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive);
    330     //
    331     // For full handshake flow control, tell the peer to send data
    332     // if receive buffer is available.
    333     //
    334     if (SerialDevice->HardwareFlowControl &&
    335         !FeaturePcdGet(PcdSerialUseHalfHandshake)&&
    336         !ReceiveFifoFull
    337         ) {
    338       Mcr.Data     = READ_MCR (SerialDevice);
    339       Mcr.Bits.Rts = 1;
    340       WRITE_MCR (SerialDevice, Mcr.Data);
    341     }
    342     do {
    343       Lsr.Data = READ_LSR (SerialDevice);
    344 
    345       //
    346       // Flush incomming data to prevent a an overrun during a long write
    347       //
    348       if ((Lsr.Bits.Dr == 1) && !ReceiveFifoFull) {
    349         ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive);
    350         if (!ReceiveFifoFull) {
    351           if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Oe == 1 || Lsr.Bits.Pe == 1 || Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {
    352             REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    353               EFI_ERROR_CODE,
    354               EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
    355               SerialDevice->DevicePath
    356               );
    357             if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Pe == 1|| Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {
    358               Data = READ_RBR (SerialDevice);
    359               continue;
    360             }
    361           }
    362 
    363           Data = READ_RBR (SerialDevice);
    364 
    365           SerialFifoAdd (&SerialDevice->Receive, Data);
    366 
    367           //
    368           // For full handshake flow control, if receive buffer full
    369           // tell the peer to stop sending data.
    370           //
    371           if (SerialDevice->HardwareFlowControl &&
    372               !FeaturePcdGet(PcdSerialUseHalfHandshake)   &&
    373               SerialFifoFull (&SerialDevice->Receive)
    374               ) {
    375             Mcr.Data     = READ_MCR (SerialDevice);
    376             Mcr.Bits.Rts = 0;
    377             WRITE_MCR (SerialDevice, Mcr.Data);
    378           }
    379 
    380 
    381           continue;
    382         } else {
    383           REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    384             EFI_PROGRESS_CODE,
    385             EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT,
    386             SerialDevice->DevicePath
    387             );
    388         }
    389       }
    390       //
    391       // Do the write
    392       //
    393       if (Lsr.Bits.Thre == 1 && !SerialFifoEmpty (&SerialDevice->Transmit)) {
    394         //
    395         // Make sure the transmit data will not be missed
    396         //
    397         if (SerialDevice->HardwareFlowControl) {
    398           //
    399           // For half handshake flow control assert RTS before sending.
    400           //
    401           if (FeaturePcdGet(PcdSerialUseHalfHandshake)) {
    402             Mcr.Data     = READ_MCR (SerialDevice);
    403             Mcr.Bits.Rts= 0;
    404             WRITE_MCR (SerialDevice, Mcr.Data);
    405           }
    406           //
    407           // Wait for CTS
    408           //
    409           TimeOut   = 0;
    410           Msr.Data  = READ_MSR (SerialDevice);
    411           while ((Msr.Bits.Dcd == 1) && ((Msr.Bits.Cts == 0) ^ FeaturePcdGet(PcdSerialUseHalfHandshake))) {
    412             gBS->Stall (TIMEOUT_STALL_INTERVAL);
    413             TimeOut++;
    414             if (TimeOut > 5) {
    415               break;
    416             }
    417 
    418             Msr.Data = READ_MSR (SerialDevice);
    419           }
    420 
    421           if ((Msr.Bits.Dcd == 0) || ((Msr.Bits.Cts == 1) ^ FeaturePcdGet(PcdSerialUseHalfHandshake))) {
    422             SerialFifoRemove (&SerialDevice->Transmit, &Data);
    423             WRITE_THR (SerialDevice, Data);
    424           }
    425 
    426           //
    427           // For half handshake flow control, tell DCE we are done.
    428           //
    429           if (FeaturePcdGet(PcdSerialUseHalfHandshake)) {
    430             Mcr.Data = READ_MCR (SerialDevice);
    431             Mcr.Bits.Rts = 1;
    432             WRITE_MCR (SerialDevice, Mcr.Data);
    433           }
    434         } else {
    435           SerialFifoRemove (&SerialDevice->Transmit, &Data);
    436           WRITE_THR (SerialDevice, Data);
    437         }
    438       }
    439     } while (Lsr.Bits.Thre == 1 && !SerialFifoEmpty (&SerialDevice->Transmit));
    440   }
    441 
    442   return EFI_SUCCESS;
    443 }
    444 
    445 /**
    446   Flush the serial hardware transmit FIFO and shift register.
    447 
    448   @param SerialDevice  The device to flush.
    449 **/
    450 VOID
    451 SerialFlushTransmitFifo (
    452   SERIAL_DEV  *SerialDevice
    453   )
    454 {
    455   SERIAL_PORT_LSR  Lsr;
    456 
    457   //
    458   // Wait for the serial port to be ready, to make sure both the transmit FIFO
    459   // and shift register empty.
    460   //
    461   do {
    462     Lsr.Data = READ_LSR (SerialDevice);
    463   } while (Lsr.Bits.Temt == 0);
    464 }
    465 
    466 //
    467 // Interface Functions
    468 //
    469 /**
    470   Reset serial device.
    471 
    472   @param This               Pointer to EFI_SERIAL_IO_PROTOCOL
    473 
    474   @retval EFI_SUCCESS        Reset successfully
    475   @retval EFI_DEVICE_ERROR   Failed to reset
    476 
    477 **/
    478 EFI_STATUS
    479 EFIAPI
    480 SerialReset (
    481   IN EFI_SERIAL_IO_PROTOCOL  *This
    482   )
    483 {
    484   EFI_STATUS      Status;
    485   SERIAL_DEV      *SerialDevice;
    486   SERIAL_PORT_LCR Lcr;
    487   SERIAL_PORT_IER Ier;
    488   SERIAL_PORT_MCR Mcr;
    489   SERIAL_PORT_FCR Fcr;
    490   EFI_TPL         Tpl;
    491   UINT32          Control;
    492 
    493   SerialDevice = SERIAL_DEV_FROM_THIS (This);
    494 
    495   //
    496   // Report the status code reset the serial
    497   //
    498   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    499     EFI_PROGRESS_CODE,
    500     EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT,
    501     SerialDevice->DevicePath
    502     );
    503 
    504   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
    505 
    506   SerialFlushTransmitFifo (SerialDevice);
    507 
    508   //
    509   // Make sure DLAB is 0.
    510   //
    511   Lcr.Data      = READ_LCR (SerialDevice);
    512   Lcr.Bits.DLab = 0;
    513   WRITE_LCR (SerialDevice, Lcr.Data);
    514 
    515   //
    516   // Turn off all interrupts
    517   //
    518   Ier.Data        = READ_IER (SerialDevice);
    519   Ier.Bits.Ravie  = 0;
    520   Ier.Bits.Theie  = 0;
    521   Ier.Bits.Rie    = 0;
    522   Ier.Bits.Mie    = 0;
    523   WRITE_IER (SerialDevice, Ier.Data);
    524 
    525   //
    526   // Reset the FIFO
    527   //
    528   Fcr.Data = 0;
    529   Fcr.Bits.TrFIFOE = 0;
    530   WRITE_FCR (SerialDevice, Fcr.Data);
    531 
    532   //
    533   // Turn off loopback and disable device interrupt.
    534   //
    535   Mcr.Data      = READ_MCR (SerialDevice);
    536   Mcr.Bits.Out1 = 0;
    537   Mcr.Bits.Out2 = 0;
    538   Mcr.Bits.Lme  = 0;
    539   WRITE_MCR (SerialDevice, Mcr.Data);
    540 
    541   //
    542   // Clear the scratch pad register
    543   //
    544   WRITE_SCR (SerialDevice, 0);
    545 
    546   //
    547   // Enable FIFO
    548   //
    549   Fcr.Bits.TrFIFOE  = 1;
    550   if (SerialDevice->ReceiveFifoDepth > 16) {
    551     Fcr.Bits.TrFIFO64 = 1;
    552   }
    553   Fcr.Bits.ResetRF  = 1;
    554   Fcr.Bits.ResetTF  = 1;
    555   WRITE_FCR (SerialDevice, Fcr.Data);
    556 
    557   //
    558   // Go set the current attributes
    559   //
    560   Status = This->SetAttributes (
    561                    This,
    562                    This->Mode->BaudRate,
    563                    This->Mode->ReceiveFifoDepth,
    564                    This->Mode->Timeout,
    565                    (EFI_PARITY_TYPE) This->Mode->Parity,
    566                    (UINT8) This->Mode->DataBits,
    567                    (EFI_STOP_BITS_TYPE) This->Mode->StopBits
    568                    );
    569 
    570   if (EFI_ERROR (Status)) {
    571     gBS->RestoreTPL (Tpl);
    572     return EFI_DEVICE_ERROR;
    573   }
    574   //
    575   // Go set the current control bits
    576   //
    577   Control = 0;
    578   if (SerialDevice->HardwareFlowControl) {
    579     Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
    580   }
    581   if (SerialDevice->SoftwareLoopbackEnable) {
    582     Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
    583   }
    584   Status = This->SetControl (
    585                    This,
    586                    Control
    587                    );
    588 
    589   if (EFI_ERROR (Status)) {
    590     gBS->RestoreTPL (Tpl);
    591     return EFI_DEVICE_ERROR;
    592   }
    593 
    594   //
    595   // Reset the software FIFO
    596   //
    597   SerialDevice->Receive.Head = SerialDevice->Receive.Tail = 0;
    598   SerialDevice->Transmit.Head = SerialDevice->Transmit.Tail = 0;
    599   gBS->RestoreTPL (Tpl);
    600 
    601   //
    602   // Device reset is complete
    603   //
    604   return EFI_SUCCESS;
    605 }
    606 
    607 /**
    608   Set new attributes to a serial device.
    609 
    610   @param This                     Pointer to EFI_SERIAL_IO_PROTOCOL
    611   @param  BaudRate                 The baudrate of the serial device
    612   @param  ReceiveFifoDepth         The depth of receive FIFO buffer
    613   @param  Timeout                  The request timeout for a single char
    614   @param  Parity                   The type of parity used in serial device
    615   @param  DataBits                 Number of databits used in serial device
    616   @param  StopBits                 Number of stopbits used in serial device
    617 
    618   @retval  EFI_SUCCESS              The new attributes were set
    619   @retval  EFI_INVALID_PARAMETERS   One or more attributes have an unsupported value
    620   @retval  EFI_UNSUPPORTED          Data Bits can not set to 5 or 6
    621   @retval  EFI_DEVICE_ERROR         The serial device is not functioning correctly (no return)
    622 
    623 **/
    624 EFI_STATUS
    625 EFIAPI
    626 SerialSetAttributes (
    627   IN EFI_SERIAL_IO_PROTOCOL  *This,
    628   IN UINT64                  BaudRate,
    629   IN UINT32                  ReceiveFifoDepth,
    630   IN UINT32                  Timeout,
    631   IN EFI_PARITY_TYPE         Parity,
    632   IN UINT8                   DataBits,
    633   IN EFI_STOP_BITS_TYPE      StopBits
    634   )
    635 {
    636   EFI_STATUS                Status;
    637   SERIAL_DEV                *SerialDevice;
    638   UINT64                    Divisor;
    639   SERIAL_PORT_LCR           Lcr;
    640   UART_DEVICE_PATH          *Uart;
    641   EFI_TPL                   Tpl;
    642 
    643   SerialDevice = SERIAL_DEV_FROM_THIS (This);
    644 
    645   //
    646   // Check for default settings and fill in actual values.
    647   //
    648   if (BaudRate == 0) {
    649     BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
    650   }
    651 
    652   if (ReceiveFifoDepth == 0) {
    653     ReceiveFifoDepth = SerialDevice->ReceiveFifoDepth;
    654   }
    655 
    656   if (Timeout == 0) {
    657     Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;
    658   }
    659 
    660   if (Parity == DefaultParity) {
    661     Parity = (EFI_PARITY_TYPE) PcdGet8 (PcdUartDefaultParity);
    662   }
    663 
    664   if (DataBits == 0) {
    665     DataBits = PcdGet8 (PcdUartDefaultDataBits);
    666   }
    667 
    668   if (StopBits == DefaultStopBits) {
    669     StopBits = (EFI_STOP_BITS_TYPE) PcdGet8 (PcdUartDefaultStopBits);
    670   }
    671 
    672   if (!VerifyUartParameters (SerialDevice->ClockRate, BaudRate, DataBits, Parity, StopBits, &Divisor, &BaudRate)) {
    673     return EFI_INVALID_PARAMETER;
    674   }
    675 
    676   if ((ReceiveFifoDepth == 0) || (ReceiveFifoDepth > SerialDevice->ReceiveFifoDepth)) {
    677     return EFI_INVALID_PARAMETER;
    678   }
    679 
    680   if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) {
    681     return EFI_INVALID_PARAMETER;
    682   }
    683 
    684   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
    685 
    686   SerialFlushTransmitFifo (SerialDevice);
    687 
    688   //
    689   // Put serial port on Divisor Latch Mode
    690   //
    691   Lcr.Data      = READ_LCR (SerialDevice);
    692   Lcr.Bits.DLab = 1;
    693   WRITE_LCR (SerialDevice, Lcr.Data);
    694 
    695   //
    696   // Write the divisor to the serial port
    697   //
    698   WRITE_DLL (SerialDevice, (UINT8) Divisor);
    699   WRITE_DLM (SerialDevice, (UINT8) ((UINT16) Divisor >> 8));
    700 
    701   //
    702   // Put serial port back in normal mode and set remaining attributes.
    703   //
    704   Lcr.Bits.DLab = 0;
    705 
    706   switch (Parity) {
    707   case NoParity:
    708     Lcr.Bits.ParEn    = 0;
    709     Lcr.Bits.EvenPar  = 0;
    710     Lcr.Bits.SticPar  = 0;
    711     break;
    712 
    713   case EvenParity:
    714     Lcr.Bits.ParEn    = 1;
    715     Lcr.Bits.EvenPar  = 1;
    716     Lcr.Bits.SticPar  = 0;
    717     break;
    718 
    719   case OddParity:
    720     Lcr.Bits.ParEn    = 1;
    721     Lcr.Bits.EvenPar  = 0;
    722     Lcr.Bits.SticPar  = 0;
    723     break;
    724 
    725   case SpaceParity:
    726     Lcr.Bits.ParEn    = 1;
    727     Lcr.Bits.EvenPar  = 1;
    728     Lcr.Bits.SticPar  = 1;
    729     break;
    730 
    731   case MarkParity:
    732     Lcr.Bits.ParEn    = 1;
    733     Lcr.Bits.EvenPar  = 0;
    734     Lcr.Bits.SticPar  = 1;
    735     break;
    736 
    737   default:
    738     break;
    739   }
    740 
    741   switch (StopBits) {
    742   case OneStopBit:
    743     Lcr.Bits.StopB = 0;
    744     break;
    745 
    746   case OneFiveStopBits:
    747   case TwoStopBits:
    748     Lcr.Bits.StopB = 1;
    749     break;
    750 
    751   default:
    752     break;
    753   }
    754   //
    755   // DataBits
    756   //
    757   Lcr.Bits.SerialDB = (UINT8) ((DataBits - 5) & 0x03);
    758   WRITE_LCR (SerialDevice, Lcr.Data);
    759 
    760   //
    761   // Set the Serial I/O mode
    762   //
    763   This->Mode->BaudRate          = BaudRate;
    764   This->Mode->ReceiveFifoDepth  = ReceiveFifoDepth;
    765   This->Mode->Timeout           = Timeout;
    766   This->Mode->Parity            = Parity;
    767   This->Mode->DataBits          = DataBits;
    768   This->Mode->StopBits          = StopBits;
    769 
    770   //
    771   // See if Device Path Node has actually changed
    772   //
    773   if (SerialDevice->UartDevicePath.BaudRate == BaudRate &&
    774       SerialDevice->UartDevicePath.DataBits == DataBits &&
    775       SerialDevice->UartDevicePath.Parity == Parity &&
    776       SerialDevice->UartDevicePath.StopBits == StopBits
    777       ) {
    778     gBS->RestoreTPL (Tpl);
    779     return EFI_SUCCESS;
    780   }
    781   //
    782   // Update the device path
    783   //
    784   SerialDevice->UartDevicePath.BaudRate = BaudRate;
    785   SerialDevice->UartDevicePath.DataBits = DataBits;
    786   SerialDevice->UartDevicePath.Parity   = (UINT8) Parity;
    787   SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits;
    788 
    789   Status = EFI_SUCCESS;
    790   if (SerialDevice->Handle != NULL) {
    791 
    792     //
    793     // Skip the optional Controller device path node
    794     //
    795     Uart = SkipControllerDevicePathNode (
    796              (EFI_DEVICE_PATH_PROTOCOL *) (
    797                (UINT8 *) SerialDevice->DevicePath + GetDevicePathSize (SerialDevice->ParentDevicePath) - END_DEVICE_PATH_LENGTH
    798                ),
    799              NULL,
    800              NULL
    801              );
    802     CopyMem (Uart, &SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH));
    803     Status = gBS->ReinstallProtocolInterface (
    804                     SerialDevice->Handle,
    805                     &gEfiDevicePathProtocolGuid,
    806                     SerialDevice->DevicePath,
    807                     SerialDevice->DevicePath
    808                     );
    809   }
    810 
    811   gBS->RestoreTPL (Tpl);
    812 
    813   return Status;
    814 }
    815 
    816 /**
    817   Set Control Bits.
    818 
    819   @param This              Pointer to EFI_SERIAL_IO_PROTOCOL
    820   @param Control           Control bits that can be settable
    821 
    822   @retval EFI_SUCCESS       New Control bits were set successfully
    823   @retval EFI_UNSUPPORTED   The Control bits wanted to set are not supported
    824 
    825 **/
    826 EFI_STATUS
    827 EFIAPI
    828 SerialSetControl (
    829   IN EFI_SERIAL_IO_PROTOCOL  *This,
    830   IN UINT32                  Control
    831   )
    832 {
    833   SERIAL_DEV                    *SerialDevice;
    834   SERIAL_PORT_MCR               Mcr;
    835   EFI_TPL                       Tpl;
    836   UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
    837   EFI_STATUS                    Status;
    838 
    839   //
    840   // The control bits that can be set are :
    841   //     EFI_SERIAL_DATA_TERMINAL_READY: 0x0001  // WO
    842   //     EFI_SERIAL_REQUEST_TO_SEND: 0x0002  // WO
    843   //     EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000  // RW
    844   //     EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000  // RW
    845   //     EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE: 0x4000 // RW
    846   //
    847   SerialDevice = SERIAL_DEV_FROM_THIS (This);
    848 
    849   //
    850   // first determine the parameter is invalid
    851   //
    852   if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
    853                     EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
    854                     EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) {
    855     return EFI_UNSUPPORTED;
    856   }
    857 
    858   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
    859 
    860   Mcr.Data = READ_MCR (SerialDevice);
    861   Mcr.Bits.DtrC = 0;
    862   Mcr.Bits.Rts = 0;
    863   Mcr.Bits.Lme = 0;
    864   SerialDevice->SoftwareLoopbackEnable = FALSE;
    865   SerialDevice->HardwareFlowControl = FALSE;
    866 
    867   if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
    868     Mcr.Bits.DtrC = 1;
    869   }
    870 
    871   if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
    872     Mcr.Bits.Rts = 1;
    873   }
    874 
    875   if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) == EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
    876     Mcr.Bits.Lme = 1;
    877   }
    878 
    879   if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
    880     SerialDevice->HardwareFlowControl = TRUE;
    881   }
    882 
    883   WRITE_MCR (SerialDevice, Mcr.Data);
    884 
    885   if ((Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) == EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
    886     SerialDevice->SoftwareLoopbackEnable = TRUE;
    887   }
    888 
    889   Status = EFI_SUCCESS;
    890   if (SerialDevice->Handle != NULL) {
    891     FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) (
    892                     (UINTN) SerialDevice->DevicePath
    893                     + GetDevicePathSize (SerialDevice->ParentDevicePath)
    894                     - END_DEVICE_PATH_LENGTH
    895                     + sizeof (UART_DEVICE_PATH)
    896                     );
    897     if (IsUartFlowControlDevicePathNode (FlowControl) &&
    898         ((BOOLEAN) (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) != SerialDevice->HardwareFlowControl)) {
    899       //
    900       // Flow Control setting is changed, need to reinstall device path protocol
    901       //
    902       WriteUnaligned32 (&FlowControl->FlowControlMap, SerialDevice->HardwareFlowControl ? UART_FLOW_CONTROL_HARDWARE : 0);
    903       Status = gBS->ReinstallProtocolInterface (
    904                       SerialDevice->Handle,
    905                       &gEfiDevicePathProtocolGuid,
    906                       SerialDevice->DevicePath,
    907                       SerialDevice->DevicePath
    908                       );
    909     }
    910   }
    911 
    912   gBS->RestoreTPL (Tpl);
    913 
    914   return Status;
    915 }
    916 
    917 /**
    918   Get ControlBits.
    919 
    920   @param This          Pointer to EFI_SERIAL_IO_PROTOCOL
    921   @param Control       Control signals of the serial device
    922 
    923   @retval EFI_SUCCESS   Get Control signals successfully
    924 
    925 **/
    926 EFI_STATUS
    927 EFIAPI
    928 SerialGetControl (
    929   IN EFI_SERIAL_IO_PROTOCOL  *This,
    930   OUT UINT32                 *Control
    931   )
    932 {
    933   SERIAL_DEV      *SerialDevice;
    934   SERIAL_PORT_MSR Msr;
    935   SERIAL_PORT_MCR Mcr;
    936   EFI_TPL         Tpl;
    937 
    938   Tpl           = gBS->RaiseTPL (TPL_NOTIFY);
    939 
    940   SerialDevice  = SERIAL_DEV_FROM_THIS (This);
    941 
    942   *Control      = 0;
    943 
    944   //
    945   // Read the Modem Status Register
    946   //
    947   Msr.Data = READ_MSR (SerialDevice);
    948 
    949   if (Msr.Bits.Cts == 1) {
    950     *Control |= EFI_SERIAL_CLEAR_TO_SEND;
    951   }
    952 
    953   if (Msr.Bits.Dsr == 1) {
    954     *Control |= EFI_SERIAL_DATA_SET_READY;
    955   }
    956 
    957   if (Msr.Bits.Ri == 1) {
    958     *Control |= EFI_SERIAL_RING_INDICATE;
    959   }
    960 
    961   if (Msr.Bits.Dcd == 1) {
    962     *Control |= EFI_SERIAL_CARRIER_DETECT;
    963   }
    964   //
    965   // Read the Modem Control Register
    966   //
    967   Mcr.Data = READ_MCR (SerialDevice);
    968 
    969   if (Mcr.Bits.DtrC == 1) {
    970     *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
    971   }
    972 
    973   if (Mcr.Bits.Rts == 1) {
    974     *Control |= EFI_SERIAL_REQUEST_TO_SEND;
    975   }
    976 
    977   if (Mcr.Bits.Lme == 1) {
    978     *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
    979   }
    980 
    981   if (SerialDevice->HardwareFlowControl) {
    982     *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
    983   }
    984   //
    985   // Update FIFO status
    986   //
    987   SerialReceiveTransmit (SerialDevice);
    988 
    989   //
    990   // See if the Transmit FIFO is empty
    991   //
    992   if (SerialFifoEmpty (&SerialDevice->Transmit)) {
    993     *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
    994   }
    995 
    996   //
    997   // See if the Receive FIFO is empty.
    998   //
    999   if (SerialFifoEmpty (&SerialDevice->Receive)) {
   1000     *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
   1001   }
   1002 
   1003   if (SerialDevice->SoftwareLoopbackEnable) {
   1004     *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
   1005   }
   1006 
   1007   gBS->RestoreTPL (Tpl);
   1008 
   1009   return EFI_SUCCESS;
   1010 }
   1011 
   1012 /**
   1013   Write the specified number of bytes to serial device.
   1014 
   1015   @param This               Pointer to EFI_SERIAL_IO_PROTOCOL
   1016   @param  BufferSize         On input the size of Buffer, on output the amount of
   1017                        data actually written
   1018   @param  Buffer             The buffer of data to write
   1019 
   1020   @retval EFI_SUCCESS        The data were written successfully
   1021   @retval EFI_DEVICE_ERROR   The device reported an error
   1022   @retval EFI_TIMEOUT        The write operation was stopped due to timeout
   1023 
   1024 **/
   1025 EFI_STATUS
   1026 EFIAPI
   1027 SerialWrite (
   1028   IN EFI_SERIAL_IO_PROTOCOL  *This,
   1029   IN OUT UINTN               *BufferSize,
   1030   IN VOID                    *Buffer
   1031   )
   1032 {
   1033   SERIAL_DEV  *SerialDevice;
   1034   UINT8       *CharBuffer;
   1035   UINT32      Index;
   1036   UINTN       Elapsed;
   1037   UINTN       ActualWrite;
   1038   EFI_TPL     Tpl;
   1039   UINTN       Timeout;
   1040   UINTN       BitsPerCharacter;
   1041 
   1042   SerialDevice  = SERIAL_DEV_FROM_THIS (This);
   1043   Elapsed       = 0;
   1044   ActualWrite   = 0;
   1045 
   1046   if (*BufferSize == 0) {
   1047     return EFI_SUCCESS;
   1048   }
   1049 
   1050   if (Buffer == NULL) {
   1051     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
   1052       EFI_ERROR_CODE,
   1053       EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
   1054       SerialDevice->DevicePath
   1055       );
   1056 
   1057     return EFI_DEVICE_ERROR;
   1058   }
   1059 
   1060   Tpl         = gBS->RaiseTPL (TPL_NOTIFY);
   1061 
   1062   CharBuffer  = (UINT8 *) Buffer;
   1063 
   1064   //
   1065   // Compute the number of bits in a single character.  This is a start bit,
   1066   // followed by the number of data bits, followed by the number of stop bits.
   1067   // The number of stop bits is specified by an enumeration that includes
   1068   // support for 1.5 stop bits.  Treat 1.5 stop bits as 2 stop bits.
   1069   //
   1070   BitsPerCharacter =
   1071     1 +
   1072     This->Mode->DataBits +
   1073     ((This->Mode->StopBits == TwoStopBits) ? 2 : This->Mode->StopBits);
   1074 
   1075   //
   1076   // Compute the timeout in microseconds to wait for a single byte to be
   1077   // transmitted.  The Mode structure contans a Timeout field that is the
   1078   // maximum time to transmit or receive a character.  However, many UARTs
   1079   // have a FIFO for transmits, so the time required to add one new character
   1080   // to the transmit FIFO may be the time required to flush a full FIFO.  If
   1081   // the Timeout in the Mode structure is smaller than the time required to
   1082   // flush a full FIFO at the current baud rate, then use a timeout value that
   1083   // is required to flush a full transmit FIFO.
   1084   //
   1085   Timeout = MAX (
   1086               This->Mode->Timeout,
   1087               (UINTN)DivU64x64Remainder (
   1088                 BitsPerCharacter * (SerialDevice->TransmitFifoDepth + 1) * 1000000,
   1089                 This->Mode->BaudRate,
   1090                 NULL
   1091                 )
   1092               );
   1093 
   1094   for (Index = 0; Index < *BufferSize; Index++) {
   1095     SerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]);
   1096 
   1097     while (SerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !SerialFifoEmpty (&SerialDevice->Transmit)) {
   1098       //
   1099       //  Unsuccessful write so check if timeout has expired, if not,
   1100       //  stall for a bit, increment time elapsed, and try again
   1101       //
   1102       if (Elapsed >= Timeout) {
   1103         *BufferSize = ActualWrite;
   1104         gBS->RestoreTPL (Tpl);
   1105         return EFI_TIMEOUT;
   1106       }
   1107 
   1108       gBS->Stall (TIMEOUT_STALL_INTERVAL);
   1109 
   1110       Elapsed += TIMEOUT_STALL_INTERVAL;
   1111     }
   1112 
   1113     ActualWrite++;
   1114     //
   1115     //  Successful write so reset timeout
   1116     //
   1117     Elapsed = 0;
   1118   }
   1119 
   1120   gBS->RestoreTPL (Tpl);
   1121 
   1122   return EFI_SUCCESS;
   1123 }
   1124 
   1125 /**
   1126   Read the specified number of bytes from serial device.
   1127 
   1128   @param This               Pointer to EFI_SERIAL_IO_PROTOCOL
   1129   @param BufferSize         On input the size of Buffer, on output the amount of
   1130                             data returned in buffer
   1131   @param Buffer             The buffer to return the data into
   1132 
   1133   @retval EFI_SUCCESS        The data were read successfully
   1134   @retval EFI_DEVICE_ERROR   The device reported an error
   1135   @retval EFI_TIMEOUT        The read operation was stopped due to timeout
   1136 
   1137 **/
   1138 EFI_STATUS
   1139 EFIAPI
   1140 SerialRead (
   1141   IN EFI_SERIAL_IO_PROTOCOL  *This,
   1142   IN OUT UINTN               *BufferSize,
   1143   OUT VOID                   *Buffer
   1144   )
   1145 {
   1146   SERIAL_DEV  *SerialDevice;
   1147   UINT32      Index;
   1148   UINT8       *CharBuffer;
   1149   UINTN       Elapsed;
   1150   EFI_STATUS  Status;
   1151   EFI_TPL     Tpl;
   1152 
   1153   SerialDevice  = SERIAL_DEV_FROM_THIS (This);
   1154   Elapsed       = 0;
   1155 
   1156   if (*BufferSize == 0) {
   1157     return EFI_SUCCESS;
   1158   }
   1159 
   1160   if (Buffer == NULL) {
   1161     return EFI_DEVICE_ERROR;
   1162   }
   1163 
   1164   Tpl     = gBS->RaiseTPL (TPL_NOTIFY);
   1165 
   1166   Status  = SerialReceiveTransmit (SerialDevice);
   1167 
   1168   if (EFI_ERROR (Status)) {
   1169     *BufferSize = 0;
   1170 
   1171     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
   1172       EFI_ERROR_CODE,
   1173       EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
   1174       SerialDevice->DevicePath
   1175       );
   1176 
   1177     gBS->RestoreTPL (Tpl);
   1178 
   1179     return EFI_DEVICE_ERROR;
   1180   }
   1181 
   1182   CharBuffer = (UINT8 *) Buffer;
   1183   for (Index = 0; Index < *BufferSize; Index++) {
   1184     while (SerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) {
   1185       //
   1186       //  Unsuccessful read so check if timeout has expired, if not,
   1187       //  stall for a bit, increment time elapsed, and try again
   1188       //  Need this time out to get conspliter to work.
   1189       //
   1190       if (Elapsed >= This->Mode->Timeout) {
   1191         *BufferSize = Index;
   1192         gBS->RestoreTPL (Tpl);
   1193         return EFI_TIMEOUT;
   1194       }
   1195 
   1196       gBS->Stall (TIMEOUT_STALL_INTERVAL);
   1197       Elapsed += TIMEOUT_STALL_INTERVAL;
   1198 
   1199       Status = SerialReceiveTransmit (SerialDevice);
   1200       if (Status == EFI_DEVICE_ERROR) {
   1201         *BufferSize = Index;
   1202         gBS->RestoreTPL (Tpl);
   1203         return EFI_DEVICE_ERROR;
   1204       }
   1205     }
   1206     //
   1207     //  Successful read so reset timeout
   1208     //
   1209     Elapsed = 0;
   1210   }
   1211 
   1212   SerialReceiveTransmit (SerialDevice);
   1213 
   1214   gBS->RestoreTPL (Tpl);
   1215 
   1216   return EFI_SUCCESS;
   1217 }
   1218 
   1219 /**
   1220   Use scratchpad register to test if this serial port is present.
   1221 
   1222   @param SerialDevice   Pointer to serial device structure
   1223 
   1224   @return if this serial port is present
   1225 **/
   1226 BOOLEAN
   1227 SerialPresent (
   1228   IN SERIAL_DEV *SerialDevice
   1229   )
   1230 
   1231 {
   1232   UINT8   Temp;
   1233   BOOLEAN Status;
   1234 
   1235   Status = TRUE;
   1236 
   1237   //
   1238   // Save SCR reg
   1239   //
   1240   Temp = READ_SCR (SerialDevice);
   1241   WRITE_SCR (SerialDevice, 0xAA);
   1242 
   1243   if (READ_SCR (SerialDevice) != 0xAA) {
   1244     Status = FALSE;
   1245   }
   1246 
   1247   WRITE_SCR (SerialDevice, 0x55);
   1248 
   1249   if (READ_SCR (SerialDevice) != 0x55) {
   1250     Status = FALSE;
   1251   }
   1252   //
   1253   // Restore SCR
   1254   //
   1255   WRITE_SCR (SerialDevice, Temp);
   1256   return Status;
   1257 }
   1258 
   1259 /**
   1260   Read serial port.
   1261 
   1262   @param SerialDev     Pointer to serial device
   1263   @param Offset        Offset in register group
   1264 
   1265   @return Data read from serial port
   1266 
   1267 **/
   1268 UINT8
   1269 SerialReadRegister (
   1270   IN SERIAL_DEV                            *SerialDev,
   1271   IN UINT32                                Offset
   1272   )
   1273 {
   1274   UINT8                                    Data;
   1275   EFI_STATUS                               Status;
   1276 
   1277   if (SerialDev->PciDeviceInfo == NULL) {
   1278     return IoRead8 ((UINTN) SerialDev->BaseAddress + Offset * SerialDev->RegisterStride);
   1279   } else {
   1280     if (SerialDev->MmioAccess) {
   1281       Status = SerialDev->PciDeviceInfo->PciIo->Mem.Read (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
   1282                                                           SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
   1283     } else {
   1284       Status = SerialDev->PciDeviceInfo->PciIo->Io.Read (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
   1285                                                          SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
   1286     }
   1287     ASSERT_EFI_ERROR (Status);
   1288     return Data;
   1289   }
   1290 }
   1291 
   1292 /**
   1293   Write serial port.
   1294 
   1295   @param  SerialDev     Pointer to serial device
   1296   @param  Offset        Offset in register group
   1297   @param  Data          data which is to be written to some serial port register
   1298 **/
   1299 VOID
   1300 SerialWriteRegister (
   1301   IN SERIAL_DEV                            *SerialDev,
   1302   IN UINT32                                Offset,
   1303   IN UINT8                                 Data
   1304   )
   1305 {
   1306   EFI_STATUS                               Status;
   1307 
   1308   if (SerialDev->PciDeviceInfo == NULL) {
   1309     IoWrite8 ((UINTN) SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, Data);
   1310   } else {
   1311     if (SerialDev->MmioAccess) {
   1312       Status = SerialDev->PciDeviceInfo->PciIo->Mem.Write (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
   1313                                                            SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
   1314     } else {
   1315       Status = SerialDev->PciDeviceInfo->PciIo->Io.Write (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
   1316                                                           SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
   1317     }
   1318     ASSERT_EFI_ERROR (Status);
   1319   }
   1320 }
   1321