1 /** @file 2 Produces Simple Text Input Protocol, Simple Text Input Extended Protocol and 3 Simple Text Output Protocol upon Serial IO Protocol. 4 5 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 17 #include "Terminal.h" 18 19 // 20 // Globals 21 // 22 EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = { 23 TerminalDriverBindingSupported, 24 TerminalDriverBindingStart, 25 TerminalDriverBindingStop, 26 0xa, 27 NULL, 28 NULL 29 }; 30 31 32 EFI_GUID *gTerminalType[] = { 33 &gEfiPcAnsiGuid, 34 &gEfiVT100Guid, 35 &gEfiVT100PlusGuid, 36 &gEfiVTUTF8Guid, 37 &gEfiTtyTermGuid 38 }; 39 40 41 TERMINAL_DEV mTerminalDevTemplate = { 42 TERMINAL_DEV_SIGNATURE, 43 NULL, 44 0, 45 NULL, 46 NULL, 47 { // SimpleTextInput 48 TerminalConInReset, 49 TerminalConInReadKeyStroke, 50 NULL 51 }, 52 { // SimpleTextOutput 53 TerminalConOutReset, 54 TerminalConOutOutputString, 55 TerminalConOutTestString, 56 TerminalConOutQueryMode, 57 TerminalConOutSetMode, 58 TerminalConOutSetAttribute, 59 TerminalConOutClearScreen, 60 TerminalConOutSetCursorPosition, 61 TerminalConOutEnableCursor, 62 NULL 63 }, 64 { // SimpleTextOutputMode 65 1, // MaxMode 66 0, // Mode 67 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK), // Attribute 68 0, // CursorColumn 69 0, // CursorRow 70 TRUE // CursorVisible 71 }, 72 NULL, // TerminalConsoleModeData 73 0, // SerialInTimeOut 74 75 NULL, // RawFifo 76 NULL, // UnicodeFiFo 77 NULL, // EfiKeyFiFo 78 79 NULL, // ControllerNameTable 80 NULL, // TimerEvent 81 NULL, // TwoSecondTimeOut 82 INPUT_STATE_DEFAULT, 83 RESET_STATE_DEFAULT, 84 { 85 0, 86 0, 87 0 88 }, 89 0, 90 FALSE, 91 { // SimpleTextInputEx 92 TerminalConInResetEx, 93 TerminalConInReadKeyStrokeEx, 94 NULL, 95 TerminalConInSetState, 96 TerminalConInRegisterKeyNotify, 97 TerminalConInUnregisterKeyNotify, 98 }, 99 { // NotifyList 100 NULL, 101 NULL, 102 } 103 }; 104 105 TERMINAL_CONSOLE_MODE_DATA mTerminalConsoleModeData[] = { 106 {100, 31}, 107 // 108 // New modes can be added here. 109 // 110 }; 111 112 /** 113 Test to see if this driver supports Controller. 114 115 @param This Protocol instance pointer. 116 @param Controller Handle of device to test 117 @param RemainingDevicePath Optional parameter use to pick a specific child 118 device to start. 119 120 @retval EFI_SUCCESS This driver supports this device. 121 @retval EFI_ALREADY_STARTED This driver is already running on this device. 122 @retval other This driver does not support this device. 123 124 **/ 125 EFI_STATUS 126 EFIAPI 127 TerminalDriverBindingSupported ( 128 IN EFI_DRIVER_BINDING_PROTOCOL *This, 129 IN EFI_HANDLE Controller, 130 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 131 ) 132 { 133 EFI_STATUS Status; 134 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; 135 EFI_SERIAL_IO_PROTOCOL *SerialIo; 136 VENDOR_DEVICE_PATH *Node; 137 138 // 139 // If remaining device path is not NULL, then make sure it is a 140 // device path that describes a terminal communications protocol. 141 // 142 if (RemainingDevicePath != NULL) { 143 // 144 // Check if RemainingDevicePath is the End of Device Path Node, 145 // if yes, go on checking other conditions 146 // 147 if (!IsDevicePathEnd (RemainingDevicePath)) { 148 // 149 // If RemainingDevicePath isn't the End of Device Path Node, 150 // check its validation 151 // 152 Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath; 153 154 if (Node->Header.Type != MESSAGING_DEVICE_PATH || 155 Node->Header.SubType != MSG_VENDOR_DP || 156 DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) { 157 158 return EFI_UNSUPPORTED; 159 160 } 161 // 162 // only supports PC ANSI, VT100, VT100+, VT-UTF8, and TtyTerm terminal types 163 // 164 if (!CompareGuid (&Node->Guid, &gEfiPcAnsiGuid) && 165 !CompareGuid (&Node->Guid, &gEfiVT100Guid) && 166 !CompareGuid (&Node->Guid, &gEfiVT100PlusGuid) && 167 !CompareGuid (&Node->Guid, &gEfiVTUTF8Guid) && 168 !CompareGuid (&Node->Guid, &gEfiTtyTermGuid)) { 169 170 return EFI_UNSUPPORTED; 171 } 172 } 173 } 174 // 175 // Open the IO Abstraction(s) needed to perform the supported test 176 // The Controller must support the Serial I/O Protocol. 177 // This driver is a bus driver with at most 1 child device, so it is 178 // ok for it to be already started. 179 // 180 Status = gBS->OpenProtocol ( 181 Controller, 182 &gEfiSerialIoProtocolGuid, 183 (VOID **) &SerialIo, 184 This->DriverBindingHandle, 185 Controller, 186 EFI_OPEN_PROTOCOL_BY_DRIVER 187 ); 188 if (Status == EFI_ALREADY_STARTED) { 189 return EFI_SUCCESS; 190 } 191 192 if (EFI_ERROR (Status)) { 193 return Status; 194 } 195 196 // 197 // Close the I/O Abstraction(s) used to perform the supported test 198 // 199 gBS->CloseProtocol ( 200 Controller, 201 &gEfiSerialIoProtocolGuid, 202 This->DriverBindingHandle, 203 Controller 204 ); 205 206 // 207 // Open the EFI Device Path protocol needed to perform the supported test 208 // 209 Status = gBS->OpenProtocol ( 210 Controller, 211 &gEfiDevicePathProtocolGuid, 212 (VOID **) &ParentDevicePath, 213 This->DriverBindingHandle, 214 Controller, 215 EFI_OPEN_PROTOCOL_BY_DRIVER 216 ); 217 if (Status == EFI_ALREADY_STARTED) { 218 return EFI_SUCCESS; 219 } 220 221 if (EFI_ERROR (Status)) { 222 return Status; 223 } 224 225 // 226 // Close protocol, don't use device path protocol in the Support() function 227 // 228 gBS->CloseProtocol ( 229 Controller, 230 &gEfiDevicePathProtocolGuid, 231 This->DriverBindingHandle, 232 Controller 233 ); 234 235 return Status; 236 } 237 238 /** 239 Build the terminal device path for the child device according to the 240 terminal type. 241 242 @param ParentDevicePath Parent device path. 243 @param RemainingDevicePath A specific child device. 244 245 @return The child device path built. 246 247 **/ 248 EFI_DEVICE_PATH_PROTOCOL* 249 EFIAPI 250 BuildTerminalDevpath ( 251 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, 252 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 253 ) 254 { 255 EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath; 256 UINT8 TerminalType; 257 VENDOR_DEVICE_PATH *Node; 258 EFI_STATUS Status; 259 260 TerminalDevicePath = NULL; 261 262 // 263 // Use the RemainingDevicePath to determine the terminal type 264 // 265 Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath; 266 if (Node == NULL) { 267 TerminalType = PcdGet8 (PcdDefaultTerminalType); 268 269 } else if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) { 270 271 TerminalType = PCANSITYPE; 272 273 } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) { 274 275 TerminalType = VT100TYPE; 276 277 } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) { 278 279 TerminalType = VT100PLUSTYPE; 280 281 } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) { 282 283 TerminalType = VTUTF8TYPE; 284 285 } else if (CompareGuid (&Node->Guid, &gEfiTtyTermGuid)) { 286 287 TerminalType = TTYTERMTYPE; 288 289 } else { 290 return NULL; 291 } 292 293 // 294 // Build the device path for the child device 295 // 296 Status = SetTerminalDevicePath ( 297 TerminalType, 298 ParentDevicePath, 299 &TerminalDevicePath 300 ); 301 if (EFI_ERROR (Status)) { 302 return NULL; 303 } 304 return TerminalDevicePath; 305 } 306 307 /** 308 Compare a device path data structure to that of all the nodes of a 309 second device path instance. 310 311 @param Multi A pointer to a multi-instance device path data structure. 312 @param Single A pointer to a single-instance device path data structure. 313 314 @retval TRUE If the Single is contained within Multi. 315 @retval FALSE The Single is not match within Multi. 316 317 **/ 318 BOOLEAN 319 MatchDevicePaths ( 320 IN EFI_DEVICE_PATH_PROTOCOL *Multi, 321 IN EFI_DEVICE_PATH_PROTOCOL *Single 322 ) 323 { 324 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 325 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst; 326 UINTN Size; 327 328 DevicePath = Multi; 329 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size); 330 // 331 // Search for the match of 'Single' in 'Multi' 332 // 333 while (DevicePathInst != NULL) { 334 // 335 // If the single device path is found in multiple device paths, 336 // return success 337 // 338 if (CompareMem (Single, DevicePathInst, Size) == 0) { 339 FreePool (DevicePathInst); 340 return TRUE; 341 } 342 343 FreePool (DevicePathInst); 344 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size); 345 } 346 347 return FALSE; 348 } 349 350 /** 351 Check whether the terminal device path is in the global variable. 352 353 @param VariableName Pointer to one global variable. 354 @param TerminalDevicePath Pointer to the terminal device's device path. 355 356 @retval TRUE The devcie is in the global variable. 357 @retval FALSE The devcie is not in the global variable. 358 359 **/ 360 BOOLEAN 361 IsTerminalInConsoleVariable ( 362 IN CHAR16 *VariableName, 363 IN EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath 364 ) 365 { 366 EFI_DEVICE_PATH_PROTOCOL *Variable; 367 BOOLEAN ReturnFlag; 368 369 // 370 // Get global variable and its size according to the name given. 371 // 372 GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL); 373 if (Variable == NULL) { 374 return FALSE; 375 } 376 377 // 378 // Check whether the terminal device path is one of the variable instances. 379 // 380 ReturnFlag = MatchDevicePaths (Variable, TerminalDevicePath); 381 382 FreePool (Variable); 383 384 return ReturnFlag; 385 } 386 387 /** 388 Free notify functions list. 389 390 @param ListHead The list head 391 392 @retval EFI_SUCCESS Free the notify list successfully. 393 @retval EFI_INVALID_PARAMETER ListHead is NULL. 394 395 **/ 396 EFI_STATUS 397 TerminalFreeNotifyList ( 398 IN OUT LIST_ENTRY *ListHead 399 ) 400 { 401 TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode; 402 403 if (ListHead == NULL) { 404 return EFI_INVALID_PARAMETER; 405 } 406 while (!IsListEmpty (ListHead)) { 407 NotifyNode = CR ( 408 ListHead->ForwardLink, 409 TERMINAL_CONSOLE_IN_EX_NOTIFY, 410 NotifyEntry, 411 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE 412 ); 413 RemoveEntryList (ListHead->ForwardLink); 414 FreePool (NotifyNode); 415 } 416 417 return EFI_SUCCESS; 418 } 419 420 /** 421 Initialize all the text modes which the terminal console supports. 422 423 It returns information for available text modes that the terminal can support. 424 425 @param[out] TextModeCount The total number of text modes that terminal console supports. 426 @param[out] TextModeData The buffer to the text modes column and row information. 427 Caller is responsible to free it when it's non-NULL. 428 429 @retval EFI_SUCCESS The supporting mode information is returned. 430 @retval EFI_INVALID_PARAMETER The parameters are invalid. 431 432 **/ 433 EFI_STATUS 434 InitializeTerminalConsoleTextMode ( 435 OUT UINTN *TextModeCount, 436 OUT TERMINAL_CONSOLE_MODE_DATA **TextModeData 437 ) 438 { 439 UINTN Index; 440 UINTN Count; 441 TERMINAL_CONSOLE_MODE_DATA *ModeBuffer; 442 TERMINAL_CONSOLE_MODE_DATA *NewModeBuffer; 443 UINTN ValidCount; 444 UINTN ValidIndex; 445 446 if ((TextModeCount == NULL) || (TextModeData == NULL)) { 447 return EFI_INVALID_PARAMETER; 448 } 449 450 Count = sizeof (mTerminalConsoleModeData) / sizeof (TERMINAL_CONSOLE_MODE_DATA); 451 452 // 453 // Get defined mode buffer pointer. 454 // 455 ModeBuffer = mTerminalConsoleModeData; 456 457 // 458 // Here we make sure that the final mode exposed does not include the duplicated modes, 459 // and does not include the invalid modes which exceed the max column and row. 460 // Reserve 2 modes for 80x25, 80x50 of terminal console. 461 // 462 NewModeBuffer = AllocateZeroPool (sizeof (TERMINAL_CONSOLE_MODE_DATA) * (Count + 2)); 463 ASSERT (NewModeBuffer != NULL); 464 465 // 466 // Mode 0 and mode 1 is for 80x25, 80x50 according to UEFI spec. 467 // 468 ValidCount = 0; 469 470 NewModeBuffer[ValidCount].Columns = 80; 471 NewModeBuffer[ValidCount].Rows = 25; 472 ValidCount++; 473 474 NewModeBuffer[ValidCount].Columns = 80; 475 NewModeBuffer[ValidCount].Rows = 50; 476 ValidCount++; 477 478 // 479 // Start from mode 2 to put the valid mode other than 80x25 and 80x50 in the output mode buffer. 480 // 481 for (Index = 0; Index < Count; Index++) { 482 if ((ModeBuffer[Index].Columns == 0) || (ModeBuffer[Index].Rows == 0)) { 483 // 484 // Skip the pre-defined mode which is invalid. 485 // 486 continue; 487 } 488 for (ValidIndex = 0; ValidIndex < ValidCount; ValidIndex++) { 489 if ((ModeBuffer[Index].Columns == NewModeBuffer[ValidIndex].Columns) && 490 (ModeBuffer[Index].Rows == NewModeBuffer[ValidIndex].Rows)) { 491 // 492 // Skip the duplicated mode. 493 // 494 break; 495 } 496 } 497 if (ValidIndex == ValidCount) { 498 NewModeBuffer[ValidCount].Columns = ModeBuffer[Index].Columns; 499 NewModeBuffer[ValidCount].Rows = ModeBuffer[Index].Rows; 500 ValidCount++; 501 } 502 } 503 504 DEBUG_CODE ( 505 for (Index = 0; Index < ValidCount; Index++) { 506 DEBUG ((EFI_D_INFO, "Terminal - Mode %d, Column = %d, Row = %d\n", 507 Index, NewModeBuffer[Index].Columns, NewModeBuffer[Index].Rows)); 508 } 509 ); 510 511 // 512 // Return valid mode count and mode information buffer. 513 // 514 *TextModeCount = ValidCount; 515 *TextModeData = NewModeBuffer; 516 return EFI_SUCCESS; 517 } 518 519 /** 520 Start this driver on Controller by opening a Serial IO protocol, 521 reading Device Path, and creating a child handle with a Simple Text In, 522 Simple Text In Ex and Simple Text Out protocol, and device path protocol. 523 And store Console Device Environment Variables. 524 525 @param This Protocol instance pointer. 526 @param Controller Handle of device to bind driver to 527 @param RemainingDevicePath Optional parameter use to pick a specific child 528 device to start. 529 530 @retval EFI_SUCCESS This driver is added to Controller. 531 @retval EFI_ALREADY_STARTED This driver is already running on Controller. 532 @retval other This driver does not support this device. 533 534 **/ 535 EFI_STATUS 536 EFIAPI 537 TerminalDriverBindingStart ( 538 IN EFI_DRIVER_BINDING_PROTOCOL *This, 539 IN EFI_HANDLE Controller, 540 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 541 ) 542 { 543 EFI_STATUS Status; 544 EFI_SERIAL_IO_PROTOCOL *SerialIo; 545 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; 546 VENDOR_DEVICE_PATH *Node; 547 EFI_SERIAL_IO_MODE *Mode; 548 UINTN SerialInTimeOut; 549 TERMINAL_DEV *TerminalDevice; 550 UINT8 TerminalType; 551 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; 552 UINTN EntryCount; 553 UINTN Index; 554 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 555 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput; 556 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextInput; 557 BOOLEAN ConInSelected; 558 BOOLEAN ConOutSelected; 559 BOOLEAN NullRemaining; 560 BOOLEAN SimTxtInInstalled; 561 BOOLEAN SimTxtOutInstalled; 562 BOOLEAN FirstEnter; 563 UINTN ModeCount; 564 565 TerminalDevice = NULL; 566 ConInSelected = FALSE; 567 ConOutSelected = FALSE; 568 NullRemaining = FALSE; 569 SimTxtInInstalled = FALSE; 570 SimTxtOutInstalled = FALSE; 571 FirstEnter = FALSE; 572 // 573 // Get the Device Path Protocol to build the device path of the child device 574 // 575 Status = gBS->OpenProtocol ( 576 Controller, 577 &gEfiDevicePathProtocolGuid, 578 (VOID **) &ParentDevicePath, 579 This->DriverBindingHandle, 580 Controller, 581 EFI_OPEN_PROTOCOL_BY_DRIVER 582 ); 583 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { 584 return Status; 585 } 586 587 // 588 // Open the Serial I/O Protocol BY_DRIVER. It might already be started. 589 // 590 Status = gBS->OpenProtocol ( 591 Controller, 592 &gEfiSerialIoProtocolGuid, 593 (VOID **) &SerialIo, 594 This->DriverBindingHandle, 595 Controller, 596 EFI_OPEN_PROTOCOL_BY_DRIVER 597 ); 598 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { 599 return Status; 600 } 601 602 if (Status != EFI_ALREADY_STARTED) { 603 // 604 // the serial I/O protocol never be opened before, it is the first 605 // time to start the serial Io controller 606 // 607 FirstEnter = TRUE; 608 } 609 610 // 611 // Serial I/O is not already open by this driver, then tag the handle 612 // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and 613 // StdErrDev variables with the list of possible terminal types on this 614 // serial port. 615 // 616 Status = gBS->OpenProtocol ( 617 Controller, 618 &gEfiCallerIdGuid, 619 NULL, 620 This->DriverBindingHandle, 621 Controller, 622 EFI_OPEN_PROTOCOL_TEST_PROTOCOL 623 ); 624 if (EFI_ERROR (Status)) { 625 Status = gBS->InstallMultipleProtocolInterfaces ( 626 &Controller, 627 &gEfiCallerIdGuid, 628 DuplicateDevicePath (ParentDevicePath), 629 NULL 630 ); 631 if (EFI_ERROR (Status)) { 632 goto Error; 633 } 634 635 if (!IsHotPlugDevice (ParentDevicePath)) { 636 // 637 // if the serial device is a hot plug device, do not update the 638 // ConInDev, ConOutDev, and StdErrDev variables. 639 // 640 TerminalUpdateConsoleDevVariable (L"ConInDev", ParentDevicePath); 641 TerminalUpdateConsoleDevVariable (L"ConOutDev", ParentDevicePath); 642 TerminalUpdateConsoleDevVariable (L"ErrOutDev", ParentDevicePath); 643 } 644 } 645 646 // 647 // Check the requirement for the SimpleTxtIn and SimpleTxtOut protocols 648 // 649 // Simple In/Out Protocol will not be installed onto the handle if the 650 // device path to the handle is not present in the ConIn/ConOut 651 // environment variable. But If RemainingDevicePath is NULL, then always 652 // produce both Simple In and Simple Text Output Protocols. This is required 653 // for the connect all sequences to make sure all possible consoles are 654 // produced no matter what the current values of ConIn, ConOut, or StdErr are. 655 // 656 if (RemainingDevicePath == NULL) { 657 NullRemaining = TRUE; 658 } 659 660 DevicePath = BuildTerminalDevpath (ParentDevicePath, RemainingDevicePath); 661 if (DevicePath != NULL) { 662 ConInSelected = IsTerminalInConsoleVariable (L"ConIn", DevicePath); 663 ConOutSelected = IsTerminalInConsoleVariable (L"ConOut", DevicePath); 664 FreePool (DevicePath); 665 } else { 666 goto Error; 667 } 668 // 669 // Not create the child terminal handle if both Simple In/In Ex and 670 // Simple text Out protocols are not required to be published 671 // 672 if ((!ConInSelected)&&(!ConOutSelected)&&(!NullRemaining)) { 673 goto Error; 674 } 675 676 // 677 // create the child terminal handle during first entry 678 // 679 if (FirstEnter) { 680 // 681 // First enther the start funciton 682 // 683 FirstEnter = FALSE; 684 // 685 // Make sure a child handle does not already exist. This driver can only 686 // produce one child per serial port. 687 // 688 Status = gBS->OpenProtocolInformation ( 689 Controller, 690 &gEfiSerialIoProtocolGuid, 691 &OpenInfoBuffer, 692 &EntryCount 693 ); 694 if (!EFI_ERROR (Status)) { 695 Status = EFI_SUCCESS; 696 for (Index = 0; Index < EntryCount; Index++) { 697 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { 698 Status = EFI_ALREADY_STARTED; 699 } 700 } 701 702 FreePool (OpenInfoBuffer); 703 if (EFI_ERROR (Status)) { 704 goto Error; 705 } 706 } 707 708 // 709 // If RemainingDevicePath is NULL, use default terminal type 710 // 711 if (RemainingDevicePath == NULL) { 712 TerminalType = PcdGet8 (PcdDefaultTerminalType); 713 // 714 // Must be between PCANSITYPE (0) and TTYTERMTYPE (4) 715 // 716 ASSERT (TerminalType <= TTYTERMTYPE); 717 } else if (!IsDevicePathEnd (RemainingDevicePath)) { 718 // 719 // If RemainingDevicePath isn't the End of Device Path Node, 720 // Use the RemainingDevicePath to determine the terminal type 721 // 722 Node = (VENDOR_DEVICE_PATH *)RemainingDevicePath; 723 if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) { 724 TerminalType = PCANSITYPE; 725 } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) { 726 TerminalType = VT100TYPE; 727 } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) { 728 TerminalType = VT100PLUSTYPE; 729 } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) { 730 TerminalType = VTUTF8TYPE; 731 } else if (CompareGuid (&Node->Guid, &gEfiTtyTermGuid)) { 732 TerminalType = TTYTERMTYPE; 733 } else { 734 goto Error; 735 } 736 } else { 737 // 738 // If RemainingDevicePath is the End of Device Path Node, 739 // skip enumerate any device and return EFI_SUCESSS 740 // 741 return EFI_SUCCESS; 742 } 743 744 // 745 // Initialize the Terminal Dev 746 // 747 TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate); 748 if (TerminalDevice == NULL) { 749 Status = EFI_OUT_OF_RESOURCES; 750 goto Error; 751 } 752 753 TerminalDevice->TerminalType = TerminalType; 754 TerminalDevice->SerialIo = SerialIo; 755 756 InitializeListHead (&TerminalDevice->NotifyList); 757 Status = gBS->CreateEvent ( 758 EVT_NOTIFY_WAIT, 759 TPL_NOTIFY, 760 TerminalConInWaitForKeyEx, 761 TerminalDevice, 762 &TerminalDevice->SimpleInputEx.WaitForKeyEx 763 ); 764 if (EFI_ERROR (Status)) { 765 goto Error; 766 } 767 768 Status = gBS->CreateEvent ( 769 EVT_NOTIFY_WAIT, 770 TPL_NOTIFY, 771 TerminalConInWaitForKey, 772 TerminalDevice, 773 &TerminalDevice->SimpleInput.WaitForKey 774 ); 775 if (EFI_ERROR (Status)) { 776 goto Error; 777 } 778 // 779 // Allocates and initializes the FIFO buffer to be zero, used for accommodating 780 // the pre-read pending characters. 781 // 782 TerminalDevice->RawFiFo = AllocateZeroPool (sizeof (RAW_DATA_FIFO)); 783 if (TerminalDevice->RawFiFo == NULL) { 784 goto Error; 785 } 786 TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO)); 787 if (TerminalDevice->UnicodeFiFo == NULL) { 788 goto Error; 789 } 790 TerminalDevice->EfiKeyFiFo = AllocateZeroPool (sizeof (EFI_KEY_FIFO)); 791 if (TerminalDevice->EfiKeyFiFo == NULL) { 792 goto Error; 793 } 794 795 // 796 // Set the timeout value of serial buffer for 797 // keystroke response performance issue 798 // 799 Mode = TerminalDevice->SerialIo->Mode; 800 801 SerialInTimeOut = 0; 802 if (Mode->BaudRate != 0) { 803 SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate; 804 } 805 806 Status = TerminalDevice->SerialIo->SetAttributes ( 807 TerminalDevice->SerialIo, 808 Mode->BaudRate, 809 0, // the device's default FIFO depth 810 (UINT32) SerialInTimeOut, 811 (EFI_PARITY_TYPE) (Mode->Parity), 812 (UINT8) Mode->DataBits, 813 (EFI_STOP_BITS_TYPE) (Mode->StopBits) 814 ); 815 if (EFI_ERROR (Status)) { 816 // 817 // if set attributes operation fails, invalidate 818 // the value of SerialInTimeOut,thus make it 819 // inconsistent with the default timeout value 820 // of serial buffer. This will invoke the recalculation 821 // in the readkeystroke routine. 822 // 823 TerminalDevice->SerialInTimeOut = 0; 824 } else { 825 TerminalDevice->SerialInTimeOut = SerialInTimeOut; 826 } 827 // 828 // Set Simple Text Output Protocol from template. 829 // 830 SimpleTextOutput = CopyMem ( 831 &TerminalDevice->SimpleTextOutput, 832 &mTerminalDevTemplate.SimpleTextOutput, 833 sizeof (mTerminalDevTemplate.SimpleTextOutput) 834 ); 835 SimpleTextOutput->Mode = &TerminalDevice->SimpleTextOutputMode; 836 837 Status = InitializeTerminalConsoleTextMode (&ModeCount, &TerminalDevice->TerminalConsoleModeData); 838 if (EFI_ERROR (Status)) { 839 goto ReportError; 840 } 841 TerminalDevice->SimpleTextOutputMode.MaxMode = (INT32) ModeCount; 842 843 // 844 // For terminal devices, cursor is always visible 845 // 846 TerminalDevice->SimpleTextOutputMode.CursorVisible = TRUE; 847 Status = TerminalConOutSetAttribute ( 848 SimpleTextOutput, 849 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK) 850 ); 851 if (EFI_ERROR (Status)) { 852 goto ReportError; 853 } 854 855 // 856 // Build the component name for the child device 857 // 858 TerminalDevice->ControllerNameTable = NULL; 859 switch (TerminalDevice->TerminalType) { 860 case PCANSITYPE: 861 AddUnicodeString2 ( 862 "eng", 863 gTerminalComponentName.SupportedLanguages, 864 &TerminalDevice->ControllerNameTable, 865 (CHAR16 *)L"PC-ANSI Serial Console", 866 TRUE 867 ); 868 AddUnicodeString2 ( 869 "en", 870 gTerminalComponentName2.SupportedLanguages, 871 &TerminalDevice->ControllerNameTable, 872 (CHAR16 *)L"PC-ANSI Serial Console", 873 FALSE 874 ); 875 876 break; 877 878 case VT100TYPE: 879 AddUnicodeString2 ( 880 "eng", 881 gTerminalComponentName.SupportedLanguages, 882 &TerminalDevice->ControllerNameTable, 883 (CHAR16 *)L"VT-100 Serial Console", 884 TRUE 885 ); 886 AddUnicodeString2 ( 887 "en", 888 gTerminalComponentName2.SupportedLanguages, 889 &TerminalDevice->ControllerNameTable, 890 (CHAR16 *)L"VT-100 Serial Console", 891 FALSE 892 ); 893 894 break; 895 896 case VT100PLUSTYPE: 897 AddUnicodeString2 ( 898 "eng", 899 gTerminalComponentName.SupportedLanguages, 900 &TerminalDevice->ControllerNameTable, 901 (CHAR16 *)L"VT-100+ Serial Console", 902 TRUE 903 ); 904 AddUnicodeString2 ( 905 "en", 906 gTerminalComponentName2.SupportedLanguages, 907 &TerminalDevice->ControllerNameTable, 908 (CHAR16 *)L"VT-100+ Serial Console", 909 FALSE 910 ); 911 912 break; 913 914 case VTUTF8TYPE: 915 AddUnicodeString2 ( 916 "eng", 917 gTerminalComponentName.SupportedLanguages, 918 &TerminalDevice->ControllerNameTable, 919 (CHAR16 *)L"VT-UTF8 Serial Console", 920 TRUE 921 ); 922 AddUnicodeString2 ( 923 "en", 924 gTerminalComponentName2.SupportedLanguages, 925 &TerminalDevice->ControllerNameTable, 926 (CHAR16 *)L"VT-UTF8 Serial Console", 927 FALSE 928 ); 929 930 break; 931 932 case TTYTERMTYPE: 933 AddUnicodeString2 ( 934 "eng", 935 gTerminalComponentName.SupportedLanguages, 936 &TerminalDevice->ControllerNameTable, 937 (CHAR16 *)L"Tty Terminal Serial Console", 938 TRUE 939 ); 940 AddUnicodeString2 ( 941 "en", 942 gTerminalComponentName2.SupportedLanguages, 943 &TerminalDevice->ControllerNameTable, 944 (CHAR16 *)L"Tty Terminal Serial Console", 945 FALSE 946 ); 947 948 break; 949 } 950 951 // 952 // Build the device path for the child device 953 // 954 Status = SetTerminalDevicePath ( 955 TerminalDevice->TerminalType, 956 ParentDevicePath, 957 &TerminalDevice->DevicePath 958 ); 959 if (EFI_ERROR (Status)) { 960 goto Error; 961 } 962 963 Status = TerminalConOutReset (SimpleTextOutput, FALSE); 964 if (EFI_ERROR (Status)) { 965 goto ReportError; 966 } 967 968 Status = TerminalConOutSetMode (SimpleTextOutput, 0); 969 if (EFI_ERROR (Status)) { 970 goto ReportError; 971 } 972 973 Status = TerminalConOutEnableCursor (SimpleTextOutput, TRUE); 974 if (EFI_ERROR (Status)) { 975 goto ReportError; 976 } 977 978 Status = gBS->CreateEvent ( 979 EVT_TIMER | EVT_NOTIFY_SIGNAL, 980 TPL_NOTIFY, 981 TerminalConInTimerHandler, 982 TerminalDevice, 983 &TerminalDevice->TimerEvent 984 ); 985 ASSERT_EFI_ERROR (Status); 986 987 Status = gBS->SetTimer ( 988 TerminalDevice->TimerEvent, 989 TimerPeriodic, 990 KEYBOARD_TIMER_INTERVAL 991 ); 992 ASSERT_EFI_ERROR (Status); 993 994 Status = gBS->CreateEvent ( 995 EVT_TIMER, 996 TPL_CALLBACK, 997 NULL, 998 NULL, 999 &TerminalDevice->TwoSecondTimeOut 1000 ); 1001 ASSERT_EFI_ERROR (Status); 1002 1003 Status = gBS->InstallProtocolInterface ( 1004 &TerminalDevice->Handle, 1005 &gEfiDevicePathProtocolGuid, 1006 EFI_NATIVE_INTERFACE, 1007 TerminalDevice->DevicePath 1008 ); 1009 if (EFI_ERROR (Status)) { 1010 goto Error; 1011 } 1012 1013 // 1014 // Register the Parent-Child relationship via 1015 // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. 1016 // 1017 Status = gBS->OpenProtocol ( 1018 Controller, 1019 &gEfiSerialIoProtocolGuid, 1020 (VOID **) &TerminalDevice->SerialIo, 1021 This->DriverBindingHandle, 1022 TerminalDevice->Handle, 1023 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 1024 ); 1025 if (EFI_ERROR (Status)) { 1026 goto Error; 1027 } 1028 } 1029 1030 // 1031 // Find the child handle, and get its TerminalDevice private data 1032 // 1033 Status = gBS->OpenProtocolInformation ( 1034 Controller, 1035 &gEfiSerialIoProtocolGuid, 1036 &OpenInfoBuffer, 1037 &EntryCount 1038 ); 1039 if (!EFI_ERROR (Status)) { 1040 Status = EFI_NOT_FOUND; 1041 ASSERT (OpenInfoBuffer != NULL); 1042 for (Index = 0; Index < EntryCount; Index++) { 1043 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { 1044 // 1045 // Find the child terminal handle. 1046 // Test whether the SimpleTxtIn and SimpleTxtOut have been published 1047 // 1048 Status = gBS->OpenProtocol ( 1049 OpenInfoBuffer[Index].ControllerHandle, 1050 &gEfiSimpleTextInProtocolGuid, 1051 (VOID **) &SimpleTextInput, 1052 This->DriverBindingHandle, 1053 OpenInfoBuffer[Index].ControllerHandle, 1054 EFI_OPEN_PROTOCOL_GET_PROTOCOL 1055 ); 1056 if (!EFI_ERROR (Status)) { 1057 SimTxtInInstalled = TRUE; 1058 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput); 1059 } 1060 1061 Status = gBS->OpenProtocol ( 1062 OpenInfoBuffer[Index].ControllerHandle, 1063 &gEfiSimpleTextOutProtocolGuid, 1064 (VOID **) &SimpleTextOutput, 1065 This->DriverBindingHandle, 1066 OpenInfoBuffer[Index].ControllerHandle, 1067 EFI_OPEN_PROTOCOL_GET_PROTOCOL 1068 ); 1069 if (!EFI_ERROR (Status)) { 1070 SimTxtOutInstalled = TRUE; 1071 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput); 1072 } 1073 Status = EFI_SUCCESS; 1074 break; 1075 } 1076 } 1077 1078 FreePool (OpenInfoBuffer); 1079 if (EFI_ERROR (Status)) { 1080 goto ReportError; 1081 } 1082 } else { 1083 goto ReportError; 1084 } 1085 1086 ASSERT (TerminalDevice != NULL); 1087 // 1088 // Only do the reset if the device path is in the Conout variable 1089 // 1090 if (ConInSelected && !SimTxtInInstalled) { 1091 Status = TerminalDevice->SimpleInput.Reset ( 1092 &TerminalDevice->SimpleInput, 1093 FALSE 1094 ); 1095 if (EFI_ERROR (Status)) { 1096 // 1097 // Need to report Error Code first 1098 // 1099 goto ReportError; 1100 } 1101 } 1102 1103 // 1104 // Only output the configure string to remote terminal if the device path 1105 // is in the Conout variable 1106 // 1107 if (ConOutSelected && !SimTxtOutInstalled) { 1108 Status = TerminalDevice->SimpleTextOutput.SetAttribute ( 1109 &TerminalDevice->SimpleTextOutput, 1110 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK) 1111 ); 1112 if (EFI_ERROR (Status)) { 1113 goto ReportError; 1114 } 1115 1116 Status = TerminalDevice->SimpleTextOutput.Reset ( 1117 &TerminalDevice->SimpleTextOutput, 1118 FALSE 1119 ); 1120 if (EFI_ERROR (Status)) { 1121 goto ReportError; 1122 } 1123 1124 Status = TerminalDevice->SimpleTextOutput.SetMode ( 1125 &TerminalDevice->SimpleTextOutput, 1126 0 1127 ); 1128 if (EFI_ERROR (Status)) { 1129 goto ReportError; 1130 } 1131 1132 Status = TerminalDevice->SimpleTextOutput.EnableCursor ( 1133 &TerminalDevice->SimpleTextOutput, 1134 TRUE 1135 ); 1136 if (EFI_ERROR (Status)) { 1137 goto ReportError; 1138 } 1139 } 1140 1141 // 1142 // Simple In/Out Protocol will not be installed onto the handle if the 1143 // device path to the handle is not present in the ConIn/ConOut 1144 // environment variable. But If RemainingDevicePath is NULL, then always 1145 // produce both Simple In and Simple Text Output Protocols. This is required 1146 // for the connect all sequences to make sure all possible consoles are 1147 // produced no matter what the current values of ConIn, ConOut, or StdErr are. 1148 // 1149 if (!SimTxtInInstalled && (ConInSelected || NullRemaining)) { 1150 Status = gBS->InstallMultipleProtocolInterfaces ( 1151 &TerminalDevice->Handle, 1152 &gEfiSimpleTextInProtocolGuid, 1153 &TerminalDevice->SimpleInput, 1154 &gEfiSimpleTextInputExProtocolGuid, 1155 &TerminalDevice->SimpleInputEx, 1156 NULL 1157 ); 1158 if (EFI_ERROR (Status)) { 1159 goto Error; 1160 } 1161 } 1162 1163 if (!SimTxtOutInstalled && (ConOutSelected || NullRemaining)) { 1164 Status = gBS->InstallProtocolInterface ( 1165 &TerminalDevice->Handle, 1166 &gEfiSimpleTextOutProtocolGuid, 1167 EFI_NATIVE_INTERFACE, 1168 &TerminalDevice->SimpleTextOutput 1169 ); 1170 if (EFI_ERROR (Status)) { 1171 goto Error; 1172 } 1173 } 1174 1175 return EFI_SUCCESS; 1176 1177 ReportError: 1178 // 1179 // Report error code before exiting 1180 // 1181 DevicePath = ParentDevicePath; 1182 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 1183 EFI_ERROR_CODE | EFI_ERROR_MINOR, 1184 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR), 1185 DevicePath 1186 ); 1187 1188 Error: 1189 // 1190 // Use the Stop() function to free all resources allocated in Start() 1191 // 1192 if (TerminalDevice != NULL) { 1193 1194 if (TerminalDevice->Handle != NULL) { 1195 This->Stop (This, Controller, 1, &TerminalDevice->Handle); 1196 } else { 1197 1198 if (TerminalDevice->TwoSecondTimeOut != NULL) { 1199 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut); 1200 } 1201 1202 if (TerminalDevice->TimerEvent != NULL) { 1203 gBS->CloseEvent (TerminalDevice->TimerEvent); 1204 } 1205 1206 if (TerminalDevice->SimpleInput.WaitForKey != NULL) { 1207 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey); 1208 } 1209 1210 if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) { 1211 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx); 1212 } 1213 1214 TerminalFreeNotifyList (&TerminalDevice->NotifyList); 1215 1216 if (TerminalDevice->RawFiFo != NULL) { 1217 FreePool (TerminalDevice->RawFiFo); 1218 } 1219 if (TerminalDevice->UnicodeFiFo != NULL) { 1220 FreePool (TerminalDevice->UnicodeFiFo); 1221 } 1222 if (TerminalDevice->EfiKeyFiFo != NULL) { 1223 FreePool (TerminalDevice->EfiKeyFiFo); 1224 } 1225 1226 if (TerminalDevice->ControllerNameTable != NULL) { 1227 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable); 1228 } 1229 1230 if (TerminalDevice->DevicePath != NULL) { 1231 FreePool (TerminalDevice->DevicePath); 1232 } 1233 1234 if (TerminalDevice->TerminalConsoleModeData != NULL) { 1235 FreePool (TerminalDevice->TerminalConsoleModeData); 1236 } 1237 1238 FreePool (TerminalDevice); 1239 } 1240 } 1241 1242 This->Stop (This, Controller, 0, NULL); 1243 1244 return Status; 1245 } 1246 1247 /** 1248 Stop this driver on Controller by closing Simple Text In, Simple Text 1249 In Ex, Simple Text Out protocol, and removing parent device path from 1250 Console Device Environment Variables. 1251 1252 @param This Protocol instance pointer. 1253 @param Controller Handle of device to stop driver on 1254 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of 1255 children is zero stop the entire bus driver. 1256 @param ChildHandleBuffer List of Child Handles to Stop. 1257 1258 @retval EFI_SUCCESS This driver is removed Controller. 1259 @retval other This driver could not be removed from this device. 1260 1261 **/ 1262 EFI_STATUS 1263 EFIAPI 1264 TerminalDriverBindingStop ( 1265 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1266 IN EFI_HANDLE Controller, 1267 IN UINTN NumberOfChildren, 1268 IN EFI_HANDLE *ChildHandleBuffer 1269 ) 1270 { 1271 EFI_STATUS Status; 1272 UINTN Index; 1273 BOOLEAN AllChildrenStopped; 1274 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput; 1275 TERMINAL_DEV *TerminalDevice; 1276 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; 1277 EFI_SERIAL_IO_PROTOCOL *SerialIo; 1278 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 1279 1280 Status = gBS->HandleProtocol ( 1281 Controller, 1282 &gEfiDevicePathProtocolGuid, 1283 (VOID **) &DevicePath 1284 ); 1285 if (EFI_ERROR (Status)) { 1286 return Status; 1287 } 1288 1289 // 1290 // Complete all outstanding transactions to Controller. 1291 // Don't allow any new transaction to Controller to be started. 1292 // 1293 if (NumberOfChildren == 0) { 1294 // 1295 // Close the bus driver 1296 // 1297 Status = gBS->OpenProtocol ( 1298 Controller, 1299 &gEfiCallerIdGuid, 1300 (VOID **) &ParentDevicePath, 1301 This->DriverBindingHandle, 1302 Controller, 1303 EFI_OPEN_PROTOCOL_GET_PROTOCOL 1304 ); 1305 if (!EFI_ERROR (Status)) { 1306 // 1307 // Remove Parent Device Path from 1308 // the Console Device Environment Variables 1309 // 1310 TerminalRemoveConsoleDevVariable (L"ConInDev", ParentDevicePath); 1311 TerminalRemoveConsoleDevVariable (L"ConOutDev", ParentDevicePath); 1312 TerminalRemoveConsoleDevVariable (L"ErrOutDev", ParentDevicePath); 1313 1314 // 1315 // Uninstall the Terminal Driver's GUID Tag from the Serial controller 1316 // 1317 Status = gBS->UninstallMultipleProtocolInterfaces ( 1318 Controller, 1319 &gEfiCallerIdGuid, 1320 ParentDevicePath, 1321 NULL 1322 ); 1323 1324 // 1325 // Free the ParentDevicePath that was duplicated in Start() 1326 // 1327 if (!EFI_ERROR (Status)) { 1328 FreePool (ParentDevicePath); 1329 } 1330 } 1331 1332 gBS->CloseProtocol ( 1333 Controller, 1334 &gEfiSerialIoProtocolGuid, 1335 This->DriverBindingHandle, 1336 Controller 1337 ); 1338 1339 gBS->CloseProtocol ( 1340 Controller, 1341 &gEfiDevicePathProtocolGuid, 1342 This->DriverBindingHandle, 1343 Controller 1344 ); 1345 1346 return EFI_SUCCESS; 1347 } 1348 1349 AllChildrenStopped = TRUE; 1350 1351 for (Index = 0; Index < NumberOfChildren; Index++) { 1352 1353 Status = gBS->OpenProtocol ( 1354 ChildHandleBuffer[Index], 1355 &gEfiSimpleTextOutProtocolGuid, 1356 (VOID **) &SimpleTextOutput, 1357 This->DriverBindingHandle, 1358 ChildHandleBuffer[Index], 1359 EFI_OPEN_PROTOCOL_GET_PROTOCOL 1360 ); 1361 if (!EFI_ERROR (Status)) { 1362 1363 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput); 1364 1365 gBS->CloseProtocol ( 1366 Controller, 1367 &gEfiSerialIoProtocolGuid, 1368 This->DriverBindingHandle, 1369 ChildHandleBuffer[Index] 1370 ); 1371 1372 Status = gBS->UninstallMultipleProtocolInterfaces ( 1373 ChildHandleBuffer[Index], 1374 &gEfiSimpleTextInProtocolGuid, 1375 &TerminalDevice->SimpleInput, 1376 &gEfiSimpleTextInputExProtocolGuid, 1377 &TerminalDevice->SimpleInputEx, 1378 &gEfiSimpleTextOutProtocolGuid, 1379 &TerminalDevice->SimpleTextOutput, 1380 &gEfiDevicePathProtocolGuid, 1381 TerminalDevice->DevicePath, 1382 NULL 1383 ); 1384 if (EFI_ERROR (Status)) { 1385 gBS->OpenProtocol ( 1386 Controller, 1387 &gEfiSerialIoProtocolGuid, 1388 (VOID **) &SerialIo, 1389 This->DriverBindingHandle, 1390 ChildHandleBuffer[Index], 1391 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 1392 ); 1393 } else { 1394 1395 if (TerminalDevice->ControllerNameTable != NULL) { 1396 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable); 1397 } 1398 1399 gBS->CloseEvent (TerminalDevice->TimerEvent); 1400 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut); 1401 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey); 1402 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx); 1403 TerminalFreeNotifyList (&TerminalDevice->NotifyList); 1404 FreePool (TerminalDevice->DevicePath); 1405 if (TerminalDevice->TerminalConsoleModeData != NULL) { 1406 FreePool (TerminalDevice->TerminalConsoleModeData); 1407 } 1408 FreePool (TerminalDevice); 1409 } 1410 } 1411 1412 if (EFI_ERROR (Status)) { 1413 AllChildrenStopped = FALSE; 1414 } 1415 } 1416 1417 if (!AllChildrenStopped) { 1418 return EFI_DEVICE_ERROR; 1419 } 1420 1421 return EFI_SUCCESS; 1422 } 1423 1424 /** 1425 Update terminal device path in Console Device Environment Variables. 1426 1427 @param VariableName The Console Device Environment Variable. 1428 @param ParentDevicePath The terminal device path to be updated. 1429 1430 **/ 1431 VOID 1432 TerminalUpdateConsoleDevVariable ( 1433 IN CHAR16 *VariableName, 1434 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath 1435 ) 1436 { 1437 EFI_STATUS Status; 1438 UINTN NameSize; 1439 UINTN VariableSize; 1440 UINT8 TerminalType; 1441 EFI_DEVICE_PATH_PROTOCOL *Variable; 1442 EFI_DEVICE_PATH_PROTOCOL *NewVariable; 1443 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; 1444 EDKII_SET_VARIABLE_STATUS *SetVariableStatus; 1445 1446 // 1447 // Get global variable and its size according to the name given. 1448 // 1449 GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL); 1450 if (Variable == NULL) { 1451 return; 1452 } 1453 1454 // 1455 // Append terminal device path onto the variable. 1456 // 1457 for (TerminalType = PCANSITYPE; TerminalType <= TTYTERMTYPE; TerminalType++) { 1458 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath); 1459 NewVariable = AppendDevicePathInstance (Variable, TempDevicePath); 1460 ASSERT (NewVariable != NULL); 1461 if (Variable != NULL) { 1462 FreePool (Variable); 1463 } 1464 1465 if (TempDevicePath != NULL) { 1466 FreePool (TempDevicePath); 1467 } 1468 1469 Variable = NewVariable; 1470 } 1471 1472 VariableSize = GetDevicePathSize (Variable); 1473 1474 Status = gRT->SetVariable ( 1475 VariableName, 1476 &gEfiGlobalVariableGuid, 1477 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 1478 VariableSize, 1479 Variable 1480 ); 1481 1482 if (EFI_ERROR (Status)) { 1483 NameSize = StrSize (VariableName); 1484 SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize); 1485 if (SetVariableStatus != NULL) { 1486 CopyGuid (&SetVariableStatus->Guid, &gEfiGlobalVariableGuid); 1487 SetVariableStatus->NameSize = NameSize; 1488 SetVariableStatus->DataSize = VariableSize; 1489 SetVariableStatus->SetStatus = Status; 1490 SetVariableStatus->Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; 1491 CopyMem (SetVariableStatus + 1, VariableName, NameSize); 1492 CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Variable, VariableSize); 1493 1494 REPORT_STATUS_CODE_EX ( 1495 EFI_ERROR_CODE, 1496 PcdGet32 (PcdErrorCodeSetVariable), 1497 0, 1498 NULL, 1499 &gEdkiiStatusCodeDataTypeVariableGuid, 1500 SetVariableStatus, 1501 sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize 1502 ); 1503 1504 FreePool (SetVariableStatus); 1505 } 1506 } 1507 1508 FreePool (Variable); 1509 1510 return ; 1511 } 1512 1513 1514 /** 1515 Remove terminal device path from Console Device Environment Variables. 1516 1517 @param VariableName Console Device Environment Variables. 1518 @param ParentDevicePath The terminal device path to be updated. 1519 1520 **/ 1521 VOID 1522 TerminalRemoveConsoleDevVariable ( 1523 IN CHAR16 *VariableName, 1524 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath 1525 ) 1526 { 1527 EFI_STATUS Status; 1528 BOOLEAN FoundOne; 1529 BOOLEAN Match; 1530 UINTN VariableSize; 1531 UINTN InstanceSize; 1532 UINT8 TerminalType; 1533 EFI_DEVICE_PATH_PROTOCOL *Instance; 1534 EFI_DEVICE_PATH_PROTOCOL *Variable; 1535 EFI_DEVICE_PATH_PROTOCOL *OriginalVariable; 1536 EFI_DEVICE_PATH_PROTOCOL *NewVariable; 1537 EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable; 1538 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; 1539 1540 Instance = NULL; 1541 1542 // 1543 // Get global variable and its size according to the name given. 1544 // 1545 GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL); 1546 if (Variable == NULL) { 1547 return ; 1548 } 1549 1550 FoundOne = FALSE; 1551 OriginalVariable = Variable; 1552 NewVariable = NULL; 1553 1554 // 1555 // Get first device path instance from Variable 1556 // 1557 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize); 1558 if (Instance == NULL) { 1559 FreePool (OriginalVariable); 1560 return ; 1561 } 1562 // 1563 // Loop through all the device path instances of Variable 1564 // 1565 do { 1566 // 1567 // Loop through all the terminal types that this driver supports 1568 // 1569 Match = FALSE; 1570 for (TerminalType = PCANSITYPE; TerminalType <= TTYTERMTYPE; TerminalType++) { 1571 1572 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath); 1573 1574 // 1575 // Compare the generated device path to the current device path instance 1576 // 1577 if (TempDevicePath != NULL) { 1578 if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) { 1579 Match = TRUE; 1580 FoundOne = TRUE; 1581 } 1582 1583 FreePool (TempDevicePath); 1584 } 1585 } 1586 // 1587 // If a match was not found, then keep the current device path instance 1588 // 1589 if (!Match) { 1590 SavedNewVariable = NewVariable; 1591 NewVariable = AppendDevicePathInstance (NewVariable, Instance); 1592 if (SavedNewVariable != NULL) { 1593 FreePool (SavedNewVariable); 1594 } 1595 } 1596 // 1597 // Get next device path instance from Variable 1598 // 1599 FreePool (Instance); 1600 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize); 1601 } while (Instance != NULL); 1602 1603 FreePool (OriginalVariable); 1604 1605 if (FoundOne) { 1606 VariableSize = GetDevicePathSize (NewVariable); 1607 1608 Status = gRT->SetVariable ( 1609 VariableName, 1610 &gEfiGlobalVariableGuid, 1611 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 1612 VariableSize, 1613 NewVariable 1614 ); 1615 // 1616 // Shrinking variable with existing variable driver implementation shouldn't fail. 1617 // 1618 ASSERT_EFI_ERROR (Status); 1619 } 1620 1621 if (NewVariable != NULL) { 1622 FreePool (NewVariable); 1623 } 1624 1625 return ; 1626 } 1627 1628 /** 1629 Build terminal device path according to terminal type. 1630 1631 @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8. 1632 @param ParentDevicePath Parent device path. 1633 @param TerminalDevicePath Returned terminal device path, if building successfully. 1634 1635 @retval EFI_UNSUPPORTED Terminal does not belong to the supported type. 1636 @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed. 1637 @retval EFI_SUCCESS Build terminal device path successfully. 1638 1639 **/ 1640 EFI_STATUS 1641 SetTerminalDevicePath ( 1642 IN UINT8 TerminalType, 1643 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, 1644 OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath 1645 ) 1646 { 1647 VENDOR_DEVICE_PATH Node; 1648 1649 *TerminalDevicePath = NULL; 1650 Node.Header.Type = MESSAGING_DEVICE_PATH; 1651 Node.Header.SubType = MSG_VENDOR_DP; 1652 1653 // 1654 // Generate terminal device path node according to terminal type. 1655 // 1656 switch (TerminalType) { 1657 1658 case PCANSITYPE: 1659 CopyGuid (&Node.Guid, &gEfiPcAnsiGuid); 1660 break; 1661 1662 case VT100TYPE: 1663 CopyGuid (&Node.Guid, &gEfiVT100Guid); 1664 break; 1665 1666 case VT100PLUSTYPE: 1667 CopyGuid (&Node.Guid, &gEfiVT100PlusGuid); 1668 break; 1669 1670 case VTUTF8TYPE: 1671 CopyGuid (&Node.Guid, &gEfiVTUTF8Guid); 1672 break; 1673 1674 case TTYTERMTYPE: 1675 CopyGuid (&Node.Guid, &gEfiTtyTermGuid); 1676 break; 1677 1678 default: 1679 return EFI_UNSUPPORTED; 1680 } 1681 1682 // 1683 // Get VENDOR_DEVCIE_PATH size and put into Node.Header 1684 // 1685 SetDevicePathNodeLength ( 1686 &Node.Header, 1687 sizeof (VENDOR_DEVICE_PATH) 1688 ); 1689 1690 // 1691 // Append the terminal node onto parent device path 1692 // to generate a complete terminal device path. 1693 // 1694 *TerminalDevicePath = AppendDevicePathNode ( 1695 ParentDevicePath, 1696 (EFI_DEVICE_PATH_PROTOCOL *) &Node 1697 ); 1698 if (*TerminalDevicePath == NULL) { 1699 return EFI_OUT_OF_RESOURCES; 1700 } 1701 1702 return EFI_SUCCESS; 1703 } 1704 1705 /** 1706 The user Entry Point for module Terminal. The user code starts with this function. 1707 1708 @param ImageHandle The firmware allocated handle for the EFI image. 1709 @param SystemTable A pointer to the EFI System Table. 1710 1711 @retval EFI_SUCCESS The entry point is executed successfully. 1712 @retval other Some error occurs when executing this entry point. 1713 1714 **/ 1715 EFI_STATUS 1716 EFIAPI 1717 InitializeTerminal( 1718 IN EFI_HANDLE ImageHandle, 1719 IN EFI_SYSTEM_TABLE *SystemTable 1720 ) 1721 { 1722 EFI_STATUS Status; 1723 1724 // 1725 // Install driver model protocol(s). 1726 // 1727 Status = EfiLibInstallDriverBindingComponentName2 ( 1728 ImageHandle, 1729 SystemTable, 1730 &gTerminalDriverBinding, 1731 ImageHandle, 1732 &gTerminalComponentName, 1733 &gTerminalComponentName2 1734 ); 1735 ASSERT_EFI_ERROR (Status); 1736 1737 return Status; 1738 } 1739 1740 /** 1741 Check if the device supports hot-plug through its device path. 1742 1743 This function could be updated to check more types of Hot Plug devices. 1744 Currently, it checks USB and PCCard device. 1745 1746 @param DevicePath Pointer to device's device path. 1747 1748 @retval TRUE The devcie is a hot-plug device 1749 @retval FALSE The devcie is not a hot-plug device. 1750 1751 **/ 1752 BOOLEAN 1753 IsHotPlugDevice ( 1754 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath 1755 ) 1756 { 1757 EFI_DEVICE_PATH_PROTOCOL *CheckDevicePath; 1758 1759 CheckDevicePath = DevicePath; 1760 while (!IsDevicePathEnd (CheckDevicePath)) { 1761 // 1762 // Check device whether is hot plug device or not throught Device Path 1763 // 1764 if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) && 1765 (DevicePathSubType (CheckDevicePath) == MSG_USB_DP || 1766 DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP || 1767 DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)) { 1768 // 1769 // If Device is USB device 1770 // 1771 return TRUE; 1772 } 1773 if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) && 1774 (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP)) { 1775 // 1776 // If Device is PCCard 1777 // 1778 return TRUE; 1779 } 1780 1781 CheckDevicePath = NextDevicePathNode (CheckDevicePath); 1782 } 1783 1784 return FALSE; 1785 } 1786 1787