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 - 2012, 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 // 316 // Install Simple Text Input Protocol and Simple Text Input Ex Protocol 317 // for the USB keyboard device. 318 // USB keyboard is a hot plug device, and expected to work immediately 319 // when plugging into system, other conventional console devices could 320 // distinguish it by its device path. 321 // 322 Status = gBS->InstallMultipleProtocolInterfaces ( 323 &Controller, 324 &gEfiSimpleTextInProtocolGuid, 325 &UsbKeyboardDevice->SimpleInput, 326 &gEfiSimpleTextInputExProtocolGuid, 327 &UsbKeyboardDevice->SimpleInputEx, 328 NULL 329 ); 330 if (EFI_ERROR (Status)) { 331 goto ErrorExit; 332 } 333 334 UsbKeyboardDevice->ControllerHandle = Controller; 335 Status = InitKeyboardLayout (UsbKeyboardDevice); 336 if (EFI_ERROR (Status)) { 337 gBS->UninstallMultipleProtocolInterfaces ( 338 Controller, 339 &gEfiSimpleTextInProtocolGuid, 340 &UsbKeyboardDevice->SimpleInput, 341 &gEfiSimpleTextInputExProtocolGuid, 342 &UsbKeyboardDevice->SimpleInputEx, 343 NULL 344 ); 345 goto ErrorExit; 346 } 347 348 349 // 350 // Reset USB Keyboard Device exhaustively. 351 // 352 Status = UsbKeyboardDevice->SimpleInputEx.Reset ( 353 &UsbKeyboardDevice->SimpleInputEx, 354 TRUE 355 ); 356 if (EFI_ERROR (Status)) { 357 gBS->UninstallMultipleProtocolInterfaces ( 358 Controller, 359 &gEfiSimpleTextInProtocolGuid, 360 &UsbKeyboardDevice->SimpleInput, 361 &gEfiSimpleTextInputExProtocolGuid, 362 &UsbKeyboardDevice->SimpleInputEx, 363 NULL 364 ); 365 goto ErrorExit; 366 } 367 368 // 369 // Submit Asynchronous Interrupt Transfer to manage this device. 370 // 371 EndpointAddr = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress; 372 PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval; 373 PacketSize = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize); 374 375 Status = UsbIo->UsbAsyncInterruptTransfer ( 376 UsbIo, 377 EndpointAddr, 378 TRUE, 379 PollingInterval, 380 PacketSize, 381 KeyboardHandler, 382 UsbKeyboardDevice 383 ); 384 385 if (EFI_ERROR (Status)) { 386 gBS->UninstallMultipleProtocolInterfaces ( 387 Controller, 388 &gEfiSimpleTextInProtocolGuid, 389 &UsbKeyboardDevice->SimpleInput, 390 &gEfiSimpleTextInputExProtocolGuid, 391 &UsbKeyboardDevice->SimpleInputEx, 392 NULL 393 ); 394 goto ErrorExit; 395 } 396 397 UsbKeyboardDevice->ControllerNameTable = NULL; 398 AddUnicodeString2 ( 399 "eng", 400 gUsbKeyboardComponentName.SupportedLanguages, 401 &UsbKeyboardDevice->ControllerNameTable, 402 L"Generic Usb Keyboard", 403 TRUE 404 ); 405 AddUnicodeString2 ( 406 "en", 407 gUsbKeyboardComponentName2.SupportedLanguages, 408 &UsbKeyboardDevice->ControllerNameTable, 409 L"Generic Usb Keyboard", 410 FALSE 411 ); 412 413 gBS->RestoreTPL (OldTpl); 414 return EFI_SUCCESS; 415 416 // 417 // Error handler 418 // 419 ErrorExit: 420 if (UsbKeyboardDevice != NULL) { 421 if (UsbKeyboardDevice->TimerEvent != NULL) { 422 gBS->CloseEvent (UsbKeyboardDevice->TimerEvent); 423 } 424 if (UsbKeyboardDevice->SimpleInput.WaitForKey != NULL) { 425 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); 426 } 427 if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) { 428 gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx); 429 } 430 if (UsbKeyboardDevice->KeyboardLayoutEvent != NULL) { 431 ReleaseKeyboardLayoutResources (UsbKeyboardDevice); 432 gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent); 433 } 434 FreePool (UsbKeyboardDevice); 435 UsbKeyboardDevice = NULL; 436 } 437 gBS->CloseProtocol ( 438 Controller, 439 &gEfiUsbIoProtocolGuid, 440 This->DriverBindingHandle, 441 Controller 442 ); 443 444 ErrorExit1: 445 gBS->RestoreTPL (OldTpl); 446 447 return Status; 448 449 } 450 451 452 /** 453 Stop the USB keyboard device handled by this driver. 454 455 @param This The USB keyboard driver binding protocol. 456 @param Controller The controller to release. 457 @param NumberOfChildren The number of handles in ChildHandleBuffer. 458 @param ChildHandleBuffer The array of child handle. 459 460 @retval EFI_SUCCESS The device was stopped. 461 @retval EFI_UNSUPPORTED Simple Text In Protocol or Simple Text In Ex Protocol 462 is not installed on Controller. 463 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. 464 @retval Others Fail to uninstall protocols attached on the device. 465 466 **/ 467 EFI_STATUS 468 EFIAPI 469 USBKeyboardDriverBindingStop ( 470 IN EFI_DRIVER_BINDING_PROTOCOL *This, 471 IN EFI_HANDLE Controller, 472 IN UINTN NumberOfChildren, 473 IN EFI_HANDLE *ChildHandleBuffer 474 ) 475 { 476 EFI_STATUS Status; 477 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleInput; 478 USB_KB_DEV *UsbKeyboardDevice; 479 480 Status = gBS->OpenProtocol ( 481 Controller, 482 &gEfiSimpleTextInProtocolGuid, 483 (VOID **) &SimpleInput, 484 This->DriverBindingHandle, 485 Controller, 486 EFI_OPEN_PROTOCOL_GET_PROTOCOL 487 ); 488 if (EFI_ERROR (Status)) { 489 return EFI_UNSUPPORTED; 490 } 491 492 Status = gBS->OpenProtocol ( 493 Controller, 494 &gEfiSimpleTextInputExProtocolGuid, 495 NULL, 496 This->DriverBindingHandle, 497 Controller, 498 EFI_OPEN_PROTOCOL_TEST_PROTOCOL 499 ); 500 if (EFI_ERROR (Status)) { 501 return EFI_UNSUPPORTED; 502 } 503 504 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput); 505 506 // 507 // The key data input from this device will be disabled. 508 // 509 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 510 EFI_PROGRESS_CODE, 511 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE), 512 UsbKeyboardDevice->DevicePath 513 ); 514 515 // 516 // Delete the Asynchronous Interrupt Transfer from this device 517 // 518 UsbKeyboardDevice->UsbIo->UsbAsyncInterruptTransfer ( 519 UsbKeyboardDevice->UsbIo, 520 UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress, 521 FALSE, 522 UsbKeyboardDevice->IntEndpointDescriptor.Interval, 523 0, 524 NULL, 525 NULL 526 ); 527 528 gBS->CloseProtocol ( 529 Controller, 530 &gEfiUsbIoProtocolGuid, 531 This->DriverBindingHandle, 532 Controller 533 ); 534 535 Status = gBS->UninstallMultipleProtocolInterfaces ( 536 Controller, 537 &gEfiSimpleTextInProtocolGuid, 538 &UsbKeyboardDevice->SimpleInput, 539 &gEfiSimpleTextInputExProtocolGuid, 540 &UsbKeyboardDevice->SimpleInputEx, 541 NULL 542 ); 543 // 544 // Free all resources. 545 // 546 gBS->CloseEvent (UsbKeyboardDevice->TimerEvent); 547 gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer); 548 gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent); 549 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); 550 gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx); 551 KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList); 552 553 ReleaseKeyboardLayoutResources (UsbKeyboardDevice); 554 gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent); 555 556 if (UsbKeyboardDevice->ControllerNameTable != NULL) { 557 FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable); 558 } 559 560 DestroyQueue (&UsbKeyboardDevice->UsbKeyQueue); 561 DestroyQueue (&UsbKeyboardDevice->EfiKeyQueue); 562 563 FreePool (UsbKeyboardDevice); 564 565 return Status; 566 } 567 568 /** 569 Internal function to read the next keystroke from the keyboard buffer. 570 571 @param UsbKeyboardDevice USB keyboard's private structure. 572 @param KeyData A pointer to buffer to hold the keystroke 573 data for the key that was pressed. 574 575 @retval EFI_SUCCESS The keystroke information was returned. 576 @retval EFI_NOT_READY There was no keystroke data availiable. 577 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to 578 hardware errors. 579 @retval EFI_INVALID_PARAMETER KeyData is NULL. 580 @retval Others Fail to translate keycode into EFI_INPUT_KEY 581 582 **/ 583 EFI_STATUS 584 USBKeyboardReadKeyStrokeWorker ( 585 IN OUT USB_KB_DEV *UsbKeyboardDevice, 586 OUT EFI_KEY_DATA *KeyData 587 ) 588 { 589 if (KeyData == NULL) { 590 return EFI_INVALID_PARAMETER; 591 } 592 593 if (IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) { 594 return EFI_NOT_READY; 595 } 596 597 Dequeue (&UsbKeyboardDevice->EfiKeyQueue, KeyData, sizeof (*KeyData)); 598 599 return EFI_SUCCESS; 600 } 601 602 /** 603 Reset the input device and optionally run diagnostics 604 605 There are 2 types of reset for USB keyboard. 606 For non-exhaustive reset, only keyboard buffer is cleared. 607 For exhaustive reset, in addition to clearance of keyboard buffer, the hardware status 608 is also re-initialized. 609 610 @param This Protocol instance pointer. 611 @param ExtendedVerification Driver may perform diagnostics on reset. 612 613 @retval EFI_SUCCESS The device was reset. 614 @retval EFI_DEVICE_ERROR The device is not functioning properly and could not be reset. 615 616 **/ 617 EFI_STATUS 618 EFIAPI 619 USBKeyboardReset ( 620 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, 621 IN BOOLEAN ExtendedVerification 622 ) 623 { 624 EFI_STATUS Status; 625 USB_KB_DEV *UsbKeyboardDevice; 626 627 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This); 628 629 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 630 EFI_PROGRESS_CODE, 631 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET), 632 UsbKeyboardDevice->DevicePath 633 ); 634 635 // 636 // Non-exhaustive reset: 637 // only reset private data structures. 638 // 639 if (!ExtendedVerification) { 640 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 641 EFI_PROGRESS_CODE, 642 (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER), 643 UsbKeyboardDevice->DevicePath 644 ); 645 // 646 // Clear the key buffer of this USB keyboard 647 // 648 InitQueue (&UsbKeyboardDevice->UsbKeyQueue, sizeof (USB_KEY)); 649 InitQueue (&UsbKeyboardDevice->EfiKeyQueue, sizeof (EFI_KEY_DATA)); 650 651 return EFI_SUCCESS; 652 } 653 654 // 655 // Exhaustive reset 656 // 657 Status = InitUSBKeyboard (UsbKeyboardDevice); 658 if (EFI_ERROR (Status)) { 659 return EFI_DEVICE_ERROR; 660 } 661 662 return EFI_SUCCESS; 663 } 664 665 666 /** 667 Reads the next keystroke from the input device. 668 669 @param This The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance. 670 @param Key A pointer to a buffer that is filled in with the keystroke 671 information for the key that was pressed. 672 673 @retval EFI_SUCCESS The keystroke information was returned. 674 @retval EFI_NOT_READY There was no keystroke data availiable. 675 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to 676 hardware errors. 677 678 **/ 679 EFI_STATUS 680 EFIAPI 681 USBKeyboardReadKeyStroke ( 682 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, 683 OUT EFI_INPUT_KEY *Key 684 ) 685 { 686 USB_KB_DEV *UsbKeyboardDevice; 687 EFI_STATUS Status; 688 EFI_KEY_DATA KeyData; 689 690 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This); 691 692 // 693 // Considering if the partial keystroke is enabled, there maybe a partial 694 // keystroke in the queue, so here skip the partial keystroke and get the 695 // next key from the queue 696 // 697 while (1) { 698 Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData); 699 if (EFI_ERROR (Status)) { 700 return Status; 701 } 702 // 703 // SimpleTextIn Protocol doesn't support partial keystroke; 704 // 705 if (KeyData.Key.ScanCode == CHAR_NULL && KeyData.Key.UnicodeChar == SCAN_NULL) { 706 continue; 707 } 708 // 709 // Translate the CTRL-Alpha characters to their corresponding control value 710 // (ctrl-a = 0x0001 through ctrl-Z = 0x001A) 711 // 712 if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) { 713 if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') { 714 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1); 715 } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') { 716 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1); 717 } 718 } 719 720 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY)); 721 return EFI_SUCCESS; 722 } 723 } 724 725 726 /** 727 Event notification function registered for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx 728 and EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey. 729 730 @param Event Event to be signaled when a key is pressed. 731 @param Context Points to USB_KB_DEV instance. 732 733 **/ 734 VOID 735 EFIAPI 736 USBKeyboardWaitForKey ( 737 IN EFI_EVENT Event, 738 IN VOID *Context 739 ) 740 { 741 USB_KB_DEV *UsbKeyboardDevice; 742 EFI_KEY_DATA KeyData; 743 EFI_TPL OldTpl; 744 745 UsbKeyboardDevice = (USB_KB_DEV *) Context; 746 747 // 748 // Enter critical section 749 // 750 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 751 752 // 753 // WaitforKey doesn't suppor the partial key. 754 // Considering if the partial keystroke is enabled, there maybe a partial 755 // keystroke in the queue, so here skip the partial keystroke and get the 756 // next key from the queue 757 // 758 while (!IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) { 759 // 760 // If there is pending key, signal the event. 761 // 762 CopyMem ( 763 &KeyData, 764 UsbKeyboardDevice->EfiKeyQueue.Buffer[UsbKeyboardDevice->EfiKeyQueue.Head], 765 sizeof (EFI_KEY_DATA) 766 ); 767 if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) { 768 Dequeue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (EFI_KEY_DATA)); 769 continue; 770 } 771 gBS->SignalEvent (Event); 772 break; 773 } 774 // 775 // Leave critical section and return 776 // 777 gBS->RestoreTPL (OldTpl); 778 } 779 780 /** 781 Timer handler to convert the key from USB. 782 783 @param Event Indicates the event that invoke this function. 784 @param Context Indicates the calling context. 785 **/ 786 VOID 787 EFIAPI 788 USBKeyboardTimerHandler ( 789 IN EFI_EVENT Event, 790 IN VOID *Context 791 ) 792 { 793 EFI_STATUS Status; 794 USB_KB_DEV *UsbKeyboardDevice; 795 UINT8 KeyCode; 796 EFI_KEY_DATA KeyData; 797 798 UsbKeyboardDevice = (USB_KB_DEV *) Context; 799 800 // 801 // Fetch raw data from the USB keyboard buffer, 802 // and translate it into USB keycode. 803 // 804 Status = USBParseKey (UsbKeyboardDevice, &KeyCode); 805 if (EFI_ERROR (Status)) { 806 return ; 807 } 808 809 // 810 // Translate saved USB keycode into EFI_INPUT_KEY 811 // 812 Status = UsbKeyCodeToEfiInputKey (UsbKeyboardDevice, KeyCode, &KeyData); 813 if (EFI_ERROR (Status)) { 814 return ; 815 } 816 817 // 818 // Insert to the EFI Key queue 819 // 820 Enqueue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (KeyData)); 821 } 822 823 /** 824 Free keyboard notify list. 825 826 @param NotifyList The keyboard notify list to free. 827 828 @retval EFI_SUCCESS Free the notify list successfully. 829 @retval EFI_INVALID_PARAMETER NotifyList is NULL. 830 831 **/ 832 EFI_STATUS 833 KbdFreeNotifyList ( 834 IN OUT LIST_ENTRY *NotifyList 835 ) 836 { 837 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode; 838 LIST_ENTRY *Link; 839 840 if (NotifyList == NULL) { 841 return EFI_INVALID_PARAMETER; 842 } 843 while (!IsListEmpty (NotifyList)) { 844 Link = GetFirstNode (NotifyList); 845 NotifyNode = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE); 846 RemoveEntryList (Link); 847 FreePool (NotifyNode); 848 } 849 850 return EFI_SUCCESS; 851 } 852 853 /** 854 Check whether the pressed key matches a registered key or not. 855 856 @param RegsiteredData A pointer to keystroke data for the key that was registered. 857 @param InputData A pointer to keystroke data for the key that was pressed. 858 859 @retval TRUE Key pressed matches a registered key. 860 @retval FLASE Key pressed does not matches a registered key. 861 862 **/ 863 BOOLEAN 864 IsKeyRegistered ( 865 IN EFI_KEY_DATA *RegsiteredData, 866 IN EFI_KEY_DATA *InputData 867 ) 868 { 869 ASSERT (RegsiteredData != NULL && InputData != NULL); 870 871 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) || 872 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) { 873 return FALSE; 874 } 875 876 // 877 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored. 878 // 879 if (RegsiteredData->KeyState.KeyShiftState != 0 && 880 RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) { 881 return FALSE; 882 } 883 if (RegsiteredData->KeyState.KeyToggleState != 0 && 884 RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) { 885 return FALSE; 886 } 887 888 return TRUE; 889 } 890 891 // 892 // Simple Text Input Ex protocol functions 893 // 894 /** 895 Resets the input device hardware. 896 897 The Reset() function resets the input device hardware. As part 898 of initialization process, the firmware/device will make a quick 899 but reasonable attempt to verify that the device is functioning. 900 If the ExtendedVerification flag is TRUE the firmware may take 901 an extended amount of time to verify the device is operating on 902 reset. Otherwise the reset operation is to occur as quickly as 903 possible. The hardware verification process is not defined by 904 this specification and is left up to the platform firmware or 905 driver to implement. 906 907 @param This A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance. 908 909 @param ExtendedVerification Indicates that the driver may perform a more exhaustive 910 verification operation of the device during reset. 911 912 @retval EFI_SUCCESS The device was reset. 913 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could not be reset. 914 915 **/ 916 EFI_STATUS 917 EFIAPI 918 USBKeyboardResetEx ( 919 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 920 IN BOOLEAN ExtendedVerification 921 ) 922 { 923 EFI_STATUS Status; 924 USB_KB_DEV *UsbKeyboardDevice; 925 926 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); 927 928 Status = UsbKeyboardDevice->SimpleInput.Reset (&UsbKeyboardDevice->SimpleInput, ExtendedVerification); 929 if (EFI_ERROR (Status)) { 930 return EFI_DEVICE_ERROR; 931 } 932 933 UsbKeyboardDevice->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID; 934 UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID; 935 936 return EFI_SUCCESS; 937 938 } 939 940 /** 941 Reads the next keystroke from the input device. 942 943 @param This Protocol instance pointer. 944 @param KeyData A pointer to a buffer that is filled in with the keystroke 945 state data for the key that was pressed. 946 947 @retval EFI_SUCCESS The keystroke information was returned. 948 @retval EFI_NOT_READY There was no keystroke data available. 949 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to 950 hardware errors. 951 @retval EFI_INVALID_PARAMETER KeyData is NULL. 952 953 **/ 954 EFI_STATUS 955 EFIAPI 956 USBKeyboardReadKeyStrokeEx ( 957 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 958 OUT EFI_KEY_DATA *KeyData 959 ) 960 { 961 USB_KB_DEV *UsbKeyboardDevice; 962 963 if (KeyData == NULL) { 964 return EFI_INVALID_PARAMETER; 965 } 966 967 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); 968 969 return USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, KeyData); 970 971 } 972 973 /** 974 Set certain state for the input device. 975 976 @param This Protocol instance pointer. 977 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the 978 state for the input device. 979 980 @retval EFI_SUCCESS The device state was set appropriately. 981 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could 982 not have the setting adjusted. 983 @retval EFI_UNSUPPORTED The device does not support the ability to have its state set. 984 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL. 985 986 **/ 987 EFI_STATUS 988 EFIAPI 989 USBKeyboardSetState ( 990 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 991 IN EFI_KEY_TOGGLE_STATE *KeyToggleState 992 ) 993 { 994 USB_KB_DEV *UsbKeyboardDevice; 995 996 if (KeyToggleState == NULL) { 997 return EFI_INVALID_PARAMETER; 998 } 999 1000 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); 1001 1002 if (((UsbKeyboardDevice->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) || 1003 ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) { 1004 return EFI_UNSUPPORTED; 1005 } 1006 1007 // 1008 // Update the status light 1009 // 1010 1011 UsbKeyboardDevice->ScrollOn = FALSE; 1012 UsbKeyboardDevice->NumLockOn = FALSE; 1013 UsbKeyboardDevice->CapsOn = FALSE; 1014 UsbKeyboardDevice->IsSupportPartialKey = FALSE; 1015 1016 if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) { 1017 UsbKeyboardDevice->ScrollOn = TRUE; 1018 } 1019 if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) { 1020 UsbKeyboardDevice->NumLockOn = TRUE; 1021 } 1022 if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) { 1023 UsbKeyboardDevice->CapsOn = TRUE; 1024 } 1025 if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) { 1026 UsbKeyboardDevice->IsSupportPartialKey = TRUE; 1027 } 1028 1029 SetKeyLED (UsbKeyboardDevice); 1030 1031 UsbKeyboardDevice->KeyState.KeyToggleState = *KeyToggleState; 1032 1033 return EFI_SUCCESS; 1034 1035 } 1036 1037 /** 1038 Register a notification function for a particular keystroke for the input device. 1039 1040 @param This Protocol instance pointer. 1041 @param KeyData A pointer to a buffer that is filled in with the keystroke 1042 information data for the key that was pressed. 1043 @param KeyNotificationFunction Points to the function to be called when the key 1044 sequence is typed specified by KeyData. 1045 @param NotifyHandle Points to the unique handle assigned to the registered notification. 1046 1047 @retval EFI_SUCCESS The notification function was registered successfully. 1048 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data structures. 1049 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle or KeyNotificationFunction is NULL. 1050 1051 **/ 1052 EFI_STATUS 1053 EFIAPI 1054 USBKeyboardRegisterKeyNotify ( 1055 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 1056 IN EFI_KEY_DATA *KeyData, 1057 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, 1058 OUT VOID **NotifyHandle 1059 ) 1060 { 1061 USB_KB_DEV *UsbKeyboardDevice; 1062 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify; 1063 LIST_ENTRY *Link; 1064 LIST_ENTRY *NotifyList; 1065 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 1066 1067 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) { 1068 return EFI_INVALID_PARAMETER; 1069 } 1070 1071 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); 1072 1073 // 1074 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. 1075 // 1076 NotifyList = &UsbKeyboardDevice->NotifyList; 1077 1078 for (Link = GetFirstNode (NotifyList); 1079 !IsNull (NotifyList, Link); 1080 Link = GetNextNode (NotifyList, Link)) { 1081 CurrentNotify = CR ( 1082 Link, 1083 KEYBOARD_CONSOLE_IN_EX_NOTIFY, 1084 NotifyEntry, 1085 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE 1086 ); 1087 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { 1088 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { 1089 *NotifyHandle = CurrentNotify; 1090 return EFI_SUCCESS; 1091 } 1092 } 1093 } 1094 1095 // 1096 // Allocate resource to save the notification function 1097 // 1098 NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY)); 1099 if (NewNotify == NULL) { 1100 return EFI_OUT_OF_RESOURCES; 1101 } 1102 1103 NewNotify->Signature = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE; 1104 NewNotify->KeyNotificationFn = KeyNotificationFunction; 1105 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA)); 1106 InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry); 1107 1108 1109 *NotifyHandle = NewNotify; 1110 1111 return EFI_SUCCESS; 1112 1113 } 1114 1115 /** 1116 Remove a registered notification function from a particular keystroke. 1117 1118 @param This Protocol instance pointer. 1119 @param NotificationHandle The handle of the notification function being unregistered. 1120 1121 @retval EFI_SUCCESS The notification function was unregistered successfully. 1122 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid 1123 1124 **/ 1125 EFI_STATUS 1126 EFIAPI 1127 USBKeyboardUnregisterKeyNotify ( 1128 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 1129 IN VOID *NotificationHandle 1130 ) 1131 { 1132 USB_KB_DEV *UsbKeyboardDevice; 1133 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 1134 LIST_ENTRY *Link; 1135 LIST_ENTRY *NotifyList; 1136 1137 if (NotificationHandle == NULL) { 1138 return EFI_INVALID_PARAMETER; 1139 } 1140 1141 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); 1142 1143 // 1144 // Traverse notify list of USB keyboard and remove the entry of NotificationHandle. 1145 // 1146 NotifyList = &UsbKeyboardDevice->NotifyList; 1147 for (Link = GetFirstNode (NotifyList); 1148 !IsNull (NotifyList, Link); 1149 Link = GetNextNode (NotifyList, Link)) { 1150 CurrentNotify = CR ( 1151 Link, 1152 KEYBOARD_CONSOLE_IN_EX_NOTIFY, 1153 NotifyEntry, 1154 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE 1155 ); 1156 if (CurrentNotify == NotificationHandle) { 1157 // 1158 // Remove the notification function from NotifyList and free resources 1159 // 1160 RemoveEntryList (&CurrentNotify->NotifyEntry); 1161 1162 FreePool (CurrentNotify); 1163 return EFI_SUCCESS; 1164 } 1165 } 1166 1167 // 1168 // Cannot find the matching entry in database. 1169 // 1170 return EFI_INVALID_PARAMETER; 1171 } 1172 1173