X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=IntelFrameworkModulePkg%2FCsm%2FBiosThunk%2FKeyboardDxe%2FBiosKeyboard.c;h=ec525891dc7a5659af89d1151a008ee1cc84fd4f;hp=06ef9d3345648e11824cbd2fc16ee18276b0f183;hb=621d1f45adf4b9ba73adfefc41e4b17b89623aad;hpb=bcecde140a561c64e297225904afebebd62336ce diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c index 06ef9d3345..ec525891dc 100644 --- a/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c +++ b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c @@ -1,7 +1,7 @@ /** @file ConsoleOut Routines that speak VGA. -Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions @@ -272,6 +272,8 @@ BiosKeyboardDriverBindingStart ( BiosKeyboardPrivate->Queue.Front = 0; BiosKeyboardPrivate->Queue.Rear = 0; + BiosKeyboardPrivate->QueueForNotify.Front = 0; + BiosKeyboardPrivate->QueueForNotify.Rear = 0; BiosKeyboardPrivate->SimpleTextInputEx.Reset = BiosKeyboardResetEx; BiosKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx = BiosKeyboardReadKeyStrokeEx; BiosKeyboardPrivate->SimpleTextInputEx.SetState = BiosKeyboardSetState; @@ -279,19 +281,12 @@ BiosKeyboardDriverBindingStart ( BiosKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = BiosKeyboardUnregisterKeyNotify; InitializeListHead (&BiosKeyboardPrivate->NotifyList); - Status = gBS->HandleProtocol ( - Controller, - &gEfiDevicePathProtocolGuid, - (VOID **) &BiosKeyboardPrivate->DevicePath - ); - // // Report that the keyboard is being enabled // - REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + REPORT_STATUS_CODE ( EFI_PROGRESS_CODE, - EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE, - BiosKeyboardPrivate->DevicePath + EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE ); // @@ -346,14 +341,26 @@ BiosKeyboardDriverBindingStart ( StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR; goto Done; } - + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + KeyNotifyProcessHandler, + BiosKeyboardPrivate, + &BiosKeyboardPrivate->KeyNotifyProcessEvent + ); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR; + goto Done; + } + // // Report a Progress Code for an attempt to detect the precense of the keyboard device in the system // - REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + REPORT_STATUS_CODE ( EFI_PROGRESS_CODE, - EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT, - BiosKeyboardPrivate->DevicePath + EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT ); // @@ -361,10 +368,10 @@ BiosKeyboardDriverBindingStart ( // Status = BiosKeyboardPrivate->SimpleTextInputEx.Reset ( &BiosKeyboardPrivate->SimpleTextInputEx, - FALSE + FeaturePcdGet (PcdPs2KbdExtendedVerification) ); - if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "[KBD]Reset Failed. Status - %r\n", Status)); StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED; goto Done; } @@ -411,7 +418,7 @@ BiosKeyboardDriverBindingStart ( // Check bit 6 of Feature Byte 2. // If it is set, then Int 16 Func 09 is supported // - if (*(UINT8 *)(UINTN) ((Regs.X.ES << 4) + Regs.X.BX + 0x06) & 0x40) { + if (*(UINT8 *) (((UINTN) Regs.X.ES << 4) + Regs.X.BX + 0x06) & 0x40) { // // Get Keyboard Functionality // @@ -436,6 +443,7 @@ BiosKeyboardDriverBindingStart ( } } } + DEBUG ((EFI_D_INFO, "[KBD]Extended keystrokes supported by CSM16 - %02x\n", (UINTN)BiosKeyboardPrivate->ExtendedKeyboard)); // // Install protocol interfaces for the keyboard device. // @@ -453,10 +461,9 @@ Done: // // Report an Error Code for failing to start the keyboard device // - REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + REPORT_STATUS_CODE ( EFI_ERROR_CODE | EFI_ERROR_MINOR, - StatusCode, - BiosKeyboardPrivate->DevicePath + StatusCode ); } @@ -470,6 +477,11 @@ Done: if ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) { gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx); } + + if (BiosKeyboardPrivate->KeyNotifyProcessEvent != NULL) { + gBS->CloseEvent (BiosKeyboardPrivate->KeyNotifyProcessEvent); + } + BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList); if (BiosKeyboardPrivate->TimerEvent != NULL) { @@ -574,6 +586,7 @@ BiosKeyboardDriverBindingStop ( gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey); gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent); gBS->CloseEvent (BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx); + gBS->CloseEvent (BiosKeyboardPrivate->KeyNotifyProcessEvent); BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList); FreePool (BiosKeyboardPrivate); @@ -942,7 +955,7 @@ KeyboardReadKeyStrokeWorker ( } // - // Use TimerEvent callback funciton to check whether there's any key pressed + // Use TimerEvent callback function to check whether there's any key pressed // // @@ -986,7 +999,7 @@ KeyboardReadKeyStrokeWorker ( @param ExtendedVerification Whether perform the extra validation of keyboard. True: perform; FALSE: skip. @retval EFI_SUCCESS The command byte is written successfully. - @retval EFI_DEVICE_ERROR Errors occurred during reseting keyboard. + @retval EFI_DEVICE_ERROR Errors occurred during resetting keyboard. **/ EFI_STATUS @@ -1010,19 +1023,17 @@ BiosKeyboardReset ( // 1 // Report reset progress code // - REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + REPORT_STATUS_CODE ( EFI_PROGRESS_CODE, - EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET, - BiosKeyboardPrivate->DevicePath + EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET ); // // Report a Progress Code for clearing the keyboard buffer // - REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + REPORT_STATUS_CODE ( EFI_PROGRESS_CODE, - EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER, - BiosKeyboardPrivate->DevicePath + EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER ); // @@ -1047,96 +1058,96 @@ BiosKeyboardReset ( // if not skip step 4&5 and jump to step 6 to selftest KBC and report this // else go step 4 // - if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_SYSF) != 0) { - // - // 4 - // CheckMouseStatus to decide enable it later or not - // - // - // Read the command byte of KBC - // - Status = KeyboardCommand ( - BiosKeyboardPrivate, - KBC_CMDREG_VIA64_CMDBYTE_R - ); - - if (EFI_ERROR (Status)) { - Status = EFI_DEVICE_ERROR; - goto Exit; - } - - Status = KeyboardRead ( - BiosKeyboardPrivate, - &CommandByte - ); - - if (EFI_ERROR (Status)) { - Status = EFI_DEVICE_ERROR; - goto Exit; - } - // - // Check mouse enabled or not before - // - if ((CommandByte & KB_CMMBYTE_DISABLE_AUX) != 0) { - MouseEnable = FALSE; + if (!PcdGetBool (PcdFastPS2Detection)) { + if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_SYSF) != 0) { + // + // 4 + // CheckMouseStatus to decide enable it later or not + // + // + // Read the command byte of KBC + // + Status = KeyboardCommand ( + BiosKeyboardPrivate, + KBC_CMDREG_VIA64_CMDBYTE_R + ); + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + + Status = KeyboardRead ( + BiosKeyboardPrivate, + &CommandByte + ); + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + // + // Check mouse enabled or not before + // + if ((CommandByte & KB_CMMBYTE_DISABLE_AUX) != 0) { + MouseEnable = FALSE; + } else { + MouseEnable = TRUE; + } + // + // 5 + // disable mouse (via KBC) and Keyborad device + // + Status = KeyboardCommand ( + BiosKeyboardPrivate, + KBC_CMDREG_VIA64_AUX_DISABLE + ); + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + + Status = KeyboardCommand ( + BiosKeyboardPrivate, + KBC_CMDREG_VIA64_KB_DISABLE + ); + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } } else { - MouseEnable = TRUE; - } - // - // 5 - // disable mouse (via KBC) and Keyborad device - // - Status = KeyboardCommand ( - BiosKeyboardPrivate, - KBC_CMDREG_VIA64_AUX_DISABLE - ); - - if (EFI_ERROR (Status)) { - Status = EFI_DEVICE_ERROR; - goto Exit; - } - - Status = KeyboardCommand ( - BiosKeyboardPrivate, - KBC_CMDREG_VIA64_KB_DISABLE - ); - - if (EFI_ERROR (Status)) { - Status = EFI_DEVICE_ERROR; - goto Exit; - } - - } else { - // - // 6 - // KBC Self Test - // - // - // Report a Progress Code for performing a self test on the keyboard controller - // - REPORT_STATUS_CODE_WITH_DEVICE_PATH ( - EFI_PROGRESS_CODE, - EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST, - BiosKeyboardPrivate->DevicePath - ); - - Status = KeyboardCommand ( - BiosKeyboardPrivate, - KBC_CMDREG_VIA64_KBC_SLFTEST - ); - if (EFI_ERROR (Status)) { - Status = EFI_DEVICE_ERROR; - goto Exit; - } - - Status = KeyboardWaitForValue ( - BiosKeyboardPrivate, - KBC_CMDECHO_KBCSLFTEST_OK, - KEYBOARD_WAITFORVALUE_TIMEOUT - ); - if (EFI_ERROR (Status)) { - Status = EFI_DEVICE_ERROR; - goto Exit; + // + // 6 + // KBC Self Test + // + // + // Report a Progress Code for performing a self test on the keyboard controller + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST + ); + + Status = KeyboardCommand ( + BiosKeyboardPrivate, + KBC_CMDREG_VIA64_KBC_SLFTEST + ); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + + Status = KeyboardWaitForValue ( + BiosKeyboardPrivate, + KBC_CMDECHO_KBCSLFTEST_OK, + KEYBOARD_WAITFORVALUE_TIMEOUT + ); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } } } // @@ -1186,8 +1197,8 @@ BiosKeyboardReset ( ); // - // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow, - // so we only do the real reseting for keyboard when user asks, and normally during booting an OS, it's skipped. + // For resetting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow, + // so we only do the real resetting for keyboard when user asks, and normally during booting an OS, it's skipped. // Call CheckKeyboardConnect() to check whether keyboard is connected, if it is not connected, // Real reset will not do. // @@ -1332,14 +1343,16 @@ BiosKeyboardReset ( // Done for validating keyboard. Enable keyboard (via KBC) // and recover the command byte to proper value // - Status = KeyboardCommand ( - BiosKeyboardPrivate, - KBC_CMDREG_VIA64_KB_ENABLE - ); - - if (EFI_ERROR (Status)) { - Status = EFI_DEVICE_ERROR; - goto Exit; + if (!PcdGetBool (PcdFastPS2Detection)) { + Status = KeyboardCommand ( + BiosKeyboardPrivate, + KBC_CMDREG_VIA64_KB_ENABLE + ); + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } } // @@ -1397,6 +1410,17 @@ BiosKeyboardReadKeyStroke ( return Status; } + // + // Convert the Ctrl+[a-z] to Ctrl+[1-26] + // + if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) { + if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') { + KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1); + } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') { + KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1); + } + } + CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY)); return EFI_SUCCESS; @@ -1428,7 +1452,7 @@ BiosKeyboardWaitForKey ( // gBS->Stall (1000); // - // Use TimerEvent callback funciton to check whether there's any key pressed + // Use TimerEvent callback function to check whether there's any key pressed // BiosKeyboardTimerHandler (NULL, BIOS_KEYBOARD_DEV_FROM_THIS (Context)); @@ -1674,25 +1698,38 @@ CheckKeyboardConnect ( // enable keyboard itself and wait for its ack // If can't receive ack, Keyboard should not be connected. // - Status = KeyboardWrite ( - BiosKeyboardPrivate, - KBC_INPBUF_VIA60_KBEN - ); - if (EFI_ERROR (Status)) { - return FALSE; - } + if (!PcdGetBool (PcdFastPS2Detection)) { + Status = KeyboardWrite ( + BiosKeyboardPrivate, + KBC_INPBUF_VIA60_KBEN + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Keyboard enable failed!\n")); + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR + ); + return FALSE; + } - Status = KeyboardWaitForValue ( - BiosKeyboardPrivate, - KBC_CMDECHO_ACK, - KEYBOARD_WAITFORVALUE_TIMEOUT - ); + Status = KeyboardWaitForValue ( + BiosKeyboardPrivate, + KBC_CMDECHO_ACK, + KEYBOARD_WAITFORVALUE_TIMEOUT + ); - if (EFI_ERROR (Status)) { - return FALSE; + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Timeout!\n")); + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR + ); + return FALSE; + } + return TRUE; + } else { + return TRUE; } - - return TRUE; } /** @@ -1763,6 +1800,13 @@ BiosKeyboardTimerHandler ( KeyData.Key.ScanCode = (UINT16) Regs.H.AH; KeyData.Key.UnicodeChar = (UINT16) Regs.H.AL; + DEBUG (( + EFI_D_INFO, + "[KBD]INT16 returns EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n", + KeyData.Key.ScanCode, + KeyData.Key.UnicodeChar + )); + KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID; KeyData.KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID; // @@ -1772,7 +1816,7 @@ BiosKeyboardTimerHandler ( // will be disabled after the thunk call finish, which means if user crazy input during int 9 being disabled, some keystrokes will be lost when // KB device own hardware buffer overflows. And if the lost keystroke code is CTRL or ALT or SHIFT release code, these function key flags bit // in BDA will not be updated. So the Int 16 will believe the CTRL or ALT or SHIFT is still pressed, and Int 16 will translate later scancode - // to wrong ASCII code. We can increase the Thunk frequence to let Int 9 response in time, but this way will much hurt other dirvers + // to wrong ASCII code. We can increase the Thunk frequence to let Int 9 response in time, but this way will much hurt other drivers // performance, like USB. // // 1. If CTRL or ALT release code is missed, all later input keys will be translated to wrong ASCII codes which the Tiano cannot support. In @@ -1798,8 +1842,44 @@ BiosKeyboardTimerHandler ( // // Clear the CTRL and ALT BDA flag // - KbFlag1 = *((UINT8 *) (UINTN) 0x417); // read the STATUS FLAGS 1 - KbFlag2 = *((UINT8 *) (UINTN) 0x418); // read STATUS FLAGS 2 + ACCESS_PAGE0_CODE ( + KbFlag1 = *((UINT8 *) (UINTN) 0x417); // read the STATUS FLAGS 1 + KbFlag2 = *((UINT8 *) (UINTN) 0x418); // read STATUS FLAGS 2 + ); + + DEBUG_CODE ( + { + if ((KbFlag1 & KB_CAPS_LOCK_BIT) == KB_CAPS_LOCK_BIT) { + DEBUG ((EFI_D_INFO, "[KBD]Caps Lock Key is pressed.\n")); + } + if ((KbFlag1 & KB_NUM_LOCK_BIT) == KB_NUM_LOCK_BIT) { + DEBUG ((EFI_D_INFO, "[KBD]Num Lock Key is pressed.\n")); + } + if ((KbFlag1 & KB_SCROLL_LOCK_BIT) == KB_SCROLL_LOCK_BIT) { + DEBUG ((EFI_D_INFO, "[KBD]Scroll Lock Key is pressed.\n")); + } + if ((KbFlag1 & KB_ALT_PRESSED) == KB_ALT_PRESSED) { + if ((KbFlag2 & KB_LEFT_ALT_PRESSED) == KB_LEFT_ALT_PRESSED) { + DEBUG ((EFI_D_INFO, "[KBD]Left Alt Key is pressed.\n")); + } else { + DEBUG ((EFI_D_INFO, "[KBD]Right Alt Key is pressed.\n")); + } + } + if ((KbFlag1 & KB_CTRL_PRESSED) == KB_CTRL_PRESSED) { + if ((KbFlag2 & KB_LEFT_CTRL_PRESSED) == KB_LEFT_CTRL_PRESSED) { + DEBUG ((EFI_D_INFO, "[KBD]Left Ctrl Key is pressed.\n")); + } else { + DEBUG ((EFI_D_INFO, "[KBD]Right Ctrl Key is pressed.\n")); + } + } + if ((KbFlag1 & KB_LEFT_SHIFT_PRESSED) == KB_LEFT_SHIFT_PRESSED) { + DEBUG ((EFI_D_INFO, "[KBD]Left Shift Key is pressed.\n")); + } + if ((KbFlag1 & KB_RIGHT_SHIFT_PRESSED) == KB_RIGHT_SHIFT_PRESSED) { + DEBUG ((EFI_D_INFO, "[KBD]Right Shift Key is pressed.\n")); + } + } + ); // // Record toggle state @@ -1833,11 +1913,12 @@ BiosKeyboardTimerHandler ( // // Clear left alt and left ctrl BDA flag // - KbFlag2 &= ~(KB_LEFT_ALT_PRESSED | KB_LEFT_CTRL_PRESSED); - *((UINT8 *) (UINTN) 0x418) = KbFlag2; - KbFlag1 &= ~0x0C; - *((UINT8 *) (UINTN) 0x417) = KbFlag1; - + ACCESS_PAGE0_CODE ( + KbFlag2 &= ~(KB_LEFT_ALT_PRESSED | KB_LEFT_CTRL_PRESSED); + *((UINT8 *) (UINTN) 0x418) = KbFlag2; + KbFlag1 &= ~0x0C; + *((UINT8 *) (UINTN) 0x417) = KbFlag1; + ); // // Output EFI input key and shift/toggle state @@ -1864,6 +1945,13 @@ BiosKeyboardTimerHandler ( } } + DEBUG (( + EFI_D_INFO, + "[KBD]Convert to EFI Scan Code, EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n", + KeyData.Key.ScanCode, + KeyData.Key.UnicodeChar + )); + // // Need not return associated shift state if a class of printable characters that // are normally adjusted by shift modifiers. @@ -1872,11 +1960,12 @@ BiosKeyboardTimerHandler ( if ((KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') || (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') ) { + DEBUG ((EFI_D_INFO, "[KBD]Shift key with a~z are pressed, remove shift state in EFI_KEY_STATE.\n")); KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED); } // - // Invoke notification functions if exist + // Signal KeyNotify process event if this key pressed matches any key registered. // for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) { CurrentNotify = CR ( @@ -1885,21 +1974,17 @@ BiosKeyboardTimerHandler ( NotifyEntry, BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE ); - if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { - CurrentNotify->KeyNotificationFn (&KeyData); + if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { + // + // The key notification function needs to run at TPL_CALLBACK + // while current TPL is TPL_NOTIFY. It will be invoked in + // KeyNotifyProcessHandler() which runs at TPL_CALLBACK. + // + Enqueue (&BiosKeyboardPrivate->QueueForNotify, &KeyData); + gBS->SignalEvent (BiosKeyboardPrivate->KeyNotifyProcessEvent); } } - // - // Convert the Ctrl+[a-z] to Ctrl+[1-26] - // - if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) { - if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') { - KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar - L'a' + 1); - } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') { - KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar - L'A' + 1); - } - } Enqueue (&BiosKeyboardPrivate->Queue, &KeyData); // // Leave critical section and return @@ -1909,6 +1994,55 @@ BiosKeyboardTimerHandler ( return ; } +/** + Process key notify. + + @param Event Indicates the event that invoke this function. + @param Context Indicates the calling context. +**/ +VOID +EFIAPI +KeyNotifyProcessHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + BIOS_KEYBOARD_DEV *BiosKeyboardPrivate; + EFI_KEY_DATA KeyData; + LIST_ENTRY *Link; + LIST_ENTRY *NotifyList; + BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + EFI_TPL OldTpl; + + BiosKeyboardPrivate = (BIOS_KEYBOARD_DEV *) Context; + + // + // Invoke notification functions. + // + NotifyList = &BiosKeyboardPrivate->NotifyList; + while (TRUE) { + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + Status = Dequeue (&BiosKeyboardPrivate->QueueForNotify, &KeyData); + // + // Leave critical section + // + gBS->RestoreTPL (OldTpl); + if (EFI_ERROR (Status)) { + break; + } + for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) { + CurrentNotify = CR (Link, BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE); + if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { + CurrentNotify->KeyNotificationFn (&KeyData); + } + } + } +} + /** Free keyboard notify list. @@ -2109,7 +2243,12 @@ BiosKeyboardSetState ( return EFI_INVALID_PARAMETER; } - if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) { + // + // Thunk keyboard driver doesn't support partial keystroke. + // + if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID || + (*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED + ) { return EFI_UNSUPPORTED; } @@ -2142,15 +2281,18 @@ BiosKeyboardSetState ( Status = KeyboardWrite (BiosKeyboardPrivate, 0xed); if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; + Status = EFI_DEVICE_ERROR; + goto Exit; } Status = KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT); if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; + Status = EFI_DEVICE_ERROR; + goto Exit; } Status = KeyboardWrite (BiosKeyboardPrivate, Command); if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; + Status = EFI_DEVICE_ERROR; + goto Exit; } // // Call Legacy BIOS Protocol to set whatever is necessary @@ -2159,6 +2301,7 @@ BiosKeyboardSetState ( Status = EFI_SUCCESS; +Exit: // // Leave critical section and return // @@ -2173,24 +2316,27 @@ BiosKeyboardSetState ( @param This Protocol instance pointer. @param KeyData A pointer to a buffer that is filled in with the keystroke - information data for the key that was pressed. + information data for the key that was pressed. If KeyData.Key, + KeyData.KeyState.KeyToggleState and KeyData.KeyState.KeyShiftState + are 0, then any incomplete keystroke will trigger a notification of + the KeyNotificationFunction. @param KeyNotificationFunction Points to the function to be called when the key - sequence is typed specified by KeyData. - @param NotifyHandle Points to the unique handle assigned to the registered notification. + sequence is typed specified by KeyData. This notification function + should be called at <=TPL_CALLBACK. + @param NotifyHandle Points to the unique handle assigned to the registered notification. - @retval EFI_SUCCESS The notification function was registered successfully. @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures. @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL. - -**/ + +**/ EFI_STATUS EFIAPI BiosKeyboardRegisterKeyNotify ( IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, IN EFI_KEY_DATA *KeyData, IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, - OUT EFI_HANDLE *NotifyHandle + OUT VOID **NotifyHandle ) { EFI_STATUS Status; @@ -2223,7 +2369,7 @@ BiosKeyboardRegisterKeyNotify ( ); if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { - *NotifyHandle = CurrentNotify->NotifyHandle; + *NotifyHandle = CurrentNotify; Status = EFI_SUCCESS; goto Exit; } @@ -2242,11 +2388,10 @@ BiosKeyboardRegisterKeyNotify ( NewNotify->Signature = BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE; NewNotify->KeyNotificationFn = KeyNotificationFunction; - NewNotify->NotifyHandle = (EFI_HANDLE) NewNotify; CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA)); InsertTailList (&BiosKeyboardPrivate->NotifyList, &NewNotify->NotifyEntry); - *NotifyHandle = NewNotify->NotifyHandle; + *NotifyHandle = NewNotify; Status = EFI_SUCCESS; Exit: @@ -2271,7 +2416,7 @@ EFI_STATUS EFIAPI BiosKeyboardUnregisterKeyNotify ( IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - IN EFI_HANDLE NotificationHandle + IN VOID *NotificationHandle ) { EFI_STATUS Status; @@ -2296,7 +2441,7 @@ BiosKeyboardUnregisterKeyNotify ( // // Enter critical section // - OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) { CurrentNotify = CR ( @@ -2305,7 +2450,7 @@ BiosKeyboardUnregisterKeyNotify ( NotifyEntry, BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE ); - if (CurrentNotify->NotifyHandle == NotificationHandle) { + if (CurrentNotify == NotificationHandle) { // // Remove the notification function from NotifyList and free resources //