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