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