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