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