1 /** @file 2 Routines implements SIMPLE_TEXT_IN protocol's interfaces based on 8042 interfaces 3 provided by Ps2KbdCtrller.c. 4 5 Copyright (c) 2006 - 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 17 #include "Ps2Keyboard.h" 18 19 /** 20 Check whether the EFI key buffer is empty. 21 22 @param Queue Pointer to instance of EFI_KEY_QUEUE. 23 24 @retval TRUE The EFI key buffer is empty. 25 @retval FALSE The EFI key buffer isn't empty. 26 **/ 27 BOOLEAN 28 IsEfikeyBufEmpty ( 29 IN EFI_KEY_QUEUE *Queue 30 ) 31 { 32 return (BOOLEAN) (Queue->Head == Queue->Tail); 33 } 34 35 /** 36 Read & remove one key data from the EFI key buffer. 37 38 @param Queue Pointer to instance of EFI_KEY_QUEUE. 39 @param KeyData Receive the key data. 40 41 @retval EFI_SUCCESS The key data is popped successfully. 42 @retval EFI_NOT_READY There is no key data available. 43 **/ 44 EFI_STATUS 45 PopEfikeyBufHead ( 46 IN EFI_KEY_QUEUE *Queue, 47 OUT EFI_KEY_DATA *KeyData OPTIONAL 48 ) 49 { 50 if (IsEfikeyBufEmpty (Queue)) { 51 return EFI_NOT_READY; 52 } 53 // 54 // Retrieve and remove the values 55 // 56 if (KeyData != NULL) { 57 CopyMem (KeyData, &Queue->Buffer[Queue->Head], sizeof (EFI_KEY_DATA)); 58 } 59 Queue->Head = (Queue->Head + 1) % KEYBOARD_EFI_KEY_MAX_COUNT; 60 return EFI_SUCCESS; 61 } 62 63 /** 64 Push one key data to the EFI key buffer. 65 66 @param Queue Pointer to instance of EFI_KEY_QUEUE. 67 @param KeyData The key data to push. 68 **/ 69 VOID 70 PushEfikeyBufTail ( 71 IN EFI_KEY_QUEUE *Queue, 72 IN EFI_KEY_DATA *KeyData 73 ) 74 { 75 if ((Queue->Tail + 1) % KEYBOARD_EFI_KEY_MAX_COUNT == Queue->Head) { 76 // 77 // If Queue is full, pop the one from head. 78 // 79 PopEfikeyBufHead (Queue, NULL); 80 } 81 CopyMem (&Queue->Buffer[Queue->Tail], KeyData, sizeof (EFI_KEY_DATA)); 82 Queue->Tail = (Queue->Tail + 1) % KEYBOARD_EFI_KEY_MAX_COUNT; 83 } 84 85 /** 86 Judge whether is a registed key 87 88 @param RegsiteredData A pointer to a buffer that is filled in with the keystroke 89 state data for the key that was registered. 90 @param InputData A pointer to a buffer that is filled in with the keystroke 91 state data for the key that was pressed. 92 93 @retval TRUE Key be pressed matches a registered key. 94 @retval FLASE Match failed. 95 96 **/ 97 BOOLEAN 98 IsKeyRegistered ( 99 IN EFI_KEY_DATA *RegsiteredData, 100 IN EFI_KEY_DATA *InputData 101 ) 102 103 { 104 ASSERT (RegsiteredData != NULL && InputData != NULL); 105 106 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) || 107 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) { 108 return FALSE; 109 } 110 111 // 112 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored. 113 // 114 if (RegsiteredData->KeyState.KeyShiftState != 0 && 115 RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) { 116 return FALSE; 117 } 118 if (RegsiteredData->KeyState.KeyToggleState != 0 && 119 RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) { 120 return FALSE; 121 } 122 123 return TRUE; 124 125 } 126 127 /** 128 Reads the next keystroke from the input device. The WaitForKey Event can 129 be used to test for existance of a keystroke via WaitForEvent () call. 130 131 @param ConsoleInDev Ps2 Keyboard private structure 132 @param KeyData A pointer to a buffer that is filled in with the keystroke 133 state data for the key that was pressed. 134 135 136 @retval EFI_SUCCESS The keystroke information was returned. 137 @retval EFI_NOT_READY There was no keystroke data availiable. 138 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to 139 hardware errors. 140 @retval EFI_INVALID_PARAMETER KeyData is NULL. 141 142 **/ 143 EFI_STATUS 144 KeyboardReadKeyStrokeWorker ( 145 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev, 146 OUT EFI_KEY_DATA *KeyData 147 ) 148 149 { 150 EFI_STATUS Status; 151 EFI_TPL OldTpl; 152 153 if (KeyData == NULL) { 154 return EFI_INVALID_PARAMETER; 155 } 156 157 // 158 // Enter critical section 159 // 160 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 161 162 KeyboardTimerHandler (NULL, ConsoleInDev); 163 164 if (ConsoleInDev->KeyboardErr) { 165 Status = EFI_DEVICE_ERROR; 166 } else { 167 Status = PopEfikeyBufHead (&ConsoleInDev->EfiKeyQueue, KeyData); 168 } 169 170 gBS->RestoreTPL (OldTpl); 171 return Status; 172 } 173 174 /** 175 Perform 8042 controller and keyboard initialization which implement SIMPLE_TEXT_IN.Reset() 176 177 @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL 178 @param ExtendedVerification Indicate that the driver may perform a more 179 exhaustive verification operation of the device during 180 reset, now this par is ignored in this driver 181 182 **/ 183 EFI_STATUS 184 EFIAPI 185 KeyboardEfiReset ( 186 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, 187 IN BOOLEAN ExtendedVerification 188 ) 189 { 190 EFI_STATUS Status; 191 KEYBOARD_CONSOLE_IN_DEV *ConsoleIn; 192 EFI_TPL OldTpl; 193 194 ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This); 195 if (ConsoleIn->KeyboardErr) { 196 return EFI_DEVICE_ERROR; 197 } 198 199 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 200 EFI_PROGRESS_CODE, 201 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET, 202 ConsoleIn->DevicePath 203 ); 204 205 // 206 // Enter critical section 207 // 208 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 209 210 // 211 // Call InitKeyboard to initialize the keyboard 212 // 213 Status = InitKeyboard (ConsoleIn, ExtendedVerification); 214 if (EFI_ERROR (Status)) { 215 // 216 // Leave critical section and return 217 // 218 gBS->RestoreTPL (OldTpl); 219 return EFI_DEVICE_ERROR; 220 } 221 222 // 223 // Leave critical section and return 224 // 225 gBS->RestoreTPL (OldTpl); 226 227 // 228 // Report the status If a stuck key was detected 229 // 230 if (KeyReadStatusRegister (ConsoleIn) & 0x01) { 231 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 232 EFI_ERROR_CODE | EFI_ERROR_MINOR, 233 EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_EC_STUCK_KEY, 234 ConsoleIn->DevicePath 235 ); 236 } 237 // 238 // Report the status If keyboard is locked 239 // 240 if ((KeyReadStatusRegister (ConsoleIn) & 0x10) == 0) { 241 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 242 EFI_ERROR_CODE | EFI_ERROR_MINOR, 243 EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_EC_LOCKED, 244 ConsoleIn->DevicePath 245 ); 246 } 247 248 return EFI_SUCCESS; 249 } 250 251 /** 252 Retrieve key values for driver user which implement SIMPLE_TEXT_IN.ReadKeyStroke(). 253 254 @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL 255 @param Key The output buffer for key value 256 257 @retval EFI_SUCCESS success to read key stroke 258 **/ 259 EFI_STATUS 260 EFIAPI 261 KeyboardReadKeyStroke ( 262 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, 263 OUT EFI_INPUT_KEY *Key 264 ) 265 { 266 EFI_STATUS Status; 267 KEYBOARD_CONSOLE_IN_DEV *ConsoleIn; 268 EFI_KEY_DATA KeyData; 269 270 ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This); 271 272 // 273 // Considering if the partial keystroke is enabled, there maybe a partial 274 // keystroke in the queue, so here skip the partial keystroke and get the 275 // next key from the queue 276 // 277 while (1) { 278 // 279 // If there is no pending key, then return. 280 // 281 Status = KeyboardReadKeyStrokeWorker (ConsoleIn, &KeyData); 282 if (EFI_ERROR (Status)) { 283 return Status; 284 } 285 // 286 // If it is partial keystroke, skip it. 287 // 288 if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) { 289 continue; 290 } 291 // 292 // Translate the CTRL-Alpha characters to their corresponding control value 293 // (ctrl-a = 0x0001 through ctrl-Z = 0x001A) 294 // 295 if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) { 296 if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') { 297 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1); 298 } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') { 299 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1); 300 } 301 } 302 303 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY)); 304 return EFI_SUCCESS; 305 } 306 } 307 308 /** 309 Event notification function for SIMPLE_TEXT_IN.WaitForKey event 310 Signal the event if there is key available 311 312 @param Event the event object 313 @param Context waitting context 314 315 **/ 316 VOID 317 EFIAPI 318 KeyboardWaitForKey ( 319 IN EFI_EVENT Event, 320 IN VOID *Context 321 ) 322 { 323 EFI_TPL OldTpl; 324 KEYBOARD_CONSOLE_IN_DEV *ConsoleIn; 325 EFI_KEY_DATA KeyData; 326 327 ConsoleIn = (KEYBOARD_CONSOLE_IN_DEV *) Context; 328 329 // 330 // Enter critical section 331 // 332 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 333 334 KeyboardTimerHandler (NULL, ConsoleIn); 335 336 if (!ConsoleIn->KeyboardErr) { 337 // 338 // WaitforKey doesn't suppor the partial key. 339 // Considering if the partial keystroke is enabled, there maybe a partial 340 // keystroke in the queue, so here skip the partial keystroke and get the 341 // next key from the queue 342 // 343 while (!IsEfikeyBufEmpty (&ConsoleIn->EfiKeyQueue)) { 344 CopyMem ( 345 &KeyData, 346 &(ConsoleIn->EfiKeyQueue.Buffer[ConsoleIn->EfiKeyQueue.Head]), 347 sizeof (EFI_KEY_DATA) 348 ); 349 if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) { 350 PopEfikeyBufHead (&ConsoleIn->EfiKeyQueue, &KeyData); 351 continue; 352 } 353 // 354 // if there is pending value key, signal the event. 355 // 356 gBS->SignalEvent (Event); 357 break; 358 } 359 } 360 // 361 // Leave critical section and return 362 // 363 gBS->RestoreTPL (OldTpl); 364 } 365 366 /** 367 Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event 368 Signal the event if there is key available 369 370 @param Event event object 371 @param Context waiting context 372 373 **/ 374 VOID 375 EFIAPI 376 KeyboardWaitForKeyEx ( 377 IN EFI_EVENT Event, 378 IN VOID *Context 379 ) 380 381 { 382 KeyboardWaitForKey (Event, Context); 383 } 384 385 /** 386 Reset the input device and optionaly run diagnostics 387 388 @param This Protocol instance pointer. 389 @param ExtendedVerification Driver may perform diagnostics on reset. 390 391 @retval EFI_SUCCESS The device was reset. 392 @retval EFI_DEVICE_ERROR The device is not functioning properly and could 393 not be reset. 394 395 **/ 396 EFI_STATUS 397 EFIAPI 398 KeyboardEfiResetEx ( 399 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 400 IN BOOLEAN ExtendedVerification 401 ) 402 403 { 404 KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev; 405 406 ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This); 407 408 return ConsoleInDev->ConIn.Reset ( 409 &ConsoleInDev->ConIn, 410 ExtendedVerification 411 ); 412 } 413 414 /** 415 Reads the next keystroke from the input device. The WaitForKey Event can 416 be used to test for existance of a keystroke via WaitForEvent () call. 417 418 419 @param This Protocol instance pointer. 420 @param KeyData A pointer to a buffer that is filled in with the keystroke 421 state data for the key that was pressed. 422 423 @retval EFI_SUCCESS The keystroke information was returned. 424 @retval EFI_NOT_READY There was no keystroke data availiable. 425 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to 426 hardware errors. 427 @retval EFI_INVALID_PARAMETER KeyData is NULL. 428 429 **/ 430 EFI_STATUS 431 EFIAPI 432 KeyboardReadKeyStrokeEx ( 433 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 434 OUT EFI_KEY_DATA *KeyData 435 ) 436 437 { 438 KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev; 439 440 if (KeyData == NULL) { 441 return EFI_INVALID_PARAMETER; 442 } 443 444 ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This); 445 return KeyboardReadKeyStrokeWorker (ConsoleInDev, KeyData); 446 } 447 448 /** 449 Set certain state for the input device. 450 451 @param This Protocol instance pointer. 452 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the 453 state for the input device. 454 455 @retval EFI_SUCCESS The device state was set successfully. 456 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could 457 not have the setting adjusted. 458 @retval EFI_UNSUPPORTED The device does not have the ability to set its state. 459 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL. 460 461 **/ 462 EFI_STATUS 463 EFIAPI 464 KeyboardSetState ( 465 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 466 IN EFI_KEY_TOGGLE_STATE *KeyToggleState 467 ) 468 469 { 470 EFI_STATUS Status; 471 KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev; 472 EFI_TPL OldTpl; 473 474 if (KeyToggleState == NULL) { 475 return EFI_INVALID_PARAMETER; 476 } 477 478 ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This); 479 480 // 481 // Enter critical section 482 // 483 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 484 485 if (ConsoleInDev->KeyboardErr) { 486 Status = EFI_DEVICE_ERROR; 487 goto Exit; 488 } 489 490 if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) { 491 Status = EFI_UNSUPPORTED; 492 goto Exit; 493 } 494 495 // 496 // Update the status light 497 // 498 ConsoleInDev->ScrollLock = FALSE; 499 ConsoleInDev->NumLock = FALSE; 500 ConsoleInDev->CapsLock = FALSE; 501 ConsoleInDev->IsSupportPartialKey = FALSE; 502 503 if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) { 504 ConsoleInDev->ScrollLock = TRUE; 505 } 506 if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) { 507 ConsoleInDev->NumLock = TRUE; 508 } 509 if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) { 510 ConsoleInDev->CapsLock = TRUE; 511 } 512 if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) { 513 ConsoleInDev->IsSupportPartialKey = TRUE; 514 } 515 516 Status = UpdateStatusLights (ConsoleInDev); 517 if (EFI_ERROR (Status)) { 518 Status = EFI_DEVICE_ERROR; 519 } 520 521 Exit: 522 // 523 // Leave critical section and return 524 // 525 gBS->RestoreTPL (OldTpl); 526 527 return Status; 528 529 } 530 531 /** 532 Register a notification function for a particular keystroke for the input device. 533 534 @param This Protocol instance pointer. 535 @param KeyData A pointer to a buffer that is filled in with the keystroke 536 information data for the key that was pressed. 537 @param KeyNotificationFunction Points to the function to be called when the key 538 sequence is typed specified by KeyData. 539 @param NotifyHandle Points to the unique handle assigned to the registered notification. 540 541 @retval EFI_SUCCESS The notification function was registered successfully. 542 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures. 543 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle or KeyNotificationFunction is NULL. 544 545 **/ 546 EFI_STATUS 547 EFIAPI 548 KeyboardRegisterKeyNotify ( 549 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 550 IN EFI_KEY_DATA *KeyData, 551 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, 552 OUT VOID **NotifyHandle 553 ) 554 { 555 EFI_STATUS Status; 556 KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev; 557 EFI_TPL OldTpl; 558 LIST_ENTRY *Link; 559 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 560 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify; 561 562 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) { 563 return EFI_INVALID_PARAMETER; 564 } 565 566 ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This); 567 568 // 569 // Enter critical section 570 // 571 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 572 573 // 574 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. 575 // 576 for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) { 577 CurrentNotify = CR ( 578 Link, 579 KEYBOARD_CONSOLE_IN_EX_NOTIFY, 580 NotifyEntry, 581 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE 582 ); 583 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { 584 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { 585 *NotifyHandle = CurrentNotify; 586 Status = EFI_SUCCESS; 587 goto Exit; 588 } 589 } 590 } 591 592 // 593 // Allocate resource to save the notification function 594 // 595 NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY)); 596 if (NewNotify == NULL) { 597 Status = EFI_OUT_OF_RESOURCES; 598 goto Exit; 599 } 600 601 NewNotify->Signature = KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE; 602 NewNotify->KeyNotificationFn = KeyNotificationFunction; 603 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA)); 604 InsertTailList (&ConsoleInDev->NotifyList, &NewNotify->NotifyEntry); 605 606 *NotifyHandle = NewNotify; 607 Status = EFI_SUCCESS; 608 609 Exit: 610 // 611 // Leave critical section and return 612 // 613 gBS->RestoreTPL (OldTpl); 614 return Status; 615 616 } 617 618 /** 619 Remove a registered notification function from a particular keystroke. 620 621 @param This Protocol instance pointer. 622 @param NotificationHandle The handle of the notification function being unregistered. 623 624 625 @retval EFI_SUCCESS The notification function was unregistered successfully. 626 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid. 627 628 **/ 629 EFI_STATUS 630 EFIAPI 631 KeyboardUnregisterKeyNotify ( 632 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, 633 IN VOID *NotificationHandle 634 ) 635 { 636 EFI_STATUS Status; 637 KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev; 638 EFI_TPL OldTpl; 639 LIST_ENTRY *Link; 640 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 641 642 if (NotificationHandle == NULL) { 643 return EFI_INVALID_PARAMETER; 644 } 645 646 ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This); 647 648 // 649 // Enter critical section 650 // 651 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 652 653 for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) { 654 CurrentNotify = CR ( 655 Link, 656 KEYBOARD_CONSOLE_IN_EX_NOTIFY, 657 NotifyEntry, 658 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE 659 ); 660 if (CurrentNotify == NotificationHandle) { 661 // 662 // Remove the notification function from NotifyList and free resources 663 // 664 RemoveEntryList (&CurrentNotify->NotifyEntry); 665 666 gBS->FreePool (CurrentNotify); 667 Status = EFI_SUCCESS; 668 goto Exit; 669 } 670 } 671 672 // 673 // Can not find the specified Notification Handle 674 // 675 Status = EFI_INVALID_PARAMETER; 676 Exit: 677 // 678 // Leave critical section and return 679 // 680 gBS->RestoreTPL (OldTpl); 681 return Status; 682 } 683 684 /** 685 Process key notify. 686 687 @param Event Indicates the event that invoke this function. 688 @param Context Indicates the calling context. 689 **/ 690 VOID 691 EFIAPI 692 KeyNotifyProcessHandler ( 693 IN EFI_EVENT Event, 694 IN VOID *Context 695 ) 696 { 697 EFI_STATUS Status; 698 KEYBOARD_CONSOLE_IN_DEV *ConsoleIn; 699 EFI_KEY_DATA KeyData; 700 LIST_ENTRY *Link; 701 LIST_ENTRY *NotifyList; 702 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; 703 EFI_TPL OldTpl; 704 705 ConsoleIn = (KEYBOARD_CONSOLE_IN_DEV *) Context; 706 707 // 708 // Invoke notification functions. 709 // 710 NotifyList = &ConsoleIn->NotifyList; 711 while (TRUE) { 712 // 713 // Enter critical section 714 // 715 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 716 Status = PopEfikeyBufHead (&ConsoleIn->EfiKeyQueueForNotify, &KeyData); 717 // 718 // Leave critical section 719 // 720 gBS->RestoreTPL (OldTpl); 721 if (EFI_ERROR (Status)) { 722 break; 723 } 724 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) { 725 CurrentNotify = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE); 726 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { 727 CurrentNotify->KeyNotificationFn (&KeyData); 728 } 729 } 730 } 731 } 732 733