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