mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 10:40:34 +00:00 
			
		
		
		
	 d1102dba72
			
		
	
	
		d1102dba72
		
	
	
	
	
		
			
			1. Do not use tab characters 2. No trailing white space in one line 3. All files must end with CRLF Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Liming Gao <liming.gao@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com>
		
			
				
	
	
		
			5109 lines
		
	
	
		
			162 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			5109 lines
		
	
	
		
			162 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Console Splitter Driver. Any Handle that attatched console I/O protocols
 | |
|   (Console In device, Console Out device, Console Error device, Simple Pointer
 | |
|   protocol, Absolute Pointer protocol) can be bound by this driver.
 | |
| 
 | |
|   So far it works like any other driver by opening a SimpleTextIn and/or
 | |
|   SimpleTextOut protocol with EFI_OPEN_PROTOCOL_BY_DRIVER attributes. The big
 | |
|   difference is this driver does not layer a protocol on the passed in
 | |
|   handle, or construct a child handle like a standard device or bus driver.
 | |
|   This driver produces three virtual handles as children, one for console input
 | |
|   splitter, one for console output splitter and one for error output splitter.
 | |
|   These 3 virtual handles would be installed on gST.
 | |
| 
 | |
|   Each virtual handle, that supports the Console I/O protocol, will be produced
 | |
|   in the driver entry point. The virtual handle are added on driver entry and
 | |
|   never removed. Such design ensures sytem function well during none console
 | |
|   device situation.
 | |
| 
 | |
| Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
| (C) Copyright 2016 Hewlett Packard Enterprise Development LP<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.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "ConSplitter.h"
 | |
| 
 | |
| //
 | |
| // Identify if ConIn is connected in PcdConInConnectOnDemand enabled mode.
 | |
| // default not connect
 | |
| //
 | |
| BOOLEAN  mConInIsConnect = FALSE;
 | |
| 
 | |
| //
 | |
| // Text In Splitter Private Data template
 | |
| //
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED TEXT_IN_SPLITTER_PRIVATE_DATA  mConIn = {
 | |
|   TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE,
 | |
|   (EFI_HANDLE) NULL,
 | |
| 
 | |
|   {
 | |
|     ConSplitterTextInReset,
 | |
|     ConSplitterTextInReadKeyStroke,
 | |
|     (EFI_EVENT) NULL
 | |
|   },
 | |
|   0,
 | |
|   (EFI_SIMPLE_TEXT_INPUT_PROTOCOL **) NULL,
 | |
|   0,
 | |
| 
 | |
|   {
 | |
|     ConSplitterTextInResetEx,
 | |
|     ConSplitterTextInReadKeyStrokeEx,
 | |
|     (EFI_EVENT) NULL,
 | |
|     ConSplitterTextInSetState,
 | |
|     ConSplitterTextInRegisterKeyNotify,
 | |
|     ConSplitterTextInUnregisterKeyNotify
 | |
|   },
 | |
|   0,
 | |
|   (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL **) NULL,
 | |
|   0,
 | |
|   {
 | |
|     (LIST_ENTRY *) NULL,
 | |
|     (LIST_ENTRY *) NULL
 | |
|   },
 | |
|   (EFI_KEY_DATA *) NULL,
 | |
|   0,
 | |
|   0,
 | |
|   FALSE,
 | |
| 
 | |
|   {
 | |
|     ConSplitterSimplePointerReset,
 | |
|     ConSplitterSimplePointerGetState,
 | |
|     (EFI_EVENT) NULL,
 | |
|     (EFI_SIMPLE_POINTER_MODE *) NULL
 | |
|   },
 | |
|   {
 | |
|     0x10000,
 | |
|     0x10000,
 | |
|     0x10000,
 | |
|     TRUE,
 | |
|     TRUE
 | |
|   },
 | |
|   0,
 | |
|   (EFI_SIMPLE_POINTER_PROTOCOL **) NULL,
 | |
|   0,
 | |
| 
 | |
|   {
 | |
|     ConSplitterAbsolutePointerReset,
 | |
|     ConSplitterAbsolutePointerGetState,
 | |
|     (EFI_EVENT) NULL,
 | |
|     (EFI_ABSOLUTE_POINTER_MODE *) NULL
 | |
|   },
 | |
|   {
 | |
|     0,       // AbsoluteMinX
 | |
|     0,       // AbsoluteMinY
 | |
|     0,       // AbsoluteMinZ
 | |
|     0x10000, // AbsoluteMaxX
 | |
|     0x10000, // AbsoluteMaxY
 | |
|     0x10000, // AbsoluteMaxZ
 | |
|     0        // Attributes
 | |
|   },
 | |
|   0,
 | |
|   (EFI_ABSOLUTE_POINTER_PROTOCOL **) NULL,
 | |
|   0,
 | |
|   FALSE,
 | |
| 
 | |
|   FALSE,
 | |
|   FALSE
 | |
| };
 | |
| 
 | |
| 
 | |
| //
 | |
| // Uga Draw Protocol Private Data template
 | |
| //
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED EFI_UGA_DRAW_PROTOCOL mUgaDrawProtocolTemplate = {
 | |
|   ConSplitterUgaDrawGetMode,
 | |
|   ConSplitterUgaDrawSetMode,
 | |
|   ConSplitterUgaDrawBlt
 | |
| };
 | |
| 
 | |
| //
 | |
| // Graphics Output Protocol Private Data template
 | |
| //
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED EFI_GRAPHICS_OUTPUT_PROTOCOL mGraphicsOutputProtocolTemplate = {
 | |
|   ConSplitterGraphicsOutputQueryMode,
 | |
|   ConSplitterGraphicsOutputSetMode,
 | |
|   ConSplitterGraphicsOutputBlt,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| 
 | |
| //
 | |
| // Text Out Splitter Private Data template
 | |
| //
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA mConOut = {
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE,
 | |
|   (EFI_HANDLE) NULL,
 | |
|   {
 | |
|     ConSplitterTextOutReset,
 | |
|     ConSplitterTextOutOutputString,
 | |
|     ConSplitterTextOutTestString,
 | |
|     ConSplitterTextOutQueryMode,
 | |
|     ConSplitterTextOutSetMode,
 | |
|     ConSplitterTextOutSetAttribute,
 | |
|     ConSplitterTextOutClearScreen,
 | |
|     ConSplitterTextOutSetCursorPosition,
 | |
|     ConSplitterTextOutEnableCursor,
 | |
|     (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL
 | |
|   },
 | |
|   {
 | |
|     1,
 | |
|     0,
 | |
|     0,
 | |
|     0,
 | |
|     0,
 | |
|     FALSE,
 | |
|   },
 | |
| 
 | |
|   {
 | |
|     NULL,
 | |
|     NULL,
 | |
|     NULL
 | |
|   },
 | |
|   0,
 | |
|   0,
 | |
|   0,
 | |
|   0,
 | |
| 
 | |
|   {
 | |
|     NULL,
 | |
|     NULL,
 | |
|     NULL,
 | |
|     NULL
 | |
|   },
 | |
|   (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) NULL,
 | |
|   0,
 | |
|   0,
 | |
| 
 | |
|   0,
 | |
|   (TEXT_OUT_AND_GOP_DATA *) NULL,
 | |
|   0,
 | |
|   (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL,
 | |
|   0,
 | |
|   (INT32 *) NULL
 | |
| };
 | |
| 
 | |
| //
 | |
| // Standard Error Text Out Splitter Data Template
 | |
| //
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA mStdErr = {
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE,
 | |
|   (EFI_HANDLE) NULL,
 | |
|   {
 | |
|     ConSplitterTextOutReset,
 | |
|     ConSplitterTextOutOutputString,
 | |
|     ConSplitterTextOutTestString,
 | |
|     ConSplitterTextOutQueryMode,
 | |
|     ConSplitterTextOutSetMode,
 | |
|     ConSplitterTextOutSetAttribute,
 | |
|     ConSplitterTextOutClearScreen,
 | |
|     ConSplitterTextOutSetCursorPosition,
 | |
|     ConSplitterTextOutEnableCursor,
 | |
|     (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL
 | |
|   },
 | |
|   {
 | |
|     1,
 | |
|     0,
 | |
|     0,
 | |
|     0,
 | |
|     0,
 | |
|     FALSE,
 | |
|   },
 | |
| 
 | |
|   {
 | |
|     NULL,
 | |
|     NULL,
 | |
|     NULL
 | |
|   },
 | |
|   0,
 | |
|   0,
 | |
|   0,
 | |
|   0,
 | |
| 
 | |
|   {
 | |
|     NULL,
 | |
|     NULL,
 | |
|     NULL,
 | |
|     NULL
 | |
|   },
 | |
|   (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) NULL,
 | |
|   0,
 | |
|   0,
 | |
| 
 | |
|   0,
 | |
|   (TEXT_OUT_AND_GOP_DATA *) NULL,
 | |
|   0,
 | |
|   (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL,
 | |
|   0,
 | |
|   (INT32 *) NULL
 | |
| };
 | |
| 
 | |
| //
 | |
| // Driver binding instance for Console Input Device
 | |
| //
 | |
| EFI_DRIVER_BINDING_PROTOCOL           gConSplitterConInDriverBinding = {
 | |
|   ConSplitterConInDriverBindingSupported,
 | |
|   ConSplitterConInDriverBindingStart,
 | |
|   ConSplitterConInDriverBindingStop,
 | |
|   0xa,
 | |
|   NULL,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| //
 | |
| // Driver binding instance for Console Out device
 | |
| //
 | |
| EFI_DRIVER_BINDING_PROTOCOL           gConSplitterConOutDriverBinding = {
 | |
|   ConSplitterConOutDriverBindingSupported,
 | |
|   ConSplitterConOutDriverBindingStart,
 | |
|   ConSplitterConOutDriverBindingStop,
 | |
|   0xa,
 | |
|   NULL,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| //
 | |
| // Driver binding instance for Standard Error device
 | |
| //
 | |
| EFI_DRIVER_BINDING_PROTOCOL           gConSplitterStdErrDriverBinding = {
 | |
|   ConSplitterStdErrDriverBindingSupported,
 | |
|   ConSplitterStdErrDriverBindingStart,
 | |
|   ConSplitterStdErrDriverBindingStop,
 | |
|   0xa,
 | |
|   NULL,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| //
 | |
| // Driver binding instance for Simple Pointer protocol
 | |
| //
 | |
| EFI_DRIVER_BINDING_PROTOCOL           gConSplitterSimplePointerDriverBinding = {
 | |
|   ConSplitterSimplePointerDriverBindingSupported,
 | |
|   ConSplitterSimplePointerDriverBindingStart,
 | |
|   ConSplitterSimplePointerDriverBindingStop,
 | |
|   0xa,
 | |
|   NULL,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| //
 | |
| // Driver binding instance for Absolute Pointer protocol
 | |
| //
 | |
| EFI_DRIVER_BINDING_PROTOCOL           gConSplitterAbsolutePointerDriverBinding = {
 | |
|   ConSplitterAbsolutePointerDriverBindingSupported,
 | |
|   ConSplitterAbsolutePointerDriverBindingStart,
 | |
|   ConSplitterAbsolutePointerDriverBindingStop,
 | |
|   0xa,
 | |
|   NULL,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Key notify for toggle state sync.
 | |
| 
 | |
|   @param KeyData        A pointer to a buffer that is filled in with
 | |
|                         the keystroke information for the key that was
 | |
|                         pressed.
 | |
| 
 | |
|   @retval EFI_SUCCESS   Toggle state sync successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ToggleStateSyncKeyNotify (
 | |
|   IN EFI_KEY_DATA   *KeyData
 | |
|   )
 | |
| {
 | |
|   UINTN     Index;
 | |
| 
 | |
|   if (((KeyData->KeyState.KeyToggleState & KEY_STATE_VALID_EXPOSED) == KEY_STATE_VALID_EXPOSED) &&
 | |
|       (KeyData->KeyState.KeyToggleState != mConIn.PhysicalKeyToggleState)) {
 | |
|     //
 | |
|     // There is toggle state change, sync to other console input devices.
 | |
|     //
 | |
|     for (Index = 0; Index < mConIn.CurrentNumberOfExConsoles; Index++) {
 | |
|       mConIn.TextInExList[Index]->SetState (
 | |
|                                     mConIn.TextInExList[Index],
 | |
|                                     &KeyData->KeyState.KeyToggleState
 | |
|                                     );
 | |
|     }
 | |
|     mConIn.PhysicalKeyToggleState = KeyData->KeyState.KeyToggleState;
 | |
|     DEBUG ((EFI_D_INFO, "Current toggle state is 0x%02x\n", mConIn.PhysicalKeyToggleState));
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialization for toggle state sync.
 | |
| 
 | |
|   @param Private                    Text In Splitter pointer.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| ToggleStateSyncInitialization (
 | |
|   IN TEXT_IN_SPLITTER_PRIVATE_DATA  *Private
 | |
|   )
 | |
| {
 | |
|   EFI_KEY_DATA      KeyData;
 | |
|   VOID              *NotifyHandle;
 | |
| 
 | |
|   //
 | |
|   // Initialize PhysicalKeyToggleState that will be synced to new console
 | |
|   // input device to turn on physical TextInEx partial key report for
 | |
|   // toggle state sync.
 | |
|   //
 | |
|   Private->PhysicalKeyToggleState = KEY_STATE_VALID_EXPOSED;
 | |
| 
 | |
|   //
 | |
|   // Initialize VirtualKeyStateExported to let the virtual TextInEx not report
 | |
|   // the partial key even though the physical TextInEx turns on the partial
 | |
|   // key report. The virtual TextInEx will report the partial key after it is
 | |
|   // required by calling SetState(X | KEY_STATE_VALID_EXPOSED) explicitly.
 | |
|   //
 | |
|   Private->VirtualKeyStateExported = FALSE;
 | |
| 
 | |
|   //
 | |
|   // Register key notify for toggle state sync.
 | |
|   //
 | |
|   KeyData.Key.ScanCode = SCAN_NULL;
 | |
|   KeyData.Key.UnicodeChar = CHAR_NULL;
 | |
|   KeyData.KeyState.KeyShiftState = 0;
 | |
|   KeyData.KeyState.KeyToggleState = 0;
 | |
|   Private->TextInEx.RegisterKeyNotify (
 | |
|                       &Private->TextInEx,
 | |
|                       &KeyData,
 | |
|                       ToggleStateSyncKeyNotify,
 | |
|                       &NotifyHandle
 | |
|                       );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reinitialization for toggle state sync.
 | |
| 
 | |
|   @param Private                    Text In Splitter pointer.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| ToggleStateSyncReInitialization (
 | |
|   IN TEXT_IN_SPLITTER_PRIVATE_DATA  *Private
 | |
|   )
 | |
| {
 | |
|   UINTN             Index;
 | |
| 
 | |
|   //
 | |
|   // Reinitialize PhysicalKeyToggleState that will be synced to new console
 | |
|   // input device to turn on physical TextInEx partial key report for
 | |
|   // toggle state sync.
 | |
|   //
 | |
|   Private->PhysicalKeyToggleState = KEY_STATE_VALID_EXPOSED;
 | |
| 
 | |
|   //
 | |
|   // Reinitialize VirtualKeyStateExported to let the virtual TextInEx not report
 | |
|   // the partial key even though the physical TextInEx turns on the partial
 | |
|   // key report. The virtual TextInEx will report the partial key after it is
 | |
|   // required by calling SetState(X | KEY_STATE_VALID_EXPOSED) explicitly.
 | |
|   //
 | |
|   Private->VirtualKeyStateExported = FALSE;
 | |
| 
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
 | |
|     Private->TextInExList[Index]->SetState (
 | |
|                                     Private->TextInExList[Index],
 | |
|                                     &Private->PhysicalKeyToggleState
 | |
|                                     );
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The Entry Point for module ConSplitter. The user code starts with this function.
 | |
| 
 | |
|   Installs driver module protocols and. Creates virtual device handles for ConIn,
 | |
|   ConOut, and StdErr. Installs Simple Text In protocol, Simple Text In Ex protocol,
 | |
|   Simple Pointer protocol, Absolute Pointer protocol on those virtual handlers.
 | |
|   Installs Graphics Output protocol and/or UGA Draw protocol if needed.
 | |
| 
 | |
|   @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
 | |
| ConSplitterDriverEntry(
 | |
|   IN EFI_HANDLE           ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE     *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
| 
 | |
|   //
 | |
|   // Install driver model protocol(s).
 | |
|   //
 | |
|   Status = EfiLibInstallDriverBindingComponentName2 (
 | |
|              ImageHandle,
 | |
|              SystemTable,
 | |
|              &gConSplitterConInDriverBinding,
 | |
|              ImageHandle,
 | |
|              &gConSplitterConInComponentName,
 | |
|              &gConSplitterConInComponentName2
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = EfiLibInstallDriverBindingComponentName2 (
 | |
|              ImageHandle,
 | |
|              SystemTable,
 | |
|              &gConSplitterSimplePointerDriverBinding,
 | |
|              NULL,
 | |
|              &gConSplitterSimplePointerComponentName,
 | |
|              &gConSplitterSimplePointerComponentName2
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = EfiLibInstallDriverBindingComponentName2 (
 | |
|              ImageHandle,
 | |
|              SystemTable,
 | |
|              &gConSplitterAbsolutePointerDriverBinding,
 | |
|              NULL,
 | |
|              &gConSplitterAbsolutePointerComponentName,
 | |
|              &gConSplitterAbsolutePointerComponentName2
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = EfiLibInstallDriverBindingComponentName2 (
 | |
|              ImageHandle,
 | |
|              SystemTable,
 | |
|              &gConSplitterConOutDriverBinding,
 | |
|              NULL,
 | |
|              &gConSplitterConOutComponentName,
 | |
|              &gConSplitterConOutComponentName2
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = EfiLibInstallDriverBindingComponentName2 (
 | |
|              ImageHandle,
 | |
|              SystemTable,
 | |
|              &gConSplitterStdErrDriverBinding,
 | |
|              NULL,
 | |
|              &gConSplitterStdErrComponentName,
 | |
|              &gConSplitterStdErrComponentName2
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Either Graphics Output protocol or UGA Draw protocol must be supported.
 | |
|   //
 | |
|   ASSERT (FeaturePcdGet (PcdConOutGopSupport) ||
 | |
|           FeaturePcdGet (PcdConOutUgaSupport));
 | |
| 
 | |
|   //
 | |
|   // The driver creates virtual handles for ConIn, ConOut, StdErr.
 | |
|   // The virtual handles will always exist even if no console exist in the
 | |
|   // system. This is need to support hotplug devices like USB.
 | |
|   //
 | |
|   //
 | |
|   // Create virtual device handle for ConIn Splitter
 | |
|   //
 | |
|   Status = ConSplitterTextInConstructor (&mConIn);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                     &mConIn.VirtualHandle,
 | |
|                     &gEfiSimpleTextInProtocolGuid,
 | |
|                     &mConIn.TextIn,
 | |
|                     &gEfiSimpleTextInputExProtocolGuid,
 | |
|                     &mConIn.TextInEx,
 | |
|                     &gEfiSimplePointerProtocolGuid,
 | |
|                     &mConIn.SimplePointer,
 | |
|                     &gEfiAbsolutePointerProtocolGuid,
 | |
|                     &mConIn.AbsolutePointer,
 | |
|                     NULL
 | |
|                     );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // Update the EFI System Table with new virtual console
 | |
|       // and update the pointer to Simple Text Input protocol.
 | |
|       //
 | |
|       gST->ConsoleInHandle  = mConIn.VirtualHandle;
 | |
|       gST->ConIn            = &mConIn.TextIn;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Create virtual device handle for ConOut Splitter
 | |
|   //
 | |
|   Status = ConSplitterTextOutConstructor (&mConOut);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                     &mConOut.VirtualHandle,
 | |
|                     &gEfiSimpleTextOutProtocolGuid,
 | |
|                     &mConOut.TextOut,
 | |
|                     NULL
 | |
|                     );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // Update the EFI System Table with new virtual console
 | |
|       // and Update the pointer to Text Output protocol.
 | |
|       //
 | |
|       gST->ConsoleOutHandle = mConOut.VirtualHandle;
 | |
|       gST->ConOut           = &mConOut.TextOut;
 | |
|     }
 | |
| 
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create virtual device handle for StdErr Splitter
 | |
|   //
 | |
|   Status = ConSplitterTextOutConstructor (&mStdErr);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                     &mStdErr.VirtualHandle,
 | |
|                     &gEfiSimpleTextOutProtocolGuid,
 | |
|                     &mStdErr.TextOut,
 | |
|                     NULL
 | |
|                     );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // Update the EFI System Table with new virtual console
 | |
|       // and update the pointer to Text Output protocol.
 | |
|       //
 | |
|       gST->StandardErrorHandle  = mStdErr.VirtualHandle;
 | |
|       gST->StdErr               = &mStdErr.TextOut;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Update the CRC32 in the EFI System Table header
 | |
|   //
 | |
|   gST->Hdr.CRC32 = 0;
 | |
|   gBS->CalculateCrc32 (
 | |
|         (UINT8 *) &gST->Hdr,
 | |
|         gST->Hdr.HeaderSize,
 | |
|         &gST->Hdr.CRC32
 | |
|         );
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Construct console input devices' private data.
 | |
| 
 | |
|   @param  ConInPrivate             A pointer to the TEXT_IN_SPLITTER_PRIVATE_DATA
 | |
|                                    structure.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES     Out of resources.
 | |
|   @retval EFI_SUCCESS              Text Input Devcie's private data has been constructed.
 | |
|   @retval other                    Failed to construct private data.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterTextInConstructor (
 | |
|   TEXT_IN_SPLITTER_PRIVATE_DATA       *ConInPrivate
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINTN       TextInExListCount;
 | |
| 
 | |
|   //
 | |
|   // Allocate buffer for Simple Text Input device
 | |
|   //
 | |
|   Status = ConSplitterGrowBuffer (
 | |
|             sizeof (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *),
 | |
|             &ConInPrivate->TextInListCount,
 | |
|             (VOID **) &ConInPrivate->TextInList
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create Event to wait for a key
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_WAIT,
 | |
|                   TPL_NOTIFY,
 | |
|                   ConSplitterTextInWaitForKey,
 | |
|                   ConInPrivate,
 | |
|                   &ConInPrivate->TextIn.WaitForKey
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Allocate buffer for KeyQueue
 | |
|   //
 | |
|   TextInExListCount = ConInPrivate->TextInExListCount;
 | |
|   Status = ConSplitterGrowBuffer (
 | |
|              sizeof (EFI_KEY_DATA),
 | |
|              &TextInExListCount,
 | |
|              (VOID **) &ConInPrivate->KeyQueue
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate buffer for Simple Text Input Ex device
 | |
|   //
 | |
|   Status = ConSplitterGrowBuffer (
 | |
|              sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *),
 | |
|              &ConInPrivate->TextInExListCount,
 | |
|              (VOID **) &ConInPrivate->TextInExList
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   //
 | |
|   // Create Event to wait for a key Ex
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_WAIT,
 | |
|                   TPL_NOTIFY,
 | |
|                   ConSplitterTextInWaitForKey,
 | |
|                   ConInPrivate,
 | |
|                   &ConInPrivate->TextInEx.WaitForKeyEx
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   InitializeListHead (&ConInPrivate->NotifyList);
 | |
| 
 | |
|   ToggleStateSyncInitialization (ConInPrivate);
 | |
| 
 | |
|   ConInPrivate->AbsolutePointer.Mode = &ConInPrivate->AbsolutePointerMode;
 | |
|   //
 | |
|   // Allocate buffer for Absolute Pointer device
 | |
|   //
 | |
|   Status = ConSplitterGrowBuffer (
 | |
|             sizeof (EFI_ABSOLUTE_POINTER_PROTOCOL *),
 | |
|             &ConInPrivate->AbsolutePointerListCount,
 | |
|             (VOID **) &ConInPrivate->AbsolutePointerList
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   //
 | |
|   // Create Event to wait for device input for Absolute pointer device
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|             EVT_NOTIFY_WAIT,
 | |
|             TPL_NOTIFY,
 | |
|             ConSplitterAbsolutePointerWaitForInput,
 | |
|             ConInPrivate,
 | |
|             &ConInPrivate->AbsolutePointer.WaitForInput
 | |
|         );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   ConInPrivate->SimplePointer.Mode = &ConInPrivate->SimplePointerMode;
 | |
|   //
 | |
|   // Allocate buffer for Simple Pointer device
 | |
|   //
 | |
|   Status = ConSplitterGrowBuffer (
 | |
|             sizeof (EFI_SIMPLE_POINTER_PROTOCOL *),
 | |
|             &ConInPrivate->PointerListCount,
 | |
|             (VOID **) &ConInPrivate->PointerList
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   //
 | |
|   // Create Event to wait for device input for Simple pointer device
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_WAIT,
 | |
|                   TPL_NOTIFY,
 | |
|                   ConSplitterSimplePointerWaitForInput,
 | |
|                   ConInPrivate,
 | |
|                   &ConInPrivate->SimplePointer.WaitForInput
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
|   //
 | |
|   // Create Event to signal ConIn connection request
 | |
|   //
 | |
|   Status = gBS->CreateEventEx (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_CALLBACK,
 | |
|                   EfiEventEmptyFunction,
 | |
|                   NULL,
 | |
|                   &gConnectConInEventGuid,
 | |
|                   &ConInPrivate->ConnectConInEvent
 | |
|                   );
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Construct console output devices' private data.
 | |
| 
 | |
|   @param  ConOutPrivate            A pointer to the TEXT_OUT_SPLITTER_PRIVATE_DATA
 | |
|                                    structure.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES     Out of resources.
 | |
|   @retval EFI_SUCCESS              Text Input Devcie's private data has been constructed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterTextOutConstructor (
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA      *ConOutPrivate
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;
 | |
| 
 | |
|   //
 | |
|   // Copy protocols template
 | |
|   //
 | |
|   if (FeaturePcdGet (PcdConOutUgaSupport)) {
 | |
|     CopyMem (&ConOutPrivate->UgaDraw, &mUgaDrawProtocolTemplate, sizeof (EFI_UGA_DRAW_PROTOCOL));
 | |
|   }
 | |
|   if (FeaturePcdGet (PcdConOutGopSupport)) {
 | |
|     CopyMem (&ConOutPrivate->GraphicsOutput, &mGraphicsOutputProtocolTemplate, sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL));
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Initilize console output splitter's private data.
 | |
|   //
 | |
|   ConOutPrivate->TextOut.Mode = &ConOutPrivate->TextOutMode;
 | |
| 
 | |
|   //
 | |
|   // When new console device is added, the new mode will be set later,
 | |
|   // so put current mode back to init state.
 | |
|   //
 | |
|   ConOutPrivate->TextOutMode.Mode = 0xFF;
 | |
|   //
 | |
|   // Allocate buffer for Console Out device
 | |
|   //
 | |
|   Status = ConSplitterGrowBuffer (
 | |
|             sizeof (TEXT_OUT_AND_GOP_DATA),
 | |
|             &ConOutPrivate->TextOutListCount,
 | |
|             (VOID **) &ConOutPrivate->TextOutList
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   //
 | |
|   // Allocate buffer for Text Out query data
 | |
|   //
 | |
|   Status = ConSplitterGrowBuffer (
 | |
|             sizeof (TEXT_OUT_SPLITTER_QUERY_DATA),
 | |
|             &ConOutPrivate->TextOutQueryDataCount,
 | |
|             (VOID **) &ConOutPrivate->TextOutQueryData
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Setup the default console to 80 x 25 and mode to 0
 | |
|   //
 | |
|   ConOutPrivate->TextOutQueryData[0].Columns  = 80;
 | |
|   ConOutPrivate->TextOutQueryData[0].Rows     = 25;
 | |
|   TextOutSetMode (ConOutPrivate, 0);
 | |
| 
 | |
| 
 | |
|   if (FeaturePcdGet (PcdConOutUgaSupport)) {
 | |
|     //
 | |
|     // Setup the UgaDraw to 800 x 600 x 32 bits per pixel, 60Hz.
 | |
|     //
 | |
|     ConSplitterUgaDrawSetMode (&ConOutPrivate->UgaDraw, 800, 600, 32, 60);
 | |
|   }
 | |
|   if (FeaturePcdGet (PcdConOutGopSupport)) {
 | |
|     //
 | |
|     // Setup resource for mode information in Graphics Output Protocol interface
 | |
|     //
 | |
|     if ((ConOutPrivate->GraphicsOutput.Mode = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE))) == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|     if ((ConOutPrivate->GraphicsOutput.Mode->Info = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION))) == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|     //
 | |
|     // Setup the DevNullGraphicsOutput to 800 x 600 x 32 bits per pixel
 | |
|     // DevNull will be updated to user-defined mode after driver has started.
 | |
|     //
 | |
|     if ((ConOutPrivate->GraphicsOutputModeBuffer = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION))) == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|     Info = &ConOutPrivate->GraphicsOutputModeBuffer[0];
 | |
|     Info->Version = 0;
 | |
|     Info->HorizontalResolution = 800;
 | |
|     Info->VerticalResolution = 600;
 | |
|     Info->PixelFormat = PixelBltOnly;
 | |
|     Info->PixelsPerScanLine = 800;
 | |
|     CopyMem (ConOutPrivate->GraphicsOutput.Mode->Info, Info, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
 | |
|     ConOutPrivate->GraphicsOutput.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
 | |
| 
 | |
|     //
 | |
|     // Initialize the following items, theset items remain unchanged in GraphicsOutput->SetMode()
 | |
|     // GraphicsOutputMode->FrameBufferBase, GraphicsOutputMode->FrameBufferSize
 | |
|     //
 | |
|     ConOutPrivate->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;
 | |
|     ConOutPrivate->GraphicsOutput.Mode->FrameBufferSize = 0;
 | |
| 
 | |
|     ConOutPrivate->GraphicsOutput.Mode->MaxMode = 1;
 | |
|     //
 | |
|     // Initial current mode to unknown state, and then set to mode 0
 | |
|     //
 | |
|     ConOutPrivate->GraphicsOutput.Mode->Mode = 0xffff;
 | |
|     ConOutPrivate->GraphicsOutput.SetMode (&ConOutPrivate->GraphicsOutput, 0);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Test to see if the specified protocol could be supported on the specified device.
 | |
| 
 | |
|   @param  This                Driver Binding protocol pointer.
 | |
|   @param  ControllerHandle    Handle of device to test.
 | |
|   @param  Guid                The specified protocol.
 | |
| 
 | |
|   @retval EFI_SUCCESS         The specified protocol is supported on this device.
 | |
|   @retval EFI_UNSUPPORTED     The specified protocol attempts to be installed on virtul handle.
 | |
|   @retval other               Failed to open specified protocol on this device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterSupported (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  EFI_GUID                        *Guid
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   VOID        *Instance;
 | |
| 
 | |
|   //
 | |
|   // Make sure the Console Splitter does not attempt to attach to itself
 | |
|   //
 | |
|   if (ControllerHandle == mConIn.VirtualHandle  ||
 | |
|       ControllerHandle == mConOut.VirtualHandle ||
 | |
|       ControllerHandle == mStdErr.VirtualHandle
 | |
|       ) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check to see whether the specific protocol could be opened BY_DRIVER
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   Guid,
 | |
|                   &Instance,
 | |
|                   This->DriverBindingHandle,
 | |
|                   ControllerHandle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   gBS->CloseProtocol (
 | |
|         ControllerHandle,
 | |
|         Guid,
 | |
|         This->DriverBindingHandle,
 | |
|         ControllerHandle
 | |
|         );
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Test to see if Console In Device could be supported on the Controller.
 | |
| 
 | |
|   @param  This                Driver Binding protocol instance pointer.
 | |
|   @param  ControllerHandle    Handle of device to test.
 | |
|   @param  RemainingDevicePath Optional parameter use to pick a specific child
 | |
|                               device to start.
 | |
| 
 | |
|   @retval EFI_SUCCESS         This driver supports this device.
 | |
|   @retval other               This driver does not support this device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterConInDriverBindingSupported (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   return ConSplitterSupported (
 | |
|           This,
 | |
|           ControllerHandle,
 | |
|           &gEfiConsoleInDeviceGuid
 | |
|           );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Test to see if Simple Pointer protocol could be supported on the Controller.
 | |
| 
 | |
|   @param  This                Driver Binding protocol instance pointer.
 | |
|   @param  ControllerHandle    Handle of device to test.
 | |
|   @param  RemainingDevicePath Optional parameter use to pick a specific child
 | |
|                               device to start.
 | |
| 
 | |
|   @retval EFI_SUCCESS         This driver supports this device.
 | |
|   @retval other               This driver does not support this device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterSimplePointerDriverBindingSupported (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   return ConSplitterSupported (
 | |
|           This,
 | |
|           ControllerHandle,
 | |
|           &gEfiSimplePointerProtocolGuid
 | |
|           );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Test to see if Absolute Pointer protocol could be supported on the Controller.
 | |
| 
 | |
|   @param  This                Driver Binding protocol instance pointer.
 | |
|   @param  ControllerHandle    Handle of device to test.
 | |
|   @param  RemainingDevicePath Optional parameter use to pick a specific child
 | |
|                               device to start.
 | |
| 
 | |
|   @retval EFI_SUCCESS         This driver supports this device.
 | |
|   @retval other               This driver does not support this device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterAbsolutePointerDriverBindingSupported (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   return ConSplitterSupported (
 | |
|           This,
 | |
|           ControllerHandle,
 | |
|           &gEfiAbsolutePointerProtocolGuid
 | |
|           );
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Test to see if Console Out Device could be supported on the Controller.
 | |
| 
 | |
|   @param  This                Driver Binding protocol instance pointer.
 | |
|   @param  ControllerHandle    Handle of device to test.
 | |
|   @param  RemainingDevicePath Optional parameter use to pick a specific child
 | |
|                               device to start.
 | |
| 
 | |
|   @retval EFI_SUCCESS         This driver supports this device.
 | |
|   @retval other               This driver does not support this device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterConOutDriverBindingSupported (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   return ConSplitterSupported (
 | |
|           This,
 | |
|           ControllerHandle,
 | |
|           &gEfiConsoleOutDeviceGuid
 | |
|           );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Test to see if Standard Error Device could be supported on the Controller.
 | |
| 
 | |
|   @param  This                Driver Binding protocol instance pointer.
 | |
|   @param  ControllerHandle    Handle of device to test.
 | |
|   @param  RemainingDevicePath Optional parameter use to pick a specific child
 | |
|                               device to start.
 | |
| 
 | |
|   @retval EFI_SUCCESS         This driver supports this device.
 | |
|   @retval other               This driver does not support this device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterStdErrDriverBindingSupported (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   return ConSplitterSupported (
 | |
|           This,
 | |
|           ControllerHandle,
 | |
|           &gEfiStandardErrorDeviceGuid
 | |
|           );
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Start ConSplitter on devcie handle by opening Console Device Guid on device handle
 | |
|   and the console virtual handle. And Get the console interface on controller handle.
 | |
| 
 | |
|   @param  This                      Driver Binding protocol instance pointer.
 | |
|   @param  ControllerHandle          Handle of device.
 | |
|   @param  ConSplitterVirtualHandle  Console virtual Handle.
 | |
|   @param  DeviceGuid                The specified Console Device, such as ConInDev,
 | |
|                                     ConOutDev.
 | |
|   @param  InterfaceGuid             The specified protocol to be opened.
 | |
|   @param  Interface                 Protocol interface returned.
 | |
| 
 | |
|   @retval EFI_SUCCESS               This driver supports this device.
 | |
|   @retval other                     Failed to open the specified Console Device Guid
 | |
|                                     or specified protocol.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterStart (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  EFI_HANDLE                      ConSplitterVirtualHandle,
 | |
|   IN  EFI_GUID                        *DeviceGuid,
 | |
|   IN  EFI_GUID                        *InterfaceGuid,
 | |
|   OUT VOID                            **Interface
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   VOID        *Instance;
 | |
| 
 | |
|   //
 | |
|   // Check to see whether the ControllerHandle has the DeviceGuid on it.
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   DeviceGuid,
 | |
|                   &Instance,
 | |
|                   This->DriverBindingHandle,
 | |
|                   ControllerHandle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Open the Parent Handle for the child.
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   DeviceGuid,
 | |
|                   &Instance,
 | |
|                   This->DriverBindingHandle,
 | |
|                   ConSplitterVirtualHandle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto Err;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Open InterfaceGuid on the virtul handle.
 | |
|   //
 | |
|   Status =  gBS->OpenProtocol (
 | |
|                 ControllerHandle,
 | |
|                 InterfaceGuid,
 | |
|                 Interface,
 | |
|                 This->DriverBindingHandle,
 | |
|                 ConSplitterVirtualHandle,
 | |
|                 EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                 );
 | |
| 
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // close the DeviceGuid on ConSplitter VirtualHandle.
 | |
|   //
 | |
|   gBS->CloseProtocol (
 | |
|         ControllerHandle,
 | |
|         DeviceGuid,
 | |
|         This->DriverBindingHandle,
 | |
|         ConSplitterVirtualHandle
 | |
|         );
 | |
| 
 | |
| Err:
 | |
|   //
 | |
|   // close the DeviceGuid on ControllerHandle.
 | |
|   //
 | |
|   gBS->CloseProtocol (
 | |
|         ControllerHandle,
 | |
|         DeviceGuid,
 | |
|         This->DriverBindingHandle,
 | |
|         ControllerHandle
 | |
|         );
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Start Console In Consplitter on device handle.
 | |
| 
 | |
|   @param  This                 Driver Binding protocol instance pointer.
 | |
|   @param  ControllerHandle     Handle of device to bind driver to.
 | |
|   @param  RemainingDevicePath  Optional parameter use to pick a specific child
 | |
|                                device to start.
 | |
| 
 | |
|   @retval EFI_SUCCESS          Console In Consplitter is added to ControllerHandle.
 | |
|   @retval other                Console In Consplitter does not support this device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterConInDriverBindingStart (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                          Status;
 | |
|   EFI_SIMPLE_TEXT_INPUT_PROTOCOL      *TextIn;
 | |
|   EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL   *TextInEx;
 | |
| 
 | |
|   //
 | |
|   // Start ConSplitter on ControllerHandle, and create the virtual
 | |
|   // agrogated console device on first call Start for a SimpleTextIn handle.
 | |
|   //
 | |
|   Status = ConSplitterStart (
 | |
|             This,
 | |
|             ControllerHandle,
 | |
|             mConIn.VirtualHandle,
 | |
|             &gEfiConsoleInDeviceGuid,
 | |
|             &gEfiSimpleTextInProtocolGuid,
 | |
|             (VOID **) &TextIn
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Add this device into Text In devices list.
 | |
|   //
 | |
|   Status = ConSplitterTextInAddDevice (&mConIn, TextIn);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   &gEfiSimpleTextInputExProtocolGuid,
 | |
|                   (VOID **) &TextInEx,
 | |
|                   This->DriverBindingHandle,
 | |
|                   mConIn.VirtualHandle,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                   );
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // If Simple Text Input Ex protocol exists,
 | |
|     // add this device into Text In Ex devices list.
 | |
|     //
 | |
|     Status = ConSplitterTextInExAddDevice (&mConIn, TextInEx);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Start Simple Pointer Consplitter on device handle.
 | |
| 
 | |
|   @param  This                 Driver Binding protocol instance pointer.
 | |
|   @param  ControllerHandle     Handle of device to bind driver to.
 | |
|   @param  RemainingDevicePath  Optional parameter use to pick a specific child
 | |
|                                device to start.
 | |
| 
 | |
|   @retval EFI_SUCCESS          Simple Pointer Consplitter is added to ControllerHandle.
 | |
|   @retval other                Simple Pointer Consplitter does not support this device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterSimplePointerDriverBindingStart (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer;
 | |
| 
 | |
|   //
 | |
|   // Start ConSplitter on ControllerHandle, and create the virtual
 | |
|   // agrogated console device on first call Start for a SimplePointer handle.
 | |
|   //
 | |
|   Status = ConSplitterStart (
 | |
|             This,
 | |
|             ControllerHandle,
 | |
|             mConIn.VirtualHandle,
 | |
|             &gEfiSimplePointerProtocolGuid,
 | |
|             &gEfiSimplePointerProtocolGuid,
 | |
|             (VOID **) &SimplePointer
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Add this devcie into Simple Pointer devices list.
 | |
|   //
 | |
|   return ConSplitterSimplePointerAddDevice (&mConIn, SimplePointer);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Start Absolute Pointer Consplitter on device handle.
 | |
| 
 | |
|   @param  This                 Driver Binding protocol instance pointer.
 | |
|   @param  ControllerHandle     Handle of device to bind driver to.
 | |
|   @param  RemainingDevicePath  Optional parameter use to pick a specific child
 | |
|                                device to start.
 | |
| 
 | |
|   @retval EFI_SUCCESS          Absolute Pointer Consplitter is added to ControllerHandle.
 | |
|   @retval other                Absolute Pointer Consplitter does not support this device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterAbsolutePointerDriverBindingStart (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   EFI_ABSOLUTE_POINTER_PROTOCOL     *AbsolutePointer;
 | |
| 
 | |
|   //
 | |
|   // Start ConSplitter on ControllerHandle, and create the virtual
 | |
|   // agrogated console device on first call Start for a AbsolutePointer handle.
 | |
|   //
 | |
|   Status = ConSplitterStart (
 | |
|              This,
 | |
|              ControllerHandle,
 | |
|              mConIn.VirtualHandle,
 | |
|              &gEfiAbsolutePointerProtocolGuid,
 | |
|              &gEfiAbsolutePointerProtocolGuid,
 | |
|              (VOID **) &AbsolutePointer
 | |
|              );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Add this devcie into Absolute Pointer devices list.
 | |
|   //
 | |
|   return ConSplitterAbsolutePointerAddDevice (&mConIn, AbsolutePointer);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Start Console Out Consplitter on device handle.
 | |
| 
 | |
|   @param  This                 Driver Binding protocol instance pointer.
 | |
|   @param  ControllerHandle     Handle of device to bind driver to.
 | |
|   @param  RemainingDevicePath  Optional parameter use to pick a specific child
 | |
|                                device to start.
 | |
| 
 | |
|   @retval EFI_SUCCESS          Console Out Consplitter is added to ControllerHandle.
 | |
|   @retval other                Console Out Consplitter does not support this device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterConOutDriverBindingStart (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                           Status;
 | |
|   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL      *TextOut;
 | |
|   EFI_GRAPHICS_OUTPUT_PROTOCOL         *GraphicsOutput;
 | |
|   EFI_UGA_DRAW_PROTOCOL                *UgaDraw;
 | |
|   UINTN                                SizeOfInfo;
 | |
|   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
 | |
| 
 | |
|   //
 | |
|   // Start ConSplitter on ControllerHandle, and create the virtual
 | |
|   // agrogated console device on first call Start for a ConsoleOut handle.
 | |
|   //
 | |
|   Status = ConSplitterStart (
 | |
|             This,
 | |
|             ControllerHandle,
 | |
|             mConOut.VirtualHandle,
 | |
|             &gEfiConsoleOutDeviceGuid,
 | |
|             &gEfiSimpleTextOutProtocolGuid,
 | |
|             (VOID **) &TextOut
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   GraphicsOutput = NULL;
 | |
|   UgaDraw        = NULL;
 | |
|   //
 | |
|   // Try to Open Graphics Output protocol
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   &gEfiGraphicsOutputProtocolGuid,
 | |
|                   (VOID **) &GraphicsOutput,
 | |
|                   This->DriverBindingHandle,
 | |
|                   mConOut.VirtualHandle,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
 | |
|     //
 | |
|     // Open UGA DRAW protocol
 | |
|     //
 | |
|     gBS->OpenProtocol (
 | |
|            ControllerHandle,
 | |
|            &gEfiUgaDrawProtocolGuid,
 | |
|            (VOID **) &UgaDraw,
 | |
|            This->DriverBindingHandle,
 | |
|            mConOut.VirtualHandle,
 | |
|            EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|            );
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // When new console device is added, the new mode will be set later,
 | |
|   // so put current mode back to init state.
 | |
|   //
 | |
|   mConOut.TextOutMode.Mode = 0xFF;
 | |
| 
 | |
|   //
 | |
|   // If both ConOut and StdErr incorporate the same Text Out device,
 | |
|   // their MaxMode and QueryData should be the intersection of both.
 | |
|   //
 | |
|   Status = ConSplitterTextOutAddDevice (&mConOut, TextOut, GraphicsOutput, UgaDraw);
 | |
|   ConSplitterTextOutSetAttribute (&mConOut.TextOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
 | |
| 
 | |
|   if (FeaturePcdGet (PcdConOutUgaSupport)) {
 | |
|     //
 | |
|     // Get the UGA mode data of ConOut from the current mode
 | |
|     //
 | |
|     if (GraphicsOutput != NULL) {
 | |
|       Status = GraphicsOutput->QueryMode (GraphicsOutput, GraphicsOutput->Mode->Mode, &SizeOfInfo, &Info);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         return Status;
 | |
|       }
 | |
|       ASSERT ( SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
 | |
| 
 | |
|       mConOut.UgaHorizontalResolution = Info->HorizontalResolution;
 | |
|       mConOut.UgaVerticalResolution   = Info->VerticalResolution;
 | |
|       mConOut.UgaColorDepth           = 32;
 | |
|       mConOut.UgaRefreshRate          = 60;
 | |
| 
 | |
|       FreePool (Info);
 | |
| 
 | |
|     } else if (UgaDraw != NULL) {
 | |
|       Status = UgaDraw->GetMode (
 | |
|                  UgaDraw,
 | |
|                  &mConOut.UgaHorizontalResolution,
 | |
|                  &mConOut.UgaVerticalResolution,
 | |
|                  &mConOut.UgaColorDepth,
 | |
|                  &mConOut.UgaRefreshRate
 | |
|                  );
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Start Standard Error Consplitter on device handle.
 | |
| 
 | |
|   @param  This                 Driver Binding protocol instance pointer.
 | |
|   @param  ControllerHandle     Handle of device to bind driver to.
 | |
|   @param  RemainingDevicePath  Optional parameter use to pick a specific child
 | |
|                                device to start.
 | |
| 
 | |
|   @retval EFI_SUCCESS          Standard Error Consplitter is added to ControllerHandle.
 | |
|   @retval other                Standard Error Consplitter does not support this device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterStdErrDriverBindingStart (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                       Status;
 | |
|   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;
 | |
| 
 | |
|   //
 | |
|   // Start ConSplitter on ControllerHandle, and create the virtual
 | |
|   // agrogated console device on first call Start for a StandardError handle.
 | |
|   //
 | |
|   Status = ConSplitterStart (
 | |
|             This,
 | |
|             ControllerHandle,
 | |
|             mStdErr.VirtualHandle,
 | |
|             &gEfiStandardErrorDeviceGuid,
 | |
|             &gEfiSimpleTextOutProtocolGuid,
 | |
|             (VOID **) &TextOut
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // When new console device is added, the new mode will be set later,
 | |
|   // so put current mode back to init state.
 | |
|   //
 | |
|   mStdErr.TextOutMode.Mode = 0xFF;
 | |
| 
 | |
|   //
 | |
|   // If both ConOut and StdErr incorporate the same Text Out device,
 | |
|   // their MaxMode and QueryData should be the intersection of both.
 | |
|   //
 | |
|   Status = ConSplitterTextOutAddDevice (&mStdErr, TextOut, NULL, NULL);
 | |
|   ConSplitterTextOutSetAttribute (&mStdErr.TextOut, EFI_TEXT_ATTR (EFI_MAGENTA, EFI_BLACK));
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Stop ConSplitter on device handle by closing Console Device Guid on device handle
 | |
|   and the console virtual handle.
 | |
| 
 | |
|   @param  This                      Protocol instance pointer.
 | |
|   @param  ControllerHandle          Handle of device.
 | |
|   @param  ConSplitterVirtualHandle  Console virtual Handle.
 | |
|   @param  DeviceGuid                The specified Console Device, such as ConInDev,
 | |
|                                     ConOutDev.
 | |
|   @param  InterfaceGuid             The specified protocol to be opened.
 | |
|   @param  Interface                 Protocol interface returned.
 | |
| 
 | |
|   @retval EFI_SUCCESS               Stop ConSplitter on ControllerHandle successfully.
 | |
|   @retval other                     Failed to Stop ConSplitter on ControllerHandle.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterStop (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  EFI_HANDLE                      ConSplitterVirtualHandle,
 | |
|   IN  EFI_GUID                        *DeviceGuid,
 | |
|   IN  EFI_GUID                        *InterfaceGuid,
 | |
|   IN  VOID                            **Interface
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   InterfaceGuid,
 | |
|                   Interface,
 | |
|                   This->DriverBindingHandle,
 | |
|                   ControllerHandle,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // close the protocol refered.
 | |
|   //
 | |
|   gBS->CloseProtocol (
 | |
|         ControllerHandle,
 | |
|         DeviceGuid,
 | |
|         This->DriverBindingHandle,
 | |
|         ConSplitterVirtualHandle
 | |
|         );
 | |
| 
 | |
|   gBS->CloseProtocol (
 | |
|         ControllerHandle,
 | |
|         DeviceGuid,
 | |
|         This->DriverBindingHandle,
 | |
|         ControllerHandle
 | |
|         );
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Stop Console In ConSplitter on ControllerHandle by closing Console In Devcice GUID.
 | |
| 
 | |
|   @param  This              Driver Binding protocol instance pointer.
 | |
|   @param  ControllerHandle  Handle of device to stop driver on
 | |
|   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
 | |
|                             children is zero stop the entire bus driver.
 | |
|   @param  ChildHandleBuffer List of Child Handles to Stop.
 | |
| 
 | |
|   @retval EFI_SUCCESS       This driver is removed ControllerHandle
 | |
|   @retval other             This driver was not removed from this device
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterConInDriverBindingStop (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  UINTN                           NumberOfChildren,
 | |
|   IN  EFI_HANDLE                      *ChildHandleBuffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   EFI_SIMPLE_TEXT_INPUT_PROTOCOL    *TextIn;
 | |
|   EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx;
 | |
| 
 | |
|   if (NumberOfChildren == 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   &gEfiSimpleTextInputExProtocolGuid,
 | |
|                   (VOID **) &TextInEx,
 | |
|                   This->DriverBindingHandle,
 | |
|                   ControllerHandle,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                   );
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // If Simple Text Input Ex protocol exists,
 | |
|     // remove device from Text Input Ex devices list.
 | |
|     //
 | |
|     Status = ConSplitterTextInExDeleteDevice (&mConIn, TextInEx);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Close Simple Text In protocol on controller handle and virtual handle.
 | |
|   //
 | |
|   Status = ConSplitterStop (
 | |
|             This,
 | |
|             ControllerHandle,
 | |
|             mConIn.VirtualHandle,
 | |
|             &gEfiConsoleInDeviceGuid,
 | |
|             &gEfiSimpleTextInProtocolGuid,
 | |
|             (VOID **) &TextIn
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Remove device from Text Input devices list.
 | |
|   //
 | |
|   return ConSplitterTextInDeleteDevice (&mConIn, TextIn);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Stop Simple Pointer protocol ConSplitter on ControllerHandle by closing
 | |
|   Simple Pointer protocol.
 | |
| 
 | |
|   @param  This              Driver Binding protocol instance pointer.
 | |
|   @param  ControllerHandle  Handle of device to stop driver on
 | |
|   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
 | |
|                             children is zero stop the entire bus driver.
 | |
|   @param  ChildHandleBuffer List of Child Handles to Stop.
 | |
| 
 | |
|   @retval EFI_SUCCESS       This driver is removed ControllerHandle
 | |
|   @retval other             This driver was not removed from this device
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterSimplePointerDriverBindingStop (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  UINTN                           NumberOfChildren,
 | |
|   IN  EFI_HANDLE                      *ChildHandleBuffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer;
 | |
| 
 | |
|   if (NumberOfChildren == 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Close Simple Pointer protocol on controller handle and virtual handle.
 | |
|   //
 | |
|   Status = ConSplitterStop (
 | |
|             This,
 | |
|             ControllerHandle,
 | |
|             mConIn.VirtualHandle,
 | |
|             &gEfiSimplePointerProtocolGuid,
 | |
|             &gEfiSimplePointerProtocolGuid,
 | |
|             (VOID **) &SimplePointer
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Remove this device from Simple Pointer device list.
 | |
|   //
 | |
|   return ConSplitterSimplePointerDeleteDevice (&mConIn, SimplePointer);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Stop Absolute Pointer protocol ConSplitter on ControllerHandle by closing
 | |
|   Absolute Pointer protocol.
 | |
| 
 | |
|   @param  This              Driver Binding protocol instance pointer.
 | |
|   @param  ControllerHandle  Handle of device to stop driver on
 | |
|   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
 | |
|                             children is zero stop the entire bus driver.
 | |
|   @param  ChildHandleBuffer List of Child Handles to Stop.
 | |
| 
 | |
|   @retval EFI_SUCCESS       This driver is removed ControllerHandle
 | |
|   @retval other             This driver was not removed from this device
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterAbsolutePointerDriverBindingStop (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  UINTN                           NumberOfChildren,
 | |
|   IN  EFI_HANDLE                      *ChildHandleBuffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   EFI_ABSOLUTE_POINTER_PROTOCOL     *AbsolutePointer;
 | |
| 
 | |
|   if (NumberOfChildren == 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Close Absolute Pointer protocol on controller handle and virtual handle.
 | |
|   //
 | |
|   Status = ConSplitterStop (
 | |
|              This,
 | |
|              ControllerHandle,
 | |
|              mConIn.VirtualHandle,
 | |
|              &gEfiAbsolutePointerProtocolGuid,
 | |
|              &gEfiAbsolutePointerProtocolGuid,
 | |
|              (VOID **) &AbsolutePointer
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Remove this device from Absolute Pointer device list.
 | |
|   //
 | |
|   return ConSplitterAbsolutePointerDeleteDevice (&mConIn, AbsolutePointer);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Stop Console Out ConSplitter on device handle by closing Console Out Devcice GUID.
 | |
| 
 | |
|   @param  This              Driver Binding protocol instance pointer.
 | |
|   @param  ControllerHandle  Handle of device to stop driver on
 | |
|   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
 | |
|                             children is zero stop the entire bus driver.
 | |
|   @param  ChildHandleBuffer List of Child Handles to Stop.
 | |
| 
 | |
|   @retval EFI_SUCCESS       This driver is removed ControllerHandle
 | |
|   @retval other             This driver was not removed from this device
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterConOutDriverBindingStop (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  UINTN                           NumberOfChildren,
 | |
|   IN  EFI_HANDLE                      *ChildHandleBuffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                       Status;
 | |
|   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;
 | |
| 
 | |
|   if (NumberOfChildren == 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Close Absolute Pointer protocol on controller handle and virtual handle.
 | |
|   //
 | |
|   Status = ConSplitterStop (
 | |
|             This,
 | |
|             ControllerHandle,
 | |
|             mConOut.VirtualHandle,
 | |
|             &gEfiConsoleOutDeviceGuid,
 | |
|             &gEfiSimpleTextOutProtocolGuid,
 | |
|             (VOID **) &TextOut
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Remove this device from Text Out device list.
 | |
|   //
 | |
|   return ConSplitterTextOutDeleteDevice (&mConOut, TextOut);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Stop Standard Error ConSplitter on ControllerHandle by closing Standard Error GUID.
 | |
| 
 | |
|   @param  This              Driver Binding protocol instance pointer.
 | |
|   @param  ControllerHandle  Handle of device to stop driver on
 | |
|   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
 | |
|                             children is zero stop the entire bus driver.
 | |
|   @param  ChildHandleBuffer List of Child Handles to Stop.
 | |
| 
 | |
|   @retval EFI_SUCCESS       This driver is removed ControllerHandle
 | |
|   @retval other             This driver was not removed from this device
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterStdErrDriverBindingStop (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      ControllerHandle,
 | |
|   IN  UINTN                           NumberOfChildren,
 | |
|   IN  EFI_HANDLE                      *ChildHandleBuffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                       Status;
 | |
|   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;
 | |
| 
 | |
|   if (NumberOfChildren == 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Close Standard Error Device on controller handle and virtual handle.
 | |
|   //
 | |
|   Status = ConSplitterStop (
 | |
|             This,
 | |
|             ControllerHandle,
 | |
|             mStdErr.VirtualHandle,
 | |
|             &gEfiStandardErrorDeviceGuid,
 | |
|             &gEfiSimpleTextOutProtocolGuid,
 | |
|             (VOID **) &TextOut
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Delete this console error out device's data structures.
 | |
|   //
 | |
|   return ConSplitterTextOutDeleteDevice (&mStdErr, TextOut);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Take the passed in Buffer of size ElementSize and grow the buffer
 | |
|   by CONSOLE_SPLITTER_ALLOC_UNIT * ElementSize bytes.
 | |
|   Copy the current data in Buffer to the new version of Buffer and
 | |
|   free the old version of buffer.
 | |
| 
 | |
|   @param  ElementSize              Size of element in array.
 | |
|   @param  Count                    Current number of elements in array.
 | |
|   @param  Buffer                   Bigger version of passed in Buffer with all the
 | |
|                                    data.
 | |
| 
 | |
|   @retval EFI_SUCCESS              Buffer size has grown.
 | |
|   @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterGrowBuffer (
 | |
|   IN      UINTN                       ElementSize,
 | |
|   IN OUT  UINTN                       *Count,
 | |
|   IN OUT  VOID                        **Buffer
 | |
|   )
 | |
| {
 | |
|   VOID  *Ptr;
 | |
| 
 | |
|   //
 | |
|   // grow the buffer to new buffer size,
 | |
|   // copy the old buffer's content to the new-size buffer,
 | |
|   // then free the old buffer.
 | |
|   //
 | |
|   Ptr = ReallocatePool (
 | |
|           ElementSize * (*Count),
 | |
|           ElementSize * ((*Count) + CONSOLE_SPLITTER_ALLOC_UNIT),
 | |
|           *Buffer
 | |
|           );
 | |
|   if (Ptr == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   *Count += CONSOLE_SPLITTER_ALLOC_UNIT;
 | |
|   *Buffer = Ptr;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Add Text Input Device in Consplitter Text Input list.
 | |
| 
 | |
|   @param  Private                  Text In Splitter pointer.
 | |
|   @param  TextIn                   Simple Text Input protocol pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS              Text Input Device added successfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterTextInAddDevice (
 | |
|   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,
 | |
|   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *TextIn
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   //
 | |
|   // If the Text In List is full, enlarge it by calling ConSplitterGrowBuffer().
 | |
|   //
 | |
|   if (Private->CurrentNumberOfConsoles >= Private->TextInListCount) {
 | |
|     Status = ConSplitterGrowBuffer (
 | |
|               sizeof (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *),
 | |
|               &Private->TextInListCount,
 | |
|               (VOID **) &Private->TextInList
 | |
|               );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Add the new text-in device data structure into the Text In List.
 | |
|   //
 | |
|   Private->TextInList[Private->CurrentNumberOfConsoles] = TextIn;
 | |
|   Private->CurrentNumberOfConsoles++;
 | |
| 
 | |
|   //
 | |
|   // Extra CheckEvent added to reduce the double CheckEvent().
 | |
|   //
 | |
|   gBS->CheckEvent (TextIn->WaitForKey);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Remove Text Input Device from Consplitter Text Input list.
 | |
| 
 | |
|   @param  Private                  Text In Splitter pointer.
 | |
|   @param  TextIn                   Simple Text protocol pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS              Simple Text Device removed successfully.
 | |
|   @retval EFI_NOT_FOUND            No Simple Text Device found.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterTextInDeleteDevice (
 | |
|   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,
 | |
|   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *TextIn
 | |
|   )
 | |
| {
 | |
|   UINTN Index;
 | |
|   //
 | |
|   // Remove the specified text-in device data structure from the Text In List,
 | |
|   // and rearrange the remaining data structures in the Text In List.
 | |
|   //
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
 | |
|     if (Private->TextInList[Index] == TextIn) {
 | |
|       for (; Index < Private->CurrentNumberOfConsoles - 1; Index++) {
 | |
|         Private->TextInList[Index] = Private->TextInList[Index + 1];
 | |
|       }
 | |
| 
 | |
|       Private->CurrentNumberOfConsoles--;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Add Text Input Ex Device in Consplitter Text Input Ex list.
 | |
| 
 | |
|   @param  Private                  Text In Splitter pointer.
 | |
|   @param  TextInEx                 Simple Text Input Ex Input protocol pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS              Text Input Ex Device added successfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterTextInExAddDevice (
 | |
|   IN  TEXT_IN_SPLITTER_PRIVATE_DATA         *Private,
 | |
|   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL     *TextInEx
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   LIST_ENTRY                  *Link;
 | |
|   TEXT_IN_EX_SPLITTER_NOTIFY  *CurrentNotify;
 | |
|   UINTN                       TextInExListCount;
 | |
| 
 | |
|   //
 | |
|   // Enlarge the NotifyHandleList and the TextInExList
 | |
|   //
 | |
|   if (Private->CurrentNumberOfExConsoles >= Private->TextInExListCount) {
 | |
|     for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
 | |
|       CurrentNotify     = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);
 | |
|       TextInExListCount = Private->TextInExListCount;
 | |
| 
 | |
|       Status = ConSplitterGrowBuffer (
 | |
|                  sizeof (EFI_HANDLE),
 | |
|                  &TextInExListCount,
 | |
|                  (VOID **) &CurrentNotify->NotifyHandleList
 | |
|                  );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     TextInExListCount = Private->TextInExListCount;
 | |
|     Status = ConSplitterGrowBuffer (
 | |
|                sizeof (EFI_KEY_DATA),
 | |
|                &TextInExListCount,
 | |
|                (VOID **) &Private->KeyQueue
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     Status = ConSplitterGrowBuffer (
 | |
|               sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *),
 | |
|               &Private->TextInExListCount,
 | |
|               (VOID **) &Private->TextInExList
 | |
|               );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Register the key notify in the new text-in device
 | |
|   //
 | |
|   for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
 | |
|     CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);
 | |
|     Status = TextInEx->RegisterKeyNotify (
 | |
|                          TextInEx,
 | |
|                          &CurrentNotify->KeyData,
 | |
|                          CurrentNotify->KeyNotificationFn,
 | |
|                          &CurrentNotify->NotifyHandleList[Private->CurrentNumberOfExConsoles]
 | |
|                          );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       for (Link = Link->BackLink; Link != &Private->NotifyList; Link = Link->BackLink) {
 | |
|         CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);
 | |
|         TextInEx->UnregisterKeyNotify (
 | |
|                     TextInEx,
 | |
|                     CurrentNotify->NotifyHandleList[Private->CurrentNumberOfExConsoles]
 | |
|                     );
 | |
|       }
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Add the new text-in device data structure into the Text Input Ex List.
 | |
|   //
 | |
|   Private->TextInExList[Private->CurrentNumberOfExConsoles] = TextInEx;
 | |
|   Private->CurrentNumberOfExConsoles++;
 | |
| 
 | |
|   //
 | |
|   // Sync current toggle state to this new console input device.
 | |
|   //
 | |
|   TextInEx->SetState (TextInEx, &Private->PhysicalKeyToggleState);
 | |
| 
 | |
|   //
 | |
|   // Extra CheckEvent added to reduce the double CheckEvent().
 | |
|   //
 | |
|   gBS->CheckEvent (TextInEx->WaitForKeyEx);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Remove Text Ex Device from Consplitter Text Input Ex list.
 | |
| 
 | |
|   @param  Private                  Text In Splitter pointer.
 | |
|   @param  TextInEx                 Simple Text Ex protocol pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS              Simple Text Input Ex Device removed successfully.
 | |
|   @retval EFI_NOT_FOUND            No Simple Text Input Ex Device found.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterTextInExDeleteDevice (
 | |
|   IN  TEXT_IN_SPLITTER_PRIVATE_DATA         *Private,
 | |
|   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL     *TextInEx
 | |
|   )
 | |
| {
 | |
|   UINTN Index;
 | |
|   //
 | |
|   // Remove the specified text-in device data structure from the Text Input Ex List,
 | |
|   // and rearrange the remaining data structures in the Text In List.
 | |
|   //
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
 | |
|     if (Private->TextInExList[Index] == TextInEx) {
 | |
|       for (; Index < Private->CurrentNumberOfExConsoles - 1; Index++) {
 | |
|         Private->TextInExList[Index] = Private->TextInExList[Index + 1];
 | |
|       }
 | |
| 
 | |
|       Private->CurrentNumberOfExConsoles--;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Add Simple Pointer Device in Consplitter Simple Pointer list.
 | |
| 
 | |
|   @param  Private                  Text In Splitter pointer.
 | |
|   @param  SimplePointer            Simple Pointer protocol pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS              Simple Pointer Device added successfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterSimplePointerAddDevice (
 | |
|   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,
 | |
|   IN  EFI_SIMPLE_POINTER_PROTOCOL     *SimplePointer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   //
 | |
|   // If the Simple Pointer List is full, enlarge it by calling ConSplitterGrowBuffer().
 | |
|   //
 | |
|   if (Private->CurrentNumberOfPointers >= Private->PointerListCount) {
 | |
|     Status = ConSplitterGrowBuffer (
 | |
|               sizeof (EFI_SIMPLE_POINTER_PROTOCOL *),
 | |
|               &Private->PointerListCount,
 | |
|               (VOID **) &Private->PointerList
 | |
|               );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Add the new text-in device data structure into the Simple Pointer List.
 | |
|   //
 | |
|   Private->PointerList[Private->CurrentNumberOfPointers] = SimplePointer;
 | |
|   Private->CurrentNumberOfPointers++;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Remove Simple Pointer Device from Consplitter Simple Pointer list.
 | |
| 
 | |
|   @param  Private                  Text In Splitter pointer.
 | |
|   @param  SimplePointer            Simple Pointer protocol pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS              Simple Pointer Device removed successfully.
 | |
|   @retval EFI_NOT_FOUND            No Simple Pointer Device found.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterSimplePointerDeleteDevice (
 | |
|   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,
 | |
|   IN  EFI_SIMPLE_POINTER_PROTOCOL     *SimplePointer
 | |
|   )
 | |
| {
 | |
|   UINTN Index;
 | |
|   //
 | |
|   // Remove the specified text-in device data structure from the Simple Pointer List,
 | |
|   // and rearrange the remaining data structures in the Text In List.
 | |
|   //
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) {
 | |
|     if (Private->PointerList[Index] == SimplePointer) {
 | |
|       for (; Index < Private->CurrentNumberOfPointers - 1; Index++) {
 | |
|         Private->PointerList[Index] = Private->PointerList[Index + 1];
 | |
|       }
 | |
| 
 | |
|       Private->CurrentNumberOfPointers--;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Add Absolute Pointer Device in Consplitter Absolute Pointer list.
 | |
| 
 | |
|   @param  Private                  Text In Splitter pointer.
 | |
|   @param  AbsolutePointer          Absolute Pointer protocol pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS              Absolute Pointer Device added successfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterAbsolutePointerAddDevice (
 | |
|   IN  TEXT_IN_SPLITTER_PRIVATE_DATA     *Private,
 | |
|   IN  EFI_ABSOLUTE_POINTER_PROTOCOL     *AbsolutePointer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   //
 | |
|   // If the Absolute Pointer List is full, enlarge it by calling ConSplitterGrowBuffer().
 | |
|   //
 | |
|   if (Private->CurrentNumberOfAbsolutePointers >= Private->AbsolutePointerListCount) {
 | |
|     Status = ConSplitterGrowBuffer (
 | |
|               sizeof (EFI_ABSOLUTE_POINTER_PROTOCOL *),
 | |
|               &Private->AbsolutePointerListCount,
 | |
|               (VOID **) &Private->AbsolutePointerList
 | |
|               );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Add the new text-in device data structure into the Absolute Pointer List.
 | |
|   //
 | |
|   Private->AbsolutePointerList[Private->CurrentNumberOfAbsolutePointers] = AbsolutePointer;
 | |
|   Private->CurrentNumberOfAbsolutePointers++;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Remove Absolute Pointer Device from Consplitter Absolute Pointer list.
 | |
| 
 | |
|   @param  Private                  Text In Splitter pointer.
 | |
|   @param  AbsolutePointer          Absolute Pointer protocol pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS              Absolute Pointer Device removed successfully.
 | |
|   @retval EFI_NOT_FOUND            No Absolute Pointer Device found.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterAbsolutePointerDeleteDevice (
 | |
|   IN  TEXT_IN_SPLITTER_PRIVATE_DATA     *Private,
 | |
|   IN  EFI_ABSOLUTE_POINTER_PROTOCOL     *AbsolutePointer
 | |
|   )
 | |
| {
 | |
|   UINTN Index;
 | |
|   //
 | |
|   // Remove the specified text-in device data structure from the Absolute Pointer List,
 | |
|   // and rearrange the remaining data structures from the Absolute Pointer List.
 | |
|   //
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {
 | |
|     if (Private->AbsolutePointerList[Index] == AbsolutePointer) {
 | |
|       for (; Index < Private->CurrentNumberOfAbsolutePointers - 1; Index++) {
 | |
|         Private->AbsolutePointerList[Index] = Private->AbsolutePointerList[Index + 1];
 | |
|       }
 | |
| 
 | |
|       Private->CurrentNumberOfAbsolutePointers--;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reallocate Text Out mode map.
 | |
| 
 | |
|   Allocate new buffer and copy original buffer into the new buffer.
 | |
| 
 | |
|   @param  Private                  Consplitter Text Out pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS              Buffer size has grown
 | |
|   @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterGrowMapTable (
 | |
|   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private
 | |
|   )
 | |
| {
 | |
|   UINTN Size;
 | |
|   UINTN NewSize;
 | |
|   UINTN TotalSize;
 | |
|   INT32 *TextOutModeMap;
 | |
|   INT32 *OldTextOutModeMap;
 | |
|   INT32 *SrcAddress;
 | |
|   INT32 Index;
 | |
|   UINTN OldStepSize;
 | |
|   UINTN NewStepSize;
 | |
| 
 | |
|   NewSize           = Private->TextOutListCount * sizeof (INT32);
 | |
|   OldTextOutModeMap = Private->TextOutModeMap;
 | |
|   TotalSize         = NewSize * (Private->TextOutQueryDataCount);
 | |
| 
 | |
|   //
 | |
|   // Allocate new buffer for Text Out List.
 | |
|   //
 | |
|   TextOutModeMap    = AllocatePool (TotalSize);
 | |
|   if (TextOutModeMap == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   SetMem (TextOutModeMap, TotalSize, 0xFF);
 | |
|   Private->TextOutModeMap = TextOutModeMap;
 | |
| 
 | |
|   //
 | |
|   // If TextOutList has been enlarged, need to realloc the mode map table
 | |
|   // The mode map table is regarded as a two dimension array.
 | |
|   //
 | |
|   //                         Old                    New
 | |
|   //  0   ---------> TextOutListCount ----> TextOutListCount
 | |
|   //  |   -------------------------------------------
 | |
|   //  |  |                    |                      |
 | |
|   //  |  |                    |                      |
 | |
|   //  |  |                    |                      |
 | |
|   //  |  |                    |                      |
 | |
|   //  |  |                    |                      |
 | |
|   // \/  |                    |                      |
 | |
|   //      -------------------------------------------
 | |
|   // QueryDataCount
 | |
|   //
 | |
|   if (OldTextOutModeMap != NULL) {
 | |
| 
 | |
|     Size        = Private->CurrentNumberOfConsoles * sizeof (INT32);
 | |
|     Index       = 0;
 | |
|     SrcAddress  = OldTextOutModeMap;
 | |
|     NewStepSize = NewSize / sizeof(INT32);
 | |
|     // If Private->CurrentNumberOfConsoles is not zero and OldTextOutModeMap
 | |
|     // is not NULL, it indicates that the original TextOutModeMap is not enough
 | |
|     // for the new console devices and has been enlarged by CONSOLE_SPLITTER_ALLOC_UNIT columns.
 | |
|     //
 | |
|     OldStepSize = NewStepSize - CONSOLE_SPLITTER_ALLOC_UNIT;
 | |
| 
 | |
|     //
 | |
|     // Copy the old data to the new one
 | |
|     //
 | |
|     while (Index < Private->TextOutMode.MaxMode) {
 | |
|       CopyMem (TextOutModeMap, SrcAddress, Size);
 | |
|       //
 | |
|       // Go to next row of new TextOutModeMap.
 | |
|       //
 | |
|       TextOutModeMap += NewStepSize;
 | |
|       //
 | |
|       // Go to next row of old TextOutModeMap.
 | |
|       //
 | |
|       SrcAddress += OldStepSize;
 | |
|       Index++;
 | |
|     }
 | |
|     //
 | |
|     // Free the old buffer
 | |
|     //
 | |
|     FreePool (OldTextOutModeMap);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Add new device's output mode to console splitter's mode list.
 | |
| 
 | |
|   @param  Private               Text Out Splitter pointer
 | |
|   @param  TextOut               Simple Text Output protocol pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS           Device added successfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Could not grow the buffer size.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterAddOutputMode (
 | |
|   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA     *Private,
 | |
|   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *TextOut
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   INT32       MaxMode;
 | |
|   INT32       Mode;
 | |
|   UINTN       Index;
 | |
| 
 | |
|   MaxMode                       = TextOut->Mode->MaxMode;
 | |
|   Private->TextOutMode.MaxMode  = MaxMode;
 | |
| 
 | |
|   //
 | |
|   // Grow the buffer if query data buffer is not large enough to
 | |
|   // hold all the mode supported by the first console.
 | |
|   //
 | |
|   while (MaxMode > (INT32) Private->TextOutQueryDataCount) {
 | |
|     Status = ConSplitterGrowBuffer (
 | |
|               sizeof (TEXT_OUT_SPLITTER_QUERY_DATA),
 | |
|               &Private->TextOutQueryDataCount,
 | |
|               (VOID **) &Private->TextOutQueryData
 | |
|               );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Allocate buffer for the output mode map
 | |
|   //
 | |
|   Status = ConSplitterGrowMapTable (Private);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   //
 | |
|   // As the first textout device, directly add the mode in to QueryData
 | |
|   // and at the same time record the mapping between QueryData and TextOut.
 | |
|   //
 | |
|   Mode  = 0;
 | |
|   Index = 0;
 | |
|   while (Mode < MaxMode) {
 | |
|     Status = TextOut->QueryMode (
 | |
|                   TextOut,
 | |
|                   Mode,
 | |
|                   &Private->TextOutQueryData[Mode].Columns,
 | |
|                   &Private->TextOutQueryData[Mode].Rows
 | |
|                   );
 | |
|     //
 | |
|     // If mode 1 (80x50) is not supported, make sure mode 1 in TextOutQueryData
 | |
|     // is clear to 0x0.
 | |
|     //
 | |
|     if ((EFI_ERROR(Status)) && (Mode == 1)) {
 | |
|       Private->TextOutQueryData[Mode].Columns = 0;
 | |
|       Private->TextOutQueryData[Mode].Rows = 0;
 | |
|     }
 | |
|     Private->TextOutModeMap[Index] = Mode;
 | |
|     Mode++;
 | |
|     Index += Private->TextOutListCount;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reconstruct TextOutModeMap to get intersection of modes.
 | |
| 
 | |
|   This routine reconstruct TextOutModeMap to get the intersection
 | |
|   of modes for all console out devices. Because EFI/UEFI spec require
 | |
|   mode 0 is 80x25, mode 1 is 80x50, this routine will not check the
 | |
|   intersection for mode 0 and mode 1.
 | |
| 
 | |
|   @param TextOutModeMap  Current text out mode map, begin with the mode 80x25
 | |
|   @param NewlyAddedMap   New text out mode map, begin with the mode 80x25
 | |
|   @param MapStepSize     Mode step size for one console device
 | |
|   @param NewMapStepSize  New Mode step size for one console device
 | |
|   @param MaxMode         IN: Current max text mode, OUT: Updated max text mode.
 | |
|   @param CurrentMode     IN: Current text mode,     OUT: Updated current text mode.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| ConSplitterGetIntersection (
 | |
|   IN     INT32                        *TextOutModeMap,
 | |
|   IN     INT32                        *NewlyAddedMap,
 | |
|   IN     UINTN                        MapStepSize,
 | |
|   IN     UINTN                        NewMapStepSize,
 | |
|   IN OUT INT32                        *MaxMode,
 | |
|   IN OUT INT32                        *CurrentMode
 | |
|   )
 | |
| {
 | |
|   INT32 Index;
 | |
|   INT32 *CurrentMapEntry;
 | |
|   INT32 *NextMapEntry;
 | |
|   INT32 *NewMapEntry;
 | |
|   INT32 CurrentMaxMode;
 | |
|   INT32 Mode;
 | |
| 
 | |
|   //
 | |
|   // According to EFI/UEFI spec, mode 0 and mode 1 have been reserved
 | |
|   // for 80x25 and 80x50 in Simple Text Out protocol, so don't make intersection
 | |
|   // for mode 0 and mode 1, mode number starts from 2.
 | |
|   //
 | |
|   Index           = 2;
 | |
|   CurrentMapEntry = &TextOutModeMap[MapStepSize * 2];
 | |
|   NextMapEntry    = CurrentMapEntry;
 | |
|   NewMapEntry     = &NewlyAddedMap[NewMapStepSize * 2];
 | |
| 
 | |
|   CurrentMaxMode  = *MaxMode;
 | |
|   Mode            = *CurrentMode;
 | |
| 
 | |
|   while (Index < CurrentMaxMode) {
 | |
|     if (*NewMapEntry == -1) {
 | |
|       //
 | |
|       // This mode is not supported any more. Remove it. Special care
 | |
|       // must be taken as this remove will also affect current mode;
 | |
|       //
 | |
|       if (Index == *CurrentMode) {
 | |
|         Mode = -1;
 | |
|       } else if (Index < *CurrentMode) {
 | |
|         Mode--;
 | |
|       }
 | |
|       (*MaxMode)--;
 | |
|     } else {
 | |
|       if (CurrentMapEntry != NextMapEntry) {
 | |
|         CopyMem (NextMapEntry, CurrentMapEntry, MapStepSize * sizeof (INT32));
 | |
|       }
 | |
| 
 | |
|       NextMapEntry += MapStepSize;
 | |
|     }
 | |
| 
 | |
|     CurrentMapEntry += MapStepSize;
 | |
|     NewMapEntry     += NewMapStepSize;
 | |
|     Index++;
 | |
|   }
 | |
| 
 | |
|   *CurrentMode = Mode;
 | |
| 
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Sync the device's output mode to console splitter's mode list.
 | |
| 
 | |
|   @param  Private               Text Out Splitter pointer.
 | |
|   @param  TextOut               Simple Text Output protocol pointer.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| ConSplitterSyncOutputMode (
 | |
|   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA     *Private,
 | |
|   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *TextOut
 | |
|   )
 | |
| {
 | |
|   INT32                         CurrentMaxMode;
 | |
|   INT32                         Mode;
 | |
|   INT32                         Index;
 | |
|   INT32                         *TextOutModeMap;
 | |
|   INT32                         *MapTable;
 | |
|   INT32                         QueryMode;
 | |
|   TEXT_OUT_SPLITTER_QUERY_DATA  *TextOutQueryData;
 | |
|   UINTN                         Rows;
 | |
|   UINTN                         Columns;
 | |
|   UINTN                         StepSize;
 | |
|   EFI_STATUS                    Status;
 | |
| 
 | |
|   //
 | |
|   // Must make sure that current mode won't change even if mode number changes
 | |
|   //
 | |
|   CurrentMaxMode    = Private->TextOutMode.MaxMode;
 | |
|   TextOutModeMap    = Private->TextOutModeMap;
 | |
|   StepSize          = Private->TextOutListCount;
 | |
|   TextOutQueryData  = Private->TextOutQueryData;
 | |
| 
 | |
|   //
 | |
|   // Query all the mode that the newly added TextOut supports
 | |
|   //
 | |
|   Mode      = 0;
 | |
|   MapTable  = TextOutModeMap + Private->CurrentNumberOfConsoles;
 | |
|   while (Mode < TextOut->Mode->MaxMode) {
 | |
|     Status = TextOut->QueryMode (TextOut, Mode, &Columns, &Rows);
 | |
| 
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       if (Mode == 1) {
 | |
|         //
 | |
|         // If mode 1 (80x50) is not supported, make sure mode 1 in TextOutQueryData
 | |
|         // is clear to 0x0.
 | |
|         //
 | |
|         MapTable[StepSize] = Mode;
 | |
|         TextOutQueryData[Mode].Columns = 0;
 | |
|         TextOutQueryData[Mode].Rows = 0;
 | |
|       }
 | |
|       Mode++;
 | |
|       continue;
 | |
|     }
 | |
|     //
 | |
|     // Search the intersection map and QueryData database to see if they intersects
 | |
|     //
 | |
|     Index = 0;
 | |
|     while (Index < CurrentMaxMode) {
 | |
|       QueryMode = *(TextOutModeMap + Index * StepSize);
 | |
|       if ((TextOutQueryData[QueryMode].Rows == Rows) && (TextOutQueryData[QueryMode].Columns == Columns)) {
 | |
|         MapTable[Index * StepSize] = Mode;
 | |
|         break;
 | |
|       }
 | |
|       Index++;
 | |
|     }
 | |
|     Mode++;
 | |
|   }
 | |
|   //
 | |
|   // Now search the TextOutModeMap table to find the intersection of supported
 | |
|   // mode between ConSplitter and the newly added device.
 | |
|   //
 | |
|   ConSplitterGetIntersection (
 | |
|     TextOutModeMap,
 | |
|     MapTable,
 | |
|     StepSize,
 | |
|     StepSize,
 | |
|     &Private->TextOutMode.MaxMode,
 | |
|     &Private->TextOutMode.Mode
 | |
|     );
 | |
| 
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Sync output device between ConOut and StdErr output.
 | |
| 
 | |
|   @retval EFI_SUCCESS              Sync implemented successfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterGetIntersectionBetweenConOutAndStrErr (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINTN                         ConOutNumOfConsoles;
 | |
|   UINTN                         StdErrNumOfConsoles;
 | |
|   TEXT_OUT_AND_GOP_DATA         *ConOutTextOutList;
 | |
|   TEXT_OUT_AND_GOP_DATA         *StdErrTextOutList;
 | |
|   UINTN                         Indexi;
 | |
|   UINTN                         Indexj;
 | |
|   UINTN                         ConOutRows;
 | |
|   UINTN                         ConOutColumns;
 | |
|   UINTN                         StdErrRows;
 | |
|   UINTN                         StdErrColumns;
 | |
|   INT32                         ConOutMaxMode;
 | |
|   INT32                         StdErrMaxMode;
 | |
|   INT32                         ConOutMode;
 | |
|   INT32                         StdErrMode;
 | |
|   INT32                         Mode;
 | |
|   INT32                         Index;
 | |
|   INT32                         *ConOutModeMap;
 | |
|   INT32                         *StdErrModeMap;
 | |
|   INT32                         *ConOutMapTable;
 | |
|   INT32                         *StdErrMapTable;
 | |
|   TEXT_OUT_SPLITTER_QUERY_DATA  *ConOutQueryData;
 | |
|   TEXT_OUT_SPLITTER_QUERY_DATA  *StdErrQueryData;
 | |
|   UINTN                         ConOutStepSize;
 | |
|   UINTN                         StdErrStepSize;
 | |
|   BOOLEAN                       FoundTheSameTextOut;
 | |
|   UINTN                         ConOutMapTableSize;
 | |
|   UINTN                         StdErrMapTableSize;
 | |
| 
 | |
|   ConOutNumOfConsoles = mConOut.CurrentNumberOfConsoles;
 | |
|   StdErrNumOfConsoles = mStdErr.CurrentNumberOfConsoles;
 | |
|   ConOutTextOutList   = mConOut.TextOutList;
 | |
|   StdErrTextOutList   = mStdErr.TextOutList;
 | |
| 
 | |
|   Indexi              = 0;
 | |
|   FoundTheSameTextOut = FALSE;
 | |
|   while ((Indexi < ConOutNumOfConsoles) && (!FoundTheSameTextOut)) {
 | |
|     Indexj = 0;
 | |
|     while (Indexj < StdErrNumOfConsoles) {
 | |
|       if (ConOutTextOutList->TextOut == StdErrTextOutList->TextOut) {
 | |
|         FoundTheSameTextOut = TRUE;
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       Indexj++;
 | |
|       StdErrTextOutList++;
 | |
|     }
 | |
| 
 | |
|     Indexi++;
 | |
|     ConOutTextOutList++;
 | |
|   }
 | |
| 
 | |
|   if (!FoundTheSameTextOut) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
|   //
 | |
|   // Must make sure that current mode won't change even if mode number changes
 | |
|   //
 | |
|   ConOutMaxMode     = mConOut.TextOutMode.MaxMode;
 | |
|   ConOutModeMap     = mConOut.TextOutModeMap;
 | |
|   ConOutStepSize    = mConOut.TextOutListCount;
 | |
|   ConOutQueryData   = mConOut.TextOutQueryData;
 | |
| 
 | |
|   StdErrMaxMode     = mStdErr.TextOutMode.MaxMode;
 | |
|   StdErrModeMap     = mStdErr.TextOutModeMap;
 | |
|   StdErrStepSize    = mStdErr.TextOutListCount;
 | |
|   StdErrQueryData   = mStdErr.TextOutQueryData;
 | |
| 
 | |
|   //
 | |
|   // Allocate the map table and set the map table's index to -1.
 | |
|   //
 | |
|   ConOutMapTableSize  = ConOutMaxMode * sizeof (INT32);
 | |
|   ConOutMapTable      = AllocateZeroPool (ConOutMapTableSize);
 | |
|   if (ConOutMapTable == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   SetMem (ConOutMapTable, ConOutMapTableSize, 0xFF);
 | |
| 
 | |
|   StdErrMapTableSize  = StdErrMaxMode * sizeof (INT32);
 | |
|   StdErrMapTable      = AllocateZeroPool (StdErrMapTableSize);
 | |
|   if (StdErrMapTable == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   SetMem (StdErrMapTable, StdErrMapTableSize, 0xFF);
 | |
| 
 | |
|   //
 | |
|   // Find the intersection of the two set of modes. If they actually intersect, the
 | |
|   // corresponding entry in the map table is set to 1.
 | |
|   //
 | |
|   Mode = 0;
 | |
|   while (Mode < ConOutMaxMode) {
 | |
|     //
 | |
|     // Search the intersection map and QueryData database to see if they intersect
 | |
|     //
 | |
|     Index = 0;
 | |
|     ConOutMode    = *(ConOutModeMap + Mode * ConOutStepSize);
 | |
|     ConOutRows    = ConOutQueryData[ConOutMode].Rows;
 | |
|     ConOutColumns = ConOutQueryData[ConOutMode].Columns;
 | |
|     while (Index < StdErrMaxMode) {
 | |
|       StdErrMode    = *(StdErrModeMap + Index * StdErrStepSize);
 | |
|       StdErrRows    = StdErrQueryData[StdErrMode].Rows;
 | |
|       StdErrColumns = StdErrQueryData[StdErrMode].Columns;
 | |
|       if ((StdErrRows == ConOutRows) && (StdErrColumns == ConOutColumns)) {
 | |
|         ConOutMapTable[Mode]  = 1;
 | |
|         StdErrMapTable[Index] = 1;
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       Index++;
 | |
|     }
 | |
| 
 | |
|     Mode++;
 | |
|   }
 | |
|   //
 | |
|   // Now search the TextOutModeMap table to find the intersection of supported
 | |
|   // mode between ConSplitter and the newly added device.
 | |
|   //
 | |
|   ConSplitterGetIntersection (
 | |
|     ConOutModeMap,
 | |
|     ConOutMapTable,
 | |
|     mConOut.TextOutListCount,
 | |
|     1,
 | |
|     &(mConOut.TextOutMode.MaxMode),
 | |
|     &(mConOut.TextOutMode.Mode)
 | |
|     );
 | |
| 
 | |
|   if (mConOut.TextOutMode.Mode < 0) {
 | |
|     mConOut.TextOut.SetMode (&(mConOut.TextOut), 0);
 | |
|   }
 | |
| 
 | |
|   ConSplitterGetIntersection (
 | |
|     StdErrModeMap,
 | |
|     StdErrMapTable,
 | |
|     mStdErr.TextOutListCount,
 | |
|     1,
 | |
|     &(mStdErr.TextOutMode.MaxMode),
 | |
|     &(mStdErr.TextOutMode.Mode)
 | |
|     );
 | |
| 
 | |
|   if (mStdErr.TextOutMode.Mode < 0) {
 | |
|     mStdErr.TextOut.SetMode (&(mStdErr.TextOut), 0);
 | |
|   }
 | |
| 
 | |
|   FreePool (ConOutMapTable);
 | |
|   FreePool (StdErrMapTable);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Add Grahpics Output modes into Consplitter Text Out list.
 | |
| 
 | |
|   @param  Private               Text Out Splitter pointer.
 | |
|   @param  GraphicsOutput        Graphics Output protocol pointer.
 | |
|   @param  UgaDraw               UGA Draw protocol pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS           Output mode added successfully.
 | |
|   @retval other                 Failed to add output mode.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterAddGraphicsOutputMode (
 | |
|   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,
 | |
|   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL    *GraphicsOutput,
 | |
|   IN  EFI_UGA_DRAW_PROTOCOL           *UgaDraw
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                           Status;
 | |
|   UINTN                                Index;
 | |
|   UINTN                                CurrentIndex;
 | |
|   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Mode;
 | |
|   UINTN                                SizeOfInfo;
 | |
|   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
 | |
|   EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE    *CurrentGraphicsOutputMode;
 | |
|   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeBuffer;
 | |
|   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *MatchedMode;
 | |
|   UINTN                                NumberIndex;
 | |
|   BOOLEAN                              Match;
 | |
|   BOOLEAN                              AlreadyExist;
 | |
|   UINT32                               UgaHorizontalResolution;
 | |
|   UINT32                               UgaVerticalResolution;
 | |
|   UINT32                               UgaColorDepth;
 | |
|   UINT32                               UgaRefreshRate;
 | |
| 
 | |
|   ASSERT (GraphicsOutput != NULL || UgaDraw != NULL);
 | |
| 
 | |
|   CurrentGraphicsOutputMode = Private->GraphicsOutput.Mode;
 | |
| 
 | |
|   Index        = 0;
 | |
|   CurrentIndex = 0;
 | |
|   Status       = EFI_SUCCESS;
 | |
| 
 | |
|   if (Private->CurrentNumberOfUgaDraw != 0) {
 | |
|     //
 | |
|     // If any UGA device has already been added, then there is no need to
 | |
|     // calculate intersection of display mode of different GOP/UGA device,
 | |
|     // since only one display mode will be exported (i.e. user-defined mode)
 | |
|     //
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   if (GraphicsOutput != NULL) {
 | |
|     if (Private->CurrentNumberOfGraphicsOutput == 0) {
 | |
|         //
 | |
|         // This is the first Graphics Output device added
 | |
|         //
 | |
|         CurrentGraphicsOutputMode->MaxMode = GraphicsOutput->Mode->MaxMode;
 | |
|         CurrentGraphicsOutputMode->Mode = GraphicsOutput->Mode->Mode;
 | |
|         CopyMem (CurrentGraphicsOutputMode->Info, GraphicsOutput->Mode->Info, GraphicsOutput->Mode->SizeOfInfo);
 | |
|         CurrentGraphicsOutputMode->SizeOfInfo = GraphicsOutput->Mode->SizeOfInfo;
 | |
|         CurrentGraphicsOutputMode->FrameBufferBase = GraphicsOutput->Mode->FrameBufferBase;
 | |
|         CurrentGraphicsOutputMode->FrameBufferSize = GraphicsOutput->Mode->FrameBufferSize;
 | |
| 
 | |
|         //
 | |
|         // Allocate resource for the private mode buffer
 | |
|         //
 | |
|         ModeBuffer = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * GraphicsOutput->Mode->MaxMode);
 | |
|         if (ModeBuffer == NULL) {
 | |
|           return EFI_OUT_OF_RESOURCES;
 | |
|         }
 | |
|         FreePool (Private->GraphicsOutputModeBuffer);
 | |
|         Private->GraphicsOutputModeBuffer = ModeBuffer;
 | |
| 
 | |
|         //
 | |
|         // Store all supported display modes to the private mode buffer
 | |
|         //
 | |
|         Mode = ModeBuffer;
 | |
|         for (Index = 0; Index < GraphicsOutput->Mode->MaxMode; Index++) {
 | |
|           //
 | |
|           // The Info buffer would be allocated by callee
 | |
|           //
 | |
|           Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) Index, &SizeOfInfo, &Info);
 | |
|           if (EFI_ERROR (Status)) {
 | |
|             return Status;
 | |
|           }
 | |
|           ASSERT ( SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
 | |
|           CopyMem (Mode, Info, SizeOfInfo);
 | |
|           Mode++;
 | |
|           FreePool (Info);
 | |
|         }
 | |
|     } else {
 | |
|       //
 | |
|       // Check intersection of display mode
 | |
|       //
 | |
|       ModeBuffer = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * CurrentGraphicsOutputMode->MaxMode);
 | |
|       if (ModeBuffer == NULL) {
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
| 
 | |
|       MatchedMode = ModeBuffer;
 | |
|       Mode = &Private->GraphicsOutputModeBuffer[0];
 | |
|       for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) {
 | |
|         Match = FALSE;
 | |
| 
 | |
|         for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex++) {
 | |
|           //
 | |
|           // The Info buffer would be allocated by callee
 | |
|           //
 | |
|           Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info);
 | |
|           if (EFI_ERROR (Status)) {
 | |
|             return Status;
 | |
|           }
 | |
|           if ((Info->HorizontalResolution == Mode->HorizontalResolution) &&
 | |
|               (Info->VerticalResolution == Mode->VerticalResolution)) {
 | |
|             //
 | |
|             // If GOP device supports one mode in current mode buffer,
 | |
|             // it will be added into matched mode buffer
 | |
|             //
 | |
|             Match = TRUE;
 | |
|             FreePool (Info);
 | |
|             break;
 | |
|           }
 | |
|           FreePool (Info);
 | |
|         }
 | |
| 
 | |
|         if (Match) {
 | |
|           AlreadyExist = FALSE;
 | |
| 
 | |
|           //
 | |
|           // Check if GOP mode has been in the mode buffer, ModeBuffer = MatchedMode at begin.
 | |
|           //
 | |
|           for (Info = ModeBuffer; Info < MatchedMode; Info++) {
 | |
|             if ((Info->HorizontalResolution == Mode->HorizontalResolution) &&
 | |
|                 (Info->VerticalResolution == Mode->VerticalResolution)) {
 | |
|               AlreadyExist = TRUE;
 | |
|               break;
 | |
|             }
 | |
|           }
 | |
| 
 | |
|           if (!AlreadyExist) {
 | |
|             CopyMem (MatchedMode, Mode, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
 | |
| 
 | |
|             //
 | |
|             // Physical frame buffer is no longer available, change PixelFormat to PixelBltOnly
 | |
|             //
 | |
|             MatchedMode->Version = 0;
 | |
|             MatchedMode->PixelFormat = PixelBltOnly;
 | |
|             ZeroMem (&MatchedMode->PixelInformation, sizeof (EFI_PIXEL_BITMASK));
 | |
| 
 | |
|             MatchedMode++;
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         Mode++;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Drop the old mode buffer, assign it to a new one
 | |
|       //
 | |
|       FreePool (Private->GraphicsOutputModeBuffer);
 | |
|       Private->GraphicsOutputModeBuffer = ModeBuffer;
 | |
| 
 | |
|       //
 | |
|       // Physical frame buffer is no longer available when there are more than one physical GOP devices
 | |
|       //
 | |
|       CurrentGraphicsOutputMode->MaxMode = (UINT32) (((UINTN) MatchedMode - (UINTN) ModeBuffer) / sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
 | |
|       CurrentGraphicsOutputMode->Info->PixelFormat = PixelBltOnly;
 | |
|       ZeroMem (&CurrentGraphicsOutputMode->Info->PixelInformation, sizeof (EFI_PIXEL_BITMASK));
 | |
|       CurrentGraphicsOutputMode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
 | |
|       CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;
 | |
|       CurrentGraphicsOutputMode->FrameBufferSize = 0;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Graphics console driver can ensure the same mode for all GOP devices
 | |
|     //
 | |
|     for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) {
 | |
|       Mode = &Private->GraphicsOutputModeBuffer[Index];
 | |
|       if ((Mode->HorizontalResolution == GraphicsOutput->Mode->Info->HorizontalResolution) &&
 | |
|          (Mode->VerticalResolution == GraphicsOutput->Mode->Info->VerticalResolution)) {
 | |
|         CurrentIndex = Index;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|     if (Index >= CurrentGraphicsOutputMode->MaxMode) {
 | |
|       //
 | |
|       // if user defined mode is not found, set to default mode 800x600
 | |
|       //
 | |
|       for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) {
 | |
|         Mode = &Private->GraphicsOutputModeBuffer[Index];
 | |
|         if ((Mode->HorizontalResolution == 800) && (Mode->VerticalResolution == 600)) {
 | |
|           CurrentIndex = Index;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   } else if (UgaDraw != NULL) {
 | |
|     //
 | |
|     // Graphics console driver can ensure the same mode for all GOP devices
 | |
|     // so we can get the current mode from this video device
 | |
|     //
 | |
|     UgaDraw->GetMode (
 | |
|                UgaDraw,
 | |
|                &UgaHorizontalResolution,
 | |
|                &UgaVerticalResolution,
 | |
|                &UgaColorDepth,
 | |
|                &UgaRefreshRate
 | |
|                );
 | |
| 
 | |
|     CurrentGraphicsOutputMode->MaxMode = 1;
 | |
|     Info = CurrentGraphicsOutputMode->Info;
 | |
|     Info->Version = 0;
 | |
|     Info->HorizontalResolution                 = UgaHorizontalResolution;
 | |
|     Info->VerticalResolution                   = UgaVerticalResolution;
 | |
|     Info->PixelFormat                          = PixelBltOnly;
 | |
|     Info->PixelsPerScanLine                    = UgaHorizontalResolution;
 | |
|     CurrentGraphicsOutputMode->SizeOfInfo      = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
 | |
|     CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;
 | |
|     CurrentGraphicsOutputMode->FrameBufferSize = 0;
 | |
| 
 | |
|     //
 | |
|     // Update the private mode buffer
 | |
|     //
 | |
|     CopyMem (&Private->GraphicsOutputModeBuffer[0], Info, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
 | |
| 
 | |
|     //
 | |
|     // Only mode 0 is available to be set
 | |
|     //
 | |
|     CurrentIndex = 0;
 | |
|   }
 | |
| 
 | |
| Done:
 | |
| 
 | |
|   if (GraphicsOutput != NULL) {
 | |
|     Private->CurrentNumberOfGraphicsOutput++;
 | |
|   }
 | |
|   if (UgaDraw != NULL) {
 | |
|     Private->CurrentNumberOfUgaDraw++;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Force GraphicsOutput mode to be set,
 | |
|   //
 | |
| 
 | |
|   Mode = &Private->GraphicsOutputModeBuffer[CurrentIndex];
 | |
|   if ((GraphicsOutput != NULL) &&
 | |
|       (Mode->HorizontalResolution == CurrentGraphicsOutputMode->Info->HorizontalResolution) &&
 | |
|       (Mode->VerticalResolution == CurrentGraphicsOutputMode->Info->VerticalResolution)) {
 | |
|     CurrentGraphicsOutputMode->Mode = (UINT32) CurrentIndex;
 | |
|     if ((Mode->HorizontalResolution != GraphicsOutput->Mode->Info->HorizontalResolution) ||
 | |
|         (Mode->VerticalResolution != GraphicsOutput->Mode->Info->VerticalResolution)) {
 | |
|       //
 | |
|       // If all existing video device has been set to common mode, only set new GOP device to
 | |
|       // the common mode
 | |
|       //
 | |
|       for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex ++) {
 | |
|         Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info);
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           return Status;
 | |
|         }
 | |
|         if ((Info->HorizontalResolution == Mode->HorizontalResolution) && (Info->VerticalResolution == Mode->VerticalResolution)) {
 | |
|           FreePool (Info);
 | |
|           break;
 | |
|         }
 | |
|         FreePool (Info);
 | |
|       }
 | |
|       Status = GraphicsOutput->SetMode (GraphicsOutput, (UINT32) NumberIndex);
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // Current mode number may need update now, so set it to an invalid mode number
 | |
|     //
 | |
|     CurrentGraphicsOutputMode->Mode = 0xffff;
 | |
|     //
 | |
|     // Graphics console can ensure all GOP devices have the same mode which can be taken as current mode.
 | |
|     //
 | |
|     Status = Private->GraphicsOutput.SetMode (&Private->GraphicsOutput, (UINT32) CurrentIndex);
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       //
 | |
|       // If user defined mode is not valid for display device, set to the default mode 800x600.
 | |
|       //
 | |
|       (Private->GraphicsOutputModeBuffer[0]).HorizontalResolution = 800;
 | |
|       (Private->GraphicsOutputModeBuffer[0]).VerticalResolution   = 600;
 | |
|       Status = Private->GraphicsOutput.SetMode (&Private->GraphicsOutput, 0);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Set the current console out mode.
 | |
| 
 | |
|   This routine will get the current console mode information (column, row)
 | |
|   from ConsoleOutMode variable and set it; if the variable does not exist,
 | |
|   set to user defined console mode.
 | |
| 
 | |
|   @param  Private            Consplitter Text Out pointer.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| ConsplitterSetConsoleOutMode (
 | |
|   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private
 | |
|   )
 | |
| {
 | |
|   UINTN                            Col;
 | |
|   UINTN                            Row;
 | |
|   UINTN                            Mode;
 | |
|   UINTN                            PreferMode;
 | |
|   UINTN                            BaseMode;
 | |
|   UINTN                            MaxMode;
 | |
|   EFI_STATUS                       Status;
 | |
|   CONSOLE_OUT_MODE                 ModeInfo;
 | |
|   CONSOLE_OUT_MODE                 MaxModeInfo;
 | |
|   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;
 | |
| 
 | |
|   PreferMode   = 0xFF;
 | |
|   BaseMode     = 0xFF;
 | |
|   TextOut      = &Private->TextOut;
 | |
|   MaxMode      = (UINTN) (TextOut->Mode->MaxMode);
 | |
| 
 | |
|   MaxModeInfo.Column = 0;
 | |
|   MaxModeInfo.Row    = 0;
 | |
|   ModeInfo.Column    = PcdGet32 (PcdConOutColumn);
 | |
|   ModeInfo.Row       = PcdGet32 (PcdConOutRow);
 | |
| 
 | |
|   //
 | |
|   // To find the prefer mode and basic mode from Text Out mode list
 | |
|   //
 | |
|   for (Mode = 0; Mode < MaxMode; Mode++) {
 | |
|     Status = TextOut->QueryMode (TextOut, Mode, &Col, &Row);
 | |
|     if (!EFI_ERROR(Status)) {
 | |
|       if ((ModeInfo.Column != 0) && (ModeInfo.Row != 0)) {
 | |
|         //
 | |
|         // Use user defined column and row
 | |
|         //
 | |
|         if (Col == ModeInfo.Column && Row == ModeInfo.Row) {
 | |
|           PreferMode = Mode;
 | |
|         }
 | |
|       } else {
 | |
|         //
 | |
|         // If user sets PcdConOutColumn or PcdConOutRow to 0,
 | |
|         // find and set the highest text mode.
 | |
|         //
 | |
|         if ((Col >= MaxModeInfo.Column) && (Row >= MaxModeInfo.Row)) {
 | |
|           MaxModeInfo.Column  = Col;
 | |
|           MaxModeInfo.Row     = Row;
 | |
|           PreferMode          = Mode;
 | |
|         }
 | |
|       }
 | |
|       if (Col == 80 && Row == 25) {
 | |
|         BaseMode = Mode;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set prefer mode to Text Out devices.
 | |
|   //
 | |
|   Status = TextOut->SetMode (TextOut, PreferMode);
 | |
|   if (EFI_ERROR(Status)) {
 | |
|     //
 | |
|     // if current mode setting is failed, default 80x25 mode will be set.
 | |
|     //
 | |
|     Status = TextOut->SetMode (TextOut, BaseMode);
 | |
|     ASSERT(!EFI_ERROR(Status));
 | |
| 
 | |
|     Status = PcdSet32S (PcdConOutColumn, 80);
 | |
|     ASSERT(!EFI_ERROR(Status));
 | |
|     Status = PcdSet32S (PcdConOutRow, 25);
 | |
|     ASSERT(!EFI_ERROR(Status));
 | |
|   }
 | |
| 
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Add Text Output Device in Consplitter Text Output list.
 | |
| 
 | |
|   @param  Private                  Text Out Splitter pointer.
 | |
|   @param  TextOut                  Simple Text Output protocol pointer.
 | |
|   @param  GraphicsOutput           Graphics Output protocol pointer.
 | |
|   @param  UgaDraw                  UGA Draw protocol pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS              Text Output Device added successfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterTextOutAddDevice (
 | |
|   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA     *Private,
 | |
|   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *TextOut,
 | |
|   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL       *GraphicsOutput,
 | |
|   IN  EFI_UGA_DRAW_PROTOCOL              *UgaDraw
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                           Status;
 | |
|   UINTN                                CurrentNumOfConsoles;
 | |
|   INT32                                MaxMode;
 | |
|   UINT32                               UgaHorizontalResolution;
 | |
|   UINT32                               UgaVerticalResolution;
 | |
|   UINT32                               UgaColorDepth;
 | |
|   UINT32                               UgaRefreshRate;
 | |
|   TEXT_OUT_AND_GOP_DATA                *TextAndGop;
 | |
|   UINTN                                SizeOfInfo;
 | |
|   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
 | |
|   EFI_STATUS                           DeviceStatus;
 | |
| 
 | |
|   Status                = EFI_SUCCESS;
 | |
|   CurrentNumOfConsoles  = Private->CurrentNumberOfConsoles;
 | |
| 
 | |
|   //
 | |
|   // If the Text Out List is full, enlarge it by calling ConSplitterGrowBuffer().
 | |
|   //
 | |
|   while (CurrentNumOfConsoles >= Private->TextOutListCount) {
 | |
|     Status = ConSplitterGrowBuffer (
 | |
|               sizeof (TEXT_OUT_AND_GOP_DATA),
 | |
|               &Private->TextOutListCount,
 | |
|               (VOID **) &Private->TextOutList
 | |
|               );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|     //
 | |
|     // Also need to reallocate the TextOutModeMap table
 | |
|     //
 | |
|     Status = ConSplitterGrowMapTable (Private);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   TextAndGop          = &Private->TextOutList[CurrentNumOfConsoles];
 | |
| 
 | |
|   TextAndGop->TextOut        = TextOut;
 | |
|   TextAndGop->GraphicsOutput = GraphicsOutput;
 | |
|   TextAndGop->UgaDraw        = UgaDraw;
 | |
| 
 | |
|   if (CurrentNumOfConsoles == 0) {
 | |
|     //
 | |
|     // Add the first device's output mode to console splitter's mode list
 | |
|     //
 | |
|     Status = ConSplitterAddOutputMode (Private, TextOut);
 | |
|   } else {
 | |
|     ConSplitterSyncOutputMode (Private, TextOut);
 | |
|   }
 | |
| 
 | |
|   Private->CurrentNumberOfConsoles++;
 | |
| 
 | |
|   //
 | |
|   // Scan both TextOutList, for the intersection TextOut device
 | |
|   // maybe both ConOut and StdErr incorporate the same Text Out
 | |
|   // device in them, thus the output of both should be synced.
 | |
|   //
 | |
|   ConSplitterGetIntersectionBetweenConOutAndStrErr ();
 | |
| 
 | |
|   MaxMode     = Private->TextOutMode.MaxMode;
 | |
|   ASSERT (MaxMode >= 1);
 | |
| 
 | |
|   DeviceStatus = EFI_DEVICE_ERROR;
 | |
|   Status       = EFI_DEVICE_ERROR;
 | |
| 
 | |
|   //
 | |
|   // This device display mode will be added into Graphics Ouput modes.
 | |
|   //
 | |
|   if ((GraphicsOutput != NULL) || (UgaDraw != NULL)) {
 | |
|     DeviceStatus = ConSplitterAddGraphicsOutputMode (Private, GraphicsOutput, UgaDraw);
 | |
|   }
 | |
| 
 | |
|   if (FeaturePcdGet (PcdConOutUgaSupport)) {
 | |
|     //
 | |
|     // If UGA is produced by Consplitter
 | |
|     //
 | |
|     if (GraphicsOutput != NULL) {
 | |
|       Status = GraphicsOutput->QueryMode (GraphicsOutput, GraphicsOutput->Mode->Mode, &SizeOfInfo, &Info);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         return Status;
 | |
|       }
 | |
|       ASSERT ( SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
 | |
| 
 | |
|       UgaHorizontalResolution = Info->HorizontalResolution;
 | |
|       UgaVerticalResolution   = Info->VerticalResolution;
 | |
| 
 | |
|       FreePool (Info);
 | |
| 
 | |
|     } else if (UgaDraw != NULL) {
 | |
|       Status = UgaDraw->GetMode (
 | |
|                     UgaDraw,
 | |
|                     &UgaHorizontalResolution,
 | |
|                     &UgaVerticalResolution,
 | |
|                     &UgaColorDepth,
 | |
|                     &UgaRefreshRate
 | |
|                     );
 | |
|       if (!EFI_ERROR (Status) && EFI_ERROR (DeviceStatus)) {
 | |
|         //
 | |
|         // if GetMode is successfully and UGA device hasn't been set, set it
 | |
|         //
 | |
|         Status = ConSplitterUgaDrawSetMode (
 | |
|                     &Private->UgaDraw,
 | |
|                     UgaHorizontalResolution,
 | |
|                     UgaVerticalResolution,
 | |
|                     UgaColorDepth,
 | |
|                     UgaRefreshRate
 | |
|                     );
 | |
|       }
 | |
|       //
 | |
|       // If GetMode/SetMode is failed, set to 800x600 mode
 | |
|       //
 | |
|       if(EFI_ERROR (Status)) {
 | |
|         Status = ConSplitterUgaDrawSetMode (
 | |
|                     &Private->UgaDraw,
 | |
|                     800,
 | |
|                     600,
 | |
|                     32,
 | |
|                     60
 | |
|                     );
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (((!EFI_ERROR (DeviceStatus)) || (!EFI_ERROR (Status))) &&
 | |
|       ((Private->CurrentNumberOfGraphicsOutput + Private->CurrentNumberOfUgaDraw) == 1)) {
 | |
|     if (!FeaturePcdGet (PcdConOutGopSupport)) {
 | |
|       //
 | |
|       // If Graphics Outpurt protocol not supported, UGA Draw protocol is installed
 | |
|       // on the virtual handle.
 | |
|       //
 | |
|       Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                       &mConOut.VirtualHandle,
 | |
|                       &gEfiUgaDrawProtocolGuid,
 | |
|                       &mConOut.UgaDraw,
 | |
|                       NULL
 | |
|                       );
 | |
|     } else if (!FeaturePcdGet (PcdConOutUgaSupport)) {
 | |
|       //
 | |
|       // If UGA Draw protocol not supported, Graphics Output Protocol is installed
 | |
|       // on virtual handle.
 | |
|       //
 | |
|       Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                       &mConOut.VirtualHandle,
 | |
|                       &gEfiGraphicsOutputProtocolGuid,
 | |
|                       &mConOut.GraphicsOutput,
 | |
|                       NULL
 | |
|                       );
 | |
|     } else {
 | |
|       //
 | |
|       // Boot Graphics Output protocol and UGA Draw protocol are supported,
 | |
|       // both they will be installed on virtual handle.
 | |
|       //
 | |
|       Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                       &mConOut.VirtualHandle,
 | |
|                       &gEfiGraphicsOutputProtocolGuid,
 | |
|                       &mConOut.GraphicsOutput,
 | |
|                       &gEfiUgaDrawProtocolGuid,
 | |
|                       &mConOut.UgaDraw,
 | |
|                       NULL
 | |
|                       );
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // After adding new console device, all existing console devices should be
 | |
|   // synced to the current shared mode.
 | |
|   //
 | |
|   ConsplitterSetConsoleOutMode (Private);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Remove Text Out Device in Consplitter Text Out list.
 | |
| 
 | |
|   @param  Private                  Text Out Splitter pointer.
 | |
|   @param  TextOut                  Simple Text Output Pointer protocol pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS              Text Out Device removed successfully.
 | |
|   @retval EFI_NOT_FOUND            No Text Out Device found.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterTextOutDeleteDevice (
 | |
|   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA     *Private,
 | |
|   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *TextOut
 | |
|   )
 | |
| {
 | |
|   INT32                 Index;
 | |
|   UINTN                 CurrentNumOfConsoles;
 | |
|   TEXT_OUT_AND_GOP_DATA *TextOutList;
 | |
|   EFI_STATUS            Status;
 | |
| 
 | |
|   //
 | |
|   // Remove the specified text-out device data structure from the Text out List,
 | |
|   // and rearrange the remaining data structures in the Text out List.
 | |
|   //
 | |
|   CurrentNumOfConsoles  = Private->CurrentNumberOfConsoles;
 | |
|   Index                 = (INT32) CurrentNumOfConsoles - 1;
 | |
|   TextOutList           = Private->TextOutList;
 | |
|   while (Index >= 0) {
 | |
|     if (TextOutList->TextOut == TextOut) {
 | |
|       if (TextOutList->UgaDraw != NULL) {
 | |
|         Private->CurrentNumberOfUgaDraw--;
 | |
|       }
 | |
|       if (TextOutList->GraphicsOutput != NULL) {
 | |
|         Private->CurrentNumberOfGraphicsOutput--;
 | |
|       }
 | |
|       CopyMem (TextOutList, TextOutList + 1, sizeof (TEXT_OUT_AND_GOP_DATA) * Index);
 | |
|       CurrentNumOfConsoles--;
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     Index--;
 | |
|     TextOutList++;
 | |
|   }
 | |
|   //
 | |
|   // The specified TextOut is not managed by the ConSplitter driver
 | |
|   //
 | |
|   if (Index < 0) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   if ((Private->CurrentNumberOfGraphicsOutput == 0) && (Private->CurrentNumberOfUgaDraw == 0)) {
 | |
|     //
 | |
|     // If there is not any physical GOP and UGA device in system,
 | |
|     // Consplitter GOP or UGA protocol will be uninstalled
 | |
|     //
 | |
|     if (!FeaturePcdGet (PcdConOutGopSupport)) {
 | |
|       Status = gBS->UninstallProtocolInterface (
 | |
|                       Private->VirtualHandle,
 | |
|                       &gEfiUgaDrawProtocolGuid,
 | |
|                       &Private->UgaDraw
 | |
|                       );
 | |
|     } else if (!FeaturePcdGet (PcdConOutUgaSupport)) {
 | |
|       Status = gBS->UninstallProtocolInterface (
 | |
|                       Private->VirtualHandle,
 | |
|                       &gEfiGraphicsOutputProtocolGuid,
 | |
|                       &Private->GraphicsOutput
 | |
|                       );
 | |
|     } else {
 | |
|       Status = gBS->UninstallMultipleProtocolInterfaces (
 | |
|              Private->VirtualHandle,
 | |
|              &gEfiUgaDrawProtocolGuid,
 | |
|              &Private->UgaDraw,
 | |
|              &gEfiGraphicsOutputProtocolGuid,
 | |
|              &Private->GraphicsOutput,
 | |
|              NULL
 | |
|              );
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (CurrentNumOfConsoles == 0) {
 | |
|     //
 | |
|     // If the number of consoles is zero, reset all parameters
 | |
|     //
 | |
|     Private->CurrentNumberOfConsoles      = 0;
 | |
|     Private->TextOutMode.MaxMode          = 1;
 | |
|     Private->TextOutQueryData[0].Columns  = 80;
 | |
|     Private->TextOutQueryData[0].Rows     = 25;
 | |
|     TextOutSetMode (Private, 0);
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
|   //
 | |
|   // Max Mode is realy an intersection of the QueryMode command to all
 | |
|   // devices. So we must copy the QueryMode of the first device to
 | |
|   // QueryData.
 | |
|   //
 | |
|   ZeroMem (
 | |
|     Private->TextOutQueryData,
 | |
|     Private->TextOutQueryDataCount * sizeof (TEXT_OUT_SPLITTER_QUERY_DATA)
 | |
|     );
 | |
| 
 | |
|   FreePool (Private->TextOutModeMap);
 | |
|   Private->TextOutModeMap = NULL;
 | |
|   TextOutList             = Private->TextOutList;
 | |
| 
 | |
|   //
 | |
|   // Add the first TextOut to the QueryData array and ModeMap table
 | |
|   //
 | |
|   Status = ConSplitterAddOutputMode (Private, TextOutList->TextOut);
 | |
| 
 | |
|   //
 | |
|   // Now add one by one
 | |
|   //
 | |
|   Index = 1;
 | |
|   Private->CurrentNumberOfConsoles = 1;
 | |
|   TextOutList++;
 | |
|   while ((UINTN) Index < CurrentNumOfConsoles) {
 | |
|     ConSplitterSyncOutputMode (Private, TextOutList->TextOut);
 | |
|     Index++;
 | |
|     Private->CurrentNumberOfConsoles++;
 | |
|     TextOutList++;
 | |
|   }
 | |
| 
 | |
|   ConSplitterGetIntersectionBetweenConOutAndStrErr ();
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Reset the input device and optionaly run diagnostics
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  ExtendedVerification     Driver may perform diagnostics on reset.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The device was reset.
 | |
|   @retval EFI_DEVICE_ERROR         The device is not functioning properly and could
 | |
|                                    not be reset.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextInReset (
 | |
|   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
 | |
|   IN  BOOLEAN                         ExtendedVerification
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   EFI_STATUS                    ReturnStatus;
 | |
|   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
 | |
|   UINTN                         Index;
 | |
| 
 | |
|   Private                       = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   Private->KeyEventSignalState  = FALSE;
 | |
| 
 | |
|   //
 | |
|   // return the worst status met
 | |
|   //
 | |
|   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
 | |
|     Status = Private->TextInList[Index]->Reset (
 | |
|                                           Private->TextInList[Index],
 | |
|                                           ExtendedVerification
 | |
|                                           );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ReturnStatus = Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!EFI_ERROR (ReturnStatus)) {
 | |
|     ToggleStateSyncReInitialization (Private);
 | |
|     //
 | |
|     // Empty the key queue.
 | |
|     //
 | |
|     Private->CurrentNumberOfKeys = 0;
 | |
|   }
 | |
| 
 | |
|   return ReturnStatus;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Dequeue the saved key from internal key queue.
 | |
| 
 | |
|   @param  Private                  Protocol instance pointer.
 | |
|   @param  KeyData                  A pointer to a buffer that is filled in with the
 | |
|                                    keystroke state data for the key that was
 | |
|                                    pressed.
 | |
|   @retval EFI_NOT_FOUND            Queue is empty.
 | |
|   @retval EFI_SUCCESS              First key is dequeued and returned.
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConSplitterTextInExDequeueKey (
 | |
|   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,
 | |
|   OUT EFI_KEY_DATA                    *KeyData
 | |
|   )
 | |
| {
 | |
|   if (Private->CurrentNumberOfKeys == 0) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
|   //
 | |
|   // Return the first saved key.
 | |
|   //
 | |
|   CopyMem (KeyData, &Private->KeyQueue[0], sizeof (EFI_KEY_DATA));
 | |
|   Private->CurrentNumberOfKeys--;
 | |
|   CopyMem (
 | |
|     &Private->KeyQueue[0],
 | |
|     &Private->KeyQueue[1],
 | |
|     Private->CurrentNumberOfKeys * sizeof (EFI_KEY_DATA)
 | |
|     );
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reads the next keystroke from the input device. The WaitForKey Event can
 | |
|   be used to test for existance of a keystroke via WaitForEvent () call.
 | |
| 
 | |
|   @param  Private                  Protocol instance pointer.
 | |
|   @param  Key                      Driver may perform diagnostics on reset.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The keystroke information was returned.
 | |
|   @retval EFI_NOT_READY            There was no keystroke data availiable.
 | |
|   @retval EFI_DEVICE_ERROR         The keydtroke information was not returned due
 | |
|                                    to hardware errors.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextInPrivateReadKeyStroke (
 | |
|   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,
 | |
|   OUT EFI_INPUT_KEY                   *Key
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS    Status;
 | |
|   UINTN         Index;
 | |
|   EFI_KEY_DATA  KeyData;
 | |
| 
 | |
|   //
 | |
|   // Return the first saved non-NULL key.
 | |
|   //
 | |
|   while (TRUE) {
 | |
|     Status = ConSplitterTextInExDequeueKey (Private, &KeyData);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       break;
 | |
|     }
 | |
|     if ((KeyData.Key.ScanCode != CHAR_NULL) || (KeyData.Key.UnicodeChar != SCAN_NULL)) {
 | |
|       CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Key->UnicodeChar  = 0;
 | |
|   Key->ScanCode     = SCAN_NULL;
 | |
| 
 | |
|   //
 | |
|   // if no physical console input device exists, return EFI_NOT_READY;
 | |
|   // if any physical console input device has key input,
 | |
|   // return the key and EFI_SUCCESS.
 | |
|   //
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfConsoles;) {
 | |
|     Status = Private->TextInList[Index]->ReadKeyStroke (
 | |
|                                           Private->TextInList[Index],
 | |
|                                           &KeyData.Key
 | |
|                                           );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // If it is not partial keystorke, return the key. Otherwise, continue
 | |
|       // to read key from THIS physical console input device.
 | |
|       //
 | |
|       if ((KeyData.Key.ScanCode != CHAR_NULL) || (KeyData.Key.UnicodeChar != SCAN_NULL)) {
 | |
|         CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
 | |
|         return Status;
 | |
|       }
 | |
|     } else {
 | |
|       //
 | |
|       // Continue to read key from NEXT physical console input device.
 | |
|       //
 | |
|       Index++;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_READY;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Reads the next keystroke from the input device. The WaitForKey Event can
 | |
|   be used to test for existance of a keystroke via WaitForEvent () call.
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  Key                      Driver may perform diagnostics on reset.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The keystroke information was returned.
 | |
|   @retval EFI_NOT_READY            There was no keystroke data availiable.
 | |
|   @retval EFI_DEVICE_ERROR         The keydtroke information was not returned due
 | |
|                                    to hardware errors.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextInReadKeyStroke (
 | |
|   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
 | |
|   OUT EFI_INPUT_KEY                   *Key
 | |
|   )
 | |
| {
 | |
|   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
 | |
| 
 | |
|   Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   Private->KeyEventSignalState = FALSE;
 | |
| 
 | |
|   //
 | |
|   // Signal ConnectConIn event on first call in Lazy ConIn mode
 | |
|   //
 | |
|   if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {
 | |
|     DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));
 | |
|     gBS->SignalEvent (Private->ConnectConInEvent);
 | |
|     mConInIsConnect = TRUE;
 | |
|   }
 | |
| 
 | |
|   return ConSplitterTextInPrivateReadKeyStroke (Private, Key);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This event aggregates all the events of the ConIn devices in the spliter.
 | |
| 
 | |
|   If any events of physical ConIn devices are signaled, signal the ConIn
 | |
|   spliter event. This will cause the calling code to call
 | |
|   ConSplitterTextInReadKeyStroke ().
 | |
| 
 | |
|   @param  Event                    The Event assoicated with callback.
 | |
|   @param  Context                  Context registered when Event was created.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| ConSplitterTextInWaitForKey (
 | |
|   IN  EFI_EVENT                       Event,
 | |
|   IN  VOID                            *Context
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
 | |
|   UINTN                         Index;
 | |
| 
 | |
|   Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context;
 | |
| 
 | |
|   if (Private->KeyEventSignalState) {
 | |
|     //
 | |
|     // If KeyEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke()
 | |
|     //
 | |
|     gBS->SignalEvent (Event);
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If any physical console input device has key input, signal the event.
 | |
|   //
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
 | |
|     Status = gBS->CheckEvent (Private->TextInList[Index]->WaitForKey);
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       gBS->SignalEvent (Event);
 | |
|       Private->KeyEventSignalState = TRUE;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Test if the key has been registered on input device.
 | |
| 
 | |
|   @param  RegsiteredData           A pointer to a buffer that is filled in with the
 | |
|                                    keystroke state data for the key that was
 | |
|                                    registered.
 | |
|   @param  InputData                A pointer to a buffer that is filled in with the
 | |
|                                    keystroke state data for the key that was
 | |
|                                    pressed.
 | |
| 
 | |
|   @retval TRUE                     Key be pressed matches a registered key.
 | |
|   @retval FLASE                    Match failed.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| IsKeyRegistered (
 | |
|   IN EFI_KEY_DATA  *RegsiteredData,
 | |
|   IN EFI_KEY_DATA  *InputData
 | |
|   )
 | |
| {
 | |
|   ASSERT (RegsiteredData != NULL && InputData != NULL);
 | |
| 
 | |
|   if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
 | |
|       (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
 | |
|   //
 | |
|   if (RegsiteredData->KeyState.KeyShiftState != 0 &&
 | |
|       RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
 | |
|     return FALSE;
 | |
|   }
 | |
|   if (RegsiteredData->KeyState.KeyToggleState != 0 &&
 | |
|       RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Reset the input device and optionaly run diagnostics
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  ExtendedVerification     Driver may perform diagnostics on reset.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The device was reset.
 | |
|   @retval EFI_DEVICE_ERROR         The device is not functioning properly and could
 | |
|                                    not be reset.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextInResetEx (
 | |
|   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
 | |
|   IN BOOLEAN                            ExtendedVerification
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   EFI_STATUS                    ReturnStatus;
 | |
|   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
 | |
|   UINTN                         Index;
 | |
| 
 | |
|   Private                       = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   Private->KeyEventSignalState  = FALSE;
 | |
| 
 | |
|   //
 | |
|   // return the worst status met
 | |
|   //
 | |
|   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfExConsoles; Index++) {
 | |
|     Status = Private->TextInExList[Index]->Reset (
 | |
|                                              Private->TextInExList[Index],
 | |
|                                              ExtendedVerification
 | |
|                                              );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ReturnStatus = Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!EFI_ERROR (ReturnStatus)) {
 | |
|     ToggleStateSyncReInitialization (Private);
 | |
|     //
 | |
|     // Empty the key queue.
 | |
|     //
 | |
|     Private->CurrentNumberOfKeys = 0;
 | |
|   }
 | |
| 
 | |
|   return ReturnStatus;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Reads the next keystroke from the input device. The WaitForKey Event can
 | |
|   be used to test for existance of a keystroke via WaitForEvent () call.
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  KeyData                  A pointer to a buffer that is filled in with the
 | |
|                                    keystroke state data for the key that was
 | |
|                                    pressed.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The keystroke information was returned.
 | |
|   @retval EFI_NOT_READY            There was no keystroke data availiable.
 | |
|   @retval EFI_DEVICE_ERROR         The keystroke information was not returned due
 | |
|                                    to hardware errors.
 | |
|   @retval EFI_INVALID_PARAMETER    KeyData is NULL.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextInReadKeyStrokeEx (
 | |
|   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
 | |
|   OUT EFI_KEY_DATA                      *KeyData
 | |
|   )
 | |
| {
 | |
|   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
 | |
|   EFI_STATUS                    Status;
 | |
|   UINTN                         Index;
 | |
|   EFI_KEY_STATE                 KeyState;
 | |
|   EFI_KEY_DATA                  CurrentKeyData;
 | |
| 
 | |
| 
 | |
|   if (KeyData == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   Private->KeyEventSignalState = FALSE;
 | |
| 
 | |
|   //
 | |
|   // Signal ConnectConIn event on first call in Lazy ConIn mode
 | |
|   //
 | |
|   if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {
 | |
|     DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));
 | |
|     gBS->SignalEvent (Private->ConnectConInEvent);
 | |
|     mConInIsConnect = TRUE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Return the first saved key.
 | |
|   //
 | |
|   Status = ConSplitterTextInExDequeueKey (Private, KeyData);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   ASSERT (Private->CurrentNumberOfKeys == 0);
 | |
| 
 | |
|   ZeroMem (&KeyState, sizeof (KeyState));
 | |
| 
 | |
|   //
 | |
|   // Iterate through all physical consoles to get key state.
 | |
|   // Some physical consoles may return valid key.
 | |
|   // Queue the valid keys.
 | |
|   //
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
 | |
|     ZeroMem (&CurrentKeyData, sizeof (EFI_KEY_DATA));
 | |
|     Status = Private->TextInExList[Index]->ReadKeyStrokeEx (
 | |
|                                              Private->TextInExList[Index],
 | |
|                                              &CurrentKeyData
 | |
|                                              );
 | |
|     if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Consolidate the key state from all physical consoles.
 | |
|     //
 | |
|     if ((CurrentKeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) {
 | |
|       KeyState.KeyShiftState |= CurrentKeyData.KeyState.KeyShiftState;
 | |
|     }
 | |
|     if ((CurrentKeyData.KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != 0) {
 | |
|       KeyState.KeyToggleState |= CurrentKeyData.KeyState.KeyToggleState;
 | |
|     }
 | |
| 
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // If virtual KeyState has been required to be exposed, or it is not
 | |
|       // partial keystorke, queue the key.
 | |
|       // It's possible that user presses at multiple keyboards at the same moment,
 | |
|       // Private->KeyQueue[] are the storage to save all the keys.
 | |
|       //
 | |
|       if ((Private->VirtualKeyStateExported) ||
 | |
|           (CurrentKeyData.Key.ScanCode != CHAR_NULL) ||
 | |
|           (CurrentKeyData.Key.UnicodeChar != SCAN_NULL)) {
 | |
|         CopyMem (
 | |
|           &Private->KeyQueue[Private->CurrentNumberOfKeys],
 | |
|           &CurrentKeyData,
 | |
|           sizeof (EFI_KEY_DATA)
 | |
|           );
 | |
|         Private->CurrentNumberOfKeys++;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Consolidate the key state for all keys in Private->KeyQueue[]
 | |
|   //
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfKeys; Index++) {
 | |
|     CopyMem (&Private->KeyQueue[Index].KeyState, &KeyState, sizeof (EFI_KEY_STATE));
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Return the first saved key.
 | |
|   //
 | |
|   Status = ConSplitterTextInExDequeueKey (Private, KeyData);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Always return the key state even there is no key pressed.
 | |
|   //
 | |
|   ZeroMem (&KeyData->Key, sizeof (KeyData->Key));
 | |
|   CopyMem (&KeyData->KeyState, &KeyState, sizeof (KeyData->KeyState));
 | |
|   return EFI_NOT_READY;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Set certain state for the input device.
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  KeyToggleState           A pointer to the EFI_KEY_TOGGLE_STATE to set the
 | |
|                                    state for the input device.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The device state was set successfully.
 | |
|   @retval EFI_DEVICE_ERROR         The device is not functioning correctly and
 | |
|                                    could not have the setting adjusted.
 | |
|   @retval EFI_UNSUPPORTED          The device does not have the ability to set its
 | |
|                                    state.
 | |
|   @retval EFI_INVALID_PARAMETER    KeyToggleState is NULL.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextInSetState (
 | |
|   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
 | |
|   IN EFI_KEY_TOGGLE_STATE               *KeyToggleState
 | |
|   )
 | |
| {
 | |
|   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
 | |
|   EFI_STATUS                    Status;
 | |
|   UINTN                         Index;
 | |
|   EFI_KEY_TOGGLE_STATE          PhysicalKeyToggleState;
 | |
| 
 | |
|   if (KeyToggleState == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // Always turn on physical TextInEx partial key report for
 | |
|   // toggle state sync.
 | |
|   //
 | |
|   PhysicalKeyToggleState = *KeyToggleState | EFI_KEY_STATE_EXPOSED;
 | |
| 
 | |
|   //
 | |
|   // if no physical console input device exists, return EFI_SUCCESS;
 | |
|   // otherwise return the status of setting state of physical console input device
 | |
|   //
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
 | |
|     Status = Private->TextInExList[Index]->SetState (
 | |
|                                              Private->TextInExList[Index],
 | |
|                                              &PhysicalKeyToggleState
 | |
|                                              );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Record the physical KeyToggleState.
 | |
|   //
 | |
|   Private->PhysicalKeyToggleState = PhysicalKeyToggleState;
 | |
|   //
 | |
|   // Get if virtual KeyState has been required to be exposed.
 | |
|   //
 | |
|   Private->VirtualKeyStateExported = (((*KeyToggleState) & EFI_KEY_STATE_EXPOSED) != 0);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Register a notification function for a particular keystroke for the input device.
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  KeyData                  A pointer to a buffer that is filled in with
 | |
|                                    the keystroke information for the key that was
 | |
|                                    pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState
 | |
|                                    and KeyData.KeyState.KeyShiftState are 0, then any incomplete
 | |
|                                    keystroke will trigger a notification of the KeyNotificationFunction.
 | |
|   @param  KeyNotificationFunction  Points to the function to be called when the key
 | |
|                                    sequence is typed specified by KeyData. This notification function
 | |
|                                    should be called at <=TPL_CALLBACK.
 | |
|   @param  NotifyHandle             Points to the unique handle assigned to the
 | |
|                                    registered notification.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The notification function was registered
 | |
|                                    successfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES     Unable to allocate resources for necesssary data
 | |
|                                    structures.
 | |
|   @retval EFI_INVALID_PARAMETER    KeyData or KeyNotificationFunction or NotifyHandle is NULL.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextInRegisterKeyNotify (
 | |
|   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
 | |
|   IN EFI_KEY_DATA                       *KeyData,
 | |
|   IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,
 | |
|   OUT VOID                              **NotifyHandle
 | |
|   )
 | |
| {
 | |
|   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
 | |
|   EFI_STATUS                    Status;
 | |
|   UINTN                         Index;
 | |
|   TEXT_IN_EX_SPLITTER_NOTIFY    *NewNotify;
 | |
|   LIST_ENTRY                    *Link;
 | |
|   TEXT_IN_EX_SPLITTER_NOTIFY    *CurrentNotify;
 | |
| 
 | |
| 
 | |
|   if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
 | |
|   //
 | |
|   for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
 | |
|     CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);
 | |
|     if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
 | |
|       if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
 | |
|         *NotifyHandle = CurrentNotify;
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate resource to save the notification function
 | |
|   //
 | |
|   NewNotify = (TEXT_IN_EX_SPLITTER_NOTIFY *) AllocateZeroPool (sizeof (TEXT_IN_EX_SPLITTER_NOTIFY));
 | |
|   if (NewNotify == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   NewNotify->NotifyHandleList = (EFI_HANDLE *) AllocateZeroPool (sizeof (EFI_HANDLE) *  Private->TextInExListCount);
 | |
|   if (NewNotify->NotifyHandleList == NULL) {
 | |
|     gBS->FreePool (NewNotify);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   NewNotify->Signature         = TEXT_IN_EX_SPLITTER_NOTIFY_SIGNATURE;
 | |
|   NewNotify->KeyNotificationFn = KeyNotificationFunction;
 | |
|   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
 | |
| 
 | |
|   //
 | |
|   // Return the wrong status of registering key notify of
 | |
|   // physical console input device if meet problems
 | |
|   //
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
 | |
|     Status = Private->TextInExList[Index]->RegisterKeyNotify (
 | |
|                                              Private->TextInExList[Index],
 | |
|                                              KeyData,
 | |
|                                              KeyNotificationFunction,
 | |
|                                              &NewNotify->NotifyHandleList[Index]
 | |
|                                              );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // Un-register the key notify on all physical console input devices
 | |
|       //
 | |
|       while (Index-- != 0) {
 | |
|         Private->TextInExList[Index]->UnregisterKeyNotify (
 | |
|                                         Private->TextInExList[Index],
 | |
|                                         NewNotify->NotifyHandleList[Index]
 | |
|                                         );
 | |
|       }
 | |
|       gBS->FreePool (NewNotify->NotifyHandleList);
 | |
|       gBS->FreePool (NewNotify);
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   InsertTailList (&Private->NotifyList, &NewNotify->NotifyEntry);
 | |
| 
 | |
|   *NotifyHandle                = NewNotify;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Remove a registered notification function from a particular keystroke.
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  NotificationHandle       The handle of the notification function being
 | |
|                                    unregistered.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The notification function was unregistered
 | |
|                                    successfully.
 | |
|   @retval EFI_INVALID_PARAMETER    The NotificationHandle is invalid.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextInUnregisterKeyNotify (
 | |
|   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
 | |
|   IN VOID                               *NotificationHandle
 | |
|   )
 | |
| {
 | |
|   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
 | |
|   UINTN                         Index;
 | |
|   TEXT_IN_EX_SPLITTER_NOTIFY    *CurrentNotify;
 | |
|   LIST_ENTRY                    *Link;
 | |
| 
 | |
|   if (NotificationHandle == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
 | |
|     CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);
 | |
|     if (CurrentNotify == NotificationHandle) {
 | |
|       for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
 | |
|         Private->TextInExList[Index]->UnregisterKeyNotify (
 | |
|                                         Private->TextInExList[Index],
 | |
|                                         CurrentNotify->NotifyHandleList[Index]
 | |
|                                         );
 | |
|       }
 | |
|       RemoveEntryList (&CurrentNotify->NotifyEntry);
 | |
| 
 | |
|       gBS->FreePool (CurrentNotify->NotifyHandleList);
 | |
|       gBS->FreePool (CurrentNotify);
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // NotificationHandle is not found in database
 | |
|   //
 | |
|   return EFI_INVALID_PARAMETER;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Reset the input device and optionaly run diagnostics
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  ExtendedVerification     Driver may perform diagnostics on reset.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The device was reset.
 | |
|   @retval EFI_DEVICE_ERROR         The device is not functioning properly and could
 | |
|                                    not be reset.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterSimplePointerReset (
 | |
|   IN  EFI_SIMPLE_POINTER_PROTOCOL     *This,
 | |
|   IN  BOOLEAN                         ExtendedVerification
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   EFI_STATUS                    ReturnStatus;
 | |
|   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
 | |
|   UINTN                         Index;
 | |
| 
 | |
|   Private                         = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS (This);
 | |
| 
 | |
|   Private->InputEventSignalState  = FALSE;
 | |
| 
 | |
|   if (Private->CurrentNumberOfPointers == 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
|   //
 | |
|   // return the worst status met
 | |
|   //
 | |
|   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfPointers; Index++) {
 | |
|     Status = Private->PointerList[Index]->Reset (
 | |
|                                             Private->PointerList[Index],
 | |
|                                             ExtendedVerification
 | |
|                                             );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ReturnStatus = Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ReturnStatus;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Reads the next keystroke from the input device. The WaitForKey Event can
 | |
|   be used to test for existance of a keystroke via WaitForEvent () call.
 | |
| 
 | |
|   @param  Private                  Protocol instance pointer.
 | |
|   @param  State                    The state information of simple pointer device.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The keystroke information was returned.
 | |
|   @retval EFI_NOT_READY            There was no keystroke data availiable.
 | |
|   @retval EFI_DEVICE_ERROR         The keydtroke information was not returned due
 | |
|                                    to hardware errors.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterSimplePointerPrivateGetState (
 | |
|   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,
 | |
|   IN OUT EFI_SIMPLE_POINTER_STATE     *State
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                Status;
 | |
|   EFI_STATUS                ReturnStatus;
 | |
|   UINTN                     Index;
 | |
|   EFI_SIMPLE_POINTER_STATE  CurrentState;
 | |
| 
 | |
|   State->RelativeMovementX  = 0;
 | |
|   State->RelativeMovementY  = 0;
 | |
|   State->RelativeMovementZ  = 0;
 | |
|   State->LeftButton         = FALSE;
 | |
|   State->RightButton        = FALSE;
 | |
| 
 | |
|   //
 | |
|   // if no physical console input device exists, return EFI_NOT_READY;
 | |
|   // if any physical console input device has key input,
 | |
|   // return the key and EFI_SUCCESS.
 | |
|   //
 | |
|   ReturnStatus = EFI_NOT_READY;
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) {
 | |
| 
 | |
|     Status = Private->PointerList[Index]->GetState (
 | |
|                                             Private->PointerList[Index],
 | |
|                                             &CurrentState
 | |
|                                             );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       if (ReturnStatus == EFI_NOT_READY) {
 | |
|         ReturnStatus = EFI_SUCCESS;
 | |
|       }
 | |
| 
 | |
|       if (CurrentState.LeftButton) {
 | |
|         State->LeftButton = TRUE;
 | |
|       }
 | |
| 
 | |
|       if (CurrentState.RightButton) {
 | |
|         State->RightButton = TRUE;
 | |
|       }
 | |
| 
 | |
|       if (CurrentState.RelativeMovementX != 0 && Private->PointerList[Index]->Mode->ResolutionX != 0) {
 | |
|         State->RelativeMovementX += (CurrentState.RelativeMovementX * (INT32) Private->SimplePointerMode.ResolutionX) / (INT32) Private->PointerList[Index]->Mode->ResolutionX;
 | |
|       }
 | |
| 
 | |
|       if (CurrentState.RelativeMovementY != 0 && Private->PointerList[Index]->Mode->ResolutionY != 0) {
 | |
|         State->RelativeMovementY += (CurrentState.RelativeMovementY * (INT32) Private->SimplePointerMode.ResolutionY) / (INT32) Private->PointerList[Index]->Mode->ResolutionY;
 | |
|       }
 | |
| 
 | |
|       if (CurrentState.RelativeMovementZ != 0 && Private->PointerList[Index]->Mode->ResolutionZ != 0) {
 | |
|         State->RelativeMovementZ += (CurrentState.RelativeMovementZ * (INT32) Private->SimplePointerMode.ResolutionZ) / (INT32) Private->PointerList[Index]->Mode->ResolutionZ;
 | |
|       }
 | |
|     } else if (Status == EFI_DEVICE_ERROR) {
 | |
|       ReturnStatus = EFI_DEVICE_ERROR;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ReturnStatus;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Reads the next keystroke from the input device. The WaitForKey Event can
 | |
|   be used to test for existance of a keystroke via WaitForEvent () call.
 | |
| 
 | |
|   @param  This                     A pointer to protocol instance.
 | |
|   @param  State                    A pointer to state information on the pointer device
 | |
| 
 | |
|   @retval EFI_SUCCESS              The keystroke information was returned in State.
 | |
|   @retval EFI_NOT_READY            There was no keystroke data availiable.
 | |
|   @retval EFI_DEVICE_ERROR         The keydtroke information was not returned due
 | |
|                                    to hardware errors.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterSimplePointerGetState (
 | |
|   IN  EFI_SIMPLE_POINTER_PROTOCOL     *This,
 | |
|   IN OUT EFI_SIMPLE_POINTER_STATE     *State
 | |
|   )
 | |
| {
 | |
|   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
 | |
| 
 | |
|   Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS (This);
 | |
| 
 | |
|   Private->InputEventSignalState = FALSE;
 | |
| 
 | |
|   return ConSplitterSimplePointerPrivateGetState (Private, State);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This event agregates all the events of the ConIn devices in the spliter.
 | |
|   If any events of physical ConIn devices are signaled, signal the ConIn
 | |
|   spliter event. This will cause the calling code to call
 | |
|   ConSplitterTextInReadKeyStroke ().
 | |
| 
 | |
|   @param  Event                    The Event assoicated with callback.
 | |
|   @param  Context                  Context registered when Event was created.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| ConSplitterSimplePointerWaitForInput (
 | |
|   IN  EFI_EVENT                       Event,
 | |
|   IN  VOID                            *Context
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
 | |
|   UINTN                         Index;
 | |
| 
 | |
|   Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context;
 | |
| 
 | |
|   //
 | |
|   // if InputEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke()
 | |
|   //
 | |
|   if (Private->InputEventSignalState) {
 | |
|     gBS->SignalEvent (Event);
 | |
|     return ;
 | |
|   }
 | |
|   //
 | |
|   // if any physical console input device has key input, signal the event.
 | |
|   //
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) {
 | |
|     Status = gBS->CheckEvent (Private->PointerList[Index]->WaitForInput);
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       gBS->SignalEvent (Event);
 | |
|       Private->InputEventSignalState = TRUE;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Resets the pointer device hardware.
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  ExtendedVerification     Driver may perform diagnostics on reset.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The device was reset.
 | |
|   @retval EFI_DEVICE_ERROR         The device is not functioning correctly and
 | |
|                                    could not be reset.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterAbsolutePointerReset (
 | |
|   IN EFI_ABSOLUTE_POINTER_PROTOCOL   *This,
 | |
|   IN BOOLEAN                         ExtendedVerification
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   EFI_STATUS                    ReturnStatus;
 | |
|   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
 | |
|   UINTN                         Index;
 | |
| 
 | |
|   Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_ABSOLUTE_POINTER_THIS (This);
 | |
| 
 | |
|   Private->AbsoluteInputEventSignalState = FALSE;
 | |
| 
 | |
|   if (Private->CurrentNumberOfAbsolutePointers == 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
|   //
 | |
|   // return the worst status met
 | |
|   //
 | |
|   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {
 | |
|     Status = Private->AbsolutePointerList[Index]->Reset (
 | |
|                                                     Private->AbsolutePointerList[Index],
 | |
|                                                     ExtendedVerification
 | |
|                                                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ReturnStatus = Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ReturnStatus;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Retrieves the current state of a pointer device.
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  State                    A pointer to the state information on the
 | |
|                                    pointer device.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The state of the pointer device was returned in
 | |
|                                    State..
 | |
|   @retval EFI_NOT_READY            The state of the pointer device has not changed
 | |
|                                    since the last call to GetState().
 | |
|   @retval EFI_DEVICE_ERROR         A device error occurred while attempting to
 | |
|                                    retrieve the pointer device's current state.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterAbsolutePointerGetState (
 | |
|   IN EFI_ABSOLUTE_POINTER_PROTOCOL   *This,
 | |
|   IN OUT EFI_ABSOLUTE_POINTER_STATE  *State
 | |
|   )
 | |
| {
 | |
|   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
 | |
|   EFI_STATUS                    Status;
 | |
|   EFI_STATUS                    ReturnStatus;
 | |
|   UINTN                         Index;
 | |
|   EFI_ABSOLUTE_POINTER_STATE    CurrentState;
 | |
|   UINT64                        MinX;
 | |
|   UINT64                        MinY;
 | |
|   UINT64                        MinZ;
 | |
|   UINT64                        MaxX;
 | |
|   UINT64                        MaxY;
 | |
|   UINT64                        MaxZ;
 | |
|   UINT64                        VirtualMinX;
 | |
|   UINT64                        VirtualMinY;
 | |
|   UINT64                        VirtualMinZ;
 | |
|   UINT64                        VirtualMaxX;
 | |
|   UINT64                        VirtualMaxY;
 | |
|   UINT64                        VirtualMaxZ;
 | |
| 
 | |
|   Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_ABSOLUTE_POINTER_THIS (This);
 | |
| 
 | |
|   Private->AbsoluteInputEventSignalState = FALSE;
 | |
| 
 | |
|   State->CurrentX                        = 0;
 | |
|   State->CurrentY                        = 0;
 | |
|   State->CurrentZ                        = 0;
 | |
|   State->ActiveButtons                   = 0;
 | |
| 
 | |
|   VirtualMinX = Private->AbsolutePointerMode.AbsoluteMinX;
 | |
|   VirtualMinY = Private->AbsolutePointerMode.AbsoluteMinY;
 | |
|   VirtualMinZ = Private->AbsolutePointerMode.AbsoluteMinZ;
 | |
|   VirtualMaxX = Private->AbsolutePointerMode.AbsoluteMaxX;
 | |
|   VirtualMaxY = Private->AbsolutePointerMode.AbsoluteMaxY;
 | |
|   VirtualMaxZ = Private->AbsolutePointerMode.AbsoluteMaxZ;
 | |
| 
 | |
|   //
 | |
|   // if no physical pointer device exists, return EFI_NOT_READY;
 | |
|   // if any physical pointer device has changed state,
 | |
|   // return the state and EFI_SUCCESS.
 | |
|   //
 | |
|   ReturnStatus = EFI_NOT_READY;
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {
 | |
| 
 | |
|     Status = Private->AbsolutePointerList[Index]->GetState (
 | |
|                                                     Private->AbsolutePointerList[Index],
 | |
|                                                     &CurrentState
 | |
|                                                     );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       if (ReturnStatus == EFI_NOT_READY) {
 | |
|         ReturnStatus = EFI_SUCCESS;
 | |
|       }
 | |
| 
 | |
|       MinX = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinX;
 | |
|       MinY = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinY;
 | |
|       MinZ = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinZ;
 | |
|       MaxX = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxX;
 | |
|       MaxY = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxY;
 | |
|       MaxZ = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxZ;
 | |
| 
 | |
|       State->ActiveButtons = CurrentState.ActiveButtons;
 | |
| 
 | |
|       //
 | |
|       // Rescale to Con Splitter virtual Absolute Pointer's resolution.
 | |
|       //
 | |
|       if (!(MinX == 0 && MaxX == 0)) {
 | |
|         State->CurrentX = VirtualMinX + DivU64x64Remainder (
 | |
|                                           MultU64x64 (
 | |
|                                             CurrentState.CurrentX,
 | |
|                                             VirtualMaxX - VirtualMinX
 | |
|                                             ),
 | |
|                                           MaxX - MinX,
 | |
|                                           NULL
 | |
|                                           );
 | |
|       }
 | |
|       if (!(MinY == 0 && MaxY == 0)) {
 | |
|         State->CurrentY = VirtualMinY + DivU64x64Remainder (
 | |
|                                           MultU64x64 (
 | |
|                                             CurrentState.CurrentY,
 | |
|                                             VirtualMaxY - VirtualMinY
 | |
|                                             ),
 | |
|                                           MaxY - MinY,
 | |
|                                           NULL
 | |
|                                           );
 | |
|       }
 | |
|       if (!(MinZ == 0 && MaxZ == 0)) {
 | |
|         State->CurrentZ = VirtualMinZ + DivU64x64Remainder (
 | |
|                                           MultU64x64 (
 | |
|                                             CurrentState.CurrentZ,
 | |
|                                             VirtualMaxZ - VirtualMinZ
 | |
|                                             ),
 | |
|                                           MaxZ - MinZ,
 | |
|                                           NULL
 | |
|                                           );
 | |
|       }
 | |
| 
 | |
|     } else if (Status == EFI_DEVICE_ERROR) {
 | |
|       ReturnStatus = EFI_DEVICE_ERROR;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ReturnStatus;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This event agregates all the events of the pointer devices in the splitter.
 | |
|   If any events of physical pointer devices are signaled, signal the pointer
 | |
|   splitter event. This will cause the calling code to call
 | |
|   ConSplitterAbsolutePointerGetState ().
 | |
| 
 | |
|   @param  Event                    The Event assoicated with callback.
 | |
|   @param  Context                  Context registered when Event was created.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| ConSplitterAbsolutePointerWaitForInput (
 | |
|   IN  EFI_EVENT                       Event,
 | |
|   IN  VOID                            *Context
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
 | |
|   UINTN                         Index;
 | |
| 
 | |
|   Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context;
 | |
| 
 | |
|   //
 | |
|   // if AbsoluteInputEventSignalState is flagged before,
 | |
|   // and not cleared by Reset() or GetState(), signal it
 | |
|   //
 | |
|   if (Private->AbsoluteInputEventSignalState) {
 | |
|     gBS->SignalEvent (Event);
 | |
|     return ;
 | |
|   }
 | |
|   //
 | |
|   // if any physical console input device has key input, signal the event.
 | |
|   //
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {
 | |
|     Status = gBS->CheckEvent (Private->AbsolutePointerList[Index]->WaitForInput);
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       gBS->SignalEvent (Event);
 | |
|       Private->AbsoluteInputEventSignalState = TRUE;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Reset the text output device hardware and optionaly run diagnostics
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  ExtendedVerification     Driver may perform more exhaustive verfication
 | |
|                                    operation of the device during reset.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The text output device was reset.
 | |
|   @retval EFI_DEVICE_ERROR         The text output device is not functioning
 | |
|                                    correctly and could not be reset.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextOutReset (
 | |
|   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
 | |
|   IN  BOOLEAN                            ExtendedVerification
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
 | |
|   UINTN                           Index;
 | |
|   EFI_STATUS                      ReturnStatus;
 | |
| 
 | |
|   Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // return the worst status met
 | |
|   //
 | |
|   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
 | |
|     Status = Private->TextOutList[Index].TextOut->Reset (
 | |
|                                                     Private->TextOutList[Index].TextOut,
 | |
|                                                     ExtendedVerification
 | |
|                                                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ReturnStatus = Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BLACK));
 | |
| 
 | |
|   //
 | |
|   // reset all mode parameters
 | |
|   //
 | |
|   TextOutSetMode (Private, 0);
 | |
| 
 | |
|   return ReturnStatus;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Write a Unicode string to the output device.
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  WString                  The NULL-terminated Unicode string to be
 | |
|                                    displayed on the output device(s). All output
 | |
|                                    devices must also support the Unicode drawing
 | |
|                                    defined in this file.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The string was output to the device.
 | |
|   @retval EFI_DEVICE_ERROR         The device reported an error while attempting to
 | |
|                                    output the text.
 | |
|   @retval EFI_UNSUPPORTED          The output device's mode is not currently in a
 | |
|                                    defined text mode.
 | |
|   @retval EFI_WARN_UNKNOWN_GLYPH   This warning code indicates that some of the
 | |
|                                    characters in the Unicode string could not be
 | |
|                                    rendered and were skipped.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextOutOutputString (
 | |
|   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
 | |
|   IN  CHAR16                             *WString
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
 | |
|   UINTN                           Index;
 | |
|   EFI_STATUS                      ReturnStatus;
 | |
|   UINTN                           MaxColumn;
 | |
|   UINTN                           MaxRow;
 | |
| 
 | |
|   This->SetAttribute (This, This->Mode->Attribute);
 | |
| 
 | |
|   Private         = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // return the worst status met
 | |
|   //
 | |
|   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
 | |
|     Status = Private->TextOutList[Index].TextOut->OutputString (
 | |
|                                                     Private->TextOutList[Index].TextOut,
 | |
|                                                     WString
 | |
|                                                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ReturnStatus = Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (Private->CurrentNumberOfConsoles > 0) {
 | |
|     Private->TextOutMode.CursorColumn = Private->TextOutList[0].TextOut->Mode->CursorColumn;
 | |
|     Private->TextOutMode.CursorRow    = Private->TextOutList[0].TextOut->Mode->CursorRow;
 | |
|   } else {
 | |
|     //
 | |
|     // When there is no real console devices in system,
 | |
|     // update cursor position for the virtual device in consplitter.
 | |
|     //
 | |
|     Private->TextOut.QueryMode (
 | |
|                        &Private->TextOut,
 | |
|                        Private->TextOutMode.Mode,
 | |
|                        &MaxColumn,
 | |
|                        &MaxRow
 | |
|                        );
 | |
|     for (; *WString != CHAR_NULL; WString++) {
 | |
|       switch (*WString) {
 | |
|       case CHAR_BACKSPACE:
 | |
|         if (Private->TextOutMode.CursorColumn == 0 && Private->TextOutMode.CursorRow > 0) {
 | |
|           Private->TextOutMode.CursorRow--;
 | |
|           Private->TextOutMode.CursorColumn = (INT32) (MaxColumn - 1);
 | |
|         } else if (Private->TextOutMode.CursorColumn > 0) {
 | |
|           Private->TextOutMode.CursorColumn--;
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|       case CHAR_LINEFEED:
 | |
|         if (Private->TextOutMode.CursorRow < (INT32) (MaxRow - 1)) {
 | |
|           Private->TextOutMode.CursorRow++;
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|       case CHAR_CARRIAGE_RETURN:
 | |
|         Private->TextOutMode.CursorColumn = 0;
 | |
|         break;
 | |
| 
 | |
|       default:
 | |
|         if (Private->TextOutMode.CursorColumn < (INT32) (MaxColumn - 1)) {
 | |
|           Private->TextOutMode.CursorColumn++;
 | |
|         } else {
 | |
|           Private->TextOutMode.CursorColumn = 0;
 | |
|           if (Private->TextOutMode.CursorRow < (INT32) (MaxRow - 1)) {
 | |
|             Private->TextOutMode.CursorRow++;
 | |
|           }
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ReturnStatus;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Verifies that all characters in a Unicode string can be output to the
 | |
|   target device.
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  WString                  The NULL-terminated Unicode string to be
 | |
|                                    examined for the output device(s).
 | |
| 
 | |
|   @retval EFI_SUCCESS              The device(s) are capable of rendering the
 | |
|                                    output string.
 | |
|   @retval EFI_UNSUPPORTED          Some of the characters in the Unicode string
 | |
|                                    cannot be rendered by one or more of the output
 | |
|                                    devices mapped by the EFI handle.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextOutTestString (
 | |
|   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
 | |
|   IN  CHAR16                             *WString
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
 | |
|   UINTN                           Index;
 | |
|   EFI_STATUS                      ReturnStatus;
 | |
| 
 | |
|   Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // return the worst status met
 | |
|   //
 | |
|   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
 | |
|     Status = Private->TextOutList[Index].TextOut->TestString (
 | |
|                                                     Private->TextOutList[Index].TextOut,
 | |
|                                                     WString
 | |
|                                                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ReturnStatus = Status;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // There is no DevNullTextOutTestString () since a Unicode buffer would
 | |
|   // always return EFI_SUCCESS.
 | |
|   // ReturnStatus will be EFI_SUCCESS if no consoles are present
 | |
|   //
 | |
|   return ReturnStatus;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Returns information for an available text mode that the output device(s)
 | |
|   supports.
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  ModeNumber               The mode number to return information on.
 | |
|   @param  Columns                  Returns the columns of the text output device
 | |
|                                    for the requested ModeNumber.
 | |
|   @param  Rows                     Returns the rows of the text output device
 | |
|                                    for the requested ModeNumber.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The requested mode information was returned.
 | |
|   @retval EFI_DEVICE_ERROR         The device had an error and could not complete
 | |
|                                    the request.
 | |
|   @retval EFI_UNSUPPORTED          The mode number was not valid.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextOutQueryMode (
 | |
|   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
 | |
|   IN  UINTN                              ModeNumber,
 | |
|   OUT UINTN                              *Columns,
 | |
|   OUT UINTN                              *Rows
 | |
|   )
 | |
| {
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
 | |
|   UINTN                           CurrentMode;
 | |
|   INT32                           *TextOutModeMap;
 | |
| 
 | |
|   Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // Check whether param ModeNumber is valid.
 | |
|   // ModeNumber should be within range 0 ~ MaxMode - 1.
 | |
|   //
 | |
|   if ( (ModeNumber > (UINTN)(((UINT32)-1)>>1)) ) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   if ((INT32) ModeNumber >= This->Mode->MaxMode) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // We get the available mode from mode intersection map if it's available
 | |
|   //
 | |
|   if (Private->TextOutModeMap != NULL) {
 | |
|     TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber;
 | |
|     CurrentMode    = (UINTN)(*TextOutModeMap);
 | |
|     *Columns       = Private->TextOutQueryData[CurrentMode].Columns;
 | |
|     *Rows          = Private->TextOutQueryData[CurrentMode].Rows;
 | |
|   } else {
 | |
|     *Columns  = Private->TextOutQueryData[ModeNumber].Columns;
 | |
|     *Rows     = Private->TextOutQueryData[ModeNumber].Rows;
 | |
|   }
 | |
| 
 | |
|   if (*Columns <= 0 && *Rows <= 0) {
 | |
|     return EFI_UNSUPPORTED;
 | |
| 
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Sets the output device(s) to a specified mode.
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  ModeNumber               The mode number to set.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The requested text mode was set.
 | |
|   @retval EFI_DEVICE_ERROR         The device had an error and could not complete
 | |
|                                    the request.
 | |
|   @retval EFI_UNSUPPORTED          The mode number was not valid.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextOutSetMode (
 | |
|   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
 | |
|   IN  UINTN                              ModeNumber
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
 | |
|   UINTN                           Index;
 | |
|   INT32                           *TextOutModeMap;
 | |
|   EFI_STATUS                      ReturnStatus;
 | |
| 
 | |
|   Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // Check whether param ModeNumber is valid.
 | |
|   // ModeNumber should be within range 0 ~ MaxMode - 1.
 | |
|   //
 | |
|   if ( (ModeNumber > (UINTN)(((UINT32)-1)>>1)) ) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   if ((INT32) ModeNumber >= This->Mode->MaxMode) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
|   //
 | |
|   // If the mode is being set to the curent mode, then just clear the screen and return.
 | |
|   //
 | |
|   if (Private->TextOutMode.Mode == (INT32) ModeNumber) {
 | |
|     return ConSplitterTextOutClearScreen (This);
 | |
|   }
 | |
|   //
 | |
|   // return the worst status met
 | |
|   //
 | |
|   TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber;
 | |
|   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
 | |
|     Status = Private->TextOutList[Index].TextOut->SetMode (
 | |
|                                                     Private->TextOutList[Index].TextOut,
 | |
|                                                     TextOutModeMap[Index]
 | |
|                                                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ReturnStatus = Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set mode parameter to specified mode number
 | |
|   //
 | |
|   TextOutSetMode (Private, ModeNumber);
 | |
| 
 | |
|   return ReturnStatus;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Sets the background and foreground colors for the OutputString () and
 | |
|   ClearScreen () functions.
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  Attribute                The attribute to set. Bits 0..3 are the
 | |
|                                    foreground color, and bits 4..6 are the
 | |
|                                    background color. All other bits are undefined
 | |
|                                    and must be zero. The valid Attributes are
 | |
|                                    defined in this file.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The attribute was set.
 | |
|   @retval EFI_DEVICE_ERROR         The device had an error and could not complete
 | |
|                                    the request.
 | |
|   @retval EFI_UNSUPPORTED          The attribute requested is not defined.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextOutSetAttribute (
 | |
|   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
 | |
|   IN  UINTN                              Attribute
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
 | |
|   UINTN                           Index;
 | |
|   EFI_STATUS                      ReturnStatus;
 | |
| 
 | |
|   Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // Check whether param Attribute is valid.
 | |
|   //
 | |
|   if ((Attribute | 0x7F) != 0x7F) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // return the worst status met
 | |
|   //
 | |
|   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
 | |
|     Status = Private->TextOutList[Index].TextOut->SetAttribute (
 | |
|                                                     Private->TextOutList[Index].TextOut,
 | |
|                                                     Attribute
 | |
|                                                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ReturnStatus = Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Private->TextOutMode.Attribute = (INT32) Attribute;
 | |
| 
 | |
|   return ReturnStatus;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Clears the output device(s) display to the currently selected background
 | |
|   color.
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The operation completed successfully.
 | |
|   @retval EFI_DEVICE_ERROR         The device had an error and could not complete
 | |
|                                    the request.
 | |
|   @retval EFI_UNSUPPORTED          The output device is not in a valid text mode.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextOutClearScreen (
 | |
|   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
 | |
|   UINTN                           Index;
 | |
|   EFI_STATUS                      ReturnStatus;
 | |
| 
 | |
|   Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // return the worst status met
 | |
|   //
 | |
|   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
 | |
|     Status = Private->TextOutList[Index].TextOut->ClearScreen (Private->TextOutList[Index].TextOut);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ReturnStatus = Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // No need to do extra check here as whether (Column, Row) is valid has
 | |
|   // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should
 | |
|   // always be supported.
 | |
|   //
 | |
|   Private->TextOutMode.CursorColumn = 0;
 | |
|   Private->TextOutMode.CursorRow    = 0;
 | |
|   Private->TextOutMode.CursorVisible = TRUE;
 | |
| 
 | |
|   return ReturnStatus;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Sets the current coordinates of the cursor position
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  Column                   The column position to set the cursor to. Must be
 | |
|                                    greater than or equal to zero and less than the
 | |
|                                    number of columns by QueryMode ().
 | |
|   @param  Row                      The row position to set the cursor to. Must be
 | |
|                                    greater than or equal to zero and less than the
 | |
|                                    number of rows by QueryMode ().
 | |
| 
 | |
|   @retval EFI_SUCCESS              The operation completed successfully.
 | |
|   @retval EFI_DEVICE_ERROR         The device had an error and could not complete
 | |
|                                    the request.
 | |
|   @retval EFI_UNSUPPORTED          The output device is not in a valid text mode,
 | |
|                                    or the cursor position is invalid for the
 | |
|                                    current mode.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextOutSetCursorPosition (
 | |
|   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
 | |
|   IN  UINTN                              Column,
 | |
|   IN  UINTN                              Row
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
 | |
|   UINTN                           Index;
 | |
|   EFI_STATUS                      ReturnStatus;
 | |
|   UINTN                           MaxColumn;
 | |
|   UINTN                           MaxRow;
 | |
|   INT32                           *TextOutModeMap;
 | |
|   INT32                           ModeNumber;
 | |
|   INT32                           CurrentMode;
 | |
| 
 | |
|   Private   = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
|   TextOutModeMap  = NULL;
 | |
|   ModeNumber      = Private->TextOutMode.Mode;
 | |
| 
 | |
|   //
 | |
|   // Get current MaxColumn and MaxRow from intersection map
 | |
|   //
 | |
|   if (Private->TextOutModeMap != NULL) {
 | |
|     TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber;
 | |
|     CurrentMode    = *TextOutModeMap;
 | |
|   } else {
 | |
|     CurrentMode = ModeNumber;
 | |
|   }
 | |
| 
 | |
|   MaxColumn = Private->TextOutQueryData[CurrentMode].Columns;
 | |
|   MaxRow    = Private->TextOutQueryData[CurrentMode].Rows;
 | |
| 
 | |
|   if (Column >= MaxColumn || Row >= MaxRow) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
|   //
 | |
|   // return the worst status met
 | |
|   //
 | |
|   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
 | |
|     Status = Private->TextOutList[Index].TextOut->SetCursorPosition (
 | |
|                                                     Private->TextOutList[Index].TextOut,
 | |
|                                                     Column,
 | |
|                                                     Row
 | |
|                                                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ReturnStatus = Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // No need to do extra check here as whether (Column, Row) is valid has
 | |
|   // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should
 | |
|   // always be supported.
 | |
|   //
 | |
|   Private->TextOutMode.CursorColumn = (INT32) Column;
 | |
|   Private->TextOutMode.CursorRow    = (INT32) Row;
 | |
| 
 | |
|   return ReturnStatus;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Makes the cursor visible or invisible
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
|   @param  Visible                  If TRUE, the cursor is set to be visible. If
 | |
|                                    FALSE, the cursor is set to be invisible.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The operation completed successfully.
 | |
|   @retval EFI_DEVICE_ERROR         The device had an error and could not complete
 | |
|                                    the request, or the device does not support
 | |
|                                    changing the cursor mode.
 | |
|   @retval EFI_UNSUPPORTED          The output device is not in a valid text mode.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSplitterTextOutEnableCursor (
 | |
|   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
 | |
|   IN  BOOLEAN                            Visible
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
 | |
|   UINTN                           Index;
 | |
|   EFI_STATUS                      ReturnStatus;
 | |
| 
 | |
|   Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // return the worst status met
 | |
|   //
 | |
|   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
 | |
|     Status = Private->TextOutList[Index].TextOut->EnableCursor (
 | |
|                                                     Private->TextOutList[Index].TextOut,
 | |
|                                                     Visible
 | |
|                                                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ReturnStatus = Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Private->TextOutMode.CursorVisible = Visible;
 | |
| 
 | |
|   return ReturnStatus;
 | |
| }
 |