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