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