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