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