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