1 /** @file 2 USB Keyboard Driver that manages USB keyboard and produces Simple Text Input 3 Protocol and Simple Text Input Ex Protocol. 4 5 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR> 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include "EfiKey.h" 17 #include "KeyBoard.h" 18 19 // 20 // USB Keyboard Driver Global Variables 21 // 22 EFI_DRIVER_BINDING_PROTOCOL gUsbKeyboardDriverBinding = { 23 USBKeyboardDriverBindingSupported, 24 USBKeyboardDriverBindingStart, 25 USBKeyboardDriverBindingStop, 26 0xa, 27 NULL, 28 NULL 29 }; 30 31 /** 32 Entrypoint of USB Keyboard Driver. 33 34 This function is the entrypoint of USB Keyboard Driver. It installs Driver Binding 35 Protocols together with Component Name Protocols. 36 37 @param ImageHandle The firmware allocated handle for the EFI image. 38 @param SystemTable A pointer to the EFI System Table. 39 40 @retval EFI_SUCCESS The entry point is executed successfully. 41 42 **/ 43 EFI_STATUS 44 EFIAPI 45 USBKeyboardDriverBindingEntryPoint ( 46 IN EFI_HANDLE ImageHandle, 47 IN EFI_SYSTEM_TABLE *SystemTable 48 ) 49 { 50 EFI_STATUS Status; 51 52 Status = EfiLibInstallDriverBindingComponentName2 ( 53 ImageHandle, 54 SystemTable, 55 &gUsbKeyboardDriverBinding, 56 ImageHandle, 57 &gUsbKeyboardComponentName, 58 &gUsbKeyboardComponentName2 59 ); 60 ASSERT_EFI_ERROR (Status); 61 62 return EFI_SUCCESS; 63 } 64 65 /** 66 Check whether USB keyboard driver supports this device. 67 68 @param This The USB keyboard driver binding protocol. 69 @param Controller The controller handle to check. 70 @param RemainingDevicePath The remaining device path. 71 72 @retval EFI_SUCCESS The driver supports this controller. 73 @retval other This device isn't supported. 74 75 **/ 76 EFI_STATUS 77 EFIAPI 78 USBKeyboardDriverBindingSupported ( 79 IN EFI_DRIVER_BINDING_PROTOCOL *This, 80 IN EFI_HANDLE Controller, 81 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 82 ) 83 { 84 EFI_STATUS Status; 85 EFI_USB_IO_PROTOCOL *UsbIo; 86 87 // 88 // Check if USB I/O Protocol is attached on the controller handle. 89 // 90 Status = gBS->OpenProtocol ( 91 Controller, 92 &gEfiUsbIoProtocolGuid, 93 (VOID **) &UsbIo, 94 This->DriverBindingHandle, 95 Controller, 96 EFI_OPEN_PROTOCOL_BY_DRIVER 97 ); 98 if (EFI_ERROR (Status)) { 99 return Status; 100 } 101 102 // 103 // Use the USB I/O Protocol interface to check whether Controller is 104 // a keyboard device that can be managed by this driver. 105 // 106 Status = EFI_SUCCESS; 107 108 if (!IsUSBKeyboard (UsbIo)) { 109 Status = EFI_UNSUPPORTED; 110 } 111 112 gBS->CloseProtocol ( 113 Controller, 114 &gEfiUsbIoProtocolGuid, 115 This->DriverBindingHandle, 116 Controller 117 ); 118 119 return Status; 120 } 121 122 /** 123 Starts the keyboard device with this driver. 124 125 This function produces Simple Text Input Protocol and Simple Text Input Ex Protocol, 126 initializes the keyboard device, and submit Asynchronous Interrupt Transfer to manage 127 this keyboard device. 128 129 @param This The USB keyboard driver binding instance. 130 @param Controller Handle of device to bind driver to. 131 @param RemainingDevicePath Optional parameter use to pick a specific child 132 device to start. 133 134 @retval EFI_SUCCESS The controller is controlled by the usb keyboard driver. 135 @retval EFI_UNSUPPORTED No interrupt endpoint can be found. 136 @retval Other This controller cannot be started. 137 138 **/ 139 EFI_STATUS 140 EFIAPI 141 USBKeyboardDriverBindingStart ( 142 IN EFI_DRIVER_BINDING_PROTOCOL *This, 143 IN EFI_HANDLE Controller, 144 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 145 ) 146 { 147 EFI_STATUS Status; 148 EFI_USB_IO_PROTOCOL *UsbIo; 149 USB_KB_DEV *UsbKeyboardDevice; 150 UINT8 EndpointNumber; 151 EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; 152 UINT8 Index; 153 UINT8 EndpointAddr; 154 UINT8 PollingInterval; 155 UINT8 PacketSize; 156 BOOLEAN Found; 157 EFI_TPL OldTpl; 158 159 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 160 // 161 // Open USB I/O Protocol 162 // 163 Status = gBS->OpenProtocol ( 164 Controller, 165 &gEfiUsbIoProtocolGuid, 166 (VOID **) &UsbIo, 167 This->DriverBindingHandle, 168 Controller, 169 EFI_OPEN_PROTOCOL_BY_DRIVER 170 ); 171 if (EFI_ERROR (Status)) { 172 goto ErrorExit1; 173 } 174 175 UsbKeyboardDevice = AllocateZeroPool (sizeof (USB_KB_DEV)); 176 ASSERT (UsbKeyboardDevice != NULL); 177 178 // 179 // Get the Device Path Protocol on Controller's handle 180 // 181 Status = gBS->OpenProtocol ( 182 Controller, 183 &gEfiDevicePathProtocolGuid, 184 (VOID **) &UsbKeyboardDevice->DevicePath, 185 This->DriverBindingHandle, 186 Controller, 187 EFI_OPEN_PROTOCOL_GET_PROTOCOL 188 ); 189 190 if (EFI_ERROR (Status)) { 191 goto ErrorExit; 192 } 193 // 194 // Report that the USB keyboard is being enabled 195 // 196 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 197 EFI_PROGRESS_CODE, 198 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE), 199 UsbKeyboardDevice->DevicePath 200 ); 201 202 // 203 // This is pretty close to keyboard detection, so log progress 204 // 205 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 206 EFI_PROGRESS_CODE, 207 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT), 208 UsbKeyboardDevice->DevicePath 209 ); 210 211 UsbKeyboardDevice->UsbIo = UsbIo; 212 213 // 214 // Get interface & endpoint descriptor 215 // 216 UsbIo->UsbGetInterfaceDescriptor ( 217 UsbIo, 218 &UsbKeyboardDevice->InterfaceDescriptor 219 ); 220 221 EndpointNumber = UsbKeyboardDevice->InterfaceDescriptor.NumEndpoints; 222 223 // 224 // Traverse endpoints to find interrupt endpoint 225 // 226 Found = FALSE; 227 for (Index = 0; Index < EndpointNumber; Index++) { 228 229 UsbIo->UsbGetEndpointDescriptor ( 230 UsbIo, 231 Index, 232 &EndpointDescriptor 233 ); 234 235 if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) { 236 // 237 // We only care interrupt endpoint here 238 // 239 CopyMem(&UsbKeyboardDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor)); 240 Found = TRUE; 241 break; 242 } 243 } 244 245 if (!Found) { 246 // 247 // Report Status Code to indicate that there is no USB keyboard 248 // 249 REPORT_STATUS_CODE ( 250 EFI_ERROR_CODE | EFI_ERROR_MINOR, 251 (EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED) 252 ); 253 // 254 // No interrupt endpoint found, then return unsupported. 255 // 256 Status = EFI_UNSUPPORTED; 257 goto ErrorExit; 258 } 259 260 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 261 EFI_PROGRESS_CODE, 262 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DETECTED), 263 UsbKeyboardDevice->DevicePath 264 ); 265 266 UsbKeyboardDevice->Signature = USB_KB_DEV_SIGNATURE; 267 UsbKeyboardDevice->SimpleInput.Reset = USBKeyboardReset; 268 UsbKeyboardDevice->SimpleInput.ReadKeyStroke = USBKeyboardReadKeyStroke; 269 270 UsbKeyboardDevice->SimpleInputEx.Reset = USBKeyboardResetEx; 271 UsbKeyboardDevice->SimpleInputEx.ReadKeyStrokeEx = USBKeyboardReadKeyStrokeEx; 272 UsbKeyboardDevice->SimpleInputEx.SetState = USBKeyboardSetState; 273 UsbKeyboardDevice->SimpleInputEx.RegisterKeyNotify = USBKeyboardRegisterKeyNotify; 274 UsbKeyboardDevice->SimpleInputEx.UnregisterKeyNotify = USBKeyboardUnregisterKeyNotify; 275 276 InitializeListHead (&UsbKeyboardDevice->NotifyList); 277 278 Status = gBS->CreateEvent ( 279 EVT_TIMER | EVT_NOTIFY_SIGNAL, 280 TPL_NOTIFY, 281 USBKeyboardTimerHandler, 282 UsbKeyboardDevice, 283 &UsbKeyboardDevice->TimerEvent 284 ); 285 if (!EFI_ERROR (Status)) { 286 Status = gBS->SetTimer (UsbKeyboardDevice->TimerEvent, TimerPeriodic, KEYBOARD_TIMER_INTERVAL); 287 } 288 if (EFI_ERROR (Status)) { 289 goto ErrorExit; 290 } 291 292 Status = gBS->CreateEvent ( 293 EVT_NOTIFY_WAIT, 294 TPL_NOTIFY, 295 USBKeyboardWaitForKey, 296 UsbKeyboardDevice, 297 &(UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx) 298 ); 299 300 if (EFI_ERROR (Status)) { 301 goto ErrorExit; 302 } 303 304 Status = gBS->CreateEvent ( 305 EVT_NOTIFY_WAIT, 306 TPL_NOTIFY, 307 USBKeyboardWaitForKey, 308 UsbKeyboardDevice, 309 &(UsbKeyboardDevice->SimpleInput.WaitForKey) 310 ); 311 if (EFI_ERROR (Status)) { 312 goto ErrorExit; 313 } 314 315 Status = gBS->CreateEvent ( 316 EVT_NOTIFY_SIGNAL, 317 TPL_CALLBACK, 318 KeyNotifyProcessHandler, 319 UsbKeyboardDevice, 320 &UsbKeyboardDevice->KeyNotifyProcessEvent 321 ); 322 if (EFI_ERROR (Status)) { 323 goto ErrorExit; 324 } 325 326 // 327 // Install Simple Text Input Protocol and Simple Text Input Ex Protocol 328 // for the USB keyboard device. 329 // USB keyboard is a hot plug device, and expected to work immediately 330 // when plugging into system, other conventional console devices could 331 // distinguish it by its device path. 332 // 333 Status = gBS->InstallMultipleProtocolInterfaces ( 334 &Controller, 335 &gEfiSimpleTextInProtocolGuid, 336 &UsbKeyboardDevice->SimpleInput, 337 &gEfiSimpleTextInputExProtocolGuid, 338 &UsbKeyboardDevice->SimpleInputEx, 339 NULL 340 ); 341 if (EFI_ERROR (Status)) { 342 goto ErrorExit; 343 } 344 345 UsbKeyboardDevice->ControllerHandle = Controller; 346 Status = InitKeyboardLayout (UsbKeyboardDevice); 347 if (EFI_ERROR (Status)) { 348 gBS->UninstallMultipleProtocolInterfaces ( 349 Controller, 350 &gEfiSimpleTextInProtocolGuid, 351 &UsbKeyboardDevice->SimpleInput, 352 &gEfiSimpleTextInputExProtocolGuid, 353 &UsbKeyboardDevice->SimpleInputEx, 354 NULL 355 ); 356 goto ErrorExit; 357 } 358 359 360 // 361 // Reset USB Keyboard Device exhaustively. 362 // 363 Status = UsbKeyboardDevice->SimpleInputEx.Reset ( 364 &UsbKeyboardDevice->SimpleInputEx, 365 TRUE 366 ); 367 if (EFI_ERROR (Status)) { 368 gBS->UninstallMultipleProtocolInterfaces ( 369 Controller, 370 &gEfiSimpleTextInProtocolGuid, 371 &UsbKeyboardDevice->SimpleInput, 372 &gEfiSimpleTextInputExProtocolGuid, 373 &UsbKeyboardDevice->SimpleInputEx, 374 NULL 375 ); 376 goto ErrorExit; 377 } 378 379 // 380 // Submit Asynchronous Interrupt Transfer to manage this device. 381 // 382 EndpointAddr = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress; 383 PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval; 384 PacketSize = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize); 385 386 Status = UsbIo->UsbAsyncInterruptTransfer ( 387 UsbIo, 388 EndpointAddr, 389 TRUE, 390 PollingInterval, 391 PacketSize, 392 KeyboardHandler, 393 UsbKeyboardDevice 394 ); 395 396 if (EFI_ERROR (Status)) { 397 gBS->UninstallMultipleProtocolInterfaces ( 398 Controller, 399 &gEfiSimpleTextInProtocolGuid, 400 &UsbKeyboardDevice->SimpleInput, 401 &gEfiSimpleTextInputExProtocolGuid, 402 &UsbKeyboardDevice->SimpleInputEx, 403 NULL 404 ); 405 goto ErrorExit; 406 } 407 408 UsbKeyboardDevice->ControllerNameTable = NULL; 409 AddUnicodeString2 ( 410 "eng", 411 gUsbKeyboardComponentName.SupportedLanguages, 412 &UsbKeyboardDevice->ControllerNameTable, 413 L"Generic Usb Keyboard", 414 TRUE 415 ); 416 AddUnicodeString2 ( 417 "en", 418 gUsbKeyboardComponentName2.SupportedLanguages, 419 &UsbKeyboardDevice->ControllerNameTable, 420 L"Generic Usb Keyboard", 421 FALSE 422 ); 423 424 gBS->RestoreTPL (OldTpl); 425 return EFI_SUCCESS; 426 427 // 428 // Error handler 429 // 430 ErrorExit: 431 if (UsbKeyboardDevice != NULL) { 432 if (UsbKeyboardDevice->TimerEvent != NULL) { 433 gBS->CloseEvent (UsbKeyboardDevice->TimerEvent); 434 } 435 if (UsbKeyboardDevice->SimpleInput.WaitForKey != NULL) { 436 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); 437 } 438 if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) { 439 gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx); 440 } 441 if (UsbKeyboardDevice->KeyNotifyProcessEvent != NULL) { 442 gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent); 443 } 444 if (UsbKeyboardDevice->KeyboardLayoutEvent != NULL) { 445 ReleaseKeyboardLayoutResources (UsbKeyboardDevice); 446 gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent); 447 } 448 FreePool (UsbKeyboardDevice); 449 UsbKeyboardDevice = NULL; 450 } 451 gBS->CloseProtocol ( 452 Controller, 453 &gEfiUsbIoProtocolGuid, 454 This->DriverBindingHandle, 455 Controller 456 ); 457 458 ErrorExit1: 459 gBS->RestoreTPL (OldTpl); 460 461 return Status; 462 463 } 464 465 466 /** 467 Stop the USB keyboard device handled by this driver. 468 469 @param This The USB keyboard driver binding protocol. 470 @param Controller The controller to release. 471 @param NumberOfChildren The number of handles in ChildHandleBuffer. 472 @param ChildHandleBuffer The array of child handle. 473 474 @retval EFI_SUCCESS The device was stopped. 475 @retval EFI_UNSUPPORTED Simple Text In Protocol or Simple Text In Ex Protocol 476 is not installed on Controller. 477 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. 478 @retval Others Fail to uninstall protocols attached on the device. 479 480 **/ 481 EFI_STATUS 482 EFIAPI 483 USBKeyboardDriverBindingStop ( 484 IN EFI_DRIVER_BINDING_PROTOCOL *This, 485 IN EFI_HANDLE Controller, 486 IN UINTN NumberOfChildren, 487 IN EFI_HANDLE *ChildHandleBuffer 488 ) 489 { 490 EFI_STATUS Status; 491 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleInput; 492 USB_KB_DEV *UsbKeyboardDevice; 493 494 Status = gBS->OpenProtocol ( 495 Controller, 496 &gEfiSimpleTextInProtocolGuid, 497 (VOID **) &SimpleInput, 498 This->DriverBindingHandle, 499 Controller, 500 EFI_OPEN_PROTOCOL_GET_PROTOCOL 501 ); 502 if (EFI_ERROR (Status)) { 503 return EFI_UNSUPPORTED; 504 } 505 506 Status = gBS->OpenProtocol ( 507 Controller, 508 &gEfiSimpleTextInputExProtocolGuid, 509 NULL, 510 This->DriverBindingHandle, 511 Controller, 512 EFI_OPEN_PROTOCOL_TEST_PROTOCOL 513 ); 514 if (EFI_ERROR (Status)) { 515 return EFI_UNSUPPORTED; 516 } 517 518 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput); 519 520 // 521 // The key data input from this device will be disabled. 522 // 523 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 524 EFI_PROGRESS_CODE, 525 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE), 526 UsbKeyboardDevice->DevicePath 527 ); 528 529 // 530 // Delete the Asynchronous Interrupt Transfer from this device 531 // 532 UsbKeyboardDevice->UsbIo->UsbAsyncInterruptTransfer ( 533 UsbKeyboardDevice->UsbIo, 534 UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress, 535 FALSE, 536 UsbKeyboardDevice->IntEndpointDescriptor.Interval, 537 0, 538 NULL, 539 NULL 540 ); 541 542 gBS->CloseProtocol ( 543 Controller, 544 &gEfiUsbIoProtocolGuid, 545 This->DriverBindingHandle, 546 Controller 547 ); 548 549 Status = gBS->UninstallMultipleProtocolInterfaces ( 550 Controller, 551 &gEfiSimpleTextInProtocolGuid, 552 &UsbKeyboardDevice->SimpleInput, 553 &gEfiSimpleTextInputExProtocolGuid, 554 &UsbKeyboardDevice->SimpleInputEx, 555 NULL 556 ); 557 // 558 // Free all resources. 559 // 560 gBS->CloseEvent (UsbKeyboardDevice->TimerEvent); 561 gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer); 562 gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent); 563 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); 564 gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx); 565 gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent); 566 KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList); 567 568 ReleaseKeyboardLayoutResources (UsbKeyboardDevice); 569 gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent); 570 571 if (UsbKeyboardDevice->ControllerNameTable != NULL) { 572 FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable); 573 } 574 575 DestroyQueue (&UsbKeyboardDevice->UsbKeyQueue); 576 DestroyQueue (&UsbKeyboardDevice->EfiKeyQueue); 577 DestroyQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify); 578 579 FreePool (UsbKeyboardDevice); 580 581 return Status; 582 } 583 584 /** 585 Internal function to read the next keystroke from the keyboard buffer. 586 587 @param UsbKeyboardDevice USB keyboard's private structure. 588 @param KeyData A pointer to buffer to hold the keystroke 589 data for the key that was pressed. 590 591 @retval EFI_SUCCESS The keystroke information was returned. 592 @retval EFI_NOT_READY There was no keystroke data availiable. 593 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to 594 hardware errors. 595 @retval EFI_INVALID_PARAMETER KeyData is NULL. 596 @retval Others Fail to translate keycode into EFI_INPUT_KEY 597 598 **/ 599 EFI_STATUS 600 USBKeyboardReadKeyStrokeWorker ( 601 IN OUT USB_KB_DEV *UsbKeyboardDevice, 602 OUT EFI_KEY_DATA *KeyData 603 ) 604 { 605 if (KeyData == NULL) { 606 return EFI_INVALID_PARAMETER; 607 } 608 609 if (IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) { 610 return EFI_NOT_READY; 611 } 612 613 Dequeue (&UsbKeyboardDevice->EfiKeyQueue, KeyData, sizeof (*KeyData)); 614 615 return EFI_SUCCESS; 616 } 617 618 /** 619 Reset the input device and optionally run diagnostics 620 621 There are 2 types of reset for USB keyboard. 622 For non-exhaustive reset, only keyboard buffer is cleared. 623 For exhaustive reset, in addition to clearance of keyboard buffer, the hardware status 624 is also re-initialized. 625 626 @param This Protocol instance pointer. 627 @param ExtendedVerification Driver may perform diagnostics on reset. 628 629 @retval EFI_SUCCESS The device was reset. 630 @retval EFI_DEVICE_ERROR The device is not functioning properly and could not be reset. 631 632 **/ 633 EFI_STATUS 634 EFIAPI 635 USBKeyboardReset ( 636 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, 637 IN BOOLEAN ExtendedVerification 638 ) 639 { 640 EFI_STATUS Status; 641 USB_KB_DEV *UsbKeyboardDevice; 642 643 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This); 644 645 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 646 EFI_PROGRESS_CODE, 647 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET), 648 UsbKeyboardDevice->DevicePath 649 ); 650 651 // 652 // Non-exhaustive reset: 653 // only reset private data structures. 654 // 655 if (!ExtendedVerification) { 656 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 657 EFI_PROGRESS_CODE, 658 (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER), 659 UsbKeyboardDevice->DevicePath 660 ); 661 // 662 // Clear the key buffer of this USB keyboard 663 // 664 InitQueue (&UsbKeyboardDevice->UsbKeyQueue, sizeof (USB_KEY)); 665 InitQueue (&UsbKeyboardDevice->EfiKeyQueue, sizeof (EFI_KEY_DATA)); 666 InitQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify, sizeof (EFI_KEY_DATA)); 667 668 return EFI_SUCCESS; 669 } 670 671 // 672 // Exhaustive reset 673 // 674 Status = InitUSBKeyboard (UsbKeyboardDevice); 675 if (EFI_ERROR (Status)) { 676 return EFI_DEVICE_ERROR; 677 } 678 679 return EFI_SUCCESS; 680 } 681 682 683 /** 684 Reads the next keystroke from the input device. 685 686 @param This The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance. 687 @param Key A pointer to a buffer that is filled in with the keystroke 688 information for the key that was pressed. 689 690 @retval EFI_SUCCESS The keystroke information was returned. 691 @retval EFI_NOT_READY There was no keystroke data availiable. 692 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to 693 hardware errors. 694 695 **/ 696 EFI_STATUS 697 EFIAPI 698 USBKeyboardReadKeyStroke ( 699 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, 700 OUT EFI_INPUT_KEY *Key 701 ) 702 { 703 USB_KB_DEV *UsbKeyboardDevice; 704 EFI_STATUS Status; 705 EFI_KEY_DATA KeyData; 706 707 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This); 708 709 // 710 // Considering if the partial keystroke is enabled, there maybe a partial 711 // keystroke in the queue, so here skip the partial keystroke and get the 712 // next key from the queue 713 // 714 while (1) { 715 Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData); 716 if (EFI_ERROR (Status)) { 717 return Status; 718 } 719 // 720 // SimpleTextIn Protocol doesn't support partial keystroke; 721 // 722 if (KeyData.Key.ScanCode == CHAR_NULL && KeyData.Key.UnicodeChar == SCAN_NULL) { 723 continue; 724 } 725 // 726 // Translate the CTRL-Alpha characters to their corresponding control value 727 // (ctrl-a = 0x0001 through ctrl-Z = 0x001A) 728 // 729 if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) { 730 if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') { 731 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1); 732 } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') { 733 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1); 734 } 735 } 736 737 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY)); 738 return EFI_SUCCESS; 739 } 740 } 741 742 743 /** 744 Event notification function registered for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx 745 and EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey. 746 747 @param Event Event to be signaled when a key is pressed. 748 @param Context Points to USB_KB_DEV instance. 749 750 **/ 751 VOID 752 EFIAPI 753 USBKeyboardWaitForKey ( 754 IN EFI_EVENT Event, 755 IN VOID *Context 756 ) 757 { 758 USB_KB_DEV *UsbKeyboardDevice; 759 EFI_KEY_DATA KeyData; 760 EFI_TPL OldTpl; 761 762 UsbKeyboardDevice = (USB_KB_DEV *) Context; 763 764 // 765 // Enter critical section 766 // 767 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 768 769 // 770 // WaitforKey doesn't suppor the partial key. 771 // Considering if the partial keystroke is enabled, there maybe a partial 772 // keystroke in the queue, so here skip the partial keystroke and get the 773 // next key from the queue 774 // 775 while (!IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) { 776 // 777 // If there is pending key, signal the event. 778 // 779 CopyMem ( 780 &KeyData, 781 UsbKeyboardDevice->EfiKeyQueue.Buffer[UsbKeyboardDevice->EfiKeyQueue.Head], 782 sizeof (EFI_KEY_DATA) 783 ); 784 if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) { 785 Dequeue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (EFI_KEY_DATA)); 786 continue; 787 } 788 gBS->SignalEvent (Event); 789 break; 790 } 791 // 792 // Leave critical section and return 793 // 794 gBS->RestoreTPL (OldTpl); 795 } 796 797 /** 798 Timer handler to convert the key from USB. 799 800 @param Event Indicates the event that invoke this function. 801 @param Context Indicates the calling context. 802 **/ 803 VOID 804 EFIAPI 805 USBKeyboardTimerHandler ( 806 IN EFI_EVENT Event, 807 IN VOID *Context 808 ) 809 { 810 EFI_STATUS Status; 811 USB_KB_DEV *UsbKeyboardDevice; 812 UINT8 KeyCode; 813 EFI_KEY_DATA KeyData; 814 815 UsbKeyboardDevice = (USB_KB_DEV *) Context; 816 817 // 818 // Fetch raw data from the USB keyboard buffer, 819 // and translate it into USB keycode. 820 // 821 Status = USBParseKey (UsbKeyboardDevice, &KeyCode); 822 if (EFI_ERROR (Status)) { 823 return ; 824 } 825 826 // 827 // Translate saved USB keycode into EFI_INPUT_KEY 828 // 829 Status = UsbKeyCodeToEfiInputKey (UsbKeyboardDevice, KeyCode, &KeyData); 830 if (EFI_ERROR (Status)) { 831 return ; 832 } 833 834 // 835 // Insert to the EFI Key queue 836 // 837 Enqueue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (KeyData)); 838 } 839 840 /** 841 Free keyboard notify list. 842 843 @param NotifyList The keyboard notify list to free. 844 845 @retval EFI_SUCCESS Free the notify list successfully. 846 @retval EFI_INVALID_PARAMETER NotifyList is NULL. 847 848 **/ 849 EFI_STATUS 850 KbdFreeNotifyList ( 851 IN OUT LIST_ENTRY *NotifyList 852 ) 853 { 854 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode; 855 LIST_ENTRY *Link; 856 857 if (NotifyList == NULL) { 858 return EFI_INVALID_PARAMETER; 859 } 860 while (!IsListEmpty (NotifyList)) { 861 Link = GetFirstNode (NotifyList); 862 NotifyNode = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE); 863 RemoveEntryList (Link); 864 FreePool (NotifyNode); 865 } 866 867 return EFI_SUCCESS; 868 } 869 870 /** 871 Check whether the pressed key matches a registered key or not. 872 873 @param RegsiteredData A pointer to keystroke data for the key that was registered. 874 @param InputData A pointer to keystroke data for the key that was pressed. 875 876 @retval TRUE Key pressed matches a registered key. 877 @retval FLASE Key pressed does not matches a registered key. 878 879 **/ 880 BOOLEAN 881 IsKeyRegistered ( 882 IN EFI_KEY_DATA *RegsiteredData, 883 IN EFI_KEY_DATA *InputData 884 ) 885 { 886 ASSERT (RegsiteredData != NULL && InputData != NULL); 887 888 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) || 889 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) { 890 return FALSE; 891 } 892 893 // 894 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored. 895 // 896 if (RegsiteredData->KeyState.KeyShiftState != 0 && 897 RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) { 898 return FALSE; 899 } 900 if (RegsiteredData->KeyState.KeyToggleState != 0 && 901 RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) { 902 return FALSE; 903 } 904 905 return TRUE; 906 } 907 908 // 909 // Simple Text Input Ex protocol functions 910 // 911 /** 912 Resets the input device hardware. 913 914 The Reset() function resets the input device hardware. As part 915 of initialization process, the firmware/device will make a quick 916 but reasonable attempt to verify that the device is functioning. 917 If the ExtendedVerification flag is TRUE the firmware may take 918 an extended amount of time to verify the device is operating on 919 reset. Otherwise the reset operation is to occur as quickly as 920 possible. The hardware verification process is not defined by 921 this specification and is left up to the platform firmware or 922 driver to implement. 923 924 @param This A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance. 925 926 @param ExtendedVerification Indicates that the driver may perform a more exhaustive 927 verification operation of the device during reset. 928 929 @retval EFI_SUCCESS The device was reset. 930 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could not be reset. 931 932 **/ 933 EFI_STATUS 934 EFIAPI 935 USBKeyboardResetEx ( 936 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 937 IN BOOLEAN ExtendedVerification 938 ) 939 { 940 EFI_STATUS Status; 941 USB_KB_DEV *UsbKeyboardDevice; 942 943 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); 944 945 Status = UsbKeyboardDevice->SimpleInput.Reset (&UsbKeyboardDevice->SimpleInput, ExtendedVerification); 946 if (EFI_ERROR (Status)) { 947 return EFI_DEVICE_ERROR; 948 } 949 950 UsbKeyboardDevice->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID; 951 UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID; 952 953 return EFI_SUCCESS; 954 955 } 956 957 /** 958 Reads the next keystroke from the input device. 959 960 @param This Protocol instance pointer. 961 @param KeyData A pointer to a buffer that is filled in with the keystroke 962 state data for the key that was pressed. 963 964 @retval EFI_SUCCESS The keystroke information was returned. 965 @retval EFI_NOT_READY There was no keystroke data available. 966 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to 967 hardware errors. 968 @retval EFI_INVALID_PARAMETER KeyData is NULL. 969 970 **/ 971 EFI_STATUS 972 EFIAPI 973 USBKeyboardReadKeyStrokeEx ( 974 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 975 OUT EFI_KEY_DATA *KeyData 976 ) 977 { 978 USB_KB_DEV *UsbKeyboardDevice; 979 980 if (KeyData == NULL) { 981 return EFI_INVALID_PARAMETER; 982 } 983 984 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); 985 986 return USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, KeyData); 987 988 } 989 990 /** 991 Set certain state for the input device. 992 993 @param This Protocol instance pointer. 994 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the 995 state for the input device. 996 997 @retval EFI_SUCCESS The device state was set appropriately. 998 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could 999 not have the setting adjusted. 1000 @retval EFI_UNSUPPORTED The device does not support the ability to have its state set. 1001 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL. 1002 1003 **/ 1004 EFI_STATUS 1005 EFIAPI 1006 USBKeyboardSetState ( 1007 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 1008 IN EFI_KEY_TOGGLE_STATE *KeyToggleState 1009 ) 1010 { 1011 USB_KB_DEV *UsbKeyboardDevice; 1012 1013 if (KeyToggleState == NULL) { 1014 return EFI_INVALID_PARAMETER; 1015 } 1016 1017 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); 1018 1019 if (((UsbKeyboardDevice->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) || 1020 ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) { 1021 return EFI_UNSUPPORTED; 1022 } 1023 1024 // 1025 // Update the status light 1026 // 1027 1028 UsbKeyboardDevice->ScrollOn = FALSE; 1029 UsbKeyboardDevice->NumLockOn = FALSE; 1030 UsbKeyboardDevice->CapsOn = FALSE; 1031 UsbKeyboardDevice->IsSupportPartialKey = FALSE; 1032 1033 if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) { 1034 UsbKeyboardDevice->ScrollOn = TRUE; 1035 } 1036 if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) { 1037 UsbKeyboardDevice->NumLockOn = TRUE; 1038 } 1039 if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) { 1040 UsbKeyboardDevice->CapsOn = TRUE; 1041 } 1042 if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) { 1043 UsbKeyboardDevice->IsSupportPartialKey = TRUE; 1044 } 1045 1046 SetKeyLED (UsbKeyboardDevice); 1047 1048 UsbKeyboardDevice->KeyState.KeyToggleState = *KeyToggleState; 1049 1050 return EFI_SUCCESS; 1051 1052 } 1053 1054 /** 1055 Register a notification function for a particular keystroke for the input device. 1056 1057 @param This Protocol instance pointer. 1058 @param KeyData A pointer to a buffer that is filled in with the keystroke 1059 information data for the key that was pressed. 1060 @param KeyNotificationFunction Points to the function to be called when the key 1061 sequence is typed specified by KeyData. 1062 @param NotifyHandle Points to the unique handle assigned to the registered notification. 1063 1064 @retval EFI_SUCCESS The notification function was registered successfully. 1065 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data structures. 1066 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle or KeyNotificationFunction is NULL. 1067 1068 **/ 1069 EFI_STATUS 1070 EFIAPI 1071 USBKeyboardRegisterKeyNotify ( 1072 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 1073 IN EFI_KEY_DATA *KeyData, 1074 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, 1075 OUT VOID **NotifyHandle 1076 ) 1077 { 1078 USB_KB_DEV *UsbKeyboardDevice; 1079 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify; 1080 LIST_ENTRY *Link; 1081 LIST_ENTRY *NotifyList; 1082 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 1083 1084 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) { 1085 return EFI_INVALID_PARAMETER; 1086 } 1087 1088 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); 1089 1090 // 1091 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. 1092 // 1093 NotifyList = &UsbKeyboardDevice->NotifyList; 1094 1095 for (Link = GetFirstNode (NotifyList); 1096 !IsNull (NotifyList, Link); 1097 Link = GetNextNode (NotifyList, Link)) { 1098 CurrentNotify = CR ( 1099 Link, 1100 KEYBOARD_CONSOLE_IN_EX_NOTIFY, 1101 NotifyEntry, 1102 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE 1103 ); 1104 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { 1105 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { 1106 *NotifyHandle = CurrentNotify; 1107 return EFI_SUCCESS; 1108 } 1109 } 1110 } 1111 1112 // 1113 // Allocate resource to save the notification function 1114 // 1115 NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY)); 1116 if (NewNotify == NULL) { 1117 return EFI_OUT_OF_RESOURCES; 1118 } 1119 1120 NewNotify->Signature = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE; 1121 NewNotify->KeyNotificationFn = KeyNotificationFunction; 1122 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA)); 1123 InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry); 1124 1125 1126 *NotifyHandle = NewNotify; 1127 1128 return EFI_SUCCESS; 1129 1130 } 1131 1132 /** 1133 Remove a registered notification function from a particular keystroke. 1134 1135 @param This Protocol instance pointer. 1136 @param NotificationHandle The handle of the notification function being unregistered. 1137 1138 @retval EFI_SUCCESS The notification function was unregistered successfully. 1139 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid 1140 1141 **/ 1142 EFI_STATUS 1143 EFIAPI 1144 USBKeyboardUnregisterKeyNotify ( 1145 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 1146 IN VOID *NotificationHandle 1147 ) 1148 { 1149 USB_KB_DEV *UsbKeyboardDevice; 1150 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 1151 LIST_ENTRY *Link; 1152 LIST_ENTRY *NotifyList; 1153 1154 if (NotificationHandle == NULL) { 1155 return EFI_INVALID_PARAMETER; 1156 } 1157 1158 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); 1159 1160 // 1161 // Traverse notify list of USB keyboard and remove the entry of NotificationHandle. 1162 // 1163 NotifyList = &UsbKeyboardDevice->NotifyList; 1164 for (Link = GetFirstNode (NotifyList); 1165 !IsNull (NotifyList, Link); 1166 Link = GetNextNode (NotifyList, Link)) { 1167 CurrentNotify = CR ( 1168 Link, 1169 KEYBOARD_CONSOLE_IN_EX_NOTIFY, 1170 NotifyEntry, 1171 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE 1172 ); 1173 if (CurrentNotify == NotificationHandle) { 1174 // 1175 // Remove the notification function from NotifyList and free resources 1176 // 1177 RemoveEntryList (&CurrentNotify->NotifyEntry); 1178 1179 FreePool (CurrentNotify); 1180 return EFI_SUCCESS; 1181 } 1182 } 1183 1184 // 1185 // Cannot find the matching entry in database. 1186 // 1187 return EFI_INVALID_PARAMETER; 1188 } 1189 1190 /** 1191 Process key notify. 1192 1193 @param Event Indicates the event that invoke this function. 1194 @param Context Indicates the calling context. 1195 **/ 1196 VOID 1197 EFIAPI 1198 KeyNotifyProcessHandler ( 1199 IN EFI_EVENT Event, 1200 IN VOID *Context 1201 ) 1202 { 1203 EFI_STATUS Status; 1204 USB_KB_DEV *UsbKeyboardDevice; 1205 EFI_KEY_DATA KeyData; 1206 LIST_ENTRY *Link; 1207 LIST_ENTRY *NotifyList; 1208 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 1209 EFI_TPL OldTpl; 1210 1211 UsbKeyboardDevice = (USB_KB_DEV *) Context; 1212 1213 // 1214 // Invoke notification functions. 1215 // 1216 NotifyList = &UsbKeyboardDevice->NotifyList; 1217 while (TRUE) { 1218 // 1219 // Enter critical section 1220 // 1221 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 1222 Status = Dequeue (&UsbKeyboardDevice->EfiKeyQueueForNotify, &KeyData, sizeof (KeyData)); 1223 // 1224 // Leave critical section 1225 // 1226 gBS->RestoreTPL (OldTpl); 1227 if (EFI_ERROR (Status)) { 1228 break; 1229 } 1230 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) { 1231 CurrentNotify = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE); 1232 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { 1233 CurrentNotify->KeyNotificationFn (&KeyData); 1234 } 1235 } 1236 } 1237 } 1238 1239