1/** @file 2 Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol. 3 4(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR> 5Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR> 6Copyright (C) 2016 Silicon Graphics, Inc. All rights reserved.<BR> 7This program and the accompanying materials 8are licensed and made available under the terms and conditions of the BSD License 9which accompanies this distribution. The full text of the license may be found at 10http://opensource.org/licenses/bsd-license.php 11 12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 15**/ 16 17#include "Terminal.h" 18 19 20/** 21 Reads the next keystroke from the input device. The WaitForKey Event can 22 be used to test for existence of a keystroke via WaitForEvent () call. 23 24 @param TerminalDevice Terminal driver private structure 25 @param KeyData A pointer to a buffer that is filled in with the 26 keystroke state data for the key that was 27 pressed. 28 29 @retval EFI_SUCCESS The keystroke information was returned. 30 @retval EFI_NOT_READY There was no keystroke data available. 31 @retval EFI_INVALID_PARAMETER KeyData is NULL. 32 33**/ 34EFI_STATUS 35ReadKeyStrokeWorker ( 36 IN TERMINAL_DEV *TerminalDevice, 37 OUT EFI_KEY_DATA *KeyData 38 ) 39{ 40 if (KeyData == NULL) { 41 return EFI_INVALID_PARAMETER; 42 } 43 44 if (!EfiKeyFiFoRemoveOneKey (TerminalDevice, &KeyData->Key)) { 45 return EFI_NOT_READY; 46 } 47 48 KeyData->KeyState.KeyShiftState = 0; 49 KeyData->KeyState.KeyToggleState = 0; 50 51 52 return EFI_SUCCESS; 53 54} 55 56/** 57 Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset(). 58 This driver only perform dependent serial device reset regardless of 59 the value of ExtendeVerification 60 61 @param This Indicates the calling context. 62 @param ExtendedVerification Skip by this driver. 63 64 @retval EFI_SUCCESS The reset operation succeeds. 65 @retval EFI_DEVICE_ERROR The dependent serial port reset fails. 66 67**/ 68EFI_STATUS 69EFIAPI 70TerminalConInReset ( 71 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, 72 IN BOOLEAN ExtendedVerification 73 ) 74{ 75 EFI_STATUS Status; 76 TERMINAL_DEV *TerminalDevice; 77 78 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This); 79 80 // 81 // Report progress code here 82 // 83 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 84 EFI_PROGRESS_CODE, 85 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_RESET), 86 TerminalDevice->DevicePath 87 ); 88 89 Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo); 90 91 // 92 // Make all the internal buffer empty for keys 93 // 94 TerminalDevice->RawFiFo->Head = TerminalDevice->RawFiFo->Tail; 95 TerminalDevice->UnicodeFiFo->Head = TerminalDevice->UnicodeFiFo->Tail; 96 TerminalDevice->EfiKeyFiFo->Head = TerminalDevice->EfiKeyFiFo->Tail; 97 TerminalDevice->EfiKeyFiFoForNotify->Head = TerminalDevice->EfiKeyFiFoForNotify->Tail; 98 99 if (EFI_ERROR (Status)) { 100 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 101 EFI_ERROR_CODE | EFI_ERROR_MINOR, 102 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR), 103 TerminalDevice->DevicePath 104 ); 105 } 106 107 return Status; 108} 109 110/** 111 Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke(). 112 113 @param This Indicates the calling context. 114 @param Key A pointer to a buffer that is filled in with the 115 keystroke information for the key that was sent 116 from terminal. 117 118 @retval EFI_SUCCESS The keystroke information is returned successfully. 119 @retval EFI_NOT_READY There is no keystroke data available. 120 @retval EFI_DEVICE_ERROR The dependent serial device encounters error. 121 122**/ 123EFI_STATUS 124EFIAPI 125TerminalConInReadKeyStroke ( 126 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, 127 OUT EFI_INPUT_KEY *Key 128 ) 129{ 130 TERMINAL_DEV *TerminalDevice; 131 EFI_STATUS Status; 132 EFI_KEY_DATA KeyData; 133 134 // 135 // get TERMINAL_DEV from "This" parameter. 136 // 137 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This); 138 139 Status = ReadKeyStrokeWorker (TerminalDevice, &KeyData); 140 if (EFI_ERROR (Status)) { 141 return Status; 142 } 143 144 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY)); 145 146 return EFI_SUCCESS; 147 148} 149 150/** 151 Check if the key already has been registered. 152 153 If both RegsiteredData and InputData is NULL, then ASSERT(). 154 155 @param RegsiteredData A pointer to a buffer that is filled in with the 156 keystroke state data for the key that was 157 registered. 158 @param InputData A pointer to a buffer that is filled in with the 159 keystroke state data for the key that was 160 pressed. 161 162 @retval TRUE Key be pressed matches a registered key. 163 @retval FALSE Match failed. 164 165**/ 166BOOLEAN 167IsKeyRegistered ( 168 IN EFI_KEY_DATA *RegsiteredData, 169 IN EFI_KEY_DATA *InputData 170 ) 171{ 172 ASSERT (RegsiteredData != NULL && InputData != NULL); 173 174 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) || 175 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) { 176 return FALSE; 177 } 178 179 return TRUE; 180} 181 182 183 184/** 185 Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event 186 Signal the event if there is key available 187 188 @param Event Indicates the event that invoke this function. 189 @param Context Indicates the calling context. 190 191**/ 192VOID 193EFIAPI 194TerminalConInWaitForKeyEx ( 195 IN EFI_EVENT Event, 196 IN VOID *Context 197 ) 198{ 199 TerminalConInWaitForKey (Event, Context); 200} 201 202// 203// Simple Text Input Ex protocol functions 204// 205 206/** 207 Reset the input device and optionally run diagnostics 208 209 @param This Protocol instance pointer. 210 @param ExtendedVerification Driver may perform diagnostics on reset. 211 212 @retval EFI_SUCCESS The device was reset. 213 @retval EFI_DEVICE_ERROR The device is not functioning properly and could 214 not be reset. 215 216**/ 217EFI_STATUS 218EFIAPI 219TerminalConInResetEx ( 220 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 221 IN BOOLEAN ExtendedVerification 222 ) 223{ 224 EFI_STATUS Status; 225 TERMINAL_DEV *TerminalDevice; 226 227 TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); 228 229 Status = TerminalDevice->SimpleInput.Reset (&TerminalDevice->SimpleInput, ExtendedVerification); 230 if (EFI_ERROR (Status)) { 231 return EFI_DEVICE_ERROR; 232 } 233 234 return EFI_SUCCESS; 235 236} 237 238 239/** 240 Reads the next keystroke from the input device. The WaitForKey Event can 241 be used to test for existence of a keystroke via WaitForEvent () call. 242 243 @param This Protocol instance pointer. 244 @param KeyData A pointer to a buffer that is filled in with the 245 keystroke state data for the key that was 246 pressed. 247 248 @retval EFI_SUCCESS The keystroke information was returned. 249 @retval EFI_NOT_READY There was no keystroke data available. 250 @retval EFI_DEVICE_ERROR The keystroke information was not returned due 251 to hardware errors. 252 @retval EFI_INVALID_PARAMETER KeyData is NULL. 253 254**/ 255EFI_STATUS 256EFIAPI 257TerminalConInReadKeyStrokeEx ( 258 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 259 OUT EFI_KEY_DATA *KeyData 260 ) 261{ 262 TERMINAL_DEV *TerminalDevice; 263 264 if (KeyData == NULL) { 265 return EFI_INVALID_PARAMETER; 266 } 267 268 TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); 269 270 return ReadKeyStrokeWorker (TerminalDevice, KeyData); 271 272} 273 274 275/** 276 Set certain state for the input device. 277 278 @param This Protocol instance pointer. 279 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the 280 state for the input device. 281 282 @retval EFI_SUCCESS The device state was set successfully. 283 @retval EFI_DEVICE_ERROR The device is not functioning correctly and 284 could not have the setting adjusted. 285 @retval EFI_UNSUPPORTED The device does not have the ability to set its 286 state. 287 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL. 288 289**/ 290EFI_STATUS 291EFIAPI 292TerminalConInSetState ( 293 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 294 IN EFI_KEY_TOGGLE_STATE *KeyToggleState 295 ) 296{ 297 if (KeyToggleState == NULL) { 298 return EFI_INVALID_PARAMETER; 299 } 300 301 if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) { 302 return EFI_UNSUPPORTED; 303 } 304 305 return EFI_SUCCESS; 306} 307 308 309/** 310 Register a notification function for a particular keystroke for the input device. 311 312 @param This Protocol instance pointer. 313 @param KeyData A pointer to a buffer that is filled in with the 314 keystroke information data for the key that was 315 pressed. 316 @param KeyNotificationFunction Points to the function to be called when the key 317 sequence is typed specified by KeyData. 318 @param NotifyHandle Points to the unique handle assigned to the 319 registered notification. 320 321 @retval EFI_SUCCESS The notification function was registered 322 successfully. 323 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data 324 structures. 325 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL. 326 327**/ 328EFI_STATUS 329EFIAPI 330TerminalConInRegisterKeyNotify ( 331 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 332 IN EFI_KEY_DATA *KeyData, 333 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, 334 OUT VOID **NotifyHandle 335 ) 336{ 337 TERMINAL_DEV *TerminalDevice; 338 TERMINAL_CONSOLE_IN_EX_NOTIFY *NewNotify; 339 LIST_ENTRY *Link; 340 LIST_ENTRY *NotifyList; 341 TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 342 343 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) { 344 return EFI_INVALID_PARAMETER; 345 } 346 347 TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); 348 349 // 350 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. 351 // 352 NotifyList = &TerminalDevice->NotifyList; 353 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) { 354 CurrentNotify = CR ( 355 Link, 356 TERMINAL_CONSOLE_IN_EX_NOTIFY, 357 NotifyEntry, 358 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE 359 ); 360 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { 361 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { 362 *NotifyHandle = CurrentNotify; 363 return EFI_SUCCESS; 364 } 365 } 366 } 367 368 // 369 // Allocate resource to save the notification function 370 // 371 NewNotify = (TERMINAL_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (TERMINAL_CONSOLE_IN_EX_NOTIFY)); 372 if (NewNotify == NULL) { 373 return EFI_OUT_OF_RESOURCES; 374 } 375 376 NewNotify->Signature = TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE; 377 NewNotify->KeyNotificationFn = KeyNotificationFunction; 378 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA)); 379 InsertTailList (&TerminalDevice->NotifyList, &NewNotify->NotifyEntry); 380 381 *NotifyHandle = NewNotify; 382 383 return EFI_SUCCESS; 384} 385 386 387/** 388 Remove a registered notification function from a particular keystroke. 389 390 @param This Protocol instance pointer. 391 @param NotificationHandle The handle of the notification function being 392 unregistered. 393 394 @retval EFI_SUCCESS The notification function was unregistered 395 successfully. 396 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid. 397 398**/ 399EFI_STATUS 400EFIAPI 401TerminalConInUnregisterKeyNotify ( 402 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 403 IN VOID *NotificationHandle 404 ) 405{ 406 TERMINAL_DEV *TerminalDevice; 407 LIST_ENTRY *Link; 408 TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 409 LIST_ENTRY *NotifyList; 410 411 if (NotificationHandle == NULL) { 412 return EFI_INVALID_PARAMETER; 413 } 414 415 TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); 416 417 NotifyList = &TerminalDevice->NotifyList; 418 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) { 419 CurrentNotify = CR ( 420 Link, 421 TERMINAL_CONSOLE_IN_EX_NOTIFY, 422 NotifyEntry, 423 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE 424 ); 425 if (CurrentNotify == NotificationHandle) { 426 // 427 // Remove the notification function from NotifyList and free resources 428 // 429 RemoveEntryList (&CurrentNotify->NotifyEntry); 430 431 gBS->FreePool (CurrentNotify); 432 return EFI_SUCCESS; 433 } 434 } 435 436 // 437 // Can not find the matching entry in database. 438 // 439 return EFI_INVALID_PARAMETER; 440} 441 442/** 443 Translate raw data into Unicode (according to different encode), and 444 translate Unicode into key information. (according to different standard). 445 446 @param TerminalDevice Terminal driver private structure. 447 448**/ 449VOID 450TranslateRawDataToEfiKey ( 451 IN TERMINAL_DEV *TerminalDevice 452 ) 453{ 454 switch (TerminalDevice->TerminalType) { 455 456 case PCANSITYPE: 457 case VT100TYPE: 458 case VT100PLUSTYPE: 459 case TTYTERMTYPE: 460 AnsiRawDataToUnicode (TerminalDevice); 461 UnicodeToEfiKey (TerminalDevice); 462 break; 463 464 case VTUTF8TYPE: 465 // 466 // Process all the raw data in the RawFIFO, 467 // put the processed key into UnicodeFIFO. 468 // 469 VTUTF8RawDataToUnicode (TerminalDevice); 470 471 // 472 // Translate all the Unicode data in the UnicodeFIFO to Efi key, 473 // then put into EfiKeyFIFO. 474 // 475 UnicodeToEfiKey (TerminalDevice); 476 477 break; 478 } 479} 480 481/** 482 Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event 483 Signal the event if there is key available 484 485 @param Event Indicates the event that invoke this function. 486 @param Context Indicates the calling context. 487 488**/ 489VOID 490EFIAPI 491TerminalConInWaitForKey ( 492 IN EFI_EVENT Event, 493 IN VOID *Context 494 ) 495{ 496 // 497 // Someone is waiting on the keystroke event, if there's 498 // a key pending, signal the event 499 // 500 if (!IsEfiKeyFiFoEmpty ((TERMINAL_DEV *) Context)) { 501 502 gBS->SignalEvent (Event); 503 } 504} 505 506/** 507 Timer handler to poll the key from serial. 508 509 @param Event Indicates the event that invoke this function. 510 @param Context Indicates the calling context. 511**/ 512VOID 513EFIAPI 514TerminalConInTimerHandler ( 515 IN EFI_EVENT Event, 516 IN VOID *Context 517 ) 518{ 519 EFI_STATUS Status; 520 TERMINAL_DEV *TerminalDevice; 521 UINT32 Control; 522 UINT8 Input; 523 EFI_SERIAL_IO_MODE *Mode; 524 EFI_SERIAL_IO_PROTOCOL *SerialIo; 525 UINTN SerialInTimeOut; 526 527 TerminalDevice = (TERMINAL_DEV *) Context; 528 529 SerialIo = TerminalDevice->SerialIo; 530 if (SerialIo == NULL) { 531 return ; 532 } 533 // 534 // if current timeout value for serial device is not identical with 535 // the value saved in TERMINAL_DEV structure, then recalculate the 536 // timeout value again and set serial attribute according to this value. 537 // 538 Mode = SerialIo->Mode; 539 if (Mode->Timeout != TerminalDevice->SerialInTimeOut) { 540 541 SerialInTimeOut = 0; 542 if (Mode->BaudRate != 0) { 543 // 544 // According to BAUD rate to calculate the timeout value. 545 // 546 SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate; 547 } 548 549 Status = SerialIo->SetAttributes ( 550 SerialIo, 551 Mode->BaudRate, 552 Mode->ReceiveFifoDepth, 553 (UINT32) SerialInTimeOut, 554 (EFI_PARITY_TYPE) (Mode->Parity), 555 (UINT8) Mode->DataBits, 556 (EFI_STOP_BITS_TYPE) (Mode->StopBits) 557 ); 558 559 if (EFI_ERROR (Status)) { 560 TerminalDevice->SerialInTimeOut = 0; 561 } else { 562 TerminalDevice->SerialInTimeOut = SerialInTimeOut; 563 } 564 } 565 // 566 // Check whether serial buffer is empty. 567 // Skip the key transfer loop only if the SerialIo protocol instance 568 // successfully reports EFI_SERIAL_INPUT_BUFFER_EMPTY. 569 // 570 Status = SerialIo->GetControl (SerialIo, &Control); 571 if (EFI_ERROR (Status) || ((Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) == 0)) { 572 // 573 // Fetch all the keys in the serial buffer, 574 // and insert the byte stream into RawFIFO. 575 // 576 while (!IsRawFiFoFull (TerminalDevice)) { 577 578 Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input); 579 580 if (EFI_ERROR (Status)) { 581 if (Status == EFI_DEVICE_ERROR) { 582 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 583 EFI_ERROR_CODE | EFI_ERROR_MINOR, 584 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_INPUT_ERROR), 585 TerminalDevice->DevicePath 586 ); 587 } 588 break; 589 } 590 591 RawFiFoInsertOneKey (TerminalDevice, Input); 592 } 593 } 594 595 // 596 // Translate all the raw data in RawFIFO into EFI Key, 597 // according to different terminal type supported. 598 // 599 TranslateRawDataToEfiKey (TerminalDevice); 600} 601 602/** 603 Process key notify. 604 605 @param Event Indicates the event that invoke this function. 606 @param Context Indicates the calling context. 607**/ 608VOID 609EFIAPI 610KeyNotifyProcessHandler ( 611 IN EFI_EVENT Event, 612 IN VOID *Context 613 ) 614{ 615 BOOLEAN HasKey; 616 TERMINAL_DEV *TerminalDevice; 617 EFI_INPUT_KEY Key; 618 EFI_KEY_DATA KeyData; 619 LIST_ENTRY *Link; 620 LIST_ENTRY *NotifyList; 621 TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 622 EFI_TPL OldTpl; 623 624 TerminalDevice = (TERMINAL_DEV *) Context; 625 626 // 627 // Invoke notification functions. 628 // 629 NotifyList = &TerminalDevice->NotifyList; 630 while (TRUE) { 631 // 632 // Enter critical section 633 // 634 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 635 HasKey = EfiKeyFiFoForNotifyRemoveOneKey (TerminalDevice->EfiKeyFiFoForNotify, &Key); 636 CopyMem (&KeyData.Key, &Key, sizeof (EFI_INPUT_KEY)); 637 KeyData.KeyState.KeyShiftState = 0; 638 KeyData.KeyState.KeyToggleState = 0; 639 // 640 // Leave critical section 641 // 642 gBS->RestoreTPL (OldTpl); 643 if (!HasKey) { 644 break; 645 } 646 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) { 647 CurrentNotify = CR (Link, TERMINAL_CONSOLE_IN_EX_NOTIFY, NotifyEntry, TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE); 648 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { 649 CurrentNotify->KeyNotificationFn (&KeyData); 650 } 651 } 652 } 653} 654 655/** 656 Get one key out of serial buffer. 657 658 @param SerialIo Serial I/O protocol attached to the serial device. 659 @param Output The fetched key. 660 661 @retval EFI_NOT_READY If serial buffer is empty. 662 @retval EFI_DEVICE_ERROR If reading serial buffer encounter error. 663 @retval EFI_SUCCESS If reading serial buffer successfully, put 664 the fetched key to the parameter output. 665 666**/ 667EFI_STATUS 668GetOneKeyFromSerial ( 669 EFI_SERIAL_IO_PROTOCOL *SerialIo, 670 UINT8 *Output 671 ) 672{ 673 EFI_STATUS Status; 674 UINTN Size; 675 676 Size = 1; 677 *Output = 0; 678 679 // 680 // Read one key from serial I/O device. 681 // 682 Status = SerialIo->Read (SerialIo, &Size, Output); 683 684 if (EFI_ERROR (Status)) { 685 686 if (Status == EFI_TIMEOUT) { 687 return EFI_NOT_READY; 688 } 689 690 return EFI_DEVICE_ERROR; 691 692 } 693 694 if (*Output == 0) { 695 return EFI_NOT_READY; 696 } 697 698 return EFI_SUCCESS; 699} 700 701/** 702 Insert one byte raw data into the Raw Data FIFO. 703 704 @param TerminalDevice Terminal driver private structure. 705 @param Input The key will be input. 706 707 @retval TRUE If insert successfully. 708 @retval FALSE If Raw Data buffer is full before key insertion, 709 and the key is lost. 710 711**/ 712BOOLEAN 713RawFiFoInsertOneKey ( 714 TERMINAL_DEV *TerminalDevice, 715 UINT8 Input 716 ) 717{ 718 UINT8 Tail; 719 720 Tail = TerminalDevice->RawFiFo->Tail; 721 722 if (IsRawFiFoFull (TerminalDevice)) { 723 // 724 // Raw FIFO is full 725 // 726 return FALSE; 727 } 728 729 TerminalDevice->RawFiFo->Data[Tail] = Input; 730 731 TerminalDevice->RawFiFo->Tail = (UINT8) ((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)); 732 733 return TRUE; 734} 735 736/** 737 Remove one pre-fetched key out of the Raw Data FIFO. 738 739 @param TerminalDevice Terminal driver private structure. 740 @param Output The key will be removed. 741 742 @retval TRUE If insert successfully. 743 @retval FALSE If Raw Data FIFO buffer is empty before remove operation. 744 745**/ 746BOOLEAN 747RawFiFoRemoveOneKey ( 748 TERMINAL_DEV *TerminalDevice, 749 UINT8 *Output 750 ) 751{ 752 UINT8 Head; 753 754 Head = TerminalDevice->RawFiFo->Head; 755 756 if (IsRawFiFoEmpty (TerminalDevice)) { 757 // 758 // FIFO is empty 759 // 760 *Output = 0; 761 return FALSE; 762 } 763 764 *Output = TerminalDevice->RawFiFo->Data[Head]; 765 766 TerminalDevice->RawFiFo->Head = (UINT8) ((Head + 1) % (RAW_FIFO_MAX_NUMBER + 1)); 767 768 return TRUE; 769} 770 771/** 772 Clarify whether Raw Data FIFO buffer is empty. 773 774 @param TerminalDevice Terminal driver private structure 775 776 @retval TRUE If Raw Data FIFO buffer is empty. 777 @retval FALSE If Raw Data FIFO buffer is not empty. 778 779**/ 780BOOLEAN 781IsRawFiFoEmpty ( 782 TERMINAL_DEV *TerminalDevice 783 ) 784{ 785 if (TerminalDevice->RawFiFo->Head == TerminalDevice->RawFiFo->Tail) { 786 return TRUE; 787 } else { 788 return FALSE; 789 } 790} 791 792/** 793 Clarify whether Raw Data FIFO buffer is full. 794 795 @param TerminalDevice Terminal driver private structure 796 797 @retval TRUE If Raw Data FIFO buffer is full. 798 @retval FALSE If Raw Data FIFO buffer is not full. 799 800**/ 801BOOLEAN 802IsRawFiFoFull ( 803 TERMINAL_DEV *TerminalDevice 804 ) 805{ 806 UINT8 Tail; 807 UINT8 Head; 808 809 Tail = TerminalDevice->RawFiFo->Tail; 810 Head = TerminalDevice->RawFiFo->Head; 811 812 if (((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)) == Head) { 813 814 return TRUE; 815 } 816 817 return FALSE; 818} 819 820/** 821 Insert one pre-fetched key into the FIFO buffer. 822 823 @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO. 824 @param Input The key will be input. 825 826 @retval TRUE If insert successfully. 827 @retval FALSE If FIFO buffer is full before key insertion, 828 and the key is lost. 829 830**/ 831BOOLEAN 832EfiKeyFiFoForNotifyInsertOneKey ( 833 EFI_KEY_FIFO *EfiKeyFiFo, 834 EFI_INPUT_KEY *Input 835 ) 836{ 837 UINT8 Tail; 838 839 Tail = EfiKeyFiFo->Tail; 840 841 if (IsEfiKeyFiFoForNotifyFull (EfiKeyFiFo)) { 842 // 843 // FIFO is full 844 // 845 return FALSE; 846 } 847 848 CopyMem (&EfiKeyFiFo->Data[Tail], Input, sizeof (EFI_INPUT_KEY)); 849 850 EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1)); 851 852 return TRUE; 853} 854 855/** 856 Remove one pre-fetched key out of the FIFO buffer. 857 858 @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO. 859 @param Output The key will be removed. 860 861 @retval TRUE If remove successfully. 862 @retval FALSE If FIFO buffer is empty before remove operation. 863 864**/ 865BOOLEAN 866EfiKeyFiFoForNotifyRemoveOneKey ( 867 EFI_KEY_FIFO *EfiKeyFiFo, 868 EFI_INPUT_KEY *Output 869 ) 870{ 871 UINT8 Head; 872 873 Head = EfiKeyFiFo->Head; 874 ASSERT (Head < FIFO_MAX_NUMBER + 1); 875 876 if (IsEfiKeyFiFoForNotifyEmpty (EfiKeyFiFo)) { 877 // 878 // FIFO is empty 879 // 880 Output->ScanCode = SCAN_NULL; 881 Output->UnicodeChar = 0; 882 return FALSE; 883 } 884 885 CopyMem (Output, &EfiKeyFiFo->Data[Head], sizeof (EFI_INPUT_KEY)); 886 887 EfiKeyFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1)); 888 889 return TRUE; 890} 891 892/** 893 Clarify whether FIFO buffer is empty. 894 895 @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO. 896 897 @retval TRUE If FIFO buffer is empty. 898 @retval FALSE If FIFO buffer is not empty. 899 900**/ 901BOOLEAN 902IsEfiKeyFiFoForNotifyEmpty ( 903 EFI_KEY_FIFO *EfiKeyFiFo 904 ) 905{ 906 if (EfiKeyFiFo->Head == EfiKeyFiFo->Tail) { 907 return TRUE; 908 } else { 909 return FALSE; 910 } 911} 912 913/** 914 Clarify whether FIFO buffer is full. 915 916 @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO. 917 918 @retval TRUE If FIFO buffer is full. 919 @retval FALSE If FIFO buffer is not full. 920 921**/ 922BOOLEAN 923IsEfiKeyFiFoForNotifyFull ( 924 EFI_KEY_FIFO *EfiKeyFiFo 925 ) 926{ 927 UINT8 Tail; 928 UINT8 Head; 929 930 Tail = EfiKeyFiFo->Tail; 931 Head = EfiKeyFiFo->Head; 932 933 if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) { 934 return TRUE; 935 } 936 937 return FALSE; 938} 939 940/** 941 Insert one pre-fetched key into the FIFO buffer. 942 943 @param TerminalDevice Terminal driver private structure. 944 @param Key The key will be input. 945 946 @retval TRUE If insert successfully. 947 @retval FALSE If FIFO buffer is full before key insertion, 948 and the key is lost. 949 950**/ 951BOOLEAN 952EfiKeyFiFoInsertOneKey ( 953 TERMINAL_DEV *TerminalDevice, 954 EFI_INPUT_KEY *Key 955 ) 956{ 957 UINT8 Tail; 958 LIST_ENTRY *Link; 959 LIST_ENTRY *NotifyList; 960 TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 961 EFI_KEY_DATA KeyData; 962 963 Tail = TerminalDevice->EfiKeyFiFo->Tail; 964 965 CopyMem (&KeyData.Key, Key, sizeof (EFI_INPUT_KEY)); 966 KeyData.KeyState.KeyShiftState = 0; 967 KeyData.KeyState.KeyToggleState = 0; 968 969 // 970 // Signal KeyNotify process event if this key pressed matches any key registered. 971 // 972 NotifyList = &TerminalDevice->NotifyList; 973 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) { 974 CurrentNotify = CR ( 975 Link, 976 TERMINAL_CONSOLE_IN_EX_NOTIFY, 977 NotifyEntry, 978 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE 979 ); 980 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { 981 // 982 // The key notification function needs to run at TPL_CALLBACK 983 // while current TPL is TPL_NOTIFY. It will be invoked in 984 // KeyNotifyProcessHandler() which runs at TPL_CALLBACK. 985 // 986 EfiKeyFiFoForNotifyInsertOneKey (TerminalDevice->EfiKeyFiFoForNotify, Key); 987 gBS->SignalEvent (TerminalDevice->KeyNotifyProcessEvent); 988 } 989 } 990 if (IsEfiKeyFiFoFull (TerminalDevice)) { 991 // 992 // Efi Key FIFO is full 993 // 994 return FALSE; 995 } 996 997 CopyMem (&TerminalDevice->EfiKeyFiFo->Data[Tail], Key, sizeof (EFI_INPUT_KEY)); 998 999 TerminalDevice->EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1)); 1000 1001 return TRUE; 1002} 1003 1004/** 1005 Remove one pre-fetched key out of the FIFO buffer. 1006 1007 @param TerminalDevice Terminal driver private structure. 1008 @param Output The key will be removed. 1009 1010 @retval TRUE If insert successfully. 1011 @retval FALSE If FIFO buffer is empty before remove operation. 1012 1013**/ 1014BOOLEAN 1015EfiKeyFiFoRemoveOneKey ( 1016 TERMINAL_DEV *TerminalDevice, 1017 EFI_INPUT_KEY *Output 1018 ) 1019{ 1020 UINT8 Head; 1021 1022 Head = TerminalDevice->EfiKeyFiFo->Head; 1023 ASSERT (Head < FIFO_MAX_NUMBER + 1); 1024 1025 if (IsEfiKeyFiFoEmpty (TerminalDevice)) { 1026 // 1027 // FIFO is empty 1028 // 1029 Output->ScanCode = SCAN_NULL; 1030 Output->UnicodeChar = 0; 1031 return FALSE; 1032 } 1033 1034 CopyMem (Output, &TerminalDevice->EfiKeyFiFo->Data[Head], sizeof (EFI_INPUT_KEY)); 1035 1036 TerminalDevice->EfiKeyFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1)); 1037 1038 return TRUE; 1039} 1040 1041/** 1042 Clarify whether FIFO buffer is empty. 1043 1044 @param TerminalDevice Terminal driver private structure 1045 1046 @retval TRUE If FIFO buffer is empty. 1047 @retval FALSE If FIFO buffer is not empty. 1048 1049**/ 1050BOOLEAN 1051IsEfiKeyFiFoEmpty ( 1052 TERMINAL_DEV *TerminalDevice 1053 ) 1054{ 1055 if (TerminalDevice->EfiKeyFiFo->Head == TerminalDevice->EfiKeyFiFo->Tail) { 1056 return TRUE; 1057 } else { 1058 return FALSE; 1059 } 1060} 1061 1062/** 1063 Clarify whether FIFO buffer is full. 1064 1065 @param TerminalDevice Terminal driver private structure 1066 1067 @retval TRUE If FIFO buffer is full. 1068 @retval FALSE If FIFO buffer is not full. 1069 1070**/ 1071BOOLEAN 1072IsEfiKeyFiFoFull ( 1073 TERMINAL_DEV *TerminalDevice 1074 ) 1075{ 1076 UINT8 Tail; 1077 UINT8 Head; 1078 1079 Tail = TerminalDevice->EfiKeyFiFo->Tail; 1080 Head = TerminalDevice->EfiKeyFiFo->Head; 1081 1082 if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) { 1083 1084 return TRUE; 1085 } 1086 1087 return FALSE; 1088} 1089 1090/** 1091 Insert one pre-fetched key into the Unicode FIFO buffer. 1092 1093 @param TerminalDevice Terminal driver private structure. 1094 @param Input The key will be input. 1095 1096 @retval TRUE If insert successfully. 1097 @retval FALSE If Unicode FIFO buffer is full before key insertion, 1098 and the key is lost. 1099 1100**/ 1101BOOLEAN 1102UnicodeFiFoInsertOneKey ( 1103 TERMINAL_DEV *TerminalDevice, 1104 UINT16 Input 1105 ) 1106{ 1107 UINT8 Tail; 1108 1109 Tail = TerminalDevice->UnicodeFiFo->Tail; 1110 ASSERT (Tail < FIFO_MAX_NUMBER + 1); 1111 1112 1113 if (IsUnicodeFiFoFull (TerminalDevice)) { 1114 // 1115 // Unicode FIFO is full 1116 // 1117 return FALSE; 1118 } 1119 1120 TerminalDevice->UnicodeFiFo->Data[Tail] = Input; 1121 1122 TerminalDevice->UnicodeFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1)); 1123 1124 return TRUE; 1125} 1126 1127/** 1128 Remove one pre-fetched key out of the Unicode FIFO buffer. 1129 The caller should guarantee that Unicode FIFO buffer is not empty 1130 by IsUnicodeFiFoEmpty (). 1131 1132 @param TerminalDevice Terminal driver private structure. 1133 @param Output The key will be removed. 1134 1135**/ 1136VOID 1137UnicodeFiFoRemoveOneKey ( 1138 TERMINAL_DEV *TerminalDevice, 1139 UINT16 *Output 1140 ) 1141{ 1142 UINT8 Head; 1143 1144 Head = TerminalDevice->UnicodeFiFo->Head; 1145 ASSERT (Head < FIFO_MAX_NUMBER + 1); 1146 1147 *Output = TerminalDevice->UnicodeFiFo->Data[Head]; 1148 1149 TerminalDevice->UnicodeFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1)); 1150} 1151 1152/** 1153 Clarify whether Unicode FIFO buffer is empty. 1154 1155 @param TerminalDevice Terminal driver private structure 1156 1157 @retval TRUE If Unicode FIFO buffer is empty. 1158 @retval FALSE If Unicode FIFO buffer is not empty. 1159 1160**/ 1161BOOLEAN 1162IsUnicodeFiFoEmpty ( 1163 TERMINAL_DEV *TerminalDevice 1164 ) 1165{ 1166 if (TerminalDevice->UnicodeFiFo->Head == TerminalDevice->UnicodeFiFo->Tail) { 1167 return TRUE; 1168 } else { 1169 return FALSE; 1170 } 1171} 1172 1173/** 1174 Clarify whether Unicode FIFO buffer is full. 1175 1176 @param TerminalDevice Terminal driver private structure 1177 1178 @retval TRUE If Unicode FIFO buffer is full. 1179 @retval FALSE If Unicode FIFO buffer is not full. 1180 1181**/ 1182BOOLEAN 1183IsUnicodeFiFoFull ( 1184 TERMINAL_DEV *TerminalDevice 1185 ) 1186{ 1187 UINT8 Tail; 1188 UINT8 Head; 1189 1190 Tail = TerminalDevice->UnicodeFiFo->Tail; 1191 Head = TerminalDevice->UnicodeFiFo->Head; 1192 1193 if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) { 1194 1195 return TRUE; 1196 } 1197 1198 return FALSE; 1199} 1200 1201/** 1202 Count Unicode FIFO buffer. 1203 1204 @param TerminalDevice Terminal driver private structure 1205 1206 @return The count in bytes of Unicode FIFO. 1207 1208**/ 1209UINT8 1210UnicodeFiFoGetKeyCount ( 1211 TERMINAL_DEV *TerminalDevice 1212 ) 1213{ 1214 UINT8 Tail; 1215 UINT8 Head; 1216 1217 Tail = TerminalDevice->UnicodeFiFo->Tail; 1218 Head = TerminalDevice->UnicodeFiFo->Head; 1219 1220 if (Tail >= Head) { 1221 return (UINT8) (Tail - Head); 1222 } else { 1223 return (UINT8) (Tail + FIFO_MAX_NUMBER + 1 - Head); 1224 } 1225} 1226 1227/** 1228 Update the Unicode characters from a terminal input device into EFI Keys FIFO. 1229 1230 @param TerminalDevice The terminal device to use to translate raw input into EFI Keys 1231 1232**/ 1233VOID 1234UnicodeToEfiKeyFlushState ( 1235 IN TERMINAL_DEV *TerminalDevice 1236 ) 1237{ 1238 EFI_INPUT_KEY Key; 1239 UINT32 InputState; 1240 1241 InputState = TerminalDevice->InputState; 1242 1243 if (IsEfiKeyFiFoFull (TerminalDevice)) { 1244 return; 1245 } 1246 1247 if ((InputState & INPUT_STATE_ESC) != 0) { 1248 Key.ScanCode = SCAN_ESC; 1249 Key.UnicodeChar = 0; 1250 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); 1251 } 1252 1253 if ((InputState & INPUT_STATE_CSI) != 0) { 1254 Key.ScanCode = SCAN_NULL; 1255 Key.UnicodeChar = CSI; 1256 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); 1257 } 1258 1259 if ((InputState & INPUT_STATE_LEFTOPENBRACKET) != 0) { 1260 Key.ScanCode = SCAN_NULL; 1261 Key.UnicodeChar = LEFTOPENBRACKET; 1262 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); 1263 } 1264 1265 if ((InputState & INPUT_STATE_O) != 0) { 1266 Key.ScanCode = SCAN_NULL; 1267 Key.UnicodeChar = 'O'; 1268 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); 1269 } 1270 1271 if ((InputState & INPUT_STATE_2) != 0) { 1272 Key.ScanCode = SCAN_NULL; 1273 Key.UnicodeChar = '2'; 1274 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); 1275 } 1276 1277 // 1278 // Cancel the timer. 1279 // 1280 gBS->SetTimer ( 1281 TerminalDevice->TwoSecondTimeOut, 1282 TimerCancel, 1283 0 1284 ); 1285 1286 TerminalDevice->InputState = INPUT_STATE_DEFAULT; 1287} 1288 1289 1290/** 1291 Converts a stream of Unicode characters from a terminal input device into EFI Keys that 1292 can be read through the Simple Input Protocol. 1293 1294 The table below shows the keyboard input mappings that this function supports. 1295 If the ESC sequence listed in one of the columns is presented, then it is translated 1296 into the corresponding EFI Scan Code. If a matching sequence is not found, then the raw 1297 key strokes are converted into EFI Keys. 1298 1299 2 seconds are allowed for an ESC sequence to be completed. If the ESC sequence is not 1300 completed in 2 seconds, then the raw key strokes of the partial ESC sequence are 1301 converted into EFI Keys. 1302 There is one special input sequence that will force the system to reset. 1303 This is ESC R ESC r ESC R. 1304 1305 Note: current implementation support terminal types include: PC ANSI, VT100+/VTUTF8, VT100. 1306 The table below is not same with UEFI Spec 2.3 Appendix B Table 201(not support ANSI X3.64 / 1307 DEC VT200-500 and extra support PC ANSI, VT100)since UEFI Table 201 is just an example. 1308 1309 Symbols used in table below 1310 =========================== 1311 ESC = 0x1B 1312 CSI = 0x9B 1313 DEL = 0x7f 1314 ^ = CTRL 1315 1316 +=========+======+===========+==========+==========+ 1317 | | EFI | UEFI 2.0 | | | 1318 | | Scan | | VT100+ | | 1319 | KEY | Code | PC ANSI | VTUTF8 | VT100 | 1320 +=========+======+===========+==========+==========+ 1321 | NULL | 0x00 | | | | 1322 | UP | 0x01 | ESC [ A | ESC [ A | ESC [ A | 1323 | DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B | 1324 | RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C | 1325 | LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D | 1326 | HOME | 0x05 | ESC [ H | ESC h | ESC [ H | 1327 | END | 0x06 | ESC [ F | ESC k | ESC [ K | 1328 | INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ | 1329 | | | ESC [ L | | ESC [ L | 1330 | DELETE | 0x08 | ESC [ X | ESC - | ESC [ P | 1331 | PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V | 1332 | | | | | ESC [ ? | 1333 | PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U | 1334 | | | | | ESC [ / | 1335 | F1 | 0x0B | ESC [ M | ESC 1 | ESC O P | 1336 | F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q | 1337 | F3 | 0x0D | ESC [ O | ESC 3 | ESC O w | 1338 | F4 | 0x0E | ESC [ P | ESC 4 | ESC O x | 1339 | F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t | 1340 | F6 | 0x10 | ESC [ R | ESC 6 | ESC O u | 1341 | F7 | 0x11 | ESC [ S | ESC 7 | ESC O q | 1342 | F8 | 0x12 | ESC [ T | ESC 8 | ESC O r | 1343 | F9 | 0x13 | ESC [ U | ESC 9 | ESC O p | 1344 | F10 | 0x14 | ESC [ V | ESC 0 | ESC O M | 1345 | Escape | 0x17 | ESC | ESC | ESC | 1346 | F11 | 0x15 | | ESC ! | | 1347 | F12 | 0x16 | | ESC @ | | 1348 +=========+======+===========+==========+==========+ 1349 1350 Special Mappings 1351 ================ 1352 ESC R ESC r ESC R = Reset System 1353 1354 @param TerminalDevice The terminal device to use to translate raw input into EFI Keys 1355 1356**/ 1357VOID 1358UnicodeToEfiKey ( 1359 IN TERMINAL_DEV *TerminalDevice 1360 ) 1361{ 1362 EFI_STATUS Status; 1363 EFI_STATUS TimerStatus; 1364 UINT16 UnicodeChar; 1365 EFI_INPUT_KEY Key; 1366 BOOLEAN SetDefaultResetState; 1367 1368 TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut); 1369 1370 if (!EFI_ERROR (TimerStatus)) { 1371 UnicodeToEfiKeyFlushState (TerminalDevice); 1372 TerminalDevice->ResetState = RESET_STATE_DEFAULT; 1373 } 1374 1375 while (!IsUnicodeFiFoEmpty (TerminalDevice) && !IsEfiKeyFiFoFull (TerminalDevice)) { 1376 1377 if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) { 1378 // 1379 // Check to see if the 2 seconds timer has expired 1380 // 1381 TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut); 1382 if (!EFI_ERROR (TimerStatus)) { 1383 UnicodeToEfiKeyFlushState (TerminalDevice); 1384 TerminalDevice->ResetState = RESET_STATE_DEFAULT; 1385 } 1386 } 1387 1388 // 1389 // Fetch one Unicode character from the Unicode FIFO 1390 // 1391 UnicodeFiFoRemoveOneKey (TerminalDevice, &UnicodeChar); 1392 1393 SetDefaultResetState = TRUE; 1394 1395 switch (TerminalDevice->InputState) { 1396 case INPUT_STATE_DEFAULT: 1397 1398 break; 1399 1400 case INPUT_STATE_ESC: 1401 1402 if (UnicodeChar == LEFTOPENBRACKET) { 1403 TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET; 1404 TerminalDevice->ResetState = RESET_STATE_DEFAULT; 1405 continue; 1406 } 1407 1408 if (UnicodeChar == 'O' && (TerminalDevice->TerminalType == VT100TYPE || 1409 TerminalDevice->TerminalType == TTYTERMTYPE)) { 1410 TerminalDevice->InputState |= INPUT_STATE_O; 1411 TerminalDevice->ResetState = RESET_STATE_DEFAULT; 1412 continue; 1413 } 1414 1415 Key.ScanCode = SCAN_NULL; 1416 1417 if (TerminalDevice->TerminalType == VT100PLUSTYPE || 1418 TerminalDevice->TerminalType == VTUTF8TYPE) { 1419 switch (UnicodeChar) { 1420 case '1': 1421 Key.ScanCode = SCAN_F1; 1422 break; 1423 case '2': 1424 Key.ScanCode = SCAN_F2; 1425 break; 1426 case '3': 1427 Key.ScanCode = SCAN_F3; 1428 break; 1429 case '4': 1430 Key.ScanCode = SCAN_F4; 1431 break; 1432 case '5': 1433 Key.ScanCode = SCAN_F5; 1434 break; 1435 case '6': 1436 Key.ScanCode = SCAN_F6; 1437 break; 1438 case '7': 1439 Key.ScanCode = SCAN_F7; 1440 break; 1441 case '8': 1442 Key.ScanCode = SCAN_F8; 1443 break; 1444 case '9': 1445 Key.ScanCode = SCAN_F9; 1446 break; 1447 case '0': 1448 Key.ScanCode = SCAN_F10; 1449 break; 1450 case '!': 1451 Key.ScanCode = SCAN_F11; 1452 break; 1453 case '@': 1454 Key.ScanCode = SCAN_F12; 1455 break; 1456 case 'h': 1457 Key.ScanCode = SCAN_HOME; 1458 break; 1459 case 'k': 1460 Key.ScanCode = SCAN_END; 1461 break; 1462 case '+': 1463 Key.ScanCode = SCAN_INSERT; 1464 break; 1465 case '-': 1466 Key.ScanCode = SCAN_DELETE; 1467 break; 1468 case '/': 1469 Key.ScanCode = SCAN_PAGE_DOWN; 1470 break; 1471 case '?': 1472 Key.ScanCode = SCAN_PAGE_UP; 1473 break; 1474 default : 1475 break; 1476 } 1477 } 1478 1479 switch (UnicodeChar) { 1480 case 'R': 1481 if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) { 1482 TerminalDevice->ResetState = RESET_STATE_ESC_R; 1483 SetDefaultResetState = FALSE; 1484 } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_R) { 1485 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); 1486 } 1487 Key.ScanCode = SCAN_NULL; 1488 break; 1489 case 'r': 1490 if (TerminalDevice->ResetState == RESET_STATE_ESC_R) { 1491 TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_R; 1492 SetDefaultResetState = FALSE; 1493 } 1494 Key.ScanCode = SCAN_NULL; 1495 break; 1496 default : 1497 break; 1498 } 1499 1500 if (SetDefaultResetState) { 1501 TerminalDevice->ResetState = RESET_STATE_DEFAULT; 1502 } 1503 1504 if (Key.ScanCode != SCAN_NULL) { 1505 Key.UnicodeChar = 0; 1506 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); 1507 TerminalDevice->InputState = INPUT_STATE_DEFAULT; 1508 UnicodeToEfiKeyFlushState (TerminalDevice); 1509 continue; 1510 } 1511 1512 UnicodeToEfiKeyFlushState (TerminalDevice); 1513 1514 break; 1515 1516 case INPUT_STATE_ESC | INPUT_STATE_O: 1517 1518 TerminalDevice->ResetState = RESET_STATE_DEFAULT; 1519 1520 Key.ScanCode = SCAN_NULL; 1521 1522 if (TerminalDevice->TerminalType == VT100TYPE) { 1523 switch (UnicodeChar) { 1524 case 'P': 1525 Key.ScanCode = SCAN_F1; 1526 break; 1527 case 'Q': 1528 Key.ScanCode = SCAN_F2; 1529 break; 1530 case 'w': 1531 Key.ScanCode = SCAN_F3; 1532 break; 1533 case 'x': 1534 Key.ScanCode = SCAN_F4; 1535 break; 1536 case 't': 1537 Key.ScanCode = SCAN_F5; 1538 break; 1539 case 'u': 1540 Key.ScanCode = SCAN_F6; 1541 break; 1542 case 'q': 1543 Key.ScanCode = SCAN_F7; 1544 break; 1545 case 'r': 1546 Key.ScanCode = SCAN_F8; 1547 break; 1548 case 'p': 1549 Key.ScanCode = SCAN_F9; 1550 break; 1551 case 'M': 1552 Key.ScanCode = SCAN_F10; 1553 break; 1554 default : 1555 break; 1556 } 1557 } else if (TerminalDevice->TerminalType == TTYTERMTYPE) { 1558 /* Also accept VT100 escape codes for F1-F4, HOME and END for TTY term */ 1559 switch (UnicodeChar) { 1560 case 'P': 1561 Key.ScanCode = SCAN_F1; 1562 break; 1563 case 'Q': 1564 Key.ScanCode = SCAN_F2; 1565 break; 1566 case 'R': 1567 Key.ScanCode = SCAN_F3; 1568 break; 1569 case 'S': 1570 Key.ScanCode = SCAN_F4; 1571 break; 1572 case 'H': 1573 Key.ScanCode = SCAN_HOME; 1574 break; 1575 case 'F': 1576 Key.ScanCode = SCAN_END; 1577 break; 1578 } 1579 } 1580 1581 if (Key.ScanCode != SCAN_NULL) { 1582 Key.UnicodeChar = 0; 1583 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); 1584 TerminalDevice->InputState = INPUT_STATE_DEFAULT; 1585 UnicodeToEfiKeyFlushState (TerminalDevice); 1586 continue; 1587 } 1588 1589 UnicodeToEfiKeyFlushState (TerminalDevice); 1590 1591 break; 1592 1593 case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET: 1594 1595 TerminalDevice->ResetState = RESET_STATE_DEFAULT; 1596 1597 Key.ScanCode = SCAN_NULL; 1598 1599 if (TerminalDevice->TerminalType == PCANSITYPE || 1600 TerminalDevice->TerminalType == VT100TYPE || 1601 TerminalDevice->TerminalType == VT100PLUSTYPE || 1602 TerminalDevice->TerminalType == VTUTF8TYPE || 1603 TerminalDevice->TerminalType == TTYTERMTYPE) { 1604 switch (UnicodeChar) { 1605 case 'A': 1606 Key.ScanCode = SCAN_UP; 1607 break; 1608 case 'B': 1609 Key.ScanCode = SCAN_DOWN; 1610 break; 1611 case 'C': 1612 Key.ScanCode = SCAN_RIGHT; 1613 break; 1614 case 'D': 1615 Key.ScanCode = SCAN_LEFT; 1616 break; 1617 case 'H': 1618 if (TerminalDevice->TerminalType == PCANSITYPE || 1619 TerminalDevice->TerminalType == VT100TYPE || 1620 TerminalDevice->TerminalType == TTYTERMTYPE) { 1621 Key.ScanCode = SCAN_HOME; 1622 } 1623 break; 1624 case 'F': 1625 if (TerminalDevice->TerminalType == PCANSITYPE || 1626 TerminalDevice->TerminalType == TTYTERMTYPE) { 1627 Key.ScanCode = SCAN_END; 1628 } 1629 break; 1630 case 'K': 1631 if (TerminalDevice->TerminalType == VT100TYPE) { 1632 Key.ScanCode = SCAN_END; 1633 } 1634 break; 1635 case 'L': 1636 case '@': 1637 if (TerminalDevice->TerminalType == PCANSITYPE || 1638 TerminalDevice->TerminalType == VT100TYPE) { 1639 Key.ScanCode = SCAN_INSERT; 1640 } 1641 break; 1642 case 'X': 1643 if (TerminalDevice->TerminalType == PCANSITYPE) { 1644 Key.ScanCode = SCAN_DELETE; 1645 } 1646 break; 1647 case 'P': 1648 if (TerminalDevice->TerminalType == VT100TYPE) { 1649 Key.ScanCode = SCAN_DELETE; 1650 } else if (TerminalDevice->TerminalType == PCANSITYPE) { 1651 Key.ScanCode = SCAN_F4; 1652 } 1653 break; 1654 case 'I': 1655 if (TerminalDevice->TerminalType == PCANSITYPE) { 1656 Key.ScanCode = SCAN_PAGE_UP; 1657 } 1658 break; 1659 case 'V': 1660 if (TerminalDevice->TerminalType == PCANSITYPE) { 1661 Key.ScanCode = SCAN_F10; 1662 } 1663 break; 1664 case '?': 1665 if (TerminalDevice->TerminalType == VT100TYPE) { 1666 Key.ScanCode = SCAN_PAGE_UP; 1667 } 1668 break; 1669 case 'G': 1670 if (TerminalDevice->TerminalType == PCANSITYPE) { 1671 Key.ScanCode = SCAN_PAGE_DOWN; 1672 } 1673 break; 1674 case 'U': 1675 if (TerminalDevice->TerminalType == PCANSITYPE) { 1676 Key.ScanCode = SCAN_F9; 1677 } 1678 break; 1679 case '/': 1680 if (TerminalDevice->TerminalType == VT100TYPE) { 1681 Key.ScanCode = SCAN_PAGE_DOWN; 1682 } 1683 break; 1684 case 'M': 1685 if (TerminalDevice->TerminalType == PCANSITYPE) { 1686 Key.ScanCode = SCAN_F1; 1687 } 1688 break; 1689 case 'N': 1690 if (TerminalDevice->TerminalType == PCANSITYPE) { 1691 Key.ScanCode = SCAN_F2; 1692 } 1693 break; 1694 case 'O': 1695 if (TerminalDevice->TerminalType == PCANSITYPE) { 1696 Key.ScanCode = SCAN_F3; 1697 } 1698 break; 1699 case 'Q': 1700 if (TerminalDevice->TerminalType == PCANSITYPE) { 1701 Key.ScanCode = SCAN_F5; 1702 } 1703 break; 1704 case 'R': 1705 if (TerminalDevice->TerminalType == PCANSITYPE) { 1706 Key.ScanCode = SCAN_F6; 1707 } 1708 break; 1709 case 'S': 1710 if (TerminalDevice->TerminalType == PCANSITYPE) { 1711 Key.ScanCode = SCAN_F7; 1712 } 1713 break; 1714 case 'T': 1715 if (TerminalDevice->TerminalType == PCANSITYPE) { 1716 Key.ScanCode = SCAN_F8; 1717 } 1718 break; 1719 default : 1720 break; 1721 } 1722 } 1723 1724 /* 1725 * The VT220 escape codes that the TTY terminal accepts all have 1726 * numeric codes, and there are no ambiguous prefixes shared with 1727 * other terminal types. 1728 */ 1729 if (TerminalDevice->TerminalType == TTYTERMTYPE && 1730 Key.ScanCode == SCAN_NULL && 1731 UnicodeChar >= '0' && 1732 UnicodeChar <= '9') { 1733 TerminalDevice->TtyEscapeStr[0] = UnicodeChar; 1734 TerminalDevice->TtyEscapeIndex = 1; 1735 TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET_2; 1736 continue; 1737 } 1738 1739 if (Key.ScanCode != SCAN_NULL) { 1740 Key.UnicodeChar = 0; 1741 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); 1742 TerminalDevice->InputState = INPUT_STATE_DEFAULT; 1743 UnicodeToEfiKeyFlushState (TerminalDevice); 1744 continue; 1745 } 1746 1747 UnicodeToEfiKeyFlushState (TerminalDevice); 1748 1749 break; 1750 1751 1752 case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_LEFTOPENBRACKET_2: 1753 /* 1754 * Here we handle the VT220 escape codes that we accept. This 1755 * state is only used by the TTY terminal type. 1756 */ 1757 Key.ScanCode = SCAN_NULL; 1758 if (TerminalDevice->TerminalType == TTYTERMTYPE) { 1759 1760 if (UnicodeChar == '~' && TerminalDevice->TtyEscapeIndex <= 2) { 1761 UINT16 EscCode; 1762 TerminalDevice->TtyEscapeStr[TerminalDevice->TtyEscapeIndex] = 0; /* Terminate string */ 1763 EscCode = (UINT16) StrDecimalToUintn(TerminalDevice->TtyEscapeStr); 1764 switch (EscCode) { 1765 case 2: 1766 Key.ScanCode = SCAN_INSERT; 1767 break; 1768 case 3: 1769 Key.ScanCode = SCAN_DELETE; 1770 break; 1771 case 5: 1772 Key.ScanCode = SCAN_PAGE_UP; 1773 break; 1774 case 6: 1775 Key.ScanCode = SCAN_PAGE_DOWN; 1776 break; 1777 case 11: 1778 case 12: 1779 case 13: 1780 case 14: 1781 case 15: 1782 Key.ScanCode = SCAN_F1 + EscCode - 11; 1783 break; 1784 case 17: 1785 case 18: 1786 case 19: 1787 case 20: 1788 case 21: 1789 Key.ScanCode = SCAN_F6 + EscCode - 17; 1790 break; 1791 case 23: 1792 case 24: 1793 Key.ScanCode = SCAN_F11 + EscCode - 23; 1794 break; 1795 default: 1796 break; 1797 } 1798 } else if (TerminalDevice->TtyEscapeIndex == 1){ 1799 /* 2 character escape code */ 1800 TerminalDevice->TtyEscapeStr[TerminalDevice->TtyEscapeIndex++] = UnicodeChar; 1801 continue; 1802 } 1803 else { 1804 DEBUG ((EFI_D_ERROR, "Unexpected state in escape2\n")); 1805 } 1806 } 1807 TerminalDevice->ResetState = RESET_STATE_DEFAULT; 1808 1809 if (Key.ScanCode != SCAN_NULL) { 1810 Key.UnicodeChar = 0; 1811 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); 1812 TerminalDevice->InputState = INPUT_STATE_DEFAULT; 1813 UnicodeToEfiKeyFlushState (TerminalDevice); 1814 continue; 1815 } 1816 1817 UnicodeToEfiKeyFlushState (TerminalDevice); 1818 break; 1819 1820 default: 1821 // 1822 // Invalid state. This should never happen. 1823 // 1824 ASSERT (FALSE); 1825 1826 UnicodeToEfiKeyFlushState (TerminalDevice); 1827 1828 break; 1829 } 1830 1831 if (UnicodeChar == ESC) { 1832 TerminalDevice->InputState = INPUT_STATE_ESC; 1833 } 1834 1835 if (UnicodeChar == CSI) { 1836 TerminalDevice->InputState = INPUT_STATE_CSI; 1837 } 1838 1839 if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) { 1840 Status = gBS->SetTimer( 1841 TerminalDevice->TwoSecondTimeOut, 1842 TimerRelative, 1843 (UINT64)20000000 1844 ); 1845 ASSERT_EFI_ERROR (Status); 1846 continue; 1847 } 1848 1849 if (SetDefaultResetState) { 1850 TerminalDevice->ResetState = RESET_STATE_DEFAULT; 1851 } 1852 1853 if (UnicodeChar == DEL) { 1854 if (TerminalDevice->TerminalType == TTYTERMTYPE) { 1855 Key.ScanCode = SCAN_NULL; 1856 Key.UnicodeChar = CHAR_BACKSPACE; 1857 } 1858 else { 1859 Key.ScanCode = SCAN_DELETE; 1860 Key.UnicodeChar = 0; 1861 } 1862 } else { 1863 Key.ScanCode = SCAN_NULL; 1864 Key.UnicodeChar = UnicodeChar; 1865 } 1866 1867 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key); 1868 } 1869} 1870