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