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