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
ConSplitterDriverEntry(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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
ConSplitterTextInConstructor(TEXT_IN_SPLITTER_PRIVATE_DATA * ConInPrivate)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
ConSplitterTextOutConstructor(TEXT_OUT_SPLITTER_PRIVATE_DATA * ConOutPrivate)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
ConSplitterSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_GUID * Guid)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
ConSplitterConInDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
ConSplitterSimplePointerDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
ConSplitterAbsolutePointerDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
ConSplitterConOutDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
ConSplitterStdErrDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
ConSplitterStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_HANDLE ConSplitterVirtualHandle,IN EFI_GUID * DeviceGuid,IN EFI_GUID * InterfaceGuid,OUT VOID ** Interface)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
ConSplitterConInDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
ConSplitterSimplePointerDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
ConSplitterAbsolutePointerDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
ConSplitterConOutDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
ConSplitterStdErrDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
ConSplitterStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_HANDLE ConSplitterVirtualHandle,IN EFI_GUID * DeviceGuid,IN EFI_GUID * InterfaceGuid,IN VOID ** Interface)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
ConSplitterConInDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)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
ConSplitterSimplePointerDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)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
ConSplitterAbsolutePointerDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)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
ConSplitterConOutDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)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
ConSplitterStdErrDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)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
ConSplitterGrowBuffer(IN UINTN ElementSize,IN OUT UINTN * Count,IN OUT VOID ** Buffer)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
ConSplitterTextInAddDevice(IN TEXT_IN_SPLITTER_PRIVATE_DATA * Private,IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL * TextIn)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
ConSplitterTextInDeleteDevice(IN TEXT_IN_SPLITTER_PRIVATE_DATA * Private,IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL * TextIn)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
ConSplitterTextInExAddDevice(IN TEXT_IN_SPLITTER_PRIVATE_DATA * Private,IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * TextInEx)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
ConSplitterTextInExDeleteDevice(IN TEXT_IN_SPLITTER_PRIVATE_DATA * Private,IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * TextInEx)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
ConSplitterSimplePointerAddDevice(IN TEXT_IN_SPLITTER_PRIVATE_DATA * Private,IN EFI_SIMPLE_POINTER_PROTOCOL * SimplePointer)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
ConSplitterSimplePointerDeleteDevice(IN TEXT_IN_SPLITTER_PRIVATE_DATA * Private,IN EFI_SIMPLE_POINTER_PROTOCOL * SimplePointer)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
ConSplitterAbsolutePointerAddDevice(IN TEXT_IN_SPLITTER_PRIVATE_DATA * Private,IN EFI_ABSOLUTE_POINTER_PROTOCOL * AbsolutePointer)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
ConSplitterAbsolutePointerDeleteDevice(IN TEXT_IN_SPLITTER_PRIVATE_DATA * Private,IN EFI_ABSOLUTE_POINTER_PROTOCOL * AbsolutePointer)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
ConSplitterGrowMapTable(IN TEXT_OUT_SPLITTER_PRIVATE_DATA * Private)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
ConSplitterAddOutputMode(IN TEXT_OUT_SPLITTER_PRIVATE_DATA * Private,IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * TextOut)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
ConSplitterGetIntersection(IN INT32 * TextOutModeMap,IN INT32 * NewlyAddedMap,IN UINTN MapStepSize,IN UINTN NewMapStepSize,IN OUT INT32 * MaxMode,IN OUT INT32 * CurrentMode)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
ConSplitterSyncOutputMode(IN TEXT_OUT_SPLITTER_PRIVATE_DATA * Private,IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * TextOut)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
ConSplitterGetIntersectionBetweenConOutAndStrErr(VOID)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
ConSplitterAddGraphicsOutputMode(IN TEXT_OUT_SPLITTER_PRIVATE_DATA * Private,IN EFI_GRAPHICS_OUTPUT_PROTOCOL * GraphicsOutput,IN EFI_UGA_DRAW_PROTOCOL * UgaDraw)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
ConsplitterSetConsoleOutMode(IN TEXT_OUT_SPLITTER_PRIVATE_DATA * Private)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
ConSplitterTextOutAddDevice(IN TEXT_OUT_SPLITTER_PRIVATE_DATA * Private,IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * TextOut,IN EFI_GRAPHICS_OUTPUT_PROTOCOL * GraphicsOutput,IN EFI_UGA_DRAW_PROTOCOL * UgaDraw)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
ConSplitterTextOutDeleteDevice(IN TEXT_OUT_SPLITTER_PRIVATE_DATA * Private,IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * TextOut)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
ConSplitterTextInReset(IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL * This,IN BOOLEAN ExtendedVerification)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
ConSplitterTextInPrivateReadKeyStroke(IN TEXT_IN_SPLITTER_PRIVATE_DATA * Private,OUT EFI_INPUT_KEY * Key)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
ConSplitterTextInReadKeyStroke(IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL * This,OUT EFI_INPUT_KEY * Key)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
ConSplitterTextInWaitForKey(IN EFI_EVENT Event,IN VOID * Context)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
IsKeyRegistered(IN EFI_KEY_DATA * RegsiteredData,IN EFI_KEY_DATA * InputData)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
ConSplitterTextInResetEx(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN BOOLEAN ExtendedVerification)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
ConSplitterTextInReadKeyStrokeEx(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,OUT EFI_KEY_DATA * KeyData)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
ConSplitterTextInSetState(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN EFI_KEY_TOGGLE_STATE * KeyToggleState)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
ConSplitterTextInRegisterKeyNotify(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN EFI_KEY_DATA * KeyData,IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,OUT VOID ** NotifyHandle)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
ConSplitterTextInUnregisterKeyNotify(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN VOID * NotificationHandle)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
ConSplitterSimplePointerReset(IN EFI_SIMPLE_POINTER_PROTOCOL * This,IN BOOLEAN ExtendedVerification)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
ConSplitterSimplePointerPrivateGetState(IN TEXT_IN_SPLITTER_PRIVATE_DATA * Private,IN OUT EFI_SIMPLE_POINTER_STATE * State)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
ConSplitterSimplePointerGetState(IN EFI_SIMPLE_POINTER_PROTOCOL * This,IN OUT EFI_SIMPLE_POINTER_STATE * State)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
ConSplitterSimplePointerWaitForInput(IN EFI_EVENT Event,IN VOID * Context)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
ConSplitterAbsolutePointerReset(IN EFI_ABSOLUTE_POINTER_PROTOCOL * This,IN BOOLEAN ExtendedVerification)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
ConSplitterAbsolutePointerGetState(IN EFI_ABSOLUTE_POINTER_PROTOCOL * This,IN OUT EFI_ABSOLUTE_POINTER_STATE * State)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
ConSplitterAbsolutePointerWaitForInput(IN EFI_EVENT Event,IN VOID * Context)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
ConSplitterTextOutReset(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN BOOLEAN ExtendedVerification)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
ConSplitterTextOutOutputString(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN CHAR16 * WString)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
ConSplitterTextOutTestString(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN CHAR16 * WString)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
ConSplitterTextOutQueryMode(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN UINTN ModeNumber,OUT UINTN * Columns,OUT UINTN * Rows)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
ConSplitterTextOutSetMode(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN UINTN ModeNumber)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
ConSplitterTextOutSetAttribute(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN UINTN Attribute)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
ConSplitterTextOutClearScreen(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This)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
ConSplitterTextOutSetCursorPosition(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN UINTN Column,IN UINTN Row)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
ConSplitterTextOutEnableCursor(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN BOOLEAN Visible)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
ConSplitterEmptyCallbackFunction(IN EFI_EVENT Event,IN VOID * Context)4773 ConSplitterEmptyCallbackFunction (
4774   IN EFI_EVENT                Event,
4775   IN VOID                     *Context
4776   )
4777 {
4778 }
4779