mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 17:09:09 +00:00 
			
		
		
		
	 f9b8ab5632
			
		
	
	
		f9b8ab5632
		
	
	
	
	
		
			
			git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10437 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1697 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1697 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
 | |
| 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.
 | |
| 
 | |
| Module Name:
 | |
| 
 | |
|   UnixSerialIo.c
 | |
| 
 | |
| Abstract:
 | |
| 
 | |
|   Our DriverBinding member functions operate on the handles
 | |
|   created by the NT Bus driver.
 | |
| 
 | |
|   Handle(1) - UnixIo - DevicePath(1)
 | |
| 
 | |
|   If a serial port is added to the system this driver creates a new handle.
 | |
|   The new handle is required, since the serial device must add an UART device
 | |
|   pathnode.
 | |
| 
 | |
|   Handle(2) - SerialIo - DevicePath(1)\UART
 | |
| 
 | |
|   The driver then adds a gEfiUnixSerialPortGuid as a protocol to Handle(1).
 | |
|   The instance data for this protocol is the private data used to create
 | |
|   Handle(2).
 | |
| 
 | |
|   Handle(1) - UnixIo - DevicePath(1) - UnixSerialPort
 | |
| 
 | |
|   If the driver is unloaded Handle(2) is removed from the system and
 | |
|   gEfiUnixSerialPortGuid is removed from Handle(1).
 | |
| 
 | |
|   Note: Handle(1) is any handle created by the Win NT Bus driver that is passed
 | |
|   into the DriverBinding member functions of this driver. This driver requires
 | |
|   a Handle(1) to contain a UnixIo protocol, a DevicePath protocol, and
 | |
|   the TypeGuid in the UnixIo must be gEfiUnixSerialPortGuid.
 | |
| 
 | |
|   If Handle(1) contains a gEfiUnixSerialPortGuid protocol then the driver is
 | |
|   loaded on the device.
 | |
| 
 | |
| --*/
 | |
| 
 | |
| #include "UnixSerialIo.h"
 | |
| 
 | |
| EFI_DRIVER_BINDING_PROTOCOL gUnixSerialIoDriverBinding = {
 | |
|   UnixSerialIoDriverBindingSupported,
 | |
|   UnixSerialIoDriverBindingStart,
 | |
|   UnixSerialIoDriverBindingStop,
 | |
|   0xa,
 | |
|   NULL,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Check the device path node whether it's the Flow Control node or not.
 | |
| 
 | |
|   @param[in] FlowControl    The device path node to be checked.
 | |
|   
 | |
|   @retval TRUE              It's the Flow Control node.
 | |
|   @retval FALSE             It's not.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| IsUartFlowControlNode (
 | |
|   IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl
 | |
|   )
 | |
| {
 | |
|   return (BOOLEAN) (
 | |
|            (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) &&
 | |
|            (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) &&
 | |
|            (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid))
 | |
|            );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check the device path node whether it contains Flow Control node or not.
 | |
| 
 | |
|   @param[in] DevicePath     The device path to be checked.
 | |
|   
 | |
|   @retval TRUE              It contains the Flow Control node.
 | |
|   @retval FALSE             It doesn't.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| ContainsFlowControl (
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL      *DevicePath
 | |
|   )
 | |
| {
 | |
|   while (!IsDevicePathEnd (DevicePath)) {
 | |
|     if (IsUartFlowControlNode ((UART_FLOW_CONTROL_DEVICE_PATH *) DevicePath)) {
 | |
|       return TRUE;
 | |
|     }
 | |
|     DevicePath = NextDevicePathNode (DevicePath);
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| UINTN
 | |
| ConvertBaud2Unix (
 | |
|   UINT64 BaudRate
 | |
|   )
 | |
| {
 | |
|   switch (BaudRate) {
 | |
|   case 0:
 | |
|     return B0;
 | |
|   case 50:
 | |
|     return B50;
 | |
|   case 75:
 | |
|     return B75;
 | |
|   case 110:
 | |
|     return B110;
 | |
|   case 134:
 | |
|     return B134;
 | |
|   case 150:
 | |
|     return B150;
 | |
|   case 200:
 | |
|     return B200;
 | |
|   case 300:
 | |
|     return B300;
 | |
|   case 600:
 | |
|     return B600;
 | |
|   case 1200:
 | |
|     return B1200;
 | |
|   case 1800:
 | |
|     return B1800;
 | |
|   case 2400:
 | |
|     return B2400;
 | |
|   case 4800:
 | |
|     return B4800;
 | |
|   case 9600:
 | |
|     return B9600;
 | |
|   case 19200:
 | |
|     return B19200;
 | |
|   case 38400:
 | |
|     return B38400;
 | |
|   case 57600:
 | |
|     return B57600;
 | |
|   case 115200:
 | |
|     return B115200;
 | |
|   case 230400:
 | |
|     return B230400;
 | |
|   case 460800:
 | |
|     return B460800;
 | |
|   case 500000:
 | |
|     return B500000;
 | |
|   case 576000:
 | |
|     return B576000;
 | |
|   case 921600:
 | |
|     return B921600;
 | |
|   case 1000000:
 | |
|     return B1000000;
 | |
|   case 1152000:
 | |
|     return B1152000;
 | |
|   case 1500000:
 | |
|     return B1500000;
 | |
|   case 2000000:
 | |
|     return B2000000;
 | |
|   case 2500000:
 | |
|     return B2500000;
 | |
|   case 3000000:
 | |
|     return B3000000;
 | |
|   case 3500000:
 | |
|     return B3500000;
 | |
|   case 4000000:
 | |
|     return B4000000;
 | |
|   case __MAX_BAUD:
 | |
|   default:
 | |
|     DEBUG ((EFI_D_ERROR, "Invalid Baud Rate Parameter!\r\n"));
 | |
|   }
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| UINTN
 | |
| ConvertByteSize2Unix (
 | |
|   UINT8 DataBit
 | |
|   )
 | |
| {
 | |
|   switch (DataBit) {
 | |
|   case 5:
 | |
|     return CS5;
 | |
|   case 6:
 | |
|     return CS6;
 | |
|   case 7:
 | |
|     return CS7;
 | |
|   case 8:
 | |
|     return CS8;
 | |
|   default:
 | |
|     DEBUG ((EFI_D_ERROR, "Invalid Data Size Parameter!\r\n"));
 | |
|   }
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| VOID
 | |
| ConvertParity2Unix (
 | |
|   struct termios    *Options,
 | |
|   EFI_PARITY_TYPE   Parity
 | |
|   )
 | |
| {
 | |
|   switch (Parity) {
 | |
|   case NoParity:
 | |
|     Options->c_cflag &= ~PARENB;
 | |
|     break;
 | |
|   case EvenParity:
 | |
|     Options->c_cflag |= PARENB;
 | |
|     break;
 | |
|   case OddParity:
 | |
|     Options->c_cflag |= PARENB;
 | |
|     Options->c_cflag |= PARODD;
 | |
|     break;
 | |
|   case MarkParity:
 | |
|     Options->c_cflag = PARENB | CMSPAR | PARODD;
 | |
|     break;
 | |
|   case SpaceParity:
 | |
|     Options->c_cflag |= PARENB | CMSPAR;
 | |
|     Options->c_cflag &= ~PARODD;
 | |
|     break;
 | |
|   default:
 | |
|     DEBUG ((EFI_D_ERROR, "Invalid Parity Parameter!\r\n"));
 | |
|   }
 | |
| }
 | |
| 
 | |
| VOID
 | |
| ConvertStopBit2Unix (
 | |
|   struct termios      *Options,
 | |
|   EFI_STOP_BITS_TYPE  StopBits
 | |
|   )
 | |
| {
 | |
|   switch (StopBits) {
 | |
|   case TwoStopBits:
 | |
|     Options->c_cflag |= CSTOPB;
 | |
|     break;
 | |
|   case OneStopBit:
 | |
|   case OneFiveStopBits:
 | |
|   case DefaultStopBits:
 | |
|     Options->c_cflag &= ~CSTOPB;
 | |
|   }
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UnixSerialIoDriverBindingSupported (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
 | |
|   IN  EFI_HANDLE                    Handle,
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   The implementation of EFI_DRIVER_BINDING_PROTOCOL.EFI_DRIVER_BINDING_SUPPORTED.
 | |
| 
 | |
| Arguments:
 | |
|   
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                          Status;
 | |
|   EFI_DEVICE_PATH_PROTOCOL            *ParentDevicePath;
 | |
|   EFI_UNIX_IO_PROTOCOL                *UnixIo;
 | |
|   UART_DEVICE_PATH                    *UartNode;
 | |
|   EFI_DEVICE_PATH_PROTOCOL            *DevicePath;
 | |
|   UART_FLOW_CONTROL_DEVICE_PATH       *FlowControlNode;
 | |
|   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
 | |
|   UINTN                               EntryCount;
 | |
|   UINTN                               Index;
 | |
| 
 | |
|   //
 | |
|   // Check RemainingDevicePath validation
 | |
|   //
 | |
|   if (RemainingDevicePath != NULL) {
 | |
|     //
 | |
|     // Check if RemainingDevicePath is the End of Device Path Node, 
 | |
|     // if yes, go on checking other conditions
 | |
|     //
 | |
|     if (!IsDevicePathEnd (RemainingDevicePath)) {
 | |
|       //
 | |
|       // If RemainingDevicePath isn't the End of Device Path Node,
 | |
|       // check its validation
 | |
|       //
 | |
|       Status = EFI_UNSUPPORTED;
 | |
|       UartNode  = (UART_DEVICE_PATH *) RemainingDevicePath;
 | |
|       if (UartNode->Header.Type != MESSAGING_DEVICE_PATH ||
 | |
|           UartNode->Header.SubType != MSG_UART_DP ||
 | |
|           DevicePathNodeLength((EFI_DEVICE_PATH_PROTOCOL *)UartNode) != sizeof(UART_DEVICE_PATH)) {
 | |
|         goto Error;
 | |
|       }
 | |
|       if (UartNode->BaudRate < 0 || 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;
 | |
|       }
 | |
| 
 | |
|       FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (UartNode);
 | |
|       if (IsUartFlowControlNode (FlowControlNode)) {
 | |
|         //
 | |
|         // If the second node is Flow Control Node,
 | |
|         //   return error when it request other than hardware flow control.
 | |
|         //
 | |
|         if ((FlowControlNode->FlowControlMap & ~UART_FLOW_CONTROL_HARDWARE) != 0) {
 | |
|           goto Error;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Open the IO Abstraction(s) needed to perform the supported test
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Handle,
 | |
|                   &gEfiUnixIoProtocolGuid,
 | |
|                   (VOID**)&UnixIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Handle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (Status == EFI_ALREADY_STARTED) {
 | |
|     if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {
 | |
|       //
 | |
|       // If RemainingDevicePath is NULL or is the End of Device Path Node
 | |
|       //
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|     //
 | |
|     // When the driver has produced device path with flow control node but RemainingDevicePath only contains UART node,
 | |
|     //   return unsupported, and vice versa.
 | |
|     //
 | |
|     Status = gBS->OpenProtocolInformation (
 | |
|                     Handle,
 | |
|                     &gEfiUnixIoProtocolGuid,
 | |
|                     &OpenInfoBuffer,
 | |
|                     &EntryCount
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     for (Index = 0; Index < EntryCount; Index++) {
 | |
|       if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
 | |
|         Status = gBS->OpenProtocol (
 | |
|                         OpenInfoBuffer[Index].ControllerHandle,
 | |
|                         &gEfiDevicePathProtocolGuid,
 | |
|                         (VOID **) &DevicePath,
 | |
|                         This->DriverBindingHandle,
 | |
|                         Handle,
 | |
|                         EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                         );
 | |
|         if (!EFI_ERROR (Status) &&
 | |
|             (ContainsFlowControl (RemainingDevicePath) ^ ContainsFlowControl (DevicePath))) {
 | |
|           Status = EFI_UNSUPPORTED;
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|     FreePool (OpenInfoBuffer);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Close the I/O Abstraction(s) used to perform the supported test
 | |
|   //
 | |
|   gBS->CloseProtocol (
 | |
|         Handle,
 | |
|         &gEfiUnixIoProtocolGuid,
 | |
|         This->DriverBindingHandle,
 | |
|         Handle
 | |
|         );
 | |
| 
 | |
|   //
 | |
|   // Open the EFI Device Path protocol needed to perform the supported test
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Handle,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   (VOID**)&ParentDevicePath,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Handle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (Status == EFI_ALREADY_STARTED) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Close protocol, don't use device path protocol in the Support() function
 | |
|   //
 | |
|   gBS->CloseProtocol (
 | |
|         Handle,
 | |
|         &gEfiDevicePathProtocolGuid,
 | |
|         This->DriverBindingHandle,
 | |
|         Handle
 | |
|         );
 | |
| 
 | |
|   //
 | |
|   // Make sure that the Unix Thunk Protocol is valid
 | |
|   //
 | |
|   if (UnixIo->UnixThunk->Signature != EFI_UNIX_THUNK_PROTOCOL_SIGNATURE) {
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|     goto Error;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check the GUID to see if this is a handle type the driver supports
 | |
|   //
 | |
|   if (!CompareGuid (UnixIo->TypeGuid, &gEfiUnixSerialPortGuid)) {
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|     goto Error;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| Error:
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UnixSerialIoDriverBindingStart (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
 | |
|   IN  EFI_HANDLE                    Handle,
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                          Status;
 | |
|   EFI_UNIX_IO_PROTOCOL                *UnixIo;
 | |
|   UNIX_SERIAL_IO_PRIVATE_DATA         *Private;
 | |
|   UINTN                               UnixHandle;
 | |
|   UART_DEVICE_PATH                    UartNode;
 | |
|   EFI_DEVICE_PATH_PROTOCOL            *ParentDevicePath;
 | |
|   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
 | |
|   UINTN                               EntryCount;
 | |
|   UINTN                               Index;
 | |
|   EFI_SERIAL_IO_PROTOCOL              *SerialIo;
 | |
|   CHAR8                               AsciiDevName[1024];
 | |
|   UART_DEVICE_PATH                    *Uart;
 | |
|   UINT32                              FlowControlMap;
 | |
|   UART_FLOW_CONTROL_DEVICE_PATH       *FlowControl;
 | |
|   EFI_DEVICE_PATH_PROTOCOL            *TempDevicePath;
 | |
|   UINT32                              Control;
 | |
| 
 | |
|   DEBUG ((EFI_D_INFO, "SerialIo drive binding start!\r\n"));
 | |
|   Private   = NULL;
 | |
|   UnixHandle  = -1;
 | |
| 
 | |
|   //
 | |
|   // Get the Parent Device Path
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Handle,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   (VOID**)&ParentDevicePath,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Handle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Grab the IO abstraction we need to get any work done
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Handle,
 | |
|                   &gEfiUnixIoProtocolGuid,
 | |
|                   (VOID**)&UnixIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Handle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
 | |
|     gBS->CloseProtocol (
 | |
|           Handle,
 | |
|           &gEfiDevicePathProtocolGuid,
 | |
|           This->DriverBindingHandle,
 | |
|           Handle
 | |
|           );
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (Status == EFI_ALREADY_STARTED) {
 | |
| 
 | |
|     if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {
 | |
|       //
 | |
|       // If RemainingDevicePath is NULL or is the End of Device Path Node
 | |
|       //
 | |
|       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 (
 | |
|                     Handle,
 | |
|                     &gEfiUnixIoProtocolGuid,
 | |
|                     &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) != 0) {
 | |
|         Status = gBS->OpenProtocol (
 | |
|                         OpenInfoBuffer[Index].ControllerHandle,
 | |
|                         &gEfiSerialIoProtocolGuid,
 | |
|                         (VOID**)&SerialIo,
 | |
|                         This->DriverBindingHandle,
 | |
|                         Handle,
 | |
|                         EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                         );
 | |
|         if (!EFI_ERROR (Status)) {
 | |
|           Uart   = (UART_DEVICE_PATH *) RemainingDevicePath;
 | |
|           Status = SerialIo->SetAttributes (
 | |
|                                SerialIo,
 | |
|                                Uart->BaudRate,
 | |
|                                SerialIo->Mode->ReceiveFifoDepth,
 | |
|                                SerialIo->Mode->Timeout,
 | |
|                                (EFI_PARITY_TYPE) Uart->Parity,
 | |
|                                Uart->DataBits,
 | |
|                                (EFI_STOP_BITS_TYPE) Uart->StopBits
 | |
|                                );
 | |
| 
 | |
|           FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
 | |
|           if (!EFI_ERROR (Status) && IsUartFlowControlNode (FlowControl)) {
 | |
|             Status = SerialIo->GetControl (SerialIo, &Control);
 | |
|             if (!EFI_ERROR (Status)) {
 | |
|               if (FlowControl->FlowControlMap == UART_FLOW_CONTROL_HARDWARE) {
 | |
|                 Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
 | |
|               } else {
 | |
|                 Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
 | |
|               }
 | |
|               //
 | |
|               // Clear the bits that are not allowed to pass to SetControl
 | |
|               //
 | |
|               Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
 | |
|                           EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE | 
 | |
|                           EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE);
 | |
|               Status = SerialIo->SetControl (SerialIo, Control);
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     FreePool (OpenInfoBuffer);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   FlowControl    = NULL;
 | |
|   FlowControlMap = 0;
 | |
|   if (RemainingDevicePath == NULL) {
 | |
|     //
 | |
|     // Build the device path by appending the UART node to the ParentDevicePath
 | |
|     // from the UnixIo handle. The Uart setings are zero here, since
 | |
|     // SetAttribute() will update them to match the default setings.
 | |
|     //
 | |
|     ZeroMem (&UartNode, sizeof (UART_DEVICE_PATH));
 | |
|     UartNode.Header.Type     = MESSAGING_DEVICE_PATH;
 | |
|     UartNode.Header.SubType  = MSG_UART_DP;
 | |
|     SetDevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) &UartNode, sizeof (UART_DEVICE_PATH));
 | |
| 
 | |
|   } else if (!IsDevicePathEnd (RemainingDevicePath)) {
 | |
|     //
 | |
|     // If RemainingDevicePath isn't the End of Device Path Node, 
 | |
|     // only scan the specified device by RemainingDevicePath
 | |
|     //
 | |
|     //
 | |
|     // Match the configuration of the RemainingDevicePath. IsHandleSupported()
 | |
|     // already checked to make sure the RemainingDevicePath contains settings
 | |
|     // that we can support.
 | |
|     //
 | |
|     CopyMem (&UartNode, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
 | |
|     FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (RemainingDevicePath);
 | |
|     if (IsUartFlowControlNode (FlowControl)) {
 | |
|       FlowControlMap = FlowControl->FlowControlMap;
 | |
|     } else {
 | |
|       FlowControl    = NULL;
 | |
|     }
 | |
| 
 | |
|   } else {
 | |
|     //
 | |
|     // If RemainingDevicePath is the End of Device Path Node,
 | |
|     // skip enumerate any device and return EFI_SUCESSS
 | |
|     // 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check to see if we can access the hardware device. If it's Open in Unix we
 | |
|   // will not get access.
 | |
|   //
 | |
|   UnicodeStrToAsciiStr(UnixIo->EnvString, AsciiDevName);
 | |
|   UnixHandle = UnixIo->UnixThunk->Open (AsciiDevName, O_RDWR | O_NOCTTY, 0);
 | |
|   
 | |
|   if (UnixHandle == -1) {
 | |
|     DEBUG ((EFI_D_INFO, "Failed to open serial device, %s!\r\n", UnixIo->EnvString ));
 | |
|     UnixIo->UnixThunk->Perror (AsciiDevName);
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto Error;
 | |
|   }
 | |
|   DEBUG ((EFI_D_INFO, "Success to open serial device %s, Hanle = 0x%x \r\n", UnixIo->EnvString, UnixHandle));
 | |
| 
 | |
|   //
 | |
|   // Construct Private data
 | |
|   //
 | |
|   Private = AllocatePool (sizeof (UNIX_SERIAL_IO_PRIVATE_DATA));
 | |
|   if (Private == NULL) {
 | |
|     goto Error;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // This signature must be valid before any member function is called
 | |
|   //
 | |
|   Private->Signature              = UNIX_SERIAL_IO_PRIVATE_DATA_SIGNATURE;
 | |
|   Private->UnixHandle             = UnixHandle;
 | |
|   Private->ControllerHandle       = Handle;
 | |
|   Private->Handle                 = NULL;
 | |
|   Private->UnixThunk              = UnixIo->UnixThunk;
 | |
|   Private->ParentDevicePath       = ParentDevicePath;
 | |
|   Private->ControllerNameTable    = NULL;
 | |
| 
 | |
|   Private->SoftwareLoopbackEnable = FALSE;
 | |
|   Private->HardwareLoopbackEnable = FALSE;
 | |
|   Private->HardwareFlowControl    = (BOOLEAN) (FlowControlMap == UART_FLOW_CONTROL_HARDWARE);
 | |
|   Private->Fifo.First             = 0;
 | |
|   Private->Fifo.Last              = 0;
 | |
|   Private->Fifo.Surplus           = SERIAL_MAX_BUFFER_SIZE;
 | |
| 
 | |
|   CopyMem (&Private->UartDevicePath, &UartNode, sizeof (UART_DEVICE_PATH));
 | |
| 
 | |
|   AddUnicodeString (
 | |
|     "eng",
 | |
|     gUnixSerialIoComponentName.SupportedLanguages,
 | |
|     &Private->ControllerNameTable,
 | |
|     UnixIo->EnvString
 | |
|     );
 | |
| 
 | |
|   Private->SerialIo.Revision      = SERIAL_IO_INTERFACE_REVISION;
 | |
|   Private->SerialIo.Reset         = UnixSerialIoReset;
 | |
|   Private->SerialIo.SetAttributes = UnixSerialIoSetAttributes;
 | |
|   Private->SerialIo.SetControl    = UnixSerialIoSetControl;
 | |
|   Private->SerialIo.GetControl    = UnixSerialIoGetControl;
 | |
|   Private->SerialIo.Write         = UnixSerialIoWrite;
 | |
|   Private->SerialIo.Read          = UnixSerialIoRead;
 | |
|   Private->SerialIo.Mode          = &Private->SerialIoMode;
 | |
| 
 | |
| 
 | |
| 
 | |
|   //
 | |
|   // Build the device path by appending the UART node to the ParentDevicePath
 | |
|   // from the UnixIo handle. The Uart setings are zero here, since
 | |
|   // SetAttribute() will update them to match the current setings.
 | |
|   //
 | |
|   Private->DevicePath = AppendDevicePathNode (
 | |
|                           ParentDevicePath,
 | |
|                           (EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath
 | |
|                           );
 | |
|   //
 | |
|   // Only produce the FlowControl node when remaining device path has it
 | |
|   //
 | |
|   if (FlowControl != NULL) {
 | |
|     TempDevicePath = Private->DevicePath;
 | |
|     if (TempDevicePath != NULL) {
 | |
|       Private->DevicePath = AppendDevicePathNode (
 | |
|                               TempDevicePath,
 | |
|                               (EFI_DEVICE_PATH_PROTOCOL *) FlowControl
 | |
|                               );
 | |
|       FreePool (TempDevicePath);
 | |
|     }
 | |
|   }
 | |
|   if (Private->DevicePath == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto Error;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
 | |
|   //
 | |
|   Private->SerialIoMode.ControlMask       = SERIAL_CONTROL_MASK;
 | |
|   Private->SerialIoMode.Timeout           = SERIAL_TIMEOUT_DEFAULT;
 | |
|   Private->SerialIoMode.BaudRate          = Private->UartDevicePath.BaudRate;
 | |
|   Private->SerialIoMode.ReceiveFifoDepth  = SERIAL_FIFO_DEFAULT;
 | |
|   Private->SerialIoMode.DataBits          = Private->UartDevicePath.DataBits;
 | |
|   Private->SerialIoMode.Parity            = Private->UartDevicePath.Parity;
 | |
|   Private->SerialIoMode.StopBits          = Private->UartDevicePath.StopBits;
 | |
| 
 | |
|   //
 | |
|   // Issue a reset to initialize the COM port
 | |
|   //
 | |
|   Status = Private->SerialIo.Reset (&Private->SerialIo);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto Error;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create new child handle
 | |
|   //
 | |
|   Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                   &Private->Handle,
 | |
|                   &gEfiSerialIoProtocolGuid,
 | |
|                   &Private->SerialIo,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   Private->DevicePath,
 | |
|                   NULL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto Error;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Open For Child Device
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Handle,
 | |
|                   &gEfiUnixIoProtocolGuid,
 | |
|                   (VOID**)&UnixIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Private->Handle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto Error;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| Error:
 | |
|   //
 | |
|   // Use the Stop() function to free all resources allocated in Start()
 | |
|   //
 | |
|   if (Private != NULL) {
 | |
|     if (Private->Handle != NULL) {
 | |
|       This->Stop (This, Handle, 1, &Private->Handle);
 | |
|     } else {
 | |
|       if (UnixHandle != -1) {
 | |
|         Private->UnixThunk->Close (UnixHandle);
 | |
|       }
 | |
| 
 | |
|       if (Private->DevicePath != NULL) {
 | |
|         FreePool (Private->DevicePath);
 | |
|       }
 | |
| 
 | |
|       FreeUnicodeStringTable (Private->ControllerNameTable);
 | |
| 
 | |
|       FreePool (Private);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   This->Stop (This, Handle, 0, NULL);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UnixSerialIoDriverBindingStop (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
 | |
|   IN  EFI_HANDLE                    Handle,
 | |
|   IN  UINTN                         NumberOfChildren,
 | |
|   IN  EFI_HANDLE                    *ChildHandleBuffer
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   TODO: Add function description
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   This              - TODO: add argument description
 | |
|   Handle            - TODO: add argument description
 | |
|   NumberOfChildren  - TODO: add argument description
 | |
|   ChildHandleBuffer - TODO: add argument description
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_DEVICE_ERROR - TODO: Add description for return value
 | |
|   EFI_SUCCESS - TODO: Add description for return value
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   UINTN                         Index;
 | |
|   BOOLEAN                       AllChildrenStopped;
 | |
|   EFI_SERIAL_IO_PROTOCOL        *SerialIo;
 | |
|   UNIX_SERIAL_IO_PRIVATE_DATA   *Private;
 | |
|   EFI_UNIX_IO_PROTOCOL          *UnixIo;
 | |
| 
 | |
|   //
 | |
|   // 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 (
 | |
|                     Handle,
 | |
|                     &gEfiUnixIoProtocolGuid,
 | |
|                     This->DriverBindingHandle,
 | |
|                     Handle
 | |
|                     );
 | |
|     Status = gBS->CloseProtocol (
 | |
|                     Handle,
 | |
|                     &gEfiDevicePathProtocolGuid,
 | |
|                     This->DriverBindingHandle,
 | |
|                     Handle
 | |
|                     );
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   AllChildrenStopped = TRUE;
 | |
| 
 | |
|   for (Index = 0; Index < NumberOfChildren; Index++) {
 | |
|     Status = gBS->OpenProtocol (
 | |
|                     ChildHandleBuffer[Index],
 | |
|                     &gEfiSerialIoProtocolGuid,
 | |
|                     (VOID**)&SerialIo,
 | |
|                     This->DriverBindingHandle,
 | |
|                     Handle,
 | |
|                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                     );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (SerialIo);
 | |
| 
 | |
|       ASSERT (Private->Handle == ChildHandleBuffer[Index]);
 | |
| 
 | |
|       Status = gBS->CloseProtocol (
 | |
|                       Handle,
 | |
|                       &gEfiUnixIoProtocolGuid,
 | |
|                       This->DriverBindingHandle,
 | |
|                       ChildHandleBuffer[Index]
 | |
|                       );
 | |
| 
 | |
|       Status = gBS->UninstallMultipleProtocolInterfaces (
 | |
|                       ChildHandleBuffer[Index],
 | |
|                       &gEfiSerialIoProtocolGuid,
 | |
|                       &Private->SerialIo,
 | |
|                       &gEfiDevicePathProtocolGuid,
 | |
|                       Private->DevicePath,
 | |
|                       NULL
 | |
|                       );
 | |
| 
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         gBS->OpenProtocol (
 | |
|               Handle,
 | |
|               &gEfiUnixIoProtocolGuid,
 | |
|               (VOID **) &UnixIo,
 | |
|               This->DriverBindingHandle,
 | |
|               ChildHandleBuffer[Index],
 | |
|               EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | |
|               );
 | |
|       } else {
 | |
|         Private->UnixThunk->Close (Private->UnixHandle);
 | |
| 
 | |
|         FreePool (Private->DevicePath);
 | |
| 
 | |
|         FreeUnicodeStringTable (Private->ControllerNameTable);
 | |
| 
 | |
|         FreePool (Private);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       AllChildrenStopped = FALSE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!AllChildrenStopped) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| //
 | |
| // Serial IO Protocol member functions
 | |
| //
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UnixSerialIoReset (
 | |
|   IN EFI_SERIAL_IO_PROTOCOL *This
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   TODO: Add function description
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   This  - TODO: add argument description
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   TODO: add return values
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UNIX_SERIAL_IO_PRIVATE_DATA *Private;
 | |
|   EFI_TPL                      Tpl;
 | |
|   UINTN                        UnixStatus;
 | |
| 
 | |
|   Tpl         = gBS->RaiseTPL (TPL_NOTIFY);
 | |
| 
 | |
|   Private     = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   UnixStatus  = Private->UnixThunk->Tcflush (
 | |
|                                     Private->UnixHandle, 
 | |
|                                     TCIOFLUSH
 | |
|                                     );
 | |
|   switch (UnixStatus) {
 | |
|   case EBADF:
 | |
|     DEBUG ((EFI_D_ERROR, "Invalid handle of serial device!\r\n"));
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   case EINVAL:
 | |
|     DEBUG ((EFI_D_ERROR, "Invalid queue selector!\r\n"));
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   case ENOTTY:
 | |
|     DEBUG ((EFI_D_ERROR, "The file associated with serial's handle is not a terminal!\r\n"));
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   default:
 | |
|     DEBUG ((EFI_D_ERROR, "The serial IO device is reset successfully!\r\n"));
 | |
|   }
 | |
| 
 | |
|   gBS->RestoreTPL (Tpl);
 | |
| 
 | |
|   return This->SetAttributes (
 | |
|                 This,
 | |
|                 This->Mode->BaudRate,
 | |
|                 This->Mode->ReceiveFifoDepth,
 | |
|                 This->Mode->Timeout,
 | |
|                 This->Mode->Parity,
 | |
|                 (UINT8) This->Mode->DataBits,
 | |
|                 This->Mode->StopBits
 | |
|                 );
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UnixSerialIoSetAttributes (
 | |
|   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:
 | |
| 
 | |
|   This function is used to set the attributes.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   This              - A pointer to the EFI_SERIAL_IO_PROTOCOL structrue.
 | |
|   BaudRate          - The Baud rate of the serial device.
 | |
|   ReceiveFifoDepth  - The request depth of fifo on receive side.
 | |
|   Timeout           - the request timeout for a single charact.
 | |
|   Parity            - The type of parity used in serial device.
 | |
|   DataBits          - Number of deata bits used in serial device.
 | |
|   StopBits          - Number of stop bits used in serial device.
 | |
| 
 | |
| Returns:
 | |
|   Status code
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   UNIX_SERIAL_IO_PRIVATE_DATA   *Private;
 | |
|   UART_DEVICE_PATH              *Uart;
 | |
|   EFI_TPL                       Tpl;
 | |
| 
 | |
|   Tpl     = gBS->RaiseTPL (TPL_NOTIFY);
 | |
|   Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   //  Some of our arguments have defaults if a null value is passed in, and
 | |
|   //   we must set the default values if a null argument is passed in.
 | |
|   //
 | |
|   if (BaudRate == 0) {
 | |
|     BaudRate = SERIAL_BAUD_DEFAULT;
 | |
|   }
 | |
| 
 | |
|   if (ReceiveFifoDepth == 0) {
 | |
|     ReceiveFifoDepth = SERIAL_FIFO_DEFAULT;
 | |
|   }
 | |
| 
 | |
|   if (Timeout == 0) {
 | |
|     Timeout = SERIAL_TIMEOUT_DEFAULT;
 | |
|   }
 | |
| 
 | |
|   if (Parity == DefaultParity) {
 | |
|     Parity = NoParity;
 | |
|   }
 | |
| 
 | |
|   if (DataBits == 0) {
 | |
|     DataBits = SERIAL_DATABITS_DEFAULT;
 | |
|   }
 | |
| 
 | |
|   if (StopBits == DefaultStopBits) {
 | |
|     StopBits = OneStopBit;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // See if the new attributes already match the current attributes
 | |
|   //
 | |
|   if (Private->UartDevicePath.BaudRate       == BaudRate         &&
 | |
|       Private->UartDevicePath.DataBits       == DataBits         &&
 | |
|       Private->UartDevicePath.Parity         == Parity           &&
 | |
|       Private->UartDevicePath.StopBits       == StopBits         &&
 | |
|       Private->SerialIoMode.ReceiveFifoDepth == ReceiveFifoDepth &&
 | |
|       Private->SerialIoMode.Timeout          == Timeout             ) {
 | |
|     gBS->RestoreTPL(Tpl);
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Try to get options from serial device.
 | |
|   // 
 | |
|   if (Private->UnixThunk->Tcgetattr (Private->UnixHandle, &Private->UnixTermios) == -1) {
 | |
|     Private->UnixThunk->Perror ("IoSetAttributes");
 | |
|     gBS->RestoreTPL (Tpl);
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Setting Baud Rate
 | |
|   // 
 | |
|   Private->UnixThunk->Cfsetispeed (&Private->UnixTermios, ConvertBaud2Unix(BaudRate));
 | |
|   Private->UnixThunk->Cfsetospeed (&Private->UnixTermios, ConvertBaud2Unix(BaudRate));
 | |
|   //
 | |
|   // Setting DataBits 
 | |
|   // 
 | |
|   Private->UnixTermios.c_cflag &= ~CSIZE;
 | |
|   Private->UnixTermios.c_cflag |= ConvertByteSize2Unix (DataBits);
 | |
|   //
 | |
|   // Setting Parity
 | |
|   // 
 | |
|   ConvertParity2Unix (&Private->UnixTermios, Parity);
 | |
|   //
 | |
|   // Setting StopBits
 | |
|   // 
 | |
|   ConvertStopBit2Unix (&Private->UnixTermios, StopBits);
 | |
|   //
 | |
|   // Raw input
 | |
|   // 
 | |
|   Private->UnixTermios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
 | |
|   //
 | |
|   // Raw output
 | |
|   // 
 | |
|   Private->UnixTermios.c_oflag &= ~OPOST;
 | |
|   //
 | |
|   // Support hardware flow control 
 | |
|   // 
 | |
|   Private->UnixTermios.c_cflag &= ~CRTSCTS;;
 | |
|   //
 | |
|   // Time out
 | |
|   // 
 | |
|   Private->UnixTermios.c_cc[VMIN]  = 0;
 | |
|   Private->UnixTermios.c_cc[VTIME] = (Timeout/1000000) * 10;
 | |
| 
 | |
|   //
 | |
|   // Set the options
 | |
|   // 
 | |
|   if (-1 == Private->UnixThunk->Tcsetattr (
 | |
|                         Private->UnixHandle, 
 | |
|                         TCSANOW, 
 | |
|                         &Private->UnixTermios
 | |
|                         )) {
 | |
|     DEBUG ((EFI_D_INFO, "Fail to set options for serial device!\r\n"));
 | |
|     gBS->RestoreTPL (Tpl);
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   //  Update mode
 | |
|   //
 | |
|   Private->SerialIoMode.BaudRate          = BaudRate;
 | |
|   Private->SerialIoMode.ReceiveFifoDepth  = ReceiveFifoDepth;
 | |
|   Private->SerialIoMode.Timeout           = Timeout;
 | |
|   Private->SerialIoMode.Parity            = Parity;
 | |
|   Private->SerialIoMode.DataBits          = DataBits;
 | |
|   Private->SerialIoMode.StopBits          = StopBits;
 | |
| 
 | |
|   //
 | |
|   // See if Device Path Node has actually changed
 | |
|   //
 | |
|   if (Private->UartDevicePath.BaudRate     == BaudRate &&
 | |
|       Private->UartDevicePath.DataBits     == DataBits &&
 | |
|       Private->UartDevicePath.Parity       == Parity   &&
 | |
|       Private->UartDevicePath.StopBits     == StopBits    ) {
 | |
|     gBS->RestoreTPL(Tpl);
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Update the device path
 | |
|   //
 | |
|   Private->UartDevicePath.BaudRate  = BaudRate;
 | |
|   Private->UartDevicePath.DataBits  = DataBits;
 | |
|   Private->UartDevicePath.Parity    = (UINT8) Parity;
 | |
|   Private->UartDevicePath.StopBits  = (UINT8) StopBits;
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
|   if (Private->Handle != NULL) {
 | |
|     Uart = (UART_DEVICE_PATH *) (
 | |
|              (UINTN) Private->DevicePath
 | |
|              + GetDevicePathSize (Private->ParentDevicePath)
 | |
|              - END_DEVICE_PATH_LENGTH
 | |
|              );
 | |
|     CopyMem (Uart, &Private->UartDevicePath, sizeof (UART_DEVICE_PATH));
 | |
|     Status = gBS->ReinstallProtocolInterface (
 | |
|                     Private->Handle,
 | |
|                     &gEfiDevicePathProtocolGuid,
 | |
|                     Private->DevicePath,
 | |
|                     Private->DevicePath
 | |
|                     );
 | |
|   }
 | |
| 
 | |
|   gBS->RestoreTPL (Tpl);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UnixSerialIoSetControl (
 | |
|   IN EFI_SERIAL_IO_PROTOCOL *This,
 | |
|   IN UINT32                 Control
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   TODO: Add function description
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   This    - TODO: add argument description
 | |
|   Control - TODO: add argument description
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_DEVICE_ERROR - TODO: Add description for return value
 | |
|   EFI_DEVICE_ERROR - TODO: Add description for return value
 | |
|   EFI_SUCCESS - TODO: Add description for return value
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UNIX_SERIAL_IO_PRIVATE_DATA   *Private;
 | |
|   UINTN                         Result;
 | |
|   UINTN                         IoStatus;
 | |
|   struct termios                Options;
 | |
|   EFI_TPL                       Tpl;
 | |
|   UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
 | |
|   EFI_STATUS                    Status;
 | |
| 
 | |
|   //
 | |
|   // first determine the parameter is invalid
 | |
|   //
 | |
|   if (Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
 | |
|                    EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE | 
 | |
|                    EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   Tpl     = gBS->RaiseTPL (TPL_NOTIFY);
 | |
| 
 | |
|   Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   Result  = Private->UnixThunk->IoCtl (Private->UnixHandle, TIOCMGET, &IoStatus);
 | |
| 
 | |
|   if (Result == -1) {
 | |
|     Private->UnixThunk->Perror ("SerialSetControl");
 | |
|     gBS->RestoreTPL (Tpl);
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   Private->HardwareFlowControl    = FALSE;
 | |
|   Private->SoftwareLoopbackEnable = FALSE;
 | |
|   Private->HardwareLoopbackEnable = FALSE;
 | |
| 
 | |
|   if (Control & EFI_SERIAL_REQUEST_TO_SEND) {
 | |
|     Options.c_cflag |= TIOCM_RTS;
 | |
|   }
 | |
| 
 | |
|   if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {
 | |
|     Options.c_cflag |= TIOCM_DTR;
 | |
|   }
 | |
| 
 | |
|   if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
 | |
|     Private->HardwareFlowControl = TRUE;
 | |
|   }
 | |
| 
 | |
|   if (Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
 | |
|     Private->SoftwareLoopbackEnable = TRUE;
 | |
|   }
 | |
| 
 | |
|   if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
 | |
|     Private->HardwareLoopbackEnable = TRUE;
 | |
|   }
 | |
| 
 | |
|   Result  = Private->UnixThunk->IoCtl (Private->UnixHandle, TIOCMSET, &IoStatus);
 | |
| 
 | |
|   if (Result == -1) {
 | |
|     Private->UnixThunk->Perror ("SerialSetControl");
 | |
|     gBS->RestoreTPL (Tpl);
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
|   if (Private->Handle != NULL) {
 | |
|     FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) (
 | |
|                     (UINTN) Private->DevicePath
 | |
|                     + GetDevicePathSize (Private->ParentDevicePath)
 | |
|                     - END_DEVICE_PATH_LENGTH
 | |
|                     + sizeof (UART_DEVICE_PATH)
 | |
|                     );
 | |
|     if (IsUartFlowControlNode (FlowControl) &&
 | |
|         ((FlowControl->FlowControlMap == UART_FLOW_CONTROL_HARDWARE) ^ Private->HardwareFlowControl)) {
 | |
|       //
 | |
|       // Flow Control setting is changed, need to reinstall device path protocol
 | |
|       //
 | |
|       FlowControl->FlowControlMap = Private->HardwareFlowControl ? UART_FLOW_CONTROL_HARDWARE : 0;
 | |
|       Status = gBS->ReinstallProtocolInterface (
 | |
|                       Private->Handle,
 | |
|                       &gEfiDevicePathProtocolGuid,
 | |
|                       Private->DevicePath,
 | |
|                       Private->DevicePath
 | |
|                       );
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   gBS->RestoreTPL (Tpl);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UnixSerialIoGetControl (
 | |
|   IN  EFI_SERIAL_IO_PROTOCOL  *This,
 | |
|   OUT UINT32                  *Control
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   TODO: Add function description
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   This    - TODO: add argument description
 | |
|   Control - TODO: add argument description
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_DEVICE_ERROR - TODO: Add description for return value
 | |
|   EFI_DEVICE_ERROR - TODO: Add description for return value
 | |
|   EFI_DEVICE_ERROR - TODO: Add description for return value
 | |
|   EFI_SUCCESS - TODO: Add description for return value
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UNIX_SERIAL_IO_PRIVATE_DATA *Private;
 | |
|   UINTN                       Result;
 | |
|   UINTN                       Status;
 | |
|   UINT32                      Bits;
 | |
|   EFI_TPL                     Tpl;
 | |
|   UINTN                       Bytes;
 | |
| 
 | |
|   Tpl     = gBS->RaiseTPL (TPL_NOTIFY);
 | |
| 
 | |
|   Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
 | |
|   Result  = Private->UnixThunk->IoCtl (Private->UnixHandle, TIOCMGET, &Status);
 | |
|   if (Result == -1) {
 | |
|     Private->UnixThunk->Perror ("SerialGetControl");
 | |
|     gBS->RestoreTPL (Tpl);
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   Bits = 0;
 | |
|   if ((Status & TIOCM_CTS) == TIOCM_CTS) {
 | |
|     Bits |= EFI_SERIAL_CLEAR_TO_SEND;
 | |
|   }
 | |
| 
 | |
|   if ((Status & TIOCM_DSR) == TIOCM_DSR) {
 | |
|     Bits |= EFI_SERIAL_DATA_SET_READY;
 | |
|   }
 | |
| 
 | |
|   if ((Status & TIOCM_DTR) == TIOCM_DTR) {
 | |
|     Bits |= EFI_SERIAL_DATA_TERMINAL_READY;
 | |
|   }
 | |
| 
 | |
|   if ((Status & TIOCM_RTS) == TIOCM_RTS) {
 | |
|     Bits |= EFI_SERIAL_REQUEST_TO_SEND;
 | |
|   }
 | |
| 
 | |
|   if ((Status & TIOCM_RNG) == TIOCM_RNG) {
 | |
|     Bits |= EFI_SERIAL_RING_INDICATE;
 | |
|   }
 | |
| 
 | |
|   if ((Status & TIOCM_CAR) == TIOCM_CAR) {
 | |
|     Bits |= EFI_SERIAL_CARRIER_DETECT;
 | |
|   }
 | |
| 
 | |
|   if (Private->HardwareFlowControl) {
 | |
|     Bits |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
 | |
|   }
 | |
| 
 | |
|   if (Private->SoftwareLoopbackEnable) {
 | |
|     Bits |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
 | |
|   }
 | |
| 
 | |
|   if (Private->HardwareLoopbackEnable) {
 | |
|     Bits |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
 | |
|   }
 | |
| 
 | |
|   Result = Private->UnixThunk->IoCtl (Private->UnixHandle, FIONREAD, &Bytes);
 | |
|   if (Result == -1) {
 | |
|     Private->UnixThunk->Perror ("SerialGetControl");
 | |
|     gBS->RestoreTPL (Tpl);
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   if (Bytes == 0) {
 | |
|     Bits |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
 | |
|   }
 | |
| 
 | |
|   *Control = Bits;
 | |
| 
 | |
|   gBS->RestoreTPL (Tpl);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UnixSerialIoWrite (
 | |
|   IN EFI_SERIAL_IO_PROTOCOL   *This,
 | |
|   IN OUT UINTN                *BufferSize,
 | |
|   IN VOID                     *Buffer
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   TODO: Add function description
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   This        - TODO: add argument description
 | |
|   BufferSize  - TODO: add argument description
 | |
|   Buffer      - TODO: add argument description
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_DEVICE_ERROR - TODO: Add description for return value
 | |
|   EFI_SUCCESS - TODO: Add description for return value
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UNIX_SERIAL_IO_PRIVATE_DATA   *Private;
 | |
|   EFI_STATUS                    Status;
 | |
|   UINT8                         *ByteBuffer;
 | |
|   UINT32                        TotalBytesWritten;
 | |
|   UINT32                        BytesToGo;
 | |
|   UINT32                        BytesWritten;
 | |
|   UINT32                        Index;
 | |
|   UINT32                        Control;
 | |
|   EFI_TPL                       Tpl;
 | |
| 
 | |
|   Tpl               = gBS->RaiseTPL (TPL_NOTIFY);
 | |
| 
 | |
|   Private           = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This); 
 | |
| 
 | |
|   ByteBuffer        = (UINT8 *) Buffer;
 | |
|   Status = EFI_SUCCESS;
 | |
|   TotalBytesWritten = 0;
 | |
| 
 | |
|   if (Private->SoftwareLoopbackEnable || Private->HardwareLoopbackEnable) {
 | |
|     for (Index = 0; Index < *BufferSize; Index++) {
 | |
|       if (IsaSerialFifoAdd (&Private->Fifo, ByteBuffer[Index]) == EFI_SUCCESS) {
 | |
|         TotalBytesWritten++;
 | |
|       } else {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     BytesToGo = (*BufferSize);
 | |
| 
 | |
|     do {
 | |
|       if (Private->HardwareFlowControl) {
 | |
|         //
 | |
|         // Send RTS
 | |
|         //
 | |
|         UnixSerialIoGetControl (&Private->SerialIo, &Control);
 | |
|         Control |= EFI_SERIAL_REQUEST_TO_SEND;
 | |
|         UnixSerialIoSetControl (&Private->SerialIo, Control);
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       //  Do the write
 | |
|       //
 | |
|       BytesWritten = Private->UnixThunk->Write ( 
 | |
|                                            Private->UnixHandle,
 | |
|                                            &ByteBuffer[TotalBytesWritten],
 | |
|                                            BytesToGo
 | |
|                                            );
 | |
|       if (BytesWritten == -1) {
 | |
|         Status = EFI_DEVICE_ERROR;
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       if (Private->HardwareFlowControl) {
 | |
|         //
 | |
|         // Assert RTS
 | |
|         //
 | |
|         UnixSerialIoGetControl (&Private->SerialIo, &Control);
 | |
|         Control &= ~ (UINT32) EFI_SERIAL_REQUEST_TO_SEND;
 | |
|         UnixSerialIoSetControl (&Private->SerialIo, Control);
 | |
|       }
 | |
| 
 | |
|       TotalBytesWritten += BytesWritten;
 | |
|       BytesToGo -= BytesWritten;
 | |
|     } while (BytesToGo > 0);
 | |
|   }
 | |
| 
 | |
|   *BufferSize = TotalBytesWritten;
 | |
| 
 | |
|   gBS->RestoreTPL (Tpl);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UnixSerialIoRead (
 | |
|   IN  EFI_SERIAL_IO_PROTOCOL  *This,
 | |
|   IN  OUT UINTN               *BufferSize,
 | |
|   OUT VOID                    *Buffer
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   TODO: Add function description
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   This        - TODO: add argument description
 | |
|   BufferSize  - TODO: add argument description
 | |
|   Buffer      - TODO: add argument description
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_DEVICE_ERROR - TODO: Add description for return value
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UNIX_SERIAL_IO_PRIVATE_DATA   *Private;
 | |
|   UINT32                        BytesRead;
 | |
|   EFI_STATUS                    Status;
 | |
|   UINT32                        Index;
 | |
|   UINT8                         Data;
 | |
|   UINT32                        Control;
 | |
|   EFI_TPL                       Tpl;
 | |
| 
 | |
|   Tpl     = gBS->RaiseTPL (TPL_NOTIFY);
 | |
| 
 | |
|   Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   //  Do the read
 | |
|   //
 | |
|   if (Private->SoftwareLoopbackEnable || Private->HardwareLoopbackEnable) {
 | |
|     for (Index = 0, BytesRead = 0; Index < *BufferSize; Index++) {
 | |
|       if (IsaSerialFifoRemove (&Private->Fifo, &Data) == EFI_SUCCESS) {
 | |
|         ((UINT8 *) Buffer)[Index] = Data;
 | |
|         BytesRead++;
 | |
|       } else {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     if (Private->HardwareFlowControl) {
 | |
|       UnixSerialIoGetControl (&Private->SerialIo, &Control);
 | |
|       Control |= EFI_SERIAL_DATA_TERMINAL_READY;
 | |
|       UnixSerialIoSetControl (&Private->SerialIo, Control);
 | |
|     }
 | |
| 
 | |
|     BytesRead = Private->UnixThunk->Read (Private->UnixHandle, Buffer, *BufferSize);
 | |
|     if (Private->HardwareFlowControl) {
 | |
|       UnixSerialIoGetControl (&Private->SerialIo, &Control);
 | |
|       Control &= ~ (UINT32) EFI_SERIAL_DATA_TERMINAL_READY;
 | |
|       UnixSerialIoSetControl (&Private->SerialIo, Control);
 | |
|     }
 | |
| 
 | |
|   }
 | |
| 
 | |
|   if (BytesRead != *BufferSize) {
 | |
|     Status = EFI_TIMEOUT;
 | |
|   } else {
 | |
|     Status = EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   *BufferSize = (UINTN) BytesRead;
 | |
| 
 | |
|   gBS->RestoreTPL (Tpl);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| BOOLEAN
 | |
| IsaSerialFifoFull (
 | |
|   IN SERIAL_DEV_FIFO *Fifo
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|   Detect whether specific FIFO is full or not
 | |
| 
 | |
|   Arguments:
 | |
|   Fifo  SERIAL_DEV_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  SERIAL_DEV_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  SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
 | |
|     Data  UINT8: the data added to FIFO
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS:  Add data to specific FIFO successfully
 | |
|     EFI_OUT_RESOURCE: Failed to add data because FIFO is already full
 | |
| 
 | |
| --*/
 | |
| // TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment
 | |
| {
 | |
|   //
 | |
|   // 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  SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
 | |
|     Data  UINT8*: the data removed from FIFO
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS:  Remove data from specific FIFO successfully
 | |
|     EFI_OUT_RESOURCE: Failed to remove data because FIFO is empty
 | |
| 
 | |
| --*/
 | |
| // TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment
 | |
| {
 | |
|   //
 | |
|   // 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;
 | |
| }
 |