1 /** @file 2 VirtualKeyboard driver 3 4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR> 5 Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR> 6 7 This program and the accompanying materials 8 are licensed and made available under the terms and conditions 9 of the BSD License which accompanies this distribution. The 10 full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php 12 13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 16 **/ 17 18 #include "VirtualKeyboard.h" 19 20 // 21 // RAM Keyboard Driver Binding Protocol Instance 22 // 23 EFI_DRIVER_BINDING_PROTOCOL gVirtualKeyboardDriverBinding = { 24 VirtualKeyboardDriverBindingSupported, 25 VirtualKeyboardDriverBindingStart, 26 VirtualKeyboardDriverBindingStop, 27 0x10, 28 NULL, 29 NULL 30 }; 31 32 // 33 // EFI Driver Binding Protocol Functions 34 // 35 36 /** 37 Check whether the driver supports this device. 38 39 @param This The Udriver binding protocol. 40 @param Controller The controller handle to check. 41 @param RemainingDevicePath The remaining device path. 42 43 @retval EFI_SUCCESS The driver supports this controller. 44 @retval other This device isn't supported. 45 46 **/ 47 EFI_STATUS 48 EFIAPI 49 VirtualKeyboardDriverBindingSupported ( 50 IN EFI_DRIVER_BINDING_PROTOCOL *This, 51 IN EFI_HANDLE Controller, 52 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 53 ) 54 { 55 EFI_STATUS Status; 56 PLATFORM_VIRTUAL_KBD_PROTOCOL *PlatformVirtual; 57 58 Status = gBS->OpenProtocol ( 59 Controller, 60 &gPlatformVirtualKeyboardProtocolGuid, 61 (VOID **) &PlatformVirtual, 62 This->DriverBindingHandle, 63 Controller, 64 EFI_OPEN_PROTOCOL_BY_DRIVER 65 ); 66 if (EFI_ERROR (Status)) { 67 return Status; 68 } 69 gBS->CloseProtocol ( 70 Controller, 71 &gPlatformVirtualKeyboardProtocolGuid, 72 This->DriverBindingHandle, 73 Controller 74 ); 75 return Status; 76 } 77 78 /** 79 Starts the device with this driver. 80 81 @param This The driver binding instance. 82 @param Controller Handle of device to bind driver to. 83 @param RemainingDevicePath Optional parameter use to pick a specific child 84 device to start. 85 86 @retval EFI_SUCCESS The controller is controlled by the driver. 87 @retval Other This controller cannot be started. 88 89 **/ 90 EFI_STATUS 91 EFIAPI 92 VirtualKeyboardDriverBindingStart ( 93 IN EFI_DRIVER_BINDING_PROTOCOL *This, 94 IN EFI_HANDLE Controller, 95 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 96 ) 97 { 98 EFI_STATUS Status; 99 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; 100 PLATFORM_VIRTUAL_KBD_PROTOCOL *PlatformVirtual; 101 102 Status = gBS->OpenProtocol ( 103 Controller, 104 &gPlatformVirtualKeyboardProtocolGuid, 105 (VOID **) &PlatformVirtual, 106 This->DriverBindingHandle, 107 Controller, 108 EFI_OPEN_PROTOCOL_BY_DRIVER 109 ); 110 if (EFI_ERROR (Status)) { 111 return Status; 112 } 113 114 // 115 // Allocate the private device structure 116 // 117 VirtualKeyboardPrivate = (VIRTUAL_KEYBOARD_DEV *) AllocateZeroPool (sizeof (VIRTUAL_KEYBOARD_DEV)); 118 if (NULL == VirtualKeyboardPrivate) { 119 Status = EFI_OUT_OF_RESOURCES; 120 goto Done; 121 } 122 123 // 124 // Initialize the private device structure 125 // 126 VirtualKeyboardPrivate->Signature = VIRTUAL_KEYBOARD_DEV_SIGNATURE; 127 VirtualKeyboardPrivate->Handle = Controller; 128 VirtualKeyboardPrivate->PlatformVirtual = PlatformVirtual; 129 VirtualKeyboardPrivate->Queue.Front = 0; 130 VirtualKeyboardPrivate->Queue.Rear = 0; 131 VirtualKeyboardPrivate->QueueForNotify.Front = 0; 132 VirtualKeyboardPrivate->QueueForNotify.Rear = 0; 133 134 VirtualKeyboardPrivate->SimpleTextIn.Reset = VirtualKeyboardReset; 135 VirtualKeyboardPrivate->SimpleTextIn.ReadKeyStroke = VirtualKeyboardReadKeyStroke; 136 137 VirtualKeyboardPrivate->SimpleTextInputEx.Reset = VirtualKeyboardResetEx; 138 VirtualKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx = VirtualKeyboardReadKeyStrokeEx; 139 VirtualKeyboardPrivate->SimpleTextInputEx.SetState = VirtualKeyboardSetState; 140 141 VirtualKeyboardPrivate->SimpleTextInputEx.RegisterKeyNotify = VirtualKeyboardRegisterKeyNotify; 142 VirtualKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = VirtualKeyboardUnregisterKeyNotify; 143 InitializeListHead (&VirtualKeyboardPrivate->NotifyList); 144 145 Status = PlatformVirtual->Register (); 146 if (EFI_ERROR (Status)) { 147 goto Done; 148 } 149 150 // 151 // Report that the keyboard is being enabled 152 // 153 REPORT_STATUS_CODE ( 154 EFI_PROGRESS_CODE, 155 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE 156 ); 157 158 // 159 // Setup the WaitForKey event 160 // 161 Status = gBS->CreateEvent ( 162 EVT_NOTIFY_WAIT, 163 TPL_NOTIFY, 164 VirtualKeyboardWaitForKey, 165 &(VirtualKeyboardPrivate->SimpleTextIn), 166 &((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey) 167 ); 168 if (EFI_ERROR (Status)) { 169 (VirtualKeyboardPrivate->SimpleTextIn).WaitForKey = NULL; 170 goto Done; 171 } 172 Status = gBS->CreateEvent ( 173 EVT_NOTIFY_WAIT, 174 TPL_NOTIFY, 175 VirtualKeyboardWaitForKeyEx, 176 &(VirtualKeyboardPrivate->SimpleTextInputEx), 177 &(VirtualKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx) 178 ); 179 if (EFI_ERROR (Status)) { 180 VirtualKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx = NULL; 181 goto Done; 182 } 183 184 // 185 // Setup a periodic timer, used for reading keystrokes at a fixed interval 186 // 187 Status = gBS->CreateEvent ( 188 EVT_TIMER | EVT_NOTIFY_SIGNAL, 189 TPL_NOTIFY, 190 VirtualKeyboardTimerHandler, 191 VirtualKeyboardPrivate, 192 &VirtualKeyboardPrivate->TimerEvent 193 ); 194 if (EFI_ERROR (Status)) { 195 Status = EFI_OUT_OF_RESOURCES; 196 goto Done; 197 } 198 199 Status = gBS->SetTimer ( 200 VirtualKeyboardPrivate->TimerEvent, 201 TimerPeriodic, 202 KEYBOARD_TIMER_INTERVAL 203 ); 204 if (EFI_ERROR (Status)) { 205 Status = EFI_OUT_OF_RESOURCES; 206 goto Done; 207 } 208 209 Status = gBS->CreateEvent ( 210 EVT_NOTIFY_SIGNAL, 211 TPL_CALLBACK, 212 KeyNotifyProcessHandler, 213 VirtualKeyboardPrivate, 214 &VirtualKeyboardPrivate->KeyNotifyProcessEvent 215 ); 216 if (EFI_ERROR (Status)) { 217 Status = EFI_OUT_OF_RESOURCES; 218 goto Done; 219 } 220 221 // 222 // Reset the keyboard device 223 // 224 Status = VirtualKeyboardPrivate->SimpleTextInputEx.Reset ( 225 &VirtualKeyboardPrivate->SimpleTextInputEx, 226 FALSE 227 ); 228 if (EFI_ERROR (Status)) { 229 DEBUG ((EFI_D_ERROR, "[KBD]Reset Failed. Status - %r\n", Status)); 230 goto Done; 231 } 232 // 233 // Install protocol interfaces for the keyboard device. 234 // 235 Status = gBS->InstallMultipleProtocolInterfaces ( 236 &Controller, 237 &gEfiSimpleTextInProtocolGuid, 238 &VirtualKeyboardPrivate->SimpleTextIn, 239 &gEfiSimpleTextInputExProtocolGuid, 240 &VirtualKeyboardPrivate->SimpleTextInputEx, 241 NULL 242 ); 243 244 Done: 245 if (EFI_ERROR (Status)) { 246 if (VirtualKeyboardPrivate != NULL) { 247 if ((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey != NULL) { 248 gBS->CloseEvent ((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey); 249 } 250 251 if ((VirtualKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) { 252 gBS->CloseEvent ((VirtualKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx); 253 } 254 255 if (VirtualKeyboardPrivate->KeyNotifyProcessEvent != NULL) { 256 gBS->CloseEvent (VirtualKeyboardPrivate->KeyNotifyProcessEvent); 257 } 258 259 VirtualKeyboardFreeNotifyList (&VirtualKeyboardPrivate->NotifyList); 260 261 if (VirtualKeyboardPrivate->TimerEvent != NULL) { 262 gBS->CloseEvent (VirtualKeyboardPrivate->TimerEvent); 263 } 264 FreePool (VirtualKeyboardPrivate); 265 } 266 } 267 268 gBS->CloseProtocol ( 269 Controller, 270 &gPlatformVirtualKeyboardProtocolGuid, 271 This->DriverBindingHandle, 272 Controller 273 ); 274 275 return Status; 276 } 277 278 /** 279 Stop the device handled by this driver. 280 281 @param This The driver binding protocol. 282 @param Controller The controller to release. 283 @param NumberOfChildren The number of handles in ChildHandleBuffer. 284 @param ChildHandleBuffer The array of child handle. 285 286 @retval EFI_SUCCESS The device was stopped. 287 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. 288 @retval Others Fail to uninstall protocols attached on the device. 289 290 **/ 291 EFI_STATUS 292 EFIAPI 293 VirtualKeyboardDriverBindingStop ( 294 IN EFI_DRIVER_BINDING_PROTOCOL *This, 295 IN EFI_HANDLE Controller, 296 IN UINTN NumberOfChildren, 297 IN EFI_HANDLE *ChildHandleBuffer 298 ) 299 { 300 return EFI_SUCCESS; 301 } 302 303 304 /** 305 Enqueue the key. 306 307 @param Queue The queue to be enqueued. 308 @param KeyData The key data to be enqueued. 309 310 @retval EFI_NOT_READY The queue is full. 311 @retval EFI_SUCCESS Successfully enqueued the key data. 312 313 **/ 314 EFI_STATUS 315 Enqueue ( 316 IN SIMPLE_QUEUE *Queue, 317 IN EFI_KEY_DATA *KeyData 318 ) 319 { 320 if ((Queue->Rear + 1) % QUEUE_MAX_COUNT == Queue->Front) { 321 return EFI_NOT_READY; 322 } 323 324 CopyMem (&Queue->Buffer[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA)); 325 Queue->Rear = (Queue->Rear + 1) % QUEUE_MAX_COUNT; 326 327 return EFI_SUCCESS; 328 } 329 330 /** 331 Dequeue the key. 332 333 @param Queue The queue to be dequeued. 334 @param KeyData The key data to be dequeued. 335 336 @retval EFI_NOT_READY The queue is empty. 337 @retval EFI_SUCCESS Successfully dequeued the key data. 338 339 **/ 340 EFI_STATUS 341 Dequeue ( 342 IN SIMPLE_QUEUE *Queue, 343 IN EFI_KEY_DATA *KeyData 344 ) 345 { 346 if (Queue->Front == Queue->Rear) { 347 return EFI_NOT_READY; 348 } 349 350 CopyMem (KeyData, &Queue->Buffer[Queue->Front], sizeof (EFI_KEY_DATA)); 351 Queue->Front = (Queue->Front + 1) % QUEUE_MAX_COUNT; 352 353 return EFI_SUCCESS; 354 } 355 356 /** 357 Check whether the queue is empty. 358 359 @param Queue The queue to be checked. 360 361 @retval EFI_NOT_READY The queue is empty. 362 @retval EFI_SUCCESS The queue is not empty. 363 364 **/ 365 EFI_STATUS 366 CheckQueue ( 367 IN SIMPLE_QUEUE *Queue 368 ) 369 { 370 if (Queue->Front == Queue->Rear) { 371 return EFI_NOT_READY; 372 } 373 374 return EFI_SUCCESS; 375 } 376 377 /** 378 Check key buffer to get the key stroke status. 379 380 @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL. 381 382 @retval EFI_SUCCESS A key is being pressed now. 383 @retval Other No key is now pressed. 384 385 **/ 386 EFI_STATUS 387 EFIAPI 388 VirtualKeyboardCheckForKey ( 389 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This 390 ) 391 { 392 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; 393 394 VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This); 395 396 return CheckQueue (&VirtualKeyboardPrivate->Queue); 397 } 398 399 /** 400 Free keyboard notify list. 401 402 @param ListHead The list head 403 404 @retval EFI_SUCCESS Free the notify list successfully 405 @retval EFI_INVALID_PARAMETER ListHead is invalid. 406 407 **/ 408 EFI_STATUS 409 VirtualKeyboardFreeNotifyList ( 410 IN OUT LIST_ENTRY *ListHead 411 ) 412 { 413 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode; 414 415 if (ListHead == NULL) { 416 return EFI_INVALID_PARAMETER; 417 } 418 while (!IsListEmpty (ListHead)) { 419 NotifyNode = CR ( 420 ListHead->ForwardLink, 421 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY, 422 NotifyEntry, 423 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE 424 ); 425 RemoveEntryList (ListHead->ForwardLink); 426 gBS->FreePool (NotifyNode); 427 } 428 429 return EFI_SUCCESS; 430 } 431 432 /** 433 Judge whether is a registed key 434 435 @param RegsiteredData A pointer to a buffer that is filled in with the keystroke 436 state data for the key that was registered. 437 @param InputData A pointer to a buffer that is filled in with the keystroke 438 state data for the key that was pressed. 439 440 @retval TRUE Key be pressed matches a registered key. 441 @retval FLASE Match failed. 442 443 **/ 444 BOOLEAN 445 IsKeyRegistered ( 446 IN EFI_KEY_DATA *RegsiteredData, 447 IN EFI_KEY_DATA *InputData 448 ) 449 450 { 451 ASSERT (RegsiteredData != NULL && InputData != NULL); 452 453 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) || 454 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) { 455 return FALSE; 456 } 457 458 // 459 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored. 460 // 461 if (RegsiteredData->KeyState.KeyShiftState != 0 && 462 RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) { 463 return FALSE; 464 } 465 if (RegsiteredData->KeyState.KeyToggleState != 0 && 466 RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) { 467 return FALSE; 468 } 469 470 return TRUE; 471 472 } 473 474 /** 475 Event notification function for SIMPLE_TEXT_IN.WaitForKey event 476 Signal the event if there is key available 477 478 @param Event the event object 479 @param Context waitting context 480 481 **/ 482 VOID 483 EFIAPI 484 VirtualKeyboardWaitForKey ( 485 IN EFI_EVENT Event, 486 IN VOID *Context 487 ) 488 { 489 // 490 // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event. 491 // Csm will be used to check whether there is a key pending, but the csm will disable all 492 // interrupt before switch to compatibility16, which mean all the efiCompatibility timer 493 // event will stop work during the compatibility16. And If a caller recursivly invoke this function, 494 // e.g. UI setup or Shell, other drivers which are driven by timer event will have a bad performance during this period, 495 // e.g. usb keyboard driver. 496 // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked. 497 // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input. 498 // 499 gBS->Stall (1000); 500 // 501 // Use TimerEvent callback function to check whether there's any key pressed 502 // 503 VirtualKeyboardTimerHandler (NULL, VIRTUAL_KEYBOARD_DEV_FROM_THIS (Context)); 504 505 if (!EFI_ERROR (VirtualKeyboardCheckForKey (Context))) { 506 gBS->SignalEvent (Event); 507 } 508 } 509 510 /** 511 Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event 512 Signal the event if there is key available 513 514 @param Event event object 515 @param Context waiting context 516 517 **/ 518 VOID 519 EFIAPI 520 VirtualKeyboardWaitForKeyEx ( 521 IN EFI_EVENT Event, 522 IN VOID *Context 523 ) 524 525 { 526 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; 527 528 VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (Context); 529 VirtualKeyboardWaitForKey (Event, &VirtualKeyboardPrivate->SimpleTextIn); 530 531 } 532 533 // 534 // EFI Simple Text In Protocol Functions 535 // 536 /** 537 Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations. 538 539 @param This Pointer of simple text Protocol. 540 @param ExtendedVerification Whether perform the extra validation of keyboard. True: perform; FALSE: skip. 541 542 @retval EFI_SUCCESS The command byte is written successfully. 543 @retval EFI_DEVICE_ERROR Errors occurred during resetting keyboard. 544 545 **/ 546 EFI_STATUS 547 EFIAPI 548 VirtualKeyboardReset ( 549 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, 550 IN BOOLEAN ExtendedVerification 551 ) 552 { 553 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; 554 EFI_STATUS Status; 555 EFI_TPL OldTpl; 556 557 VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This); 558 559 // 560 // Raise TPL to avoid mouse operation impact 561 // 562 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 563 564 if (VirtualKeyboardPrivate->PlatformVirtual && VirtualKeyboardPrivate->PlatformVirtual->Reset) { 565 Status = VirtualKeyboardPrivate->PlatformVirtual->Reset (); 566 } else { 567 Status = EFI_INVALID_PARAMETER; 568 } 569 570 // 571 // resume priority of task level 572 // 573 gBS->RestoreTPL (OldTpl); 574 575 return Status; 576 } 577 578 /** 579 Reset the input device and optionaly run diagnostics 580 581 @param This Protocol instance pointer. 582 @param ExtendedVerification Driver may perform diagnostics on reset. 583 584 @retval EFI_SUCCESS The device was reset. 585 @retval EFI_DEVICE_ERROR The device is not functioning properly and could- 586 not be reset. 587 588 **/ 589 EFI_STATUS 590 EFIAPI 591 VirtualKeyboardResetEx ( 592 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 593 IN BOOLEAN ExtendedVerification 594 ) 595 { 596 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; 597 EFI_STATUS Status; 598 EFI_TPL OldTpl; 599 600 VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This); 601 602 Status = VirtualKeyboardPrivate->SimpleTextIn.Reset ( 603 &VirtualKeyboardPrivate->SimpleTextIn, 604 ExtendedVerification 605 ); 606 if (EFI_ERROR (Status)) { 607 return EFI_DEVICE_ERROR; 608 } 609 610 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 611 612 gBS->RestoreTPL (OldTpl); 613 614 return EFI_SUCCESS; 615 616 } 617 618 /** 619 Reads the next keystroke from the input device. The WaitForKey Event can 620 be used to test for existance of a keystroke via WaitForEvent () call. 621 622 @param VirtualKeyboardPrivate Virtualkeyboard driver private structure. 623 @param KeyData A pointer to a buffer that is filled in with the keystroke 624 state data for the key that was pressed. 625 626 @retval EFI_SUCCESS The keystroke information was returned. 627 @retval EFI_NOT_READY There was no keystroke data availiable. 628 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to 629 hardware errors. 630 @retval EFI_INVALID_PARAMETER KeyData is NULL. 631 632 **/ 633 EFI_STATUS 634 KeyboardReadKeyStrokeWorker ( 635 IN VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate, 636 OUT EFI_KEY_DATA *KeyData 637 ) 638 { 639 EFI_STATUS Status; 640 EFI_TPL OldTpl; 641 if (KeyData == NULL) { 642 return EFI_INVALID_PARAMETER; 643 } 644 645 // 646 // Use TimerEvent callback function to check whether there's any key pressed 647 // 648 649 // 650 // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event. 651 // Csm will be used to check whether there is a key pending, but the csm will disable all 652 // interrupt before switch to compatibility16, which mean all the efiCompatibility timer 653 // event will stop work during the compatibility16. And If a caller recursivly invoke this function, 654 // e.g. OS loader, other drivers which are driven by timer event will have a bad performance during this period, 655 // e.g. usb keyboard driver. 656 // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked. 657 // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input. 658 // 659 gBS->Stall (1000); 660 661 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 662 663 VirtualKeyboardTimerHandler (NULL, VirtualKeyboardPrivate); 664 // 665 // If there's no key, just return 666 // 667 Status = CheckQueue (&VirtualKeyboardPrivate->Queue); 668 if (EFI_ERROR (Status)) { 669 gBS->RestoreTPL (OldTpl); 670 return EFI_NOT_READY; 671 } 672 673 Status = Dequeue (&VirtualKeyboardPrivate->Queue, KeyData); 674 675 gBS->RestoreTPL (OldTpl); 676 677 return EFI_SUCCESS; 678 } 679 680 /** 681 Read out the scan code of the key that has just been stroked. 682 683 @param This Pointer of simple text Protocol. 684 @param Key Pointer for store the key that read out. 685 686 @retval EFI_SUCCESS The key is read out successfully. 687 @retval other The key reading failed. 688 689 **/ 690 EFI_STATUS 691 EFIAPI 692 VirtualKeyboardReadKeyStroke ( 693 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, 694 OUT EFI_INPUT_KEY *Key 695 ) 696 { 697 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; 698 EFI_STATUS Status; 699 EFI_KEY_DATA KeyData; 700 701 VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This); 702 703 Status = KeyboardReadKeyStrokeWorker (VirtualKeyboardPrivate, &KeyData); 704 if (EFI_ERROR (Status)) { 705 return Status; 706 } 707 708 // 709 // Convert the Ctrl+[a-z] to Ctrl+[1-26] 710 // 711 if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) { 712 if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') { 713 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1); 714 } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') { 715 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1); 716 } 717 } 718 719 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY)); 720 721 return EFI_SUCCESS; 722 } 723 724 /** 725 Reads the next keystroke from the input device. The WaitForKey Event can 726 be used to test for existance of a keystroke via WaitForEvent () call. 727 728 @param This Protocol instance pointer. 729 @param KeyData A pointer to a buffer that is filled in with the keystroke 730 state data for the key that was pressed. 731 732 @retval EFI_SUCCESS The keystroke information was returned. 733 @retval EFI_NOT_READY There was no keystroke data availiable. 734 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to 735 hardware errors. 736 @retval EFI_INVALID_PARAMETER KeyData is NULL. 737 738 **/ 739 EFI_STATUS 740 EFIAPI 741 VirtualKeyboardReadKeyStrokeEx ( 742 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 743 OUT EFI_KEY_DATA *KeyData 744 ) 745 { 746 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; 747 748 if (KeyData == NULL) { 749 return EFI_INVALID_PARAMETER; 750 } 751 752 VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This); 753 754 return KeyboardReadKeyStrokeWorker (VirtualKeyboardPrivate, KeyData); 755 756 } 757 758 /** 759 Set certain state for the input device. 760 761 @param This Protocol instance pointer. 762 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the- 763 state for the input device. 764 765 @retval EFI_SUCCESS The device state was set successfully. 766 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could- 767 not have the setting adjusted. 768 @retval EFI_UNSUPPORTED The device does not have the ability to set its state. 769 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL. 770 771 **/ 772 EFI_STATUS 773 EFIAPI 774 VirtualKeyboardSetState ( 775 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 776 IN EFI_KEY_TOGGLE_STATE *KeyToggleState 777 ) 778 { 779 if (KeyToggleState == NULL) { 780 return EFI_INVALID_PARAMETER; 781 } 782 783 // 784 // Thunk keyboard driver doesn't support partial keystroke. 785 // 786 if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID || 787 (*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED 788 ) { 789 return EFI_UNSUPPORTED; 790 } 791 792 return EFI_SUCCESS; 793 } 794 795 /** 796 Register a notification function for a particular keystroke for the input device. 797 798 @param This Protocol instance pointer. 799 @param KeyData A pointer to a buffer that is filled in with the keystroke 800 information data for the key that was pressed. 801 @param KeyNotificationFunction Points to the function to be called when the key 802 sequence is typed specified by KeyData. 803 @param NotifyHandle Points to the unique handle assigned to the registered notification. 804 805 806 @retval EFI_SUCCESS The notification function was registered successfully. 807 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures. 808 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL. 809 810 **/ 811 EFI_STATUS 812 EFIAPI 813 VirtualKeyboardRegisterKeyNotify ( 814 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 815 IN EFI_KEY_DATA *KeyData, 816 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, 817 OUT VOID **NotifyHandle 818 ) 819 { 820 EFI_STATUS Status; 821 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; 822 EFI_TPL OldTpl; 823 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify; 824 LIST_ENTRY *Link; 825 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 826 827 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) { 828 return EFI_INVALID_PARAMETER; 829 } 830 831 VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This); 832 833 // 834 // Enter critical section 835 // 836 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 837 838 // 839 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. 840 // 841 for (Link = VirtualKeyboardPrivate->NotifyList.ForwardLink; Link != &VirtualKeyboardPrivate->NotifyList; Link = Link->ForwardLink) { 842 CurrentNotify = CR ( 843 Link, 844 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY, 845 NotifyEntry, 846 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE 847 ); 848 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { 849 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { 850 *NotifyHandle = CurrentNotify; 851 Status = EFI_SUCCESS; 852 goto Exit; 853 } 854 } 855 } 856 857 // 858 // Allocate resource to save the notification function 859 // 860 861 NewNotify = (VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY)); 862 if (NewNotify == NULL) { 863 Status = EFI_OUT_OF_RESOURCES; 864 goto Exit; 865 } 866 867 NewNotify->Signature = VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE; 868 NewNotify->KeyNotificationFn = KeyNotificationFunction; 869 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA)); 870 InsertTailList (&VirtualKeyboardPrivate->NotifyList, &NewNotify->NotifyEntry); 871 872 *NotifyHandle = NewNotify; 873 Status = EFI_SUCCESS; 874 875 Exit: 876 // 877 // Leave critical section and return 878 // 879 gBS->RestoreTPL (OldTpl); 880 return Status; 881 882 } 883 884 /** 885 Remove a registered notification function from a particular keystroke. 886 887 @param This Protocol instance pointer. 888 @param NotificationHandle The handle of the notification function being unregistered. 889 890 @retval EFI_SUCCESS The notification function was unregistered successfully. 891 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid. 892 893 **/ 894 EFI_STATUS 895 EFIAPI 896 VirtualKeyboardUnregisterKeyNotify ( 897 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 898 IN VOID *NotificationHandle 899 ) 900 { 901 EFI_STATUS Status; 902 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; 903 EFI_TPL OldTpl; 904 LIST_ENTRY *Link; 905 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 906 907 // 908 // Check incoming notification handle 909 // 910 if (NotificationHandle == NULL) { 911 return EFI_INVALID_PARAMETER; 912 } 913 914 if (((VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE) { 915 return EFI_INVALID_PARAMETER; 916 } 917 918 VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This); 919 920 // 921 // Enter critical section 922 // 923 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 924 925 for (Link = VirtualKeyboardPrivate->NotifyList.ForwardLink; Link != &VirtualKeyboardPrivate->NotifyList; Link = Link->ForwardLink) { 926 CurrentNotify = CR ( 927 Link, 928 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY, 929 NotifyEntry, 930 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE 931 ); 932 if (CurrentNotify == NotificationHandle) { 933 // 934 // Remove the notification function from NotifyList and free resources 935 // 936 RemoveEntryList (&CurrentNotify->NotifyEntry); 937 938 Status = EFI_SUCCESS; 939 goto Exit; 940 } 941 } 942 943 // 944 // Can not find the specified Notification Handle 945 // 946 Status = EFI_INVALID_PARAMETER; 947 948 Exit: 949 // 950 // Leave critical section and return 951 // 952 gBS->RestoreTPL (OldTpl); 953 return Status; 954 } 955 956 /** 957 Timer event handler: read a series of scancodes from 8042 958 and put them into memory scancode buffer. 959 it read as much scancodes to either fill 960 the memory buffer or empty the keyboard buffer. 961 It is registered as running under TPL_NOTIFY 962 963 @param Event The timer event 964 @param Context A KEYBOARD_CONSOLE_IN_DEV pointer 965 966 **/ 967 VOID 968 EFIAPI 969 VirtualKeyboardTimerHandler ( 970 IN EFI_EVENT Event, 971 IN VOID *Context 972 ) 973 { 974 EFI_TPL OldTpl; 975 LIST_ENTRY *Link; 976 EFI_KEY_DATA KeyData; 977 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 978 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; 979 VIRTUAL_KBD_KEY VirtualKey; 980 981 VirtualKeyboardPrivate = Context; 982 983 // 984 // Enter critical section 985 // 986 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 987 988 if (VirtualKeyboardPrivate->PlatformVirtual && 989 VirtualKeyboardPrivate->PlatformVirtual->Query) { 990 if (VirtualKeyboardPrivate->PlatformVirtual->Query (&VirtualKey) == FALSE) { 991 goto Exit; 992 } 993 // Found key 994 KeyData.Key.ScanCode = VirtualKey.Key.ScanCode; 995 KeyData.Key.UnicodeChar = VirtualKey.Key.UnicodeChar; 996 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID; 997 KeyData.KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID; 998 if (VirtualKeyboardPrivate->PlatformVirtual->Clear) { 999 VirtualKeyboardPrivate->PlatformVirtual->Clear (&VirtualKey); 1000 } 1001 } else { 1002 goto Exit; 1003 } 1004 1005 // 1006 // Signal KeyNotify process event if this key pressed matches any key registered. 1007 // 1008 for (Link = VirtualKeyboardPrivate->NotifyList.ForwardLink; Link != &VirtualKeyboardPrivate->NotifyList; Link = Link->ForwardLink) { 1009 CurrentNotify = CR ( 1010 Link, 1011 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY, 1012 NotifyEntry, 1013 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE 1014 ); 1015 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { 1016 // 1017 // The key notification function needs to run at TPL_CALLBACK 1018 // while current TPL is TPL_NOTIFY. It will be invoked in 1019 // KeyNotifyProcessHandler() which runs at TPL_CALLBACK. 1020 // 1021 Enqueue (&VirtualKeyboardPrivate->QueueForNotify, &KeyData); 1022 gBS->SignalEvent (VirtualKeyboardPrivate->KeyNotifyProcessEvent); 1023 } 1024 } 1025 1026 Enqueue (&VirtualKeyboardPrivate->Queue, &KeyData); 1027 1028 Exit: 1029 // 1030 // Leave critical section and return 1031 // 1032 gBS->RestoreTPL (OldTpl); 1033 } 1034 1035 /** 1036 Process key notify. 1037 1038 @param Event Indicates the event that invoke this function. 1039 @param Context Indicates the calling context. 1040 **/ 1041 VOID 1042 EFIAPI 1043 KeyNotifyProcessHandler ( 1044 IN EFI_EVENT Event, 1045 IN VOID *Context 1046 ) 1047 { 1048 EFI_STATUS Status; 1049 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; 1050 EFI_KEY_DATA KeyData; 1051 LIST_ENTRY *Link; 1052 LIST_ENTRY *NotifyList; 1053 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 1054 EFI_TPL OldTpl; 1055 1056 VirtualKeyboardPrivate = (VIRTUAL_KEYBOARD_DEV *) Context; 1057 1058 // 1059 // Invoke notification functions. 1060 // 1061 NotifyList = &VirtualKeyboardPrivate->NotifyList; 1062 while (TRUE) { 1063 // 1064 // Enter critical section 1065 // 1066 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 1067 Status = Dequeue (&VirtualKeyboardPrivate->QueueForNotify, &KeyData); 1068 // 1069 // Leave critical section 1070 // 1071 gBS->RestoreTPL (OldTpl); 1072 if (EFI_ERROR (Status)) { 1073 break; 1074 } 1075 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) { 1076 CurrentNotify = CR (Link, VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE); 1077 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { 1078 CurrentNotify->KeyNotificationFn (&KeyData); 1079 } 1080 } 1081 } 1082 } 1083 1084 /** 1085 The user Entry Point for module VirtualKeyboard. The user code starts with this function. 1086 1087 @param[in] ImageHandle The firmware allocated handle for the EFI image. 1088 @param[in] SystemTable A pointer to the EFI System Table. 1089 1090 @retval EFI_SUCCESS The entry point is executed successfully. 1091 @retval other Some error occurs when executing this entry point. 1092 1093 **/ 1094 EFI_STATUS 1095 EFIAPI 1096 InitializeVirtualKeyboard( 1097 IN EFI_HANDLE ImageHandle, 1098 IN EFI_SYSTEM_TABLE *SystemTable 1099 ) 1100 { 1101 EFI_STATUS Status; 1102 1103 // 1104 // Install driver model protocol(s). 1105 // 1106 Status = EfiLibInstallDriverBindingComponentName2 ( 1107 ImageHandle, 1108 SystemTable, 1109 &gVirtualKeyboardDriverBinding, 1110 ImageHandle, 1111 &gVirtualKeyboardComponentName, 1112 &gVirtualKeyboardComponentName2 1113 ); 1114 ASSERT_EFI_ERROR (Status); 1115 1116 return Status; 1117 } 1118