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