1 /** @file 2 ConsoleOut Routines that speak VGA. 3 4 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> 5 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions 8 of the BSD License which accompanies this distribution. The 9 full text of the license may be found at 10 http://opensource.org/licenses/bsd-license.php 11 12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 15 **/ 16 17 #include "BiosKeyboard.h" 18 19 // 20 // EFI Driver Binding Protocol Instance 21 // 22 EFI_DRIVER_BINDING_PROTOCOL gBiosKeyboardDriverBinding = { 23 BiosKeyboardDriverBindingSupported, 24 BiosKeyboardDriverBindingStart, 25 BiosKeyboardDriverBindingStop, 26 0x3, 27 NULL, 28 NULL 29 }; 30 31 32 /** 33 Enqueue the key. 34 35 @param Queue The queue to be enqueued. 36 @param KeyData The key data to be enqueued. 37 38 @retval EFI_NOT_READY The queue is full. 39 @retval EFI_SUCCESS Successfully enqueued the key data. 40 41 **/ 42 EFI_STATUS 43 Enqueue ( 44 IN SIMPLE_QUEUE *Queue, 45 IN EFI_KEY_DATA *KeyData 46 ) 47 { 48 if ((Queue->Rear + 1) % QUEUE_MAX_COUNT == Queue->Front) { 49 return EFI_NOT_READY; 50 } 51 52 CopyMem (&Queue->Buffer[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA)); 53 Queue->Rear = (Queue->Rear + 1) % QUEUE_MAX_COUNT; 54 55 return EFI_SUCCESS; 56 } 57 58 59 /** 60 Dequeue the key. 61 62 @param Queue The queue to be dequeued. 63 @param KeyData The key data to be dequeued. 64 65 @retval EFI_NOT_READY The queue is empty. 66 @retval EFI_SUCCESS Successfully dequeued the key data. 67 68 **/ 69 EFI_STATUS 70 Dequeue ( 71 IN SIMPLE_QUEUE *Queue, 72 IN EFI_KEY_DATA *KeyData 73 ) 74 { 75 if (Queue->Front == Queue->Rear) { 76 return EFI_NOT_READY; 77 } 78 79 CopyMem (KeyData, &Queue->Buffer[Queue->Front], sizeof (EFI_KEY_DATA)); 80 Queue->Front = (Queue->Front + 1) % QUEUE_MAX_COUNT; 81 82 return EFI_SUCCESS; 83 } 84 85 86 /** 87 Check whether the queue is empty. 88 89 @param Queue The queue to be checked. 90 91 @retval EFI_NOT_READY The queue is empty. 92 @retval EFI_SUCCESS The queue is not empty. 93 94 **/ 95 EFI_STATUS 96 CheckQueue ( 97 IN SIMPLE_QUEUE *Queue 98 ) 99 { 100 if (Queue->Front == Queue->Rear) { 101 return EFI_NOT_READY; 102 } 103 104 return EFI_SUCCESS; 105 } 106 107 // 108 // EFI Driver Binding Protocol Functions 109 // 110 111 /** 112 Check whether the driver supports this device. 113 114 @param This The Udriver binding protocol. 115 @param Controller The controller handle to check. 116 @param RemainingDevicePath The remaining device path. 117 118 @retval EFI_SUCCESS The driver supports this controller. 119 @retval other This device isn't supported. 120 121 **/ 122 EFI_STATUS 123 EFIAPI 124 BiosKeyboardDriverBindingSupported ( 125 IN EFI_DRIVER_BINDING_PROTOCOL *This, 126 IN EFI_HANDLE Controller, 127 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 128 ) 129 { 130 EFI_STATUS Status; 131 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; 132 EFI_ISA_IO_PROTOCOL *IsaIo; 133 134 // 135 // See if the Legacy BIOS Protocol is available 136 // 137 Status = gBS->LocateProtocol ( 138 &gEfiLegacyBiosProtocolGuid, 139 NULL, 140 (VOID **) &LegacyBios 141 ); 142 143 if (EFI_ERROR (Status)) { 144 return Status; 145 } 146 // 147 // Open the IO Abstraction(s) needed to perform the supported test 148 // 149 Status = gBS->OpenProtocol ( 150 Controller, 151 &gEfiIsaIoProtocolGuid, 152 (VOID **) &IsaIo, 153 This->DriverBindingHandle, 154 Controller, 155 EFI_OPEN_PROTOCOL_BY_DRIVER 156 ); 157 158 if (EFI_ERROR (Status)) { 159 return Status; 160 } 161 // 162 // Use the ISA I/O Protocol to see if Controller is the Keyboard controller 163 // 164 if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) { 165 Status = EFI_UNSUPPORTED; 166 } 167 168 gBS->CloseProtocol ( 169 Controller, 170 &gEfiIsaIoProtocolGuid, 171 This->DriverBindingHandle, 172 Controller 173 ); 174 175 return Status; 176 } 177 178 /** 179 Starts the device with this driver. 180 181 @param This The driver binding instance. 182 @param Controller Handle of device to bind driver to. 183 @param RemainingDevicePath Optional parameter use to pick a specific child 184 device to start. 185 186 @retval EFI_SUCCESS The controller is controlled by the driver. 187 @retval Other This controller cannot be started. 188 189 **/ 190 EFI_STATUS 191 EFIAPI 192 BiosKeyboardDriverBindingStart ( 193 IN EFI_DRIVER_BINDING_PROTOCOL *This, 194 IN EFI_HANDLE Controller, 195 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 196 ) 197 { 198 EFI_STATUS Status; 199 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; 200 EFI_ISA_IO_PROTOCOL *IsaIo; 201 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate; 202 EFI_IA32_REGISTER_SET Regs; 203 BOOLEAN CarryFlag; 204 EFI_PS2_POLICY_PROTOCOL *Ps2Policy; 205 UINT8 Command; 206 EFI_STATUS_CODE_VALUE StatusCode; 207 208 BiosKeyboardPrivate = NULL; 209 IsaIo = NULL; 210 StatusCode = 0; 211 212 // 213 // Get Ps2 policy to set. Will be use if present. 214 // 215 gBS->LocateProtocol ( 216 &gEfiPs2PolicyProtocolGuid, 217 NULL, 218 (VOID **) &Ps2Policy 219 ); 220 221 // 222 // See if the Legacy BIOS Protocol is available 223 // 224 Status = gBS->LocateProtocol ( 225 &gEfiLegacyBiosProtocolGuid, 226 NULL, 227 (VOID **) &LegacyBios 228 ); 229 230 if (EFI_ERROR (Status)) { 231 return Status; 232 } 233 // 234 // Open the IO Abstraction(s) needed 235 // 236 Status = gBS->OpenProtocol ( 237 Controller, 238 &gEfiIsaIoProtocolGuid, 239 (VOID **) &IsaIo, 240 This->DriverBindingHandle, 241 Controller, 242 EFI_OPEN_PROTOCOL_BY_DRIVER 243 ); 244 if (EFI_ERROR (Status)) { 245 return Status; 246 } 247 248 // 249 // Allocate the private device structure 250 // 251 BiosKeyboardPrivate = (BIOS_KEYBOARD_DEV *) AllocateZeroPool (sizeof (BIOS_KEYBOARD_DEV)); 252 if (NULL == BiosKeyboardPrivate) { 253 Status = EFI_OUT_OF_RESOURCES; 254 goto Done; 255 } 256 257 // 258 // Initialize the private device structure 259 // 260 BiosKeyboardPrivate->Signature = BIOS_KEYBOARD_DEV_SIGNATURE; 261 BiosKeyboardPrivate->Handle = Controller; 262 BiosKeyboardPrivate->LegacyBios = LegacyBios; 263 BiosKeyboardPrivate->IsaIo = IsaIo; 264 265 BiosKeyboardPrivate->SimpleTextIn.Reset = BiosKeyboardReset; 266 BiosKeyboardPrivate->SimpleTextIn.ReadKeyStroke = BiosKeyboardReadKeyStroke; 267 268 BiosKeyboardPrivate->DataRegisterAddress = KEYBOARD_8042_DATA_REGISTER; 269 BiosKeyboardPrivate->StatusRegisterAddress = KEYBOARD_8042_STATUS_REGISTER; 270 BiosKeyboardPrivate->CommandRegisterAddress = KEYBOARD_8042_COMMAND_REGISTER; 271 BiosKeyboardPrivate->ExtendedKeyboard = TRUE; 272 273 BiosKeyboardPrivate->Queue.Front = 0; 274 BiosKeyboardPrivate->Queue.Rear = 0; 275 BiosKeyboardPrivate->SimpleTextInputEx.Reset = BiosKeyboardResetEx; 276 BiosKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx = BiosKeyboardReadKeyStrokeEx; 277 BiosKeyboardPrivate->SimpleTextInputEx.SetState = BiosKeyboardSetState; 278 BiosKeyboardPrivate->SimpleTextInputEx.RegisterKeyNotify = BiosKeyboardRegisterKeyNotify; 279 BiosKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = BiosKeyboardUnregisterKeyNotify; 280 InitializeListHead (&BiosKeyboardPrivate->NotifyList); 281 282 // 283 // Report that the keyboard is being enabled 284 // 285 REPORT_STATUS_CODE ( 286 EFI_PROGRESS_CODE, 287 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE 288 ); 289 290 // 291 // Setup the WaitForKey event 292 // 293 Status = gBS->CreateEvent ( 294 EVT_NOTIFY_WAIT, 295 TPL_NOTIFY, 296 BiosKeyboardWaitForKey, 297 &(BiosKeyboardPrivate->SimpleTextIn), 298 &((BiosKeyboardPrivate->SimpleTextIn).WaitForKey) 299 ); 300 if (EFI_ERROR (Status)) { 301 (BiosKeyboardPrivate->SimpleTextIn).WaitForKey = NULL; 302 goto Done; 303 } 304 Status = gBS->CreateEvent ( 305 EVT_NOTIFY_WAIT, 306 TPL_NOTIFY, 307 BiosKeyboardWaitForKeyEx, 308 &(BiosKeyboardPrivate->SimpleTextInputEx), 309 &(BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx) 310 ); 311 if (EFI_ERROR (Status)) { 312 BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx = NULL; 313 goto Done; 314 } 315 316 // 317 // Setup a periodic timer, used for reading keystrokes at a fixed interval 318 // 319 Status = gBS->CreateEvent ( 320 EVT_TIMER | EVT_NOTIFY_SIGNAL, 321 TPL_NOTIFY, 322 BiosKeyboardTimerHandler, 323 BiosKeyboardPrivate, 324 &BiosKeyboardPrivate->TimerEvent 325 ); 326 if (EFI_ERROR (Status)) { 327 Status = EFI_OUT_OF_RESOURCES; 328 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR; 329 goto Done; 330 } 331 332 Status = gBS->SetTimer ( 333 BiosKeyboardPrivate->TimerEvent, 334 TimerPeriodic, 335 KEYBOARD_TIMER_INTERVAL 336 ); 337 if (EFI_ERROR (Status)) { 338 Status = EFI_OUT_OF_RESOURCES; 339 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR; 340 goto Done; 341 } 342 343 // 344 // Report a Progress Code for an attempt to detect the precense of the keyboard device in the system 345 // 346 REPORT_STATUS_CODE ( 347 EFI_PROGRESS_CODE, 348 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT 349 ); 350 351 // 352 // Reset the keyboard device 353 // 354 Status = BiosKeyboardPrivate->SimpleTextInputEx.Reset ( 355 &BiosKeyboardPrivate->SimpleTextInputEx, 356 FeaturePcdGet (PcdPs2KbdExtendedVerification) 357 ); 358 if (EFI_ERROR (Status)) { 359 DEBUG ((EFI_D_ERROR, "[KBD]Reset Failed. Status - %r\n", Status)); 360 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED; 361 goto Done; 362 } 363 // 364 // Do platform specific policy like port swapping and keyboard light default 365 // 366 if (Ps2Policy != NULL) { 367 368 Ps2Policy->Ps2InitHardware (Controller); 369 370 Command = 0; 371 if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_CAPSLOCK) == EFI_KEYBOARD_CAPSLOCK) { 372 Command |= 4; 373 } 374 375 if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_NUMLOCK) == EFI_KEYBOARD_NUMLOCK) { 376 Command |= 2; 377 } 378 379 if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_SCROLLLOCK) == EFI_KEYBOARD_SCROLLLOCK) { 380 Command |= 1; 381 } 382 383 KeyboardWrite (BiosKeyboardPrivate, 0xed); 384 KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT); 385 KeyboardWrite (BiosKeyboardPrivate, Command); 386 // 387 // Call Legacy BIOS Protocol to set whatever is necessary 388 // 389 LegacyBios->UpdateKeyboardLedStatus (LegacyBios, Command); 390 } 391 // 392 // Get Configuration 393 // 394 Regs.H.AH = 0xc0; 395 CarryFlag = BiosKeyboardPrivate->LegacyBios->Int86 ( 396 BiosKeyboardPrivate->LegacyBios, 397 0x15, 398 &Regs 399 ); 400 401 if (!CarryFlag) { 402 // 403 // Check bit 6 of Feature Byte 2. 404 // If it is set, then Int 16 Func 09 is supported 405 // 406 if (*(UINT8 *)(UINTN) ((Regs.X.ES << 4) + Regs.X.BX + 0x06) & 0x40) { 407 // 408 // Get Keyboard Functionality 409 // 410 Regs.H.AH = 0x09; 411 CarryFlag = BiosKeyboardPrivate->LegacyBios->Int86 ( 412 BiosKeyboardPrivate->LegacyBios, 413 0x16, 414 &Regs 415 ); 416 417 if (!CarryFlag) { 418 // 419 // Check bit 5 of AH. 420 // If it is set, then INT 16 Finc 10-12 are supported. 421 // 422 if ((Regs.H.AL & 0x40) != 0) { 423 // 424 // Set the flag to use INT 16 Func 10-12 425 // 426 BiosKeyboardPrivate->ExtendedKeyboard = TRUE; 427 } 428 } 429 } 430 } 431 DEBUG ((EFI_D_INFO, "[KBD]Extended keystrokes supported by CSM16 - %02x\n", (UINTN)BiosKeyboardPrivate->ExtendedKeyboard)); 432 // 433 // Install protocol interfaces for the keyboard device. 434 // 435 Status = gBS->InstallMultipleProtocolInterfaces ( 436 &Controller, 437 &gEfiSimpleTextInProtocolGuid, 438 &BiosKeyboardPrivate->SimpleTextIn, 439 &gEfiSimpleTextInputExProtocolGuid, 440 &BiosKeyboardPrivate->SimpleTextInputEx, 441 NULL 442 ); 443 444 Done: 445 if (StatusCode != 0) { 446 // 447 // Report an Error Code for failing to start the keyboard device 448 // 449 REPORT_STATUS_CODE ( 450 EFI_ERROR_CODE | EFI_ERROR_MINOR, 451 StatusCode 452 ); 453 } 454 455 if (EFI_ERROR (Status)) { 456 457 if (BiosKeyboardPrivate != NULL) { 458 if ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey != NULL) { 459 gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey); 460 } 461 462 if ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) { 463 gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx); 464 } 465 BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList); 466 467 if (BiosKeyboardPrivate->TimerEvent != NULL) { 468 gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent); 469 } 470 471 FreePool (BiosKeyboardPrivate); 472 } 473 474 if (IsaIo != NULL) { 475 gBS->CloseProtocol ( 476 Controller, 477 &gEfiIsaIoProtocolGuid, 478 This->DriverBindingHandle, 479 Controller 480 ); 481 } 482 } 483 484 return Status; 485 } 486 487 /** 488 Stop the device handled by this driver. 489 490 @param This The driver binding protocol. 491 @param Controller The controller to release. 492 @param NumberOfChildren The number of handles in ChildHandleBuffer. 493 @param ChildHandleBuffer The array of child handle. 494 495 @retval EFI_SUCCESS The device was stopped. 496 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. 497 @retval Others Fail to uninstall protocols attached on the device. 498 499 **/ 500 EFI_STATUS 501 EFIAPI 502 BiosKeyboardDriverBindingStop ( 503 IN EFI_DRIVER_BINDING_PROTOCOL *This, 504 IN EFI_HANDLE Controller, 505 IN UINTN NumberOfChildren, 506 IN EFI_HANDLE *ChildHandleBuffer 507 ) 508 { 509 EFI_STATUS Status; 510 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextIn; 511 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate; 512 513 // 514 // Disable Keyboard 515 // 516 Status = gBS->OpenProtocol ( 517 Controller, 518 &gEfiSimpleTextInProtocolGuid, 519 (VOID **) &SimpleTextIn, 520 This->DriverBindingHandle, 521 Controller, 522 EFI_OPEN_PROTOCOL_GET_PROTOCOL 523 ); 524 if (EFI_ERROR (Status)) { 525 return Status; 526 } 527 528 Status = gBS->OpenProtocol ( 529 Controller, 530 &gEfiSimpleTextInputExProtocolGuid, 531 NULL, 532 This->DriverBindingHandle, 533 Controller, 534 EFI_OPEN_PROTOCOL_TEST_PROTOCOL 535 ); 536 if (EFI_ERROR (Status)) { 537 return Status; 538 } 539 540 BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (SimpleTextIn); 541 542 Status = gBS->UninstallMultipleProtocolInterfaces ( 543 Controller, 544 &gEfiSimpleTextInProtocolGuid, 545 &BiosKeyboardPrivate->SimpleTextIn, 546 &gEfiSimpleTextInputExProtocolGuid, 547 &BiosKeyboardPrivate->SimpleTextInputEx, 548 NULL 549 ); 550 if (EFI_ERROR (Status)) { 551 return Status; 552 } 553 // 554 // Release the IsaIo protocol on the controller handle 555 // 556 gBS->CloseProtocol ( 557 Controller, 558 &gEfiIsaIoProtocolGuid, 559 This->DriverBindingHandle, 560 Controller 561 ); 562 563 // 564 // Free other resources 565 // 566 gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey); 567 gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent); 568 gBS->CloseEvent (BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx); 569 BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList); 570 571 FreePool (BiosKeyboardPrivate); 572 573 return EFI_SUCCESS; 574 } 575 576 /** 577 Read data byte from output buffer of Keyboard Controller without delay and waiting for buffer-empty state. 578 579 @param BiosKeyboardPrivate Keyboard instance pointer. 580 581 @return The data byte read from output buffer of Keyboard Controller from data port which often is port 60H. 582 583 **/ 584 UINT8 585 KeyReadDataRegister ( 586 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate 587 ) 588 { 589 UINT8 Data; 590 591 // 592 // Use IsaIo protocol to perform IO operations 593 // 594 BiosKeyboardPrivate->IsaIo->Io.Read ( 595 BiosKeyboardPrivate->IsaIo, 596 EfiIsaIoWidthUint8, 597 BiosKeyboardPrivate->DataRegisterAddress, 598 1, 599 &Data 600 ); 601 602 return Data; 603 } 604 605 /** 606 Read status byte from status register of Keyboard Controller without delay and waiting for buffer-empty state. 607 608 @param BiosKeyboardPrivate Keyboard instance pointer. 609 610 @return The status byte read from status register of Keyboard Controller from command port which often is port 64H. 611 612 **/ 613 UINT8 614 KeyReadStatusRegister ( 615 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate 616 ) 617 { 618 UINT8 Data; 619 620 // 621 // Use IsaIo protocol to perform IO operations 622 // 623 BiosKeyboardPrivate->IsaIo->Io.Read ( 624 BiosKeyboardPrivate->IsaIo, 625 EfiIsaIoWidthUint8, 626 BiosKeyboardPrivate->StatusRegisterAddress, 627 1, 628 &Data 629 ); 630 631 return Data; 632 } 633 634 /** 635 Write command byte to control register of Keyboard Controller without delay and waiting for buffer-empty state. 636 637 @param BiosKeyboardPrivate Keyboard instance pointer. 638 @param Data Data byte to write. 639 640 **/ 641 VOID 642 KeyWriteCommandRegister ( 643 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate, 644 IN UINT8 Data 645 ) 646 { 647 // 648 // Use IsaIo protocol to perform IO operations 649 // 650 BiosKeyboardPrivate->IsaIo->Io.Write ( 651 BiosKeyboardPrivate->IsaIo, 652 EfiIsaIoWidthUint8, 653 BiosKeyboardPrivate->CommandRegisterAddress, 654 1, 655 &Data 656 ); 657 } 658 659 /** 660 Write data byte to input buffer or input/output ports of Keyboard Controller without delay and waiting for buffer-empty state. 661 662 @param BiosKeyboardPrivate Keyboard instance pointer. 663 @param Data Data byte to write. 664 665 **/ 666 VOID 667 KeyWriteDataRegister ( 668 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate, 669 IN UINT8 Data 670 ) 671 { 672 // 673 // Use IsaIo protocol to perform IO operations 674 // 675 BiosKeyboardPrivate->IsaIo->Io.Write ( 676 BiosKeyboardPrivate->IsaIo, 677 EfiIsaIoWidthUint8, 678 BiosKeyboardPrivate->DataRegisterAddress, 679 1, 680 &Data 681 ); 682 } 683 684 /** 685 Read data byte from output buffer of Keyboard Controller with delay and waiting for buffer-empty state. 686 687 @param BiosKeyboardPrivate Keyboard instance pointer. 688 @param Data The pointer for data that being read out. 689 690 @retval EFI_SUCCESS The data byte read out successfully. 691 @retval EFI_TIMEOUT Timeout occurred during reading out data byte. 692 693 **/ 694 EFI_STATUS 695 KeyboardRead ( 696 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate, 697 OUT UINT8 *Data 698 ) 699 { 700 UINT32 TimeOut; 701 UINT32 RegFilled; 702 703 TimeOut = 0; 704 RegFilled = 0; 705 706 // 707 // wait till output buffer full then perform the read 708 // 709 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) { 710 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_OUTB) != 0) { 711 RegFilled = 1; 712 *Data = KeyReadDataRegister (BiosKeyboardPrivate); 713 break; 714 } 715 716 gBS->Stall (30); 717 } 718 719 if (RegFilled == 0) { 720 return EFI_TIMEOUT; 721 } 722 723 return EFI_SUCCESS; 724 } 725 726 /** 727 Write data byte to input buffer or input/output ports of Keyboard Controller with delay and waiting for buffer-empty state. 728 729 @param BiosKeyboardPrivate Keyboard instance pointer. 730 @param Data Data byte to write. 731 732 @retval EFI_SUCCESS The data byte is written successfully. 733 @retval EFI_TIMEOUT Timeout occurred during writing. 734 735 **/ 736 EFI_STATUS 737 KeyboardWrite ( 738 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate, 739 IN UINT8 Data 740 ) 741 { 742 UINT32 TimeOut; 743 UINT32 RegEmptied; 744 745 TimeOut = 0; 746 RegEmptied = 0; 747 748 // 749 // wait for input buffer empty 750 // 751 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) { 752 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) { 753 RegEmptied = 1; 754 break; 755 } 756 757 gBS->Stall (30); 758 } 759 760 if (RegEmptied == 0) { 761 return EFI_TIMEOUT; 762 } 763 // 764 // Write it 765 // 766 KeyWriteDataRegister (BiosKeyboardPrivate, Data); 767 768 return EFI_SUCCESS; 769 } 770 771 /** 772 Write command byte to control register of Keyboard Controller with delay and waiting for buffer-empty state. 773 774 @param BiosKeyboardPrivate Keyboard instance pointer. 775 @param Data Command byte to write. 776 777 @retval EFI_SUCCESS The command byte is written successfully. 778 @retval EFI_TIMEOUT Timeout occurred during writing. 779 780 **/ 781 EFI_STATUS 782 KeyboardCommand ( 783 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate, 784 IN UINT8 Data 785 ) 786 { 787 UINT32 TimeOut; 788 UINT32 RegEmptied; 789 790 TimeOut = 0; 791 RegEmptied = 0; 792 793 // 794 // Wait For Input Buffer Empty 795 // 796 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) { 797 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) { 798 RegEmptied = 1; 799 break; 800 } 801 802 gBS->Stall (30); 803 } 804 805 if (RegEmptied == 0) { 806 return EFI_TIMEOUT; 807 } 808 // 809 // issue the command 810 // 811 KeyWriteCommandRegister (BiosKeyboardPrivate, Data); 812 813 // 814 // Wait For Input Buffer Empty again 815 // 816 RegEmptied = 0; 817 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) { 818 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) { 819 RegEmptied = 1; 820 break; 821 } 822 823 gBS->Stall (30); 824 } 825 826 if (RegEmptied == 0) { 827 return EFI_TIMEOUT; 828 } 829 830 return EFI_SUCCESS; 831 } 832 833 /** 834 Wait for a specific value to be presented in 835 Data register of Keyboard Controller by keyboard and then read it, 836 used in keyboard commands ack 837 838 @param BiosKeyboardPrivate Keyboard instance pointer. 839 @param Value The value to be waited for 840 @param WaitForValueTimeOut The limit of microseconds for timeout 841 842 @retval EFI_SUCCESS The command byte is written successfully. 843 @retval EFI_TIMEOUT Timeout occurred during writing. 844 845 **/ 846 EFI_STATUS 847 KeyboardWaitForValue ( 848 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate, 849 IN UINT8 Value, 850 IN UINTN WaitForValueTimeOut 851 ) 852 { 853 UINT8 Data; 854 UINT32 TimeOut; 855 UINT32 SumTimeOut; 856 UINT32 GotIt; 857 858 GotIt = 0; 859 TimeOut = 0; 860 SumTimeOut = 0; 861 862 // 863 // Make sure the initial value of 'Data' is different from 'Value' 864 // 865 Data = 0; 866 if (Data == Value) { 867 Data = 1; 868 } 869 // 870 // Read from 8042 (multiple times if needed) 871 // until the expected value appears 872 // use SumTimeOut to control the iteration 873 // 874 while (1) { 875 // 876 // Perform a read 877 // 878 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) { 879 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_OUTB) != 0) { 880 Data = KeyReadDataRegister (BiosKeyboardPrivate); 881 break; 882 } 883 884 gBS->Stall (30); 885 } 886 887 SumTimeOut += TimeOut; 888 889 if (Data == Value) { 890 GotIt = 1; 891 break; 892 } 893 894 if (SumTimeOut >= WaitForValueTimeOut) { 895 break; 896 } 897 } 898 // 899 // Check results 900 // 901 if (GotIt != 0) { 902 return EFI_SUCCESS; 903 } else { 904 return EFI_TIMEOUT; 905 } 906 907 } 908 909 /** 910 Reads the next keystroke from the input device. The WaitForKey Event can 911 be used to test for existance of a keystroke via WaitForEvent () call. 912 913 @param BiosKeyboardPrivate Bioskeyboard driver private structure. 914 @param KeyData A pointer to a buffer that is filled in with the keystroke 915 state data for the key that was pressed. 916 917 @retval EFI_SUCCESS The keystroke information was returned. 918 @retval EFI_NOT_READY There was no keystroke data availiable. 919 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to 920 hardware errors. 921 @retval EFI_INVALID_PARAMETER KeyData is NULL. 922 923 **/ 924 EFI_STATUS 925 KeyboardReadKeyStrokeWorker ( 926 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate, 927 OUT EFI_KEY_DATA *KeyData 928 ) 929 { 930 EFI_STATUS Status; 931 EFI_TPL OldTpl; 932 if (KeyData == NULL) { 933 return EFI_INVALID_PARAMETER; 934 } 935 936 // 937 // Use TimerEvent callback funciton to check whether there's any key pressed 938 // 939 940 // 941 // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event. 942 // Csm will be used to check whether there is a key pending, but the csm will disable all 943 // interrupt before switch to compatibility16, which mean all the efiCompatibility timer 944 // event will stop work during the compatibility16. And If a caller recursivly invoke this function, 945 // e.g. OS loader, other drivers which are driven by timer event will have a bad performance during this period, 946 // e.g. usb keyboard driver. 947 // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked. 948 // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input. 949 // 950 gBS->Stall (1000); 951 952 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 953 954 BiosKeyboardTimerHandler (NULL, BiosKeyboardPrivate); 955 // 956 // If there's no key, just return 957 // 958 Status = CheckQueue (&BiosKeyboardPrivate->Queue); 959 if (EFI_ERROR (Status)) { 960 gBS->RestoreTPL (OldTpl); 961 return EFI_NOT_READY; 962 } 963 964 Status = Dequeue (&BiosKeyboardPrivate->Queue, KeyData); 965 966 gBS->RestoreTPL (OldTpl); 967 968 return EFI_SUCCESS; 969 } 970 971 // 972 // EFI Simple Text In Protocol Functions 973 // 974 /** 975 Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations. 976 977 @param This Pointer of simple text Protocol. 978 @param ExtendedVerification Whether perform the extra validation of keyboard. True: perform; FALSE: skip. 979 980 @retval EFI_SUCCESS The command byte is written successfully. 981 @retval EFI_DEVICE_ERROR Errors occurred during reseting keyboard. 982 983 **/ 984 EFI_STATUS 985 EFIAPI 986 BiosKeyboardReset ( 987 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, 988 IN BOOLEAN ExtendedVerification 989 ) 990 { 991 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate; 992 EFI_STATUS Status; 993 EFI_TPL OldTpl; 994 UINT8 CommandByte; 995 BOOLEAN MouseEnable; 996 EFI_INPUT_KEY Key; 997 998 MouseEnable = FALSE; 999 BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This); 1000 1001 // 1002 // 1 1003 // Report reset progress code 1004 // 1005 REPORT_STATUS_CODE ( 1006 EFI_PROGRESS_CODE, 1007 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET 1008 ); 1009 1010 // 1011 // Report a Progress Code for clearing the keyboard buffer 1012 // 1013 REPORT_STATUS_CODE ( 1014 EFI_PROGRESS_CODE, 1015 EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER 1016 ); 1017 1018 // 1019 // 2 1020 // Raise TPL to avoid mouse operation impact 1021 // 1022 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 1023 1024 // 1025 // 1026 // Exhaust output buffer data 1027 // 1028 do { 1029 Status = BiosKeyboardReadKeyStroke ( 1030 This, 1031 &Key 1032 ); 1033 } while (!EFI_ERROR (Status)); 1034 // 1035 // 3 1036 // check for KBC itself firstly for setted-up already or not by reading SYSF (bit2) of status register via 64H 1037 // if not skip step 4&5 and jump to step 6 to selftest KBC and report this 1038 // else go step 4 1039 // 1040 if (!PcdGetBool (PcdFastPS2Detection)) { 1041 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_SYSF) != 0) { 1042 // 1043 // 4 1044 // CheckMouseStatus to decide enable it later or not 1045 // 1046 // 1047 // Read the command byte of KBC 1048 // 1049 Status = KeyboardCommand ( 1050 BiosKeyboardPrivate, 1051 KBC_CMDREG_VIA64_CMDBYTE_R 1052 ); 1053 1054 if (EFI_ERROR (Status)) { 1055 Status = EFI_DEVICE_ERROR; 1056 goto Exit; 1057 } 1058 1059 Status = KeyboardRead ( 1060 BiosKeyboardPrivate, 1061 &CommandByte 1062 ); 1063 1064 if (EFI_ERROR (Status)) { 1065 Status = EFI_DEVICE_ERROR; 1066 goto Exit; 1067 } 1068 // 1069 // Check mouse enabled or not before 1070 // 1071 if ((CommandByte & KB_CMMBYTE_DISABLE_AUX) != 0) { 1072 MouseEnable = FALSE; 1073 } else { 1074 MouseEnable = TRUE; 1075 } 1076 // 1077 // 5 1078 // disable mouse (via KBC) and Keyborad device 1079 // 1080 Status = KeyboardCommand ( 1081 BiosKeyboardPrivate, 1082 KBC_CMDREG_VIA64_AUX_DISABLE 1083 ); 1084 1085 if (EFI_ERROR (Status)) { 1086 Status = EFI_DEVICE_ERROR; 1087 goto Exit; 1088 } 1089 1090 Status = KeyboardCommand ( 1091 BiosKeyboardPrivate, 1092 KBC_CMDREG_VIA64_KB_DISABLE 1093 ); 1094 1095 if (EFI_ERROR (Status)) { 1096 Status = EFI_DEVICE_ERROR; 1097 goto Exit; 1098 } 1099 } else { 1100 // 1101 // 6 1102 // KBC Self Test 1103 // 1104 // 1105 // Report a Progress Code for performing a self test on the keyboard controller 1106 // 1107 REPORT_STATUS_CODE ( 1108 EFI_PROGRESS_CODE, 1109 EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST 1110 ); 1111 1112 Status = KeyboardCommand ( 1113 BiosKeyboardPrivate, 1114 KBC_CMDREG_VIA64_KBC_SLFTEST 1115 ); 1116 if (EFI_ERROR (Status)) { 1117 Status = EFI_DEVICE_ERROR; 1118 goto Exit; 1119 } 1120 1121 Status = KeyboardWaitForValue ( 1122 BiosKeyboardPrivate, 1123 KBC_CMDECHO_KBCSLFTEST_OK, 1124 KEYBOARD_WAITFORVALUE_TIMEOUT 1125 ); 1126 if (EFI_ERROR (Status)) { 1127 Status = EFI_DEVICE_ERROR; 1128 goto Exit; 1129 } 1130 } 1131 } 1132 // 1133 // 7 1134 // Disable Mouse interface, enable Keyboard interface and declare selftest success 1135 // 1136 // Mouse device will block keyboard interface before it be configured, so we should disable mouse first. 1137 // 1138 Status = KeyboardCommand ( 1139 BiosKeyboardPrivate, 1140 KBC_CMDREG_VIA64_CMDBYTE_W 1141 ); 1142 1143 if (EFI_ERROR (Status)) { 1144 Status = EFI_DEVICE_ERROR; 1145 goto Exit; 1146 } 1147 1148 // 1149 // Write 8042 Command Byte, set System Flag 1150 // While at the same time: 1151 // 1. disable mouse interface, 1152 // 2. enable kbd interface, 1153 // 3. enable PC/XT kbd translation mode 1154 // 4. enable mouse and kbd interrupts 1155 // 1156 //Command Byte bits: 1157 // 7: Reserved 1158 // 6: PC/XT translation mode 1159 // 5: Disable Auxiliary device interface 1160 // 4: Disable keyboard interface 1161 // 3: Reserved 1162 // 2: System Flag 1163 // 1: Enable Auxiliary device interrupt 1164 // 0: Enable Keyboard interrupt 1165 // 1166 CommandByte = 0; 1167 Status = KeyboardWrite ( 1168 BiosKeyboardPrivate, 1169 (UINT8) ((CommandByte & 1170 (~KB_CMMBYTE_DISABLE_KB)) | 1171 KB_CMMBYTE_KSCAN2UNI_COV | 1172 KB_CMMBYTE_ENABLE_AUXINT | 1173 KB_CMMBYTE_ENABLE_KBINT | 1174 KB_CMMBYTE_SLFTEST_SUCC | 1175 KB_CMMBYTE_DISABLE_AUX) 1176 ); 1177 1178 // 1179 // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow, 1180 // so we only do the real reseting for keyboard when user asks, and normally during booting an OS, it's skipped. 1181 // Call CheckKeyboardConnect() to check whether keyboard is connected, if it is not connected, 1182 // Real reset will not do. 1183 // 1184 if (ExtendedVerification && CheckKeyboardConnect (BiosKeyboardPrivate)) { 1185 // 1186 // 8 1187 // Send keyboard reset command then read ACK 1188 // 1189 Status = KeyboardWrite ( 1190 BiosKeyboardPrivate, 1191 KBC_INPBUF_VIA60_KBRESET 1192 ); 1193 1194 if (EFI_ERROR (Status)) { 1195 Status = EFI_DEVICE_ERROR; 1196 goto Exit; 1197 } 1198 1199 Status = KeyboardWaitForValue ( 1200 BiosKeyboardPrivate, 1201 KBC_CMDECHO_ACK, 1202 KEYBOARD_WAITFORVALUE_TIMEOUT 1203 ); 1204 1205 if (EFI_ERROR (Status)) { 1206 Status = EFI_DEVICE_ERROR; 1207 goto Exit; 1208 } 1209 // 1210 // 9 1211 // Wait for keyboard return test OK. 1212 // 1213 Status = KeyboardWaitForValue ( 1214 BiosKeyboardPrivate, 1215 KBC_CMDECHO_BATTEST_OK, 1216 KEYBOARD_WAITFORVALUE_TIMEOUT 1217 ); 1218 1219 if (EFI_ERROR (Status)) { 1220 Status = EFI_DEVICE_ERROR; 1221 goto Exit; 1222 } 1223 // 1224 // 10 1225 // set keyboard scan code set = 02 (standard configuration) 1226 // 1227 Status = KeyboardWrite ( 1228 BiosKeyboardPrivate, 1229 KBC_INPBUF_VIA60_KBSCODE 1230 ); 1231 if (EFI_ERROR (Status)) { 1232 Status = EFI_DEVICE_ERROR; 1233 goto Exit; 1234 } 1235 1236 Status = KeyboardWaitForValue ( 1237 BiosKeyboardPrivate, 1238 KBC_CMDECHO_ACK, 1239 KEYBOARD_WAITFORVALUE_TIMEOUT 1240 ); 1241 1242 if (EFI_ERROR (Status)) { 1243 Status = EFI_DEVICE_ERROR; 1244 goto Exit; 1245 } 1246 1247 Status = KeyboardWrite ( 1248 BiosKeyboardPrivate, 1249 KBC_INPBUF_VIA60_SCODESET2 1250 ); 1251 if (EFI_ERROR (Status)) { 1252 Status = EFI_DEVICE_ERROR; 1253 goto Exit; 1254 } 1255 1256 Status = KeyboardWaitForValue ( 1257 BiosKeyboardPrivate, 1258 KBC_CMDECHO_ACK, 1259 KEYBOARD_WAITFORVALUE_TIMEOUT 1260 ); 1261 1262 if (EFI_ERROR (Status)) { 1263 Status = EFI_DEVICE_ERROR; 1264 goto Exit; 1265 } 1266 // 1267 // 11 1268 // enable keyboard itself (not via KBC) by writing CMD F4 via 60H 1269 // 1270 Status = KeyboardWrite ( 1271 BiosKeyboardPrivate, 1272 KBC_INPBUF_VIA60_KBEN 1273 ); 1274 if (EFI_ERROR (Status)) { 1275 Status = EFI_DEVICE_ERROR; 1276 goto Exit; 1277 } 1278 1279 Status = KeyboardWaitForValue ( 1280 BiosKeyboardPrivate, 1281 KBC_CMDECHO_ACK, 1282 KEYBOARD_WAITFORVALUE_TIMEOUT 1283 ); 1284 1285 if (EFI_ERROR (Status)) { 1286 Status = EFI_DEVICE_ERROR; 1287 goto Exit; 1288 } 1289 // 1290 // 12 1291 // Additional validation, do it as follow: 1292 // 1). check for status register of PARE && TIM via 64H 1293 // 2). perform KB checking by writing ABh via 64H 1294 // 1295 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & (KBC_STSREG_VIA64_PARE | KBC_STSREG_VIA64_TIM)) != 0) { 1296 Status = EFI_DEVICE_ERROR; 1297 goto Exit; 1298 } 1299 1300 Status = KeyboardCommand ( 1301 BiosKeyboardPrivate, 1302 KBC_CMDREG_VIA64_KB_CKECK 1303 ); 1304 if (EFI_ERROR (Status)) { 1305 Status = EFI_DEVICE_ERROR; 1306 goto Exit; 1307 } 1308 1309 Status = KeyboardWaitForValue ( 1310 BiosKeyboardPrivate, 1311 KBC_CMDECHO_KBCHECK_OK, 1312 KEYBOARD_WAITFORVALUE_TIMEOUT 1313 ); 1314 1315 if (EFI_ERROR (Status)) { 1316 Status = EFI_DEVICE_ERROR; 1317 goto Exit; 1318 } 1319 } 1320 // 1321 // 13 1322 // Done for validating keyboard. Enable keyboard (via KBC) 1323 // and recover the command byte to proper value 1324 // 1325 if (!PcdGetBool (PcdFastPS2Detection)) { 1326 Status = KeyboardCommand ( 1327 BiosKeyboardPrivate, 1328 KBC_CMDREG_VIA64_KB_ENABLE 1329 ); 1330 1331 if (EFI_ERROR (Status)) { 1332 Status = EFI_DEVICE_ERROR; 1333 goto Exit; 1334 } 1335 } 1336 1337 // 1338 // 14 1339 // conditionally enable mouse (via KBC) 1340 // 1341 if (MouseEnable) { 1342 Status = KeyboardCommand ( 1343 BiosKeyboardPrivate, 1344 KBC_CMDREG_VIA64_AUX_ENABLE 1345 ); 1346 1347 if (EFI_ERROR (Status)) { 1348 Status = EFI_DEVICE_ERROR; 1349 1350 } 1351 } 1352 1353 Exit: 1354 // 1355 // 15 1356 // resume priority of task level 1357 // 1358 gBS->RestoreTPL (OldTpl); 1359 1360 return Status; 1361 1362 } 1363 1364 /** 1365 Read out the scan code of the key that has just been stroked. 1366 1367 @param This Pointer of simple text Protocol. 1368 @param Key Pointer for store the key that read out. 1369 1370 @retval EFI_SUCCESS The key is read out successfully. 1371 @retval other The key reading failed. 1372 1373 **/ 1374 EFI_STATUS 1375 EFIAPI 1376 BiosKeyboardReadKeyStroke ( 1377 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, 1378 OUT EFI_INPUT_KEY *Key 1379 ) 1380 { 1381 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate; 1382 EFI_STATUS Status; 1383 EFI_KEY_DATA KeyData; 1384 1385 BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This); 1386 1387 Status = KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate, &KeyData); 1388 if (EFI_ERROR (Status)) { 1389 return Status; 1390 } 1391 1392 // 1393 // Convert the Ctrl+[a-z] to Ctrl+[1-26] 1394 // 1395 if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) { 1396 if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') { 1397 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1); 1398 } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') { 1399 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1); 1400 } 1401 } 1402 1403 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY)); 1404 1405 return EFI_SUCCESS; 1406 } 1407 1408 /** 1409 Waiting on the keyboard event, if there's any key pressed by the user, signal the event 1410 1411 @param Event The event that be siganlled when any key has been stroked. 1412 @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL. 1413 1414 **/ 1415 VOID 1416 EFIAPI 1417 BiosKeyboardWaitForKey ( 1418 IN EFI_EVENT Event, 1419 IN VOID *Context 1420 ) 1421 { 1422 // 1423 // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event. 1424 // Csm will be used to check whether there is a key pending, but the csm will disable all 1425 // interrupt before switch to compatibility16, which mean all the efiCompatibility timer 1426 // event will stop work during the compatibility16. And If a caller recursivly invoke this function, 1427 // e.g. UI setup or Shell, other drivers which are driven by timer event will have a bad performance during this period, 1428 // e.g. usb keyboard driver. 1429 // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked. 1430 // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input. 1431 // 1432 gBS->Stall (1000); 1433 // 1434 // Use TimerEvent callback funciton to check whether there's any key pressed 1435 // 1436 BiosKeyboardTimerHandler (NULL, BIOS_KEYBOARD_DEV_FROM_THIS (Context)); 1437 1438 if (!EFI_ERROR (BiosKeyboardCheckForKey (Context))) { 1439 gBS->SignalEvent (Event); 1440 } 1441 } 1442 1443 /** 1444 Check key buffer to get the key stroke status. 1445 1446 @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL. 1447 1448 @retval EFI_SUCCESS A key is being pressed now. 1449 @retval Other No key is now pressed. 1450 1451 **/ 1452 EFI_STATUS 1453 EFIAPI 1454 BiosKeyboardCheckForKey ( 1455 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This 1456 ) 1457 { 1458 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate; 1459 1460 BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This); 1461 1462 return CheckQueue (&BiosKeyboardPrivate->Queue); 1463 } 1464 // 1465 // Private worker functions 1466 // 1467 #define TABLE_END 0x0 1468 1469 typedef struct _CONVERT_TABLE_ENTRY { 1470 UINT16 ScanCode; 1471 UINT16 EfiScanCode; 1472 } CONVERT_TABLE_ENTRY; 1473 1474 CONVERT_TABLE_ENTRY mConvertTable[] = { 1475 { 1476 0x47, 1477 SCAN_HOME 1478 }, 1479 { 1480 0x48, 1481 SCAN_UP 1482 }, 1483 { 1484 0x49, 1485 SCAN_PAGE_UP 1486 }, 1487 { 1488 0x4b, 1489 SCAN_LEFT 1490 }, 1491 { 1492 0x4d, 1493 SCAN_RIGHT 1494 }, 1495 { 1496 0x4f, 1497 SCAN_END 1498 }, 1499 { 1500 0x50, 1501 SCAN_DOWN 1502 }, 1503 { 1504 0x51, 1505 SCAN_PAGE_DOWN 1506 }, 1507 { 1508 0x52, 1509 SCAN_INSERT 1510 }, 1511 { 1512 0x53, 1513 SCAN_DELETE 1514 }, 1515 // 1516 // Function Keys are only valid if KeyChar == 0x00 1517 // This function does not require KeyChar to be 0x00 1518 // 1519 { 1520 0x3b, 1521 SCAN_F1 1522 }, 1523 { 1524 0x3c, 1525 SCAN_F2 1526 }, 1527 { 1528 0x3d, 1529 SCAN_F3 1530 }, 1531 { 1532 0x3e, 1533 SCAN_F4 1534 }, 1535 { 1536 0x3f, 1537 SCAN_F5 1538 }, 1539 { 1540 0x40, 1541 SCAN_F6 1542 }, 1543 { 1544 0x41, 1545 SCAN_F7 1546 }, 1547 { 1548 0x42, 1549 SCAN_F8 1550 }, 1551 { 1552 0x43, 1553 SCAN_F9 1554 }, 1555 { 1556 0x44, 1557 SCAN_F10 1558 }, 1559 { 1560 0x85, 1561 SCAN_F11 1562 }, 1563 { 1564 0x86, 1565 SCAN_F12 1566 }, 1567 // 1568 // Convert ALT + Fn keys 1569 // 1570 { 1571 0x68, 1572 SCAN_F1 1573 }, 1574 { 1575 0x69, 1576 SCAN_F2 1577 }, 1578 { 1579 0x6a, 1580 SCAN_F3 1581 }, 1582 { 1583 0x6b, 1584 SCAN_F4 1585 }, 1586 { 1587 0x6c, 1588 SCAN_F5 1589 }, 1590 { 1591 0x6d, 1592 SCAN_F6 1593 }, 1594 { 1595 0x6e, 1596 SCAN_F7 1597 }, 1598 { 1599 0x6f, 1600 SCAN_F8 1601 }, 1602 { 1603 0x70, 1604 SCAN_F9 1605 }, 1606 { 1607 0x71, 1608 SCAN_F10 1609 }, 1610 { 1611 TABLE_END, 1612 SCAN_NULL 1613 }, 1614 }; 1615 1616 /** 1617 Convert unicode combined with scan code of key to the counterpart of EFIScancode of it. 1618 1619 @param KeyChar Unicode of key. 1620 @param ScanCode Scan code of key. 1621 1622 @return The value of EFI Scancode for the key. 1623 @retval SCAN_NULL No corresponding value in the EFI convert table is found for the key. 1624 1625 **/ 1626 UINT16 1627 ConvertToEFIScanCode ( 1628 IN CHAR16 KeyChar, 1629 IN UINT16 ScanCode 1630 ) 1631 { 1632 UINT16 EfiScanCode; 1633 UINT16 Index; 1634 1635 if (KeyChar == CHAR_ESC) { 1636 EfiScanCode = SCAN_ESC; 1637 } else if (KeyChar == 0x00 || KeyChar == 0xe0) { 1638 // 1639 // Movement & Function Keys 1640 // 1641 for (Index = 0; (Index < sizeof (mConvertTable) / sizeof (CONVERT_TABLE_ENTRY)) && (mConvertTable[Index].ScanCode != TABLE_END); Index += 1) { 1642 if (ScanCode == mConvertTable[Index].ScanCode) { 1643 return mConvertTable[Index].EfiScanCode; 1644 } 1645 } 1646 // 1647 // Reach Table end, return default value 1648 // 1649 return SCAN_NULL; 1650 } else { 1651 return SCAN_NULL; 1652 } 1653 1654 return EfiScanCode; 1655 } 1656 1657 /** 1658 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command 1659 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device 1660 should not be in system. 1661 1662 @param BiosKeyboardPrivate Keyboard Private Data Struture 1663 1664 @retval TRUE Keyboard in System. 1665 @retval FALSE Keyboard not in System. 1666 1667 **/ 1668 BOOLEAN 1669 CheckKeyboardConnect ( 1670 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate 1671 ) 1672 { 1673 EFI_STATUS Status; 1674 1675 Status = EFI_SUCCESS; 1676 // 1677 // enable keyboard itself and wait for its ack 1678 // If can't receive ack, Keyboard should not be connected. 1679 // 1680 if (!PcdGetBool (PcdFastPS2Detection)) { 1681 Status = KeyboardWrite ( 1682 BiosKeyboardPrivate, 1683 KBC_INPBUF_VIA60_KBEN 1684 ); 1685 if (EFI_ERROR (Status)) { 1686 DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Keyboard enable failed!\n")); 1687 REPORT_STATUS_CODE ( 1688 EFI_ERROR_CODE | EFI_ERROR_MINOR, 1689 EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR 1690 ); 1691 return FALSE; 1692 } 1693 1694 Status = KeyboardWaitForValue ( 1695 BiosKeyboardPrivate, 1696 KBC_CMDECHO_ACK, 1697 KEYBOARD_WAITFORVALUE_TIMEOUT 1698 ); 1699 1700 if (EFI_ERROR (Status)) { 1701 DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Timeout!\n")); 1702 REPORT_STATUS_CODE ( 1703 EFI_ERROR_CODE | EFI_ERROR_MINOR, 1704 EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR 1705 ); 1706 return FALSE; 1707 } 1708 return TRUE; 1709 } else { 1710 return TRUE; 1711 } 1712 } 1713 1714 /** 1715 Timer event handler: read a series of key stroke from 8042 1716 and put them into memory key buffer. 1717 It is registered as running under TPL_NOTIFY 1718 1719 @param Event The timer event 1720 @param Context A BIOS_KEYBOARD_DEV pointer 1721 1722 **/ 1723 VOID 1724 EFIAPI 1725 BiosKeyboardTimerHandler ( 1726 IN EFI_EVENT Event, 1727 IN VOID *Context 1728 ) 1729 { 1730 EFI_TPL OldTpl; 1731 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate; 1732 EFI_IA32_REGISTER_SET Regs; 1733 UINT8 KbFlag1; // 0040h:0017h - KEYBOARD - STATUS FLAGS 1 1734 UINT8 KbFlag2; // 0040h:0018h - KEYBOARD - STATUS FLAGS 2 1735 EFI_KEY_DATA KeyData; 1736 LIST_ENTRY *Link; 1737 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 1738 1739 BiosKeyboardPrivate = Context; 1740 1741 // 1742 // Enter critical section 1743 // 1744 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 1745 1746 // 1747 // if there is no key present, just return 1748 // 1749 if (BiosKeyboardPrivate->ExtendedKeyboard) { 1750 Regs.H.AH = 0x11; 1751 } else { 1752 Regs.H.AH = 0x01; 1753 } 1754 1755 BiosKeyboardPrivate->LegacyBios->Int86 ( 1756 BiosKeyboardPrivate->LegacyBios, 1757 0x16, 1758 &Regs 1759 ); 1760 if (Regs.X.Flags.ZF != 0) { 1761 gBS->RestoreTPL (OldTpl); 1762 return; 1763 } 1764 1765 // 1766 // Read the key 1767 // 1768 if (BiosKeyboardPrivate->ExtendedKeyboard) { 1769 Regs.H.AH = 0x10; 1770 } else { 1771 Regs.H.AH = 0x00; 1772 } 1773 1774 BiosKeyboardPrivate->LegacyBios->Int86 ( 1775 BiosKeyboardPrivate->LegacyBios, 1776 0x16, 1777 &Regs 1778 ); 1779 1780 KeyData.Key.ScanCode = (UINT16) Regs.H.AH; 1781 KeyData.Key.UnicodeChar = (UINT16) Regs.H.AL; 1782 DEBUG (( 1783 EFI_D_INFO, 1784 "[KBD]INT16 returns EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n", 1785 KeyData.Key.ScanCode, 1786 KeyData.Key.UnicodeChar 1787 )); 1788 1789 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID; 1790 KeyData.KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID; 1791 // 1792 // Leagcy Bios use Int 9 which is IRQ1 interrupt handler to get keystroke scancode to KB buffer in BDA (BIOS DATE AREA), then 1793 // Int 16 depend KB buffer and some key bits in BDA to translate the scancode to ASCII code, and return both the scancode and ASCII 1794 // code to Int 16 caller. This translation process works well if the Int 9 could response user input in time. But in Tiano enviorment, the Int 9 1795 // will be disabled after the thunk call finish, which means if user crazy input during int 9 being disabled, some keystrokes will be lost when 1796 // KB device own hardware buffer overflows. And if the lost keystroke code is CTRL or ALT or SHIFT release code, these function key flags bit 1797 // in BDA will not be updated. So the Int 16 will believe the CTRL or ALT or SHIFT is still pressed, and Int 16 will translate later scancode 1798 // to wrong ASCII code. We can increase the Thunk frequence to let Int 9 response in time, but this way will much hurt other dirvers 1799 // performance, like USB. 1800 // 1801 // 1. If CTRL or ALT release code is missed, all later input keys will be translated to wrong ASCII codes which the Tiano cannot support. In 1802 // this case, the KB input seems fail to work, and user input is blocked. To solve the problem, we can help to clear the CTRL or ALT flag in BDA 1803 // after every Int 16 finish. Thus persist to press CTRL or ALT has same effection as only press one time. It is Ok, since user not often use the 1804 // CTRL and ALT. 1805 // 1806 // 2. If SHIFT release code is missed, all later lowercase input will become capital. This is ugly, but not block user input. If user press the lost 1807 // SHIFT again, the lowercase will come back to normal. Since user often use the SHIFT, it is not reasonable to help to clear the SHIFT flag in BDA, 1808 // which will let persist to press SHIFT has same effection as only press one time. 1809 // 1810 //0040h:0017h - KEYBOARD - STATUS FLAGS 1 1811 // 7 INSert active 1812 // 6 Caps Lock active 1813 // 5 Num Lock active 1814 // 4 Scroll Lock active 1815 // 3 either Alt pressed 1816 // 2 either Ctrl pressed 1817 // 1 Left Shift pressed 1818 // 0 Right Shift pressed 1819 1820 1821 // 1822 // Clear the CTRL and ALT BDA flag 1823 // 1824 KbFlag1 = *((UINT8 *) (UINTN) 0x417); // read the STATUS FLAGS 1 1825 KbFlag2 = *((UINT8 *) (UINTN) 0x418); // read STATUS FLAGS 2 1826 1827 DEBUG_CODE ( 1828 { 1829 if ((KbFlag1 & KB_CAPS_LOCK_BIT) == KB_CAPS_LOCK_BIT) { 1830 DEBUG ((EFI_D_INFO, "[KBD]Caps Lock Key is pressed.\n")); 1831 } 1832 if ((KbFlag1 & KB_NUM_LOCK_BIT) == KB_NUM_LOCK_BIT) { 1833 DEBUG ((EFI_D_INFO, "[KBD]Num Lock Key is pressed.\n")); 1834 } 1835 if ((KbFlag1 & KB_SCROLL_LOCK_BIT) == KB_SCROLL_LOCK_BIT) { 1836 DEBUG ((EFI_D_INFO, "[KBD]Scroll Lock Key is pressed.\n")); 1837 } 1838 if ((KbFlag1 & KB_ALT_PRESSED) == KB_ALT_PRESSED) { 1839 if ((KbFlag2 & KB_LEFT_ALT_PRESSED) == KB_LEFT_ALT_PRESSED) { 1840 DEBUG ((EFI_D_INFO, "[KBD]Left Alt Key is pressed.\n")); 1841 } else { 1842 DEBUG ((EFI_D_INFO, "[KBD]Right Alt Key is pressed.\n")); 1843 } 1844 } 1845 if ((KbFlag1 & KB_CTRL_PRESSED) == KB_CTRL_PRESSED) { 1846 if ((KbFlag2 & KB_LEFT_CTRL_PRESSED) == KB_LEFT_CTRL_PRESSED) { 1847 DEBUG ((EFI_D_INFO, "[KBD]Left Ctrl Key is pressed.\n")); 1848 } else { 1849 DEBUG ((EFI_D_INFO, "[KBD]Right Ctrl Key is pressed.\n")); 1850 } 1851 } 1852 if ((KbFlag1 & KB_LEFT_SHIFT_PRESSED) == KB_LEFT_SHIFT_PRESSED) { 1853 DEBUG ((EFI_D_INFO, "[KBD]Left Shift Key is pressed.\n")); 1854 } 1855 if ((KbFlag1 & KB_RIGHT_SHIFT_PRESSED) == KB_RIGHT_SHIFT_PRESSED) { 1856 DEBUG ((EFI_D_INFO, "[KBD]Right Shift Key is pressed.\n")); 1857 } 1858 } 1859 ); 1860 1861 // 1862 // Record toggle state 1863 // 1864 if ((KbFlag1 & KB_CAPS_LOCK_BIT) == KB_CAPS_LOCK_BIT) { 1865 KeyData.KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE; 1866 } 1867 if ((KbFlag1 & KB_NUM_LOCK_BIT) == KB_NUM_LOCK_BIT) { 1868 KeyData.KeyState.KeyToggleState |= EFI_NUM_LOCK_ACTIVE; 1869 } 1870 if ((KbFlag1 & KB_SCROLL_LOCK_BIT) == KB_SCROLL_LOCK_BIT) { 1871 KeyData.KeyState.KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE; 1872 } 1873 // 1874 // Record shift state 1875 // BUGBUG: Need add Menu key and Left/Right Logo key state in the future 1876 // 1877 if ((KbFlag1 & KB_ALT_PRESSED) == KB_ALT_PRESSED) { 1878 KeyData.KeyState.KeyShiftState |= ((KbFlag2 & KB_LEFT_ALT_PRESSED) == KB_LEFT_ALT_PRESSED) ? EFI_LEFT_ALT_PRESSED : EFI_RIGHT_ALT_PRESSED; 1879 } 1880 if ((KbFlag1 & KB_CTRL_PRESSED) == KB_CTRL_PRESSED) { 1881 KeyData.KeyState.KeyShiftState |= ((KbFlag2 & KB_LEFT_CTRL_PRESSED) == KB_LEFT_CTRL_PRESSED) ? EFI_LEFT_CONTROL_PRESSED : EFI_RIGHT_CONTROL_PRESSED; 1882 } 1883 if ((KbFlag1 & KB_LEFT_SHIFT_PRESSED) == KB_LEFT_SHIFT_PRESSED) { 1884 KeyData.KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED; 1885 } 1886 if ((KbFlag1 & KB_RIGHT_SHIFT_PRESSED) == KB_RIGHT_SHIFT_PRESSED) { 1887 KeyData.KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED; 1888 } 1889 1890 // 1891 // Clear left alt and left ctrl BDA flag 1892 // 1893 KbFlag2 &= ~(KB_LEFT_ALT_PRESSED | KB_LEFT_CTRL_PRESSED); 1894 *((UINT8 *) (UINTN) 0x418) = KbFlag2; 1895 KbFlag1 &= ~0x0C; 1896 *((UINT8 *) (UINTN) 0x417) = KbFlag1; 1897 1898 1899 // 1900 // Output EFI input key and shift/toggle state 1901 // 1902 if (KeyData.Key.UnicodeChar == CHAR_NULL || KeyData.Key.UnicodeChar == CHAR_SCANCODE || KeyData.Key.UnicodeChar == CHAR_ESC) { 1903 KeyData.Key.ScanCode = ConvertToEFIScanCode (KeyData.Key.UnicodeChar, KeyData.Key.ScanCode); 1904 KeyData.Key.UnicodeChar = CHAR_NULL; 1905 } else { 1906 KeyData.Key.ScanCode = SCAN_NULL; 1907 } 1908 1909 // 1910 // CSM16 has converted the Ctrl+[a-z] to [1-26], converted it back. 1911 // 1912 if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) { 1913 if (KeyData.Key.UnicodeChar >= 1 && KeyData.Key.UnicodeChar <= 26) { 1914 if (((KeyData.KeyState.KeyShiftState & (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)) != 0) == 1915 ((KeyData.KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) != 0) 1916 ) { 1917 KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar + L'a' - 1); 1918 } else { 1919 KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar + L'A' - 1); 1920 } 1921 } 1922 } 1923 1924 DEBUG (( 1925 EFI_D_INFO, 1926 "[KBD]Convert to EFI Scan Code, EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n", 1927 KeyData.Key.ScanCode, 1928 KeyData.Key.UnicodeChar 1929 )); 1930 1931 // 1932 // Need not return associated shift state if a class of printable characters that 1933 // are normally adjusted by shift modifiers. 1934 // e.g. Shift Key + 'f' key = 'F'; Shift Key + 'F' key = 'f'. 1935 // 1936 if ((KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') || 1937 (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') 1938 ) { 1939 DEBUG ((EFI_D_INFO, "[KBD]Shift key with a~z are pressed, remove shift state in EFI_KEY_STATE.\n")); 1940 KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED); 1941 } 1942 1943 // 1944 // Invoke notification functions if exist 1945 // 1946 for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) { 1947 CurrentNotify = CR ( 1948 Link, 1949 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, 1950 NotifyEntry, 1951 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE 1952 ); 1953 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { 1954 CurrentNotify->KeyNotificationFn (&KeyData); 1955 } 1956 } 1957 1958 Enqueue (&BiosKeyboardPrivate->Queue, &KeyData); 1959 // 1960 // Leave critical section and return 1961 // 1962 gBS->RestoreTPL (OldTpl); 1963 1964 return ; 1965 } 1966 1967 /** 1968 Free keyboard notify list. 1969 1970 @param ListHead The list head 1971 1972 @retval EFI_SUCCESS Free the notify list successfully 1973 @retval EFI_INVALID_PARAMETER ListHead is invalid. 1974 1975 **/ 1976 EFI_STATUS 1977 BiosKeyboardFreeNotifyList ( 1978 IN OUT LIST_ENTRY *ListHead 1979 ) 1980 { 1981 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode; 1982 1983 if (ListHead == NULL) { 1984 return EFI_INVALID_PARAMETER; 1985 } 1986 while (!IsListEmpty (ListHead)) { 1987 NotifyNode = CR ( 1988 ListHead->ForwardLink, 1989 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, 1990 NotifyEntry, 1991 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE 1992 ); 1993 RemoveEntryList (ListHead->ForwardLink); 1994 gBS->FreePool (NotifyNode); 1995 } 1996 1997 return EFI_SUCCESS; 1998 } 1999 2000 /** 2001 Check if key is registered. 2002 2003 @param RegsiteredData A pointer to a buffer that is filled in with the keystroke 2004 state data for the key that was registered. 2005 @param InputData A pointer to a buffer that is filled in with the keystroke 2006 state data for the key that was pressed. 2007 2008 @retval TRUE Key be pressed matches a registered key. 2009 @retval FLASE Match failed. 2010 2011 **/ 2012 BOOLEAN 2013 IsKeyRegistered ( 2014 IN EFI_KEY_DATA *RegsiteredData, 2015 IN EFI_KEY_DATA *InputData 2016 ) 2017 { 2018 ASSERT (RegsiteredData != NULL && InputData != NULL); 2019 2020 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) || 2021 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) { 2022 return FALSE; 2023 } 2024 2025 // 2026 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored. 2027 // 2028 if (RegsiteredData->KeyState.KeyShiftState != 0 && 2029 RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) { 2030 return FALSE; 2031 } 2032 if (RegsiteredData->KeyState.KeyToggleState != 0 && 2033 RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) { 2034 return FALSE; 2035 } 2036 2037 return TRUE; 2038 2039 } 2040 2041 /** 2042 Waiting on the keyboard event, if there's any key pressed by the user, signal the event 2043 2044 @param Event The event that be siganlled when any key has been stroked. 2045 @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL. 2046 2047 **/ 2048 VOID 2049 EFIAPI 2050 BiosKeyboardWaitForKeyEx ( 2051 IN EFI_EVENT Event, 2052 IN VOID *Context 2053 ) 2054 { 2055 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate; 2056 2057 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (Context); 2058 BiosKeyboardWaitForKey (Event, &BiosKeyboardPrivate->SimpleTextIn); 2059 2060 } 2061 2062 /** 2063 Reset the input device and optionaly run diagnostics 2064 2065 @param This Protocol instance pointer. 2066 @param ExtendedVerification Driver may perform diagnostics on reset. 2067 2068 @retval EFI_SUCCESS The device was reset. 2069 @retval EFI_DEVICE_ERROR The device is not functioning properly and could 2070 not be reset. 2071 2072 **/ 2073 EFI_STATUS 2074 EFIAPI 2075 BiosKeyboardResetEx ( 2076 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 2077 IN BOOLEAN ExtendedVerification 2078 ) 2079 { 2080 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate; 2081 EFI_STATUS Status; 2082 EFI_TPL OldTpl; 2083 2084 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This); 2085 2086 Status = BiosKeyboardPrivate->SimpleTextIn.Reset ( 2087 &BiosKeyboardPrivate->SimpleTextIn, 2088 ExtendedVerification 2089 ); 2090 if (EFI_ERROR (Status)) { 2091 return EFI_DEVICE_ERROR; 2092 } 2093 2094 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 2095 2096 gBS->RestoreTPL (OldTpl); 2097 2098 return EFI_SUCCESS; 2099 2100 } 2101 2102 /** 2103 Reads the next keystroke from the input device. The WaitForKey Event can 2104 be used to test for existance of a keystroke via WaitForEvent () call. 2105 2106 @param This Protocol instance pointer. 2107 @param KeyData A pointer to a buffer that is filled in with the keystroke 2108 state data for the key that was pressed. 2109 2110 @retval EFI_SUCCESS The keystroke information was returned. 2111 @retval EFI_NOT_READY There was no keystroke data availiable. 2112 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to 2113 hardware errors. 2114 @retval EFI_INVALID_PARAMETER KeyData is NULL. 2115 2116 **/ 2117 EFI_STATUS 2118 EFIAPI 2119 BiosKeyboardReadKeyStrokeEx ( 2120 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 2121 OUT EFI_KEY_DATA *KeyData 2122 ) 2123 { 2124 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate; 2125 2126 if (KeyData == NULL) { 2127 return EFI_INVALID_PARAMETER; 2128 } 2129 2130 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This); 2131 2132 return KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate, KeyData); 2133 2134 } 2135 2136 /** 2137 Set certain state for the input device. 2138 2139 @param This Protocol instance pointer. 2140 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the 2141 state for the input device. 2142 2143 @retval EFI_SUCCESS The device state was set successfully. 2144 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could 2145 not have the setting adjusted. 2146 @retval EFI_UNSUPPORTED The device does not have the ability to set its state. 2147 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL. 2148 2149 **/ 2150 EFI_STATUS 2151 EFIAPI 2152 BiosKeyboardSetState ( 2153 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 2154 IN EFI_KEY_TOGGLE_STATE *KeyToggleState 2155 ) 2156 { 2157 EFI_STATUS Status; 2158 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate; 2159 EFI_TPL OldTpl; 2160 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; 2161 UINT8 Command; 2162 2163 if (KeyToggleState == NULL) { 2164 return EFI_INVALID_PARAMETER; 2165 } 2166 2167 // 2168 // Thunk keyboard driver doesn't support partial keystroke. 2169 // 2170 if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID || 2171 (*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED 2172 ) { 2173 return EFI_UNSUPPORTED; 2174 } 2175 2176 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This); 2177 // 2178 // See if the Legacy BIOS Protocol is available 2179 // 2180 Status = gBS->LocateProtocol ( 2181 &gEfiLegacyBiosProtocolGuid, 2182 NULL, 2183 (VOID **) &LegacyBios 2184 ); 2185 2186 ASSERT_EFI_ERROR (Status); 2187 // 2188 // Enter critical section 2189 // 2190 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 2191 2192 Command = 0; 2193 if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) { 2194 Command |= 4; 2195 } 2196 if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) { 2197 Command |= 2; 2198 } 2199 if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) { 2200 Command |= 1; 2201 } 2202 2203 Status = KeyboardWrite (BiosKeyboardPrivate, 0xed); 2204 if (EFI_ERROR (Status)) { 2205 Status = EFI_DEVICE_ERROR; 2206 goto Exit; 2207 } 2208 Status = KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT); 2209 if (EFI_ERROR (Status)) { 2210 Status = EFI_DEVICE_ERROR; 2211 goto Exit; 2212 } 2213 Status = KeyboardWrite (BiosKeyboardPrivate, Command); 2214 if (EFI_ERROR (Status)) { 2215 Status = EFI_DEVICE_ERROR; 2216 goto Exit; 2217 } 2218 // 2219 // Call Legacy BIOS Protocol to set whatever is necessary 2220 // 2221 LegacyBios->UpdateKeyboardLedStatus (LegacyBios, Command); 2222 2223 Status = EFI_SUCCESS; 2224 2225 Exit: 2226 // 2227 // Leave critical section and return 2228 // 2229 gBS->RestoreTPL (OldTpl); 2230 2231 return Status; 2232 2233 } 2234 2235 /** 2236 Register a notification function for a particular keystroke for the input device. 2237 2238 @param This Protocol instance pointer. 2239 @param KeyData A pointer to a buffer that is filled in with the keystroke 2240 information data for the key that was pressed. 2241 @param KeyNotificationFunction Points to the function to be called when the key 2242 sequence is typed specified by KeyData. 2243 @param NotifyHandle Points to the unique handle assigned to the registered notification. 2244 2245 2246 @retval EFI_SUCCESS The notification function was registered successfully. 2247 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures. 2248 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL. 2249 2250 **/ 2251 EFI_STATUS 2252 EFIAPI 2253 BiosKeyboardRegisterKeyNotify ( 2254 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 2255 IN EFI_KEY_DATA *KeyData, 2256 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, 2257 OUT VOID **NotifyHandle 2258 ) 2259 { 2260 EFI_STATUS Status; 2261 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate; 2262 EFI_TPL OldTpl; 2263 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify; 2264 LIST_ENTRY *Link; 2265 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 2266 2267 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) { 2268 return EFI_INVALID_PARAMETER; 2269 } 2270 2271 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This); 2272 2273 // 2274 // Enter critical section 2275 // 2276 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 2277 2278 // 2279 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. 2280 // 2281 for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) { 2282 CurrentNotify = CR ( 2283 Link, 2284 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, 2285 NotifyEntry, 2286 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE 2287 ); 2288 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { 2289 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { 2290 *NotifyHandle = CurrentNotify; 2291 Status = EFI_SUCCESS; 2292 goto Exit; 2293 } 2294 } 2295 } 2296 2297 // 2298 // Allocate resource to save the notification function 2299 // 2300 2301 NewNotify = (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY)); 2302 if (NewNotify == NULL) { 2303 Status = EFI_OUT_OF_RESOURCES; 2304 goto Exit; 2305 } 2306 2307 NewNotify->Signature = BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE; 2308 NewNotify->KeyNotificationFn = KeyNotificationFunction; 2309 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA)); 2310 InsertTailList (&BiosKeyboardPrivate->NotifyList, &NewNotify->NotifyEntry); 2311 2312 *NotifyHandle = NewNotify; 2313 Status = EFI_SUCCESS; 2314 2315 Exit: 2316 // 2317 // Leave critical section and return 2318 // 2319 gBS->RestoreTPL (OldTpl); 2320 return Status; 2321 } 2322 2323 /** 2324 Remove a registered notification function from a particular keystroke. 2325 2326 @param This Protocol instance pointer. 2327 @param NotificationHandle The handle of the notification function being unregistered. 2328 2329 @retval EFI_SUCCESS The notification function was unregistered successfully. 2330 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid. 2331 2332 **/ 2333 EFI_STATUS 2334 EFIAPI 2335 BiosKeyboardUnregisterKeyNotify ( 2336 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 2337 IN VOID *NotificationHandle 2338 ) 2339 { 2340 EFI_STATUS Status; 2341 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate; 2342 EFI_TPL OldTpl; 2343 LIST_ENTRY *Link; 2344 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 2345 2346 // 2347 // Check incoming notification handle 2348 // 2349 if (NotificationHandle == NULL) { 2350 return EFI_INVALID_PARAMETER; 2351 } 2352 2353 if (((BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE) { 2354 return EFI_INVALID_PARAMETER; 2355 } 2356 2357 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This); 2358 2359 // 2360 // Enter critical section 2361 // 2362 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 2363 2364 for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) { 2365 CurrentNotify = CR ( 2366 Link, 2367 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, 2368 NotifyEntry, 2369 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE 2370 ); 2371 if (CurrentNotify == NotificationHandle) { 2372 // 2373 // Remove the notification function from NotifyList and free resources 2374 // 2375 RemoveEntryList (&CurrentNotify->NotifyEntry); 2376 2377 Status = EFI_SUCCESS; 2378 goto Exit; 2379 } 2380 } 2381 2382 // 2383 // Can not find the specified Notification Handle 2384 // 2385 Status = EFI_INVALID_PARAMETER; 2386 2387 Exit: 2388 // 2389 // Leave critical section and return 2390 // 2391 gBS->RestoreTPL (OldTpl); 2392 return Status; 2393 } 2394 2395 /** 2396 The user Entry Point for module BiosKeyboard. The user code starts with this function. 2397 2398 @param[in] ImageHandle The firmware allocated handle for the EFI image. 2399 @param[in] SystemTable A pointer to the EFI System Table. 2400 2401 @retval EFI_SUCCESS The entry point is executed successfully. 2402 @retval other Some error occurs when executing this entry point. 2403 2404 **/ 2405 EFI_STATUS 2406 EFIAPI 2407 InitializeBiosKeyboard( 2408 IN EFI_HANDLE ImageHandle, 2409 IN EFI_SYSTEM_TABLE *SystemTable 2410 ) 2411 { 2412 EFI_STATUS Status; 2413 2414 // 2415 // Install driver model protocol(s). 2416 // 2417 Status = EfiLibInstallDriverBindingComponentName2 ( 2418 ImageHandle, 2419 SystemTable, 2420 &gBiosKeyboardDriverBinding, 2421 ImageHandle, 2422 &gBiosKeyboardComponentName, 2423 &gBiosKeyboardComponentName2 2424 ); 2425 ASSERT_EFI_ERROR (Status); 2426 2427 return Status; 2428 } 2429