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