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