/** @file
  Basic serial IO abstraction for GDB
  Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
  SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
EFI_DEBUGPORT_PROTOCOL  *gDebugPort = NULL;
UINT32                  gTimeOut    = 0;
/**
  The constructor function initializes the UART.
  @param  ImageHandle   The firmware allocated handle for the EFI image.
  @param  SystemTable   A pointer to the EFI System Table.
  @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
**/
RETURN_STATUS
EFIAPI
GdbSerialLibDebugPortConstructor (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS  Status;
  Status = gBS->LocateProtocol (&gEfiDebugPortProtocolGuid, NULL, (VOID **)&gDebugPort);
  if (!EFI_ERROR (Status)) {
    gTimeOut = PcdGet32 (PcdGdbMaxPacketRetryCount);
    gDebugPort->Reset (gDebugPort);
  }
  return Status;
}
/**
  Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,
  data buts, and stop bits on a serial device. This call is optional as the serial
  port will be set up with defaults base on PCD values.
  @param  BaudRate         The requested baud rate. A BaudRate value of 0 will use the
                           device's default interface speed.
  @param  Parity           The type of parity to use on this serial device. A Parity value of
                           DefaultParity will use the device's default parity value.
  @param  DataBits         The number of data bits to use on the serial device. A DataBits
                           value of 0 will use the device's default data bit setting.
  @param  StopBits         The number of stop bits to use on this serial device. A StopBits
                           value of DefaultStopBits will use the device's default number of
                           stop bits.
  @retval EFI_SUCCESS      The device was configured.
  @retval EFI_DEVICE_ERROR The serial device could not be configured.
**/
RETURN_STATUS
EFIAPI
GdbSerialInit (
  IN UINT64  BaudRate,
  IN UINT8   Parity,
  IN UINT8   DataBits,
  IN UINT8   StopBits
  )
{
  EFI_STATUS  Status;
  Status = gDebugPort->Reset (gDebugPort);
  return Status;
}
/**
  Check to see if a character is available from GDB. Do not read the character as that is
  done via GdbGetChar().
  @return TRUE  - Character available
  @return FALSE - Character not available
**/
BOOLEAN
EFIAPI
GdbIsCharAvailable (
  VOID
  )
{
  EFI_STATUS  Status;
  Status = gDebugPort->Poll (gDebugPort);
  return (Status == EFI_SUCCESS ? TRUE : FALSE);
}
/**
  Get a character from GDB. This function must be able to run in interrupt context.
  @return A character from GDB
**/
CHAR8
EFIAPI
GdbGetChar (
  VOID
  )
{
  EFI_STATUS  Status;
  CHAR8       Char;
  UINTN       BufferSize;
  do {
    BufferSize = sizeof (Char);
    Status     = gDebugPort->Read (gDebugPort, gTimeOut, &BufferSize, &Char);
  } while (EFI_ERROR (Status) || BufferSize != sizeof (Char));
  return Char;
}
/**
  Send a character to GDB. This function must be able to run in interrupt context.
  @param  Char    Send a character to GDB
**/
VOID
EFIAPI
GdbPutChar (
  IN  CHAR8  Char
  )
{
  EFI_STATUS  Status;
  UINTN       BufferSize;
  do {
    BufferSize = sizeof (Char);
    Status     = gDebugPort->Write (gDebugPort, gTimeOut, &BufferSize, &Char);
  } while (EFI_ERROR (Status) || BufferSize != sizeof (Char));
  return;
}
/**
  Send an ASCII string to GDB. This function must be able to run in interrupt context.
  @param  String    Send a string to GDB
**/
VOID
GdbPutString (
  IN CHAR8  *String
  )
{
  // We could performance enhance this function by calling gDebugPort->Write ()
  while (*String != '\0') {
    GdbPutChar (*String);
    String++;
  }
}