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