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