1 /** @file 2 Console Splitter Driver. Any Handle that attatched console I/O protocols 3 (Console In device, Console Out device, Console Error device, Simple Pointer 4 protocol, Absolute Pointer protocol) can be bound by this driver. 5 6 So far it works like any other driver by opening a SimpleTextIn and/or 7 SimpleTextOut protocol with EFI_OPEN_PROTOCOL_BY_DRIVER attributes. The big 8 difference is this driver does not layer a protocol on the passed in 9 handle, or construct a child handle like a standard device or bus driver. 10 This driver produces three virtual handles as children, one for console input 11 splitter, one for console output splitter and one for error output splitter. 12 These 3 virtual handles would be installed on gST. 13 14 Each virtual handle, that supports the Console I/O protocol, will be produced 15 in the driver entry point. The virtual handle are added on driver entry and 16 never removed. Such design ensures sytem function well during none console 17 device situation. 18 19 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR> 20 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> 21 This program and the accompanying materials 22 are licensed and made available under the terms and conditions of the BSD License 23 which accompanies this distribution. The full text of the license may be found at 24 http://opensource.org/licenses/bsd-license.php 25 26 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 27 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 28 29 **/ 30 31 #include "ConSplitter.h" 32 33 // 34 // Identify if ConIn is connected in PcdConInConnectOnDemand enabled mode. 35 // default not connect 36 // 37 BOOLEAN mConInIsConnect = FALSE; 38 39 // 40 // Text In Splitter Private Data template 41 // 42 GLOBAL_REMOVE_IF_UNREFERENCED TEXT_IN_SPLITTER_PRIVATE_DATA mConIn = { 43 TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE, 44 (EFI_HANDLE) NULL, 45 46 { 47 ConSplitterTextInReset, 48 ConSplitterTextInReadKeyStroke, 49 (EFI_EVENT) NULL 50 }, 51 0, 52 (EFI_SIMPLE_TEXT_INPUT_PROTOCOL **) NULL, 53 0, 54 55 { 56 ConSplitterTextInResetEx, 57 ConSplitterTextInReadKeyStrokeEx, 58 (EFI_EVENT) NULL, 59 ConSplitterTextInSetState, 60 ConSplitterTextInRegisterKeyNotify, 61 ConSplitterTextInUnregisterKeyNotify 62 }, 63 0, 64 (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL **) NULL, 65 0, 66 { 67 (LIST_ENTRY *) NULL, 68 (LIST_ENTRY *) NULL 69 }, 70 0, 71 FALSE, 72 73 { 74 ConSplitterSimplePointerReset, 75 ConSplitterSimplePointerGetState, 76 (EFI_EVENT) NULL, 77 (EFI_SIMPLE_POINTER_MODE *) NULL 78 }, 79 { 80 0x10000, 81 0x10000, 82 0x10000, 83 TRUE, 84 TRUE 85 }, 86 0, 87 (EFI_SIMPLE_POINTER_PROTOCOL **) NULL, 88 0, 89 90 { 91 ConSplitterAbsolutePointerReset, 92 ConSplitterAbsolutePointerGetState, 93 (EFI_EVENT) NULL, 94 (EFI_ABSOLUTE_POINTER_MODE *) NULL 95 }, 96 { 97 0, // AbsoluteMinX 98 0, // AbsoluteMinY 99 0, // AbsoluteMinZ 100 0x10000, // AbsoluteMaxX 101 0x10000, // AbsoluteMaxY 102 0x10000, // AbsoluteMaxZ 103 0 // Attributes 104 }, 105 0, 106 (EFI_ABSOLUTE_POINTER_PROTOCOL **) NULL, 107 0, 108 FALSE, 109 110 FALSE, 111 FALSE 112 }; 113 114 115 // 116 // Uga Draw Protocol Private Data template 117 // 118 GLOBAL_REMOVE_IF_UNREFERENCED EFI_UGA_DRAW_PROTOCOL mUgaDrawProtocolTemplate = { 119 ConSplitterUgaDrawGetMode, 120 ConSplitterUgaDrawSetMode, 121 ConSplitterUgaDrawBlt 122 }; 123 124 // 125 // Graphics Output Protocol Private Data template 126 // 127 GLOBAL_REMOVE_IF_UNREFERENCED EFI_GRAPHICS_OUTPUT_PROTOCOL mGraphicsOutputProtocolTemplate = { 128 ConSplitterGraphicsOutputQueryMode, 129 ConSplitterGraphicsOutputSetMode, 130 ConSplitterGraphicsOutputBlt, 131 NULL 132 }; 133 134 135 // 136 // Text Out Splitter Private Data template 137 // 138 GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA mConOut = { 139 TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE, 140 (EFI_HANDLE) NULL, 141 { 142 ConSplitterTextOutReset, 143 ConSplitterTextOutOutputString, 144 ConSplitterTextOutTestString, 145 ConSplitterTextOutQueryMode, 146 ConSplitterTextOutSetMode, 147 ConSplitterTextOutSetAttribute, 148 ConSplitterTextOutClearScreen, 149 ConSplitterTextOutSetCursorPosition, 150 ConSplitterTextOutEnableCursor, 151 (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL 152 }, 153 { 154 1, 155 0, 156 0, 157 0, 158 0, 159 FALSE, 160 }, 161 162 { 163 NULL, 164 NULL, 165 NULL 166 }, 167 0, 168 0, 169 0, 170 0, 171 172 { 173 NULL, 174 NULL, 175 NULL, 176 NULL 177 }, 178 (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) NULL, 179 0, 180 0, 181 182 0, 183 (TEXT_OUT_AND_GOP_DATA *) NULL, 184 0, 185 (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL, 186 0, 187 (INT32 *) NULL 188 }; 189 190 // 191 // Standard Error Text Out Splitter Data Template 192 // 193 GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA mStdErr = { 194 TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE, 195 (EFI_HANDLE) NULL, 196 { 197 ConSplitterTextOutReset, 198 ConSplitterTextOutOutputString, 199 ConSplitterTextOutTestString, 200 ConSplitterTextOutQueryMode, 201 ConSplitterTextOutSetMode, 202 ConSplitterTextOutSetAttribute, 203 ConSplitterTextOutClearScreen, 204 ConSplitterTextOutSetCursorPosition, 205 ConSplitterTextOutEnableCursor, 206 (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL 207 }, 208 { 209 1, 210 0, 211 0, 212 0, 213 0, 214 FALSE, 215 }, 216 217 { 218 NULL, 219 NULL, 220 NULL 221 }, 222 0, 223 0, 224 0, 225 0, 226 227 { 228 NULL, 229 NULL, 230 NULL, 231 NULL 232 }, 233 (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) NULL, 234 0, 235 0, 236 237 0, 238 (TEXT_OUT_AND_GOP_DATA *) NULL, 239 0, 240 (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL, 241 0, 242 (INT32 *) NULL 243 }; 244 245 // 246 // Driver binding instance for Console Input Device 247 // 248 EFI_DRIVER_BINDING_PROTOCOL gConSplitterConInDriverBinding = { 249 ConSplitterConInDriverBindingSupported, 250 ConSplitterConInDriverBindingStart, 251 ConSplitterConInDriverBindingStop, 252 0xa, 253 NULL, 254 NULL 255 }; 256 257 // 258 // Driver binding instance for Console Out device 259 // 260 EFI_DRIVER_BINDING_PROTOCOL gConSplitterConOutDriverBinding = { 261 ConSplitterConOutDriverBindingSupported, 262 ConSplitterConOutDriverBindingStart, 263 ConSplitterConOutDriverBindingStop, 264 0xa, 265 NULL, 266 NULL 267 }; 268 269 // 270 // Driver binding instance for Standard Error device 271 // 272 EFI_DRIVER_BINDING_PROTOCOL gConSplitterStdErrDriverBinding = { 273 ConSplitterStdErrDriverBindingSupported, 274 ConSplitterStdErrDriverBindingStart, 275 ConSplitterStdErrDriverBindingStop, 276 0xa, 277 NULL, 278 NULL 279 }; 280 281 // 282 // Driver binding instance for Simple Pointer protocol 283 // 284 EFI_DRIVER_BINDING_PROTOCOL gConSplitterSimplePointerDriverBinding = { 285 ConSplitterSimplePointerDriverBindingSupported, 286 ConSplitterSimplePointerDriverBindingStart, 287 ConSplitterSimplePointerDriverBindingStop, 288 0xa, 289 NULL, 290 NULL 291 }; 292 293 // 294 // Driver binding instance for Absolute Pointer protocol 295 // 296 EFI_DRIVER_BINDING_PROTOCOL gConSplitterAbsolutePointerDriverBinding = { 297 ConSplitterAbsolutePointerDriverBindingSupported, 298 ConSplitterAbsolutePointerDriverBindingStart, 299 ConSplitterAbsolutePointerDriverBindingStop, 300 0xa, 301 NULL, 302 NULL 303 }; 304 305 /** 306 Key notify for toggle state sync. 307 308 @param KeyData A pointer to a buffer that is filled in with 309 the keystroke information for the key that was 310 pressed. 311 312 @retval EFI_SUCCESS Toggle state sync successfully. 313 314 **/ 315 EFI_STATUS 316 EFIAPI 317 ToggleStateSyncKeyNotify ( 318 IN EFI_KEY_DATA *KeyData 319 ) 320 { 321 UINTN Index; 322 323 if (((KeyData->KeyState.KeyToggleState & KEY_STATE_VALID_EXPOSED) == KEY_STATE_VALID_EXPOSED) && 324 (KeyData->KeyState.KeyToggleState != mConIn.PhysicalKeyToggleState)) { 325 // 326 // There is toggle state change, sync to other console input devices. 327 // 328 for (Index = 0; Index < mConIn.CurrentNumberOfExConsoles; Index++) { 329 mConIn.TextInExList[Index]->SetState ( 330 mConIn.TextInExList[Index], 331 &KeyData->KeyState.KeyToggleState 332 ); 333 } 334 mConIn.PhysicalKeyToggleState = KeyData->KeyState.KeyToggleState; 335 DEBUG ((EFI_D_INFO, "Current toggle state is 0x%02x\n", mConIn.PhysicalKeyToggleState)); 336 } 337 338 return EFI_SUCCESS; 339 } 340 341 /** 342 Initialization for toggle state sync. 343 344 @param Private Text In Splitter pointer. 345 346 **/ 347 VOID 348 ToggleStateSyncInitialization ( 349 IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private 350 ) 351 { 352 EFI_KEY_DATA KeyData; 353 VOID *NotifyHandle; 354 355 // 356 // Initialize PhysicalKeyToggleState that will be synced to new console 357 // input device to turn on physical TextInEx partial key report for 358 // toggle state sync. 359 // 360 Private->PhysicalKeyToggleState = KEY_STATE_VALID_EXPOSED; 361 362 // 363 // Initialize VirtualKeyStateExported to let the virtual TextInEx not report 364 // the partial key even though the physical TextInEx turns on the partial 365 // key report. The virtual TextInEx will report the partial key after it is 366 // required by calling SetState(X | KEY_STATE_VALID_EXPOSED) explicitly. 367 // 368 Private->VirtualKeyStateExported = FALSE; 369 370 // 371 // Register key notify for toggle state sync. 372 // 373 KeyData.Key.ScanCode = SCAN_NULL; 374 KeyData.Key.UnicodeChar = CHAR_NULL; 375 KeyData.KeyState.KeyShiftState = 0; 376 KeyData.KeyState.KeyToggleState = 0; 377 Private->TextInEx.RegisterKeyNotify ( 378 &Private->TextInEx, 379 &KeyData, 380 ToggleStateSyncKeyNotify, 381 &NotifyHandle 382 ); 383 } 384 385 /** 386 Reinitialization for toggle state sync. 387 388 @param Private Text In Splitter pointer. 389 390 **/ 391 VOID 392 ToggleStateSyncReInitialization ( 393 IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private 394 ) 395 { 396 UINTN Index; 397 398 // 399 // Reinitialize PhysicalKeyToggleState that will be synced to new console 400 // input device to turn on physical TextInEx partial key report for 401 // toggle state sync. 402 // 403 Private->PhysicalKeyToggleState = KEY_STATE_VALID_EXPOSED; 404 405 // 406 // Reinitialize VirtualKeyStateExported to let the virtual TextInEx not report 407 // the partial key even though the physical TextInEx turns on the partial 408 // key report. The virtual TextInEx will report the partial key after it is 409 // required by calling SetState(X | KEY_STATE_VALID_EXPOSED) explicitly. 410 // 411 Private->VirtualKeyStateExported = FALSE; 412 413 for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { 414 Private->TextInExList[Index]->SetState ( 415 Private->TextInExList[Index], 416 &Private->PhysicalKeyToggleState 417 ); 418 } 419 } 420 421 /** 422 The Entry Point for module ConSplitter. The user code starts with this function. 423 424 Installs driver module protocols and. Creates virtual device handles for ConIn, 425 ConOut, and StdErr. Installs Simple Text In protocol, Simple Text In Ex protocol, 426 Simple Pointer protocol, Absolute Pointer protocol on those virtual handlers. 427 Installs Graphics Output protocol and/or UGA Draw protocol if needed. 428 429 @param[in] ImageHandle The firmware allocated handle for the EFI image. 430 @param[in] SystemTable A pointer to the EFI System Table. 431 432 @retval EFI_SUCCESS The entry point is executed successfully. 433 @retval other Some error occurs when executing this entry point. 434 435 **/ 436 EFI_STATUS 437 EFIAPI 438 ConSplitterDriverEntry( 439 IN EFI_HANDLE ImageHandle, 440 IN EFI_SYSTEM_TABLE *SystemTable 441 ) 442 { 443 EFI_STATUS Status; 444 445 // 446 // Install driver model protocol(s). 447 // 448 Status = EfiLibInstallDriverBindingComponentName2 ( 449 ImageHandle, 450 SystemTable, 451 &gConSplitterConInDriverBinding, 452 ImageHandle, 453 &gConSplitterConInComponentName, 454 &gConSplitterConInComponentName2 455 ); 456 ASSERT_EFI_ERROR (Status); 457 458 Status = EfiLibInstallDriverBindingComponentName2 ( 459 ImageHandle, 460 SystemTable, 461 &gConSplitterSimplePointerDriverBinding, 462 NULL, 463 &gConSplitterSimplePointerComponentName, 464 &gConSplitterSimplePointerComponentName2 465 ); 466 ASSERT_EFI_ERROR (Status); 467 468 Status = EfiLibInstallDriverBindingComponentName2 ( 469 ImageHandle, 470 SystemTable, 471 &gConSplitterAbsolutePointerDriverBinding, 472 NULL, 473 &gConSplitterAbsolutePointerComponentName, 474 &gConSplitterAbsolutePointerComponentName2 475 ); 476 ASSERT_EFI_ERROR (Status); 477 478 Status = EfiLibInstallDriverBindingComponentName2 ( 479 ImageHandle, 480 SystemTable, 481 &gConSplitterConOutDriverBinding, 482 NULL, 483 &gConSplitterConOutComponentName, 484 &gConSplitterConOutComponentName2 485 ); 486 ASSERT_EFI_ERROR (Status); 487 488 Status = EfiLibInstallDriverBindingComponentName2 ( 489 ImageHandle, 490 SystemTable, 491 &gConSplitterStdErrDriverBinding, 492 NULL, 493 &gConSplitterStdErrComponentName, 494 &gConSplitterStdErrComponentName2 495 ); 496 ASSERT_EFI_ERROR (Status); 497 498 // 499 // Either Graphics Output protocol or UGA Draw protocol must be supported. 500 // 501 ASSERT (FeaturePcdGet (PcdConOutGopSupport) || 502 FeaturePcdGet (PcdConOutUgaSupport)); 503 504 // 505 // The driver creates virtual handles for ConIn, ConOut, StdErr. 506 // The virtual handles will always exist even if no console exist in the 507 // system. This is need to support hotplug devices like USB. 508 // 509 // 510 // Create virtual device handle for ConIn Splitter 511 // 512 Status = ConSplitterTextInConstructor (&mConIn); 513 if (!EFI_ERROR (Status)) { 514 Status = gBS->InstallMultipleProtocolInterfaces ( 515 &mConIn.VirtualHandle, 516 &gEfiSimpleTextInProtocolGuid, 517 &mConIn.TextIn, 518 &gEfiSimpleTextInputExProtocolGuid, 519 &mConIn.TextInEx, 520 &gEfiSimplePointerProtocolGuid, 521 &mConIn.SimplePointer, 522 &gEfiAbsolutePointerProtocolGuid, 523 &mConIn.AbsolutePointer, 524 NULL 525 ); 526 if (!EFI_ERROR (Status)) { 527 // 528 // Update the EFI System Table with new virtual console 529 // and update the pointer to Simple Text Input protocol. 530 // 531 gST->ConsoleInHandle = mConIn.VirtualHandle; 532 gST->ConIn = &mConIn.TextIn; 533 } 534 } 535 // 536 // Create virtual device handle for ConOut Splitter 537 // 538 Status = ConSplitterTextOutConstructor (&mConOut); 539 if (!EFI_ERROR (Status)) { 540 Status = gBS->InstallMultipleProtocolInterfaces ( 541 &mConOut.VirtualHandle, 542 &gEfiSimpleTextOutProtocolGuid, 543 &mConOut.TextOut, 544 NULL 545 ); 546 if (!EFI_ERROR (Status)) { 547 // 548 // Update the EFI System Table with new virtual console 549 // and Update the pointer to Text Output protocol. 550 // 551 gST->ConsoleOutHandle = mConOut.VirtualHandle; 552 gST->ConOut = &mConOut.TextOut; 553 } 554 555 } 556 557 // 558 // Create virtual device handle for StdErr Splitter 559 // 560 Status = ConSplitterTextOutConstructor (&mStdErr); 561 if (!EFI_ERROR (Status)) { 562 Status = gBS->InstallMultipleProtocolInterfaces ( 563 &mStdErr.VirtualHandle, 564 &gEfiSimpleTextOutProtocolGuid, 565 &mStdErr.TextOut, 566 NULL 567 ); 568 if (!EFI_ERROR (Status)) { 569 // 570 // Update the EFI System Table with new virtual console 571 // and update the pointer to Text Output protocol. 572 // 573 gST->StandardErrorHandle = mStdErr.VirtualHandle; 574 gST->StdErr = &mStdErr.TextOut; 575 } 576 } 577 578 // 579 // Update the CRC32 in the EFI System Table header 580 // 581 gST->Hdr.CRC32 = 0; 582 gBS->CalculateCrc32 ( 583 (UINT8 *) &gST->Hdr, 584 gST->Hdr.HeaderSize, 585 &gST->Hdr.CRC32 586 ); 587 588 return EFI_SUCCESS; 589 590 } 591 592 /** 593 Construct console input devices' private data. 594 595 @param ConInPrivate A pointer to the TEXT_IN_SPLITTER_PRIVATE_DATA 596 structure. 597 598 @retval EFI_OUT_OF_RESOURCES Out of resources. 599 @retval EFI_SUCCESS Text Input Devcie's private data has been constructed. 600 @retval other Failed to construct private data. 601 602 **/ 603 EFI_STATUS 604 ConSplitterTextInConstructor ( 605 TEXT_IN_SPLITTER_PRIVATE_DATA *ConInPrivate 606 ) 607 { 608 EFI_STATUS Status; 609 610 // 611 // Allocate buffer for Simple Text Input device 612 // 613 Status = ConSplitterGrowBuffer ( 614 sizeof (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *), 615 &ConInPrivate->TextInListCount, 616 (VOID **) &ConInPrivate->TextInList 617 ); 618 if (EFI_ERROR (Status)) { 619 return EFI_OUT_OF_RESOURCES; 620 } 621 622 // 623 // Create Event to wait for a key 624 // 625 Status = gBS->CreateEvent ( 626 EVT_NOTIFY_WAIT, 627 TPL_NOTIFY, 628 ConSplitterTextInWaitForKey, 629 ConInPrivate, 630 &ConInPrivate->TextIn.WaitForKey 631 ); 632 ASSERT_EFI_ERROR (Status); 633 634 // 635 // Allocate buffer for Simple Text Input Ex device 636 // 637 Status = ConSplitterGrowBuffer ( 638 sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *), 639 &ConInPrivate->TextInExListCount, 640 (VOID **) &ConInPrivate->TextInExList 641 ); 642 if (EFI_ERROR (Status)) { 643 return EFI_OUT_OF_RESOURCES; 644 } 645 // 646 // Create Event to wait for a key Ex 647 // 648 Status = gBS->CreateEvent ( 649 EVT_NOTIFY_WAIT, 650 TPL_NOTIFY, 651 ConSplitterTextInWaitForKey, 652 ConInPrivate, 653 &ConInPrivate->TextInEx.WaitForKeyEx 654 ); 655 ASSERT_EFI_ERROR (Status); 656 657 InitializeListHead (&ConInPrivate->NotifyList); 658 659 ToggleStateSyncInitialization (ConInPrivate); 660 661 ConInPrivate->AbsolutePointer.Mode = &ConInPrivate->AbsolutePointerMode; 662 // 663 // Allocate buffer for Absolute Pointer device 664 // 665 Status = ConSplitterGrowBuffer ( 666 sizeof (EFI_ABSOLUTE_POINTER_PROTOCOL *), 667 &ConInPrivate->AbsolutePointerListCount, 668 (VOID **) &ConInPrivate->AbsolutePointerList 669 ); 670 if (EFI_ERROR (Status)) { 671 return EFI_OUT_OF_RESOURCES; 672 } 673 // 674 // Create Event to wait for device input for Absolute pointer device 675 // 676 Status = gBS->CreateEvent ( 677 EVT_NOTIFY_WAIT, 678 TPL_NOTIFY, 679 ConSplitterAbsolutePointerWaitForInput, 680 ConInPrivate, 681 &ConInPrivate->AbsolutePointer.WaitForInput 682 ); 683 ASSERT_EFI_ERROR (Status); 684 685 ConInPrivate->SimplePointer.Mode = &ConInPrivate->SimplePointerMode; 686 // 687 // Allocate buffer for Simple Pointer device 688 // 689 Status = ConSplitterGrowBuffer ( 690 sizeof (EFI_SIMPLE_POINTER_PROTOCOL *), 691 &ConInPrivate->PointerListCount, 692 (VOID **) &ConInPrivate->PointerList 693 ); 694 if (EFI_ERROR (Status)) { 695 return EFI_OUT_OF_RESOURCES; 696 } 697 // 698 // Create Event to wait for device input for Simple pointer device 699 // 700 Status = gBS->CreateEvent ( 701 EVT_NOTIFY_WAIT, 702 TPL_NOTIFY, 703 ConSplitterSimplePointerWaitForInput, 704 ConInPrivate, 705 &ConInPrivate->SimplePointer.WaitForInput 706 ); 707 ASSERT_EFI_ERROR (Status); 708 // 709 // Create Event to signal ConIn connection request 710 // 711 Status = gBS->CreateEventEx ( 712 EVT_NOTIFY_SIGNAL, 713 TPL_CALLBACK, 714 ConSplitterEmptyCallbackFunction, 715 NULL, 716 &gConnectConInEventGuid, 717 &ConInPrivate->ConnectConInEvent 718 ); 719 720 return Status; 721 } 722 723 /** 724 Construct console output devices' private data. 725 726 @param ConOutPrivate A pointer to the TEXT_OUT_SPLITTER_PRIVATE_DATA 727 structure. 728 729 @retval EFI_OUT_OF_RESOURCES Out of resources. 730 @retval EFI_SUCCESS Text Input Devcie's private data has been constructed. 731 732 **/ 733 EFI_STATUS 734 ConSplitterTextOutConstructor ( 735 TEXT_OUT_SPLITTER_PRIVATE_DATA *ConOutPrivate 736 ) 737 { 738 EFI_STATUS Status; 739 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; 740 741 // 742 // Copy protocols template 743 // 744 if (FeaturePcdGet (PcdConOutUgaSupport)) { 745 CopyMem (&ConOutPrivate->UgaDraw, &mUgaDrawProtocolTemplate, sizeof (EFI_UGA_DRAW_PROTOCOL)); 746 } 747 if (FeaturePcdGet (PcdConOutGopSupport)) { 748 CopyMem (&ConOutPrivate->GraphicsOutput, &mGraphicsOutputProtocolTemplate, sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL)); 749 } 750 751 // 752 // Initilize console output splitter's private data. 753 // 754 ConOutPrivate->TextOut.Mode = &ConOutPrivate->TextOutMode; 755 756 // 757 // When new console device is added, the new mode will be set later, 758 // so put current mode back to init state. 759 // 760 ConOutPrivate->TextOutMode.Mode = 0xFF; 761 // 762 // Allocate buffer for Console Out device 763 // 764 Status = ConSplitterGrowBuffer ( 765 sizeof (TEXT_OUT_AND_GOP_DATA), 766 &ConOutPrivate->TextOutListCount, 767 (VOID **) &ConOutPrivate->TextOutList 768 ); 769 if (EFI_ERROR (Status)) { 770 return EFI_OUT_OF_RESOURCES; 771 } 772 // 773 // Allocate buffer for Text Out query data 774 // 775 Status = ConSplitterGrowBuffer ( 776 sizeof (TEXT_OUT_SPLITTER_QUERY_DATA), 777 &ConOutPrivate->TextOutQueryDataCount, 778 (VOID **) &ConOutPrivate->TextOutQueryData 779 ); 780 if (EFI_ERROR (Status)) { 781 return EFI_OUT_OF_RESOURCES; 782 } 783 784 // 785 // Setup the default console to 80 x 25 and mode to 0 786 // 787 ConOutPrivate->TextOutQueryData[0].Columns = 80; 788 ConOutPrivate->TextOutQueryData[0].Rows = 25; 789 TextOutSetMode (ConOutPrivate, 0); 790 791 792 if (FeaturePcdGet (PcdConOutUgaSupport)) { 793 // 794 // Setup the UgaDraw to 800 x 600 x 32 bits per pixel, 60Hz. 795 // 796 ConSplitterUgaDrawSetMode (&ConOutPrivate->UgaDraw, 800, 600, 32, 60); 797 } 798 if (FeaturePcdGet (PcdConOutGopSupport)) { 799 // 800 // Setup resource for mode information in Graphics Output Protocol interface 801 // 802 if ((ConOutPrivate->GraphicsOutput.Mode = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE))) == NULL) { 803 return EFI_OUT_OF_RESOURCES; 804 } 805 if ((ConOutPrivate->GraphicsOutput.Mode->Info = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION))) == NULL) { 806 return EFI_OUT_OF_RESOURCES; 807 } 808 // 809 // Setup the DevNullGraphicsOutput to 800 x 600 x 32 bits per pixel 810 // DevNull will be updated to user-defined mode after driver has started. 811 // 812 if ((ConOutPrivate->GraphicsOutputModeBuffer = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION))) == NULL) { 813 return EFI_OUT_OF_RESOURCES; 814 } 815 Info = &ConOutPrivate->GraphicsOutputModeBuffer[0]; 816 Info->Version = 0; 817 Info->HorizontalResolution = 800; 818 Info->VerticalResolution = 600; 819 Info->PixelFormat = PixelBltOnly; 820 Info->PixelsPerScanLine = 800; 821 CopyMem (ConOutPrivate->GraphicsOutput.Mode->Info, Info, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); 822 ConOutPrivate->GraphicsOutput.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); 823 824 // 825 // Initialize the following items, theset items remain unchanged in GraphicsOutput->SetMode() 826 // GraphicsOutputMode->FrameBufferBase, GraphicsOutputMode->FrameBufferSize 827 // 828 ConOutPrivate->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL; 829 ConOutPrivate->GraphicsOutput.Mode->FrameBufferSize = 0; 830 831 ConOutPrivate->GraphicsOutput.Mode->MaxMode = 1; 832 // 833 // Initial current mode to unknown state, and then set to mode 0 834 // 835 ConOutPrivate->GraphicsOutput.Mode->Mode = 0xffff; 836 ConOutPrivate->GraphicsOutput.SetMode (&ConOutPrivate->GraphicsOutput, 0); 837 } 838 839 return EFI_SUCCESS; 840 } 841 842 843 /** 844 Test to see if the specified protocol could be supported on the specified device. 845 846 @param This Driver Binding protocol pointer. 847 @param ControllerHandle Handle of device to test. 848 @param Guid The specified protocol. 849 850 @retval EFI_SUCCESS The specified protocol is supported on this device. 851 @retval EFI_UNSUPPORTED The specified protocol attempts to be installed on virtul handle. 852 @retval other Failed to open specified protocol on this device. 853 854 **/ 855 EFI_STATUS 856 ConSplitterSupported ( 857 IN EFI_DRIVER_BINDING_PROTOCOL *This, 858 IN EFI_HANDLE ControllerHandle, 859 IN EFI_GUID *Guid 860 ) 861 { 862 EFI_STATUS Status; 863 VOID *Instance; 864 865 // 866 // Make sure the Console Splitter does not attempt to attach to itself 867 // 868 if (ControllerHandle == mConIn.VirtualHandle || 869 ControllerHandle == mConOut.VirtualHandle || 870 ControllerHandle == mStdErr.VirtualHandle 871 ) { 872 return EFI_UNSUPPORTED; 873 } 874 875 // 876 // Check to see whether the specific protocol could be opened BY_DRIVER 877 // 878 Status = gBS->OpenProtocol ( 879 ControllerHandle, 880 Guid, 881 &Instance, 882 This->DriverBindingHandle, 883 ControllerHandle, 884 EFI_OPEN_PROTOCOL_BY_DRIVER 885 ); 886 887 if (EFI_ERROR (Status)) { 888 return Status; 889 } 890 891 gBS->CloseProtocol ( 892 ControllerHandle, 893 Guid, 894 This->DriverBindingHandle, 895 ControllerHandle 896 ); 897 898 return EFI_SUCCESS; 899 } 900 901 /** 902 Test to see if Console In Device could be supported on the Controller. 903 904 @param This Driver Binding protocol instance pointer. 905 @param ControllerHandle Handle of device to test. 906 @param RemainingDevicePath Optional parameter use to pick a specific child 907 device to start. 908 909 @retval EFI_SUCCESS This driver supports this device. 910 @retval other This driver does not support this device. 911 912 **/ 913 EFI_STATUS 914 EFIAPI 915 ConSplitterConInDriverBindingSupported ( 916 IN EFI_DRIVER_BINDING_PROTOCOL *This, 917 IN EFI_HANDLE ControllerHandle, 918 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 919 ) 920 { 921 return ConSplitterSupported ( 922 This, 923 ControllerHandle, 924 &gEfiConsoleInDeviceGuid 925 ); 926 } 927 928 /** 929 Test to see if Simple Pointer protocol could be supported on the Controller. 930 931 @param This Driver Binding protocol instance pointer. 932 @param ControllerHandle Handle of device to test. 933 @param RemainingDevicePath Optional parameter use to pick a specific child 934 device to start. 935 936 @retval EFI_SUCCESS This driver supports this device. 937 @retval other This driver does not support this device. 938 939 **/ 940 EFI_STATUS 941 EFIAPI 942 ConSplitterSimplePointerDriverBindingSupported ( 943 IN EFI_DRIVER_BINDING_PROTOCOL *This, 944 IN EFI_HANDLE ControllerHandle, 945 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 946 ) 947 { 948 return ConSplitterSupported ( 949 This, 950 ControllerHandle, 951 &gEfiSimplePointerProtocolGuid 952 ); 953 } 954 955 /** 956 Test to see if Absolute Pointer protocol could be supported on the Controller. 957 958 @param This Driver Binding protocol instance pointer. 959 @param ControllerHandle Handle of device to test. 960 @param RemainingDevicePath Optional parameter use to pick a specific child 961 device to start. 962 963 @retval EFI_SUCCESS This driver supports this device. 964 @retval other This driver does not support this device. 965 966 **/ 967 EFI_STATUS 968 EFIAPI 969 ConSplitterAbsolutePointerDriverBindingSupported ( 970 IN EFI_DRIVER_BINDING_PROTOCOL *This, 971 IN EFI_HANDLE ControllerHandle, 972 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 973 ) 974 { 975 return ConSplitterSupported ( 976 This, 977 ControllerHandle, 978 &gEfiAbsolutePointerProtocolGuid 979 ); 980 } 981 982 983 /** 984 Test to see if Console Out Device could be supported on the Controller. 985 986 @param This Driver Binding protocol instance pointer. 987 @param ControllerHandle Handle of device to test. 988 @param RemainingDevicePath Optional parameter use to pick a specific child 989 device to start. 990 991 @retval EFI_SUCCESS This driver supports this device. 992 @retval other This driver does not support this device. 993 994 **/ 995 EFI_STATUS 996 EFIAPI 997 ConSplitterConOutDriverBindingSupported ( 998 IN EFI_DRIVER_BINDING_PROTOCOL *This, 999 IN EFI_HANDLE ControllerHandle, 1000 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 1001 ) 1002 { 1003 return ConSplitterSupported ( 1004 This, 1005 ControllerHandle, 1006 &gEfiConsoleOutDeviceGuid 1007 ); 1008 } 1009 1010 /** 1011 Test to see if Standard Error Device could be supported on the Controller. 1012 1013 @param This Driver Binding protocol instance pointer. 1014 @param ControllerHandle Handle of device to test. 1015 @param RemainingDevicePath Optional parameter use to pick a specific child 1016 device to start. 1017 1018 @retval EFI_SUCCESS This driver supports this device. 1019 @retval other This driver does not support this device. 1020 1021 **/ 1022 EFI_STATUS 1023 EFIAPI 1024 ConSplitterStdErrDriverBindingSupported ( 1025 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1026 IN EFI_HANDLE ControllerHandle, 1027 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 1028 ) 1029 { 1030 return ConSplitterSupported ( 1031 This, 1032 ControllerHandle, 1033 &gEfiStandardErrorDeviceGuid 1034 ); 1035 } 1036 1037 1038 /** 1039 Start ConSplitter on devcie handle by opening Console Device Guid on device handle 1040 and the console virtual handle. And Get the console interface on controller handle. 1041 1042 @param This Driver Binding protocol instance pointer. 1043 @param ControllerHandle Handle of device. 1044 @param ConSplitterVirtualHandle Console virtual Handle. 1045 @param DeviceGuid The specified Console Device, such as ConInDev, 1046 ConOutDev. 1047 @param InterfaceGuid The specified protocol to be opened. 1048 @param Interface Protocol interface returned. 1049 1050 @retval EFI_SUCCESS This driver supports this device. 1051 @retval other Failed to open the specified Console Device Guid 1052 or specified protocol. 1053 1054 **/ 1055 EFI_STATUS 1056 ConSplitterStart ( 1057 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1058 IN EFI_HANDLE ControllerHandle, 1059 IN EFI_HANDLE ConSplitterVirtualHandle, 1060 IN EFI_GUID *DeviceGuid, 1061 IN EFI_GUID *InterfaceGuid, 1062 OUT VOID **Interface 1063 ) 1064 { 1065 EFI_STATUS Status; 1066 VOID *Instance; 1067 1068 // 1069 // Check to see whether the ControllerHandle has the DeviceGuid on it. 1070 // 1071 Status = gBS->OpenProtocol ( 1072 ControllerHandle, 1073 DeviceGuid, 1074 &Instance, 1075 This->DriverBindingHandle, 1076 ControllerHandle, 1077 EFI_OPEN_PROTOCOL_BY_DRIVER 1078 ); 1079 if (EFI_ERROR (Status)) { 1080 return Status; 1081 } 1082 1083 // 1084 // Open the Parent Handle for the child. 1085 // 1086 Status = gBS->OpenProtocol ( 1087 ControllerHandle, 1088 DeviceGuid, 1089 &Instance, 1090 This->DriverBindingHandle, 1091 ConSplitterVirtualHandle, 1092 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 1093 ); 1094 if (EFI_ERROR (Status)) { 1095 goto Err; 1096 } 1097 1098 // 1099 // Open InterfaceGuid on the virtul handle. 1100 // 1101 Status = gBS->OpenProtocol ( 1102 ControllerHandle, 1103 InterfaceGuid, 1104 Interface, 1105 This->DriverBindingHandle, 1106 ConSplitterVirtualHandle, 1107 EFI_OPEN_PROTOCOL_GET_PROTOCOL 1108 ); 1109 1110 if (!EFI_ERROR (Status)) { 1111 return EFI_SUCCESS; 1112 } 1113 1114 // 1115 // close the DeviceGuid on ConSplitter VirtualHandle. 1116 // 1117 gBS->CloseProtocol ( 1118 ControllerHandle, 1119 DeviceGuid, 1120 This->DriverBindingHandle, 1121 ConSplitterVirtualHandle 1122 ); 1123 1124 Err: 1125 // 1126 // close the DeviceGuid on ControllerHandle. 1127 // 1128 gBS->CloseProtocol ( 1129 ControllerHandle, 1130 DeviceGuid, 1131 This->DriverBindingHandle, 1132 ControllerHandle 1133 ); 1134 1135 return Status; 1136 } 1137 1138 1139 /** 1140 Start Console In Consplitter on device handle. 1141 1142 @param This Driver Binding protocol instance pointer. 1143 @param ControllerHandle Handle of device to bind driver to. 1144 @param RemainingDevicePath Optional parameter use to pick a specific child 1145 device to start. 1146 1147 @retval EFI_SUCCESS Console In Consplitter is added to ControllerHandle. 1148 @retval other Console In Consplitter does not support this device. 1149 1150 **/ 1151 EFI_STATUS 1152 EFIAPI 1153 ConSplitterConInDriverBindingStart ( 1154 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1155 IN EFI_HANDLE ControllerHandle, 1156 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 1157 ) 1158 { 1159 EFI_STATUS Status; 1160 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn; 1161 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx; 1162 1163 // 1164 // Start ConSplitter on ControllerHandle, and create the virtual 1165 // agrogated console device on first call Start for a SimpleTextIn handle. 1166 // 1167 Status = ConSplitterStart ( 1168 This, 1169 ControllerHandle, 1170 mConIn.VirtualHandle, 1171 &gEfiConsoleInDeviceGuid, 1172 &gEfiSimpleTextInProtocolGuid, 1173 (VOID **) &TextIn 1174 ); 1175 if (EFI_ERROR (Status)) { 1176 return Status; 1177 } 1178 1179 // 1180 // Add this device into Text In devices list. 1181 // 1182 Status = ConSplitterTextInAddDevice (&mConIn, TextIn); 1183 if (EFI_ERROR (Status)) { 1184 return Status; 1185 } 1186 1187 Status = gBS->OpenProtocol ( 1188 ControllerHandle, 1189 &gEfiSimpleTextInputExProtocolGuid, 1190 (VOID **) &TextInEx, 1191 This->DriverBindingHandle, 1192 mConIn.VirtualHandle, 1193 EFI_OPEN_PROTOCOL_GET_PROTOCOL 1194 ); 1195 if (!EFI_ERROR (Status)) { 1196 // 1197 // If Simple Text Input Ex protocol exists, 1198 // add this device into Text In Ex devices list. 1199 // 1200 Status = ConSplitterTextInExAddDevice (&mConIn, TextInEx); 1201 } 1202 1203 return Status; 1204 } 1205 1206 1207 /** 1208 Start Simple Pointer Consplitter on device handle. 1209 1210 @param This Driver Binding protocol instance pointer. 1211 @param ControllerHandle Handle of device to bind driver to. 1212 @param RemainingDevicePath Optional parameter use to pick a specific child 1213 device to start. 1214 1215 @retval EFI_SUCCESS Simple Pointer Consplitter is added to ControllerHandle. 1216 @retval other Simple Pointer Consplitter does not support this device. 1217 1218 **/ 1219 EFI_STATUS 1220 EFIAPI 1221 ConSplitterSimplePointerDriverBindingStart ( 1222 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1223 IN EFI_HANDLE ControllerHandle, 1224 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 1225 ) 1226 { 1227 EFI_STATUS Status; 1228 EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer; 1229 1230 // 1231 // Start ConSplitter on ControllerHandle, and create the virtual 1232 // agrogated console device on first call Start for a SimplePointer handle. 1233 // 1234 Status = ConSplitterStart ( 1235 This, 1236 ControllerHandle, 1237 mConIn.VirtualHandle, 1238 &gEfiSimplePointerProtocolGuid, 1239 &gEfiSimplePointerProtocolGuid, 1240 (VOID **) &SimplePointer 1241 ); 1242 if (EFI_ERROR (Status)) { 1243 return Status; 1244 } 1245 1246 // 1247 // Add this devcie into Simple Pointer devices list. 1248 // 1249 return ConSplitterSimplePointerAddDevice (&mConIn, SimplePointer); 1250 } 1251 1252 1253 /** 1254 Start Absolute Pointer Consplitter on device handle. 1255 1256 @param This Driver Binding protocol instance pointer. 1257 @param ControllerHandle Handle of device to bind driver to. 1258 @param RemainingDevicePath Optional parameter use to pick a specific child 1259 device to start. 1260 1261 @retval EFI_SUCCESS Absolute Pointer Consplitter is added to ControllerHandle. 1262 @retval other Absolute Pointer Consplitter does not support this device. 1263 1264 **/ 1265 EFI_STATUS 1266 EFIAPI 1267 ConSplitterAbsolutePointerDriverBindingStart ( 1268 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1269 IN EFI_HANDLE ControllerHandle, 1270 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 1271 ) 1272 { 1273 EFI_STATUS Status; 1274 EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer; 1275 1276 // 1277 // Start ConSplitter on ControllerHandle, and create the virtual 1278 // agrogated console device on first call Start for a AbsolutePointer handle. 1279 // 1280 Status = ConSplitterStart ( 1281 This, 1282 ControllerHandle, 1283 mConIn.VirtualHandle, 1284 &gEfiAbsolutePointerProtocolGuid, 1285 &gEfiAbsolutePointerProtocolGuid, 1286 (VOID **) &AbsolutePointer 1287 ); 1288 1289 if (EFI_ERROR (Status)) { 1290 return Status; 1291 } 1292 1293 // 1294 // Add this devcie into Absolute Pointer devices list. 1295 // 1296 return ConSplitterAbsolutePointerAddDevice (&mConIn, AbsolutePointer); 1297 } 1298 1299 1300 /** 1301 Start Console Out Consplitter on device handle. 1302 1303 @param This Driver Binding protocol instance pointer. 1304 @param ControllerHandle Handle of device to bind driver to. 1305 @param RemainingDevicePath Optional parameter use to pick a specific child 1306 device to start. 1307 1308 @retval EFI_SUCCESS Console Out Consplitter is added to ControllerHandle. 1309 @retval other Console Out Consplitter does not support this device. 1310 1311 **/ 1312 EFI_STATUS 1313 EFIAPI 1314 ConSplitterConOutDriverBindingStart ( 1315 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1316 IN EFI_HANDLE ControllerHandle, 1317 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 1318 ) 1319 { 1320 EFI_STATUS Status; 1321 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; 1322 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; 1323 EFI_UGA_DRAW_PROTOCOL *UgaDraw; 1324 UINTN SizeOfInfo; 1325 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; 1326 1327 // 1328 // Start ConSplitter on ControllerHandle, and create the virtual 1329 // agrogated console device on first call Start for a ConsoleOut handle. 1330 // 1331 Status = ConSplitterStart ( 1332 This, 1333 ControllerHandle, 1334 mConOut.VirtualHandle, 1335 &gEfiConsoleOutDeviceGuid, 1336 &gEfiSimpleTextOutProtocolGuid, 1337 (VOID **) &TextOut 1338 ); 1339 if (EFI_ERROR (Status)) { 1340 return Status; 1341 } 1342 1343 GraphicsOutput = NULL; 1344 UgaDraw = NULL; 1345 // 1346 // Try to Open Graphics Output protocol 1347 // 1348 Status = gBS->OpenProtocol ( 1349 ControllerHandle, 1350 &gEfiGraphicsOutputProtocolGuid, 1351 (VOID **) &GraphicsOutput, 1352 This->DriverBindingHandle, 1353 mConOut.VirtualHandle, 1354 EFI_OPEN_PROTOCOL_GET_PROTOCOL 1355 ); 1356 1357 if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) { 1358 // 1359 // Open UGA DRAW protocol 1360 // 1361 gBS->OpenProtocol ( 1362 ControllerHandle, 1363 &gEfiUgaDrawProtocolGuid, 1364 (VOID **) &UgaDraw, 1365 This->DriverBindingHandle, 1366 mConOut.VirtualHandle, 1367 EFI_OPEN_PROTOCOL_GET_PROTOCOL 1368 ); 1369 } 1370 1371 // 1372 // When new console device is added, the new mode will be set later, 1373 // so put current mode back to init state. 1374 // 1375 mConOut.TextOutMode.Mode = 0xFF; 1376 1377 // 1378 // If both ConOut and StdErr incorporate the same Text Out device, 1379 // their MaxMode and QueryData should be the intersection of both. 1380 // 1381 Status = ConSplitterTextOutAddDevice (&mConOut, TextOut, GraphicsOutput, UgaDraw); 1382 ConSplitterTextOutSetAttribute (&mConOut.TextOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); 1383 1384 if (FeaturePcdGet (PcdConOutUgaSupport)) { 1385 // 1386 // Get the UGA mode data of ConOut from the current mode 1387 // 1388 if (GraphicsOutput != NULL) { 1389 Status = GraphicsOutput->QueryMode (GraphicsOutput, GraphicsOutput->Mode->Mode, &SizeOfInfo, &Info); 1390 if (EFI_ERROR (Status)) { 1391 return Status; 1392 } 1393 ASSERT ( SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); 1394 1395 mConOut.UgaHorizontalResolution = Info->HorizontalResolution; 1396 mConOut.UgaVerticalResolution = Info->VerticalResolution; 1397 mConOut.UgaColorDepth = 32; 1398 mConOut.UgaRefreshRate = 60; 1399 1400 FreePool (Info); 1401 1402 } else if (UgaDraw != NULL) { 1403 Status = UgaDraw->GetMode ( 1404 UgaDraw, 1405 &mConOut.UgaHorizontalResolution, 1406 &mConOut.UgaVerticalResolution, 1407 &mConOut.UgaColorDepth, 1408 &mConOut.UgaRefreshRate 1409 ); 1410 } 1411 } 1412 1413 return Status; 1414 } 1415 1416 1417 /** 1418 Start Standard Error Consplitter on device handle. 1419 1420 @param This Driver Binding protocol instance pointer. 1421 @param ControllerHandle Handle of device to bind driver to. 1422 @param RemainingDevicePath Optional parameter use to pick a specific child 1423 device to start. 1424 1425 @retval EFI_SUCCESS Standard Error Consplitter is added to ControllerHandle. 1426 @retval other Standard Error Consplitter does not support this device. 1427 1428 **/ 1429 EFI_STATUS 1430 EFIAPI 1431 ConSplitterStdErrDriverBindingStart ( 1432 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1433 IN EFI_HANDLE ControllerHandle, 1434 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 1435 ) 1436 { 1437 EFI_STATUS Status; 1438 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; 1439 1440 // 1441 // Start ConSplitter on ControllerHandle, and create the virtual 1442 // agrogated console device on first call Start for a StandardError handle. 1443 // 1444 Status = ConSplitterStart ( 1445 This, 1446 ControllerHandle, 1447 mStdErr.VirtualHandle, 1448 &gEfiStandardErrorDeviceGuid, 1449 &gEfiSimpleTextOutProtocolGuid, 1450 (VOID **) &TextOut 1451 ); 1452 if (EFI_ERROR (Status)) { 1453 return Status; 1454 } 1455 1456 // 1457 // When new console device is added, the new mode will be set later, 1458 // so put current mode back to init state. 1459 // 1460 mStdErr.TextOutMode.Mode = 0xFF; 1461 1462 // 1463 // If both ConOut and StdErr incorporate the same Text Out device, 1464 // their MaxMode and QueryData should be the intersection of both. 1465 // 1466 Status = ConSplitterTextOutAddDevice (&mStdErr, TextOut, NULL, NULL); 1467 ConSplitterTextOutSetAttribute (&mStdErr.TextOut, EFI_TEXT_ATTR (EFI_MAGENTA, EFI_BLACK)); 1468 if (EFI_ERROR (Status)) { 1469 return Status; 1470 } 1471 1472 return Status; 1473 } 1474 1475 1476 /** 1477 Stop ConSplitter on device handle by closing Console Device Guid on device handle 1478 and the console virtual handle. 1479 1480 @param This Protocol instance pointer. 1481 @param ControllerHandle Handle of device. 1482 @param ConSplitterVirtualHandle Console virtual Handle. 1483 @param DeviceGuid The specified Console Device, such as ConInDev, 1484 ConOutDev. 1485 @param InterfaceGuid The specified protocol to be opened. 1486 @param Interface Protocol interface returned. 1487 1488 @retval EFI_SUCCESS Stop ConSplitter on ControllerHandle successfully. 1489 @retval other Failed to Stop ConSplitter on ControllerHandle. 1490 1491 **/ 1492 EFI_STATUS 1493 ConSplitterStop ( 1494 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1495 IN EFI_HANDLE ControllerHandle, 1496 IN EFI_HANDLE ConSplitterVirtualHandle, 1497 IN EFI_GUID *DeviceGuid, 1498 IN EFI_GUID *InterfaceGuid, 1499 IN VOID **Interface 1500 ) 1501 { 1502 EFI_STATUS Status; 1503 1504 Status = gBS->OpenProtocol ( 1505 ControllerHandle, 1506 InterfaceGuid, 1507 Interface, 1508 This->DriverBindingHandle, 1509 ControllerHandle, 1510 EFI_OPEN_PROTOCOL_GET_PROTOCOL 1511 ); 1512 if (EFI_ERROR (Status)) { 1513 return Status; 1514 } 1515 // 1516 // close the protocol refered. 1517 // 1518 gBS->CloseProtocol ( 1519 ControllerHandle, 1520 DeviceGuid, 1521 This->DriverBindingHandle, 1522 ConSplitterVirtualHandle 1523 ); 1524 1525 gBS->CloseProtocol ( 1526 ControllerHandle, 1527 DeviceGuid, 1528 This->DriverBindingHandle, 1529 ControllerHandle 1530 ); 1531 1532 return EFI_SUCCESS; 1533 } 1534 1535 1536 /** 1537 Stop Console In ConSplitter on ControllerHandle by closing Console In Devcice GUID. 1538 1539 @param This Driver Binding protocol instance pointer. 1540 @param ControllerHandle Handle of device to stop driver on 1541 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of 1542 children is zero stop the entire bus driver. 1543 @param ChildHandleBuffer List of Child Handles to Stop. 1544 1545 @retval EFI_SUCCESS This driver is removed ControllerHandle 1546 @retval other This driver was not removed from this device 1547 1548 **/ 1549 EFI_STATUS 1550 EFIAPI 1551 ConSplitterConInDriverBindingStop ( 1552 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1553 IN EFI_HANDLE ControllerHandle, 1554 IN UINTN NumberOfChildren, 1555 IN EFI_HANDLE *ChildHandleBuffer 1556 ) 1557 { 1558 EFI_STATUS Status; 1559 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn; 1560 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx; 1561 1562 if (NumberOfChildren == 0) { 1563 return EFI_SUCCESS; 1564 } 1565 1566 Status = gBS->OpenProtocol ( 1567 ControllerHandle, 1568 &gEfiSimpleTextInputExProtocolGuid, 1569 (VOID **) &TextInEx, 1570 This->DriverBindingHandle, 1571 ControllerHandle, 1572 EFI_OPEN_PROTOCOL_GET_PROTOCOL 1573 ); 1574 if (!EFI_ERROR (Status)) { 1575 // 1576 // If Simple Text Input Ex protocol exists, 1577 // remove device from Text Input Ex devices list. 1578 // 1579 Status = ConSplitterTextInExDeleteDevice (&mConIn, TextInEx); 1580 if (EFI_ERROR (Status)) { 1581 return Status; 1582 } 1583 } 1584 1585 // 1586 // Close Simple Text In protocol on controller handle and virtual handle. 1587 // 1588 Status = ConSplitterStop ( 1589 This, 1590 ControllerHandle, 1591 mConIn.VirtualHandle, 1592 &gEfiConsoleInDeviceGuid, 1593 &gEfiSimpleTextInProtocolGuid, 1594 (VOID **) &TextIn 1595 ); 1596 if (EFI_ERROR (Status)) { 1597 return Status; 1598 } 1599 1600 // 1601 // Remove device from Text Input devices list. 1602 // 1603 return ConSplitterTextInDeleteDevice (&mConIn, TextIn); 1604 } 1605 1606 1607 /** 1608 Stop Simple Pointer protocol ConSplitter on ControllerHandle by closing 1609 Simple Pointer protocol. 1610 1611 @param This Driver Binding protocol instance pointer. 1612 @param ControllerHandle Handle of device to stop driver on 1613 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of 1614 children is zero stop the entire bus driver. 1615 @param ChildHandleBuffer List of Child Handles to Stop. 1616 1617 @retval EFI_SUCCESS This driver is removed ControllerHandle 1618 @retval other This driver was not removed from this device 1619 1620 **/ 1621 EFI_STATUS 1622 EFIAPI 1623 ConSplitterSimplePointerDriverBindingStop ( 1624 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1625 IN EFI_HANDLE ControllerHandle, 1626 IN UINTN NumberOfChildren, 1627 IN EFI_HANDLE *ChildHandleBuffer 1628 ) 1629 { 1630 EFI_STATUS Status; 1631 EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer; 1632 1633 if (NumberOfChildren == 0) { 1634 return EFI_SUCCESS; 1635 } 1636 1637 // 1638 // Close Simple Pointer protocol on controller handle and virtual handle. 1639 // 1640 Status = ConSplitterStop ( 1641 This, 1642 ControllerHandle, 1643 mConIn.VirtualHandle, 1644 &gEfiSimplePointerProtocolGuid, 1645 &gEfiSimplePointerProtocolGuid, 1646 (VOID **) &SimplePointer 1647 ); 1648 if (EFI_ERROR (Status)) { 1649 return Status; 1650 } 1651 1652 // 1653 // Remove this device from Simple Pointer device list. 1654 // 1655 return ConSplitterSimplePointerDeleteDevice (&mConIn, SimplePointer); 1656 } 1657 1658 1659 /** 1660 Stop Absolute Pointer protocol ConSplitter on ControllerHandle by closing 1661 Absolute Pointer protocol. 1662 1663 @param This Driver Binding protocol instance pointer. 1664 @param ControllerHandle Handle of device to stop driver on 1665 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of 1666 children is zero stop the entire bus driver. 1667 @param ChildHandleBuffer List of Child Handles to Stop. 1668 1669 @retval EFI_SUCCESS This driver is removed ControllerHandle 1670 @retval other This driver was not removed from this device 1671 1672 **/ 1673 EFI_STATUS 1674 EFIAPI 1675 ConSplitterAbsolutePointerDriverBindingStop ( 1676 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1677 IN EFI_HANDLE ControllerHandle, 1678 IN UINTN NumberOfChildren, 1679 IN EFI_HANDLE *ChildHandleBuffer 1680 ) 1681 { 1682 EFI_STATUS Status; 1683 EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer; 1684 1685 if (NumberOfChildren == 0) { 1686 return EFI_SUCCESS; 1687 } 1688 1689 // 1690 // Close Absolute Pointer protocol on controller handle and virtual handle. 1691 // 1692 Status = ConSplitterStop ( 1693 This, 1694 ControllerHandle, 1695 mConIn.VirtualHandle, 1696 &gEfiAbsolutePointerProtocolGuid, 1697 &gEfiAbsolutePointerProtocolGuid, 1698 (VOID **) &AbsolutePointer 1699 ); 1700 if (EFI_ERROR (Status)) { 1701 return Status; 1702 } 1703 1704 // 1705 // Remove this device from Absolute Pointer device list. 1706 // 1707 return ConSplitterAbsolutePointerDeleteDevice (&mConIn, AbsolutePointer); 1708 } 1709 1710 1711 /** 1712 Stop Console Out ConSplitter on device handle by closing Console Out Devcice GUID. 1713 1714 @param This Driver Binding protocol instance pointer. 1715 @param ControllerHandle Handle of device to stop driver on 1716 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of 1717 children is zero stop the entire bus driver. 1718 @param ChildHandleBuffer List of Child Handles to Stop. 1719 1720 @retval EFI_SUCCESS This driver is removed ControllerHandle 1721 @retval other This driver was not removed from this device 1722 1723 **/ 1724 EFI_STATUS 1725 EFIAPI 1726 ConSplitterConOutDriverBindingStop ( 1727 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1728 IN EFI_HANDLE ControllerHandle, 1729 IN UINTN NumberOfChildren, 1730 IN EFI_HANDLE *ChildHandleBuffer 1731 ) 1732 { 1733 EFI_STATUS Status; 1734 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; 1735 1736 if (NumberOfChildren == 0) { 1737 return EFI_SUCCESS; 1738 } 1739 1740 // 1741 // Close Absolute Pointer protocol on controller handle and virtual handle. 1742 // 1743 Status = ConSplitterStop ( 1744 This, 1745 ControllerHandle, 1746 mConOut.VirtualHandle, 1747 &gEfiConsoleOutDeviceGuid, 1748 &gEfiSimpleTextOutProtocolGuid, 1749 (VOID **) &TextOut 1750 ); 1751 if (EFI_ERROR (Status)) { 1752 return Status; 1753 } 1754 1755 // 1756 // Remove this device from Text Out device list. 1757 // 1758 return ConSplitterTextOutDeleteDevice (&mConOut, TextOut); 1759 } 1760 1761 1762 /** 1763 Stop Standard Error ConSplitter on ControllerHandle by closing Standard Error GUID. 1764 1765 @param This Driver Binding protocol instance pointer. 1766 @param ControllerHandle Handle of device to stop driver on 1767 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of 1768 children is zero stop the entire bus driver. 1769 @param ChildHandleBuffer List of Child Handles to Stop. 1770 1771 @retval EFI_SUCCESS This driver is removed ControllerHandle 1772 @retval other This driver was not removed from this device 1773 1774 **/ 1775 EFI_STATUS 1776 EFIAPI 1777 ConSplitterStdErrDriverBindingStop ( 1778 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1779 IN EFI_HANDLE ControllerHandle, 1780 IN UINTN NumberOfChildren, 1781 IN EFI_HANDLE *ChildHandleBuffer 1782 ) 1783 { 1784 EFI_STATUS Status; 1785 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; 1786 1787 if (NumberOfChildren == 0) { 1788 return EFI_SUCCESS; 1789 } 1790 1791 // 1792 // Close Standard Error Device on controller handle and virtual handle. 1793 // 1794 Status = ConSplitterStop ( 1795 This, 1796 ControllerHandle, 1797 mStdErr.VirtualHandle, 1798 &gEfiStandardErrorDeviceGuid, 1799 &gEfiSimpleTextOutProtocolGuid, 1800 (VOID **) &TextOut 1801 ); 1802 if (EFI_ERROR (Status)) { 1803 return Status; 1804 } 1805 // 1806 // Delete this console error out device's data structures. 1807 // 1808 return ConSplitterTextOutDeleteDevice (&mStdErr, TextOut); 1809 } 1810 1811 1812 /** 1813 Take the passed in Buffer of size ElementSize and grow the buffer 1814 by CONSOLE_SPLITTER_ALLOC_UNIT * ElementSize bytes. 1815 Copy the current data in Buffer to the new version of Buffer and 1816 free the old version of buffer. 1817 1818 @param ElementSize Size of element in array. 1819 @param Count Current number of elements in array. 1820 @param Buffer Bigger version of passed in Buffer with all the 1821 data. 1822 1823 @retval EFI_SUCCESS Buffer size has grown. 1824 @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. 1825 1826 **/ 1827 EFI_STATUS 1828 ConSplitterGrowBuffer ( 1829 IN UINTN ElementSize, 1830 IN OUT UINTN *Count, 1831 IN OUT VOID **Buffer 1832 ) 1833 { 1834 VOID *Ptr; 1835 1836 // 1837 // grow the buffer to new buffer size, 1838 // copy the old buffer's content to the new-size buffer, 1839 // then free the old buffer. 1840 // 1841 Ptr = ReallocatePool ( 1842 ElementSize * (*Count), 1843 ElementSize * ((*Count) + CONSOLE_SPLITTER_ALLOC_UNIT), 1844 *Buffer 1845 ); 1846 if (Ptr == NULL) { 1847 return EFI_OUT_OF_RESOURCES; 1848 } 1849 *Count += CONSOLE_SPLITTER_ALLOC_UNIT; 1850 *Buffer = Ptr; 1851 return EFI_SUCCESS; 1852 } 1853 1854 1855 /** 1856 Add Text Input Device in Consplitter Text Input list. 1857 1858 @param Private Text In Splitter pointer. 1859 @param TextIn Simple Text Input protocol pointer. 1860 1861 @retval EFI_SUCCESS Text Input Device added successfully. 1862 @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. 1863 1864 **/ 1865 EFI_STATUS 1866 ConSplitterTextInAddDevice ( 1867 IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, 1868 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn 1869 ) 1870 { 1871 EFI_STATUS Status; 1872 1873 // 1874 // If the Text In List is full, enlarge it by calling ConSplitterGrowBuffer(). 1875 // 1876 if (Private->CurrentNumberOfConsoles >= Private->TextInListCount) { 1877 Status = ConSplitterGrowBuffer ( 1878 sizeof (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *), 1879 &Private->TextInListCount, 1880 (VOID **) &Private->TextInList 1881 ); 1882 if (EFI_ERROR (Status)) { 1883 return EFI_OUT_OF_RESOURCES; 1884 } 1885 } 1886 // 1887 // Add the new text-in device data structure into the Text In List. 1888 // 1889 Private->TextInList[Private->CurrentNumberOfConsoles] = TextIn; 1890 Private->CurrentNumberOfConsoles++; 1891 1892 // 1893 // Extra CheckEvent added to reduce the double CheckEvent(). 1894 // 1895 gBS->CheckEvent (TextIn->WaitForKey); 1896 1897 return EFI_SUCCESS; 1898 } 1899 1900 1901 /** 1902 Remove Text Input Device from Consplitter Text Input list. 1903 1904 @param Private Text In Splitter pointer. 1905 @param TextIn Simple Text protocol pointer. 1906 1907 @retval EFI_SUCCESS Simple Text Device removed successfully. 1908 @retval EFI_NOT_FOUND No Simple Text Device found. 1909 1910 **/ 1911 EFI_STATUS 1912 ConSplitterTextInDeleteDevice ( 1913 IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, 1914 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn 1915 ) 1916 { 1917 UINTN Index; 1918 // 1919 // Remove the specified text-in device data structure from the Text In List, 1920 // and rearrange the remaining data structures in the Text In List. 1921 // 1922 for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) { 1923 if (Private->TextInList[Index] == TextIn) { 1924 for (; Index < Private->CurrentNumberOfConsoles - 1; Index++) { 1925 Private->TextInList[Index] = Private->TextInList[Index + 1]; 1926 } 1927 1928 Private->CurrentNumberOfConsoles--; 1929 return EFI_SUCCESS; 1930 } 1931 } 1932 1933 return EFI_NOT_FOUND; 1934 } 1935 1936 /** 1937 Add Text Input Ex Device in Consplitter Text Input Ex list. 1938 1939 @param Private Text In Splitter pointer. 1940 @param TextInEx Simple Text Input Ex Input protocol pointer. 1941 1942 @retval EFI_SUCCESS Text Input Ex Device added successfully. 1943 @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. 1944 1945 **/ 1946 EFI_STATUS 1947 ConSplitterTextInExAddDevice ( 1948 IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, 1949 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx 1950 ) 1951 { 1952 EFI_STATUS Status; 1953 LIST_ENTRY *Link; 1954 TEXT_IN_EX_SPLITTER_NOTIFY *CurrentNotify; 1955 UINTN TextInExListCount; 1956 1957 // 1958 // Enlarge the NotifyHandleList and the TextInExList 1959 // 1960 if (Private->CurrentNumberOfExConsoles >= Private->TextInExListCount) { 1961 for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) { 1962 CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link); 1963 TextInExListCount = Private->TextInExListCount; 1964 1965 Status = ConSplitterGrowBuffer ( 1966 sizeof (EFI_HANDLE), 1967 &TextInExListCount, 1968 (VOID **) &CurrentNotify->NotifyHandleList 1969 ); 1970 if (EFI_ERROR (Status)) { 1971 return EFI_OUT_OF_RESOURCES; 1972 } 1973 } 1974 Status = ConSplitterGrowBuffer ( 1975 sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *), 1976 &Private->TextInExListCount, 1977 (VOID **) &Private->TextInExList 1978 ); 1979 if (EFI_ERROR (Status)) { 1980 return EFI_OUT_OF_RESOURCES; 1981 } 1982 } 1983 1984 // 1985 // Register the key notify in the new text-in device 1986 // 1987 for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) { 1988 CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link); 1989 Status = TextInEx->RegisterKeyNotify ( 1990 TextInEx, 1991 &CurrentNotify->KeyData, 1992 CurrentNotify->KeyNotificationFn, 1993 &CurrentNotify->NotifyHandleList[Private->CurrentNumberOfExConsoles] 1994 ); 1995 if (EFI_ERROR (Status)) { 1996 for (Link = Link->BackLink; Link != &Private->NotifyList; Link = Link->BackLink) { 1997 CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link); 1998 TextInEx->UnregisterKeyNotify ( 1999 TextInEx, 2000 CurrentNotify->NotifyHandleList[Private->CurrentNumberOfExConsoles] 2001 ); 2002 } 2003 return Status; 2004 } 2005 } 2006 2007 // 2008 // Add the new text-in device data structure into the Text Input Ex List. 2009 // 2010 Private->TextInExList[Private->CurrentNumberOfExConsoles] = TextInEx; 2011 Private->CurrentNumberOfExConsoles++; 2012 2013 // 2014 // Sync current toggle state to this new console input device. 2015 // 2016 TextInEx->SetState (TextInEx, &Private->PhysicalKeyToggleState); 2017 2018 // 2019 // Extra CheckEvent added to reduce the double CheckEvent(). 2020 // 2021 gBS->CheckEvent (TextInEx->WaitForKeyEx); 2022 2023 return EFI_SUCCESS; 2024 } 2025 2026 /** 2027 Remove Text Ex Device from Consplitter Text Input Ex list. 2028 2029 @param Private Text In Splitter pointer. 2030 @param TextInEx Simple Text Ex protocol pointer. 2031 2032 @retval EFI_SUCCESS Simple Text Input Ex Device removed successfully. 2033 @retval EFI_NOT_FOUND No Simple Text Input Ex Device found. 2034 2035 **/ 2036 EFI_STATUS 2037 ConSplitterTextInExDeleteDevice ( 2038 IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, 2039 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx 2040 ) 2041 { 2042 UINTN Index; 2043 // 2044 // Remove the specified text-in device data structure from the Text Input Ex List, 2045 // and rearrange the remaining data structures in the Text In List. 2046 // 2047 for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { 2048 if (Private->TextInExList[Index] == TextInEx) { 2049 for (; Index < Private->CurrentNumberOfExConsoles - 1; Index++) { 2050 Private->TextInExList[Index] = Private->TextInExList[Index + 1]; 2051 } 2052 2053 Private->CurrentNumberOfExConsoles--; 2054 return EFI_SUCCESS; 2055 } 2056 } 2057 2058 return EFI_NOT_FOUND; 2059 } 2060 2061 2062 /** 2063 Add Simple Pointer Device in Consplitter Simple Pointer list. 2064 2065 @param Private Text In Splitter pointer. 2066 @param SimplePointer Simple Pointer protocol pointer. 2067 2068 @retval EFI_SUCCESS Simple Pointer Device added successfully. 2069 @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. 2070 2071 **/ 2072 EFI_STATUS 2073 ConSplitterSimplePointerAddDevice ( 2074 IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, 2075 IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer 2076 ) 2077 { 2078 EFI_STATUS Status; 2079 2080 // 2081 // If the Simple Pointer List is full, enlarge it by calling ConSplitterGrowBuffer(). 2082 // 2083 if (Private->CurrentNumberOfPointers >= Private->PointerListCount) { 2084 Status = ConSplitterGrowBuffer ( 2085 sizeof (EFI_SIMPLE_POINTER_PROTOCOL *), 2086 &Private->PointerListCount, 2087 (VOID **) &Private->PointerList 2088 ); 2089 if (EFI_ERROR (Status)) { 2090 return EFI_OUT_OF_RESOURCES; 2091 } 2092 } 2093 // 2094 // Add the new text-in device data structure into the Simple Pointer List. 2095 // 2096 Private->PointerList[Private->CurrentNumberOfPointers] = SimplePointer; 2097 Private->CurrentNumberOfPointers++; 2098 2099 return EFI_SUCCESS; 2100 } 2101 2102 2103 /** 2104 Remove Simple Pointer Device from Consplitter Simple Pointer list. 2105 2106 @param Private Text In Splitter pointer. 2107 @param SimplePointer Simple Pointer protocol pointer. 2108 2109 @retval EFI_SUCCESS Simple Pointer Device removed successfully. 2110 @retval EFI_NOT_FOUND No Simple Pointer Device found. 2111 2112 **/ 2113 EFI_STATUS 2114 ConSplitterSimplePointerDeleteDevice ( 2115 IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, 2116 IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer 2117 ) 2118 { 2119 UINTN Index; 2120 // 2121 // Remove the specified text-in device data structure from the Simple Pointer List, 2122 // and rearrange the remaining data structures in the Text In List. 2123 // 2124 for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) { 2125 if (Private->PointerList[Index] == SimplePointer) { 2126 for (; Index < Private->CurrentNumberOfPointers - 1; Index++) { 2127 Private->PointerList[Index] = Private->PointerList[Index + 1]; 2128 } 2129 2130 Private->CurrentNumberOfPointers--; 2131 return EFI_SUCCESS; 2132 } 2133 } 2134 2135 return EFI_NOT_FOUND; 2136 } 2137 2138 2139 /** 2140 Add Absolute Pointer Device in Consplitter Absolute Pointer list. 2141 2142 @param Private Text In Splitter pointer. 2143 @param AbsolutePointer Absolute Pointer protocol pointer. 2144 2145 @retval EFI_SUCCESS Absolute Pointer Device added successfully. 2146 @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. 2147 2148 **/ 2149 EFI_STATUS 2150 ConSplitterAbsolutePointerAddDevice ( 2151 IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, 2152 IN EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer 2153 ) 2154 { 2155 EFI_STATUS Status; 2156 2157 // 2158 // If the Absolute Pointer List is full, enlarge it by calling ConSplitterGrowBuffer(). 2159 // 2160 if (Private->CurrentNumberOfAbsolutePointers >= Private->AbsolutePointerListCount) { 2161 Status = ConSplitterGrowBuffer ( 2162 sizeof (EFI_ABSOLUTE_POINTER_PROTOCOL *), 2163 &Private->AbsolutePointerListCount, 2164 (VOID **) &Private->AbsolutePointerList 2165 ); 2166 if (EFI_ERROR (Status)) { 2167 return EFI_OUT_OF_RESOURCES; 2168 } 2169 } 2170 // 2171 // Add the new text-in device data structure into the Absolute Pointer List. 2172 // 2173 Private->AbsolutePointerList[Private->CurrentNumberOfAbsolutePointers] = AbsolutePointer; 2174 Private->CurrentNumberOfAbsolutePointers++; 2175 2176 return EFI_SUCCESS; 2177 } 2178 2179 2180 /** 2181 Remove Absolute Pointer Device from Consplitter Absolute Pointer list. 2182 2183 @param Private Text In Splitter pointer. 2184 @param AbsolutePointer Absolute Pointer protocol pointer. 2185 2186 @retval EFI_SUCCESS Absolute Pointer Device removed successfully. 2187 @retval EFI_NOT_FOUND No Absolute Pointer Device found. 2188 2189 **/ 2190 EFI_STATUS 2191 ConSplitterAbsolutePointerDeleteDevice ( 2192 IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, 2193 IN EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer 2194 ) 2195 { 2196 UINTN Index; 2197 // 2198 // Remove the specified text-in device data structure from the Absolute Pointer List, 2199 // and rearrange the remaining data structures from the Absolute Pointer List. 2200 // 2201 for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) { 2202 if (Private->AbsolutePointerList[Index] == AbsolutePointer) { 2203 for (; Index < Private->CurrentNumberOfAbsolutePointers - 1; Index++) { 2204 Private->AbsolutePointerList[Index] = Private->AbsolutePointerList[Index + 1]; 2205 } 2206 2207 Private->CurrentNumberOfAbsolutePointers--; 2208 return EFI_SUCCESS; 2209 } 2210 } 2211 2212 return EFI_NOT_FOUND; 2213 } 2214 2215 /** 2216 Reallocate Text Out mode map. 2217 2218 Allocate new buffer and copy original buffer into the new buffer. 2219 2220 @param Private Consplitter Text Out pointer. 2221 2222 @retval EFI_SUCCESS Buffer size has grown 2223 @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. 2224 2225 **/ 2226 EFI_STATUS 2227 ConSplitterGrowMapTable ( 2228 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private 2229 ) 2230 { 2231 UINTN Size; 2232 UINTN NewSize; 2233 UINTN TotalSize; 2234 INT32 *TextOutModeMap; 2235 INT32 *OldTextOutModeMap; 2236 INT32 *SrcAddress; 2237 INT32 Index; 2238 UINTN OldStepSize; 2239 UINTN NewStepSize; 2240 2241 NewSize = Private->TextOutListCount * sizeof (INT32); 2242 OldTextOutModeMap = Private->TextOutModeMap; 2243 TotalSize = NewSize * (Private->TextOutQueryDataCount); 2244 2245 // 2246 // Allocate new buffer for Text Out List. 2247 // 2248 TextOutModeMap = AllocatePool (TotalSize); 2249 if (TextOutModeMap == NULL) { 2250 return EFI_OUT_OF_RESOURCES; 2251 } 2252 2253 SetMem (TextOutModeMap, TotalSize, 0xFF); 2254 Private->TextOutModeMap = TextOutModeMap; 2255 2256 // 2257 // If TextOutList has been enlarged, need to realloc the mode map table 2258 // The mode map table is regarded as a two dimension array. 2259 // 2260 // Old New 2261 // 0 ---------> TextOutListCount ----> TextOutListCount 2262 // | ------------------------------------------- 2263 // | | | | 2264 // | | | | 2265 // | | | | 2266 // | | | | 2267 // | | | | 2268 // \/ | | | 2269 // ------------------------------------------- 2270 // QueryDataCount 2271 // 2272 if (OldTextOutModeMap != NULL) { 2273 2274 Size = Private->CurrentNumberOfConsoles * sizeof (INT32); 2275 Index = 0; 2276 SrcAddress = OldTextOutModeMap; 2277 NewStepSize = NewSize / sizeof(INT32); 2278 // If Private->CurrentNumberOfConsoles is not zero and OldTextOutModeMap 2279 // is not NULL, it indicates that the original TextOutModeMap is not enough 2280 // for the new console devices and has been enlarged by CONSOLE_SPLITTER_ALLOC_UNIT columns. 2281 // 2282 OldStepSize = NewStepSize - CONSOLE_SPLITTER_ALLOC_UNIT; 2283 2284 // 2285 // Copy the old data to the new one 2286 // 2287 while (Index < Private->TextOutMode.MaxMode) { 2288 CopyMem (TextOutModeMap, SrcAddress, Size); 2289 // 2290 // Go to next row of new TextOutModeMap. 2291 // 2292 TextOutModeMap += NewStepSize; 2293 // 2294 // Go to next row of old TextOutModeMap. 2295 // 2296 SrcAddress += OldStepSize; 2297 Index++; 2298 } 2299 // 2300 // Free the old buffer 2301 // 2302 FreePool (OldTextOutModeMap); 2303 } 2304 2305 return EFI_SUCCESS; 2306 } 2307 2308 2309 /** 2310 Add new device's output mode to console splitter's mode list. 2311 2312 @param Private Text Out Splitter pointer 2313 @param TextOut Simple Text Output protocol pointer. 2314 2315 @retval EFI_SUCCESS Device added successfully. 2316 @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. 2317 2318 **/ 2319 EFI_STATUS 2320 ConSplitterAddOutputMode ( 2321 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, 2322 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut 2323 ) 2324 { 2325 EFI_STATUS Status; 2326 INT32 MaxMode; 2327 INT32 Mode; 2328 UINTN Index; 2329 2330 MaxMode = TextOut->Mode->MaxMode; 2331 Private->TextOutMode.MaxMode = MaxMode; 2332 2333 // 2334 // Grow the buffer if query data buffer is not large enough to 2335 // hold all the mode supported by the first console. 2336 // 2337 while (MaxMode > (INT32) Private->TextOutQueryDataCount) { 2338 Status = ConSplitterGrowBuffer ( 2339 sizeof (TEXT_OUT_SPLITTER_QUERY_DATA), 2340 &Private->TextOutQueryDataCount, 2341 (VOID **) &Private->TextOutQueryData 2342 ); 2343 if (EFI_ERROR (Status)) { 2344 return EFI_OUT_OF_RESOURCES; 2345 } 2346 } 2347 // 2348 // Allocate buffer for the output mode map 2349 // 2350 Status = ConSplitterGrowMapTable (Private); 2351 if (EFI_ERROR (Status)) { 2352 return EFI_OUT_OF_RESOURCES; 2353 } 2354 // 2355 // As the first textout device, directly add the mode in to QueryData 2356 // and at the same time record the mapping between QueryData and TextOut. 2357 // 2358 Mode = 0; 2359 Index = 0; 2360 while (Mode < MaxMode) { 2361 Status = TextOut->QueryMode ( 2362 TextOut, 2363 Mode, 2364 &Private->TextOutQueryData[Mode].Columns, 2365 &Private->TextOutQueryData[Mode].Rows 2366 ); 2367 // 2368 // If mode 1 (80x50) is not supported, make sure mode 1 in TextOutQueryData 2369 // is clear to 0x0. 2370 // 2371 if ((EFI_ERROR(Status)) && (Mode == 1)) { 2372 Private->TextOutQueryData[Mode].Columns = 0; 2373 Private->TextOutQueryData[Mode].Rows = 0; 2374 } 2375 Private->TextOutModeMap[Index] = Mode; 2376 Mode++; 2377 Index += Private->TextOutListCount; 2378 } 2379 2380 return EFI_SUCCESS; 2381 } 2382 2383 /** 2384 Reconstruct TextOutModeMap to get intersection of modes. 2385 2386 This routine reconstruct TextOutModeMap to get the intersection 2387 of modes for all console out devices. Because EFI/UEFI spec require 2388 mode 0 is 80x25, mode 1 is 80x50, this routine will not check the 2389 intersection for mode 0 and mode 1. 2390 2391 @param TextOutModeMap Current text out mode map, begin with the mode 80x25 2392 @param NewlyAddedMap New text out mode map, begin with the mode 80x25 2393 @param MapStepSize Mode step size for one console device 2394 @param NewMapStepSize New Mode step size for one console device 2395 @param MaxMode IN: Current max text mode, OUT: Updated max text mode. 2396 @param CurrentMode IN: Current text mode, OUT: Updated current text mode. 2397 2398 **/ 2399 VOID 2400 ConSplitterGetIntersection ( 2401 IN INT32 *TextOutModeMap, 2402 IN INT32 *NewlyAddedMap, 2403 IN UINTN MapStepSize, 2404 IN UINTN NewMapStepSize, 2405 IN OUT INT32 *MaxMode, 2406 IN OUT INT32 *CurrentMode 2407 ) 2408 { 2409 INT32 Index; 2410 INT32 *CurrentMapEntry; 2411 INT32 *NextMapEntry; 2412 INT32 *NewMapEntry; 2413 INT32 CurrentMaxMode; 2414 INT32 Mode; 2415 2416 // 2417 // According to EFI/UEFI spec, mode 0 and mode 1 have been reserved 2418 // for 80x25 and 80x50 in Simple Text Out protocol, so don't make intersection 2419 // for mode 0 and mode 1, mode number starts from 2. 2420 // 2421 Index = 2; 2422 CurrentMapEntry = &TextOutModeMap[MapStepSize * 2]; 2423 NextMapEntry = CurrentMapEntry; 2424 NewMapEntry = &NewlyAddedMap[NewMapStepSize * 2]; 2425 2426 CurrentMaxMode = *MaxMode; 2427 Mode = *CurrentMode; 2428 2429 while (Index < CurrentMaxMode) { 2430 if (*NewMapEntry == -1) { 2431 // 2432 // This mode is not supported any more. Remove it. Special care 2433 // must be taken as this remove will also affect current mode; 2434 // 2435 if (Index == *CurrentMode) { 2436 Mode = -1; 2437 } else if (Index < *CurrentMode) { 2438 Mode--; 2439 } 2440 (*MaxMode)--; 2441 } else { 2442 if (CurrentMapEntry != NextMapEntry) { 2443 CopyMem (NextMapEntry, CurrentMapEntry, MapStepSize * sizeof (INT32)); 2444 } 2445 2446 NextMapEntry += MapStepSize; 2447 } 2448 2449 CurrentMapEntry += MapStepSize; 2450 NewMapEntry += NewMapStepSize; 2451 Index++; 2452 } 2453 2454 *CurrentMode = Mode; 2455 2456 return ; 2457 } 2458 2459 /** 2460 Sync the device's output mode to console splitter's mode list. 2461 2462 @param Private Text Out Splitter pointer. 2463 @param TextOut Simple Text Output protocol pointer. 2464 2465 **/ 2466 VOID 2467 ConSplitterSyncOutputMode ( 2468 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, 2469 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut 2470 ) 2471 { 2472 INT32 CurrentMaxMode; 2473 INT32 Mode; 2474 INT32 Index; 2475 INT32 *TextOutModeMap; 2476 INT32 *MapTable; 2477 INT32 QueryMode; 2478 TEXT_OUT_SPLITTER_QUERY_DATA *TextOutQueryData; 2479 UINTN Rows; 2480 UINTN Columns; 2481 UINTN StepSize; 2482 EFI_STATUS Status; 2483 2484 // 2485 // Must make sure that current mode won't change even if mode number changes 2486 // 2487 CurrentMaxMode = Private->TextOutMode.MaxMode; 2488 TextOutModeMap = Private->TextOutModeMap; 2489 StepSize = Private->TextOutListCount; 2490 TextOutQueryData = Private->TextOutQueryData; 2491 2492 // 2493 // Query all the mode that the newly added TextOut supports 2494 // 2495 Mode = 0; 2496 MapTable = TextOutModeMap + Private->CurrentNumberOfConsoles; 2497 while (Mode < TextOut->Mode->MaxMode) { 2498 Status = TextOut->QueryMode (TextOut, Mode, &Columns, &Rows); 2499 2500 if (EFI_ERROR(Status)) { 2501 if (Mode == 1) { 2502 // 2503 // If mode 1 (80x50) is not supported, make sure mode 1 in TextOutQueryData 2504 // is clear to 0x0. 2505 // 2506 MapTable[StepSize] = Mode; 2507 TextOutQueryData[Mode].Columns = 0; 2508 TextOutQueryData[Mode].Rows = 0; 2509 } 2510 Mode++; 2511 continue; 2512 } 2513 // 2514 // Search the intersection map and QueryData database to see if they intersects 2515 // 2516 Index = 0; 2517 while (Index < CurrentMaxMode) { 2518 QueryMode = *(TextOutModeMap + Index * StepSize); 2519 if ((TextOutQueryData[QueryMode].Rows == Rows) && (TextOutQueryData[QueryMode].Columns == Columns)) { 2520 MapTable[Index * StepSize] = Mode; 2521 break; 2522 } 2523 Index++; 2524 } 2525 Mode++; 2526 } 2527 // 2528 // Now search the TextOutModeMap table to find the intersection of supported 2529 // mode between ConSplitter and the newly added device. 2530 // 2531 ConSplitterGetIntersection ( 2532 TextOutModeMap, 2533 MapTable, 2534 StepSize, 2535 StepSize, 2536 &Private->TextOutMode.MaxMode, 2537 &Private->TextOutMode.Mode 2538 ); 2539 2540 return ; 2541 } 2542 2543 2544 /** 2545 Sync output device between ConOut and StdErr output. 2546 2547 @retval EFI_SUCCESS Sync implemented successfully. 2548 @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. 2549 2550 **/ 2551 EFI_STATUS 2552 ConSplitterGetIntersectionBetweenConOutAndStrErr ( 2553 VOID 2554 ) 2555 { 2556 UINTN ConOutNumOfConsoles; 2557 UINTN StdErrNumOfConsoles; 2558 TEXT_OUT_AND_GOP_DATA *ConOutTextOutList; 2559 TEXT_OUT_AND_GOP_DATA *StdErrTextOutList; 2560 UINTN Indexi; 2561 UINTN Indexj; 2562 UINTN ConOutRows; 2563 UINTN ConOutColumns; 2564 UINTN StdErrRows; 2565 UINTN StdErrColumns; 2566 INT32 ConOutMaxMode; 2567 INT32 StdErrMaxMode; 2568 INT32 ConOutMode; 2569 INT32 StdErrMode; 2570 INT32 Mode; 2571 INT32 Index; 2572 INT32 *ConOutModeMap; 2573 INT32 *StdErrModeMap; 2574 INT32 *ConOutMapTable; 2575 INT32 *StdErrMapTable; 2576 TEXT_OUT_SPLITTER_QUERY_DATA *ConOutQueryData; 2577 TEXT_OUT_SPLITTER_QUERY_DATA *StdErrQueryData; 2578 UINTN ConOutStepSize; 2579 UINTN StdErrStepSize; 2580 BOOLEAN FoundTheSameTextOut; 2581 UINTN ConOutMapTableSize; 2582 UINTN StdErrMapTableSize; 2583 2584 ConOutNumOfConsoles = mConOut.CurrentNumberOfConsoles; 2585 StdErrNumOfConsoles = mStdErr.CurrentNumberOfConsoles; 2586 ConOutTextOutList = mConOut.TextOutList; 2587 StdErrTextOutList = mStdErr.TextOutList; 2588 2589 Indexi = 0; 2590 FoundTheSameTextOut = FALSE; 2591 while ((Indexi < ConOutNumOfConsoles) && (!FoundTheSameTextOut)) { 2592 Indexj = 0; 2593 while (Indexj < StdErrNumOfConsoles) { 2594 if (ConOutTextOutList->TextOut == StdErrTextOutList->TextOut) { 2595 FoundTheSameTextOut = TRUE; 2596 break; 2597 } 2598 2599 Indexj++; 2600 StdErrTextOutList++; 2601 } 2602 2603 Indexi++; 2604 ConOutTextOutList++; 2605 } 2606 2607 if (!FoundTheSameTextOut) { 2608 return EFI_SUCCESS; 2609 } 2610 // 2611 // Must make sure that current mode won't change even if mode number changes 2612 // 2613 ConOutMaxMode = mConOut.TextOutMode.MaxMode; 2614 ConOutModeMap = mConOut.TextOutModeMap; 2615 ConOutStepSize = mConOut.TextOutListCount; 2616 ConOutQueryData = mConOut.TextOutQueryData; 2617 2618 StdErrMaxMode = mStdErr.TextOutMode.MaxMode; 2619 StdErrModeMap = mStdErr.TextOutModeMap; 2620 StdErrStepSize = mStdErr.TextOutListCount; 2621 StdErrQueryData = mStdErr.TextOutQueryData; 2622 2623 // 2624 // Allocate the map table and set the map table's index to -1. 2625 // 2626 ConOutMapTableSize = ConOutMaxMode * sizeof (INT32); 2627 ConOutMapTable = AllocateZeroPool (ConOutMapTableSize); 2628 if (ConOutMapTable == NULL) { 2629 return EFI_OUT_OF_RESOURCES; 2630 } 2631 2632 SetMem (ConOutMapTable, ConOutMapTableSize, 0xFF); 2633 2634 StdErrMapTableSize = StdErrMaxMode * sizeof (INT32); 2635 StdErrMapTable = AllocateZeroPool (StdErrMapTableSize); 2636 if (StdErrMapTable == NULL) { 2637 return EFI_OUT_OF_RESOURCES; 2638 } 2639 2640 SetMem (StdErrMapTable, StdErrMapTableSize, 0xFF); 2641 2642 // 2643 // Find the intersection of the two set of modes. If they actually intersect, the 2644 // corresponding entry in the map table is set to 1. 2645 // 2646 Mode = 0; 2647 while (Mode < ConOutMaxMode) { 2648 // 2649 // Search the intersection map and QueryData database to see if they intersect 2650 // 2651 Index = 0; 2652 ConOutMode = *(ConOutModeMap + Mode * ConOutStepSize); 2653 ConOutRows = ConOutQueryData[ConOutMode].Rows; 2654 ConOutColumns = ConOutQueryData[ConOutMode].Columns; 2655 while (Index < StdErrMaxMode) { 2656 StdErrMode = *(StdErrModeMap + Index * StdErrStepSize); 2657 StdErrRows = StdErrQueryData[StdErrMode].Rows; 2658 StdErrColumns = StdErrQueryData[StdErrMode].Columns; 2659 if ((StdErrRows == ConOutRows) && (StdErrColumns == ConOutColumns)) { 2660 ConOutMapTable[Mode] = 1; 2661 StdErrMapTable[Index] = 1; 2662 break; 2663 } 2664 2665 Index++; 2666 } 2667 2668 Mode++; 2669 } 2670 // 2671 // Now search the TextOutModeMap table to find the intersection of supported 2672 // mode between ConSplitter and the newly added device. 2673 // 2674 ConSplitterGetIntersection ( 2675 ConOutModeMap, 2676 ConOutMapTable, 2677 mConOut.TextOutListCount, 2678 1, 2679 &(mConOut.TextOutMode.MaxMode), 2680 &(mConOut.TextOutMode.Mode) 2681 ); 2682 2683 if (mConOut.TextOutMode.Mode < 0) { 2684 mConOut.TextOut.SetMode (&(mConOut.TextOut), 0); 2685 } 2686 2687 ConSplitterGetIntersection ( 2688 StdErrModeMap, 2689 StdErrMapTable, 2690 mStdErr.TextOutListCount, 2691 1, 2692 &(mStdErr.TextOutMode.MaxMode), 2693 &(mStdErr.TextOutMode.Mode) 2694 ); 2695 2696 if (mStdErr.TextOutMode.Mode < 0) { 2697 mStdErr.TextOut.SetMode (&(mStdErr.TextOut), 0); 2698 } 2699 2700 FreePool (ConOutMapTable); 2701 FreePool (StdErrMapTable); 2702 2703 return EFI_SUCCESS; 2704 } 2705 2706 2707 /** 2708 Add Grahpics Output modes into Consplitter Text Out list. 2709 2710 @param Private Text Out Splitter pointer. 2711 @param GraphicsOutput Graphics Output protocol pointer. 2712 @param UgaDraw UGA Draw protocol pointer. 2713 2714 @retval EFI_SUCCESS Output mode added successfully. 2715 @retval other Failed to add output mode. 2716 2717 **/ 2718 EFI_STATUS 2719 ConSplitterAddGraphicsOutputMode ( 2720 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, 2721 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput, 2722 IN EFI_UGA_DRAW_PROTOCOL *UgaDraw 2723 ) 2724 { 2725 EFI_STATUS Status; 2726 UINTN Index; 2727 UINTN CurrentIndex; 2728 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Mode; 2729 UINTN SizeOfInfo; 2730 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; 2731 EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *CurrentGraphicsOutputMode; 2732 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeBuffer; 2733 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *MatchedMode; 2734 UINTN NumberIndex; 2735 BOOLEAN Match; 2736 BOOLEAN AlreadyExist; 2737 UINT32 UgaHorizontalResolution; 2738 UINT32 UgaVerticalResolution; 2739 UINT32 UgaColorDepth; 2740 UINT32 UgaRefreshRate; 2741 2742 ASSERT (GraphicsOutput != NULL || UgaDraw != NULL); 2743 2744 CurrentGraphicsOutputMode = Private->GraphicsOutput.Mode; 2745 2746 Index = 0; 2747 CurrentIndex = 0; 2748 Status = EFI_SUCCESS; 2749 2750 if (Private->CurrentNumberOfUgaDraw != 0) { 2751 // 2752 // If any UGA device has already been added, then there is no need to 2753 // calculate intersection of display mode of different GOP/UGA device, 2754 // since only one display mode will be exported (i.e. user-defined mode) 2755 // 2756 goto Done; 2757 } 2758 2759 if (GraphicsOutput != NULL) { 2760 if (Private->CurrentNumberOfGraphicsOutput == 0) { 2761 // 2762 // This is the first Graphics Output device added 2763 // 2764 CurrentGraphicsOutputMode->MaxMode = GraphicsOutput->Mode->MaxMode; 2765 CurrentGraphicsOutputMode->Mode = GraphicsOutput->Mode->Mode; 2766 CopyMem (CurrentGraphicsOutputMode->Info, GraphicsOutput->Mode->Info, GraphicsOutput->Mode->SizeOfInfo); 2767 CurrentGraphicsOutputMode->SizeOfInfo = GraphicsOutput->Mode->SizeOfInfo; 2768 CurrentGraphicsOutputMode->FrameBufferBase = GraphicsOutput->Mode->FrameBufferBase; 2769 CurrentGraphicsOutputMode->FrameBufferSize = GraphicsOutput->Mode->FrameBufferSize; 2770 2771 // 2772 // Allocate resource for the private mode buffer 2773 // 2774 ModeBuffer = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * GraphicsOutput->Mode->MaxMode); 2775 if (ModeBuffer == NULL) { 2776 return EFI_OUT_OF_RESOURCES; 2777 } 2778 FreePool (Private->GraphicsOutputModeBuffer); 2779 Private->GraphicsOutputModeBuffer = ModeBuffer; 2780 2781 // 2782 // Store all supported display modes to the private mode buffer 2783 // 2784 Mode = ModeBuffer; 2785 for (Index = 0; Index < GraphicsOutput->Mode->MaxMode; Index++) { 2786 // 2787 // The Info buffer would be allocated by callee 2788 // 2789 Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) Index, &SizeOfInfo, &Info); 2790 if (EFI_ERROR (Status)) { 2791 return Status; 2792 } 2793 ASSERT ( SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); 2794 CopyMem (Mode, Info, SizeOfInfo); 2795 Mode++; 2796 FreePool (Info); 2797 } 2798 } else { 2799 // 2800 // Check intersection of display mode 2801 // 2802 ModeBuffer = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * CurrentGraphicsOutputMode->MaxMode); 2803 if (ModeBuffer == NULL) { 2804 return EFI_OUT_OF_RESOURCES; 2805 } 2806 2807 MatchedMode = ModeBuffer; 2808 Mode = &Private->GraphicsOutputModeBuffer[0]; 2809 for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) { 2810 Match = FALSE; 2811 2812 for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex++) { 2813 // 2814 // The Info buffer would be allocated by callee 2815 // 2816 Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info); 2817 if (EFI_ERROR (Status)) { 2818 return Status; 2819 } 2820 if ((Info->HorizontalResolution == Mode->HorizontalResolution) && 2821 (Info->VerticalResolution == Mode->VerticalResolution)) { 2822 // 2823 // If GOP device supports one mode in current mode buffer, 2824 // it will be added into matched mode buffer 2825 // 2826 Match = TRUE; 2827 FreePool (Info); 2828 break; 2829 } 2830 FreePool (Info); 2831 } 2832 2833 if (Match) { 2834 AlreadyExist = FALSE; 2835 2836 // 2837 // Check if GOP mode has been in the mode buffer, ModeBuffer = MatchedMode at begin. 2838 // 2839 for (Info = ModeBuffer; Info < MatchedMode; Info++) { 2840 if ((Info->HorizontalResolution == Mode->HorizontalResolution) && 2841 (Info->VerticalResolution == Mode->VerticalResolution)) { 2842 AlreadyExist = TRUE; 2843 break; 2844 } 2845 } 2846 2847 if (!AlreadyExist) { 2848 CopyMem (MatchedMode, Mode, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); 2849 2850 // 2851 // Physical frame buffer is no longer available, change PixelFormat to PixelBltOnly 2852 // 2853 MatchedMode->Version = 0; 2854 MatchedMode->PixelFormat = PixelBltOnly; 2855 ZeroMem (&MatchedMode->PixelInformation, sizeof (EFI_PIXEL_BITMASK)); 2856 2857 MatchedMode++; 2858 } 2859 } 2860 2861 Mode++; 2862 } 2863 2864 // 2865 // Drop the old mode buffer, assign it to a new one 2866 // 2867 FreePool (Private->GraphicsOutputModeBuffer); 2868 Private->GraphicsOutputModeBuffer = ModeBuffer; 2869 2870 // 2871 // Physical frame buffer is no longer available when there are more than one physical GOP devices 2872 // 2873 CurrentGraphicsOutputMode->MaxMode = (UINT32) (((UINTN) MatchedMode - (UINTN) ModeBuffer) / sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); 2874 CurrentGraphicsOutputMode->Info->PixelFormat = PixelBltOnly; 2875 ZeroMem (&CurrentGraphicsOutputMode->Info->PixelInformation, sizeof (EFI_PIXEL_BITMASK)); 2876 CurrentGraphicsOutputMode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); 2877 CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL; 2878 CurrentGraphicsOutputMode->FrameBufferSize = 0; 2879 } 2880 2881 // 2882 // Graphics console driver can ensure the same mode for all GOP devices 2883 // 2884 for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) { 2885 Mode = &Private->GraphicsOutputModeBuffer[Index]; 2886 if ((Mode->HorizontalResolution == GraphicsOutput->Mode->Info->HorizontalResolution) && 2887 (Mode->VerticalResolution == GraphicsOutput->Mode->Info->VerticalResolution)) { 2888 CurrentIndex = Index; 2889 break; 2890 } 2891 } 2892 if (Index >= CurrentGraphicsOutputMode->MaxMode) { 2893 // 2894 // if user defined mode is not found, set to default mode 800x600 2895 // 2896 for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) { 2897 Mode = &Private->GraphicsOutputModeBuffer[Index]; 2898 if ((Mode->HorizontalResolution == 800) && (Mode->VerticalResolution == 600)) { 2899 CurrentIndex = Index; 2900 break; 2901 } 2902 } 2903 } 2904 } else if (UgaDraw != NULL) { 2905 // 2906 // Graphics console driver can ensure the same mode for all GOP devices 2907 // so we can get the current mode from this video device 2908 // 2909 UgaDraw->GetMode ( 2910 UgaDraw, 2911 &UgaHorizontalResolution, 2912 &UgaVerticalResolution, 2913 &UgaColorDepth, 2914 &UgaRefreshRate 2915 ); 2916 2917 CurrentGraphicsOutputMode->MaxMode = 1; 2918 Info = CurrentGraphicsOutputMode->Info; 2919 Info->Version = 0; 2920 Info->HorizontalResolution = UgaHorizontalResolution; 2921 Info->VerticalResolution = UgaVerticalResolution; 2922 Info->PixelFormat = PixelBltOnly; 2923 Info->PixelsPerScanLine = UgaHorizontalResolution; 2924 CurrentGraphicsOutputMode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); 2925 CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL; 2926 CurrentGraphicsOutputMode->FrameBufferSize = 0; 2927 2928 // 2929 // Update the private mode buffer 2930 // 2931 CopyMem (&Private->GraphicsOutputModeBuffer[0], Info, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); 2932 2933 // 2934 // Only mode 0 is available to be set 2935 // 2936 CurrentIndex = 0; 2937 } 2938 2939 Done: 2940 2941 if (GraphicsOutput != NULL) { 2942 Private->CurrentNumberOfGraphicsOutput++; 2943 } 2944 if (UgaDraw != NULL) { 2945 Private->CurrentNumberOfUgaDraw++; 2946 } 2947 2948 // 2949 // Force GraphicsOutput mode to be set, 2950 // 2951 2952 Mode = &Private->GraphicsOutputModeBuffer[CurrentIndex]; 2953 if ((GraphicsOutput != NULL) && 2954 (Mode->HorizontalResolution == CurrentGraphicsOutputMode->Info->HorizontalResolution) && 2955 (Mode->VerticalResolution == CurrentGraphicsOutputMode->Info->VerticalResolution)) { 2956 CurrentGraphicsOutputMode->Mode = (UINT32) CurrentIndex; 2957 if ((Mode->HorizontalResolution != GraphicsOutput->Mode->Info->HorizontalResolution) || 2958 (Mode->VerticalResolution != GraphicsOutput->Mode->Info->VerticalResolution)) { 2959 // 2960 // If all existing video device has been set to common mode, only set new GOP device to 2961 // the common mode 2962 // 2963 for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex ++) { 2964 Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info); 2965 if (EFI_ERROR (Status)) { 2966 return Status; 2967 } 2968 if ((Info->HorizontalResolution == Mode->HorizontalResolution) && (Info->VerticalResolution == Mode->VerticalResolution)) { 2969 FreePool (Info); 2970 break; 2971 } 2972 FreePool (Info); 2973 } 2974 Status = GraphicsOutput->SetMode (GraphicsOutput, (UINT32) NumberIndex); 2975 } 2976 } else { 2977 // 2978 // Current mode number may need update now, so set it to an invalid mode number 2979 // 2980 CurrentGraphicsOutputMode->Mode = 0xffff; 2981 // 2982 // Graphics console can ensure all GOP devices have the same mode which can be taken as current mode. 2983 // 2984 Status = Private->GraphicsOutput.SetMode (&Private->GraphicsOutput, (UINT32) CurrentIndex); 2985 if (EFI_ERROR(Status)) { 2986 // 2987 // If user defined mode is not valid for display device, set to the default mode 800x600. 2988 // 2989 (Private->GraphicsOutputModeBuffer[0]).HorizontalResolution = 800; 2990 (Private->GraphicsOutputModeBuffer[0]).VerticalResolution = 600; 2991 Status = Private->GraphicsOutput.SetMode (&Private->GraphicsOutput, 0); 2992 } 2993 } 2994 2995 return Status; 2996 } 2997 2998 /** 2999 Set the current console out mode. 3000 3001 This routine will get the current console mode information (column, row) 3002 from ConsoleOutMode variable and set it; if the variable does not exist, 3003 set to user defined console mode. 3004 3005 @param Private Consplitter Text Out pointer. 3006 3007 **/ 3008 VOID 3009 ConsplitterSetConsoleOutMode ( 3010 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private 3011 ) 3012 { 3013 UINTN Col; 3014 UINTN Row; 3015 UINTN Mode; 3016 UINTN PreferMode; 3017 UINTN BaseMode; 3018 UINTN MaxMode; 3019 EFI_STATUS Status; 3020 CONSOLE_OUT_MODE ModeInfo; 3021 CONSOLE_OUT_MODE MaxModeInfo; 3022 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; 3023 3024 PreferMode = 0xFF; 3025 BaseMode = 0xFF; 3026 TextOut = &Private->TextOut; 3027 MaxMode = (UINTN) (TextOut->Mode->MaxMode); 3028 3029 MaxModeInfo.Column = 0; 3030 MaxModeInfo.Row = 0; 3031 ModeInfo.Column = PcdGet32 (PcdConOutColumn); 3032 ModeInfo.Row = PcdGet32 (PcdConOutRow); 3033 3034 // 3035 // To find the prefer mode and basic mode from Text Out mode list 3036 // 3037 for (Mode = 0; Mode < MaxMode; Mode++) { 3038 Status = TextOut->QueryMode (TextOut, Mode, &Col, &Row); 3039 if (!EFI_ERROR(Status)) { 3040 if ((ModeInfo.Column != 0) && (ModeInfo.Row != 0)) { 3041 // 3042 // Use user defined column and row 3043 // 3044 if (Col == ModeInfo.Column && Row == ModeInfo.Row) { 3045 PreferMode = Mode; 3046 } 3047 } else { 3048 // 3049 // If user sets PcdConOutColumn or PcdConOutRow to 0, 3050 // find and set the highest text mode. 3051 // 3052 if ((Col >= MaxModeInfo.Column) && (Row >= MaxModeInfo.Row)) { 3053 MaxModeInfo.Column = Col; 3054 MaxModeInfo.Row = Row; 3055 PreferMode = Mode; 3056 } 3057 } 3058 if (Col == 80 && Row == 25) { 3059 BaseMode = Mode; 3060 } 3061 } 3062 } 3063 3064 // 3065 // Set prefer mode to Text Out devices. 3066 // 3067 Status = TextOut->SetMode (TextOut, PreferMode); 3068 if (EFI_ERROR(Status)) { 3069 // 3070 // if current mode setting is failed, default 80x25 mode will be set. 3071 // 3072 Status = TextOut->SetMode (TextOut, BaseMode); 3073 ASSERT(!EFI_ERROR(Status)); 3074 3075 Status = PcdSet32S (PcdConOutColumn, 80); 3076 ASSERT(!EFI_ERROR(Status)); 3077 Status = PcdSet32S (PcdConOutRow, 25); 3078 ASSERT(!EFI_ERROR(Status)); 3079 } 3080 3081 return ; 3082 } 3083 3084 3085 /** 3086 Add Text Output Device in Consplitter Text Output list. 3087 3088 @param Private Text Out Splitter pointer. 3089 @param TextOut Simple Text Output protocol pointer. 3090 @param GraphicsOutput Graphics Output protocol pointer. 3091 @param UgaDraw UGA Draw protocol pointer. 3092 3093 @retval EFI_SUCCESS Text Output Device added successfully. 3094 @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. 3095 3096 **/ 3097 EFI_STATUS 3098 ConSplitterTextOutAddDevice ( 3099 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, 3100 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut, 3101 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput, 3102 IN EFI_UGA_DRAW_PROTOCOL *UgaDraw 3103 ) 3104 { 3105 EFI_STATUS Status; 3106 UINTN CurrentNumOfConsoles; 3107 INT32 MaxMode; 3108 UINT32 UgaHorizontalResolution; 3109 UINT32 UgaVerticalResolution; 3110 UINT32 UgaColorDepth; 3111 UINT32 UgaRefreshRate; 3112 TEXT_OUT_AND_GOP_DATA *TextAndGop; 3113 UINTN SizeOfInfo; 3114 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; 3115 EFI_STATUS DeviceStatus; 3116 3117 Status = EFI_SUCCESS; 3118 CurrentNumOfConsoles = Private->CurrentNumberOfConsoles; 3119 3120 // 3121 // If the Text Out List is full, enlarge it by calling ConSplitterGrowBuffer(). 3122 // 3123 while (CurrentNumOfConsoles >= Private->TextOutListCount) { 3124 Status = ConSplitterGrowBuffer ( 3125 sizeof (TEXT_OUT_AND_GOP_DATA), 3126 &Private->TextOutListCount, 3127 (VOID **) &Private->TextOutList 3128 ); 3129 if (EFI_ERROR (Status)) { 3130 return EFI_OUT_OF_RESOURCES; 3131 } 3132 // 3133 // Also need to reallocate the TextOutModeMap table 3134 // 3135 Status = ConSplitterGrowMapTable (Private); 3136 if (EFI_ERROR (Status)) { 3137 return EFI_OUT_OF_RESOURCES; 3138 } 3139 } 3140 3141 TextAndGop = &Private->TextOutList[CurrentNumOfConsoles]; 3142 3143 TextAndGop->TextOut = TextOut; 3144 TextAndGop->GraphicsOutput = GraphicsOutput; 3145 TextAndGop->UgaDraw = UgaDraw; 3146 3147 if (CurrentNumOfConsoles == 0) { 3148 // 3149 // Add the first device's output mode to console splitter's mode list 3150 // 3151 Status = ConSplitterAddOutputMode (Private, TextOut); 3152 } else { 3153 ConSplitterSyncOutputMode (Private, TextOut); 3154 } 3155 3156 Private->CurrentNumberOfConsoles++; 3157 3158 // 3159 // Scan both TextOutList, for the intersection TextOut device 3160 // maybe both ConOut and StdErr incorporate the same Text Out 3161 // device in them, thus the output of both should be synced. 3162 // 3163 ConSplitterGetIntersectionBetweenConOutAndStrErr (); 3164 3165 MaxMode = Private->TextOutMode.MaxMode; 3166 ASSERT (MaxMode >= 1); 3167 3168 DeviceStatus = EFI_DEVICE_ERROR; 3169 Status = EFI_DEVICE_ERROR; 3170 3171 // 3172 // This device display mode will be added into Graphics Ouput modes. 3173 // 3174 if ((GraphicsOutput != NULL) || (UgaDraw != NULL)) { 3175 DeviceStatus = ConSplitterAddGraphicsOutputMode (Private, GraphicsOutput, UgaDraw); 3176 } 3177 3178 if (FeaturePcdGet (PcdConOutUgaSupport)) { 3179 // 3180 // If UGA is produced by Consplitter 3181 // 3182 if (GraphicsOutput != NULL) { 3183 Status = GraphicsOutput->QueryMode (GraphicsOutput, GraphicsOutput->Mode->Mode, &SizeOfInfo, &Info); 3184 if (EFI_ERROR (Status)) { 3185 return Status; 3186 } 3187 ASSERT ( SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); 3188 3189 UgaHorizontalResolution = Info->HorizontalResolution; 3190 UgaVerticalResolution = Info->VerticalResolution; 3191 3192 FreePool (Info); 3193 3194 } else if (UgaDraw != NULL) { 3195 Status = UgaDraw->GetMode ( 3196 UgaDraw, 3197 &UgaHorizontalResolution, 3198 &UgaVerticalResolution, 3199 &UgaColorDepth, 3200 &UgaRefreshRate 3201 ); 3202 if (!EFI_ERROR (Status) && EFI_ERROR (DeviceStatus)) { 3203 // 3204 // if GetMode is successfully and UGA device hasn't been set, set it 3205 // 3206 Status = ConSplitterUgaDrawSetMode ( 3207 &Private->UgaDraw, 3208 UgaHorizontalResolution, 3209 UgaVerticalResolution, 3210 UgaColorDepth, 3211 UgaRefreshRate 3212 ); 3213 } 3214 // 3215 // If GetMode/SetMode is failed, set to 800x600 mode 3216 // 3217 if(EFI_ERROR (Status)) { 3218 Status = ConSplitterUgaDrawSetMode ( 3219 &Private->UgaDraw, 3220 800, 3221 600, 3222 32, 3223 60 3224 ); 3225 } 3226 } 3227 } 3228 3229 if (((!EFI_ERROR (DeviceStatus)) || (!EFI_ERROR (Status))) && 3230 ((Private->CurrentNumberOfGraphicsOutput + Private->CurrentNumberOfUgaDraw) == 1)) { 3231 if (!FeaturePcdGet (PcdConOutGopSupport)) { 3232 // 3233 // If Graphics Outpurt protocol not supported, UGA Draw protocol is installed 3234 // on the virtual handle. 3235 // 3236 Status = gBS->InstallMultipleProtocolInterfaces ( 3237 &mConOut.VirtualHandle, 3238 &gEfiUgaDrawProtocolGuid, 3239 &mConOut.UgaDraw, 3240 NULL 3241 ); 3242 } else if (!FeaturePcdGet (PcdConOutUgaSupport)) { 3243 // 3244 // If UGA Draw protocol not supported, Graphics Output Protocol is installed 3245 // on virtual handle. 3246 // 3247 Status = gBS->InstallMultipleProtocolInterfaces ( 3248 &mConOut.VirtualHandle, 3249 &gEfiGraphicsOutputProtocolGuid, 3250 &mConOut.GraphicsOutput, 3251 NULL 3252 ); 3253 } else { 3254 // 3255 // Boot Graphics Output protocol and UGA Draw protocol are supported, 3256 // both they will be installed on virtual handle. 3257 // 3258 Status = gBS->InstallMultipleProtocolInterfaces ( 3259 &mConOut.VirtualHandle, 3260 &gEfiGraphicsOutputProtocolGuid, 3261 &mConOut.GraphicsOutput, 3262 &gEfiUgaDrawProtocolGuid, 3263 &mConOut.UgaDraw, 3264 NULL 3265 ); 3266 } 3267 } 3268 3269 // 3270 // After adding new console device, all existing console devices should be 3271 // synced to the current shared mode. 3272 // 3273 ConsplitterSetConsoleOutMode (Private); 3274 3275 return Status; 3276 } 3277 3278 3279 /** 3280 Remove Text Out Device in Consplitter Text Out list. 3281 3282 @param Private Text Out Splitter pointer. 3283 @param TextOut Simple Text Output Pointer protocol pointer. 3284 3285 @retval EFI_SUCCESS Text Out Device removed successfully. 3286 @retval EFI_NOT_FOUND No Text Out Device found. 3287 3288 **/ 3289 EFI_STATUS 3290 ConSplitterTextOutDeleteDevice ( 3291 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, 3292 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut 3293 ) 3294 { 3295 INT32 Index; 3296 UINTN CurrentNumOfConsoles; 3297 TEXT_OUT_AND_GOP_DATA *TextOutList; 3298 EFI_STATUS Status; 3299 3300 // 3301 // Remove the specified text-out device data structure from the Text out List, 3302 // and rearrange the remaining data structures in the Text out List. 3303 // 3304 CurrentNumOfConsoles = Private->CurrentNumberOfConsoles; 3305 Index = (INT32) CurrentNumOfConsoles - 1; 3306 TextOutList = Private->TextOutList; 3307 while (Index >= 0) { 3308 if (TextOutList->TextOut == TextOut) { 3309 if (TextOutList->UgaDraw != NULL) { 3310 Private->CurrentNumberOfUgaDraw--; 3311 } 3312 if (TextOutList->GraphicsOutput != NULL) { 3313 Private->CurrentNumberOfGraphicsOutput--; 3314 } 3315 CopyMem (TextOutList, TextOutList + 1, sizeof (TEXT_OUT_AND_GOP_DATA) * Index); 3316 CurrentNumOfConsoles--; 3317 break; 3318 } 3319 3320 Index--; 3321 TextOutList++; 3322 } 3323 // 3324 // The specified TextOut is not managed by the ConSplitter driver 3325 // 3326 if (Index < 0) { 3327 return EFI_NOT_FOUND; 3328 } 3329 3330 if ((Private->CurrentNumberOfGraphicsOutput == 0) && (Private->CurrentNumberOfUgaDraw == 0)) { 3331 // 3332 // If there is not any physical GOP and UGA device in system, 3333 // Consplitter GOP or UGA protocol will be uninstalled 3334 // 3335 if (!FeaturePcdGet (PcdConOutGopSupport)) { 3336 Status = gBS->UninstallProtocolInterface ( 3337 Private->VirtualHandle, 3338 &gEfiUgaDrawProtocolGuid, 3339 &Private->UgaDraw 3340 ); 3341 } else if (!FeaturePcdGet (PcdConOutUgaSupport)) { 3342 Status = gBS->UninstallProtocolInterface ( 3343 Private->VirtualHandle, 3344 &gEfiGraphicsOutputProtocolGuid, 3345 &Private->GraphicsOutput 3346 ); 3347 } else { 3348 Status = gBS->UninstallMultipleProtocolInterfaces ( 3349 Private->VirtualHandle, 3350 &gEfiUgaDrawProtocolGuid, 3351 &Private->UgaDraw, 3352 &gEfiGraphicsOutputProtocolGuid, 3353 &Private->GraphicsOutput, 3354 NULL 3355 ); 3356 } 3357 } 3358 3359 if (CurrentNumOfConsoles == 0) { 3360 // 3361 // If the number of consoles is zero, reset all parameters 3362 // 3363 Private->CurrentNumberOfConsoles = 0; 3364 Private->TextOutMode.MaxMode = 1; 3365 Private->TextOutQueryData[0].Columns = 80; 3366 Private->TextOutQueryData[0].Rows = 25; 3367 TextOutSetMode (Private, 0); 3368 3369 return EFI_SUCCESS; 3370 } 3371 // 3372 // Max Mode is realy an intersection of the QueryMode command to all 3373 // devices. So we must copy the QueryMode of the first device to 3374 // QueryData. 3375 // 3376 ZeroMem ( 3377 Private->TextOutQueryData, 3378 Private->TextOutQueryDataCount * sizeof (TEXT_OUT_SPLITTER_QUERY_DATA) 3379 ); 3380 3381 FreePool (Private->TextOutModeMap); 3382 Private->TextOutModeMap = NULL; 3383 TextOutList = Private->TextOutList; 3384 3385 // 3386 // Add the first TextOut to the QueryData array and ModeMap table 3387 // 3388 Status = ConSplitterAddOutputMode (Private, TextOutList->TextOut); 3389 3390 // 3391 // Now add one by one 3392 // 3393 Index = 1; 3394 Private->CurrentNumberOfConsoles = 1; 3395 TextOutList++; 3396 while ((UINTN) Index < CurrentNumOfConsoles) { 3397 ConSplitterSyncOutputMode (Private, TextOutList->TextOut); 3398 Index++; 3399 Private->CurrentNumberOfConsoles++; 3400 TextOutList++; 3401 } 3402 3403 ConSplitterGetIntersectionBetweenConOutAndStrErr (); 3404 3405 return Status; 3406 } 3407 3408 3409 /** 3410 Reset the input device and optionaly run diagnostics 3411 3412 @param This Protocol instance pointer. 3413 @param ExtendedVerification Driver may perform diagnostics on reset. 3414 3415 @retval EFI_SUCCESS The device was reset. 3416 @retval EFI_DEVICE_ERROR The device is not functioning properly and could 3417 not be reset. 3418 3419 **/ 3420 EFI_STATUS 3421 EFIAPI 3422 ConSplitterTextInReset ( 3423 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, 3424 IN BOOLEAN ExtendedVerification 3425 ) 3426 { 3427 EFI_STATUS Status; 3428 EFI_STATUS ReturnStatus; 3429 TEXT_IN_SPLITTER_PRIVATE_DATA *Private; 3430 UINTN Index; 3431 3432 Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This); 3433 3434 Private->KeyEventSignalState = FALSE; 3435 3436 // 3437 // return the worst status met 3438 // 3439 for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { 3440 Status = Private->TextInList[Index]->Reset ( 3441 Private->TextInList[Index], 3442 ExtendedVerification 3443 ); 3444 if (EFI_ERROR (Status)) { 3445 ReturnStatus = Status; 3446 } 3447 } 3448 3449 if (!EFI_ERROR (ReturnStatus)) { 3450 ToggleStateSyncReInitialization (Private); 3451 } 3452 3453 return ReturnStatus; 3454 } 3455 3456 3457 /** 3458 Reads the next keystroke from the input device. The WaitForKey Event can 3459 be used to test for existance of a keystroke via WaitForEvent () call. 3460 3461 @param Private Protocol instance pointer. 3462 @param Key Driver may perform diagnostics on reset. 3463 3464 @retval EFI_SUCCESS The keystroke information was returned. 3465 @retval EFI_NOT_READY There was no keystroke data availiable. 3466 @retval EFI_DEVICE_ERROR The keydtroke information was not returned due 3467 to hardware errors. 3468 3469 **/ 3470 EFI_STATUS 3471 EFIAPI 3472 ConSplitterTextInPrivateReadKeyStroke ( 3473 IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, 3474 OUT EFI_INPUT_KEY *Key 3475 ) 3476 { 3477 EFI_STATUS Status; 3478 UINTN Index; 3479 EFI_INPUT_KEY CurrentKey; 3480 3481 Key->UnicodeChar = 0; 3482 Key->ScanCode = SCAN_NULL; 3483 3484 // 3485 // if no physical console input device exists, return EFI_NOT_READY; 3486 // if any physical console input device has key input, 3487 // return the key and EFI_SUCCESS. 3488 // 3489 for (Index = 0; Index < Private->CurrentNumberOfConsoles;) { 3490 Status = Private->TextInList[Index]->ReadKeyStroke ( 3491 Private->TextInList[Index], 3492 &CurrentKey 3493 ); 3494 if (!EFI_ERROR (Status)) { 3495 // 3496 // If it is not partial keystorke, return the key. Otherwise, continue 3497 // to read key from THIS physical console input device. 3498 // 3499 if ((CurrentKey.ScanCode != CHAR_NULL) || (CurrentKey.UnicodeChar != SCAN_NULL)) { 3500 *Key = CurrentKey; 3501 return Status; 3502 } 3503 } else { 3504 // 3505 // Continue to read key from NEXT physical console input device. 3506 // 3507 Index++; 3508 } 3509 } 3510 3511 return EFI_NOT_READY; 3512 } 3513 3514 3515 3516 /** 3517 Reads the next keystroke from the input device. The WaitForKey Event can 3518 be used to test for existance of a keystroke via WaitForEvent () call. 3519 3520 @param This Protocol instance pointer. 3521 @param Key Driver may perform diagnostics on reset. 3522 3523 @retval EFI_SUCCESS The keystroke information was returned. 3524 @retval EFI_NOT_READY There was no keystroke data availiable. 3525 @retval EFI_DEVICE_ERROR The keydtroke information was not returned due 3526 to hardware errors. 3527 3528 **/ 3529 EFI_STATUS 3530 EFIAPI 3531 ConSplitterTextInReadKeyStroke ( 3532 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, 3533 OUT EFI_INPUT_KEY *Key 3534 ) 3535 { 3536 TEXT_IN_SPLITTER_PRIVATE_DATA *Private; 3537 3538 Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This); 3539 3540 Private->KeyEventSignalState = FALSE; 3541 3542 // 3543 // Signal ConnectConIn event on first call in Lazy ConIn mode 3544 // 3545 if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) { 3546 DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n")); 3547 gBS->SignalEvent (Private->ConnectConInEvent); 3548 mConInIsConnect = TRUE; 3549 } 3550 3551 return ConSplitterTextInPrivateReadKeyStroke (Private, Key); 3552 } 3553 3554 3555 /** 3556 This event aggregates all the events of the ConIn devices in the spliter. 3557 3558 If any events of physical ConIn devices are signaled, signal the ConIn 3559 spliter event. This will cause the calling code to call 3560 ConSplitterTextInReadKeyStroke (). 3561 3562 @param Event The Event assoicated with callback. 3563 @param Context Context registered when Event was created. 3564 3565 **/ 3566 VOID 3567 EFIAPI 3568 ConSplitterTextInWaitForKey ( 3569 IN EFI_EVENT Event, 3570 IN VOID *Context 3571 ) 3572 { 3573 EFI_STATUS Status; 3574 TEXT_IN_SPLITTER_PRIVATE_DATA *Private; 3575 UINTN Index; 3576 3577 Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context; 3578 3579 if (Private->KeyEventSignalState) { 3580 // 3581 // If KeyEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke() 3582 // 3583 gBS->SignalEvent (Event); 3584 return ; 3585 } 3586 3587 // 3588 // If any physical console input device has key input, signal the event. 3589 // 3590 for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) { 3591 Status = gBS->CheckEvent (Private->TextInList[Index]->WaitForKey); 3592 if (!EFI_ERROR (Status)) { 3593 gBS->SignalEvent (Event); 3594 Private->KeyEventSignalState = TRUE; 3595 } 3596 } 3597 } 3598 3599 3600 3601 /** 3602 Test if the key has been registered on input device. 3603 3604 @param RegsiteredData A pointer to a buffer that is filled in with the 3605 keystroke state data for the key that was 3606 registered. 3607 @param InputData A pointer to a buffer that is filled in with the 3608 keystroke state data for the key that was 3609 pressed. 3610 3611 @retval TRUE Key be pressed matches a registered key. 3612 @retval FLASE Match failed. 3613 3614 **/ 3615 BOOLEAN 3616 IsKeyRegistered ( 3617 IN EFI_KEY_DATA *RegsiteredData, 3618 IN EFI_KEY_DATA *InputData 3619 ) 3620 { 3621 ASSERT (RegsiteredData != NULL && InputData != NULL); 3622 3623 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) || 3624 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) { 3625 return FALSE; 3626 } 3627 3628 // 3629 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored. 3630 // 3631 if (RegsiteredData->KeyState.KeyShiftState != 0 && 3632 RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) { 3633 return FALSE; 3634 } 3635 if (RegsiteredData->KeyState.KeyToggleState != 0 && 3636 RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) { 3637 return FALSE; 3638 } 3639 3640 return TRUE; 3641 3642 } 3643 3644 3645 /** 3646 Reset the input device and optionaly run diagnostics 3647 3648 @param This Protocol instance pointer. 3649 @param ExtendedVerification Driver may perform diagnostics on reset. 3650 3651 @retval EFI_SUCCESS The device was reset. 3652 @retval EFI_DEVICE_ERROR The device is not functioning properly and could 3653 not be reset. 3654 3655 **/ 3656 EFI_STATUS 3657 EFIAPI 3658 ConSplitterTextInResetEx ( 3659 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 3660 IN BOOLEAN ExtendedVerification 3661 ) 3662 { 3663 EFI_STATUS Status; 3664 EFI_STATUS ReturnStatus; 3665 TEXT_IN_SPLITTER_PRIVATE_DATA *Private; 3666 UINTN Index; 3667 3668 Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); 3669 3670 Private->KeyEventSignalState = FALSE; 3671 3672 // 3673 // return the worst status met 3674 // 3675 for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfExConsoles; Index++) { 3676 Status = Private->TextInExList[Index]->Reset ( 3677 Private->TextInExList[Index], 3678 ExtendedVerification 3679 ); 3680 if (EFI_ERROR (Status)) { 3681 ReturnStatus = Status; 3682 } 3683 } 3684 3685 if (!EFI_ERROR (ReturnStatus)) { 3686 ToggleStateSyncReInitialization (Private); 3687 } 3688 3689 return ReturnStatus; 3690 3691 } 3692 3693 3694 /** 3695 Reads the next keystroke from the input device. The WaitForKey Event can 3696 be used to test for existance of a keystroke via WaitForEvent () call. 3697 3698 @param This Protocol instance pointer. 3699 @param KeyData A pointer to a buffer that is filled in with the 3700 keystroke state data for the key that was 3701 pressed. 3702 3703 @retval EFI_SUCCESS The keystroke information was returned. 3704 @retval EFI_NOT_READY There was no keystroke data availiable. 3705 @retval EFI_DEVICE_ERROR The keystroke information was not returned due 3706 to hardware errors. 3707 @retval EFI_INVALID_PARAMETER KeyData is NULL. 3708 3709 **/ 3710 EFI_STATUS 3711 EFIAPI 3712 ConSplitterTextInReadKeyStrokeEx ( 3713 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 3714 OUT EFI_KEY_DATA *KeyData 3715 ) 3716 { 3717 TEXT_IN_SPLITTER_PRIVATE_DATA *Private; 3718 EFI_STATUS Status; 3719 UINTN Index; 3720 EFI_KEY_DATA CurrentKeyData; 3721 3722 3723 if (KeyData == NULL) { 3724 return EFI_INVALID_PARAMETER; 3725 } 3726 3727 Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); 3728 3729 Private->KeyEventSignalState = FALSE; 3730 3731 KeyData->Key.UnicodeChar = 0; 3732 KeyData->Key.ScanCode = SCAN_NULL; 3733 3734 // 3735 // Signal ConnectConIn event on first call in Lazy ConIn mode 3736 // 3737 if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) { 3738 DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n")); 3739 gBS->SignalEvent (Private->ConnectConInEvent); 3740 mConInIsConnect = TRUE; 3741 } 3742 3743 // 3744 // if no physical console input device exists, return EFI_NOT_READY; 3745 // if any physical console input device has key input, 3746 // return the key and EFI_SUCCESS. 3747 // 3748 for (Index = 0; Index < Private->CurrentNumberOfExConsoles;) { 3749 Status = Private->TextInExList[Index]->ReadKeyStrokeEx ( 3750 Private->TextInExList[Index], 3751 &CurrentKeyData 3752 ); 3753 if (!EFI_ERROR (Status)) { 3754 // 3755 // If virtual KeyState has been required to be exposed, or it is not 3756 // partial keystorke, return the key. Otherwise, continue to read key 3757 // from THIS physical console input device. 3758 // 3759 if ((Private->VirtualKeyStateExported) || 3760 (CurrentKeyData.Key.ScanCode != CHAR_NULL) || 3761 (CurrentKeyData.Key.UnicodeChar != SCAN_NULL)) { 3762 CopyMem (KeyData, &CurrentKeyData, sizeof (CurrentKeyData)); 3763 return Status; 3764 } 3765 } else { 3766 // 3767 // Continue to read key from NEXT physical console input device. 3768 // 3769 Index++; 3770 } 3771 } 3772 3773 return EFI_NOT_READY; 3774 } 3775 3776 3777 /** 3778 Set certain state for the input device. 3779 3780 @param This Protocol instance pointer. 3781 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the 3782 state for the input device. 3783 3784 @retval EFI_SUCCESS The device state was set successfully. 3785 @retval EFI_DEVICE_ERROR The device is not functioning correctly and 3786 could not have the setting adjusted. 3787 @retval EFI_UNSUPPORTED The device does not have the ability to set its 3788 state. 3789 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL. 3790 3791 **/ 3792 EFI_STATUS 3793 EFIAPI 3794 ConSplitterTextInSetState ( 3795 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 3796 IN EFI_KEY_TOGGLE_STATE *KeyToggleState 3797 ) 3798 { 3799 TEXT_IN_SPLITTER_PRIVATE_DATA *Private; 3800 EFI_STATUS Status; 3801 UINTN Index; 3802 EFI_KEY_TOGGLE_STATE PhysicalKeyToggleState; 3803 3804 if (KeyToggleState == NULL) { 3805 return EFI_INVALID_PARAMETER; 3806 } 3807 3808 Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); 3809 3810 // 3811 // Always turn on physical TextInEx partial key report for 3812 // toggle state sync. 3813 // 3814 PhysicalKeyToggleState = *KeyToggleState | EFI_KEY_STATE_EXPOSED; 3815 3816 // 3817 // if no physical console input device exists, return EFI_SUCCESS; 3818 // otherwise return the status of setting state of physical console input device 3819 // 3820 for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { 3821 Status = Private->TextInExList[Index]->SetState ( 3822 Private->TextInExList[Index], 3823 &PhysicalKeyToggleState 3824 ); 3825 if (EFI_ERROR (Status)) { 3826 return Status; 3827 } 3828 } 3829 3830 // 3831 // Record the physical KeyToggleState. 3832 // 3833 Private->PhysicalKeyToggleState = PhysicalKeyToggleState; 3834 // 3835 // Get if virtual KeyState has been required to be exposed. 3836 // 3837 Private->VirtualKeyStateExported = (((*KeyToggleState) & EFI_KEY_STATE_EXPOSED) != 0); 3838 3839 return EFI_SUCCESS; 3840 3841 } 3842 3843 3844 /** 3845 Register a notification function for a particular keystroke for the input device. 3846 3847 @param This Protocol instance pointer. 3848 @param KeyData A pointer to a buffer that is filled in with the 3849 keystroke information data for the key that was 3850 pressed. 3851 @param KeyNotificationFunction Points to the function to be called when the key 3852 sequence is typed specified by KeyData. 3853 @param NotifyHandle Points to the unique handle assigned to the 3854 registered notification. 3855 3856 @retval EFI_SUCCESS The notification function was registered 3857 successfully. 3858 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data 3859 structures. 3860 @retval EFI_INVALID_PARAMETER KeyData or KeyNotificationFunction or NotifyHandle is NULL. 3861 3862 **/ 3863 EFI_STATUS 3864 EFIAPI 3865 ConSplitterTextInRegisterKeyNotify ( 3866 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 3867 IN EFI_KEY_DATA *KeyData, 3868 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, 3869 OUT VOID **NotifyHandle 3870 ) 3871 { 3872 TEXT_IN_SPLITTER_PRIVATE_DATA *Private; 3873 EFI_STATUS Status; 3874 UINTN Index; 3875 TEXT_IN_EX_SPLITTER_NOTIFY *NewNotify; 3876 LIST_ENTRY *Link; 3877 TEXT_IN_EX_SPLITTER_NOTIFY *CurrentNotify; 3878 3879 3880 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) { 3881 return EFI_INVALID_PARAMETER; 3882 } 3883 3884 Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); 3885 3886 // 3887 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. 3888 // 3889 for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) { 3890 CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link); 3891 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { 3892 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { 3893 *NotifyHandle = CurrentNotify; 3894 return EFI_SUCCESS; 3895 } 3896 } 3897 } 3898 3899 // 3900 // Allocate resource to save the notification function 3901 // 3902 NewNotify = (TEXT_IN_EX_SPLITTER_NOTIFY *) AllocateZeroPool (sizeof (TEXT_IN_EX_SPLITTER_NOTIFY)); 3903 if (NewNotify == NULL) { 3904 return EFI_OUT_OF_RESOURCES; 3905 } 3906 NewNotify->NotifyHandleList = (EFI_HANDLE *) AllocateZeroPool (sizeof (EFI_HANDLE) * Private->TextInExListCount); 3907 if (NewNotify->NotifyHandleList == NULL) { 3908 gBS->FreePool (NewNotify); 3909 return EFI_OUT_OF_RESOURCES; 3910 } 3911 NewNotify->Signature = TEXT_IN_EX_SPLITTER_NOTIFY_SIGNATURE; 3912 NewNotify->KeyNotificationFn = KeyNotificationFunction; 3913 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA)); 3914 3915 // 3916 // Return the wrong status of registering key notify of 3917 // physical console input device if meet problems 3918 // 3919 for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { 3920 Status = Private->TextInExList[Index]->RegisterKeyNotify ( 3921 Private->TextInExList[Index], 3922 KeyData, 3923 KeyNotificationFunction, 3924 &NewNotify->NotifyHandleList[Index] 3925 ); 3926 if (EFI_ERROR (Status)) { 3927 // 3928 // Un-register the key notify on all physical console input devices 3929 // 3930 while (Index-- != 0) { 3931 Private->TextInExList[Index]->UnregisterKeyNotify ( 3932 Private->TextInExList[Index], 3933 NewNotify->NotifyHandleList[Index] 3934 ); 3935 } 3936 gBS->FreePool (NewNotify->NotifyHandleList); 3937 gBS->FreePool (NewNotify); 3938 return Status; 3939 } 3940 } 3941 3942 InsertTailList (&Private->NotifyList, &NewNotify->NotifyEntry); 3943 3944 *NotifyHandle = NewNotify; 3945 3946 return EFI_SUCCESS; 3947 3948 } 3949 3950 3951 /** 3952 Remove a registered notification function from a particular keystroke. 3953 3954 @param This Protocol instance pointer. 3955 @param NotificationHandle The handle of the notification function being 3956 unregistered. 3957 3958 @retval EFI_SUCCESS The notification function was unregistered 3959 successfully. 3960 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid. 3961 3962 **/ 3963 EFI_STATUS 3964 EFIAPI 3965 ConSplitterTextInUnregisterKeyNotify ( 3966 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 3967 IN VOID *NotificationHandle 3968 ) 3969 { 3970 TEXT_IN_SPLITTER_PRIVATE_DATA *Private; 3971 UINTN Index; 3972 TEXT_IN_EX_SPLITTER_NOTIFY *CurrentNotify; 3973 LIST_ENTRY *Link; 3974 3975 if (NotificationHandle == NULL) { 3976 return EFI_INVALID_PARAMETER; 3977 } 3978 3979 Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); 3980 3981 for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) { 3982 CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link); 3983 if (CurrentNotify == NotificationHandle) { 3984 for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { 3985 Private->TextInExList[Index]->UnregisterKeyNotify ( 3986 Private->TextInExList[Index], 3987 CurrentNotify->NotifyHandleList[Index] 3988 ); 3989 } 3990 RemoveEntryList (&CurrentNotify->NotifyEntry); 3991 3992 gBS->FreePool (CurrentNotify->NotifyHandleList); 3993 gBS->FreePool (CurrentNotify); 3994 return EFI_SUCCESS; 3995 } 3996 } 3997 3998 // 3999 // NotificationHandle is not found in database 4000 // 4001 return EFI_INVALID_PARAMETER; 4002 } 4003 4004 4005 /** 4006 Reset the input device and optionaly run diagnostics 4007 4008 @param This Protocol instance pointer. 4009 @param ExtendedVerification Driver may perform diagnostics on reset. 4010 4011 @retval EFI_SUCCESS The device was reset. 4012 @retval EFI_DEVICE_ERROR The device is not functioning properly and could 4013 not be reset. 4014 4015 **/ 4016 EFI_STATUS 4017 EFIAPI 4018 ConSplitterSimplePointerReset ( 4019 IN EFI_SIMPLE_POINTER_PROTOCOL *This, 4020 IN BOOLEAN ExtendedVerification 4021 ) 4022 { 4023 EFI_STATUS Status; 4024 EFI_STATUS ReturnStatus; 4025 TEXT_IN_SPLITTER_PRIVATE_DATA *Private; 4026 UINTN Index; 4027 4028 Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS (This); 4029 4030 Private->InputEventSignalState = FALSE; 4031 4032 if (Private->CurrentNumberOfPointers == 0) { 4033 return EFI_SUCCESS; 4034 } 4035 // 4036 // return the worst status met 4037 // 4038 for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfPointers; Index++) { 4039 Status = Private->PointerList[Index]->Reset ( 4040 Private->PointerList[Index], 4041 ExtendedVerification 4042 ); 4043 if (EFI_ERROR (Status)) { 4044 ReturnStatus = Status; 4045 } 4046 } 4047 4048 return ReturnStatus; 4049 } 4050 4051 4052 /** 4053 Reads the next keystroke from the input device. The WaitForKey Event can 4054 be used to test for existance of a keystroke via WaitForEvent () call. 4055 4056 @param Private Protocol instance pointer. 4057 @param State The state information of simple pointer device. 4058 4059 @retval EFI_SUCCESS The keystroke information was returned. 4060 @retval EFI_NOT_READY There was no keystroke data availiable. 4061 @retval EFI_DEVICE_ERROR The keydtroke information was not returned due 4062 to hardware errors. 4063 4064 **/ 4065 EFI_STATUS 4066 EFIAPI 4067 ConSplitterSimplePointerPrivateGetState ( 4068 IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, 4069 IN OUT EFI_SIMPLE_POINTER_STATE *State 4070 ) 4071 { 4072 EFI_STATUS Status; 4073 EFI_STATUS ReturnStatus; 4074 UINTN Index; 4075 EFI_SIMPLE_POINTER_STATE CurrentState; 4076 4077 State->RelativeMovementX = 0; 4078 State->RelativeMovementY = 0; 4079 State->RelativeMovementZ = 0; 4080 State->LeftButton = FALSE; 4081 State->RightButton = FALSE; 4082 4083 // 4084 // if no physical console input device exists, return EFI_NOT_READY; 4085 // if any physical console input device has key input, 4086 // return the key and EFI_SUCCESS. 4087 // 4088 ReturnStatus = EFI_NOT_READY; 4089 for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) { 4090 4091 Status = Private->PointerList[Index]->GetState ( 4092 Private->PointerList[Index], 4093 &CurrentState 4094 ); 4095 if (!EFI_ERROR (Status)) { 4096 if (ReturnStatus == EFI_NOT_READY) { 4097 ReturnStatus = EFI_SUCCESS; 4098 } 4099 4100 if (CurrentState.LeftButton) { 4101 State->LeftButton = TRUE; 4102 } 4103 4104 if (CurrentState.RightButton) { 4105 State->RightButton = TRUE; 4106 } 4107 4108 if (CurrentState.RelativeMovementX != 0 && Private->PointerList[Index]->Mode->ResolutionX != 0) { 4109 State->RelativeMovementX += (CurrentState.RelativeMovementX * (INT32) Private->SimplePointerMode.ResolutionX) / (INT32) Private->PointerList[Index]->Mode->ResolutionX; 4110 } 4111 4112 if (CurrentState.RelativeMovementY != 0 && Private->PointerList[Index]->Mode->ResolutionY != 0) { 4113 State->RelativeMovementY += (CurrentState.RelativeMovementY * (INT32) Private->SimplePointerMode.ResolutionY) / (INT32) Private->PointerList[Index]->Mode->ResolutionY; 4114 } 4115 4116 if (CurrentState.RelativeMovementZ != 0 && Private->PointerList[Index]->Mode->ResolutionZ != 0) { 4117 State->RelativeMovementZ += (CurrentState.RelativeMovementZ * (INT32) Private->SimplePointerMode.ResolutionZ) / (INT32) Private->PointerList[Index]->Mode->ResolutionZ; 4118 } 4119 } else if (Status == EFI_DEVICE_ERROR) { 4120 ReturnStatus = EFI_DEVICE_ERROR; 4121 } 4122 } 4123 4124 return ReturnStatus; 4125 } 4126 4127 4128 /** 4129 Reads the next keystroke from the input device. The WaitForKey Event can 4130 be used to test for existance of a keystroke via WaitForEvent () call. 4131 4132 @param This A pointer to protocol instance. 4133 @param State A pointer to state information on the pointer device 4134 4135 @retval EFI_SUCCESS The keystroke information was returned in State. 4136 @retval EFI_NOT_READY There was no keystroke data availiable. 4137 @retval EFI_DEVICE_ERROR The keydtroke information was not returned due 4138 to hardware errors. 4139 4140 **/ 4141 EFI_STATUS 4142 EFIAPI 4143 ConSplitterSimplePointerGetState ( 4144 IN EFI_SIMPLE_POINTER_PROTOCOL *This, 4145 IN OUT EFI_SIMPLE_POINTER_STATE *State 4146 ) 4147 { 4148 TEXT_IN_SPLITTER_PRIVATE_DATA *Private; 4149 4150 Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS (This); 4151 4152 Private->InputEventSignalState = FALSE; 4153 4154 return ConSplitterSimplePointerPrivateGetState (Private, State); 4155 } 4156 4157 4158 /** 4159 This event agregates all the events of the ConIn devices in the spliter. 4160 If any events of physical ConIn devices are signaled, signal the ConIn 4161 spliter event. This will cause the calling code to call 4162 ConSplitterTextInReadKeyStroke (). 4163 4164 @param Event The Event assoicated with callback. 4165 @param Context Context registered when Event was created. 4166 4167 **/ 4168 VOID 4169 EFIAPI 4170 ConSplitterSimplePointerWaitForInput ( 4171 IN EFI_EVENT Event, 4172 IN VOID *Context 4173 ) 4174 { 4175 EFI_STATUS Status; 4176 TEXT_IN_SPLITTER_PRIVATE_DATA *Private; 4177 UINTN Index; 4178 4179 Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context; 4180 4181 // 4182 // if InputEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke() 4183 // 4184 if (Private->InputEventSignalState) { 4185 gBS->SignalEvent (Event); 4186 return ; 4187 } 4188 // 4189 // if any physical console input device has key input, signal the event. 4190 // 4191 for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) { 4192 Status = gBS->CheckEvent (Private->PointerList[Index]->WaitForInput); 4193 if (!EFI_ERROR (Status)) { 4194 gBS->SignalEvent (Event); 4195 Private->InputEventSignalState = TRUE; 4196 } 4197 } 4198 } 4199 4200 /** 4201 Resets the pointer device hardware. 4202 4203 @param This Protocol instance pointer. 4204 @param ExtendedVerification Driver may perform diagnostics on reset. 4205 4206 @retval EFI_SUCCESS The device was reset. 4207 @retval EFI_DEVICE_ERROR The device is not functioning correctly and 4208 could not be reset. 4209 4210 **/ 4211 EFI_STATUS 4212 EFIAPI 4213 ConSplitterAbsolutePointerReset ( 4214 IN EFI_ABSOLUTE_POINTER_PROTOCOL *This, 4215 IN BOOLEAN ExtendedVerification 4216 ) 4217 { 4218 EFI_STATUS Status; 4219 EFI_STATUS ReturnStatus; 4220 TEXT_IN_SPLITTER_PRIVATE_DATA *Private; 4221 UINTN Index; 4222 4223 Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_ABSOLUTE_POINTER_THIS (This); 4224 4225 Private->AbsoluteInputEventSignalState = FALSE; 4226 4227 if (Private->CurrentNumberOfAbsolutePointers == 0) { 4228 return EFI_SUCCESS; 4229 } 4230 // 4231 // return the worst status met 4232 // 4233 for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfAbsolutePointers; Index++) { 4234 Status = Private->AbsolutePointerList[Index]->Reset ( 4235 Private->AbsolutePointerList[Index], 4236 ExtendedVerification 4237 ); 4238 if (EFI_ERROR (Status)) { 4239 ReturnStatus = Status; 4240 } 4241 } 4242 4243 return ReturnStatus; 4244 } 4245 4246 4247 /** 4248 Retrieves the current state of a pointer device. 4249 4250 @param This Protocol instance pointer. 4251 @param State A pointer to the state information on the 4252 pointer device. 4253 4254 @retval EFI_SUCCESS The state of the pointer device was returned in 4255 State.. 4256 @retval EFI_NOT_READY The state of the pointer device has not changed 4257 since the last call to GetState(). 4258 @retval EFI_DEVICE_ERROR A device error occurred while attempting to 4259 retrieve the pointer device's current state. 4260 4261 **/ 4262 EFI_STATUS 4263 EFIAPI 4264 ConSplitterAbsolutePointerGetState ( 4265 IN EFI_ABSOLUTE_POINTER_PROTOCOL *This, 4266 IN OUT EFI_ABSOLUTE_POINTER_STATE *State 4267 ) 4268 { 4269 TEXT_IN_SPLITTER_PRIVATE_DATA *Private; 4270 EFI_STATUS Status; 4271 EFI_STATUS ReturnStatus; 4272 UINTN Index; 4273 EFI_ABSOLUTE_POINTER_STATE CurrentState; 4274 UINT64 MinX; 4275 UINT64 MinY; 4276 UINT64 MinZ; 4277 UINT64 MaxX; 4278 UINT64 MaxY; 4279 UINT64 MaxZ; 4280 UINT64 VirtualMinX; 4281 UINT64 VirtualMinY; 4282 UINT64 VirtualMinZ; 4283 UINT64 VirtualMaxX; 4284 UINT64 VirtualMaxY; 4285 UINT64 VirtualMaxZ; 4286 4287 Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_ABSOLUTE_POINTER_THIS (This); 4288 4289 Private->AbsoluteInputEventSignalState = FALSE; 4290 4291 State->CurrentX = 0; 4292 State->CurrentY = 0; 4293 State->CurrentZ = 0; 4294 State->ActiveButtons = 0; 4295 4296 VirtualMinX = Private->AbsolutePointerMode.AbsoluteMinX; 4297 VirtualMinY = Private->AbsolutePointerMode.AbsoluteMinY; 4298 VirtualMinZ = Private->AbsolutePointerMode.AbsoluteMinZ; 4299 VirtualMaxX = Private->AbsolutePointerMode.AbsoluteMaxX; 4300 VirtualMaxY = Private->AbsolutePointerMode.AbsoluteMaxY; 4301 VirtualMaxZ = Private->AbsolutePointerMode.AbsoluteMaxZ; 4302 4303 // 4304 // if no physical pointer device exists, return EFI_NOT_READY; 4305 // if any physical pointer device has changed state, 4306 // return the state and EFI_SUCCESS. 4307 // 4308 ReturnStatus = EFI_NOT_READY; 4309 for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) { 4310 4311 Status = Private->AbsolutePointerList[Index]->GetState ( 4312 Private->AbsolutePointerList[Index], 4313 &CurrentState 4314 ); 4315 if (!EFI_ERROR (Status)) { 4316 if (ReturnStatus == EFI_NOT_READY) { 4317 ReturnStatus = EFI_SUCCESS; 4318 } 4319 4320 MinX = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinX; 4321 MinY = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinY; 4322 MinZ = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinZ; 4323 MaxX = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxX; 4324 MaxY = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxY; 4325 MaxZ = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxZ; 4326 4327 State->ActiveButtons = CurrentState.ActiveButtons; 4328 4329 // 4330 // Rescale to Con Splitter virtual Absolute Pointer's resolution. 4331 // 4332 if (!(MinX == 0 && MaxX == 0)) { 4333 State->CurrentX = VirtualMinX + DivU64x64Remainder ( 4334 MultU64x64 ( 4335 CurrentState.CurrentX, 4336 VirtualMaxX - VirtualMinX 4337 ), 4338 MaxX - MinX, 4339 NULL 4340 ); 4341 } 4342 if (!(MinY == 0 && MaxY == 0)) { 4343 State->CurrentY = VirtualMinY + DivU64x64Remainder ( 4344 MultU64x64 ( 4345 CurrentState.CurrentY, 4346 VirtualMaxY - VirtualMinY 4347 ), 4348 MaxY - MinY, 4349 NULL 4350 ); 4351 } 4352 if (!(MinZ == 0 && MaxZ == 0)) { 4353 State->CurrentZ = VirtualMinZ + DivU64x64Remainder ( 4354 MultU64x64 ( 4355 CurrentState.CurrentZ, 4356 VirtualMaxZ - VirtualMinZ 4357 ), 4358 MaxZ - MinZ, 4359 NULL 4360 ); 4361 } 4362 4363 } else if (Status == EFI_DEVICE_ERROR) { 4364 ReturnStatus = EFI_DEVICE_ERROR; 4365 } 4366 } 4367 4368 return ReturnStatus; 4369 } 4370 4371 4372 /** 4373 This event agregates all the events of the pointer devices in the splitter. 4374 If any events of physical pointer devices are signaled, signal the pointer 4375 splitter event. This will cause the calling code to call 4376 ConSplitterAbsolutePointerGetState (). 4377 4378 @param Event The Event assoicated with callback. 4379 @param Context Context registered when Event was created. 4380 4381 **/ 4382 VOID 4383 EFIAPI 4384 ConSplitterAbsolutePointerWaitForInput ( 4385 IN EFI_EVENT Event, 4386 IN VOID *Context 4387 ) 4388 { 4389 EFI_STATUS Status; 4390 TEXT_IN_SPLITTER_PRIVATE_DATA *Private; 4391 UINTN Index; 4392 4393 Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context; 4394 4395 // 4396 // if AbsoluteInputEventSignalState is flagged before, 4397 // and not cleared by Reset() or GetState(), signal it 4398 // 4399 if (Private->AbsoluteInputEventSignalState) { 4400 gBS->SignalEvent (Event); 4401 return ; 4402 } 4403 // 4404 // if any physical console input device has key input, signal the event. 4405 // 4406 for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) { 4407 Status = gBS->CheckEvent (Private->AbsolutePointerList[Index]->WaitForInput); 4408 if (!EFI_ERROR (Status)) { 4409 gBS->SignalEvent (Event); 4410 Private->AbsoluteInputEventSignalState = TRUE; 4411 } 4412 } 4413 } 4414 4415 4416 /** 4417 Reset the text output device hardware and optionaly run diagnostics 4418 4419 @param This Protocol instance pointer. 4420 @param ExtendedVerification Driver may perform more exhaustive verfication 4421 operation of the device during reset. 4422 4423 @retval EFI_SUCCESS The text output device was reset. 4424 @retval EFI_DEVICE_ERROR The text output device is not functioning 4425 correctly and could not be reset. 4426 4427 **/ 4428 EFI_STATUS 4429 EFIAPI 4430 ConSplitterTextOutReset ( 4431 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, 4432 IN BOOLEAN ExtendedVerification 4433 ) 4434 { 4435 EFI_STATUS Status; 4436 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; 4437 UINTN Index; 4438 EFI_STATUS ReturnStatus; 4439 4440 Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); 4441 4442 // 4443 // return the worst status met 4444 // 4445 for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { 4446 Status = Private->TextOutList[Index].TextOut->Reset ( 4447 Private->TextOutList[Index].TextOut, 4448 ExtendedVerification 4449 ); 4450 if (EFI_ERROR (Status)) { 4451 ReturnStatus = Status; 4452 } 4453 } 4454 4455 This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BLACK)); 4456 4457 // 4458 // reset all mode parameters 4459 // 4460 TextOutSetMode (Private, 0); 4461 4462 return ReturnStatus; 4463 } 4464 4465 4466 /** 4467 Write a Unicode string to the output device. 4468 4469 @param This Protocol instance pointer. 4470 @param WString The NULL-terminated Unicode string to be 4471 displayed on the output device(s). All output 4472 devices must also support the Unicode drawing 4473 defined in this file. 4474 4475 @retval EFI_SUCCESS The string was output to the device. 4476 @retval EFI_DEVICE_ERROR The device reported an error while attempting to 4477 output the text. 4478 @retval EFI_UNSUPPORTED The output device's mode is not currently in a 4479 defined text mode. 4480 @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the 4481 characters in the Unicode string could not be 4482 rendered and were skipped. 4483 4484 **/ 4485 EFI_STATUS 4486 EFIAPI 4487 ConSplitterTextOutOutputString ( 4488 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, 4489 IN CHAR16 *WString 4490 ) 4491 { 4492 EFI_STATUS Status; 4493 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; 4494 UINTN Index; 4495 EFI_STATUS ReturnStatus; 4496 UINTN MaxColumn; 4497 UINTN MaxRow; 4498 4499 This->SetAttribute (This, This->Mode->Attribute); 4500 4501 Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); 4502 4503 // 4504 // return the worst status met 4505 // 4506 for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { 4507 Status = Private->TextOutList[Index].TextOut->OutputString ( 4508 Private->TextOutList[Index].TextOut, 4509 WString 4510 ); 4511 if (EFI_ERROR (Status)) { 4512 ReturnStatus = Status; 4513 } 4514 } 4515 4516 if (Private->CurrentNumberOfConsoles > 0) { 4517 Private->TextOutMode.CursorColumn = Private->TextOutList[0].TextOut->Mode->CursorColumn; 4518 Private->TextOutMode.CursorRow = Private->TextOutList[0].TextOut->Mode->CursorRow; 4519 } else { 4520 // 4521 // When there is no real console devices in system, 4522 // update cursor position for the virtual device in consplitter. 4523 // 4524 Private->TextOut.QueryMode ( 4525 &Private->TextOut, 4526 Private->TextOutMode.Mode, 4527 &MaxColumn, 4528 &MaxRow 4529 ); 4530 for (; *WString != CHAR_NULL; WString++) { 4531 switch (*WString) { 4532 case CHAR_BACKSPACE: 4533 if (Private->TextOutMode.CursorColumn == 0 && Private->TextOutMode.CursorRow > 0) { 4534 Private->TextOutMode.CursorRow--; 4535 Private->TextOutMode.CursorColumn = (INT32) (MaxColumn - 1); 4536 } else if (Private->TextOutMode.CursorColumn > 0) { 4537 Private->TextOutMode.CursorColumn--; 4538 } 4539 break; 4540 4541 case CHAR_LINEFEED: 4542 if (Private->TextOutMode.CursorRow < (INT32) (MaxRow - 1)) { 4543 Private->TextOutMode.CursorRow++; 4544 } 4545 break; 4546 4547 case CHAR_CARRIAGE_RETURN: 4548 Private->TextOutMode.CursorColumn = 0; 4549 break; 4550 4551 default: 4552 if (Private->TextOutMode.CursorColumn < (INT32) (MaxColumn - 1)) { 4553 Private->TextOutMode.CursorColumn++; 4554 } else { 4555 Private->TextOutMode.CursorColumn = 0; 4556 if (Private->TextOutMode.CursorRow < (INT32) (MaxRow - 1)) { 4557 Private->TextOutMode.CursorRow++; 4558 } 4559 } 4560 break; 4561 } 4562 } 4563 } 4564 4565 return ReturnStatus; 4566 } 4567 4568 4569 /** 4570 Verifies that all characters in a Unicode string can be output to the 4571 target device. 4572 4573 @param This Protocol instance pointer. 4574 @param WString The NULL-terminated Unicode string to be 4575 examined for the output device(s). 4576 4577 @retval EFI_SUCCESS The device(s) are capable of rendering the 4578 output string. 4579 @retval EFI_UNSUPPORTED Some of the characters in the Unicode string 4580 cannot be rendered by one or more of the output 4581 devices mapped by the EFI handle. 4582 4583 **/ 4584 EFI_STATUS 4585 EFIAPI 4586 ConSplitterTextOutTestString ( 4587 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, 4588 IN CHAR16 *WString 4589 ) 4590 { 4591 EFI_STATUS Status; 4592 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; 4593 UINTN Index; 4594 EFI_STATUS ReturnStatus; 4595 4596 Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); 4597 4598 // 4599 // return the worst status met 4600 // 4601 for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { 4602 Status = Private->TextOutList[Index].TextOut->TestString ( 4603 Private->TextOutList[Index].TextOut, 4604 WString 4605 ); 4606 if (EFI_ERROR (Status)) { 4607 ReturnStatus = Status; 4608 } 4609 } 4610 // 4611 // There is no DevNullTextOutTestString () since a Unicode buffer would 4612 // always return EFI_SUCCESS. 4613 // ReturnStatus will be EFI_SUCCESS if no consoles are present 4614 // 4615 return ReturnStatus; 4616 } 4617 4618 4619 /** 4620 Returns information for an available text mode that the output device(s) 4621 supports. 4622 4623 @param This Protocol instance pointer. 4624 @param ModeNumber The mode number to return information on. 4625 @param Columns Returns the columns of the text output device 4626 for the requested ModeNumber. 4627 @param Rows Returns the rows of the text output device 4628 for the requested ModeNumber. 4629 4630 @retval EFI_SUCCESS The requested mode information was returned. 4631 @retval EFI_DEVICE_ERROR The device had an error and could not complete 4632 the request. 4633 @retval EFI_UNSUPPORTED The mode number was not valid. 4634 4635 **/ 4636 EFI_STATUS 4637 EFIAPI 4638 ConSplitterTextOutQueryMode ( 4639 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, 4640 IN UINTN ModeNumber, 4641 OUT UINTN *Columns, 4642 OUT UINTN *Rows 4643 ) 4644 { 4645 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; 4646 UINTN CurrentMode; 4647 INT32 *TextOutModeMap; 4648 4649 Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); 4650 4651 // 4652 // Check whether param ModeNumber is valid. 4653 // ModeNumber should be within range 0 ~ MaxMode - 1. 4654 // 4655 if ( (ModeNumber > (UINTN)(((UINT32)-1)>>1)) ) { 4656 return EFI_UNSUPPORTED; 4657 } 4658 4659 if ((INT32) ModeNumber >= This->Mode->MaxMode) { 4660 return EFI_UNSUPPORTED; 4661 } 4662 4663 // 4664 // We get the available mode from mode intersection map if it's available 4665 // 4666 if (Private->TextOutModeMap != NULL) { 4667 TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber; 4668 CurrentMode = (UINTN)(*TextOutModeMap); 4669 *Columns = Private->TextOutQueryData[CurrentMode].Columns; 4670 *Rows = Private->TextOutQueryData[CurrentMode].Rows; 4671 } else { 4672 *Columns = Private->TextOutQueryData[ModeNumber].Columns; 4673 *Rows = Private->TextOutQueryData[ModeNumber].Rows; 4674 } 4675 4676 if (*Columns <= 0 && *Rows <= 0) { 4677 return EFI_UNSUPPORTED; 4678 4679 } 4680 4681 return EFI_SUCCESS; 4682 } 4683 4684 4685 /** 4686 Sets the output device(s) to a specified mode. 4687 4688 @param This Protocol instance pointer. 4689 @param ModeNumber The mode number to set. 4690 4691 @retval EFI_SUCCESS The requested text mode was set. 4692 @retval EFI_DEVICE_ERROR The device had an error and could not complete 4693 the request. 4694 @retval EFI_UNSUPPORTED The mode number was not valid. 4695 4696 **/ 4697 EFI_STATUS 4698 EFIAPI 4699 ConSplitterTextOutSetMode ( 4700 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, 4701 IN UINTN ModeNumber 4702 ) 4703 { 4704 EFI_STATUS Status; 4705 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; 4706 UINTN Index; 4707 INT32 *TextOutModeMap; 4708 EFI_STATUS ReturnStatus; 4709 4710 Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); 4711 4712 // 4713 // Check whether param ModeNumber is valid. 4714 // ModeNumber should be within range 0 ~ MaxMode - 1. 4715 // 4716 if ( (ModeNumber > (UINTN)(((UINT32)-1)>>1)) ) { 4717 return EFI_UNSUPPORTED; 4718 } 4719 4720 if ((INT32) ModeNumber >= This->Mode->MaxMode) { 4721 return EFI_UNSUPPORTED; 4722 } 4723 // 4724 // If the mode is being set to the curent mode, then just clear the screen and return. 4725 // 4726 if (Private->TextOutMode.Mode == (INT32) ModeNumber) { 4727 return ConSplitterTextOutClearScreen (This); 4728 } 4729 // 4730 // return the worst status met 4731 // 4732 TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber; 4733 for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { 4734 Status = Private->TextOutList[Index].TextOut->SetMode ( 4735 Private->TextOutList[Index].TextOut, 4736 TextOutModeMap[Index] 4737 ); 4738 if (EFI_ERROR (Status)) { 4739 ReturnStatus = Status; 4740 } 4741 } 4742 4743 // 4744 // Set mode parameter to specified mode number 4745 // 4746 TextOutSetMode (Private, ModeNumber); 4747 4748 return ReturnStatus; 4749 } 4750 4751 4752 /** 4753 Sets the background and foreground colors for the OutputString () and 4754 ClearScreen () functions. 4755 4756 @param This Protocol instance pointer. 4757 @param Attribute The attribute to set. Bits 0..3 are the 4758 foreground color, and bits 4..6 are the 4759 background color. All other bits are undefined 4760 and must be zero. The valid Attributes are 4761 defined in this file. 4762 4763 @retval EFI_SUCCESS The attribute was set. 4764 @retval EFI_DEVICE_ERROR The device had an error and could not complete 4765 the request. 4766 @retval EFI_UNSUPPORTED The attribute requested is not defined. 4767 4768 **/ 4769 EFI_STATUS 4770 EFIAPI 4771 ConSplitterTextOutSetAttribute ( 4772 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, 4773 IN UINTN Attribute 4774 ) 4775 { 4776 EFI_STATUS Status; 4777 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; 4778 UINTN Index; 4779 EFI_STATUS ReturnStatus; 4780 4781 Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); 4782 4783 // 4784 // Check whether param Attribute is valid. 4785 // 4786 if ((Attribute | 0x7F) != 0x7F) { 4787 return EFI_UNSUPPORTED; 4788 } 4789 4790 // 4791 // return the worst status met 4792 // 4793 for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { 4794 Status = Private->TextOutList[Index].TextOut->SetAttribute ( 4795 Private->TextOutList[Index].TextOut, 4796 Attribute 4797 ); 4798 if (EFI_ERROR (Status)) { 4799 ReturnStatus = Status; 4800 } 4801 } 4802 4803 Private->TextOutMode.Attribute = (INT32) Attribute; 4804 4805 return ReturnStatus; 4806 } 4807 4808 4809 /** 4810 Clears the output device(s) display to the currently selected background 4811 color. 4812 4813 @param This Protocol instance pointer. 4814 4815 @retval EFI_SUCCESS The operation completed successfully. 4816 @retval EFI_DEVICE_ERROR The device had an error and could not complete 4817 the request. 4818 @retval EFI_UNSUPPORTED The output device is not in a valid text mode. 4819 4820 **/ 4821 EFI_STATUS 4822 EFIAPI 4823 ConSplitterTextOutClearScreen ( 4824 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This 4825 ) 4826 { 4827 EFI_STATUS Status; 4828 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; 4829 UINTN Index; 4830 EFI_STATUS ReturnStatus; 4831 4832 Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); 4833 4834 // 4835 // return the worst status met 4836 // 4837 for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { 4838 Status = Private->TextOutList[Index].TextOut->ClearScreen (Private->TextOutList[Index].TextOut); 4839 if (EFI_ERROR (Status)) { 4840 ReturnStatus = Status; 4841 } 4842 } 4843 4844 // 4845 // No need to do extra check here as whether (Column, Row) is valid has 4846 // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should 4847 // always be supported. 4848 // 4849 Private->TextOutMode.CursorColumn = 0; 4850 Private->TextOutMode.CursorRow = 0; 4851 Private->TextOutMode.CursorVisible = TRUE; 4852 4853 return ReturnStatus; 4854 } 4855 4856 4857 /** 4858 Sets the current coordinates of the cursor position 4859 4860 @param This Protocol instance pointer. 4861 @param Column The column position to set the cursor to. Must be 4862 greater than or equal to zero and less than the 4863 number of columns by QueryMode (). 4864 @param Row The row position to set the cursor to. Must be 4865 greater than or equal to zero and less than the 4866 number of rows by QueryMode (). 4867 4868 @retval EFI_SUCCESS The operation completed successfully. 4869 @retval EFI_DEVICE_ERROR The device had an error and could not complete 4870 the request. 4871 @retval EFI_UNSUPPORTED The output device is not in a valid text mode, 4872 or the cursor position is invalid for the 4873 current mode. 4874 4875 **/ 4876 EFI_STATUS 4877 EFIAPI 4878 ConSplitterTextOutSetCursorPosition ( 4879 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, 4880 IN UINTN Column, 4881 IN UINTN Row 4882 ) 4883 { 4884 EFI_STATUS Status; 4885 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; 4886 UINTN Index; 4887 EFI_STATUS ReturnStatus; 4888 UINTN MaxColumn; 4889 UINTN MaxRow; 4890 INT32 *TextOutModeMap; 4891 INT32 ModeNumber; 4892 INT32 CurrentMode; 4893 4894 Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); 4895 TextOutModeMap = NULL; 4896 ModeNumber = Private->TextOutMode.Mode; 4897 4898 // 4899 // Get current MaxColumn and MaxRow from intersection map 4900 // 4901 if (Private->TextOutModeMap != NULL) { 4902 TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber; 4903 CurrentMode = *TextOutModeMap; 4904 } else { 4905 CurrentMode = ModeNumber; 4906 } 4907 4908 MaxColumn = Private->TextOutQueryData[CurrentMode].Columns; 4909 MaxRow = Private->TextOutQueryData[CurrentMode].Rows; 4910 4911 if (Column >= MaxColumn || Row >= MaxRow) { 4912 return EFI_UNSUPPORTED; 4913 } 4914 // 4915 // return the worst status met 4916 // 4917 for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { 4918 Status = Private->TextOutList[Index].TextOut->SetCursorPosition ( 4919 Private->TextOutList[Index].TextOut, 4920 Column, 4921 Row 4922 ); 4923 if (EFI_ERROR (Status)) { 4924 ReturnStatus = Status; 4925 } 4926 } 4927 4928 // 4929 // No need to do extra check here as whether (Column, Row) is valid has 4930 // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should 4931 // always be supported. 4932 // 4933 Private->TextOutMode.CursorColumn = (INT32) Column; 4934 Private->TextOutMode.CursorRow = (INT32) Row; 4935 4936 return ReturnStatus; 4937 } 4938 4939 4940 /** 4941 Makes the cursor visible or invisible 4942 4943 @param This Protocol instance pointer. 4944 @param Visible If TRUE, the cursor is set to be visible. If 4945 FALSE, the cursor is set to be invisible. 4946 4947 @retval EFI_SUCCESS The operation completed successfully. 4948 @retval EFI_DEVICE_ERROR The device had an error and could not complete 4949 the request, or the device does not support 4950 changing the cursor mode. 4951 @retval EFI_UNSUPPORTED The output device is not in a valid text mode. 4952 4953 **/ 4954 EFI_STATUS 4955 EFIAPI 4956 ConSplitterTextOutEnableCursor ( 4957 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, 4958 IN BOOLEAN Visible 4959 ) 4960 { 4961 EFI_STATUS Status; 4962 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; 4963 UINTN Index; 4964 EFI_STATUS ReturnStatus; 4965 4966 Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); 4967 4968 // 4969 // return the worst status met 4970 // 4971 for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { 4972 Status = Private->TextOutList[Index].TextOut->EnableCursor ( 4973 Private->TextOutList[Index].TextOut, 4974 Visible 4975 ); 4976 if (EFI_ERROR (Status)) { 4977 ReturnStatus = Status; 4978 } 4979 } 4980 4981 Private->TextOutMode.CursorVisible = Visible; 4982 4983 return ReturnStatus; 4984 } 4985 4986 4987 /** 4988 An empty function to pass error checking of CreateEventEx (). 4989 4990 @param Event Event whose notification function is being invoked. 4991 @param Context Pointer to the notification function's context, 4992 which is implementation-dependent. 4993 4994 **/ 4995 VOID 4996 EFIAPI 4997 ConSplitterEmptyCallbackFunction ( 4998 IN EFI_EVENT Event, 4999 IN VOID *Context 5000 ) 5001 { 5002 } 5003