git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3721 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1926 lines
		
	
	
		
			49 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1926 lines
		
	
	
		
			49 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/**@file
 | 
						|
	Serial driver for standard UARTS on an ISA bus.
 | 
						|
 | 
						|
  Copyright (c) 2006 - 2007, Intel Corporation<BR>
 | 
						|
  All rights reserved. This program and the accompanying materials
 | 
						|
  are licensed and made available under the terms and conditions of the BSD License
 | 
						|
  which accompanies this distribution.  The full text of the license may be found at
 | 
						|
  http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "Serial.h"
 | 
						|
 | 
						|
//
 | 
						|
// ISA Serial Driver Global Variables
 | 
						|
//
 | 
						|
EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = {
 | 
						|
  SerialControllerDriverSupported,
 | 
						|
  SerialControllerDriverStart,
 | 
						|
  SerialControllerDriverStop,
 | 
						|
  0xa,
 | 
						|
  NULL,
 | 
						|
  NULL
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
SERIAL_DEV  gSerialDevTempate = {
 | 
						|
  SERIAL_DEV_SIGNATURE,
 | 
						|
  NULL,
 | 
						|
  { // SerialIo
 | 
						|
    SERIAL_IO_INTERFACE_REVISION,
 | 
						|
    IsaSerialReset,
 | 
						|
    IsaSerialSetAttributes,
 | 
						|
    IsaSerialSetControl,
 | 
						|
    IsaSerialGetControl,
 | 
						|
    IsaSerialWrite,
 | 
						|
    IsaSerialRead,
 | 
						|
    NULL
 | 
						|
  },
 | 
						|
  { // SerialMode
 | 
						|
    SERIAL_PORT_DEFAULT_CONTROL_MASK,
 | 
						|
    SERIAL_PORT_DEFAULT_TIMEOUT,
 | 
						|
    FixedPcdGet64 (PcdUartDefaultBaudRate),     // BaudRate
 | 
						|
    SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH,
 | 
						|
    FixedPcdGet8 (PcdUartDefaultDataBits),      // DataBits
 | 
						|
    FixedPcdGet8 (PcdUartDefaultParity),        // Parity
 | 
						|
    FixedPcdGet8 (PcdUartDefaultStopBits)       // StopBits
 | 
						|
  },
 | 
						|
  NULL,
 | 
						|
  NULL,
 | 
						|
  { // UartDevicePath
 | 
						|
    {
 | 
						|
      MESSAGING_DEVICE_PATH,
 | 
						|
      MSG_UART_DP,
 | 
						|
      {
 | 
						|
        (UINT8) (sizeof (UART_DEVICE_PATH)),
 | 
						|
        (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)
 | 
						|
      }
 | 
						|
    },
 | 
						|
    0,
 | 
						|
    FixedPcdGet64 (PcdUartDefaultBaudRate),    
 | 
						|
    FixedPcdGet8 (PcdUartDefaultDataBits),
 | 
						|
    FixedPcdGet8 (PcdUartDefaultParity),
 | 
						|
    FixedPcdGet8 (PcdUartDefaultStopBits)
 | 
						|
  },
 | 
						|
  NULL,
 | 
						|
  0,    //BaseAddress
 | 
						|
  {
 | 
						|
    0,
 | 
						|
    0,
 | 
						|
    SERIAL_MAX_BUFFER_SIZE,
 | 
						|
    { 0 }
 | 
						|
  },
 | 
						|
  {
 | 
						|
    0,
 | 
						|
    0,
 | 
						|
    SERIAL_MAX_BUFFER_SIZE,
 | 
						|
    { 0 }
 | 
						|
  },
 | 
						|
  FALSE,
 | 
						|
  FALSE,
 | 
						|
  UART16550A,
 | 
						|
  NULL
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  The user Entry Point for module IsaSerial. The user code starts with this function.
 | 
						|
 | 
						|
  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  
 | 
						|
  @param[in] SystemTable    A pointer to the EFI System Table.
 | 
						|
  
 | 
						|
  @retval EFI_SUCCESS       The entry point is executed successfully.
 | 
						|
  @retval other             Some error occurs when executing this entry point.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
InitializeIsaSerial (
 | 
						|
  IN EFI_HANDLE           ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE     *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS              Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Install driver model protocol(s).
 | 
						|
  //
 | 
						|
  Status = EfiLibInstallAllDriverProtocols (
 | 
						|
             ImageHandle,
 | 
						|
             SystemTable,
 | 
						|
             &gSerialControllerDriver,
 | 
						|
             ImageHandle,
 | 
						|
             &gIsaSerialComponentName,
 | 
						|
             NULL,
 | 
						|
             NULL
 | 
						|
             );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SerialControllerDriverSupported (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
 | 
						|
  IN EFI_HANDLE                     Controller,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Check to see if this driver supports the given controller
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
 | 
						|
    Controller - The handle of the controller to test.
 | 
						|
    RemainingDevicePath - A pointer to the remaining portion of a device path.
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    EFI_SUCCESS - This driver can support the given controller
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS                                Status;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL                  *ParentDevicePath;
 | 
						|
  EFI_ISA_IO_PROTOCOL                       *IsaIo;
 | 
						|
  UART_DEVICE_PATH                          UartNode;
 | 
						|
 | 
						|
  //
 | 
						|
  // Ignore the RemainingDevicePath
 | 
						|
  //
 | 
						|
  //
 | 
						|
  // Open the IO Abstraction(s) needed to perform the supported test
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  (VOID **) &ParentDevicePath,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
  if (Status == EFI_ALREADY_STARTED) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->CloseProtocol (
 | 
						|
         Controller,
 | 
						|
         &gEfiDevicePathProtocolGuid,
 | 
						|
         This->DriverBindingHandle,
 | 
						|
         Controller
 | 
						|
         );
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiIsaIoProtocolGuid,
 | 
						|
                  (VOID **) &IsaIo,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
 | 
						|
  if (Status == EFI_ALREADY_STARTED) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Use the ISA I/O Protocol to see if Controller is standard ISA UART that
 | 
						|
  // can be managed by this driver.
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x501)) {
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
    goto Error;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Make sure RemainingDevicePath is valid
 | 
						|
  //
 | 
						|
  if (RemainingDevicePath != NULL) {
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
    CopyMem (
 | 
						|
      &UartNode,
 | 
						|
      (UART_DEVICE_PATH *) RemainingDevicePath,
 | 
						|
      sizeof (UART_DEVICE_PATH)
 | 
						|
      );
 | 
						|
    if (UartNode.Header.Type != MESSAGING_DEVICE_PATH ||
 | 
						|
        UartNode.Header.SubType != MSG_UART_DP ||
 | 
						|
        sizeof (UART_DEVICE_PATH) != DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) &UartNode)
 | 
						|
                                      ) {
 | 
						|
      goto Error;
 | 
						|
    }
 | 
						|
 | 
						|
    if (UartNode.BaudRate > SERIAL_PORT_MAX_BAUD_RATE) {
 | 
						|
      goto Error;
 | 
						|
    }
 | 
						|
 | 
						|
    if (UartNode.Parity < NoParity || UartNode.Parity > SpaceParity) {
 | 
						|
      goto Error;
 | 
						|
    }
 | 
						|
 | 
						|
    if (UartNode.DataBits < 5 || UartNode.DataBits > 8) {
 | 
						|
      goto Error;
 | 
						|
    }
 | 
						|
 | 
						|
    if (UartNode.StopBits < OneStopBit || UartNode.StopBits > TwoStopBits) {
 | 
						|
      goto Error;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((UartNode.DataBits == 5) && (UartNode.StopBits == TwoStopBits)) {
 | 
						|
      goto Error;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((UartNode.DataBits >= 6) && (UartNode.DataBits <= 8) && (UartNode.StopBits == OneFiveStopBits)) {
 | 
						|
      goto Error;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
Error:
 | 
						|
  //
 | 
						|
  // Close the I/O Abstraction(s) used to perform the supported test
 | 
						|
  //
 | 
						|
  gBS->CloseProtocol (
 | 
						|
         Controller,
 | 
						|
         &gEfiIsaIoProtocolGuid,
 | 
						|
         This->DriverBindingHandle,
 | 
						|
         Controller
 | 
						|
         );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SerialControllerDriverStart (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
 | 
						|
  IN EFI_HANDLE                     Controller,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Start to management the controller passed in
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
 | 
						|
    Controller - The handle of the controller to test.
 | 
						|
    RemainingDevicePath - A pointer to the remaining portion of a device path.
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    EFI_SUCCESS - Driver is started successfully
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS                          Status;
 | 
						|
  EFI_ISA_IO_PROTOCOL                 *IsaIo;
 | 
						|
  SERIAL_DEV                          *SerialDevice;
 | 
						|
  UINTN                               Index;
 | 
						|
  UART_DEVICE_PATH                    Node;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL            *ParentDevicePath;
 | 
						|
  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
 | 
						|
  UINTN                               EntryCount;
 | 
						|
  EFI_SERIAL_IO_PROTOCOL              *SerialIo;
 | 
						|
 | 
						|
  SerialDevice = NULL;
 | 
						|
  //
 | 
						|
  // Get the Parent Device Path
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  (VOID **) &ParentDevicePath,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Report status code enable the serial
 | 
						|
  //
 | 
						|
  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
    EFI_PROGRESS_CODE,
 | 
						|
    EFI_P_PC_ENABLE | EFI_PERIPHERAL_SERIAL_PORT,
 | 
						|
    ParentDevicePath
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Grab the IO abstraction we need to get any work done
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiIsaIoProtocolGuid,
 | 
						|
                  (VOID **) &IsaIo,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
 | 
						|
    goto Error;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Status == EFI_ALREADY_STARTED) {
 | 
						|
 | 
						|
    if (RemainingDevicePath == NULL) {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Make sure a child handle does not already exist.  This driver can only
 | 
						|
    // produce one child per serial port.
 | 
						|
    //
 | 
						|
    Status = gBS->OpenProtocolInformation (
 | 
						|
                    Controller,
 | 
						|
                    &gEfiIsaIoProtocolGuid,
 | 
						|
                    &OpenInfoBuffer,
 | 
						|
                    &EntryCount
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = EFI_ALREADY_STARTED;
 | 
						|
    for (Index = 0; Index < EntryCount; Index++) {
 | 
						|
      if (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
 | 
						|
        Status = gBS->OpenProtocol (
 | 
						|
                        OpenInfoBuffer[Index].ControllerHandle,
 | 
						|
                        &gEfiSerialIoProtocolGuid,
 | 
						|
                        (VOID **) &SerialIo,
 | 
						|
                        This->DriverBindingHandle,
 | 
						|
                        Controller,
 | 
						|
                        EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                        );
 | 
						|
        if (!EFI_ERROR (Status)) {
 | 
						|
          CopyMem (&Node, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
 | 
						|
          Status = SerialIo->SetAttributes (
 | 
						|
                               SerialIo,
 | 
						|
                               Node.BaudRate,
 | 
						|
                               SerialIo->Mode->ReceiveFifoDepth,
 | 
						|
                               SerialIo->Mode->Timeout,
 | 
						|
                               (EFI_PARITY_TYPE) Node.Parity,
 | 
						|
                               Node.DataBits,
 | 
						|
                               (EFI_STOP_BITS_TYPE) Node.StopBits
 | 
						|
                               );
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    gBS->FreePool (OpenInfoBuffer);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Initialize the serial device instance
 | 
						|
  //
 | 
						|
  SerialDevice = AllocateCopyPool (sizeof (SERIAL_DEV), &gSerialDevTempate);
 | 
						|
  if (SerialDevice == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto Error;
 | 
						|
  }
 | 
						|
 | 
						|
  SerialDevice->SerialIo.Mode       = &(SerialDevice->SerialMode);
 | 
						|
  SerialDevice->IsaIo               = IsaIo;
 | 
						|
  SerialDevice->ParentDevicePath    = ParentDevicePath;
 | 
						|
 | 
						|
  ADD_SERIAL_NAME (SerialDevice, IsaIo);
 | 
						|
 | 
						|
  for (Index = 0; SerialDevice->IsaIo->ResourceList->ResourceItem[Index].Type != EfiIsaAcpiResourceEndOfList; Index++) {
 | 
						|
    if (SerialDevice->IsaIo->ResourceList->ResourceItem[Index].Type == EfiIsaAcpiResourceIo) {
 | 
						|
      SerialDevice->BaseAddress = (UINT16) SerialDevice->IsaIo->ResourceList->ResourceItem[Index].StartRange;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Report status code the serial present
 | 
						|
  //
 | 
						|
  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
    EFI_PROGRESS_CODE,
 | 
						|
    EFI_P_PC_PRESENCE_DETECT | EFI_PERIPHERAL_SERIAL_PORT,
 | 
						|
    ParentDevicePath
 | 
						|
    );
 | 
						|
 | 
						|
  if (!IsaSerialPortPresent (SerialDevice)) {
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
      EFI_ERROR_CODE,
 | 
						|
      EFI_P_EC_NOT_DETECTED | EFI_PERIPHERAL_SERIAL_PORT,
 | 
						|
      ParentDevicePath
 | 
						|
      );
 | 
						|
    goto Error;
 | 
						|
  }
 | 
						|
 | 
						|
  if (RemainingDevicePath != NULL) {
 | 
						|
    //
 | 
						|
    // Match the configuration of the RemainingDevicePath. IsHandleSupported()
 | 
						|
    // already checked to make sure the RemainingDevicePath contains settings
 | 
						|
    // that we can support.
 | 
						|
    //
 | 
						|
    CopyMem (&SerialDevice->UartDevicePath, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Use the values from the gSerialDevTempate as no remaining device path was
 | 
						|
    // passed in.
 | 
						|
    //
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Build the device path by appending the UART node to the ParentDevicePath
 | 
						|
  // from the WinNtIo handle. The Uart setings are zero here, since
 | 
						|
  // SetAttribute() will update them to match the current setings.
 | 
						|
  //
 | 
						|
  SerialDevice->DevicePath = AppendDevicePathNode (
 | 
						|
                               ParentDevicePath,
 | 
						|
                               (EFI_DEVICE_PATH_PROTOCOL *)&SerialDevice->UartDevicePath
 | 
						|
                               );
 | 
						|
  if (SerialDevice->DevicePath == NULL) {
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
    goto Error;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
 | 
						|
  //
 | 
						|
  SerialDevice->SerialMode.BaudRate         = SerialDevice->UartDevicePath.BaudRate;
 | 
						|
  SerialDevice->SerialMode.DataBits         = SerialDevice->UartDevicePath.DataBits;
 | 
						|
  SerialDevice->SerialMode.Parity           = SerialDevice->UartDevicePath.Parity;
 | 
						|
  SerialDevice->SerialMode.StopBits         = SerialDevice->UartDevicePath.StopBits;
 | 
						|
 | 
						|
  //
 | 
						|
  // Issue a reset to initialize the COM port
 | 
						|
  //
 | 
						|
  Status = SerialDevice->SerialIo.Reset (&SerialDevice->SerialIo);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
      EFI_ERROR_CODE,
 | 
						|
      EFI_P_EC_CONTROLLER_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
 | 
						|
      ParentDevicePath
 | 
						|
      );
 | 
						|
    goto Error;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Install protocol interfaces for the serial device.
 | 
						|
  //
 | 
						|
  Status = gBS->InstallMultipleProtocolInterfaces (
 | 
						|
                  &SerialDevice->Handle,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  SerialDevice->DevicePath,
 | 
						|
                  &gEfiSerialIoProtocolGuid,
 | 
						|
                  &SerialDevice->SerialIo,
 | 
						|
                  NULL
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto Error;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Open For Child Device
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiIsaIoProtocolGuid,
 | 
						|
                  (VOID **) &IsaIo,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  SerialDevice->Handle,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | 
						|
                  );
 | 
						|
 | 
						|
Error:
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->CloseProtocol (
 | 
						|
           Controller,
 | 
						|
           &gEfiDevicePathProtocolGuid,
 | 
						|
           This->DriverBindingHandle,
 | 
						|
           Controller
 | 
						|
           );
 | 
						|
    gBS->CloseProtocol (
 | 
						|
           Controller,
 | 
						|
           &gEfiIsaIoProtocolGuid,
 | 
						|
           This->DriverBindingHandle,
 | 
						|
           Controller
 | 
						|
           );
 | 
						|
    if (SerialDevice) {
 | 
						|
      if (SerialDevice->DevicePath) {
 | 
						|
        gBS->FreePool (SerialDevice->DevicePath);
 | 
						|
      }
 | 
						|
 | 
						|
      FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
 | 
						|
      gBS->FreePool (SerialDevice);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SerialControllerDriverStop (
 | 
						|
  IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
 | 
						|
  IN  EFI_HANDLE                     Controller,
 | 
						|
  IN  UINTN                          NumberOfChildren,
 | 
						|
  IN  EFI_HANDLE                     *ChildHandleBuffer
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Disconnect this driver with the controller, uninstall related protocol instance
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    This                - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
 | 
						|
    Controller          - The handle of the controller to test.
 | 
						|
    NumberOfChildren    - Number of child device.
 | 
						|
    RemainingDevicePath - A pointer to the remaining portion of a device path.
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    EFI_SUCCESS         - Operation successfully
 | 
						|
    EFI_DEVICE_ERROR    - Cannot stop the driver successfully
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS                          Status;
 | 
						|
  UINTN                               Index;
 | 
						|
  BOOLEAN                             AllChildrenStopped;
 | 
						|
  EFI_SERIAL_IO_PROTOCOL              *SerialIo;
 | 
						|
  SERIAL_DEV                          *SerialDevice;
 | 
						|
  EFI_ISA_IO_PROTOCOL                 *IsaIo;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL            *DevicePath;
 | 
						|
 | 
						|
  Status = gBS->HandleProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  (VOID **) &DevicePath
 | 
						|
                  );
 | 
						|
 | 
						|
  //
 | 
						|
  // Report the status code disable the serial
 | 
						|
  //
 | 
						|
  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
    EFI_PROGRESS_CODE,
 | 
						|
    EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT,
 | 
						|
    DevicePath
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Complete all outstanding transactions to Controller.
 | 
						|
  // Don't allow any new transaction to Controller to be started.
 | 
						|
  //
 | 
						|
  if (NumberOfChildren == 0) {
 | 
						|
    //
 | 
						|
    // Close the bus driver
 | 
						|
    //
 | 
						|
    Status = gBS->CloseProtocol (
 | 
						|
                    Controller,
 | 
						|
                    &gEfiIsaIoProtocolGuid,
 | 
						|
                    This->DriverBindingHandle,
 | 
						|
                    Controller
 | 
						|
                    );
 | 
						|
 | 
						|
    Status = gBS->CloseProtocol (
 | 
						|
                    Controller,
 | 
						|
                    &gEfiDevicePathProtocolGuid,
 | 
						|
                    This->DriverBindingHandle,
 | 
						|
                    Controller
 | 
						|
                    );
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  AllChildrenStopped = TRUE;
 | 
						|
 | 
						|
  for (Index = 0; Index < NumberOfChildren; Index++) {
 | 
						|
 | 
						|
    Status = gBS->OpenProtocol (
 | 
						|
                    ChildHandleBuffer[Index],
 | 
						|
                    &gEfiSerialIoProtocolGuid,
 | 
						|
                    (VOID **) &SerialIo,
 | 
						|
                    This->DriverBindingHandle,
 | 
						|
                    Controller,
 | 
						|
                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                    );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
 | 
						|
      SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);
 | 
						|
 | 
						|
      Status = gBS->CloseProtocol (
 | 
						|
                      Controller,
 | 
						|
                      &gEfiIsaIoProtocolGuid,
 | 
						|
                      This->DriverBindingHandle,
 | 
						|
                      ChildHandleBuffer[Index]
 | 
						|
                      );
 | 
						|
 | 
						|
      Status = gBS->UninstallMultipleProtocolInterfaces (
 | 
						|
                      ChildHandleBuffer[Index],
 | 
						|
                      &gEfiDevicePathProtocolGuid,
 | 
						|
                      SerialDevice->DevicePath,
 | 
						|
                      &gEfiSerialIoProtocolGuid,
 | 
						|
                      &SerialDevice->SerialIo,
 | 
						|
                      NULL
 | 
						|
                      );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        gBS->OpenProtocol (
 | 
						|
               Controller,
 | 
						|
               &gEfiIsaIoProtocolGuid,
 | 
						|
               (VOID **) &IsaIo,
 | 
						|
               This->DriverBindingHandle,
 | 
						|
               ChildHandleBuffer[Index],
 | 
						|
               EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | 
						|
               );
 | 
						|
      } else {
 | 
						|
        if (SerialDevice->DevicePath) {
 | 
						|
          gBS->FreePool (SerialDevice->DevicePath);
 | 
						|
        }
 | 
						|
 | 
						|
        FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
 | 
						|
        gBS->FreePool (SerialDevice);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      AllChildrenStopped = FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!AllChildrenStopped) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
BOOLEAN
 | 
						|
IsaSerialFifoFull (
 | 
						|
  IN SERIAL_DEV_FIFO *Fifo
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Detect whether specific FIFO is full or not
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    Fifo  - A pointer to the Data Structure SERIAL_DEV_FIFO
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    TRUE  - the FIFO is full
 | 
						|
    FALSE - the FIFO is not full
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  if (Fifo->Surplus == 0) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
BOOLEAN
 | 
						|
IsaSerialFifoEmpty (
 | 
						|
  IN SERIAL_DEV_FIFO *Fifo
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Detect whether specific FIFO is empty or not
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    Fifo  - A pointer to the Data Structure SERIAL_DEV_FIFO
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    TRUE  - the FIFO is empty
 | 
						|
    FALSE - the FIFO is not empty
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
IsaSerialFifoAdd (
 | 
						|
  IN SERIAL_DEV_FIFO *Fifo,
 | 
						|
  IN UINT8           Data
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Add data to specific FIFO
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    Fifo                - A pointer to the Data Structure SERIAL_DEV_FIFO
 | 
						|
    Data                - the data added to FIFO
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    EFI_SUCCESS         - Add data to specific FIFO successfully
 | 
						|
    EFI_OUT_OF_RESOURCE - Failed to add data because FIFO is already full
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  //
 | 
						|
  // if FIFO full can not add data
 | 
						|
  //
 | 
						|
  if (IsaSerialFifoFull (Fifo)) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // FIFO is not full can add data
 | 
						|
  //
 | 
						|
  Fifo->Data[Fifo->Last] = Data;
 | 
						|
  Fifo->Surplus--;
 | 
						|
  Fifo->Last++;
 | 
						|
  if (Fifo->Last == SERIAL_MAX_BUFFER_SIZE) {
 | 
						|
    Fifo->Last = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
IsaSerialFifoRemove (
 | 
						|
  IN  SERIAL_DEV_FIFO *Fifo,
 | 
						|
  OUT UINT8           *Data
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Remove data from specific FIFO
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    Fifo                - A pointer to the Data Structure SERIAL_DEV_FIFO
 | 
						|
    Data                - the data removed from FIFO
 | 
						|
 | 
						|
  Returns:
 | 
						|
    EFI_SUCCESS         - Remove data from specific FIFO successfully
 | 
						|
    EFI_OUT_OF_RESOURCE - Failed to remove data because FIFO is empty
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  //
 | 
						|
  // if FIFO is empty, no data can remove
 | 
						|
  //
 | 
						|
  if (IsaSerialFifoEmpty (Fifo)) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // FIFO is not empty, can remove data
 | 
						|
  //
 | 
						|
  *Data = Fifo->Data[Fifo->First];
 | 
						|
  Fifo->Surplus++;
 | 
						|
  Fifo->First++;
 | 
						|
  if (Fifo->First == SERIAL_MAX_BUFFER_SIZE) {
 | 
						|
    Fifo->First = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
IsaSerialReceiveTransmit (
 | 
						|
  IN SERIAL_DEV *SerialDevice
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Reads and writes all avaliable data.
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    SerialDevice        - The device to flush
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    EFI_SUCCESS         - Data was read/written successfully.
 | 
						|
    EFI_OUT_OF_RESOURCE - Failed because software receive FIFO is full.  Note, when
 | 
						|
                          this happens, pending writes are not done.
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  SERIAL_PORT_LSR Lsr;
 | 
						|
  UINT8           Data;
 | 
						|
  BOOLEAN         ReceiveFifoFull;
 | 
						|
  SERIAL_PORT_MSR Msr;
 | 
						|
  SERIAL_PORT_MCR Mcr;
 | 
						|
  UINTN           TimeOut;
 | 
						|
 | 
						|
  Data = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // Begin the read or write
 | 
						|
  //
 | 
						|
  if (SerialDevice->SoftwareLoopbackEnable) {
 | 
						|
    do {
 | 
						|
      ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
 | 
						|
      if (!IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
 | 
						|
        IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);
 | 
						|
        if (ReceiveFifoFull) {
 | 
						|
          return EFI_OUT_OF_RESOURCES;
 | 
						|
        }
 | 
						|
 | 
						|
        IsaSerialFifoAdd (&SerialDevice->Receive, Data);
 | 
						|
      }
 | 
						|
    } while (!IsaSerialFifoEmpty (&SerialDevice->Transmit));
 | 
						|
  } else {
 | 
						|
    ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
 | 
						|
    do {
 | 
						|
      Lsr.Data = READ_LSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
 | 
						|
      if (FeaturePcdGet (PcdNtEmulatorEnable)) {
 | 
						|
        //
 | 
						|
        // This is required for NT to avoid a forever-spin...
 | 
						|
        // This would be better if READ_LSR was a polling operation
 | 
						|
        // that would timeout.
 | 
						|
        //
 | 
						|
        Lsr.Bits.THRE = 1;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Flush incomming data to prevent a an overrun during a long write
 | 
						|
      //
 | 
						|
      if (Lsr.Bits.DR && !ReceiveFifoFull) {
 | 
						|
        ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
 | 
						|
        if (!ReceiveFifoFull) {
 | 
						|
          if (Lsr.Bits.FIFOE || Lsr.Bits.OE || Lsr.Bits.PE || Lsr.Bits.FE || Lsr.Bits.BI) {
 | 
						|
            REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
              EFI_ERROR_CODE,
 | 
						|
              EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
 | 
						|
              SerialDevice->DevicePath
 | 
						|
              );
 | 
						|
            if (Lsr.Bits.FIFOE || Lsr.Bits.PE || Lsr.Bits.FE || Lsr.Bits.BI) {
 | 
						|
              Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
              continue;
 | 
						|
            }
 | 
						|
          }
 | 
						|
          //
 | 
						|
          // Make sure the receive data will not be missed, Assert DTR
 | 
						|
          //
 | 
						|
          if (SerialDevice->HardwareFlowControl) {
 | 
						|
            Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
            Mcr.Bits.DTRC &= 0;
 | 
						|
            WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
 | 
						|
          }
 | 
						|
 | 
						|
          Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
 | 
						|
          //
 | 
						|
          // Deassert DTR
 | 
						|
          //
 | 
						|
          if (SerialDevice->HardwareFlowControl) {
 | 
						|
            Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
            Mcr.Bits.DTRC |= 1;
 | 
						|
            WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
 | 
						|
          }
 | 
						|
 | 
						|
          IsaSerialFifoAdd (&SerialDevice->Receive, Data);
 | 
						|
 | 
						|
          continue;
 | 
						|
        } else {
 | 
						|
          REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
            EFI_PROGRESS_CODE,
 | 
						|
            EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT,
 | 
						|
            SerialDevice->DevicePath
 | 
						|
            );
 | 
						|
        }
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Do the write
 | 
						|
      //
 | 
						|
      if (Lsr.Bits.THRE && !IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
 | 
						|
        //
 | 
						|
        // Make sure the transmit data will not be missed
 | 
						|
        //
 | 
						|
        if (SerialDevice->HardwareFlowControl) {
 | 
						|
          //
 | 
						|
          // Send RTS
 | 
						|
          //
 | 
						|
          Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
          Mcr.Bits.RTS |= 1;
 | 
						|
          WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
 | 
						|
          //
 | 
						|
          // Wait for CTS
 | 
						|
          //
 | 
						|
          TimeOut   = 0;
 | 
						|
          Msr.Data  = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
          while (!Msr.Bits.CTS) {
 | 
						|
            gBS->Stall (TIMEOUT_STALL_INTERVAL);
 | 
						|
            TimeOut++;
 | 
						|
            if (TimeOut > 5) {
 | 
						|
              break;
 | 
						|
            }
 | 
						|
 | 
						|
            Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
          }
 | 
						|
 | 
						|
          if (Msr.Bits.CTS) {
 | 
						|
            IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);
 | 
						|
            WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data);
 | 
						|
          }
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // write the data out
 | 
						|
        //
 | 
						|
        if (!SerialDevice->HardwareFlowControl) {
 | 
						|
          IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);
 | 
						|
          WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data);
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // Make sure the transmit data will not be missed
 | 
						|
        //
 | 
						|
        if (SerialDevice->HardwareFlowControl) {
 | 
						|
          //
 | 
						|
          // Assert RTS
 | 
						|
          //
 | 
						|
          Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
          Mcr.Bits.RTS &= 0;
 | 
						|
          WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } while (Lsr.Bits.THRE && !IsaSerialFifoEmpty (&SerialDevice->Transmit));
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
//
 | 
						|
// Interface Functions
 | 
						|
//
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
IsaSerialReset (
 | 
						|
  IN EFI_SERIAL_IO_PROTOCOL  *This
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Reset serial device
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    This             - Pointer to EFI_SERIAL_IO_PROTOCOL
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    EFI_SUCCESS      - Reset successfully
 | 
						|
    EFI_DEVICE_ERROR - Failed to reset
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS      Status;
 | 
						|
  SERIAL_DEV      *SerialDevice;
 | 
						|
  SERIAL_PORT_LCR Lcr;
 | 
						|
  SERIAL_PORT_IER Ier;
 | 
						|
  SERIAL_PORT_MCR Mcr;
 | 
						|
  SERIAL_PORT_FCR Fcr;
 | 
						|
  EFI_TPL         Tpl;
 | 
						|
 | 
						|
  SerialDevice = SERIAL_DEV_FROM_THIS (This);
 | 
						|
 | 
						|
  //
 | 
						|
  // Report the status code reset the serial
 | 
						|
  //
 | 
						|
  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
    EFI_PROGRESS_CODE,
 | 
						|
    EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT,
 | 
						|
    SerialDevice->DevicePath
 | 
						|
    );
 | 
						|
 | 
						|
  Tpl = gBS->RaiseTPL (TPL_NOTIFY);
 | 
						|
 | 
						|
  //
 | 
						|
  // Make sure DLAB is 0.
 | 
						|
  //
 | 
						|
  Lcr.Data      = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
  Lcr.Bits.DLAB = 0;
 | 
						|
  WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
 | 
						|
 | 
						|
  //
 | 
						|
  // Turn off all interrupts
 | 
						|
  //
 | 
						|
  Ier.Data        = READ_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
  Ier.Bits.RAVIE  = 0;
 | 
						|
  Ier.Bits.THEIE  = 0;
 | 
						|
  Ier.Bits.RIE    = 0;
 | 
						|
  Ier.Bits.MIE    = 0;
 | 
						|
  WRITE_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress, Ier.Data);
 | 
						|
 | 
						|
  //
 | 
						|
  // Disable the FIFO.
 | 
						|
  //
 | 
						|
  Fcr.Bits.TRFIFOE = 0;
 | 
						|
  WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data);
 | 
						|
 | 
						|
  //
 | 
						|
  // Turn off loopback and disable device interrupt.
 | 
						|
  //
 | 
						|
  Mcr.Data      = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
  Mcr.Bits.OUT1 = 0;
 | 
						|
  Mcr.Bits.OUT2 = 0;
 | 
						|
  Mcr.Bits.LME  = 0;
 | 
						|
  WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
 | 
						|
 | 
						|
  //
 | 
						|
  // Clear the scratch pad register
 | 
						|
  //
 | 
						|
  WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // Go set the current attributes
 | 
						|
  //
 | 
						|
  Status = This->SetAttributes (
 | 
						|
                   This,
 | 
						|
                   This->Mode->BaudRate,
 | 
						|
                   This->Mode->ReceiveFifoDepth,
 | 
						|
                   This->Mode->Timeout,
 | 
						|
                   (EFI_PARITY_TYPE) This->Mode->Parity,
 | 
						|
                   (UINT8) This->Mode->DataBits,
 | 
						|
                   (EFI_STOP_BITS_TYPE) This->Mode->StopBits
 | 
						|
                   );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->RestoreTPL (Tpl);
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Go set the current control bits
 | 
						|
  //
 | 
						|
  Status = This->SetControl (
 | 
						|
                   This,
 | 
						|
                   This->Mode->ControlMask
 | 
						|
                   );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->RestoreTPL (Tpl);
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // for 16550A enable FIFO, 16550 disable FIFO
 | 
						|
  //
 | 
						|
  Fcr.Bits.TRFIFOE  = 1;
 | 
						|
  Fcr.Bits.RESETRF  = 1;
 | 
						|
  Fcr.Bits.RESETTF  = 1;
 | 
						|
  WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data);
 | 
						|
 | 
						|
  //
 | 
						|
  // Reset the software FIFO
 | 
						|
  //
 | 
						|
  SerialDevice->Receive.First     = 0;
 | 
						|
  SerialDevice->Receive.Last      = 0;
 | 
						|
  SerialDevice->Receive.Surplus   = SERIAL_MAX_BUFFER_SIZE;
 | 
						|
  SerialDevice->Transmit.First    = 0;
 | 
						|
  SerialDevice->Transmit.Last     = 0;
 | 
						|
  SerialDevice->Transmit.Surplus  = SERIAL_MAX_BUFFER_SIZE;
 | 
						|
 | 
						|
  gBS->RestoreTPL (Tpl);
 | 
						|
 | 
						|
  //
 | 
						|
  // Device reset is complete
 | 
						|
  //
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
IsaSerialSetAttributes (
 | 
						|
  IN EFI_SERIAL_IO_PROTOCOL  *This,
 | 
						|
  IN UINT64                  BaudRate,
 | 
						|
  IN UINT32                  ReceiveFifoDepth,
 | 
						|
  IN UINT32                  Timeout,
 | 
						|
  IN EFI_PARITY_TYPE         Parity,
 | 
						|
  IN UINT8                   DataBits,
 | 
						|
  IN EFI_STOP_BITS_TYPE      StopBits
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Set new attributes to a serial device
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    This                   - Pointer to EFI_SERIAL_IO_PROTOCOL
 | 
						|
    BaudRate               - The baudrate of the serial device
 | 
						|
    ReceiveFifoDepth       - The depth of receive FIFO buffer
 | 
						|
    Timeout                - The request timeout for a single char
 | 
						|
    Parity                 - The type of parity used in serial device
 | 
						|
    DataBits               - Number of databits used in serial device
 | 
						|
    StopBits               - Number of stopbits used in serial device
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    EFI_SUCCESS            - The new attributes were set
 | 
						|
    EFI_INVALID_PARAMETERS - One or more attributes have an unsupported value
 | 
						|
    EFI_UNSUPPORTED        - Data Bits can not set to 5 or 6
 | 
						|
    EFI_DEVICE_ERROR       - The serial device is not functioning correctly (no return)
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  SERIAL_DEV                *SerialDevice;
 | 
						|
  UINT32                    Divisor;
 | 
						|
  UINT32                    Remained;
 | 
						|
  SERIAL_PORT_LCR           Lcr;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
 | 
						|
  EFI_TPL                   Tpl;
 | 
						|
 | 
						|
  SerialDevice = SERIAL_DEV_FROM_THIS (This);
 | 
						|
 | 
						|
  //
 | 
						|
  // Check for default settings and fill in actual values.
 | 
						|
  //
 | 
						|
  if (BaudRate == 0) {
 | 
						|
    BaudRate = FixedPcdGet64 (PcdUartDefaultBaudRate);
 | 
						|
  }
 | 
						|
 | 
						|
  if (ReceiveFifoDepth == 0) {
 | 
						|
    ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Timeout == 0) {
 | 
						|
    Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Parity == DefaultParity) {
 | 
						|
    Parity = (EFI_PARITY_TYPE)FixedPcdGet8 (PcdUartDefaultParity);
 | 
						|
  }
 | 
						|
 | 
						|
  if (DataBits == 0) {
 | 
						|
    DataBits = FixedPcdGet8 (PcdUartDefaultDataBits);
 | 
						|
  }
 | 
						|
 | 
						|
  if (StopBits == DefaultStopBits) {
 | 
						|
    StopBits = (EFI_STOP_BITS_TYPE) FixedPcdGet8 (PcdUartDefaultStopBits);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // 5 and 6 data bits can not be verified on a 16550A UART
 | 
						|
  // Return EFI_INVALID_PARAMETER if an attempt is made to use these settings.
 | 
						|
  //
 | 
						|
  if ((DataBits == 5) || (DataBits == 6)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Make sure all parameters are valid
 | 
						|
  //
 | 
						|
  if ((BaudRate > SERIAL_PORT_MAX_BAUD_RATE) || (BaudRate < SERIAL_PORT_MIN_BAUD_RATE)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // 50,75,110,134,150,300,600,1200,1800,2000,2400,3600,4800,7200,9600,19200,
 | 
						|
  // 38400,57600,115200
 | 
						|
  //
 | 
						|
  if (BaudRate < 75) {
 | 
						|
    BaudRate = 50;
 | 
						|
  } else if (BaudRate < 110) {
 | 
						|
    BaudRate = 75;
 | 
						|
  } else if (BaudRate < 134) {
 | 
						|
    BaudRate = 110;
 | 
						|
  } else if (BaudRate < 150) {
 | 
						|
    BaudRate = 134;
 | 
						|
  } else if (BaudRate < 300) {
 | 
						|
    BaudRate = 150;
 | 
						|
  } else if (BaudRate < 600) {
 | 
						|
    BaudRate = 300;
 | 
						|
  } else if (BaudRate < 1200) {
 | 
						|
    BaudRate = 600;
 | 
						|
  } else if (BaudRate < 1800) {
 | 
						|
    BaudRate = 1200;
 | 
						|
  } else if (BaudRate < 2000) {
 | 
						|
    BaudRate = 1800;
 | 
						|
  } else if (BaudRate < 2400) {
 | 
						|
    BaudRate = 2000;
 | 
						|
  } else if (BaudRate < 3600) {
 | 
						|
    BaudRate = 2400;
 | 
						|
  } else if (BaudRate < 4800) {
 | 
						|
    BaudRate = 3600;
 | 
						|
  } else if (BaudRate < 7200) {
 | 
						|
    BaudRate = 4800;
 | 
						|
  } else if (BaudRate < 9600) {
 | 
						|
    BaudRate = 7200;
 | 
						|
  } else if (BaudRate < 19200) {
 | 
						|
    BaudRate = 9600;
 | 
						|
  } else if (BaudRate < 38400) {
 | 
						|
    BaudRate = 19200;
 | 
						|
  } else if (BaudRate < 57600) {
 | 
						|
    BaudRate = 38400;
 | 
						|
  } else if (BaudRate < 115200) {
 | 
						|
    BaudRate = 57600;
 | 
						|
  } else if (BaudRate <= SERIAL_PORT_MAX_BAUD_RATE) {
 | 
						|
    BaudRate = 115200;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((ReceiveFifoDepth < 1) || (ReceiveFifoDepth > SERIAL_PORT_MAX_RECEIVE_FIFO_DEPTH)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Parity < NoParity) || (Parity > SpaceParity)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((DataBits < 5) || (DataBits > 8)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((StopBits < OneStopBit) || (StopBits > TwoStopBits)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // for DataBits = 5, StopBits can not set TwoStopBits
 | 
						|
  //
 | 
						|
  // if ((DataBits == 5) && (StopBits == TwoStopBits)) {
 | 
						|
  //  return EFI_INVALID_PARAMETER;
 | 
						|
  // }
 | 
						|
  //
 | 
						|
  // for DataBits = 6,7,8, StopBits can not set OneFiveStopBits
 | 
						|
  //
 | 
						|
  if ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Compute divisor use to program the baud rate using a round determination
 | 
						|
  //
 | 
						|
  Divisor = (UINT32) DivU64x32Remainder (
 | 
						|
                       SERIAL_PORT_INPUT_CLOCK,
 | 
						|
                       ((UINT32) BaudRate * 16),
 | 
						|
                       &Remained
 | 
						|
                       );
 | 
						|
  if (Remained) {
 | 
						|
    Divisor += 1;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Divisor == 0) || (Divisor & 0xffff0000)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Tpl = gBS->RaiseTPL (TPL_NOTIFY);
 | 
						|
 | 
						|
  //
 | 
						|
  // Compute the actual baud rate that the serial port will be programmed for.
 | 
						|
  //
 | 
						|
  BaudRate = SERIAL_PORT_INPUT_CLOCK / Divisor / 16;
 | 
						|
 | 
						|
  //
 | 
						|
  // Put serial port on Divisor Latch Mode
 | 
						|
  //
 | 
						|
  Lcr.Data      = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
  Lcr.Bits.DLAB = 1;
 | 
						|
  WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
 | 
						|
 | 
						|
  //
 | 
						|
  // Write the divisor to the serial port
 | 
						|
  //
 | 
						|
  WRITE_DLL (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) (Divisor & 0xff));
 | 
						|
  WRITE_DLM (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) ((Divisor >> 8) & 0xff));
 | 
						|
 | 
						|
  //
 | 
						|
  // Put serial port back in normal mode and set remaining attributes.
 | 
						|
  //
 | 
						|
  Lcr.Bits.DLAB = 0;
 | 
						|
 | 
						|
  switch (Parity) {
 | 
						|
  case NoParity:
 | 
						|
    Lcr.Bits.PAREN    = 0;
 | 
						|
    Lcr.Bits.EVENPAR  = 0;
 | 
						|
    Lcr.Bits.STICPAR  = 0;
 | 
						|
    break;
 | 
						|
 | 
						|
  case EvenParity:
 | 
						|
    Lcr.Bits.PAREN    = 1;
 | 
						|
    Lcr.Bits.EVENPAR  = 1;
 | 
						|
    Lcr.Bits.STICPAR  = 0;
 | 
						|
    break;
 | 
						|
 | 
						|
  case OddParity:
 | 
						|
    Lcr.Bits.PAREN    = 1;
 | 
						|
    Lcr.Bits.EVENPAR  = 0;
 | 
						|
    Lcr.Bits.STICPAR  = 0;
 | 
						|
    break;
 | 
						|
 | 
						|
  case SpaceParity:
 | 
						|
    Lcr.Bits.PAREN    = 1;
 | 
						|
    Lcr.Bits.EVENPAR  = 1;
 | 
						|
    Lcr.Bits.STICPAR  = 1;
 | 
						|
    break;
 | 
						|
 | 
						|
  case MarkParity:
 | 
						|
    Lcr.Bits.PAREN    = 1;
 | 
						|
    Lcr.Bits.EVENPAR  = 0;
 | 
						|
    Lcr.Bits.STICPAR  = 1;
 | 
						|
    break;
 | 
						|
 | 
						|
  default:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  switch (StopBits) {
 | 
						|
  case OneStopBit:
 | 
						|
    Lcr.Bits.STOPB = 0;
 | 
						|
    break;
 | 
						|
 | 
						|
  case OneFiveStopBits:
 | 
						|
  case TwoStopBits:
 | 
						|
    Lcr.Bits.STOPB = 1;
 | 
						|
    break;
 | 
						|
 | 
						|
  default:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // DataBits
 | 
						|
  //
 | 
						|
  Lcr.Bits.SERIALDB = (UINT8) ((DataBits - 5) & 0x03);
 | 
						|
  WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
 | 
						|
 | 
						|
  //
 | 
						|
  // Set the Serial I/O mode
 | 
						|
  //
 | 
						|
  This->Mode->BaudRate          = BaudRate;
 | 
						|
  This->Mode->ReceiveFifoDepth  = ReceiveFifoDepth;
 | 
						|
  This->Mode->Timeout           = Timeout;
 | 
						|
  This->Mode->Parity            = Parity;
 | 
						|
  This->Mode->DataBits          = DataBits;
 | 
						|
  This->Mode->StopBits          = StopBits;
 | 
						|
 | 
						|
  //
 | 
						|
  // See if Device Path Node has actually changed
 | 
						|
  //
 | 
						|
  if (SerialDevice->UartDevicePath.BaudRate == BaudRate &&
 | 
						|
      SerialDevice->UartDevicePath.DataBits == DataBits &&
 | 
						|
      SerialDevice->UartDevicePath.Parity == Parity &&
 | 
						|
      SerialDevice->UartDevicePath.StopBits == StopBits
 | 
						|
      ) {
 | 
						|
    gBS->RestoreTPL (Tpl);
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Update the device path
 | 
						|
  //
 | 
						|
  SerialDevice->UartDevicePath.BaudRate = BaudRate;
 | 
						|
  SerialDevice->UartDevicePath.DataBits = DataBits;
 | 
						|
  SerialDevice->UartDevicePath.Parity   = (UINT8) Parity;
 | 
						|
  SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits;
 | 
						|
 | 
						|
  NewDevicePath = AppendDevicePathNode (
 | 
						|
                    SerialDevice->ParentDevicePath,
 | 
						|
                    (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath
 | 
						|
                    );
 | 
						|
  if (NewDevicePath == NULL) {
 | 
						|
    gBS->RestoreTPL (Tpl);
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (SerialDevice->Handle != NULL) {
 | 
						|
    Status = gBS->ReinstallProtocolInterface (
 | 
						|
                    SerialDevice->Handle,
 | 
						|
                    &gEfiDevicePathProtocolGuid,
 | 
						|
                    SerialDevice->DevicePath,
 | 
						|
                    NewDevicePath
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      gBS->RestoreTPL (Tpl);
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (SerialDevice->DevicePath) {
 | 
						|
    gBS->FreePool (SerialDevice->DevicePath);
 | 
						|
  }
 | 
						|
 | 
						|
  SerialDevice->DevicePath = NewDevicePath;
 | 
						|
 | 
						|
  gBS->RestoreTPL (Tpl);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
IsaSerialSetControl (
 | 
						|
  IN EFI_SERIAL_IO_PROTOCOL  *This,
 | 
						|
  IN UINT32                  Control
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Set Control Bits
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    This            - Pointer to EFI_SERIAL_IO_PROTOCOL
 | 
						|
    Control         - Control bits that can be settable
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    EFI_SUCCESS     - New Control bits were set successfully
 | 
						|
    EFI_UNSUPPORTED - The Control bits wanted to set are not supported
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  SERIAL_DEV      *SerialDevice;
 | 
						|
  SERIAL_PORT_MCR Mcr;
 | 
						|
  EFI_TPL         Tpl;
 | 
						|
 | 
						|
  //
 | 
						|
  // The control bits that can be set are :
 | 
						|
  //     EFI_SERIAL_DATA_TERMINAL_READY: 0x0001  // WO
 | 
						|
  //     EFI_SERIAL_REQUEST_TO_SEND: 0x0002  // WO
 | 
						|
  //     EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000  // RW
 | 
						|
  //     EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000  // RW
 | 
						|
  //
 | 
						|
  SerialDevice = SERIAL_DEV_FROM_THIS (This);
 | 
						|
 | 
						|
  //
 | 
						|
  // first determine the parameter is invalid
 | 
						|
  //
 | 
						|
  if (Control & 0xffff8ffc) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  Tpl = gBS->RaiseTPL (TPL_NOTIFY);
 | 
						|
 | 
						|
  Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
  Mcr.Bits.DTRC = 0;
 | 
						|
  Mcr.Bits.RTS = 0;
 | 
						|
  Mcr.Bits.LME = 0;
 | 
						|
  SerialDevice->SoftwareLoopbackEnable = FALSE;
 | 
						|
  SerialDevice->HardwareFlowControl = FALSE;
 | 
						|
 | 
						|
  if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {
 | 
						|
    Mcr.Bits.DTRC = 1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Control & EFI_SERIAL_REQUEST_TO_SEND) {
 | 
						|
    Mcr.Bits.RTS = 1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
 | 
						|
    Mcr.Bits.LME = 1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
 | 
						|
    SerialDevice->HardwareFlowControl = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
 | 
						|
 | 
						|
  if (Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
 | 
						|
    SerialDevice->SoftwareLoopbackEnable = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->RestoreTPL (Tpl);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
IsaSerialGetControl (
 | 
						|
  IN EFI_SERIAL_IO_PROTOCOL  *This,
 | 
						|
  OUT UINT32                 *Control
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Get ControlBits
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    This        - Pointer to EFI_SERIAL_IO_PROTOCOL
 | 
						|
    Control     - Control signals of the serial device
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    EFI_SUCCESS - Get Control signals successfully
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  SERIAL_DEV      *SerialDevice;
 | 
						|
  SERIAL_PORT_MSR Msr;
 | 
						|
  SERIAL_PORT_MCR Mcr;
 | 
						|
  EFI_TPL         Tpl;
 | 
						|
 | 
						|
  Tpl           = gBS->RaiseTPL (TPL_NOTIFY);
 | 
						|
 | 
						|
  SerialDevice  = SERIAL_DEV_FROM_THIS (This);
 | 
						|
 | 
						|
  *Control      = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read the Modem Status Register
 | 
						|
  //
 | 
						|
  Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
 | 
						|
  if (Msr.Bits.CTS) {
 | 
						|
    *Control |= EFI_SERIAL_CLEAR_TO_SEND;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Msr.Bits.DSR) {
 | 
						|
    *Control |= EFI_SERIAL_DATA_SET_READY;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Msr.Bits.RI) {
 | 
						|
    *Control |= EFI_SERIAL_RING_INDICATE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Msr.Bits.DCD) {
 | 
						|
    *Control |= EFI_SERIAL_CARRIER_DETECT;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Read the Modem Control Register
 | 
						|
  //
 | 
						|
  Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
 | 
						|
  if (Mcr.Bits.DTRC) {
 | 
						|
    *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Mcr.Bits.RTS) {
 | 
						|
    *Control |= EFI_SERIAL_REQUEST_TO_SEND;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Mcr.Bits.LME) {
 | 
						|
    *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (SerialDevice->HardwareFlowControl) {
 | 
						|
    *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // See if the Transmit FIFO is empty
 | 
						|
  //
 | 
						|
  IsaSerialReceiveTransmit (SerialDevice);
 | 
						|
 | 
						|
  if (IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
 | 
						|
    *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // See if the Receive FIFO is empty.
 | 
						|
  //
 | 
						|
  IsaSerialReceiveTransmit (SerialDevice);
 | 
						|
 | 
						|
  if (IsaSerialFifoEmpty (&SerialDevice->Receive)) {
 | 
						|
    *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
 | 
						|
  }
 | 
						|
 | 
						|
  if (SerialDevice->SoftwareLoopbackEnable) {
 | 
						|
    *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->RestoreTPL (Tpl);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
IsaSerialWrite (
 | 
						|
  IN EFI_SERIAL_IO_PROTOCOL  *This,
 | 
						|
  IN OUT UINTN               *BufferSize,
 | 
						|
  IN VOID                    *Buffer
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Write the specified number of bytes to serial device
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    This             - Pointer to EFI_SERIAL_IO_PROTOCOL
 | 
						|
    BufferSize       - On input the size of Buffer, on output the amount of
 | 
						|
                       data actually written
 | 
						|
    Buffer           - The buffer of data to write
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    EFI_SUCCESS      - The data were written successfully
 | 
						|
    EFI_DEVICE_ERROR - The device reported an error
 | 
						|
    EFI_TIMEOUT      - The write operation was stopped due to timeout
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  SERIAL_DEV  *SerialDevice;
 | 
						|
  UINT8       *CharBuffer;
 | 
						|
  UINT32      Index;
 | 
						|
  UINTN       Elapsed;
 | 
						|
  UINTN       ActualWrite;
 | 
						|
  EFI_TPL     Tpl;
 | 
						|
 | 
						|
  SerialDevice  = SERIAL_DEV_FROM_THIS (This);
 | 
						|
  Elapsed       = 0;
 | 
						|
  ActualWrite   = 0;
 | 
						|
 | 
						|
  if (*BufferSize == 0) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!Buffer) {
 | 
						|
    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
      EFI_ERROR_CODE,
 | 
						|
      EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
 | 
						|
      SerialDevice->DevicePath
 | 
						|
      );
 | 
						|
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Tpl         = gBS->RaiseTPL (TPL_NOTIFY);
 | 
						|
 | 
						|
  CharBuffer  = (UINT8 *) Buffer;
 | 
						|
 | 
						|
  for (Index = 0; Index < *BufferSize; Index++) {
 | 
						|
    IsaSerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]);
 | 
						|
 | 
						|
    while (IsaSerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
 | 
						|
      //
 | 
						|
      //  Unsuccessful write so check if timeout has expired, if not,
 | 
						|
      //  stall for a bit, increment time elapsed, and try again
 | 
						|
      //
 | 
						|
      if (Elapsed >= This->Mode->Timeout) {
 | 
						|
        *BufferSize = ActualWrite;
 | 
						|
        gBS->RestoreTPL (Tpl);
 | 
						|
        return EFI_TIMEOUT;
 | 
						|
      }
 | 
						|
 | 
						|
      gBS->Stall (TIMEOUT_STALL_INTERVAL);
 | 
						|
 | 
						|
      Elapsed += TIMEOUT_STALL_INTERVAL;
 | 
						|
    }
 | 
						|
 | 
						|
    ActualWrite++;
 | 
						|
    //
 | 
						|
    //  Successful write so reset timeout
 | 
						|
    //
 | 
						|
    Elapsed = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->RestoreTPL (Tpl);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
IsaSerialRead (
 | 
						|
  IN EFI_SERIAL_IO_PROTOCOL  *This,
 | 
						|
  IN OUT UINTN               *BufferSize,
 | 
						|
  OUT VOID                   *Buffer
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Read the specified number of bytes from serial device
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    This             - Pointer to EFI_SERIAL_IO_PROTOCOL
 | 
						|
    BufferSize       - On input the size of Buffer, on output the amount of
 | 
						|
                       data returned in buffer
 | 
						|
    Buffer           -  The buffer to return the data into
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    EFI_SUCCESS      - The data were read successfully
 | 
						|
    EFI_DEVICE_ERROR - The device reported an error
 | 
						|
    EFI_TIMEOUT      - The read operation was stopped due to timeout
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  SERIAL_DEV  *SerialDevice;
 | 
						|
  UINT32      Index;
 | 
						|
  UINT8       *CharBuffer;
 | 
						|
  UINTN       Elapsed;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  EFI_TPL     Tpl;
 | 
						|
 | 
						|
  SerialDevice  = SERIAL_DEV_FROM_THIS (This);
 | 
						|
  Elapsed       = 0;
 | 
						|
 | 
						|
  if (*BufferSize == 0) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!Buffer) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Tpl     = gBS->RaiseTPL (TPL_NOTIFY);
 | 
						|
 | 
						|
  Status  = IsaSerialReceiveTransmit (SerialDevice);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    *BufferSize = 0;
 | 
						|
 | 
						|
    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
      EFI_ERROR_CODE,
 | 
						|
      EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
 | 
						|
      SerialDevice->DevicePath
 | 
						|
      );
 | 
						|
 | 
						|
    gBS->RestoreTPL (Tpl);
 | 
						|
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  CharBuffer = (UINT8 *) Buffer;
 | 
						|
  for (Index = 0; Index < *BufferSize; Index++) {
 | 
						|
    while (IsaSerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) {
 | 
						|
      //
 | 
						|
      //  Unsuccessful read so check if timeout has expired, if not,
 | 
						|
      //  stall for a bit, increment time elapsed, and try again
 | 
						|
      //  Need this time out to get conspliter to work.
 | 
						|
      //
 | 
						|
      if (Elapsed >= This->Mode->Timeout) {
 | 
						|
        *BufferSize = Index;
 | 
						|
        gBS->RestoreTPL (Tpl);
 | 
						|
        return EFI_TIMEOUT;
 | 
						|
      }
 | 
						|
 | 
						|
      gBS->Stall (TIMEOUT_STALL_INTERVAL);
 | 
						|
      Elapsed += TIMEOUT_STALL_INTERVAL;
 | 
						|
 | 
						|
      Status = IsaSerialReceiveTransmit (SerialDevice);
 | 
						|
      if (Status == EFI_DEVICE_ERROR) {
 | 
						|
        *BufferSize = Index;
 | 
						|
        gBS->RestoreTPL (Tpl);
 | 
						|
        return EFI_DEVICE_ERROR;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    //
 | 
						|
    //  Successful read so reset timeout
 | 
						|
    //
 | 
						|
    Elapsed = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  IsaSerialReceiveTransmit (SerialDevice);
 | 
						|
 | 
						|
  gBS->RestoreTPL (Tpl);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
BOOLEAN
 | 
						|
IsaSerialPortPresent (
 | 
						|
  IN SERIAL_DEV *SerialDevice
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Use scratchpad register to test if this serial port is present
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    SerialDevice - Pointer to serial device structure
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    TRUE         - The serial port is present
 | 
						|
    FALSE        - The serial port is NOT present
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINT8   Temp;
 | 
						|
  BOOLEAN Status;
 | 
						|
 | 
						|
  Status = TRUE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Save SCR reg
 | 
						|
  //
 | 
						|
  Temp = READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
 | 
						|
  WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0xAA);
 | 
						|
 | 
						|
  if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0xAA) {
 | 
						|
    if (!FeaturePcdGet (PcdNtEmulatorEnable)) {
 | 
						|
      Status = FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0x55);
 | 
						|
 | 
						|
  if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0x55) {
 | 
						|
    if (!FeaturePcdGet (PcdNtEmulatorEnable)) {
 | 
						|
      Status = FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Restore SCR
 | 
						|
  //
 | 
						|
  WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Temp);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
UINT8
 | 
						|
IsaSerialReadPort (
 | 
						|
  IN EFI_ISA_IO_PROTOCOL                   *IsaIo,
 | 
						|
  IN UINT16                                BaseAddress,
 | 
						|
  IN UINT32                                Offset
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Use IsaIo protocol to read serial port
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    IsaIo       - Pointer to EFI_ISA_IO_PROTOCOL instance
 | 
						|
    BaseAddress - Serial port register group base address
 | 
						|
    Offset      - Offset in register group
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    Data read from serial port
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINT8 Data;
 | 
						|
 | 
						|
  //
 | 
						|
  // Use IsaIo to access IO
 | 
						|
  //
 | 
						|
  IsaIo->Io.Read (
 | 
						|
             IsaIo,
 | 
						|
             EfiIsaIoWidthUint8,
 | 
						|
             BaseAddress + Offset,
 | 
						|
             1,
 | 
						|
             &Data
 | 
						|
             );
 | 
						|
  return Data;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
IsaSerialWritePort (
 | 
						|
  IN EFI_ISA_IO_PROTOCOL                 *IsaIo,
 | 
						|
  IN UINT16                              BaseAddress,
 | 
						|
  IN UINT32                              Offset,
 | 
						|
  IN UINT8                               Data
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Use IsaIo protocol to write serial port
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    IsaIo       - Pointer to EFI_ISA_IO_PROTOCOL instance
 | 
						|
    BaseAddress - Serial port register group base address
 | 
						|
    Offset      - Offset in register group
 | 
						|
    Data        - data which is to be written to some serial port register
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    None
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Use IsaIo to access IO
 | 
						|
  //
 | 
						|
  IsaIo->Io.Write (
 | 
						|
             IsaIo,
 | 
						|
             EfiIsaIoWidthUint8,
 | 
						|
             BaseAddress + Offset,
 | 
						|
             1,
 | 
						|
             &Data
 | 
						|
             );
 | 
						|
}
 | 
						|
 |