Home | History | Annotate | Download | only in ConSplitterDxe
      1 /** @file
      2   Console Splitter Driver. Any Handle that attatched console I/O protocols
      3   (Console In device, Console Out device, Console Error device, Simple Pointer
      4   protocol, Absolute Pointer protocol) can be bound by this driver.
      5 
      6   So far it works like any other driver by opening a SimpleTextIn and/or
      7   SimpleTextOut protocol with EFI_OPEN_PROTOCOL_BY_DRIVER attributes. The big
      8   difference is this driver does not layer a protocol on the passed in
      9   handle, or construct a child handle like a standard device or bus driver.
     10   This driver produces three virtual handles as children, one for console input
     11   splitter, one for console output splitter and one for error output splitter.
     12   These 3 virtual handles would be installed on gST.
     13 
     14   Each virtual handle, that supports the Console I/O protocol, will be produced
     15   in the driver entry point. The virtual handle are added on driver entry and
     16   never removed. Such design ensures sytem function well during none console
     17   device situation.
     18 
     19 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
     20 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
     21 This program and the accompanying materials
     22 are licensed and made available under the terms and conditions of the BSD License
     23 which accompanies this distribution.  The full text of the license may be found at
     24 http://opensource.org/licenses/bsd-license.php
     25 
     26 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     27 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     28 
     29 **/
     30 
     31 #include "ConSplitter.h"
     32 
     33 //
     34 // Identify if ConIn is connected in PcdConInConnectOnDemand enabled mode.
     35 // default not connect
     36 //
     37 BOOLEAN  mConInIsConnect = FALSE;
     38 
     39 //
     40 // Text In Splitter Private Data template
     41 //
     42 GLOBAL_REMOVE_IF_UNREFERENCED TEXT_IN_SPLITTER_PRIVATE_DATA  mConIn = {
     43   TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE,
     44   (EFI_HANDLE) NULL,
     45 
     46   {
     47     ConSplitterTextInReset,
     48     ConSplitterTextInReadKeyStroke,
     49     (EFI_EVENT) NULL
     50   },
     51   0,
     52   (EFI_SIMPLE_TEXT_INPUT_PROTOCOL **) NULL,
     53   0,
     54 
     55   {
     56     ConSplitterTextInResetEx,
     57     ConSplitterTextInReadKeyStrokeEx,
     58     (EFI_EVENT) NULL,
     59     ConSplitterTextInSetState,
     60     ConSplitterTextInRegisterKeyNotify,
     61     ConSplitterTextInUnregisterKeyNotify
     62   },
     63   0,
     64   (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL **) NULL,
     65   0,
     66   {
     67     (LIST_ENTRY *) NULL,
     68     (LIST_ENTRY *) NULL
     69   },
     70   0,
     71   FALSE,
     72 
     73   {
     74     ConSplitterSimplePointerReset,
     75     ConSplitterSimplePointerGetState,
     76     (EFI_EVENT) NULL,
     77     (EFI_SIMPLE_POINTER_MODE *) NULL
     78   },
     79   {
     80     0x10000,
     81     0x10000,
     82     0x10000,
     83     TRUE,
     84     TRUE
     85   },
     86   0,
     87   (EFI_SIMPLE_POINTER_PROTOCOL **) NULL,
     88   0,
     89 
     90   {
     91     ConSplitterAbsolutePointerReset,
     92     ConSplitterAbsolutePointerGetState,
     93     (EFI_EVENT) NULL,
     94     (EFI_ABSOLUTE_POINTER_MODE *) NULL
     95   },
     96   {
     97     0,       // AbsoluteMinX
     98     0,       // AbsoluteMinY
     99     0,       // AbsoluteMinZ
    100     0x10000, // AbsoluteMaxX
    101     0x10000, // AbsoluteMaxY
    102     0x10000, // AbsoluteMaxZ
    103     0        // Attributes
    104   },
    105   0,
    106   (EFI_ABSOLUTE_POINTER_PROTOCOL **) NULL,
    107   0,
    108   FALSE,
    109 
    110   FALSE,
    111   FALSE
    112 };
    113 
    114 
    115 //
    116 // Uga Draw Protocol Private Data template
    117 //
    118 GLOBAL_REMOVE_IF_UNREFERENCED EFI_UGA_DRAW_PROTOCOL mUgaDrawProtocolTemplate = {
    119   ConSplitterUgaDrawGetMode,
    120   ConSplitterUgaDrawSetMode,
    121   ConSplitterUgaDrawBlt
    122 };
    123 
    124 //
    125 // Graphics Output Protocol Private Data template
    126 //
    127 GLOBAL_REMOVE_IF_UNREFERENCED EFI_GRAPHICS_OUTPUT_PROTOCOL mGraphicsOutputProtocolTemplate = {
    128   ConSplitterGraphicsOutputQueryMode,
    129   ConSplitterGraphicsOutputSetMode,
    130   ConSplitterGraphicsOutputBlt,
    131   NULL
    132 };
    133 
    134 
    135 //
    136 // Text Out Splitter Private Data template
    137 //
    138 GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA mConOut = {
    139   TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE,
    140   (EFI_HANDLE) NULL,
    141   {
    142     ConSplitterTextOutReset,
    143     ConSplitterTextOutOutputString,
    144     ConSplitterTextOutTestString,
    145     ConSplitterTextOutQueryMode,
    146     ConSplitterTextOutSetMode,
    147     ConSplitterTextOutSetAttribute,
    148     ConSplitterTextOutClearScreen,
    149     ConSplitterTextOutSetCursorPosition,
    150     ConSplitterTextOutEnableCursor,
    151     (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL
    152   },
    153   {
    154     1,
    155     0,
    156     0,
    157     0,
    158     0,
    159     FALSE,
    160   },
    161 
    162   {
    163     NULL,
    164     NULL,
    165     NULL
    166   },
    167   0,
    168   0,
    169   0,
    170   0,
    171 
    172   {
    173     NULL,
    174     NULL,
    175     NULL,
    176     NULL
    177   },
    178   (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) NULL,
    179   0,
    180   0,
    181 
    182   0,
    183   (TEXT_OUT_AND_GOP_DATA *) NULL,
    184   0,
    185   (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL,
    186   0,
    187   (INT32 *) NULL
    188 };
    189 
    190 //
    191 // Standard Error Text Out Splitter Data Template
    192 //
    193 GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA mStdErr = {
    194   TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE,
    195   (EFI_HANDLE) NULL,
    196   {
    197     ConSplitterTextOutReset,
    198     ConSplitterTextOutOutputString,
    199     ConSplitterTextOutTestString,
    200     ConSplitterTextOutQueryMode,
    201     ConSplitterTextOutSetMode,
    202     ConSplitterTextOutSetAttribute,
    203     ConSplitterTextOutClearScreen,
    204     ConSplitterTextOutSetCursorPosition,
    205     ConSplitterTextOutEnableCursor,
    206     (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL
    207   },
    208   {
    209     1,
    210     0,
    211     0,
    212     0,
    213     0,
    214     FALSE,
    215   },
    216 
    217   {
    218     NULL,
    219     NULL,
    220     NULL
    221   },
    222   0,
    223   0,
    224   0,
    225   0,
    226 
    227   {
    228     NULL,
    229     NULL,
    230     NULL,
    231     NULL
    232   },
    233   (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) NULL,
    234   0,
    235   0,
    236 
    237   0,
    238   (TEXT_OUT_AND_GOP_DATA *) NULL,
    239   0,
    240   (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL,
    241   0,
    242   (INT32 *) NULL
    243 };
    244 
    245 //
    246 // Driver binding instance for Console Input Device
    247 //
    248 EFI_DRIVER_BINDING_PROTOCOL           gConSplitterConInDriverBinding = {
    249   ConSplitterConInDriverBindingSupported,
    250   ConSplitterConInDriverBindingStart,
    251   ConSplitterConInDriverBindingStop,
    252   0xa,
    253   NULL,
    254   NULL
    255 };
    256 
    257 //
    258 // Driver binding instance for Console Out device
    259 //
    260 EFI_DRIVER_BINDING_PROTOCOL           gConSplitterConOutDriverBinding = {
    261   ConSplitterConOutDriverBindingSupported,
    262   ConSplitterConOutDriverBindingStart,
    263   ConSplitterConOutDriverBindingStop,
    264   0xa,
    265   NULL,
    266   NULL
    267 };
    268 
    269 //
    270 // Driver binding instance for Standard Error device
    271 //
    272 EFI_DRIVER_BINDING_PROTOCOL           gConSplitterStdErrDriverBinding = {
    273   ConSplitterStdErrDriverBindingSupported,
    274   ConSplitterStdErrDriverBindingStart,
    275   ConSplitterStdErrDriverBindingStop,
    276   0xa,
    277   NULL,
    278   NULL
    279 };
    280 
    281 //
    282 // Driver binding instance for Simple Pointer protocol
    283 //
    284 EFI_DRIVER_BINDING_PROTOCOL           gConSplitterSimplePointerDriverBinding = {
    285   ConSplitterSimplePointerDriverBindingSupported,
    286   ConSplitterSimplePointerDriverBindingStart,
    287   ConSplitterSimplePointerDriverBindingStop,
    288   0xa,
    289   NULL,
    290   NULL
    291 };
    292 
    293 //
    294 // Driver binding instance for Absolute Pointer protocol
    295 //
    296 EFI_DRIVER_BINDING_PROTOCOL           gConSplitterAbsolutePointerDriverBinding = {
    297   ConSplitterAbsolutePointerDriverBindingSupported,
    298   ConSplitterAbsolutePointerDriverBindingStart,
    299   ConSplitterAbsolutePointerDriverBindingStop,
    300   0xa,
    301   NULL,
    302   NULL
    303 };
    304 
    305 /**
    306   Key notify for toggle state sync.
    307 
    308   @param KeyData        A pointer to a buffer that is filled in with
    309                         the keystroke information for the key that was
    310                         pressed.
    311 
    312   @retval EFI_SUCCESS   Toggle state sync successfully.
    313 
    314 **/
    315 EFI_STATUS
    316 EFIAPI
    317 ToggleStateSyncKeyNotify (
    318   IN EFI_KEY_DATA   *KeyData
    319   )
    320 {
    321   UINTN     Index;
    322 
    323   if (((KeyData->KeyState.KeyToggleState & KEY_STATE_VALID_EXPOSED) == KEY_STATE_VALID_EXPOSED) &&
    324       (KeyData->KeyState.KeyToggleState != mConIn.PhysicalKeyToggleState)) {
    325     //
    326     // There is toggle state change, sync to other console input devices.
    327     //
    328     for (Index = 0; Index < mConIn.CurrentNumberOfExConsoles; Index++) {
    329       mConIn.TextInExList[Index]->SetState (
    330                                     mConIn.TextInExList[Index],
    331                                     &KeyData->KeyState.KeyToggleState
    332                                     );
    333     }
    334     mConIn.PhysicalKeyToggleState = KeyData->KeyState.KeyToggleState;
    335     DEBUG ((EFI_D_INFO, "Current toggle state is 0x%02x\n", mConIn.PhysicalKeyToggleState));
    336   }
    337 
    338   return EFI_SUCCESS;
    339 }
    340 
    341 /**
    342   Initialization for toggle state sync.
    343 
    344   @param Private                    Text In Splitter pointer.
    345 
    346 **/
    347 VOID
    348 ToggleStateSyncInitialization (
    349   IN TEXT_IN_SPLITTER_PRIVATE_DATA  *Private
    350   )
    351 {
    352   EFI_KEY_DATA      KeyData;
    353   VOID              *NotifyHandle;
    354 
    355   //
    356   // Initialize PhysicalKeyToggleState that will be synced to new console
    357   // input device to turn on physical TextInEx partial key report for
    358   // toggle state sync.
    359   //
    360   Private->PhysicalKeyToggleState = KEY_STATE_VALID_EXPOSED;
    361 
    362   //
    363   // Initialize VirtualKeyStateExported to let the virtual TextInEx not report
    364   // the partial key even though the physical TextInEx turns on the partial
    365   // key report. The virtual TextInEx will report the partial key after it is
    366   // required by calling SetState(X | KEY_STATE_VALID_EXPOSED) explicitly.
    367   //
    368   Private->VirtualKeyStateExported = FALSE;
    369 
    370   //
    371   // Register key notify for toggle state sync.
    372   //
    373   KeyData.Key.ScanCode = SCAN_NULL;
    374   KeyData.Key.UnicodeChar = CHAR_NULL;
    375   KeyData.KeyState.KeyShiftState = 0;
    376   KeyData.KeyState.KeyToggleState = 0;
    377   Private->TextInEx.RegisterKeyNotify (
    378                       &Private->TextInEx,
    379                       &KeyData,
    380                       ToggleStateSyncKeyNotify,
    381                       &NotifyHandle
    382                       );
    383 }
    384 
    385 /**
    386   Reinitialization for toggle state sync.
    387 
    388   @param Private                    Text In Splitter pointer.
    389 
    390 **/
    391 VOID
    392 ToggleStateSyncReInitialization (
    393   IN TEXT_IN_SPLITTER_PRIVATE_DATA  *Private
    394   )
    395 {
    396   UINTN             Index;
    397 
    398   //
    399   // Reinitialize PhysicalKeyToggleState that will be synced to new console
    400   // input device to turn on physical TextInEx partial key report for
    401   // toggle state sync.
    402   //
    403   Private->PhysicalKeyToggleState = KEY_STATE_VALID_EXPOSED;
    404 
    405   //
    406   // Reinitialize VirtualKeyStateExported to let the virtual TextInEx not report
    407   // the partial key even though the physical TextInEx turns on the partial
    408   // key report. The virtual TextInEx will report the partial key after it is
    409   // required by calling SetState(X | KEY_STATE_VALID_EXPOSED) explicitly.
    410   //
    411   Private->VirtualKeyStateExported = FALSE;
    412 
    413   for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
    414     Private->TextInExList[Index]->SetState (
    415                                     Private->TextInExList[Index],
    416                                     &Private->PhysicalKeyToggleState
    417                                     );
    418   }
    419 }
    420 
    421 /**
    422   The Entry Point for module ConSplitter. The user code starts with this function.
    423 
    424   Installs driver module protocols and. Creates virtual device handles for ConIn,
    425   ConOut, and StdErr. Installs Simple Text In protocol, Simple Text In Ex protocol,
    426   Simple Pointer protocol, Absolute Pointer protocol on those virtual handlers.
    427   Installs Graphics Output protocol and/or UGA Draw protocol if needed.
    428 
    429   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
    430   @param[in] SystemTable    A pointer to the EFI System Table.
    431 
    432   @retval EFI_SUCCESS       The entry point is executed successfully.
    433   @retval other             Some error occurs when executing this entry point.
    434 
    435 **/
    436 EFI_STATUS
    437 EFIAPI
    438 ConSplitterDriverEntry(
    439   IN EFI_HANDLE           ImageHandle,
    440   IN EFI_SYSTEM_TABLE     *SystemTable
    441   )
    442 {
    443   EFI_STATUS              Status;
    444 
    445   //
    446   // Install driver model protocol(s).
    447   //
    448   Status = EfiLibInstallDriverBindingComponentName2 (
    449              ImageHandle,
    450              SystemTable,
    451              &gConSplitterConInDriverBinding,
    452              ImageHandle,
    453              &gConSplitterConInComponentName,
    454              &gConSplitterConInComponentName2
    455              );
    456   ASSERT_EFI_ERROR (Status);
    457 
    458   Status = EfiLibInstallDriverBindingComponentName2 (
    459              ImageHandle,
    460              SystemTable,
    461              &gConSplitterSimplePointerDriverBinding,
    462              NULL,
    463              &gConSplitterSimplePointerComponentName,
    464              &gConSplitterSimplePointerComponentName2
    465              );
    466   ASSERT_EFI_ERROR (Status);
    467 
    468   Status = EfiLibInstallDriverBindingComponentName2 (
    469              ImageHandle,
    470              SystemTable,
    471              &gConSplitterAbsolutePointerDriverBinding,
    472              NULL,
    473              &gConSplitterAbsolutePointerComponentName,
    474              &gConSplitterAbsolutePointerComponentName2
    475              );
    476   ASSERT_EFI_ERROR (Status);
    477 
    478   Status = EfiLibInstallDriverBindingComponentName2 (
    479              ImageHandle,
    480              SystemTable,
    481              &gConSplitterConOutDriverBinding,
    482              NULL,
    483              &gConSplitterConOutComponentName,
    484              &gConSplitterConOutComponentName2
    485              );
    486   ASSERT_EFI_ERROR (Status);
    487 
    488   Status = EfiLibInstallDriverBindingComponentName2 (
    489              ImageHandle,
    490              SystemTable,
    491              &gConSplitterStdErrDriverBinding,
    492              NULL,
    493              &gConSplitterStdErrComponentName,
    494              &gConSplitterStdErrComponentName2
    495              );
    496   ASSERT_EFI_ERROR (Status);
    497 
    498   //
    499   // Either Graphics Output protocol or UGA Draw protocol must be supported.
    500   //
    501   ASSERT (FeaturePcdGet (PcdConOutGopSupport) ||
    502           FeaturePcdGet (PcdConOutUgaSupport));
    503 
    504   //
    505   // The driver creates virtual handles for ConIn, ConOut, StdErr.
    506   // The virtual handles will always exist even if no console exist in the
    507   // system. This is need to support hotplug devices like USB.
    508   //
    509   //
    510   // Create virtual device handle for ConIn Splitter
    511   //
    512   Status = ConSplitterTextInConstructor (&mConIn);
    513   if (!EFI_ERROR (Status)) {
    514     Status = gBS->InstallMultipleProtocolInterfaces (
    515                     &mConIn.VirtualHandle,
    516                     &gEfiSimpleTextInProtocolGuid,
    517                     &mConIn.TextIn,
    518                     &gEfiSimpleTextInputExProtocolGuid,
    519                     &mConIn.TextInEx,
    520                     &gEfiSimplePointerProtocolGuid,
    521                     &mConIn.SimplePointer,
    522                     &gEfiAbsolutePointerProtocolGuid,
    523                     &mConIn.AbsolutePointer,
    524                     NULL
    525                     );
    526     if (!EFI_ERROR (Status)) {
    527       //
    528       // Update the EFI System Table with new virtual console
    529       // and update the pointer to Simple Text Input protocol.
    530       //
    531       gST->ConsoleInHandle  = mConIn.VirtualHandle;
    532       gST->ConIn            = &mConIn.TextIn;
    533     }
    534   }
    535   //
    536   // Create virtual device handle for ConOut Splitter
    537   //
    538   Status = ConSplitterTextOutConstructor (&mConOut);
    539   if (!EFI_ERROR (Status)) {
    540     Status = gBS->InstallMultipleProtocolInterfaces (
    541                     &mConOut.VirtualHandle,
    542                     &gEfiSimpleTextOutProtocolGuid,
    543                     &mConOut.TextOut,
    544                     NULL
    545                     );
    546     if (!EFI_ERROR (Status)) {
    547       //
    548       // Update the EFI System Table with new virtual console
    549       // and Update the pointer to Text Output protocol.
    550       //
    551       gST->ConsoleOutHandle = mConOut.VirtualHandle;
    552       gST->ConOut           = &mConOut.TextOut;
    553     }
    554 
    555   }
    556 
    557   //
    558   // Create virtual device handle for StdErr Splitter
    559   //
    560   Status = ConSplitterTextOutConstructor (&mStdErr);
    561   if (!EFI_ERROR (Status)) {
    562     Status = gBS->InstallMultipleProtocolInterfaces (
    563                     &mStdErr.VirtualHandle,
    564                     &gEfiSimpleTextOutProtocolGuid,
    565                     &mStdErr.TextOut,
    566                     NULL
    567                     );
    568     if (!EFI_ERROR (Status)) {
    569       //
    570       // Update the EFI System Table with new virtual console
    571       // and update the pointer to Text Output protocol.
    572       //
    573       gST->StandardErrorHandle  = mStdErr.VirtualHandle;
    574       gST->StdErr               = &mStdErr.TextOut;
    575     }
    576   }
    577 
    578   //
    579   // Update the CRC32 in the EFI System Table header
    580   //
    581   gST->Hdr.CRC32 = 0;
    582   gBS->CalculateCrc32 (
    583         (UINT8 *) &gST->Hdr,
    584         gST->Hdr.HeaderSize,
    585         &gST->Hdr.CRC32
    586         );
    587 
    588   return EFI_SUCCESS;
    589 
    590 }
    591 
    592 /**
    593   Construct console input devices' private data.
    594 
    595   @param  ConInPrivate             A pointer to the TEXT_IN_SPLITTER_PRIVATE_DATA
    596                                    structure.
    597 
    598   @retval EFI_OUT_OF_RESOURCES     Out of resources.
    599   @retval EFI_SUCCESS              Text Input Devcie's private data has been constructed.
    600   @retval other                    Failed to construct private data.
    601 
    602 **/
    603 EFI_STATUS
    604 ConSplitterTextInConstructor (
    605   TEXT_IN_SPLITTER_PRIVATE_DATA       *ConInPrivate
    606   )
    607 {
    608   EFI_STATUS  Status;
    609 
    610   //
    611   // Allocate buffer for Simple Text Input device
    612   //
    613   Status = ConSplitterGrowBuffer (
    614             sizeof (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *),
    615             &ConInPrivate->TextInListCount,
    616             (VOID **) &ConInPrivate->TextInList
    617             );
    618   if (EFI_ERROR (Status)) {
    619     return EFI_OUT_OF_RESOURCES;
    620   }
    621 
    622   //
    623   // Create Event to wait for a key
    624   //
    625   Status = gBS->CreateEvent (
    626                   EVT_NOTIFY_WAIT,
    627                   TPL_NOTIFY,
    628                   ConSplitterTextInWaitForKey,
    629                   ConInPrivate,
    630                   &ConInPrivate->TextIn.WaitForKey
    631                   );
    632   ASSERT_EFI_ERROR (Status);
    633 
    634   //
    635   // Allocate buffer for Simple Text Input Ex device
    636   //
    637   Status = ConSplitterGrowBuffer (
    638              sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *),
    639              &ConInPrivate->TextInExListCount,
    640              (VOID **) &ConInPrivate->TextInExList
    641              );
    642   if (EFI_ERROR (Status)) {
    643     return EFI_OUT_OF_RESOURCES;
    644   }
    645   //
    646   // Create Event to wait for a key Ex
    647   //
    648   Status = gBS->CreateEvent (
    649                   EVT_NOTIFY_WAIT,
    650                   TPL_NOTIFY,
    651                   ConSplitterTextInWaitForKey,
    652                   ConInPrivate,
    653                   &ConInPrivate->TextInEx.WaitForKeyEx
    654                   );
    655   ASSERT_EFI_ERROR (Status);
    656 
    657   InitializeListHead (&ConInPrivate->NotifyList);
    658 
    659   ToggleStateSyncInitialization (ConInPrivate);
    660 
    661   ConInPrivate->AbsolutePointer.Mode = &ConInPrivate->AbsolutePointerMode;
    662   //
    663   // Allocate buffer for Absolute Pointer device
    664   //
    665   Status = ConSplitterGrowBuffer (
    666             sizeof (EFI_ABSOLUTE_POINTER_PROTOCOL *),
    667             &ConInPrivate->AbsolutePointerListCount,
    668             (VOID **) &ConInPrivate->AbsolutePointerList
    669             );
    670   if (EFI_ERROR (Status)) {
    671     return EFI_OUT_OF_RESOURCES;
    672   }
    673   //
    674   // Create Event to wait for device input for Absolute pointer device
    675   //
    676   Status = gBS->CreateEvent (
    677             EVT_NOTIFY_WAIT,
    678             TPL_NOTIFY,
    679             ConSplitterAbsolutePointerWaitForInput,
    680             ConInPrivate,
    681             &ConInPrivate->AbsolutePointer.WaitForInput
    682         );
    683   ASSERT_EFI_ERROR (Status);
    684 
    685   ConInPrivate->SimplePointer.Mode = &ConInPrivate->SimplePointerMode;
    686   //
    687   // Allocate buffer for Simple Pointer device
    688   //
    689   Status = ConSplitterGrowBuffer (
    690             sizeof (EFI_SIMPLE_POINTER_PROTOCOL *),
    691             &ConInPrivate->PointerListCount,
    692             (VOID **) &ConInPrivate->PointerList
    693             );
    694   if (EFI_ERROR (Status)) {
    695     return EFI_OUT_OF_RESOURCES;
    696   }
    697   //
    698   // Create Event to wait for device input for Simple pointer device
    699   //
    700   Status = gBS->CreateEvent (
    701                   EVT_NOTIFY_WAIT,
    702                   TPL_NOTIFY,
    703                   ConSplitterSimplePointerWaitForInput,
    704                   ConInPrivate,
    705                   &ConInPrivate->SimplePointer.WaitForInput
    706                   );
    707   ASSERT_EFI_ERROR (Status);
    708   //
    709   // Create Event to signal ConIn connection request
    710   //
    711   Status = gBS->CreateEventEx (
    712                   EVT_NOTIFY_SIGNAL,
    713                   TPL_CALLBACK,
    714                   ConSplitterEmptyCallbackFunction,
    715                   NULL,
    716                   &gConnectConInEventGuid,
    717                   &ConInPrivate->ConnectConInEvent
    718                   );
    719 
    720   return Status;
    721 }
    722 
    723 /**
    724   Construct console output devices' private data.
    725 
    726   @param  ConOutPrivate            A pointer to the TEXT_OUT_SPLITTER_PRIVATE_DATA
    727                                    structure.
    728 
    729   @retval EFI_OUT_OF_RESOURCES     Out of resources.
    730   @retval EFI_SUCCESS              Text Input Devcie's private data has been constructed.
    731 
    732 **/
    733 EFI_STATUS
    734 ConSplitterTextOutConstructor (
    735   TEXT_OUT_SPLITTER_PRIVATE_DATA      *ConOutPrivate
    736   )
    737 {
    738   EFI_STATUS  Status;
    739   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;
    740 
    741   //
    742   // Copy protocols template
    743   //
    744   if (FeaturePcdGet (PcdConOutUgaSupport)) {
    745     CopyMem (&ConOutPrivate->UgaDraw, &mUgaDrawProtocolTemplate, sizeof (EFI_UGA_DRAW_PROTOCOL));
    746   }
    747   if (FeaturePcdGet (PcdConOutGopSupport)) {
    748     CopyMem (&ConOutPrivate->GraphicsOutput, &mGraphicsOutputProtocolTemplate, sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL));
    749   }
    750 
    751   //
    752   // Initilize console output splitter's private data.
    753   //
    754   ConOutPrivate->TextOut.Mode = &ConOutPrivate->TextOutMode;
    755 
    756   //
    757   // When new console device is added, the new mode will be set later,
    758   // so put current mode back to init state.
    759   //
    760   ConOutPrivate->TextOutMode.Mode = 0xFF;
    761   //
    762   // Allocate buffer for Console Out device
    763   //
    764   Status = ConSplitterGrowBuffer (
    765             sizeof (TEXT_OUT_AND_GOP_DATA),
    766             &ConOutPrivate->TextOutListCount,
    767             (VOID **) &ConOutPrivate->TextOutList
    768             );
    769   if (EFI_ERROR (Status)) {
    770     return EFI_OUT_OF_RESOURCES;
    771   }
    772   //
    773   // Allocate buffer for Text Out query data
    774   //
    775   Status = ConSplitterGrowBuffer (
    776             sizeof (TEXT_OUT_SPLITTER_QUERY_DATA),
    777             &ConOutPrivate->TextOutQueryDataCount,
    778             (VOID **) &ConOutPrivate->TextOutQueryData
    779             );
    780   if (EFI_ERROR (Status)) {
    781     return EFI_OUT_OF_RESOURCES;
    782   }
    783 
    784   //
    785   // Setup the default console to 80 x 25 and mode to 0
    786   //
    787   ConOutPrivate->TextOutQueryData[0].Columns  = 80;
    788   ConOutPrivate->TextOutQueryData[0].Rows     = 25;
    789   TextOutSetMode (ConOutPrivate, 0);
    790 
    791 
    792   if (FeaturePcdGet (PcdConOutUgaSupport)) {
    793     //
    794     // Setup the UgaDraw to 800 x 600 x 32 bits per pixel, 60Hz.
    795     //
    796     ConSplitterUgaDrawSetMode (&ConOutPrivate->UgaDraw, 800, 600, 32, 60);
    797   }
    798   if (FeaturePcdGet (PcdConOutGopSupport)) {
    799     //
    800     // Setup resource for mode information in Graphics Output Protocol interface
    801     //
    802     if ((ConOutPrivate->GraphicsOutput.Mode = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE))) == NULL) {
    803       return EFI_OUT_OF_RESOURCES;
    804     }
    805     if ((ConOutPrivate->GraphicsOutput.Mode->Info = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION))) == NULL) {
    806       return EFI_OUT_OF_RESOURCES;
    807     }
    808     //
    809     // Setup the DevNullGraphicsOutput to 800 x 600 x 32 bits per pixel
    810     // DevNull will be updated to user-defined mode after driver has started.
    811     //
    812     if ((ConOutPrivate->GraphicsOutputModeBuffer = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION))) == NULL) {
    813       return EFI_OUT_OF_RESOURCES;
    814     }
    815     Info = &ConOutPrivate->GraphicsOutputModeBuffer[0];
    816     Info->Version = 0;
    817     Info->HorizontalResolution = 800;
    818     Info->VerticalResolution = 600;
    819     Info->PixelFormat = PixelBltOnly;
    820     Info->PixelsPerScanLine = 800;
    821     CopyMem (ConOutPrivate->GraphicsOutput.Mode->Info, Info, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
    822     ConOutPrivate->GraphicsOutput.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
    823 
    824     //
    825     // Initialize the following items, theset items remain unchanged in GraphicsOutput->SetMode()
    826     // GraphicsOutputMode->FrameBufferBase, GraphicsOutputMode->FrameBufferSize
    827     //
    828     ConOutPrivate->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;
    829     ConOutPrivate->GraphicsOutput.Mode->FrameBufferSize = 0;
    830 
    831     ConOutPrivate->GraphicsOutput.Mode->MaxMode = 1;
    832     //
    833     // Initial current mode to unknown state, and then set to mode 0
    834     //
    835     ConOutPrivate->GraphicsOutput.Mode->Mode = 0xffff;
    836     ConOutPrivate->GraphicsOutput.SetMode (&ConOutPrivate->GraphicsOutput, 0);
    837   }
    838 
    839   return EFI_SUCCESS;
    840 }
    841 
    842 
    843 /**
    844   Test to see if the specified protocol could be supported on the specified device.
    845 
    846   @param  This                Driver Binding protocol pointer.
    847   @param  ControllerHandle    Handle of device to test.
    848   @param  Guid                The specified protocol.
    849 
    850   @retval EFI_SUCCESS         The specified protocol is supported on this device.
    851   @retval EFI_UNSUPPORTED     The specified protocol attempts to be installed on virtul handle.
    852   @retval other               Failed to open specified protocol on this device.
    853 
    854 **/
    855 EFI_STATUS
    856 ConSplitterSupported (
    857   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
    858   IN  EFI_HANDLE                      ControllerHandle,
    859   IN  EFI_GUID                        *Guid
    860   )
    861 {
    862   EFI_STATUS  Status;
    863   VOID        *Instance;
    864 
    865   //
    866   // Make sure the Console Splitter does not attempt to attach to itself
    867   //
    868   if (ControllerHandle == mConIn.VirtualHandle  ||
    869       ControllerHandle == mConOut.VirtualHandle ||
    870       ControllerHandle == mStdErr.VirtualHandle
    871       ) {
    872     return EFI_UNSUPPORTED;
    873   }
    874 
    875   //
    876   // Check to see whether the specific protocol could be opened BY_DRIVER
    877   //
    878   Status = gBS->OpenProtocol (
    879                   ControllerHandle,
    880                   Guid,
    881                   &Instance,
    882                   This->DriverBindingHandle,
    883                   ControllerHandle,
    884                   EFI_OPEN_PROTOCOL_BY_DRIVER
    885                   );
    886 
    887   if (EFI_ERROR (Status)) {
    888     return Status;
    889   }
    890 
    891   gBS->CloseProtocol (
    892         ControllerHandle,
    893         Guid,
    894         This->DriverBindingHandle,
    895         ControllerHandle
    896         );
    897 
    898   return EFI_SUCCESS;
    899 }
    900 
    901 /**
    902   Test to see if Console In Device could be supported on the Controller.
    903 
    904   @param  This                Driver Binding protocol instance pointer.
    905   @param  ControllerHandle    Handle of device to test.
    906   @param  RemainingDevicePath Optional parameter use to pick a specific child
    907                               device to start.
    908 
    909   @retval EFI_SUCCESS         This driver supports this device.
    910   @retval other               This driver does not support this device.
    911 
    912 **/
    913 EFI_STATUS
    914 EFIAPI
    915 ConSplitterConInDriverBindingSupported (
    916   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
    917   IN  EFI_HANDLE                      ControllerHandle,
    918   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
    919   )
    920 {
    921   return ConSplitterSupported (
    922           This,
    923           ControllerHandle,
    924           &gEfiConsoleInDeviceGuid
    925           );
    926 }
    927 
    928 /**
    929   Test to see if Simple Pointer protocol could be supported on the Controller.
    930 
    931   @param  This                Driver Binding protocol instance pointer.
    932   @param  ControllerHandle    Handle of device to test.
    933   @param  RemainingDevicePath Optional parameter use to pick a specific child
    934                               device to start.
    935 
    936   @retval EFI_SUCCESS         This driver supports this device.
    937   @retval other               This driver does not support this device.
    938 
    939 **/
    940 EFI_STATUS
    941 EFIAPI
    942 ConSplitterSimplePointerDriverBindingSupported (
    943   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
    944   IN  EFI_HANDLE                      ControllerHandle,
    945   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
    946   )
    947 {
    948   return ConSplitterSupported (
    949           This,
    950           ControllerHandle,
    951           &gEfiSimplePointerProtocolGuid
    952           );
    953 }
    954 
    955 /**
    956   Test to see if Absolute Pointer protocol could be supported on the Controller.
    957 
    958   @param  This                Driver Binding protocol instance pointer.
    959   @param  ControllerHandle    Handle of device to test.
    960   @param  RemainingDevicePath Optional parameter use to pick a specific child
    961                               device to start.
    962 
    963   @retval EFI_SUCCESS         This driver supports this device.
    964   @retval other               This driver does not support this device.
    965 
    966 **/
    967 EFI_STATUS
    968 EFIAPI
    969 ConSplitterAbsolutePointerDriverBindingSupported (
    970   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
    971   IN  EFI_HANDLE                      ControllerHandle,
    972   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
    973   )
    974 {
    975   return ConSplitterSupported (
    976           This,
    977           ControllerHandle,
    978           &gEfiAbsolutePointerProtocolGuid
    979           );
    980 }
    981 
    982 
    983 /**
    984   Test to see if Console Out Device could be supported on the Controller.
    985 
    986   @param  This                Driver Binding protocol instance pointer.
    987   @param  ControllerHandle    Handle of device to test.
    988   @param  RemainingDevicePath Optional parameter use to pick a specific child
    989                               device to start.
    990 
    991   @retval EFI_SUCCESS         This driver supports this device.
    992   @retval other               This driver does not support this device.
    993 
    994 **/
    995 EFI_STATUS
    996 EFIAPI
    997 ConSplitterConOutDriverBindingSupported (
    998   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
    999   IN  EFI_HANDLE                      ControllerHandle,
   1000   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
   1001   )
   1002 {
   1003   return ConSplitterSupported (
   1004           This,
   1005           ControllerHandle,
   1006           &gEfiConsoleOutDeviceGuid
   1007           );
   1008 }
   1009 
   1010 /**
   1011   Test to see if Standard Error Device could be supported on the Controller.
   1012 
   1013   @param  This                Driver Binding protocol instance pointer.
   1014   @param  ControllerHandle    Handle of device to test.
   1015   @param  RemainingDevicePath Optional parameter use to pick a specific child
   1016                               device to start.
   1017 
   1018   @retval EFI_SUCCESS         This driver supports this device.
   1019   @retval other               This driver does not support this device.
   1020 
   1021 **/
   1022 EFI_STATUS
   1023 EFIAPI
   1024 ConSplitterStdErrDriverBindingSupported (
   1025   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
   1026   IN  EFI_HANDLE                      ControllerHandle,
   1027   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
   1028   )
   1029 {
   1030   return ConSplitterSupported (
   1031           This,
   1032           ControllerHandle,
   1033           &gEfiStandardErrorDeviceGuid
   1034           );
   1035 }
   1036 
   1037 
   1038 /**
   1039   Start ConSplitter on devcie handle by opening Console Device Guid on device handle
   1040   and the console virtual handle. And Get the console interface on controller handle.
   1041 
   1042   @param  This                      Driver Binding protocol instance pointer.
   1043   @param  ControllerHandle          Handle of device.
   1044   @param  ConSplitterVirtualHandle  Console virtual Handle.
   1045   @param  DeviceGuid                The specified Console Device, such as ConInDev,
   1046                                     ConOutDev.
   1047   @param  InterfaceGuid             The specified protocol to be opened.
   1048   @param  Interface                 Protocol interface returned.
   1049 
   1050   @retval EFI_SUCCESS               This driver supports this device.
   1051   @retval other                     Failed to open the specified Console Device Guid
   1052                                     or specified protocol.
   1053 
   1054 **/
   1055 EFI_STATUS
   1056 ConSplitterStart (
   1057   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
   1058   IN  EFI_HANDLE                      ControllerHandle,
   1059   IN  EFI_HANDLE                      ConSplitterVirtualHandle,
   1060   IN  EFI_GUID                        *DeviceGuid,
   1061   IN  EFI_GUID                        *InterfaceGuid,
   1062   OUT VOID                            **Interface
   1063   )
   1064 {
   1065   EFI_STATUS  Status;
   1066   VOID        *Instance;
   1067 
   1068   //
   1069   // Check to see whether the ControllerHandle has the DeviceGuid on it.
   1070   //
   1071   Status = gBS->OpenProtocol (
   1072                   ControllerHandle,
   1073                   DeviceGuid,
   1074                   &Instance,
   1075                   This->DriverBindingHandle,
   1076                   ControllerHandle,
   1077                   EFI_OPEN_PROTOCOL_BY_DRIVER
   1078                   );
   1079   if (EFI_ERROR (Status)) {
   1080     return Status;
   1081   }
   1082 
   1083   //
   1084   // Open the Parent Handle for the child.
   1085   //
   1086   Status = gBS->OpenProtocol (
   1087                   ControllerHandle,
   1088                   DeviceGuid,
   1089                   &Instance,
   1090                   This->DriverBindingHandle,
   1091                   ConSplitterVirtualHandle,
   1092                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
   1093                   );
   1094   if (EFI_ERROR (Status)) {
   1095     goto Err;
   1096   }
   1097 
   1098   //
   1099   // Open InterfaceGuid on the virtul handle.
   1100   //
   1101   Status =  gBS->OpenProtocol (
   1102                 ControllerHandle,
   1103                 InterfaceGuid,
   1104                 Interface,
   1105                 This->DriverBindingHandle,
   1106                 ConSplitterVirtualHandle,
   1107                 EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1108                 );
   1109 
   1110   if (!EFI_ERROR (Status)) {
   1111     return EFI_SUCCESS;
   1112   }
   1113 
   1114   //
   1115   // close the DeviceGuid on ConSplitter VirtualHandle.
   1116   //
   1117   gBS->CloseProtocol (
   1118         ControllerHandle,
   1119         DeviceGuid,
   1120         This->DriverBindingHandle,
   1121         ConSplitterVirtualHandle
   1122         );
   1123 
   1124 Err:
   1125   //
   1126   // close the DeviceGuid on ControllerHandle.
   1127   //
   1128   gBS->CloseProtocol (
   1129         ControllerHandle,
   1130         DeviceGuid,
   1131         This->DriverBindingHandle,
   1132         ControllerHandle
   1133         );
   1134 
   1135   return Status;
   1136 }
   1137 
   1138 
   1139 /**
   1140   Start Console In Consplitter on device handle.
   1141 
   1142   @param  This                 Driver Binding protocol instance pointer.
   1143   @param  ControllerHandle     Handle of device to bind driver to.
   1144   @param  RemainingDevicePath  Optional parameter use to pick a specific child
   1145                                device to start.
   1146 
   1147   @retval EFI_SUCCESS          Console In Consplitter is added to ControllerHandle.
   1148   @retval other                Console In Consplitter does not support this device.
   1149 
   1150 **/
   1151 EFI_STATUS
   1152 EFIAPI
   1153 ConSplitterConInDriverBindingStart (
   1154   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
   1155   IN  EFI_HANDLE                      ControllerHandle,
   1156   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
   1157   )
   1158 {
   1159   EFI_STATUS                          Status;
   1160   EFI_SIMPLE_TEXT_INPUT_PROTOCOL      *TextIn;
   1161   EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL   *TextInEx;
   1162 
   1163   //
   1164   // Start ConSplitter on ControllerHandle, and create the virtual
   1165   // agrogated console device on first call Start for a SimpleTextIn handle.
   1166   //
   1167   Status = ConSplitterStart (
   1168             This,
   1169             ControllerHandle,
   1170             mConIn.VirtualHandle,
   1171             &gEfiConsoleInDeviceGuid,
   1172             &gEfiSimpleTextInProtocolGuid,
   1173             (VOID **) &TextIn
   1174             );
   1175   if (EFI_ERROR (Status)) {
   1176     return Status;
   1177   }
   1178 
   1179   //
   1180   // Add this device into Text In devices list.
   1181   //
   1182   Status = ConSplitterTextInAddDevice (&mConIn, TextIn);
   1183   if (EFI_ERROR (Status)) {
   1184     return Status;
   1185   }
   1186 
   1187   Status = gBS->OpenProtocol (
   1188                   ControllerHandle,
   1189                   &gEfiSimpleTextInputExProtocolGuid,
   1190                   (VOID **) &TextInEx,
   1191                   This->DriverBindingHandle,
   1192                   mConIn.VirtualHandle,
   1193                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1194                   );
   1195   if (!EFI_ERROR (Status)) {
   1196     //
   1197     // If Simple Text Input Ex protocol exists,
   1198     // add this device into Text In Ex devices list.
   1199     //
   1200     Status = ConSplitterTextInExAddDevice (&mConIn, TextInEx);
   1201   }
   1202 
   1203   return Status;
   1204 }
   1205 
   1206 
   1207 /**
   1208   Start Simple Pointer Consplitter on device handle.
   1209 
   1210   @param  This                 Driver Binding protocol instance pointer.
   1211   @param  ControllerHandle     Handle of device to bind driver to.
   1212   @param  RemainingDevicePath  Optional parameter use to pick a specific child
   1213                                device to start.
   1214 
   1215   @retval EFI_SUCCESS          Simple Pointer Consplitter is added to ControllerHandle.
   1216   @retval other                Simple Pointer Consplitter does not support this device.
   1217 
   1218 **/
   1219 EFI_STATUS
   1220 EFIAPI
   1221 ConSplitterSimplePointerDriverBindingStart (
   1222   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
   1223   IN  EFI_HANDLE                      ControllerHandle,
   1224   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
   1225   )
   1226 {
   1227   EFI_STATUS                  Status;
   1228   EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer;
   1229 
   1230   //
   1231   // Start ConSplitter on ControllerHandle, and create the virtual
   1232   // agrogated console device on first call Start for a SimplePointer handle.
   1233   //
   1234   Status = ConSplitterStart (
   1235             This,
   1236             ControllerHandle,
   1237             mConIn.VirtualHandle,
   1238             &gEfiSimplePointerProtocolGuid,
   1239             &gEfiSimplePointerProtocolGuid,
   1240             (VOID **) &SimplePointer
   1241             );
   1242   if (EFI_ERROR (Status)) {
   1243     return Status;
   1244   }
   1245 
   1246   //
   1247   // Add this devcie into Simple Pointer devices list.
   1248   //
   1249   return ConSplitterSimplePointerAddDevice (&mConIn, SimplePointer);
   1250 }
   1251 
   1252 
   1253 /**
   1254   Start Absolute Pointer Consplitter on device handle.
   1255 
   1256   @param  This                 Driver Binding protocol instance pointer.
   1257   @param  ControllerHandle     Handle of device to bind driver to.
   1258   @param  RemainingDevicePath  Optional parameter use to pick a specific child
   1259                                device to start.
   1260 
   1261   @retval EFI_SUCCESS          Absolute Pointer Consplitter is added to ControllerHandle.
   1262   @retval other                Absolute Pointer Consplitter does not support this device.
   1263 
   1264 **/
   1265 EFI_STATUS
   1266 EFIAPI
   1267 ConSplitterAbsolutePointerDriverBindingStart (
   1268   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
   1269   IN  EFI_HANDLE                      ControllerHandle,
   1270   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
   1271   )
   1272 {
   1273   EFI_STATUS                        Status;
   1274   EFI_ABSOLUTE_POINTER_PROTOCOL     *AbsolutePointer;
   1275 
   1276   //
   1277   // Start ConSplitter on ControllerHandle, and create the virtual
   1278   // agrogated console device on first call Start for a AbsolutePointer handle.
   1279   //
   1280   Status = ConSplitterStart (
   1281              This,
   1282              ControllerHandle,
   1283              mConIn.VirtualHandle,
   1284              &gEfiAbsolutePointerProtocolGuid,
   1285              &gEfiAbsolutePointerProtocolGuid,
   1286              (VOID **) &AbsolutePointer
   1287              );
   1288 
   1289   if (EFI_ERROR (Status)) {
   1290     return Status;
   1291   }
   1292 
   1293   //
   1294   // Add this devcie into Absolute Pointer devices list.
   1295   //
   1296   return ConSplitterAbsolutePointerAddDevice (&mConIn, AbsolutePointer);
   1297 }
   1298 
   1299 
   1300 /**
   1301   Start Console Out Consplitter on device handle.
   1302 
   1303   @param  This                 Driver Binding protocol instance pointer.
   1304   @param  ControllerHandle     Handle of device to bind driver to.
   1305   @param  RemainingDevicePath  Optional parameter use to pick a specific child
   1306                                device to start.
   1307 
   1308   @retval EFI_SUCCESS          Console Out Consplitter is added to ControllerHandle.
   1309   @retval other                Console Out Consplitter does not support this device.
   1310 
   1311 **/
   1312 EFI_STATUS
   1313 EFIAPI
   1314 ConSplitterConOutDriverBindingStart (
   1315   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
   1316   IN  EFI_HANDLE                      ControllerHandle,
   1317   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
   1318   )
   1319 {
   1320   EFI_STATUS                           Status;
   1321   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL      *TextOut;
   1322   EFI_GRAPHICS_OUTPUT_PROTOCOL         *GraphicsOutput;
   1323   EFI_UGA_DRAW_PROTOCOL                *UgaDraw;
   1324   UINTN                                SizeOfInfo;
   1325   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
   1326 
   1327   //
   1328   // Start ConSplitter on ControllerHandle, and create the virtual
   1329   // agrogated console device on first call Start for a ConsoleOut handle.
   1330   //
   1331   Status = ConSplitterStart (
   1332             This,
   1333             ControllerHandle,
   1334             mConOut.VirtualHandle,
   1335             &gEfiConsoleOutDeviceGuid,
   1336             &gEfiSimpleTextOutProtocolGuid,
   1337             (VOID **) &TextOut
   1338             );
   1339   if (EFI_ERROR (Status)) {
   1340     return Status;
   1341   }
   1342 
   1343   GraphicsOutput = NULL;
   1344   UgaDraw        = NULL;
   1345   //
   1346   // Try to Open Graphics Output protocol
   1347   //
   1348   Status = gBS->OpenProtocol (
   1349                   ControllerHandle,
   1350                   &gEfiGraphicsOutputProtocolGuid,
   1351                   (VOID **) &GraphicsOutput,
   1352                   This->DriverBindingHandle,
   1353                   mConOut.VirtualHandle,
   1354                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1355                   );
   1356 
   1357   if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
   1358     //
   1359     // Open UGA DRAW protocol
   1360     //
   1361     gBS->OpenProtocol (
   1362            ControllerHandle,
   1363            &gEfiUgaDrawProtocolGuid,
   1364            (VOID **) &UgaDraw,
   1365            This->DriverBindingHandle,
   1366            mConOut.VirtualHandle,
   1367            EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1368            );
   1369   }
   1370 
   1371   //
   1372   // When new console device is added, the new mode will be set later,
   1373   // so put current mode back to init state.
   1374   //
   1375   mConOut.TextOutMode.Mode = 0xFF;
   1376 
   1377   //
   1378   // If both ConOut and StdErr incorporate the same Text Out device,
   1379   // their MaxMode and QueryData should be the intersection of both.
   1380   //
   1381   Status = ConSplitterTextOutAddDevice (&mConOut, TextOut, GraphicsOutput, UgaDraw);
   1382   ConSplitterTextOutSetAttribute (&mConOut.TextOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
   1383 
   1384   if (FeaturePcdGet (PcdConOutUgaSupport)) {
   1385     //
   1386     // Get the UGA mode data of ConOut from the current mode
   1387     //
   1388     if (GraphicsOutput != NULL) {
   1389       Status = GraphicsOutput->QueryMode (GraphicsOutput, GraphicsOutput->Mode->Mode, &SizeOfInfo, &Info);
   1390       if (EFI_ERROR (Status)) {
   1391         return Status;
   1392       }
   1393       ASSERT ( SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
   1394 
   1395       mConOut.UgaHorizontalResolution = Info->HorizontalResolution;
   1396       mConOut.UgaVerticalResolution   = Info->VerticalResolution;
   1397       mConOut.UgaColorDepth           = 32;
   1398       mConOut.UgaRefreshRate          = 60;
   1399 
   1400       FreePool (Info);
   1401 
   1402     } else if (UgaDraw != NULL) {
   1403       Status = UgaDraw->GetMode (
   1404                  UgaDraw,
   1405                  &mConOut.UgaHorizontalResolution,
   1406                  &mConOut.UgaVerticalResolution,
   1407                  &mConOut.UgaColorDepth,
   1408                  &mConOut.UgaRefreshRate
   1409                  );
   1410     }
   1411   }
   1412 
   1413   return Status;
   1414 }
   1415 
   1416 
   1417 /**
   1418   Start Standard Error Consplitter on device handle.
   1419 
   1420   @param  This                 Driver Binding protocol instance pointer.
   1421   @param  ControllerHandle     Handle of device to bind driver to.
   1422   @param  RemainingDevicePath  Optional parameter use to pick a specific child
   1423                                device to start.
   1424 
   1425   @retval EFI_SUCCESS          Standard Error Consplitter is added to ControllerHandle.
   1426   @retval other                Standard Error Consplitter does not support this device.
   1427 
   1428 **/
   1429 EFI_STATUS
   1430 EFIAPI
   1431 ConSplitterStdErrDriverBindingStart (
   1432   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
   1433   IN  EFI_HANDLE                      ControllerHandle,
   1434   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
   1435   )
   1436 {
   1437   EFI_STATUS                       Status;
   1438   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;
   1439 
   1440   //
   1441   // Start ConSplitter on ControllerHandle, and create the virtual
   1442   // agrogated console device on first call Start for a StandardError handle.
   1443   //
   1444   Status = ConSplitterStart (
   1445             This,
   1446             ControllerHandle,
   1447             mStdErr.VirtualHandle,
   1448             &gEfiStandardErrorDeviceGuid,
   1449             &gEfiSimpleTextOutProtocolGuid,
   1450             (VOID **) &TextOut
   1451             );
   1452   if (EFI_ERROR (Status)) {
   1453     return Status;
   1454   }
   1455 
   1456   //
   1457   // When new console device is added, the new mode will be set later,
   1458   // so put current mode back to init state.
   1459   //
   1460   mStdErr.TextOutMode.Mode = 0xFF;
   1461 
   1462   //
   1463   // If both ConOut and StdErr incorporate the same Text Out device,
   1464   // their MaxMode and QueryData should be the intersection of both.
   1465   //
   1466   Status = ConSplitterTextOutAddDevice (&mStdErr, TextOut, NULL, NULL);
   1467   ConSplitterTextOutSetAttribute (&mStdErr.TextOut, EFI_TEXT_ATTR (EFI_MAGENTA, EFI_BLACK));
   1468   if (EFI_ERROR (Status)) {
   1469     return Status;
   1470   }
   1471 
   1472   return Status;
   1473 }
   1474 
   1475 
   1476 /**
   1477   Stop ConSplitter on device handle by closing Console Device Guid on device handle
   1478   and the console virtual handle.
   1479 
   1480   @param  This                      Protocol instance pointer.
   1481   @param  ControllerHandle          Handle of device.
   1482   @param  ConSplitterVirtualHandle  Console virtual Handle.
   1483   @param  DeviceGuid                The specified Console Device, such as ConInDev,
   1484                                     ConOutDev.
   1485   @param  InterfaceGuid             The specified protocol to be opened.
   1486   @param  Interface                 Protocol interface returned.
   1487 
   1488   @retval EFI_SUCCESS               Stop ConSplitter on ControllerHandle successfully.
   1489   @retval other                     Failed to Stop ConSplitter on ControllerHandle.
   1490 
   1491 **/
   1492 EFI_STATUS
   1493 ConSplitterStop (
   1494   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
   1495   IN  EFI_HANDLE                      ControllerHandle,
   1496   IN  EFI_HANDLE                      ConSplitterVirtualHandle,
   1497   IN  EFI_GUID                        *DeviceGuid,
   1498   IN  EFI_GUID                        *InterfaceGuid,
   1499   IN  VOID                            **Interface
   1500   )
   1501 {
   1502   EFI_STATUS  Status;
   1503 
   1504   Status = gBS->OpenProtocol (
   1505                   ControllerHandle,
   1506                   InterfaceGuid,
   1507                   Interface,
   1508                   This->DriverBindingHandle,
   1509                   ControllerHandle,
   1510                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1511                   );
   1512   if (EFI_ERROR (Status)) {
   1513     return Status;
   1514   }
   1515   //
   1516   // close the protocol refered.
   1517   //
   1518   gBS->CloseProtocol (
   1519         ControllerHandle,
   1520         DeviceGuid,
   1521         This->DriverBindingHandle,
   1522         ConSplitterVirtualHandle
   1523         );
   1524 
   1525   gBS->CloseProtocol (
   1526         ControllerHandle,
   1527         DeviceGuid,
   1528         This->DriverBindingHandle,
   1529         ControllerHandle
   1530         );
   1531 
   1532   return EFI_SUCCESS;
   1533 }
   1534 
   1535 
   1536 /**
   1537   Stop Console In ConSplitter on ControllerHandle by closing Console In Devcice GUID.
   1538 
   1539   @param  This              Driver Binding protocol instance pointer.
   1540   @param  ControllerHandle  Handle of device to stop driver on
   1541   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
   1542                             children is zero stop the entire bus driver.
   1543   @param  ChildHandleBuffer List of Child Handles to Stop.
   1544 
   1545   @retval EFI_SUCCESS       This driver is removed ControllerHandle
   1546   @retval other             This driver was not removed from this device
   1547 
   1548 **/
   1549 EFI_STATUS
   1550 EFIAPI
   1551 ConSplitterConInDriverBindingStop (
   1552   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
   1553   IN  EFI_HANDLE                      ControllerHandle,
   1554   IN  UINTN                           NumberOfChildren,
   1555   IN  EFI_HANDLE                      *ChildHandleBuffer
   1556   )
   1557 {
   1558   EFI_STATUS                        Status;
   1559   EFI_SIMPLE_TEXT_INPUT_PROTOCOL    *TextIn;
   1560   EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx;
   1561 
   1562   if (NumberOfChildren == 0) {
   1563     return EFI_SUCCESS;
   1564   }
   1565 
   1566   Status = gBS->OpenProtocol (
   1567                   ControllerHandle,
   1568                   &gEfiSimpleTextInputExProtocolGuid,
   1569                   (VOID **) &TextInEx,
   1570                   This->DriverBindingHandle,
   1571                   ControllerHandle,
   1572                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1573                   );
   1574   if (!EFI_ERROR (Status)) {
   1575     //
   1576     // If Simple Text Input Ex protocol exists,
   1577     // remove device from Text Input Ex devices list.
   1578     //
   1579     Status = ConSplitterTextInExDeleteDevice (&mConIn, TextInEx);
   1580     if (EFI_ERROR (Status)) {
   1581       return Status;
   1582     }
   1583   }
   1584 
   1585   //
   1586   // Close Simple Text In protocol on controller handle and virtual handle.
   1587   //
   1588   Status = ConSplitterStop (
   1589             This,
   1590             ControllerHandle,
   1591             mConIn.VirtualHandle,
   1592             &gEfiConsoleInDeviceGuid,
   1593             &gEfiSimpleTextInProtocolGuid,
   1594             (VOID **) &TextIn
   1595             );
   1596   if (EFI_ERROR (Status)) {
   1597     return Status;
   1598   }
   1599 
   1600   //
   1601   // Remove device from Text Input devices list.
   1602   //
   1603   return ConSplitterTextInDeleteDevice (&mConIn, TextIn);
   1604 }
   1605 
   1606 
   1607 /**
   1608   Stop Simple Pointer protocol ConSplitter on ControllerHandle by closing
   1609   Simple Pointer protocol.
   1610 
   1611   @param  This              Driver Binding protocol instance pointer.
   1612   @param  ControllerHandle  Handle of device to stop driver on
   1613   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
   1614                             children is zero stop the entire bus driver.
   1615   @param  ChildHandleBuffer List of Child Handles to Stop.
   1616 
   1617   @retval EFI_SUCCESS       This driver is removed ControllerHandle
   1618   @retval other             This driver was not removed from this device
   1619 
   1620 **/
   1621 EFI_STATUS
   1622 EFIAPI
   1623 ConSplitterSimplePointerDriverBindingStop (
   1624   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
   1625   IN  EFI_HANDLE                      ControllerHandle,
   1626   IN  UINTN                           NumberOfChildren,
   1627   IN  EFI_HANDLE                      *ChildHandleBuffer
   1628   )
   1629 {
   1630   EFI_STATUS                  Status;
   1631   EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer;
   1632 
   1633   if (NumberOfChildren == 0) {
   1634     return EFI_SUCCESS;
   1635   }
   1636 
   1637   //
   1638   // Close Simple Pointer protocol on controller handle and virtual handle.
   1639   //
   1640   Status = ConSplitterStop (
   1641             This,
   1642             ControllerHandle,
   1643             mConIn.VirtualHandle,
   1644             &gEfiSimplePointerProtocolGuid,
   1645             &gEfiSimplePointerProtocolGuid,
   1646             (VOID **) &SimplePointer
   1647             );
   1648   if (EFI_ERROR (Status)) {
   1649     return Status;
   1650   }
   1651 
   1652   //
   1653   // Remove this device from Simple Pointer device list.
   1654   //
   1655   return ConSplitterSimplePointerDeleteDevice (&mConIn, SimplePointer);
   1656 }
   1657 
   1658 
   1659 /**
   1660   Stop Absolute Pointer protocol ConSplitter on ControllerHandle by closing
   1661   Absolute Pointer protocol.
   1662 
   1663   @param  This              Driver Binding protocol instance pointer.
   1664   @param  ControllerHandle  Handle of device to stop driver on
   1665   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
   1666                             children is zero stop the entire bus driver.
   1667   @param  ChildHandleBuffer List of Child Handles to Stop.
   1668 
   1669   @retval EFI_SUCCESS       This driver is removed ControllerHandle
   1670   @retval other             This driver was not removed from this device
   1671 
   1672 **/
   1673 EFI_STATUS
   1674 EFIAPI
   1675 ConSplitterAbsolutePointerDriverBindingStop (
   1676   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
   1677   IN  EFI_HANDLE                      ControllerHandle,
   1678   IN  UINTN                           NumberOfChildren,
   1679   IN  EFI_HANDLE                      *ChildHandleBuffer
   1680   )
   1681 {
   1682   EFI_STATUS                        Status;
   1683   EFI_ABSOLUTE_POINTER_PROTOCOL     *AbsolutePointer;
   1684 
   1685   if (NumberOfChildren == 0) {
   1686     return EFI_SUCCESS;
   1687   }
   1688 
   1689   //
   1690   // Close Absolute Pointer protocol on controller handle and virtual handle.
   1691   //
   1692   Status = ConSplitterStop (
   1693              This,
   1694              ControllerHandle,
   1695              mConIn.VirtualHandle,
   1696              &gEfiAbsolutePointerProtocolGuid,
   1697              &gEfiAbsolutePointerProtocolGuid,
   1698              (VOID **) &AbsolutePointer
   1699              );
   1700   if (EFI_ERROR (Status)) {
   1701     return Status;
   1702   }
   1703 
   1704   //
   1705   // Remove this device from Absolute Pointer device list.
   1706   //
   1707   return ConSplitterAbsolutePointerDeleteDevice (&mConIn, AbsolutePointer);
   1708 }
   1709 
   1710 
   1711 /**
   1712   Stop Console Out ConSplitter on device handle by closing Console Out Devcice GUID.
   1713 
   1714   @param  This              Driver Binding protocol instance pointer.
   1715   @param  ControllerHandle  Handle of device to stop driver on
   1716   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
   1717                             children is zero stop the entire bus driver.
   1718   @param  ChildHandleBuffer List of Child Handles to Stop.
   1719 
   1720   @retval EFI_SUCCESS       This driver is removed ControllerHandle
   1721   @retval other             This driver was not removed from this device
   1722 
   1723 **/
   1724 EFI_STATUS
   1725 EFIAPI
   1726 ConSplitterConOutDriverBindingStop (
   1727   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
   1728   IN  EFI_HANDLE                      ControllerHandle,
   1729   IN  UINTN                           NumberOfChildren,
   1730   IN  EFI_HANDLE                      *ChildHandleBuffer
   1731   )
   1732 {
   1733   EFI_STATUS                       Status;
   1734   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;
   1735 
   1736   if (NumberOfChildren == 0) {
   1737     return EFI_SUCCESS;
   1738   }
   1739 
   1740   //
   1741   // Close Absolute Pointer protocol on controller handle and virtual handle.
   1742   //
   1743   Status = ConSplitterStop (
   1744             This,
   1745             ControllerHandle,
   1746             mConOut.VirtualHandle,
   1747             &gEfiConsoleOutDeviceGuid,
   1748             &gEfiSimpleTextOutProtocolGuid,
   1749             (VOID **) &TextOut
   1750             );
   1751   if (EFI_ERROR (Status)) {
   1752     return Status;
   1753   }
   1754 
   1755   //
   1756   // Remove this device from Text Out device list.
   1757   //
   1758   return ConSplitterTextOutDeleteDevice (&mConOut, TextOut);
   1759 }
   1760 
   1761 
   1762 /**
   1763   Stop Standard Error ConSplitter on ControllerHandle by closing Standard Error GUID.
   1764 
   1765   @param  This              Driver Binding protocol instance pointer.
   1766   @param  ControllerHandle  Handle of device to stop driver on
   1767   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
   1768                             children is zero stop the entire bus driver.
   1769   @param  ChildHandleBuffer List of Child Handles to Stop.
   1770 
   1771   @retval EFI_SUCCESS       This driver is removed ControllerHandle
   1772   @retval other             This driver was not removed from this device
   1773 
   1774 **/
   1775 EFI_STATUS
   1776 EFIAPI
   1777 ConSplitterStdErrDriverBindingStop (
   1778   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
   1779   IN  EFI_HANDLE                      ControllerHandle,
   1780   IN  UINTN                           NumberOfChildren,
   1781   IN  EFI_HANDLE                      *ChildHandleBuffer
   1782   )
   1783 {
   1784   EFI_STATUS                       Status;
   1785   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;
   1786 
   1787   if (NumberOfChildren == 0) {
   1788     return EFI_SUCCESS;
   1789   }
   1790 
   1791   //
   1792   // Close Standard Error Device on controller handle and virtual handle.
   1793   //
   1794   Status = ConSplitterStop (
   1795             This,
   1796             ControllerHandle,
   1797             mStdErr.VirtualHandle,
   1798             &gEfiStandardErrorDeviceGuid,
   1799             &gEfiSimpleTextOutProtocolGuid,
   1800             (VOID **) &TextOut
   1801             );
   1802   if (EFI_ERROR (Status)) {
   1803     return Status;
   1804   }
   1805   //
   1806   // Delete this console error out device's data structures.
   1807   //
   1808   return ConSplitterTextOutDeleteDevice (&mStdErr, TextOut);
   1809 }
   1810 
   1811 
   1812 /**
   1813   Take the passed in Buffer of size ElementSize and grow the buffer
   1814   by CONSOLE_SPLITTER_ALLOC_UNIT * ElementSize bytes.
   1815   Copy the current data in Buffer to the new version of Buffer and
   1816   free the old version of buffer.
   1817 
   1818   @param  ElementSize              Size of element in array.
   1819   @param  Count                    Current number of elements in array.
   1820   @param  Buffer                   Bigger version of passed in Buffer with all the
   1821                                    data.
   1822 
   1823   @retval EFI_SUCCESS              Buffer size has grown.
   1824   @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.
   1825 
   1826 **/
   1827 EFI_STATUS
   1828 ConSplitterGrowBuffer (
   1829   IN      UINTN                       ElementSize,
   1830   IN OUT  UINTN                       *Count,
   1831   IN OUT  VOID                        **Buffer
   1832   )
   1833 {
   1834   VOID  *Ptr;
   1835 
   1836   //
   1837   // grow the buffer to new buffer size,
   1838   // copy the old buffer's content to the new-size buffer,
   1839   // then free the old buffer.
   1840   //
   1841   Ptr = ReallocatePool (
   1842           ElementSize * (*Count),
   1843           ElementSize * ((*Count) + CONSOLE_SPLITTER_ALLOC_UNIT),
   1844           *Buffer
   1845           );
   1846   if (Ptr == NULL) {
   1847     return EFI_OUT_OF_RESOURCES;
   1848   }
   1849   *Count += CONSOLE_SPLITTER_ALLOC_UNIT;
   1850   *Buffer = Ptr;
   1851   return EFI_SUCCESS;
   1852 }
   1853 
   1854 
   1855 /**
   1856   Add Text Input Device in Consplitter Text Input list.
   1857 
   1858   @param  Private                  Text In Splitter pointer.
   1859   @param  TextIn                   Simple Text Input protocol pointer.
   1860 
   1861   @retval EFI_SUCCESS              Text Input Device added successfully.
   1862   @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.
   1863 
   1864 **/
   1865 EFI_STATUS
   1866 ConSplitterTextInAddDevice (
   1867   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,
   1868   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *TextIn
   1869   )
   1870 {
   1871   EFI_STATUS  Status;
   1872 
   1873   //
   1874   // If the Text In List is full, enlarge it by calling ConSplitterGrowBuffer().
   1875   //
   1876   if (Private->CurrentNumberOfConsoles >= Private->TextInListCount) {
   1877     Status = ConSplitterGrowBuffer (
   1878               sizeof (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *),
   1879               &Private->TextInListCount,
   1880               (VOID **) &Private->TextInList
   1881               );
   1882     if (EFI_ERROR (Status)) {
   1883       return EFI_OUT_OF_RESOURCES;
   1884     }
   1885   }
   1886   //
   1887   // Add the new text-in device data structure into the Text In List.
   1888   //
   1889   Private->TextInList[Private->CurrentNumberOfConsoles] = TextIn;
   1890   Private->CurrentNumberOfConsoles++;
   1891 
   1892   //
   1893   // Extra CheckEvent added to reduce the double CheckEvent().
   1894   //
   1895   gBS->CheckEvent (TextIn->WaitForKey);
   1896 
   1897   return EFI_SUCCESS;
   1898 }
   1899 
   1900 
   1901 /**
   1902   Remove Text Input Device from Consplitter Text Input list.
   1903 
   1904   @param  Private                  Text In Splitter pointer.
   1905   @param  TextIn                   Simple Text protocol pointer.
   1906 
   1907   @retval EFI_SUCCESS              Simple Text Device removed successfully.
   1908   @retval EFI_NOT_FOUND            No Simple Text Device found.
   1909 
   1910 **/
   1911 EFI_STATUS
   1912 ConSplitterTextInDeleteDevice (
   1913   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,
   1914   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *TextIn
   1915   )
   1916 {
   1917   UINTN Index;
   1918   //
   1919   // Remove the specified text-in device data structure from the Text In List,
   1920   // and rearrange the remaining data structures in the Text In List.
   1921   //
   1922   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
   1923     if (Private->TextInList[Index] == TextIn) {
   1924       for (; Index < Private->CurrentNumberOfConsoles - 1; Index++) {
   1925         Private->TextInList[Index] = Private->TextInList[Index + 1];
   1926       }
   1927 
   1928       Private->CurrentNumberOfConsoles--;
   1929       return EFI_SUCCESS;
   1930     }
   1931   }
   1932 
   1933   return EFI_NOT_FOUND;
   1934 }
   1935 
   1936 /**
   1937   Add Text Input Ex Device in Consplitter Text Input Ex list.
   1938 
   1939   @param  Private                  Text In Splitter pointer.
   1940   @param  TextInEx                 Simple Text Input Ex Input protocol pointer.
   1941 
   1942   @retval EFI_SUCCESS              Text Input Ex Device added successfully.
   1943   @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.
   1944 
   1945 **/
   1946 EFI_STATUS
   1947 ConSplitterTextInExAddDevice (
   1948   IN  TEXT_IN_SPLITTER_PRIVATE_DATA         *Private,
   1949   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL     *TextInEx
   1950   )
   1951 {
   1952   EFI_STATUS                  Status;
   1953   LIST_ENTRY                  *Link;
   1954   TEXT_IN_EX_SPLITTER_NOTIFY  *CurrentNotify;
   1955   UINTN                       TextInExListCount;
   1956 
   1957   //
   1958   // Enlarge the NotifyHandleList and the TextInExList
   1959   //
   1960   if (Private->CurrentNumberOfExConsoles >= Private->TextInExListCount) {
   1961     for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
   1962       CurrentNotify     = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);
   1963       TextInExListCount = Private->TextInExListCount;
   1964 
   1965       Status = ConSplitterGrowBuffer (
   1966                  sizeof (EFI_HANDLE),
   1967                  &TextInExListCount,
   1968                  (VOID **) &CurrentNotify->NotifyHandleList
   1969                  );
   1970       if (EFI_ERROR (Status)) {
   1971         return EFI_OUT_OF_RESOURCES;
   1972       }
   1973     }
   1974     Status = ConSplitterGrowBuffer (
   1975               sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *),
   1976               &Private->TextInExListCount,
   1977               (VOID **) &Private->TextInExList
   1978               );
   1979     if (EFI_ERROR (Status)) {
   1980       return EFI_OUT_OF_RESOURCES;
   1981     }
   1982   }
   1983 
   1984   //
   1985   // Register the key notify in the new text-in device
   1986   //
   1987   for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
   1988     CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);
   1989     Status = TextInEx->RegisterKeyNotify (
   1990                          TextInEx,
   1991                          &CurrentNotify->KeyData,
   1992                          CurrentNotify->KeyNotificationFn,
   1993                          &CurrentNotify->NotifyHandleList[Private->CurrentNumberOfExConsoles]
   1994                          );
   1995     if (EFI_ERROR (Status)) {
   1996       for (Link = Link->BackLink; Link != &Private->NotifyList; Link = Link->BackLink) {
   1997         CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);
   1998         TextInEx->UnregisterKeyNotify (
   1999                     TextInEx,
   2000                     CurrentNotify->NotifyHandleList[Private->CurrentNumberOfExConsoles]
   2001                     );
   2002       }
   2003       return Status;
   2004     }
   2005   }
   2006 
   2007   //
   2008   // Add the new text-in device data structure into the Text Input Ex List.
   2009   //
   2010   Private->TextInExList[Private->CurrentNumberOfExConsoles] = TextInEx;
   2011   Private->CurrentNumberOfExConsoles++;
   2012 
   2013   //
   2014   // Sync current toggle state to this new console input device.
   2015   //
   2016   TextInEx->SetState (TextInEx, &Private->PhysicalKeyToggleState);
   2017 
   2018   //
   2019   // Extra CheckEvent added to reduce the double CheckEvent().
   2020   //
   2021   gBS->CheckEvent (TextInEx->WaitForKeyEx);
   2022 
   2023   return EFI_SUCCESS;
   2024 }
   2025 
   2026 /**
   2027   Remove Text Ex Device from Consplitter Text Input Ex list.
   2028 
   2029   @param  Private                  Text In Splitter pointer.
   2030   @param  TextInEx                 Simple Text Ex protocol pointer.
   2031 
   2032   @retval EFI_SUCCESS              Simple Text Input Ex Device removed successfully.
   2033   @retval EFI_NOT_FOUND            No Simple Text Input Ex Device found.
   2034 
   2035 **/
   2036 EFI_STATUS
   2037 ConSplitterTextInExDeleteDevice (
   2038   IN  TEXT_IN_SPLITTER_PRIVATE_DATA         *Private,
   2039   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL     *TextInEx
   2040   )
   2041 {
   2042   UINTN Index;
   2043   //
   2044   // Remove the specified text-in device data structure from the Text Input Ex List,
   2045   // and rearrange the remaining data structures in the Text In List.
   2046   //
   2047   for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
   2048     if (Private->TextInExList[Index] == TextInEx) {
   2049       for (; Index < Private->CurrentNumberOfExConsoles - 1; Index++) {
   2050         Private->TextInExList[Index] = Private->TextInExList[Index + 1];
   2051       }
   2052 
   2053       Private->CurrentNumberOfExConsoles--;
   2054       return EFI_SUCCESS;
   2055     }
   2056   }
   2057 
   2058   return EFI_NOT_FOUND;
   2059 }
   2060 
   2061 
   2062 /**
   2063   Add Simple Pointer Device in Consplitter Simple Pointer list.
   2064 
   2065   @param  Private                  Text In Splitter pointer.
   2066   @param  SimplePointer            Simple Pointer protocol pointer.
   2067 
   2068   @retval EFI_SUCCESS              Simple Pointer Device added successfully.
   2069   @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.
   2070 
   2071 **/
   2072 EFI_STATUS
   2073 ConSplitterSimplePointerAddDevice (
   2074   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,
   2075   IN  EFI_SIMPLE_POINTER_PROTOCOL     *SimplePointer
   2076   )
   2077 {
   2078   EFI_STATUS  Status;
   2079 
   2080   //
   2081   // If the Simple Pointer List is full, enlarge it by calling ConSplitterGrowBuffer().
   2082   //
   2083   if (Private->CurrentNumberOfPointers >= Private->PointerListCount) {
   2084     Status = ConSplitterGrowBuffer (
   2085               sizeof (EFI_SIMPLE_POINTER_PROTOCOL *),
   2086               &Private->PointerListCount,
   2087               (VOID **) &Private->PointerList
   2088               );
   2089     if (EFI_ERROR (Status)) {
   2090       return EFI_OUT_OF_RESOURCES;
   2091     }
   2092   }
   2093   //
   2094   // Add the new text-in device data structure into the Simple Pointer List.
   2095   //
   2096   Private->PointerList[Private->CurrentNumberOfPointers] = SimplePointer;
   2097   Private->CurrentNumberOfPointers++;
   2098 
   2099   return EFI_SUCCESS;
   2100 }
   2101 
   2102 
   2103 /**
   2104   Remove Simple Pointer Device from Consplitter Simple Pointer list.
   2105 
   2106   @param  Private                  Text In Splitter pointer.
   2107   @param  SimplePointer            Simple Pointer protocol pointer.
   2108 
   2109   @retval EFI_SUCCESS              Simple Pointer Device removed successfully.
   2110   @retval EFI_NOT_FOUND            No Simple Pointer Device found.
   2111 
   2112 **/
   2113 EFI_STATUS
   2114 ConSplitterSimplePointerDeleteDevice (
   2115   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,
   2116   IN  EFI_SIMPLE_POINTER_PROTOCOL     *SimplePointer
   2117   )
   2118 {
   2119   UINTN Index;
   2120   //
   2121   // Remove the specified text-in device data structure from the Simple Pointer List,
   2122   // and rearrange the remaining data structures in the Text In List.
   2123   //
   2124   for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) {
   2125     if (Private->PointerList[Index] == SimplePointer) {
   2126       for (; Index < Private->CurrentNumberOfPointers - 1; Index++) {
   2127         Private->PointerList[Index] = Private->PointerList[Index + 1];
   2128       }
   2129 
   2130       Private->CurrentNumberOfPointers--;
   2131       return EFI_SUCCESS;
   2132     }
   2133   }
   2134 
   2135   return EFI_NOT_FOUND;
   2136 }
   2137 
   2138 
   2139 /**
   2140   Add Absolute Pointer Device in Consplitter Absolute Pointer list.
   2141 
   2142   @param  Private                  Text In Splitter pointer.
   2143   @param  AbsolutePointer          Absolute Pointer protocol pointer.
   2144 
   2145   @retval EFI_SUCCESS              Absolute Pointer Device added successfully.
   2146   @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.
   2147 
   2148 **/
   2149 EFI_STATUS
   2150 ConSplitterAbsolutePointerAddDevice (
   2151   IN  TEXT_IN_SPLITTER_PRIVATE_DATA     *Private,
   2152   IN  EFI_ABSOLUTE_POINTER_PROTOCOL     *AbsolutePointer
   2153   )
   2154 {
   2155   EFI_STATUS  Status;
   2156 
   2157   //
   2158   // If the Absolute Pointer List is full, enlarge it by calling ConSplitterGrowBuffer().
   2159   //
   2160   if (Private->CurrentNumberOfAbsolutePointers >= Private->AbsolutePointerListCount) {
   2161     Status = ConSplitterGrowBuffer (
   2162               sizeof (EFI_ABSOLUTE_POINTER_PROTOCOL *),
   2163               &Private->AbsolutePointerListCount,
   2164               (VOID **) &Private->AbsolutePointerList
   2165               );
   2166     if (EFI_ERROR (Status)) {
   2167       return EFI_OUT_OF_RESOURCES;
   2168     }
   2169   }
   2170   //
   2171   // Add the new text-in device data structure into the Absolute Pointer List.
   2172   //
   2173   Private->AbsolutePointerList[Private->CurrentNumberOfAbsolutePointers] = AbsolutePointer;
   2174   Private->CurrentNumberOfAbsolutePointers++;
   2175 
   2176   return EFI_SUCCESS;
   2177 }
   2178 
   2179 
   2180 /**
   2181   Remove Absolute Pointer Device from Consplitter Absolute Pointer list.
   2182 
   2183   @param  Private                  Text In Splitter pointer.
   2184   @param  AbsolutePointer          Absolute Pointer protocol pointer.
   2185 
   2186   @retval EFI_SUCCESS              Absolute Pointer Device removed successfully.
   2187   @retval EFI_NOT_FOUND            No Absolute Pointer Device found.
   2188 
   2189 **/
   2190 EFI_STATUS
   2191 ConSplitterAbsolutePointerDeleteDevice (
   2192   IN  TEXT_IN_SPLITTER_PRIVATE_DATA     *Private,
   2193   IN  EFI_ABSOLUTE_POINTER_PROTOCOL     *AbsolutePointer
   2194   )
   2195 {
   2196   UINTN Index;
   2197   //
   2198   // Remove the specified text-in device data structure from the Absolute Pointer List,
   2199   // and rearrange the remaining data structures from the Absolute Pointer List.
   2200   //
   2201   for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {
   2202     if (Private->AbsolutePointerList[Index] == AbsolutePointer) {
   2203       for (; Index < Private->CurrentNumberOfAbsolutePointers - 1; Index++) {
   2204         Private->AbsolutePointerList[Index] = Private->AbsolutePointerList[Index + 1];
   2205       }
   2206 
   2207       Private->CurrentNumberOfAbsolutePointers--;
   2208       return EFI_SUCCESS;
   2209     }
   2210   }
   2211 
   2212   return EFI_NOT_FOUND;
   2213 }
   2214 
   2215 /**
   2216   Reallocate Text Out mode map.
   2217 
   2218   Allocate new buffer and copy original buffer into the new buffer.
   2219 
   2220   @param  Private                  Consplitter Text Out pointer.
   2221 
   2222   @retval EFI_SUCCESS              Buffer size has grown
   2223   @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.
   2224 
   2225 **/
   2226 EFI_STATUS
   2227 ConSplitterGrowMapTable (
   2228   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private
   2229   )
   2230 {
   2231   UINTN Size;
   2232   UINTN NewSize;
   2233   UINTN TotalSize;
   2234   INT32 *TextOutModeMap;
   2235   INT32 *OldTextOutModeMap;
   2236   INT32 *SrcAddress;
   2237   INT32 Index;
   2238   UINTN OldStepSize;
   2239   UINTN NewStepSize;
   2240 
   2241   NewSize           = Private->TextOutListCount * sizeof (INT32);
   2242   OldTextOutModeMap = Private->TextOutModeMap;
   2243   TotalSize         = NewSize * (Private->TextOutQueryDataCount);
   2244 
   2245   //
   2246   // Allocate new buffer for Text Out List.
   2247   //
   2248   TextOutModeMap    = AllocatePool (TotalSize);
   2249   if (TextOutModeMap == NULL) {
   2250     return EFI_OUT_OF_RESOURCES;
   2251   }
   2252 
   2253   SetMem (TextOutModeMap, TotalSize, 0xFF);
   2254   Private->TextOutModeMap = TextOutModeMap;
   2255 
   2256   //
   2257   // If TextOutList has been enlarged, need to realloc the mode map table
   2258   // The mode map table is regarded as a two dimension array.
   2259   //
   2260   //                         Old                    New
   2261   //  0   ---------> TextOutListCount ----> TextOutListCount
   2262   //  |   -------------------------------------------
   2263   //  |  |                    |                      |
   2264   //  |  |                    |                      |
   2265   //  |  |                    |                      |
   2266   //  |  |                    |                      |
   2267   //  |  |                    |                      |
   2268   // \/  |                    |                      |
   2269   //      -------------------------------------------
   2270   // QueryDataCount
   2271   //
   2272   if (OldTextOutModeMap != NULL) {
   2273 
   2274     Size        = Private->CurrentNumberOfConsoles * sizeof (INT32);
   2275     Index       = 0;
   2276     SrcAddress  = OldTextOutModeMap;
   2277     NewStepSize = NewSize / sizeof(INT32);
   2278     // If Private->CurrentNumberOfConsoles is not zero and OldTextOutModeMap
   2279     // is not NULL, it indicates that the original TextOutModeMap is not enough
   2280     // for the new console devices and has been enlarged by CONSOLE_SPLITTER_ALLOC_UNIT columns.
   2281     //
   2282     OldStepSize = NewStepSize - CONSOLE_SPLITTER_ALLOC_UNIT;
   2283 
   2284     //
   2285     // Copy the old data to the new one
   2286     //
   2287     while (Index < Private->TextOutMode.MaxMode) {
   2288       CopyMem (TextOutModeMap, SrcAddress, Size);
   2289       //
   2290       // Go to next row of new TextOutModeMap.
   2291       //
   2292       TextOutModeMap += NewStepSize;
   2293       //
   2294       // Go to next row of old TextOutModeMap.
   2295       //
   2296       SrcAddress += OldStepSize;
   2297       Index++;
   2298     }
   2299     //
   2300     // Free the old buffer
   2301     //
   2302     FreePool (OldTextOutModeMap);
   2303   }
   2304 
   2305   return EFI_SUCCESS;
   2306 }
   2307 
   2308 
   2309 /**
   2310   Add new device's output mode to console splitter's mode list.
   2311 
   2312   @param  Private               Text Out Splitter pointer
   2313   @param  TextOut               Simple Text Output protocol pointer.
   2314 
   2315   @retval EFI_SUCCESS           Device added successfully.
   2316   @retval EFI_OUT_OF_RESOURCES  Could not grow the buffer size.
   2317 
   2318 **/
   2319 EFI_STATUS
   2320 ConSplitterAddOutputMode (
   2321   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA     *Private,
   2322   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *TextOut
   2323   )
   2324 {
   2325   EFI_STATUS  Status;
   2326   INT32       MaxMode;
   2327   INT32       Mode;
   2328   UINTN       Index;
   2329 
   2330   MaxMode                       = TextOut->Mode->MaxMode;
   2331   Private->TextOutMode.MaxMode  = MaxMode;
   2332 
   2333   //
   2334   // Grow the buffer if query data buffer is not large enough to
   2335   // hold all the mode supported by the first console.
   2336   //
   2337   while (MaxMode > (INT32) Private->TextOutQueryDataCount) {
   2338     Status = ConSplitterGrowBuffer (
   2339               sizeof (TEXT_OUT_SPLITTER_QUERY_DATA),
   2340               &Private->TextOutQueryDataCount,
   2341               (VOID **) &Private->TextOutQueryData
   2342               );
   2343     if (EFI_ERROR (Status)) {
   2344       return EFI_OUT_OF_RESOURCES;
   2345     }
   2346   }
   2347   //
   2348   // Allocate buffer for the output mode map
   2349   //
   2350   Status = ConSplitterGrowMapTable (Private);
   2351   if (EFI_ERROR (Status)) {
   2352     return EFI_OUT_OF_RESOURCES;
   2353   }
   2354   //
   2355   // As the first textout device, directly add the mode in to QueryData
   2356   // and at the same time record the mapping between QueryData and TextOut.
   2357   //
   2358   Mode  = 0;
   2359   Index = 0;
   2360   while (Mode < MaxMode) {
   2361     Status = TextOut->QueryMode (
   2362                   TextOut,
   2363                   Mode,
   2364                   &Private->TextOutQueryData[Mode].Columns,
   2365                   &Private->TextOutQueryData[Mode].Rows
   2366                   );
   2367     //
   2368     // If mode 1 (80x50) is not supported, make sure mode 1 in TextOutQueryData
   2369     // is clear to 0x0.
   2370     //
   2371     if ((EFI_ERROR(Status)) && (Mode == 1)) {
   2372       Private->TextOutQueryData[Mode].Columns = 0;
   2373       Private->TextOutQueryData[Mode].Rows = 0;
   2374     }
   2375     Private->TextOutModeMap[Index] = Mode;
   2376     Mode++;
   2377     Index += Private->TextOutListCount;
   2378   }
   2379 
   2380   return EFI_SUCCESS;
   2381 }
   2382 
   2383 /**
   2384   Reconstruct TextOutModeMap to get intersection of modes.
   2385 
   2386   This routine reconstruct TextOutModeMap to get the intersection
   2387   of modes for all console out devices. Because EFI/UEFI spec require
   2388   mode 0 is 80x25, mode 1 is 80x50, this routine will not check the
   2389   intersection for mode 0 and mode 1.
   2390 
   2391   @param TextOutModeMap  Current text out mode map, begin with the mode 80x25
   2392   @param NewlyAddedMap   New text out mode map, begin with the mode 80x25
   2393   @param MapStepSize     Mode step size for one console device
   2394   @param NewMapStepSize  New Mode step size for one console device
   2395   @param MaxMode         IN: Current max text mode, OUT: Updated max text mode.
   2396   @param CurrentMode     IN: Current text mode,     OUT: Updated current text mode.
   2397 
   2398 **/
   2399 VOID
   2400 ConSplitterGetIntersection (
   2401   IN     INT32                        *TextOutModeMap,
   2402   IN     INT32                        *NewlyAddedMap,
   2403   IN     UINTN                        MapStepSize,
   2404   IN     UINTN                        NewMapStepSize,
   2405   IN OUT INT32                        *MaxMode,
   2406   IN OUT INT32                        *CurrentMode
   2407   )
   2408 {
   2409   INT32 Index;
   2410   INT32 *CurrentMapEntry;
   2411   INT32 *NextMapEntry;
   2412   INT32 *NewMapEntry;
   2413   INT32 CurrentMaxMode;
   2414   INT32 Mode;
   2415 
   2416   //
   2417   // According to EFI/UEFI spec, mode 0 and mode 1 have been reserved
   2418   // for 80x25 and 80x50 in Simple Text Out protocol, so don't make intersection
   2419   // for mode 0 and mode 1, mode number starts from 2.
   2420   //
   2421   Index           = 2;
   2422   CurrentMapEntry = &TextOutModeMap[MapStepSize * 2];
   2423   NextMapEntry    = CurrentMapEntry;
   2424   NewMapEntry     = &NewlyAddedMap[NewMapStepSize * 2];
   2425 
   2426   CurrentMaxMode  = *MaxMode;
   2427   Mode            = *CurrentMode;
   2428 
   2429   while (Index < CurrentMaxMode) {
   2430     if (*NewMapEntry == -1) {
   2431       //
   2432       // This mode is not supported any more. Remove it. Special care
   2433       // must be taken as this remove will also affect current mode;
   2434       //
   2435       if (Index == *CurrentMode) {
   2436         Mode = -1;
   2437       } else if (Index < *CurrentMode) {
   2438         Mode--;
   2439       }
   2440       (*MaxMode)--;
   2441     } else {
   2442       if (CurrentMapEntry != NextMapEntry) {
   2443         CopyMem (NextMapEntry, CurrentMapEntry, MapStepSize * sizeof (INT32));
   2444       }
   2445 
   2446       NextMapEntry += MapStepSize;
   2447     }
   2448 
   2449     CurrentMapEntry += MapStepSize;
   2450     NewMapEntry     += NewMapStepSize;
   2451     Index++;
   2452   }
   2453 
   2454   *CurrentMode = Mode;
   2455 
   2456   return ;
   2457 }
   2458 
   2459 /**
   2460   Sync the device's output mode to console splitter's mode list.
   2461 
   2462   @param  Private               Text Out Splitter pointer.
   2463   @param  TextOut               Simple Text Output protocol pointer.
   2464 
   2465 **/
   2466 VOID
   2467 ConSplitterSyncOutputMode (
   2468   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA     *Private,
   2469   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *TextOut
   2470   )
   2471 {
   2472   INT32                         CurrentMaxMode;
   2473   INT32                         Mode;
   2474   INT32                         Index;
   2475   INT32                         *TextOutModeMap;
   2476   INT32                         *MapTable;
   2477   INT32                         QueryMode;
   2478   TEXT_OUT_SPLITTER_QUERY_DATA  *TextOutQueryData;
   2479   UINTN                         Rows;
   2480   UINTN                         Columns;
   2481   UINTN                         StepSize;
   2482   EFI_STATUS                    Status;
   2483 
   2484   //
   2485   // Must make sure that current mode won't change even if mode number changes
   2486   //
   2487   CurrentMaxMode    = Private->TextOutMode.MaxMode;
   2488   TextOutModeMap    = Private->TextOutModeMap;
   2489   StepSize          = Private->TextOutListCount;
   2490   TextOutQueryData  = Private->TextOutQueryData;
   2491 
   2492   //
   2493   // Query all the mode that the newly added TextOut supports
   2494   //
   2495   Mode      = 0;
   2496   MapTable  = TextOutModeMap + Private->CurrentNumberOfConsoles;
   2497   while (Mode < TextOut->Mode->MaxMode) {
   2498     Status = TextOut->QueryMode (TextOut, Mode, &Columns, &Rows);
   2499 
   2500     if (EFI_ERROR(Status)) {
   2501       if (Mode == 1) {
   2502         //
   2503         // If mode 1 (80x50) is not supported, make sure mode 1 in TextOutQueryData
   2504         // is clear to 0x0.
   2505         //
   2506         MapTable[StepSize] = Mode;
   2507         TextOutQueryData[Mode].Columns = 0;
   2508         TextOutQueryData[Mode].Rows = 0;
   2509       }
   2510       Mode++;
   2511       continue;
   2512     }
   2513     //
   2514     // Search the intersection map and QueryData database to see if they intersects
   2515     //
   2516     Index = 0;
   2517     while (Index < CurrentMaxMode) {
   2518       QueryMode = *(TextOutModeMap + Index * StepSize);
   2519       if ((TextOutQueryData[QueryMode].Rows == Rows) && (TextOutQueryData[QueryMode].Columns == Columns)) {
   2520         MapTable[Index * StepSize] = Mode;
   2521         break;
   2522       }
   2523       Index++;
   2524     }
   2525     Mode++;
   2526   }
   2527   //
   2528   // Now search the TextOutModeMap table to find the intersection of supported
   2529   // mode between ConSplitter and the newly added device.
   2530   //
   2531   ConSplitterGetIntersection (
   2532     TextOutModeMap,
   2533     MapTable,
   2534     StepSize,
   2535     StepSize,
   2536     &Private->TextOutMode.MaxMode,
   2537     &Private->TextOutMode.Mode
   2538     );
   2539 
   2540   return ;
   2541 }
   2542 
   2543 
   2544 /**
   2545   Sync output device between ConOut and StdErr output.
   2546 
   2547   @retval EFI_SUCCESS              Sync implemented successfully.
   2548   @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.
   2549 
   2550 **/
   2551 EFI_STATUS
   2552 ConSplitterGetIntersectionBetweenConOutAndStrErr (
   2553   VOID
   2554   )
   2555 {
   2556   UINTN                         ConOutNumOfConsoles;
   2557   UINTN                         StdErrNumOfConsoles;
   2558   TEXT_OUT_AND_GOP_DATA         *ConOutTextOutList;
   2559   TEXT_OUT_AND_GOP_DATA         *StdErrTextOutList;
   2560   UINTN                         Indexi;
   2561   UINTN                         Indexj;
   2562   UINTN                         ConOutRows;
   2563   UINTN                         ConOutColumns;
   2564   UINTN                         StdErrRows;
   2565   UINTN                         StdErrColumns;
   2566   INT32                         ConOutMaxMode;
   2567   INT32                         StdErrMaxMode;
   2568   INT32                         ConOutMode;
   2569   INT32                         StdErrMode;
   2570   INT32                         Mode;
   2571   INT32                         Index;
   2572   INT32                         *ConOutModeMap;
   2573   INT32                         *StdErrModeMap;
   2574   INT32                         *ConOutMapTable;
   2575   INT32                         *StdErrMapTable;
   2576   TEXT_OUT_SPLITTER_QUERY_DATA  *ConOutQueryData;
   2577   TEXT_OUT_SPLITTER_QUERY_DATA  *StdErrQueryData;
   2578   UINTN                         ConOutStepSize;
   2579   UINTN                         StdErrStepSize;
   2580   BOOLEAN                       FoundTheSameTextOut;
   2581   UINTN                         ConOutMapTableSize;
   2582   UINTN                         StdErrMapTableSize;
   2583 
   2584   ConOutNumOfConsoles = mConOut.CurrentNumberOfConsoles;
   2585   StdErrNumOfConsoles = mStdErr.CurrentNumberOfConsoles;
   2586   ConOutTextOutList   = mConOut.TextOutList;
   2587   StdErrTextOutList   = mStdErr.TextOutList;
   2588 
   2589   Indexi              = 0;
   2590   FoundTheSameTextOut = FALSE;
   2591   while ((Indexi < ConOutNumOfConsoles) && (!FoundTheSameTextOut)) {
   2592     Indexj = 0;
   2593     while (Indexj < StdErrNumOfConsoles) {
   2594       if (ConOutTextOutList->TextOut == StdErrTextOutList->TextOut) {
   2595         FoundTheSameTextOut = TRUE;
   2596         break;
   2597       }
   2598 
   2599       Indexj++;
   2600       StdErrTextOutList++;
   2601     }
   2602 
   2603     Indexi++;
   2604     ConOutTextOutList++;
   2605   }
   2606 
   2607   if (!FoundTheSameTextOut) {
   2608     return EFI_SUCCESS;
   2609   }
   2610   //
   2611   // Must make sure that current mode won't change even if mode number changes
   2612   //
   2613   ConOutMaxMode     = mConOut.TextOutMode.MaxMode;
   2614   ConOutModeMap     = mConOut.TextOutModeMap;
   2615   ConOutStepSize    = mConOut.TextOutListCount;
   2616   ConOutQueryData   = mConOut.TextOutQueryData;
   2617 
   2618   StdErrMaxMode     = mStdErr.TextOutMode.MaxMode;
   2619   StdErrModeMap     = mStdErr.TextOutModeMap;
   2620   StdErrStepSize    = mStdErr.TextOutListCount;
   2621   StdErrQueryData   = mStdErr.TextOutQueryData;
   2622 
   2623   //
   2624   // Allocate the map table and set the map table's index to -1.
   2625   //
   2626   ConOutMapTableSize  = ConOutMaxMode * sizeof (INT32);
   2627   ConOutMapTable      = AllocateZeroPool (ConOutMapTableSize);
   2628   if (ConOutMapTable == NULL) {
   2629     return EFI_OUT_OF_RESOURCES;
   2630   }
   2631 
   2632   SetMem (ConOutMapTable, ConOutMapTableSize, 0xFF);
   2633 
   2634   StdErrMapTableSize  = StdErrMaxMode * sizeof (INT32);
   2635   StdErrMapTable      = AllocateZeroPool (StdErrMapTableSize);
   2636   if (StdErrMapTable == NULL) {
   2637     return EFI_OUT_OF_RESOURCES;
   2638   }
   2639 
   2640   SetMem (StdErrMapTable, StdErrMapTableSize, 0xFF);
   2641 
   2642   //
   2643   // Find the intersection of the two set of modes. If they actually intersect, the
   2644   // corresponding entry in the map table is set to 1.
   2645   //
   2646   Mode = 0;
   2647   while (Mode < ConOutMaxMode) {
   2648     //
   2649     // Search the intersection map and QueryData database to see if they intersect
   2650     //
   2651     Index = 0;
   2652     ConOutMode    = *(ConOutModeMap + Mode * ConOutStepSize);
   2653     ConOutRows    = ConOutQueryData[ConOutMode].Rows;
   2654     ConOutColumns = ConOutQueryData[ConOutMode].Columns;
   2655     while (Index < StdErrMaxMode) {
   2656       StdErrMode    = *(StdErrModeMap + Index * StdErrStepSize);
   2657       StdErrRows    = StdErrQueryData[StdErrMode].Rows;
   2658       StdErrColumns = StdErrQueryData[StdErrMode].Columns;
   2659       if ((StdErrRows == ConOutRows) && (StdErrColumns == ConOutColumns)) {
   2660         ConOutMapTable[Mode]  = 1;
   2661         StdErrMapTable[Index] = 1;
   2662         break;
   2663       }
   2664 
   2665       Index++;
   2666     }
   2667 
   2668     Mode++;
   2669   }
   2670   //
   2671   // Now search the TextOutModeMap table to find the intersection of supported
   2672   // mode between ConSplitter and the newly added device.
   2673   //
   2674   ConSplitterGetIntersection (
   2675     ConOutModeMap,
   2676     ConOutMapTable,
   2677     mConOut.TextOutListCount,
   2678     1,
   2679     &(mConOut.TextOutMode.MaxMode),
   2680     &(mConOut.TextOutMode.Mode)
   2681     );
   2682 
   2683   if (mConOut.TextOutMode.Mode < 0) {
   2684     mConOut.TextOut.SetMode (&(mConOut.TextOut), 0);
   2685   }
   2686 
   2687   ConSplitterGetIntersection (
   2688     StdErrModeMap,
   2689     StdErrMapTable,
   2690     mStdErr.TextOutListCount,
   2691     1,
   2692     &(mStdErr.TextOutMode.MaxMode),
   2693     &(mStdErr.TextOutMode.Mode)
   2694     );
   2695 
   2696   if (mStdErr.TextOutMode.Mode < 0) {
   2697     mStdErr.TextOut.SetMode (&(mStdErr.TextOut), 0);
   2698   }
   2699 
   2700   FreePool (ConOutMapTable);
   2701   FreePool (StdErrMapTable);
   2702 
   2703   return EFI_SUCCESS;
   2704 }
   2705 
   2706 
   2707 /**
   2708   Add Grahpics Output modes into Consplitter Text Out list.
   2709 
   2710   @param  Private               Text Out Splitter pointer.
   2711   @param  GraphicsOutput        Graphics Output protocol pointer.
   2712   @param  UgaDraw               UGA Draw protocol pointer.
   2713 
   2714   @retval EFI_SUCCESS           Output mode added successfully.
   2715   @retval other                 Failed to add output mode.
   2716 
   2717 **/
   2718 EFI_STATUS
   2719 ConSplitterAddGraphicsOutputMode (
   2720   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,
   2721   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL    *GraphicsOutput,
   2722   IN  EFI_UGA_DRAW_PROTOCOL           *UgaDraw
   2723   )
   2724 {
   2725   EFI_STATUS                           Status;
   2726   UINTN                                Index;
   2727   UINTN                                CurrentIndex;
   2728   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Mode;
   2729   UINTN                                SizeOfInfo;
   2730   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
   2731   EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE    *CurrentGraphicsOutputMode;
   2732   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeBuffer;
   2733   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *MatchedMode;
   2734   UINTN                                NumberIndex;
   2735   BOOLEAN                              Match;
   2736   BOOLEAN                              AlreadyExist;
   2737   UINT32                               UgaHorizontalResolution;
   2738   UINT32                               UgaVerticalResolution;
   2739   UINT32                               UgaColorDepth;
   2740   UINT32                               UgaRefreshRate;
   2741 
   2742   ASSERT (GraphicsOutput != NULL || UgaDraw != NULL);
   2743 
   2744   CurrentGraphicsOutputMode = Private->GraphicsOutput.Mode;
   2745 
   2746   Index        = 0;
   2747   CurrentIndex = 0;
   2748   Status       = EFI_SUCCESS;
   2749 
   2750   if (Private->CurrentNumberOfUgaDraw != 0) {
   2751     //
   2752     // If any UGA device has already been added, then there is no need to
   2753     // calculate intersection of display mode of different GOP/UGA device,
   2754     // since only one display mode will be exported (i.e. user-defined mode)
   2755     //
   2756     goto Done;
   2757   }
   2758 
   2759   if (GraphicsOutput != NULL) {
   2760     if (Private->CurrentNumberOfGraphicsOutput == 0) {
   2761         //
   2762         // This is the first Graphics Output device added
   2763         //
   2764         CurrentGraphicsOutputMode->MaxMode = GraphicsOutput->Mode->MaxMode;
   2765         CurrentGraphicsOutputMode->Mode = GraphicsOutput->Mode->Mode;
   2766         CopyMem (CurrentGraphicsOutputMode->Info, GraphicsOutput->Mode->Info, GraphicsOutput->Mode->SizeOfInfo);
   2767         CurrentGraphicsOutputMode->SizeOfInfo = GraphicsOutput->Mode->SizeOfInfo;
   2768         CurrentGraphicsOutputMode->FrameBufferBase = GraphicsOutput->Mode->FrameBufferBase;
   2769         CurrentGraphicsOutputMode->FrameBufferSize = GraphicsOutput->Mode->FrameBufferSize;
   2770 
   2771         //
   2772         // Allocate resource for the private mode buffer
   2773         //
   2774         ModeBuffer = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * GraphicsOutput->Mode->MaxMode);
   2775         if (ModeBuffer == NULL) {
   2776           return EFI_OUT_OF_RESOURCES;
   2777         }
   2778         FreePool (Private->GraphicsOutputModeBuffer);
   2779         Private->GraphicsOutputModeBuffer = ModeBuffer;
   2780 
   2781         //
   2782         // Store all supported display modes to the private mode buffer
   2783         //
   2784         Mode = ModeBuffer;
   2785         for (Index = 0; Index < GraphicsOutput->Mode->MaxMode; Index++) {
   2786           //
   2787           // The Info buffer would be allocated by callee
   2788           //
   2789           Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) Index, &SizeOfInfo, &Info);
   2790           if (EFI_ERROR (Status)) {
   2791             return Status;
   2792           }
   2793           ASSERT ( SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
   2794           CopyMem (Mode, Info, SizeOfInfo);
   2795           Mode++;
   2796           FreePool (Info);
   2797         }
   2798     } else {
   2799       //
   2800       // Check intersection of display mode
   2801       //
   2802       ModeBuffer = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * CurrentGraphicsOutputMode->MaxMode);
   2803       if (ModeBuffer == NULL) {
   2804         return EFI_OUT_OF_RESOURCES;
   2805       }
   2806 
   2807       MatchedMode = ModeBuffer;
   2808       Mode = &Private->GraphicsOutputModeBuffer[0];
   2809       for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) {
   2810         Match = FALSE;
   2811 
   2812         for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex++) {
   2813           //
   2814           // The Info buffer would be allocated by callee
   2815           //
   2816           Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info);
   2817           if (EFI_ERROR (Status)) {
   2818             return Status;
   2819           }
   2820           if ((Info->HorizontalResolution == Mode->HorizontalResolution) &&
   2821               (Info->VerticalResolution == Mode->VerticalResolution)) {
   2822             //
   2823             // If GOP device supports one mode in current mode buffer,
   2824             // it will be added into matched mode buffer
   2825             //
   2826             Match = TRUE;
   2827             FreePool (Info);
   2828             break;
   2829           }
   2830           FreePool (Info);
   2831         }
   2832 
   2833         if (Match) {
   2834           AlreadyExist = FALSE;
   2835 
   2836           //
   2837           // Check if GOP mode has been in the mode buffer, ModeBuffer = MatchedMode at begin.
   2838           //
   2839           for (Info = ModeBuffer; Info < MatchedMode; Info++) {
   2840             if ((Info->HorizontalResolution == Mode->HorizontalResolution) &&
   2841                 (Info->VerticalResolution == Mode->VerticalResolution)) {
   2842               AlreadyExist = TRUE;
   2843               break;
   2844             }
   2845           }
   2846 
   2847           if (!AlreadyExist) {
   2848             CopyMem (MatchedMode, Mode, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
   2849 
   2850             //
   2851             // Physical frame buffer is no longer available, change PixelFormat to PixelBltOnly
   2852             //
   2853             MatchedMode->Version = 0;
   2854             MatchedMode->PixelFormat = PixelBltOnly;
   2855             ZeroMem (&MatchedMode->PixelInformation, sizeof (EFI_PIXEL_BITMASK));
   2856 
   2857             MatchedMode++;
   2858           }
   2859         }
   2860 
   2861         Mode++;
   2862       }
   2863 
   2864       //
   2865       // Drop the old mode buffer, assign it to a new one
   2866       //
   2867       FreePool (Private->GraphicsOutputModeBuffer);
   2868       Private->GraphicsOutputModeBuffer = ModeBuffer;
   2869 
   2870       //
   2871       // Physical frame buffer is no longer available when there are more than one physical GOP devices
   2872       //
   2873       CurrentGraphicsOutputMode->MaxMode = (UINT32) (((UINTN) MatchedMode - (UINTN) ModeBuffer) / sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
   2874       CurrentGraphicsOutputMode->Info->PixelFormat = PixelBltOnly;
   2875       ZeroMem (&CurrentGraphicsOutputMode->Info->PixelInformation, sizeof (EFI_PIXEL_BITMASK));
   2876       CurrentGraphicsOutputMode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
   2877       CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;
   2878       CurrentGraphicsOutputMode->FrameBufferSize = 0;
   2879     }
   2880 
   2881     //
   2882     // Graphics console driver can ensure the same mode for all GOP devices
   2883     //
   2884     for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) {
   2885       Mode = &Private->GraphicsOutputModeBuffer[Index];
   2886       if ((Mode->HorizontalResolution == GraphicsOutput->Mode->Info->HorizontalResolution) &&
   2887          (Mode->VerticalResolution == GraphicsOutput->Mode->Info->VerticalResolution)) {
   2888         CurrentIndex = Index;
   2889         break;
   2890       }
   2891     }
   2892     if (Index >= CurrentGraphicsOutputMode->MaxMode) {
   2893       //
   2894       // if user defined mode is not found, set to default mode 800x600
   2895       //
   2896       for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) {
   2897         Mode = &Private->GraphicsOutputModeBuffer[Index];
   2898         if ((Mode->HorizontalResolution == 800) && (Mode->VerticalResolution == 600)) {
   2899           CurrentIndex = Index;
   2900           break;
   2901         }
   2902       }
   2903     }
   2904   } else if (UgaDraw != NULL) {
   2905     //
   2906     // Graphics console driver can ensure the same mode for all GOP devices
   2907     // so we can get the current mode from this video device
   2908     //
   2909     UgaDraw->GetMode (
   2910                UgaDraw,
   2911                &UgaHorizontalResolution,
   2912                &UgaVerticalResolution,
   2913                &UgaColorDepth,
   2914                &UgaRefreshRate
   2915                );
   2916 
   2917     CurrentGraphicsOutputMode->MaxMode = 1;
   2918     Info = CurrentGraphicsOutputMode->Info;
   2919     Info->Version = 0;
   2920     Info->HorizontalResolution                 = UgaHorizontalResolution;
   2921     Info->VerticalResolution                   = UgaVerticalResolution;
   2922     Info->PixelFormat                          = PixelBltOnly;
   2923     Info->PixelsPerScanLine                    = UgaHorizontalResolution;
   2924     CurrentGraphicsOutputMode->SizeOfInfo      = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
   2925     CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;
   2926     CurrentGraphicsOutputMode->FrameBufferSize = 0;
   2927 
   2928     //
   2929     // Update the private mode buffer
   2930     //
   2931     CopyMem (&Private->GraphicsOutputModeBuffer[0], Info, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
   2932 
   2933     //
   2934     // Only mode 0 is available to be set
   2935     //
   2936     CurrentIndex = 0;
   2937   }
   2938 
   2939 Done:
   2940 
   2941   if (GraphicsOutput != NULL) {
   2942     Private->CurrentNumberOfGraphicsOutput++;
   2943   }
   2944   if (UgaDraw != NULL) {
   2945     Private->CurrentNumberOfUgaDraw++;
   2946   }
   2947 
   2948   //
   2949   // Force GraphicsOutput mode to be set,
   2950   //
   2951 
   2952   Mode = &Private->GraphicsOutputModeBuffer[CurrentIndex];
   2953   if ((GraphicsOutput != NULL) &&
   2954       (Mode->HorizontalResolution == CurrentGraphicsOutputMode->Info->HorizontalResolution) &&
   2955       (Mode->VerticalResolution == CurrentGraphicsOutputMode->Info->VerticalResolution)) {
   2956     CurrentGraphicsOutputMode->Mode = (UINT32) CurrentIndex;
   2957     if ((Mode->HorizontalResolution != GraphicsOutput->Mode->Info->HorizontalResolution) ||
   2958         (Mode->VerticalResolution != GraphicsOutput->Mode->Info->VerticalResolution)) {
   2959       //
   2960       // If all existing video device has been set to common mode, only set new GOP device to
   2961       // the common mode
   2962       //
   2963       for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex ++) {
   2964         Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info);
   2965         if (EFI_ERROR (Status)) {
   2966           return Status;
   2967         }
   2968         if ((Info->HorizontalResolution == Mode->HorizontalResolution) && (Info->VerticalResolution == Mode->VerticalResolution)) {
   2969           FreePool (Info);
   2970           break;
   2971         }
   2972         FreePool (Info);
   2973       }
   2974       Status = GraphicsOutput->SetMode (GraphicsOutput, (UINT32) NumberIndex);
   2975     }
   2976   } else {
   2977     //
   2978     // Current mode number may need update now, so set it to an invalid mode number
   2979     //
   2980     CurrentGraphicsOutputMode->Mode = 0xffff;
   2981     //
   2982     // Graphics console can ensure all GOP devices have the same mode which can be taken as current mode.
   2983     //
   2984     Status = Private->GraphicsOutput.SetMode (&Private->GraphicsOutput, (UINT32) CurrentIndex);
   2985     if (EFI_ERROR(Status)) {
   2986       //
   2987       // If user defined mode is not valid for display device, set to the default mode 800x600.
   2988       //
   2989       (Private->GraphicsOutputModeBuffer[0]).HorizontalResolution = 800;
   2990       (Private->GraphicsOutputModeBuffer[0]).VerticalResolution   = 600;
   2991       Status = Private->GraphicsOutput.SetMode (&Private->GraphicsOutput, 0);
   2992     }
   2993   }
   2994 
   2995   return Status;
   2996 }
   2997 
   2998 /**
   2999   Set the current console out mode.
   3000 
   3001   This routine will get the current console mode information (column, row)
   3002   from ConsoleOutMode variable and set it; if the variable does not exist,
   3003   set to user defined console mode.
   3004 
   3005   @param  Private            Consplitter Text Out pointer.
   3006 
   3007 **/
   3008 VOID
   3009 ConsplitterSetConsoleOutMode (
   3010   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private
   3011   )
   3012 {
   3013   UINTN                            Col;
   3014   UINTN                            Row;
   3015   UINTN                            Mode;
   3016   UINTN                            PreferMode;
   3017   UINTN                            BaseMode;
   3018   UINTN                            MaxMode;
   3019   EFI_STATUS                       Status;
   3020   CONSOLE_OUT_MODE                 ModeInfo;
   3021   CONSOLE_OUT_MODE                 MaxModeInfo;
   3022   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;
   3023 
   3024   PreferMode   = 0xFF;
   3025   BaseMode     = 0xFF;
   3026   TextOut      = &Private->TextOut;
   3027   MaxMode      = (UINTN) (TextOut->Mode->MaxMode);
   3028 
   3029   MaxModeInfo.Column = 0;
   3030   MaxModeInfo.Row    = 0;
   3031   ModeInfo.Column    = PcdGet32 (PcdConOutColumn);
   3032   ModeInfo.Row       = PcdGet32 (PcdConOutRow);
   3033 
   3034   //
   3035   // To find the prefer mode and basic mode from Text Out mode list
   3036   //
   3037   for (Mode = 0; Mode < MaxMode; Mode++) {
   3038     Status = TextOut->QueryMode (TextOut, Mode, &Col, &Row);
   3039     if (!EFI_ERROR(Status)) {
   3040       if ((ModeInfo.Column != 0) && (ModeInfo.Row != 0)) {
   3041         //
   3042         // Use user defined column and row
   3043         //
   3044         if (Col == ModeInfo.Column && Row == ModeInfo.Row) {
   3045           PreferMode = Mode;
   3046         }
   3047       } else {
   3048         //
   3049         // If user sets PcdConOutColumn or PcdConOutRow to 0,
   3050         // find and set the highest text mode.
   3051         //
   3052         if ((Col >= MaxModeInfo.Column) && (Row >= MaxModeInfo.Row)) {
   3053           MaxModeInfo.Column  = Col;
   3054           MaxModeInfo.Row     = Row;
   3055           PreferMode          = Mode;
   3056         }
   3057       }
   3058       if (Col == 80 && Row == 25) {
   3059         BaseMode = Mode;
   3060       }
   3061     }
   3062   }
   3063 
   3064   //
   3065   // Set prefer mode to Text Out devices.
   3066   //
   3067   Status = TextOut->SetMode (TextOut, PreferMode);
   3068   if (EFI_ERROR(Status)) {
   3069     //
   3070     // if current mode setting is failed, default 80x25 mode will be set.
   3071     //
   3072     Status = TextOut->SetMode (TextOut, BaseMode);
   3073     ASSERT(!EFI_ERROR(Status));
   3074 
   3075     Status = PcdSet32S (PcdConOutColumn, 80);
   3076     ASSERT(!EFI_ERROR(Status));
   3077     Status = PcdSet32S (PcdConOutRow, 25);
   3078     ASSERT(!EFI_ERROR(Status));
   3079   }
   3080 
   3081   return ;
   3082 }
   3083 
   3084 
   3085 /**
   3086   Add Text Output Device in Consplitter Text Output list.
   3087 
   3088   @param  Private                  Text Out Splitter pointer.
   3089   @param  TextOut                  Simple Text Output protocol pointer.
   3090   @param  GraphicsOutput           Graphics Output protocol pointer.
   3091   @param  UgaDraw                  UGA Draw protocol pointer.
   3092 
   3093   @retval EFI_SUCCESS              Text Output Device added successfully.
   3094   @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.
   3095 
   3096 **/
   3097 EFI_STATUS
   3098 ConSplitterTextOutAddDevice (
   3099   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA     *Private,
   3100   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *TextOut,
   3101   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL       *GraphicsOutput,
   3102   IN  EFI_UGA_DRAW_PROTOCOL              *UgaDraw
   3103   )
   3104 {
   3105   EFI_STATUS                           Status;
   3106   UINTN                                CurrentNumOfConsoles;
   3107   INT32                                MaxMode;
   3108   UINT32                               UgaHorizontalResolution;
   3109   UINT32                               UgaVerticalResolution;
   3110   UINT32                               UgaColorDepth;
   3111   UINT32                               UgaRefreshRate;
   3112   TEXT_OUT_AND_GOP_DATA                *TextAndGop;
   3113   UINTN                                SizeOfInfo;
   3114   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
   3115   EFI_STATUS                           DeviceStatus;
   3116 
   3117   Status                = EFI_SUCCESS;
   3118   CurrentNumOfConsoles  = Private->CurrentNumberOfConsoles;
   3119 
   3120   //
   3121   // If the Text Out List is full, enlarge it by calling ConSplitterGrowBuffer().
   3122   //
   3123   while (CurrentNumOfConsoles >= Private->TextOutListCount) {
   3124     Status = ConSplitterGrowBuffer (
   3125               sizeof (TEXT_OUT_AND_GOP_DATA),
   3126               &Private->TextOutListCount,
   3127               (VOID **) &Private->TextOutList
   3128               );
   3129     if (EFI_ERROR (Status)) {
   3130       return EFI_OUT_OF_RESOURCES;
   3131     }
   3132     //
   3133     // Also need to reallocate the TextOutModeMap table
   3134     //
   3135     Status = ConSplitterGrowMapTable (Private);
   3136     if (EFI_ERROR (Status)) {
   3137       return EFI_OUT_OF_RESOURCES;
   3138     }
   3139   }
   3140 
   3141   TextAndGop          = &Private->TextOutList[CurrentNumOfConsoles];
   3142 
   3143   TextAndGop->TextOut        = TextOut;
   3144   TextAndGop->GraphicsOutput = GraphicsOutput;
   3145   TextAndGop->UgaDraw        = UgaDraw;
   3146 
   3147   if (CurrentNumOfConsoles == 0) {
   3148     //
   3149     // Add the first device's output mode to console splitter's mode list
   3150     //
   3151     Status = ConSplitterAddOutputMode (Private, TextOut);
   3152   } else {
   3153     ConSplitterSyncOutputMode (Private, TextOut);
   3154   }
   3155 
   3156   Private->CurrentNumberOfConsoles++;
   3157 
   3158   //
   3159   // Scan both TextOutList, for the intersection TextOut device
   3160   // maybe both ConOut and StdErr incorporate the same Text Out
   3161   // device in them, thus the output of both should be synced.
   3162   //
   3163   ConSplitterGetIntersectionBetweenConOutAndStrErr ();
   3164 
   3165   MaxMode     = Private->TextOutMode.MaxMode;
   3166   ASSERT (MaxMode >= 1);
   3167 
   3168   DeviceStatus = EFI_DEVICE_ERROR;
   3169   Status       = EFI_DEVICE_ERROR;
   3170 
   3171   //
   3172   // This device display mode will be added into Graphics Ouput modes.
   3173   //
   3174   if ((GraphicsOutput != NULL) || (UgaDraw != NULL)) {
   3175     DeviceStatus = ConSplitterAddGraphicsOutputMode (Private, GraphicsOutput, UgaDraw);
   3176   }
   3177 
   3178   if (FeaturePcdGet (PcdConOutUgaSupport)) {
   3179     //
   3180     // If UGA is produced by Consplitter
   3181     //
   3182     if (GraphicsOutput != NULL) {
   3183       Status = GraphicsOutput->QueryMode (GraphicsOutput, GraphicsOutput->Mode->Mode, &SizeOfInfo, &Info);
   3184       if (EFI_ERROR (Status)) {
   3185         return Status;
   3186       }
   3187       ASSERT ( SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
   3188 
   3189       UgaHorizontalResolution = Info->HorizontalResolution;
   3190       UgaVerticalResolution   = Info->VerticalResolution;
   3191 
   3192       FreePool (Info);
   3193 
   3194     } else if (UgaDraw != NULL) {
   3195       Status = UgaDraw->GetMode (
   3196                     UgaDraw,
   3197                     &UgaHorizontalResolution,
   3198                     &UgaVerticalResolution,
   3199                     &UgaColorDepth,
   3200                     &UgaRefreshRate
   3201                     );
   3202       if (!EFI_ERROR (Status) && EFI_ERROR (DeviceStatus)) {
   3203         //
   3204         // if GetMode is successfully and UGA device hasn't been set, set it
   3205         //
   3206         Status = ConSplitterUgaDrawSetMode (
   3207                     &Private->UgaDraw,
   3208                     UgaHorizontalResolution,
   3209                     UgaVerticalResolution,
   3210                     UgaColorDepth,
   3211                     UgaRefreshRate
   3212                     );
   3213       }
   3214       //
   3215       // If GetMode/SetMode is failed, set to 800x600 mode
   3216       //
   3217       if(EFI_ERROR (Status)) {
   3218         Status = ConSplitterUgaDrawSetMode (
   3219                     &Private->UgaDraw,
   3220                     800,
   3221                     600,
   3222                     32,
   3223                     60
   3224                     );
   3225       }
   3226     }
   3227   }
   3228 
   3229   if (((!EFI_ERROR (DeviceStatus)) || (!EFI_ERROR (Status))) &&
   3230       ((Private->CurrentNumberOfGraphicsOutput + Private->CurrentNumberOfUgaDraw) == 1)) {
   3231     if (!FeaturePcdGet (PcdConOutGopSupport)) {
   3232       //
   3233       // If Graphics Outpurt protocol not supported, UGA Draw protocol is installed
   3234       // on the virtual handle.
   3235       //
   3236       Status = gBS->InstallMultipleProtocolInterfaces (
   3237                       &mConOut.VirtualHandle,
   3238                       &gEfiUgaDrawProtocolGuid,
   3239                       &mConOut.UgaDraw,
   3240                       NULL
   3241                       );
   3242     } else if (!FeaturePcdGet (PcdConOutUgaSupport)) {
   3243       //
   3244       // If UGA Draw protocol not supported, Graphics Output Protocol is installed
   3245       // on virtual handle.
   3246       //
   3247       Status = gBS->InstallMultipleProtocolInterfaces (
   3248                       &mConOut.VirtualHandle,
   3249                       &gEfiGraphicsOutputProtocolGuid,
   3250                       &mConOut.GraphicsOutput,
   3251                       NULL
   3252                       );
   3253     } else {
   3254       //
   3255       // Boot Graphics Output protocol and UGA Draw protocol are supported,
   3256       // both they will be installed on virtual handle.
   3257       //
   3258       Status = gBS->InstallMultipleProtocolInterfaces (
   3259                       &mConOut.VirtualHandle,
   3260                       &gEfiGraphicsOutputProtocolGuid,
   3261                       &mConOut.GraphicsOutput,
   3262                       &gEfiUgaDrawProtocolGuid,
   3263                       &mConOut.UgaDraw,
   3264                       NULL
   3265                       );
   3266     }
   3267   }
   3268 
   3269   //
   3270   // After adding new console device, all existing console devices should be
   3271   // synced to the current shared mode.
   3272   //
   3273   ConsplitterSetConsoleOutMode (Private);
   3274 
   3275   return Status;
   3276 }
   3277 
   3278 
   3279 /**
   3280   Remove Text Out Device in Consplitter Text Out list.
   3281 
   3282   @param  Private                  Text Out Splitter pointer.
   3283   @param  TextOut                  Simple Text Output Pointer protocol pointer.
   3284 
   3285   @retval EFI_SUCCESS              Text Out Device removed successfully.
   3286   @retval EFI_NOT_FOUND            No Text Out Device found.
   3287 
   3288 **/
   3289 EFI_STATUS
   3290 ConSplitterTextOutDeleteDevice (
   3291   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA     *Private,
   3292   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *TextOut
   3293   )
   3294 {
   3295   INT32                 Index;
   3296   UINTN                 CurrentNumOfConsoles;
   3297   TEXT_OUT_AND_GOP_DATA *TextOutList;
   3298   EFI_STATUS            Status;
   3299 
   3300   //
   3301   // Remove the specified text-out device data structure from the Text out List,
   3302   // and rearrange the remaining data structures in the Text out List.
   3303   //
   3304   CurrentNumOfConsoles  = Private->CurrentNumberOfConsoles;
   3305   Index                 = (INT32) CurrentNumOfConsoles - 1;
   3306   TextOutList           = Private->TextOutList;
   3307   while (Index >= 0) {
   3308     if (TextOutList->TextOut == TextOut) {
   3309       if (TextOutList->UgaDraw != NULL) {
   3310         Private->CurrentNumberOfUgaDraw--;
   3311       }
   3312       if (TextOutList->GraphicsOutput != NULL) {
   3313         Private->CurrentNumberOfGraphicsOutput--;
   3314       }
   3315       CopyMem (TextOutList, TextOutList + 1, sizeof (TEXT_OUT_AND_GOP_DATA) * Index);
   3316       CurrentNumOfConsoles--;
   3317       break;
   3318     }
   3319 
   3320     Index--;
   3321     TextOutList++;
   3322   }
   3323   //
   3324   // The specified TextOut is not managed by the ConSplitter driver
   3325   //
   3326   if (Index < 0) {
   3327     return EFI_NOT_FOUND;
   3328   }
   3329 
   3330   if ((Private->CurrentNumberOfGraphicsOutput == 0) && (Private->CurrentNumberOfUgaDraw == 0)) {
   3331     //
   3332     // If there is not any physical GOP and UGA device in system,
   3333     // Consplitter GOP or UGA protocol will be uninstalled
   3334     //
   3335     if (!FeaturePcdGet (PcdConOutGopSupport)) {
   3336       Status = gBS->UninstallProtocolInterface (
   3337                       Private->VirtualHandle,
   3338                       &gEfiUgaDrawProtocolGuid,
   3339                       &Private->UgaDraw
   3340                       );
   3341     } else if (!FeaturePcdGet (PcdConOutUgaSupport)) {
   3342       Status = gBS->UninstallProtocolInterface (
   3343                       Private->VirtualHandle,
   3344                       &gEfiGraphicsOutputProtocolGuid,
   3345                       &Private->GraphicsOutput
   3346                       );
   3347     } else {
   3348       Status = gBS->UninstallMultipleProtocolInterfaces (
   3349              Private->VirtualHandle,
   3350              &gEfiUgaDrawProtocolGuid,
   3351              &Private->UgaDraw,
   3352              &gEfiGraphicsOutputProtocolGuid,
   3353              &Private->GraphicsOutput,
   3354              NULL
   3355              );
   3356     }
   3357   }
   3358 
   3359   if (CurrentNumOfConsoles == 0) {
   3360     //
   3361     // If the number of consoles is zero, reset all parameters
   3362     //
   3363     Private->CurrentNumberOfConsoles      = 0;
   3364     Private->TextOutMode.MaxMode          = 1;
   3365     Private->TextOutQueryData[0].Columns  = 80;
   3366     Private->TextOutQueryData[0].Rows     = 25;
   3367     TextOutSetMode (Private, 0);
   3368 
   3369     return EFI_SUCCESS;
   3370   }
   3371   //
   3372   // Max Mode is realy an intersection of the QueryMode command to all
   3373   // devices. So we must copy the QueryMode of the first device to
   3374   // QueryData.
   3375   //
   3376   ZeroMem (
   3377     Private->TextOutQueryData,
   3378     Private->TextOutQueryDataCount * sizeof (TEXT_OUT_SPLITTER_QUERY_DATA)
   3379     );
   3380 
   3381   FreePool (Private->TextOutModeMap);
   3382   Private->TextOutModeMap = NULL;
   3383   TextOutList             = Private->TextOutList;
   3384 
   3385   //
   3386   // Add the first TextOut to the QueryData array and ModeMap table
   3387   //
   3388   Status = ConSplitterAddOutputMode (Private, TextOutList->TextOut);
   3389 
   3390   //
   3391   // Now add one by one
   3392   //
   3393   Index = 1;
   3394   Private->CurrentNumberOfConsoles = 1;
   3395   TextOutList++;
   3396   while ((UINTN) Index < CurrentNumOfConsoles) {
   3397     ConSplitterSyncOutputMode (Private, TextOutList->TextOut);
   3398     Index++;
   3399     Private->CurrentNumberOfConsoles++;
   3400     TextOutList++;
   3401   }
   3402 
   3403   ConSplitterGetIntersectionBetweenConOutAndStrErr ();
   3404 
   3405   return Status;
   3406 }
   3407 
   3408 
   3409 /**
   3410   Reset the input device and optionaly run diagnostics
   3411 
   3412   @param  This                     Protocol instance pointer.
   3413   @param  ExtendedVerification     Driver may perform diagnostics on reset.
   3414 
   3415   @retval EFI_SUCCESS              The device was reset.
   3416   @retval EFI_DEVICE_ERROR         The device is not functioning properly and could
   3417                                    not be reset.
   3418 
   3419 **/
   3420 EFI_STATUS
   3421 EFIAPI
   3422 ConSplitterTextInReset (
   3423   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
   3424   IN  BOOLEAN                         ExtendedVerification
   3425   )
   3426 {
   3427   EFI_STATUS                    Status;
   3428   EFI_STATUS                    ReturnStatus;
   3429   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
   3430   UINTN                         Index;
   3431 
   3432   Private                       = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
   3433 
   3434   Private->KeyEventSignalState  = FALSE;
   3435 
   3436   //
   3437   // return the worst status met
   3438   //
   3439   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
   3440     Status = Private->TextInList[Index]->Reset (
   3441                                           Private->TextInList[Index],
   3442                                           ExtendedVerification
   3443                                           );
   3444     if (EFI_ERROR (Status)) {
   3445       ReturnStatus = Status;
   3446     }
   3447   }
   3448 
   3449   if (!EFI_ERROR (ReturnStatus)) {
   3450     ToggleStateSyncReInitialization (Private);
   3451   }
   3452 
   3453   return ReturnStatus;
   3454 }
   3455 
   3456 
   3457 /**
   3458   Reads the next keystroke from the input device. The WaitForKey Event can
   3459   be used to test for existance of a keystroke via WaitForEvent () call.
   3460 
   3461   @param  Private                  Protocol instance pointer.
   3462   @param  Key                      Driver may perform diagnostics on reset.
   3463 
   3464   @retval EFI_SUCCESS              The keystroke information was returned.
   3465   @retval EFI_NOT_READY            There was no keystroke data availiable.
   3466   @retval EFI_DEVICE_ERROR         The keydtroke information was not returned due
   3467                                    to hardware errors.
   3468 
   3469 **/
   3470 EFI_STATUS
   3471 EFIAPI
   3472 ConSplitterTextInPrivateReadKeyStroke (
   3473   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,
   3474   OUT EFI_INPUT_KEY                   *Key
   3475   )
   3476 {
   3477   EFI_STATUS    Status;
   3478   UINTN         Index;
   3479   EFI_INPUT_KEY CurrentKey;
   3480 
   3481   Key->UnicodeChar  = 0;
   3482   Key->ScanCode     = SCAN_NULL;
   3483 
   3484   //
   3485   // if no physical console input device exists, return EFI_NOT_READY;
   3486   // if any physical console input device has key input,
   3487   // return the key and EFI_SUCCESS.
   3488   //
   3489   for (Index = 0; Index < Private->CurrentNumberOfConsoles;) {
   3490     Status = Private->TextInList[Index]->ReadKeyStroke (
   3491                                           Private->TextInList[Index],
   3492                                           &CurrentKey
   3493                                           );
   3494     if (!EFI_ERROR (Status)) {
   3495       //
   3496       // If it is not partial keystorke, return the key. Otherwise, continue
   3497       // to read key from THIS physical console input device.
   3498       //
   3499       if ((CurrentKey.ScanCode != CHAR_NULL) || (CurrentKey.UnicodeChar != SCAN_NULL)) {
   3500         *Key = CurrentKey;
   3501         return Status;
   3502       }
   3503     } else {
   3504       //
   3505       // Continue to read key from NEXT physical console input device.
   3506       //
   3507       Index++;
   3508     }
   3509   }
   3510 
   3511   return EFI_NOT_READY;
   3512 }
   3513 
   3514 
   3515 
   3516 /**
   3517   Reads the next keystroke from the input device. The WaitForKey Event can
   3518   be used to test for existance of a keystroke via WaitForEvent () call.
   3519 
   3520   @param  This                     Protocol instance pointer.
   3521   @param  Key                      Driver may perform diagnostics on reset.
   3522 
   3523   @retval EFI_SUCCESS              The keystroke information was returned.
   3524   @retval EFI_NOT_READY            There was no keystroke data availiable.
   3525   @retval EFI_DEVICE_ERROR         The keydtroke information was not returned due
   3526                                    to hardware errors.
   3527 
   3528 **/
   3529 EFI_STATUS
   3530 EFIAPI
   3531 ConSplitterTextInReadKeyStroke (
   3532   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
   3533   OUT EFI_INPUT_KEY                   *Key
   3534   )
   3535 {
   3536   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
   3537 
   3538   Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
   3539 
   3540   Private->KeyEventSignalState = FALSE;
   3541 
   3542   //
   3543   // Signal ConnectConIn event on first call in Lazy ConIn mode
   3544   //
   3545   if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {
   3546     DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));
   3547     gBS->SignalEvent (Private->ConnectConInEvent);
   3548     mConInIsConnect = TRUE;
   3549   }
   3550 
   3551   return ConSplitterTextInPrivateReadKeyStroke (Private, Key);
   3552 }
   3553 
   3554 
   3555 /**
   3556   This event aggregates all the events of the ConIn devices in the spliter.
   3557 
   3558   If any events of physical ConIn devices are signaled, signal the ConIn
   3559   spliter event. This will cause the calling code to call
   3560   ConSplitterTextInReadKeyStroke ().
   3561 
   3562   @param  Event                    The Event assoicated with callback.
   3563   @param  Context                  Context registered when Event was created.
   3564 
   3565 **/
   3566 VOID
   3567 EFIAPI
   3568 ConSplitterTextInWaitForKey (
   3569   IN  EFI_EVENT                       Event,
   3570   IN  VOID                            *Context
   3571   )
   3572 {
   3573   EFI_STATUS                    Status;
   3574   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
   3575   UINTN                         Index;
   3576 
   3577   Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context;
   3578 
   3579   if (Private->KeyEventSignalState) {
   3580     //
   3581     // If KeyEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke()
   3582     //
   3583     gBS->SignalEvent (Event);
   3584     return ;
   3585   }
   3586 
   3587   //
   3588   // If any physical console input device has key input, signal the event.
   3589   //
   3590   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
   3591     Status = gBS->CheckEvent (Private->TextInList[Index]->WaitForKey);
   3592     if (!EFI_ERROR (Status)) {
   3593       gBS->SignalEvent (Event);
   3594       Private->KeyEventSignalState = TRUE;
   3595     }
   3596   }
   3597 }
   3598 
   3599 
   3600 
   3601 /**
   3602   Test if the key has been registered on input device.
   3603 
   3604   @param  RegsiteredData           A pointer to a buffer that is filled in with the
   3605                                    keystroke state data for the key that was
   3606                                    registered.
   3607   @param  InputData                A pointer to a buffer that is filled in with the
   3608                                    keystroke state data for the key that was
   3609                                    pressed.
   3610 
   3611   @retval TRUE                     Key be pressed matches a registered key.
   3612   @retval FLASE                    Match failed.
   3613 
   3614 **/
   3615 BOOLEAN
   3616 IsKeyRegistered (
   3617   IN EFI_KEY_DATA  *RegsiteredData,
   3618   IN EFI_KEY_DATA  *InputData
   3619   )
   3620 {
   3621   ASSERT (RegsiteredData != NULL && InputData != NULL);
   3622 
   3623   if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
   3624       (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
   3625     return FALSE;
   3626   }
   3627 
   3628   //
   3629   // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
   3630   //
   3631   if (RegsiteredData->KeyState.KeyShiftState != 0 &&
   3632       RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
   3633     return FALSE;
   3634   }
   3635   if (RegsiteredData->KeyState.KeyToggleState != 0 &&
   3636       RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
   3637     return FALSE;
   3638   }
   3639 
   3640   return TRUE;
   3641 
   3642 }
   3643 
   3644 
   3645 /**
   3646   Reset the input device and optionaly run diagnostics
   3647 
   3648   @param  This                     Protocol instance pointer.
   3649   @param  ExtendedVerification     Driver may perform diagnostics on reset.
   3650 
   3651   @retval EFI_SUCCESS              The device was reset.
   3652   @retval EFI_DEVICE_ERROR         The device is not functioning properly and could
   3653                                    not be reset.
   3654 
   3655 **/
   3656 EFI_STATUS
   3657 EFIAPI
   3658 ConSplitterTextInResetEx (
   3659   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
   3660   IN BOOLEAN                            ExtendedVerification
   3661   )
   3662 {
   3663   EFI_STATUS                    Status;
   3664   EFI_STATUS                    ReturnStatus;
   3665   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
   3666   UINTN                         Index;
   3667 
   3668   Private                       = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
   3669 
   3670   Private->KeyEventSignalState  = FALSE;
   3671 
   3672   //
   3673   // return the worst status met
   3674   //
   3675   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfExConsoles; Index++) {
   3676     Status = Private->TextInExList[Index]->Reset (
   3677                                              Private->TextInExList[Index],
   3678                                              ExtendedVerification
   3679                                              );
   3680     if (EFI_ERROR (Status)) {
   3681       ReturnStatus = Status;
   3682     }
   3683   }
   3684 
   3685   if (!EFI_ERROR (ReturnStatus)) {
   3686     ToggleStateSyncReInitialization (Private);
   3687   }
   3688 
   3689   return ReturnStatus;
   3690 
   3691 }
   3692 
   3693 
   3694 /**
   3695   Reads the next keystroke from the input device. The WaitForKey Event can
   3696   be used to test for existance of a keystroke via WaitForEvent () call.
   3697 
   3698   @param  This                     Protocol instance pointer.
   3699   @param  KeyData                  A pointer to a buffer that is filled in with the
   3700                                    keystroke state data for the key that was
   3701                                    pressed.
   3702 
   3703   @retval EFI_SUCCESS              The keystroke information was returned.
   3704   @retval EFI_NOT_READY            There was no keystroke data availiable.
   3705   @retval EFI_DEVICE_ERROR         The keystroke information was not returned due
   3706                                    to hardware errors.
   3707   @retval EFI_INVALID_PARAMETER    KeyData is NULL.
   3708 
   3709 **/
   3710 EFI_STATUS
   3711 EFIAPI
   3712 ConSplitterTextInReadKeyStrokeEx (
   3713   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
   3714   OUT EFI_KEY_DATA                      *KeyData
   3715   )
   3716 {
   3717   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
   3718   EFI_STATUS                    Status;
   3719   UINTN                         Index;
   3720   EFI_KEY_DATA                  CurrentKeyData;
   3721 
   3722 
   3723   if (KeyData == NULL) {
   3724     return EFI_INVALID_PARAMETER;
   3725   }
   3726 
   3727   Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
   3728 
   3729   Private->KeyEventSignalState = FALSE;
   3730 
   3731   KeyData->Key.UnicodeChar  = 0;
   3732   KeyData->Key.ScanCode     = SCAN_NULL;
   3733 
   3734   //
   3735   // Signal ConnectConIn event on first call in Lazy ConIn mode
   3736   //
   3737   if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {
   3738     DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));
   3739     gBS->SignalEvent (Private->ConnectConInEvent);
   3740     mConInIsConnect = TRUE;
   3741   }
   3742 
   3743   //
   3744   // if no physical console input device exists, return EFI_NOT_READY;
   3745   // if any physical console input device has key input,
   3746   // return the key and EFI_SUCCESS.
   3747   //
   3748   for (Index = 0; Index < Private->CurrentNumberOfExConsoles;) {
   3749     Status = Private->TextInExList[Index]->ReadKeyStrokeEx (
   3750                                           Private->TextInExList[Index],
   3751                                           &CurrentKeyData
   3752                                           );
   3753     if (!EFI_ERROR (Status)) {
   3754       //
   3755       // If virtual KeyState has been required to be exposed, or it is not
   3756       // partial keystorke, return the key. Otherwise, continue to read key
   3757       // from THIS physical console input device.
   3758       //
   3759       if ((Private->VirtualKeyStateExported) ||
   3760           (CurrentKeyData.Key.ScanCode != CHAR_NULL) ||
   3761           (CurrentKeyData.Key.UnicodeChar != SCAN_NULL)) {
   3762         CopyMem (KeyData, &CurrentKeyData, sizeof (CurrentKeyData));
   3763         return Status;
   3764       }
   3765     } else {
   3766       //
   3767       // Continue to read key from NEXT physical console input device.
   3768       //
   3769       Index++;
   3770     }
   3771   }
   3772 
   3773   return EFI_NOT_READY;
   3774 }
   3775 
   3776 
   3777 /**
   3778   Set certain state for the input device.
   3779 
   3780   @param  This                     Protocol instance pointer.
   3781   @param  KeyToggleState           A pointer to the EFI_KEY_TOGGLE_STATE to set the
   3782                                    state for the input device.
   3783 
   3784   @retval EFI_SUCCESS              The device state was set successfully.
   3785   @retval EFI_DEVICE_ERROR         The device is not functioning correctly and
   3786                                    could not have the setting adjusted.
   3787   @retval EFI_UNSUPPORTED          The device does not have the ability to set its
   3788                                    state.
   3789   @retval EFI_INVALID_PARAMETER    KeyToggleState is NULL.
   3790 
   3791 **/
   3792 EFI_STATUS
   3793 EFIAPI
   3794 ConSplitterTextInSetState (
   3795   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
   3796   IN EFI_KEY_TOGGLE_STATE               *KeyToggleState
   3797   )
   3798 {
   3799   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
   3800   EFI_STATUS                    Status;
   3801   UINTN                         Index;
   3802   EFI_KEY_TOGGLE_STATE          PhysicalKeyToggleState;
   3803 
   3804   if (KeyToggleState == NULL) {
   3805     return EFI_INVALID_PARAMETER;
   3806   }
   3807 
   3808   Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
   3809 
   3810   //
   3811   // Always turn on physical TextInEx partial key report for
   3812   // toggle state sync.
   3813   //
   3814   PhysicalKeyToggleState = *KeyToggleState | EFI_KEY_STATE_EXPOSED;
   3815 
   3816   //
   3817   // if no physical console input device exists, return EFI_SUCCESS;
   3818   // otherwise return the status of setting state of physical console input device
   3819   //
   3820   for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
   3821     Status = Private->TextInExList[Index]->SetState (
   3822                                              Private->TextInExList[Index],
   3823                                              &PhysicalKeyToggleState
   3824                                              );
   3825     if (EFI_ERROR (Status)) {
   3826       return Status;
   3827     }
   3828   }
   3829 
   3830   //
   3831   // Record the physical KeyToggleState.
   3832   //
   3833   Private->PhysicalKeyToggleState = PhysicalKeyToggleState;
   3834   //
   3835   // Get if virtual KeyState has been required to be exposed.
   3836   //
   3837   Private->VirtualKeyStateExported = (((*KeyToggleState) & EFI_KEY_STATE_EXPOSED) != 0);
   3838 
   3839   return EFI_SUCCESS;
   3840 
   3841 }
   3842 
   3843 
   3844 /**
   3845   Register a notification function for a particular keystroke for the input device.
   3846 
   3847   @param  This                     Protocol instance pointer.
   3848   @param  KeyData                  A pointer to a buffer that is filled in with the
   3849                                    keystroke information data for the key that was
   3850                                    pressed.
   3851   @param  KeyNotificationFunction  Points to the function to be called when the key
   3852                                    sequence is typed specified by KeyData.
   3853   @param  NotifyHandle             Points to the unique handle assigned to the
   3854                                    registered notification.
   3855 
   3856   @retval EFI_SUCCESS              The notification function was registered
   3857                                    successfully.
   3858   @retval EFI_OUT_OF_RESOURCES     Unable to allocate resources for necesssary data
   3859                                    structures.
   3860   @retval EFI_INVALID_PARAMETER    KeyData or KeyNotificationFunction or NotifyHandle is NULL.
   3861 
   3862 **/
   3863 EFI_STATUS
   3864 EFIAPI
   3865 ConSplitterTextInRegisterKeyNotify (
   3866   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
   3867   IN EFI_KEY_DATA                       *KeyData,
   3868   IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,
   3869   OUT VOID                              **NotifyHandle
   3870   )
   3871 {
   3872   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
   3873   EFI_STATUS                    Status;
   3874   UINTN                         Index;
   3875   TEXT_IN_EX_SPLITTER_NOTIFY    *NewNotify;
   3876   LIST_ENTRY                    *Link;
   3877   TEXT_IN_EX_SPLITTER_NOTIFY    *CurrentNotify;
   3878 
   3879 
   3880   if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
   3881     return EFI_INVALID_PARAMETER;
   3882   }
   3883 
   3884   Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
   3885 
   3886   //
   3887   // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
   3888   //
   3889   for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
   3890     CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);
   3891     if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
   3892       if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
   3893         *NotifyHandle = CurrentNotify;
   3894         return EFI_SUCCESS;
   3895       }
   3896     }
   3897   }
   3898 
   3899   //
   3900   // Allocate resource to save the notification function
   3901   //
   3902   NewNotify = (TEXT_IN_EX_SPLITTER_NOTIFY *) AllocateZeroPool (sizeof (TEXT_IN_EX_SPLITTER_NOTIFY));
   3903   if (NewNotify == NULL) {
   3904     return EFI_OUT_OF_RESOURCES;
   3905   }
   3906   NewNotify->NotifyHandleList = (EFI_HANDLE *) AllocateZeroPool (sizeof (EFI_HANDLE) *  Private->TextInExListCount);
   3907   if (NewNotify->NotifyHandleList == NULL) {
   3908     gBS->FreePool (NewNotify);
   3909     return EFI_OUT_OF_RESOURCES;
   3910   }
   3911   NewNotify->Signature         = TEXT_IN_EX_SPLITTER_NOTIFY_SIGNATURE;
   3912   NewNotify->KeyNotificationFn = KeyNotificationFunction;
   3913   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
   3914 
   3915   //
   3916   // Return the wrong status of registering key notify of
   3917   // physical console input device if meet problems
   3918   //
   3919   for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
   3920     Status = Private->TextInExList[Index]->RegisterKeyNotify (
   3921                                              Private->TextInExList[Index],
   3922                                              KeyData,
   3923                                              KeyNotificationFunction,
   3924                                              &NewNotify->NotifyHandleList[Index]
   3925                                              );
   3926     if (EFI_ERROR (Status)) {
   3927       //
   3928       // Un-register the key notify on all physical console input devices
   3929       //
   3930       while (Index-- != 0) {
   3931         Private->TextInExList[Index]->UnregisterKeyNotify (
   3932                                         Private->TextInExList[Index],
   3933                                         NewNotify->NotifyHandleList[Index]
   3934                                         );
   3935       }
   3936       gBS->FreePool (NewNotify->NotifyHandleList);
   3937       gBS->FreePool (NewNotify);
   3938       return Status;
   3939     }
   3940   }
   3941 
   3942   InsertTailList (&Private->NotifyList, &NewNotify->NotifyEntry);
   3943 
   3944   *NotifyHandle                = NewNotify;
   3945 
   3946   return EFI_SUCCESS;
   3947 
   3948 }
   3949 
   3950 
   3951 /**
   3952   Remove a registered notification function from a particular keystroke.
   3953 
   3954   @param  This                     Protocol instance pointer.
   3955   @param  NotificationHandle       The handle of the notification function being
   3956                                    unregistered.
   3957 
   3958   @retval EFI_SUCCESS              The notification function was unregistered
   3959                                    successfully.
   3960   @retval EFI_INVALID_PARAMETER    The NotificationHandle is invalid.
   3961 
   3962 **/
   3963 EFI_STATUS
   3964 EFIAPI
   3965 ConSplitterTextInUnregisterKeyNotify (
   3966   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
   3967   IN VOID                               *NotificationHandle
   3968   )
   3969 {
   3970   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
   3971   UINTN                         Index;
   3972   TEXT_IN_EX_SPLITTER_NOTIFY    *CurrentNotify;
   3973   LIST_ENTRY                    *Link;
   3974 
   3975   if (NotificationHandle == NULL) {
   3976     return EFI_INVALID_PARAMETER;
   3977   }
   3978 
   3979   Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
   3980 
   3981   for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
   3982     CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);
   3983     if (CurrentNotify == NotificationHandle) {
   3984       for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
   3985         Private->TextInExList[Index]->UnregisterKeyNotify (
   3986                                         Private->TextInExList[Index],
   3987                                         CurrentNotify->NotifyHandleList[Index]
   3988                                         );
   3989       }
   3990       RemoveEntryList (&CurrentNotify->NotifyEntry);
   3991 
   3992       gBS->FreePool (CurrentNotify->NotifyHandleList);
   3993       gBS->FreePool (CurrentNotify);
   3994       return EFI_SUCCESS;
   3995     }
   3996   }
   3997 
   3998   //
   3999   // NotificationHandle is not found in database
   4000   //
   4001   return EFI_INVALID_PARAMETER;
   4002 }
   4003 
   4004 
   4005 /**
   4006   Reset the input device and optionaly run diagnostics
   4007 
   4008   @param  This                     Protocol instance pointer.
   4009   @param  ExtendedVerification     Driver may perform diagnostics on reset.
   4010 
   4011   @retval EFI_SUCCESS              The device was reset.
   4012   @retval EFI_DEVICE_ERROR         The device is not functioning properly and could
   4013                                    not be reset.
   4014 
   4015 **/
   4016 EFI_STATUS
   4017 EFIAPI
   4018 ConSplitterSimplePointerReset (
   4019   IN  EFI_SIMPLE_POINTER_PROTOCOL     *This,
   4020   IN  BOOLEAN                         ExtendedVerification
   4021   )
   4022 {
   4023   EFI_STATUS                    Status;
   4024   EFI_STATUS                    ReturnStatus;
   4025   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
   4026   UINTN                         Index;
   4027 
   4028   Private                         = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS (This);
   4029 
   4030   Private->InputEventSignalState  = FALSE;
   4031 
   4032   if (Private->CurrentNumberOfPointers == 0) {
   4033     return EFI_SUCCESS;
   4034   }
   4035   //
   4036   // return the worst status met
   4037   //
   4038   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfPointers; Index++) {
   4039     Status = Private->PointerList[Index]->Reset (
   4040                                             Private->PointerList[Index],
   4041                                             ExtendedVerification
   4042                                             );
   4043     if (EFI_ERROR (Status)) {
   4044       ReturnStatus = Status;
   4045     }
   4046   }
   4047 
   4048   return ReturnStatus;
   4049 }
   4050 
   4051 
   4052 /**
   4053   Reads the next keystroke from the input device. The WaitForKey Event can
   4054   be used to test for existance of a keystroke via WaitForEvent () call.
   4055 
   4056   @param  Private                  Protocol instance pointer.
   4057   @param  State                    The state information of simple pointer device.
   4058 
   4059   @retval EFI_SUCCESS              The keystroke information was returned.
   4060   @retval EFI_NOT_READY            There was no keystroke data availiable.
   4061   @retval EFI_DEVICE_ERROR         The keydtroke information was not returned due
   4062                                    to hardware errors.
   4063 
   4064 **/
   4065 EFI_STATUS
   4066 EFIAPI
   4067 ConSplitterSimplePointerPrivateGetState (
   4068   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,
   4069   IN OUT EFI_SIMPLE_POINTER_STATE     *State
   4070   )
   4071 {
   4072   EFI_STATUS                Status;
   4073   EFI_STATUS                ReturnStatus;
   4074   UINTN                     Index;
   4075   EFI_SIMPLE_POINTER_STATE  CurrentState;
   4076 
   4077   State->RelativeMovementX  = 0;
   4078   State->RelativeMovementY  = 0;
   4079   State->RelativeMovementZ  = 0;
   4080   State->LeftButton         = FALSE;
   4081   State->RightButton        = FALSE;
   4082 
   4083   //
   4084   // if no physical console input device exists, return EFI_NOT_READY;
   4085   // if any physical console input device has key input,
   4086   // return the key and EFI_SUCCESS.
   4087   //
   4088   ReturnStatus = EFI_NOT_READY;
   4089   for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) {
   4090 
   4091     Status = Private->PointerList[Index]->GetState (
   4092                                             Private->PointerList[Index],
   4093                                             &CurrentState
   4094                                             );
   4095     if (!EFI_ERROR (Status)) {
   4096       if (ReturnStatus == EFI_NOT_READY) {
   4097         ReturnStatus = EFI_SUCCESS;
   4098       }
   4099 
   4100       if (CurrentState.LeftButton) {
   4101         State->LeftButton = TRUE;
   4102       }
   4103 
   4104       if (CurrentState.RightButton) {
   4105         State->RightButton = TRUE;
   4106       }
   4107 
   4108       if (CurrentState.RelativeMovementX != 0 && Private->PointerList[Index]->Mode->ResolutionX != 0) {
   4109         State->RelativeMovementX += (CurrentState.RelativeMovementX * (INT32) Private->SimplePointerMode.ResolutionX) / (INT32) Private->PointerList[Index]->Mode->ResolutionX;
   4110       }
   4111 
   4112       if (CurrentState.RelativeMovementY != 0 && Private->PointerList[Index]->Mode->ResolutionY != 0) {
   4113         State->RelativeMovementY += (CurrentState.RelativeMovementY * (INT32) Private->SimplePointerMode.ResolutionY) / (INT32) Private->PointerList[Index]->Mode->ResolutionY;
   4114       }
   4115 
   4116       if (CurrentState.RelativeMovementZ != 0 && Private->PointerList[Index]->Mode->ResolutionZ != 0) {
   4117         State->RelativeMovementZ += (CurrentState.RelativeMovementZ * (INT32) Private->SimplePointerMode.ResolutionZ) / (INT32) Private->PointerList[Index]->Mode->ResolutionZ;
   4118       }
   4119     } else if (Status == EFI_DEVICE_ERROR) {
   4120       ReturnStatus = EFI_DEVICE_ERROR;
   4121     }
   4122   }
   4123 
   4124   return ReturnStatus;
   4125 }
   4126 
   4127 
   4128 /**
   4129   Reads the next keystroke from the input device. The WaitForKey Event can
   4130   be used to test for existance of a keystroke via WaitForEvent () call.
   4131 
   4132   @param  This                     A pointer to protocol instance.
   4133   @param  State                    A pointer to state information on the pointer device
   4134 
   4135   @retval EFI_SUCCESS              The keystroke information was returned in State.
   4136   @retval EFI_NOT_READY            There was no keystroke data availiable.
   4137   @retval EFI_DEVICE_ERROR         The keydtroke information was not returned due
   4138                                    to hardware errors.
   4139 
   4140 **/
   4141 EFI_STATUS
   4142 EFIAPI
   4143 ConSplitterSimplePointerGetState (
   4144   IN  EFI_SIMPLE_POINTER_PROTOCOL     *This,
   4145   IN OUT EFI_SIMPLE_POINTER_STATE     *State
   4146   )
   4147 {
   4148   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
   4149 
   4150   Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS (This);
   4151 
   4152   Private->InputEventSignalState = FALSE;
   4153 
   4154   return ConSplitterSimplePointerPrivateGetState (Private, State);
   4155 }
   4156 
   4157 
   4158 /**
   4159   This event agregates all the events of the ConIn devices in the spliter.
   4160   If any events of physical ConIn devices are signaled, signal the ConIn
   4161   spliter event. This will cause the calling code to call
   4162   ConSplitterTextInReadKeyStroke ().
   4163 
   4164   @param  Event                    The Event assoicated with callback.
   4165   @param  Context                  Context registered when Event was created.
   4166 
   4167 **/
   4168 VOID
   4169 EFIAPI
   4170 ConSplitterSimplePointerWaitForInput (
   4171   IN  EFI_EVENT                       Event,
   4172   IN  VOID                            *Context
   4173   )
   4174 {
   4175   EFI_STATUS                    Status;
   4176   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
   4177   UINTN                         Index;
   4178 
   4179   Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context;
   4180 
   4181   //
   4182   // if InputEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke()
   4183   //
   4184   if (Private->InputEventSignalState) {
   4185     gBS->SignalEvent (Event);
   4186     return ;
   4187   }
   4188   //
   4189   // if any physical console input device has key input, signal the event.
   4190   //
   4191   for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) {
   4192     Status = gBS->CheckEvent (Private->PointerList[Index]->WaitForInput);
   4193     if (!EFI_ERROR (Status)) {
   4194       gBS->SignalEvent (Event);
   4195       Private->InputEventSignalState = TRUE;
   4196     }
   4197   }
   4198 }
   4199 
   4200 /**
   4201   Resets the pointer device hardware.
   4202 
   4203   @param  This                     Protocol instance pointer.
   4204   @param  ExtendedVerification     Driver may perform diagnostics on reset.
   4205 
   4206   @retval EFI_SUCCESS              The device was reset.
   4207   @retval EFI_DEVICE_ERROR         The device is not functioning correctly and
   4208                                    could not be reset.
   4209 
   4210 **/
   4211 EFI_STATUS
   4212 EFIAPI
   4213 ConSplitterAbsolutePointerReset (
   4214   IN EFI_ABSOLUTE_POINTER_PROTOCOL   *This,
   4215   IN BOOLEAN                         ExtendedVerification
   4216   )
   4217 {
   4218   EFI_STATUS                    Status;
   4219   EFI_STATUS                    ReturnStatus;
   4220   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
   4221   UINTN                         Index;
   4222 
   4223   Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_ABSOLUTE_POINTER_THIS (This);
   4224 
   4225   Private->AbsoluteInputEventSignalState = FALSE;
   4226 
   4227   if (Private->CurrentNumberOfAbsolutePointers == 0) {
   4228     return EFI_SUCCESS;
   4229   }
   4230   //
   4231   // return the worst status met
   4232   //
   4233   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {
   4234     Status = Private->AbsolutePointerList[Index]->Reset (
   4235                                                     Private->AbsolutePointerList[Index],
   4236                                                     ExtendedVerification
   4237                                                     );
   4238     if (EFI_ERROR (Status)) {
   4239       ReturnStatus = Status;
   4240     }
   4241   }
   4242 
   4243   return ReturnStatus;
   4244 }
   4245 
   4246 
   4247 /**
   4248   Retrieves the current state of a pointer device.
   4249 
   4250   @param  This                     Protocol instance pointer.
   4251   @param  State                    A pointer to the state information on the
   4252                                    pointer device.
   4253 
   4254   @retval EFI_SUCCESS              The state of the pointer device was returned in
   4255                                    State..
   4256   @retval EFI_NOT_READY            The state of the pointer device has not changed
   4257                                    since the last call to GetState().
   4258   @retval EFI_DEVICE_ERROR         A device error occurred while attempting to
   4259                                    retrieve the pointer device's current state.
   4260 
   4261 **/
   4262 EFI_STATUS
   4263 EFIAPI
   4264 ConSplitterAbsolutePointerGetState (
   4265   IN EFI_ABSOLUTE_POINTER_PROTOCOL   *This,
   4266   IN OUT EFI_ABSOLUTE_POINTER_STATE  *State
   4267   )
   4268 {
   4269   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
   4270   EFI_STATUS                    Status;
   4271   EFI_STATUS                    ReturnStatus;
   4272   UINTN                         Index;
   4273   EFI_ABSOLUTE_POINTER_STATE    CurrentState;
   4274   UINT64                        MinX;
   4275   UINT64                        MinY;
   4276   UINT64                        MinZ;
   4277   UINT64                        MaxX;
   4278   UINT64                        MaxY;
   4279   UINT64                        MaxZ;
   4280   UINT64                        VirtualMinX;
   4281   UINT64                        VirtualMinY;
   4282   UINT64                        VirtualMinZ;
   4283   UINT64                        VirtualMaxX;
   4284   UINT64                        VirtualMaxY;
   4285   UINT64                        VirtualMaxZ;
   4286 
   4287   Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_ABSOLUTE_POINTER_THIS (This);
   4288 
   4289   Private->AbsoluteInputEventSignalState = FALSE;
   4290 
   4291   State->CurrentX                        = 0;
   4292   State->CurrentY                        = 0;
   4293   State->CurrentZ                        = 0;
   4294   State->ActiveButtons                   = 0;
   4295 
   4296   VirtualMinX = Private->AbsolutePointerMode.AbsoluteMinX;
   4297   VirtualMinY = Private->AbsolutePointerMode.AbsoluteMinY;
   4298   VirtualMinZ = Private->AbsolutePointerMode.AbsoluteMinZ;
   4299   VirtualMaxX = Private->AbsolutePointerMode.AbsoluteMaxX;
   4300   VirtualMaxY = Private->AbsolutePointerMode.AbsoluteMaxY;
   4301   VirtualMaxZ = Private->AbsolutePointerMode.AbsoluteMaxZ;
   4302 
   4303   //
   4304   // if no physical pointer device exists, return EFI_NOT_READY;
   4305   // if any physical pointer device has changed state,
   4306   // return the state and EFI_SUCCESS.
   4307   //
   4308   ReturnStatus = EFI_NOT_READY;
   4309   for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {
   4310 
   4311     Status = Private->AbsolutePointerList[Index]->GetState (
   4312                                                     Private->AbsolutePointerList[Index],
   4313                                                     &CurrentState
   4314                                                     );
   4315     if (!EFI_ERROR (Status)) {
   4316       if (ReturnStatus == EFI_NOT_READY) {
   4317         ReturnStatus = EFI_SUCCESS;
   4318       }
   4319 
   4320       MinX = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinX;
   4321       MinY = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinY;
   4322       MinZ = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinZ;
   4323       MaxX = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxX;
   4324       MaxY = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxY;
   4325       MaxZ = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxZ;
   4326 
   4327       State->ActiveButtons = CurrentState.ActiveButtons;
   4328 
   4329       //
   4330       // Rescale to Con Splitter virtual Absolute Pointer's resolution.
   4331       //
   4332       if (!(MinX == 0 && MaxX == 0)) {
   4333         State->CurrentX = VirtualMinX + DivU64x64Remainder (
   4334                                           MultU64x64 (
   4335                                             CurrentState.CurrentX,
   4336                                             VirtualMaxX - VirtualMinX
   4337                                             ),
   4338                                           MaxX - MinX,
   4339                                           NULL
   4340                                           );
   4341       }
   4342       if (!(MinY == 0 && MaxY == 0)) {
   4343         State->CurrentY = VirtualMinY + DivU64x64Remainder (
   4344                                           MultU64x64 (
   4345                                             CurrentState.CurrentY,
   4346                                             VirtualMaxY - VirtualMinY
   4347                                             ),
   4348                                           MaxY - MinY,
   4349                                           NULL
   4350                                           );
   4351       }
   4352       if (!(MinZ == 0 && MaxZ == 0)) {
   4353         State->CurrentZ = VirtualMinZ + DivU64x64Remainder (
   4354                                           MultU64x64 (
   4355                                             CurrentState.CurrentZ,
   4356                                             VirtualMaxZ - VirtualMinZ
   4357                                             ),
   4358                                           MaxZ - MinZ,
   4359                                           NULL
   4360                                           );
   4361       }
   4362 
   4363     } else if (Status == EFI_DEVICE_ERROR) {
   4364       ReturnStatus = EFI_DEVICE_ERROR;
   4365     }
   4366   }
   4367 
   4368   return ReturnStatus;
   4369 }
   4370 
   4371 
   4372 /**
   4373   This event agregates all the events of the pointer devices in the splitter.
   4374   If any events of physical pointer devices are signaled, signal the pointer
   4375   splitter event. This will cause the calling code to call
   4376   ConSplitterAbsolutePointerGetState ().
   4377 
   4378   @param  Event                    The Event assoicated with callback.
   4379   @param  Context                  Context registered when Event was created.
   4380 
   4381 **/
   4382 VOID
   4383 EFIAPI
   4384 ConSplitterAbsolutePointerWaitForInput (
   4385   IN  EFI_EVENT                       Event,
   4386   IN  VOID                            *Context
   4387   )
   4388 {
   4389   EFI_STATUS                    Status;
   4390   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
   4391   UINTN                         Index;
   4392 
   4393   Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context;
   4394 
   4395   //
   4396   // if AbsoluteInputEventSignalState is flagged before,
   4397   // and not cleared by Reset() or GetState(), signal it
   4398   //
   4399   if (Private->AbsoluteInputEventSignalState) {
   4400     gBS->SignalEvent (Event);
   4401     return ;
   4402   }
   4403   //
   4404   // if any physical console input device has key input, signal the event.
   4405   //
   4406   for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {
   4407     Status = gBS->CheckEvent (Private->AbsolutePointerList[Index]->WaitForInput);
   4408     if (!EFI_ERROR (Status)) {
   4409       gBS->SignalEvent (Event);
   4410       Private->AbsoluteInputEventSignalState = TRUE;
   4411     }
   4412   }
   4413 }
   4414 
   4415 
   4416 /**
   4417   Reset the text output device hardware and optionaly run diagnostics
   4418 
   4419   @param  This                     Protocol instance pointer.
   4420   @param  ExtendedVerification     Driver may perform more exhaustive verfication
   4421                                    operation of the device during reset.
   4422 
   4423   @retval EFI_SUCCESS              The text output device was reset.
   4424   @retval EFI_DEVICE_ERROR         The text output device is not functioning
   4425                                    correctly and could not be reset.
   4426 
   4427 **/
   4428 EFI_STATUS
   4429 EFIAPI
   4430 ConSplitterTextOutReset (
   4431   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
   4432   IN  BOOLEAN                            ExtendedVerification
   4433   )
   4434 {
   4435   EFI_STATUS                      Status;
   4436   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
   4437   UINTN                           Index;
   4438   EFI_STATUS                      ReturnStatus;
   4439 
   4440   Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
   4441 
   4442   //
   4443   // return the worst status met
   4444   //
   4445   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
   4446     Status = Private->TextOutList[Index].TextOut->Reset (
   4447                                                     Private->TextOutList[Index].TextOut,
   4448                                                     ExtendedVerification
   4449                                                     );
   4450     if (EFI_ERROR (Status)) {
   4451       ReturnStatus = Status;
   4452     }
   4453   }
   4454 
   4455   This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BLACK));
   4456 
   4457   //
   4458   // reset all mode parameters
   4459   //
   4460   TextOutSetMode (Private, 0);
   4461 
   4462   return ReturnStatus;
   4463 }
   4464 
   4465 
   4466 /**
   4467   Write a Unicode string to the output device.
   4468 
   4469   @param  This                     Protocol instance pointer.
   4470   @param  WString                  The NULL-terminated Unicode string to be
   4471                                    displayed on the output device(s). All output
   4472                                    devices must also support the Unicode drawing
   4473                                    defined in this file.
   4474 
   4475   @retval EFI_SUCCESS              The string was output to the device.
   4476   @retval EFI_DEVICE_ERROR         The device reported an error while attempting to
   4477                                    output the text.
   4478   @retval EFI_UNSUPPORTED          The output device's mode is not currently in a
   4479                                    defined text mode.
   4480   @retval EFI_WARN_UNKNOWN_GLYPH   This warning code indicates that some of the
   4481                                    characters in the Unicode string could not be
   4482                                    rendered and were skipped.
   4483 
   4484 **/
   4485 EFI_STATUS
   4486 EFIAPI
   4487 ConSplitterTextOutOutputString (
   4488   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
   4489   IN  CHAR16                             *WString
   4490   )
   4491 {
   4492   EFI_STATUS                      Status;
   4493   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
   4494   UINTN                           Index;
   4495   EFI_STATUS                      ReturnStatus;
   4496   UINTN                           MaxColumn;
   4497   UINTN                           MaxRow;
   4498 
   4499   This->SetAttribute (This, This->Mode->Attribute);
   4500 
   4501   Private         = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
   4502 
   4503   //
   4504   // return the worst status met
   4505   //
   4506   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
   4507     Status = Private->TextOutList[Index].TextOut->OutputString (
   4508                                                     Private->TextOutList[Index].TextOut,
   4509                                                     WString
   4510                                                     );
   4511     if (EFI_ERROR (Status)) {
   4512       ReturnStatus = Status;
   4513     }
   4514   }
   4515 
   4516   if (Private->CurrentNumberOfConsoles > 0) {
   4517     Private->TextOutMode.CursorColumn = Private->TextOutList[0].TextOut->Mode->CursorColumn;
   4518     Private->TextOutMode.CursorRow    = Private->TextOutList[0].TextOut->Mode->CursorRow;
   4519   } else {
   4520     //
   4521     // When there is no real console devices in system,
   4522     // update cursor position for the virtual device in consplitter.
   4523     //
   4524     Private->TextOut.QueryMode (
   4525                        &Private->TextOut,
   4526                        Private->TextOutMode.Mode,
   4527                        &MaxColumn,
   4528                        &MaxRow
   4529                        );
   4530     for (; *WString != CHAR_NULL; WString++) {
   4531       switch (*WString) {
   4532       case CHAR_BACKSPACE:
   4533         if (Private->TextOutMode.CursorColumn == 0 && Private->TextOutMode.CursorRow > 0) {
   4534           Private->TextOutMode.CursorRow--;
   4535           Private->TextOutMode.CursorColumn = (INT32) (MaxColumn - 1);
   4536         } else if (Private->TextOutMode.CursorColumn > 0) {
   4537           Private->TextOutMode.CursorColumn--;
   4538         }
   4539         break;
   4540 
   4541       case CHAR_LINEFEED:
   4542         if (Private->TextOutMode.CursorRow < (INT32) (MaxRow - 1)) {
   4543           Private->TextOutMode.CursorRow++;
   4544         }
   4545         break;
   4546 
   4547       case CHAR_CARRIAGE_RETURN:
   4548         Private->TextOutMode.CursorColumn = 0;
   4549         break;
   4550 
   4551       default:
   4552         if (Private->TextOutMode.CursorColumn < (INT32) (MaxColumn - 1)) {
   4553           Private->TextOutMode.CursorColumn++;
   4554         } else {
   4555           Private->TextOutMode.CursorColumn = 0;
   4556           if (Private->TextOutMode.CursorRow < (INT32) (MaxRow - 1)) {
   4557             Private->TextOutMode.CursorRow++;
   4558           }
   4559         }
   4560         break;
   4561       }
   4562     }
   4563   }
   4564 
   4565   return ReturnStatus;
   4566 }
   4567 
   4568 
   4569 /**
   4570   Verifies that all characters in a Unicode string can be output to the
   4571   target device.
   4572 
   4573   @param  This                     Protocol instance pointer.
   4574   @param  WString                  The NULL-terminated Unicode string to be
   4575                                    examined for the output device(s).
   4576 
   4577   @retval EFI_SUCCESS              The device(s) are capable of rendering the
   4578                                    output string.
   4579   @retval EFI_UNSUPPORTED          Some of the characters in the Unicode string
   4580                                    cannot be rendered by one or more of the output
   4581                                    devices mapped by the EFI handle.
   4582 
   4583 **/
   4584 EFI_STATUS
   4585 EFIAPI
   4586 ConSplitterTextOutTestString (
   4587   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
   4588   IN  CHAR16                             *WString
   4589   )
   4590 {
   4591   EFI_STATUS                      Status;
   4592   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
   4593   UINTN                           Index;
   4594   EFI_STATUS                      ReturnStatus;
   4595 
   4596   Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
   4597 
   4598   //
   4599   // return the worst status met
   4600   //
   4601   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
   4602     Status = Private->TextOutList[Index].TextOut->TestString (
   4603                                                     Private->TextOutList[Index].TextOut,
   4604                                                     WString
   4605                                                     );
   4606     if (EFI_ERROR (Status)) {
   4607       ReturnStatus = Status;
   4608     }
   4609   }
   4610   //
   4611   // There is no DevNullTextOutTestString () since a Unicode buffer would
   4612   // always return EFI_SUCCESS.
   4613   // ReturnStatus will be EFI_SUCCESS if no consoles are present
   4614   //
   4615   return ReturnStatus;
   4616 }
   4617 
   4618 
   4619 /**
   4620   Returns information for an available text mode that the output device(s)
   4621   supports.
   4622 
   4623   @param  This                     Protocol instance pointer.
   4624   @param  ModeNumber               The mode number to return information on.
   4625   @param  Columns                  Returns the columns of the text output device
   4626                                    for the requested ModeNumber.
   4627   @param  Rows                     Returns the rows of the text output device
   4628                                    for the requested ModeNumber.
   4629 
   4630   @retval EFI_SUCCESS              The requested mode information was returned.
   4631   @retval EFI_DEVICE_ERROR         The device had an error and could not complete
   4632                                    the request.
   4633   @retval EFI_UNSUPPORTED          The mode number was not valid.
   4634 
   4635 **/
   4636 EFI_STATUS
   4637 EFIAPI
   4638 ConSplitterTextOutQueryMode (
   4639   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
   4640   IN  UINTN                              ModeNumber,
   4641   OUT UINTN                              *Columns,
   4642   OUT UINTN                              *Rows
   4643   )
   4644 {
   4645   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
   4646   UINTN                           CurrentMode;
   4647   INT32                           *TextOutModeMap;
   4648 
   4649   Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
   4650 
   4651   //
   4652   // Check whether param ModeNumber is valid.
   4653   // ModeNumber should be within range 0 ~ MaxMode - 1.
   4654   //
   4655   if ( (ModeNumber > (UINTN)(((UINT32)-1)>>1)) ) {
   4656     return EFI_UNSUPPORTED;
   4657   }
   4658 
   4659   if ((INT32) ModeNumber >= This->Mode->MaxMode) {
   4660     return EFI_UNSUPPORTED;
   4661   }
   4662 
   4663   //
   4664   // We get the available mode from mode intersection map if it's available
   4665   //
   4666   if (Private->TextOutModeMap != NULL) {
   4667     TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber;
   4668     CurrentMode    = (UINTN)(*TextOutModeMap);
   4669     *Columns       = Private->TextOutQueryData[CurrentMode].Columns;
   4670     *Rows          = Private->TextOutQueryData[CurrentMode].Rows;
   4671   } else {
   4672     *Columns  = Private->TextOutQueryData[ModeNumber].Columns;
   4673     *Rows     = Private->TextOutQueryData[ModeNumber].Rows;
   4674   }
   4675 
   4676   if (*Columns <= 0 && *Rows <= 0) {
   4677     return EFI_UNSUPPORTED;
   4678 
   4679   }
   4680 
   4681   return EFI_SUCCESS;
   4682 }
   4683 
   4684 
   4685 /**
   4686   Sets the output device(s) to a specified mode.
   4687 
   4688   @param  This                     Protocol instance pointer.
   4689   @param  ModeNumber               The mode number to set.
   4690 
   4691   @retval EFI_SUCCESS              The requested text mode was set.
   4692   @retval EFI_DEVICE_ERROR         The device had an error and could not complete
   4693                                    the request.
   4694   @retval EFI_UNSUPPORTED          The mode number was not valid.
   4695 
   4696 **/
   4697 EFI_STATUS
   4698 EFIAPI
   4699 ConSplitterTextOutSetMode (
   4700   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
   4701   IN  UINTN                              ModeNumber
   4702   )
   4703 {
   4704   EFI_STATUS                      Status;
   4705   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
   4706   UINTN                           Index;
   4707   INT32                           *TextOutModeMap;
   4708   EFI_STATUS                      ReturnStatus;
   4709 
   4710   Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
   4711 
   4712   //
   4713   // Check whether param ModeNumber is valid.
   4714   // ModeNumber should be within range 0 ~ MaxMode - 1.
   4715   //
   4716   if ( (ModeNumber > (UINTN)(((UINT32)-1)>>1)) ) {
   4717     return EFI_UNSUPPORTED;
   4718   }
   4719 
   4720   if ((INT32) ModeNumber >= This->Mode->MaxMode) {
   4721     return EFI_UNSUPPORTED;
   4722   }
   4723   //
   4724   // If the mode is being set to the curent mode, then just clear the screen and return.
   4725   //
   4726   if (Private->TextOutMode.Mode == (INT32) ModeNumber) {
   4727     return ConSplitterTextOutClearScreen (This);
   4728   }
   4729   //
   4730   // return the worst status met
   4731   //
   4732   TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber;
   4733   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
   4734     Status = Private->TextOutList[Index].TextOut->SetMode (
   4735                                                     Private->TextOutList[Index].TextOut,
   4736                                                     TextOutModeMap[Index]
   4737                                                     );
   4738     if (EFI_ERROR (Status)) {
   4739       ReturnStatus = Status;
   4740     }
   4741   }
   4742 
   4743   //
   4744   // Set mode parameter to specified mode number
   4745   //
   4746   TextOutSetMode (Private, ModeNumber);
   4747 
   4748   return ReturnStatus;
   4749 }
   4750 
   4751 
   4752 /**
   4753   Sets the background and foreground colors for the OutputString () and
   4754   ClearScreen () functions.
   4755 
   4756   @param  This                     Protocol instance pointer.
   4757   @param  Attribute                The attribute to set. Bits 0..3 are the
   4758                                    foreground color, and bits 4..6 are the
   4759                                    background color. All other bits are undefined
   4760                                    and must be zero. The valid Attributes are
   4761                                    defined in this file.
   4762 
   4763   @retval EFI_SUCCESS              The attribute was set.
   4764   @retval EFI_DEVICE_ERROR         The device had an error and could not complete
   4765                                    the request.
   4766   @retval EFI_UNSUPPORTED          The attribute requested is not defined.
   4767 
   4768 **/
   4769 EFI_STATUS
   4770 EFIAPI
   4771 ConSplitterTextOutSetAttribute (
   4772   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
   4773   IN  UINTN                              Attribute
   4774   )
   4775 {
   4776   EFI_STATUS                      Status;
   4777   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
   4778   UINTN                           Index;
   4779   EFI_STATUS                      ReturnStatus;
   4780 
   4781   Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
   4782 
   4783   //
   4784   // Check whether param Attribute is valid.
   4785   //
   4786   if ((Attribute | 0x7F) != 0x7F) {
   4787     return EFI_UNSUPPORTED;
   4788   }
   4789 
   4790   //
   4791   // return the worst status met
   4792   //
   4793   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
   4794     Status = Private->TextOutList[Index].TextOut->SetAttribute (
   4795                                                     Private->TextOutList[Index].TextOut,
   4796                                                     Attribute
   4797                                                     );
   4798     if (EFI_ERROR (Status)) {
   4799       ReturnStatus = Status;
   4800     }
   4801   }
   4802 
   4803   Private->TextOutMode.Attribute = (INT32) Attribute;
   4804 
   4805   return ReturnStatus;
   4806 }
   4807 
   4808 
   4809 /**
   4810   Clears the output device(s) display to the currently selected background
   4811   color.
   4812 
   4813   @param  This                     Protocol instance pointer.
   4814 
   4815   @retval EFI_SUCCESS              The operation completed successfully.
   4816   @retval EFI_DEVICE_ERROR         The device had an error and could not complete
   4817                                    the request.
   4818   @retval EFI_UNSUPPORTED          The output device is not in a valid text mode.
   4819 
   4820 **/
   4821 EFI_STATUS
   4822 EFIAPI
   4823 ConSplitterTextOutClearScreen (
   4824   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This
   4825   )
   4826 {
   4827   EFI_STATUS                      Status;
   4828   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
   4829   UINTN                           Index;
   4830   EFI_STATUS                      ReturnStatus;
   4831 
   4832   Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
   4833 
   4834   //
   4835   // return the worst status met
   4836   //
   4837   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
   4838     Status = Private->TextOutList[Index].TextOut->ClearScreen (Private->TextOutList[Index].TextOut);
   4839     if (EFI_ERROR (Status)) {
   4840       ReturnStatus = Status;
   4841     }
   4842   }
   4843 
   4844   //
   4845   // No need to do extra check here as whether (Column, Row) is valid has
   4846   // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should
   4847   // always be supported.
   4848   //
   4849   Private->TextOutMode.CursorColumn = 0;
   4850   Private->TextOutMode.CursorRow    = 0;
   4851   Private->TextOutMode.CursorVisible = TRUE;
   4852 
   4853   return ReturnStatus;
   4854 }
   4855 
   4856 
   4857 /**
   4858   Sets the current coordinates of the cursor position
   4859 
   4860   @param  This                     Protocol instance pointer.
   4861   @param  Column                   The column position to set the cursor to. Must be
   4862                                    greater than or equal to zero and less than the
   4863                                    number of columns by QueryMode ().
   4864   @param  Row                      The row position to set the cursor to. Must be
   4865                                    greater than or equal to zero and less than the
   4866                                    number of rows by QueryMode ().
   4867 
   4868   @retval EFI_SUCCESS              The operation completed successfully.
   4869   @retval EFI_DEVICE_ERROR         The device had an error and could not complete
   4870                                    the request.
   4871   @retval EFI_UNSUPPORTED          The output device is not in a valid text mode,
   4872                                    or the cursor position is invalid for the
   4873                                    current mode.
   4874 
   4875 **/
   4876 EFI_STATUS
   4877 EFIAPI
   4878 ConSplitterTextOutSetCursorPosition (
   4879   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
   4880   IN  UINTN                              Column,
   4881   IN  UINTN                              Row
   4882   )
   4883 {
   4884   EFI_STATUS                      Status;
   4885   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
   4886   UINTN                           Index;
   4887   EFI_STATUS                      ReturnStatus;
   4888   UINTN                           MaxColumn;
   4889   UINTN                           MaxRow;
   4890   INT32                           *TextOutModeMap;
   4891   INT32                           ModeNumber;
   4892   INT32                           CurrentMode;
   4893 
   4894   Private   = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
   4895   TextOutModeMap  = NULL;
   4896   ModeNumber      = Private->TextOutMode.Mode;
   4897 
   4898   //
   4899   // Get current MaxColumn and MaxRow from intersection map
   4900   //
   4901   if (Private->TextOutModeMap != NULL) {
   4902     TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber;
   4903     CurrentMode    = *TextOutModeMap;
   4904   } else {
   4905     CurrentMode = ModeNumber;
   4906   }
   4907 
   4908   MaxColumn = Private->TextOutQueryData[CurrentMode].Columns;
   4909   MaxRow    = Private->TextOutQueryData[CurrentMode].Rows;
   4910 
   4911   if (Column >= MaxColumn || Row >= MaxRow) {
   4912     return EFI_UNSUPPORTED;
   4913   }
   4914   //
   4915   // return the worst status met
   4916   //
   4917   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
   4918     Status = Private->TextOutList[Index].TextOut->SetCursorPosition (
   4919                                                     Private->TextOutList[Index].TextOut,
   4920                                                     Column,
   4921                                                     Row
   4922                                                     );
   4923     if (EFI_ERROR (Status)) {
   4924       ReturnStatus = Status;
   4925     }
   4926   }
   4927 
   4928   //
   4929   // No need to do extra check here as whether (Column, Row) is valid has
   4930   // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should
   4931   // always be supported.
   4932   //
   4933   Private->TextOutMode.CursorColumn = (INT32) Column;
   4934   Private->TextOutMode.CursorRow    = (INT32) Row;
   4935 
   4936   return ReturnStatus;
   4937 }
   4938 
   4939 
   4940 /**
   4941   Makes the cursor visible or invisible
   4942 
   4943   @param  This                     Protocol instance pointer.
   4944   @param  Visible                  If TRUE, the cursor is set to be visible. If
   4945                                    FALSE, the cursor is set to be invisible.
   4946 
   4947   @retval EFI_SUCCESS              The operation completed successfully.
   4948   @retval EFI_DEVICE_ERROR         The device had an error and could not complete
   4949                                    the request, or the device does not support
   4950                                    changing the cursor mode.
   4951   @retval EFI_UNSUPPORTED          The output device is not in a valid text mode.
   4952 
   4953 **/
   4954 EFI_STATUS
   4955 EFIAPI
   4956 ConSplitterTextOutEnableCursor (
   4957   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
   4958   IN  BOOLEAN                            Visible
   4959   )
   4960 {
   4961   EFI_STATUS                      Status;
   4962   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
   4963   UINTN                           Index;
   4964   EFI_STATUS                      ReturnStatus;
   4965 
   4966   Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
   4967 
   4968   //
   4969   // return the worst status met
   4970   //
   4971   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
   4972     Status = Private->TextOutList[Index].TextOut->EnableCursor (
   4973                                                     Private->TextOutList[Index].TextOut,
   4974                                                     Visible
   4975                                                     );
   4976     if (EFI_ERROR (Status)) {
   4977       ReturnStatus = Status;
   4978     }
   4979   }
   4980 
   4981   Private->TextOutMode.CursorVisible = Visible;
   4982 
   4983   return ReturnStatus;
   4984 }
   4985 
   4986 
   4987 /**
   4988   An empty function to pass error checking of CreateEventEx ().
   4989 
   4990   @param  Event                 Event whose notification function is being invoked.
   4991   @param  Context               Pointer to the notification function's context,
   4992                                 which is implementation-dependent.
   4993 
   4994 **/
   4995 VOID
   4996 EFIAPI
   4997 ConSplitterEmptyCallbackFunction (
   4998   IN EFI_EVENT                Event,
   4999   IN VOID                     *Context
   5000   )
   5001 {
   5002 }
   5003