From f3d1e94028e0b1d6cefda99056d12d98e53e63a8 Mon Sep 17 00:00:00 2001 From: qhuang8 Date: Fri, 19 Oct 2007 02:35:55 +0000 Subject: [PATCH] Update to support EFI_SIMPLE_INPUT_EX protocol git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@4179 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c | 126 +++- .../Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c | 588 ++++++++++++++++-- .../Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c | 103 ++- .../Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h | 227 ++++++- .../Bus/Isa/Ps2KeyboardDxe/Ps2keyboardDxe.inf | 6 + 5 files changed, 983 insertions(+), 67 deletions(-) diff --git a/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c b/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c index c4f1ee1780..26e40d6bea 100644 --- a/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c +++ b/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c @@ -85,16 +85,6 @@ KeyboardWaitForValue ( IN UINT8 Value ); -STATIC -EFI_STATUS -UpdateStatusLights ( - IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn - ); - -// -// Global variables -// - STATIC struct { UINT8 ScanCode; UINT16 EfiScanCode; @@ -613,6 +603,24 @@ ConvertKeyboardScanCodeToEfiKey[] = { 0x00, 0x00 }, + { + 0x5B, //Left LOGO + SCAN_NULL, + 0x00, + 0x00 + }, + { + 0x5C, //Right LOGO + SCAN_NULL, + 0x00, + 0x00 + }, + { + 0x5D, //Menu key + SCAN_NULL, + 0x00, + 0x00 + }, { TABLE_END, TABLE_END, @@ -1316,7 +1324,6 @@ Returns: } -STATIC EFI_STATUS UpdateStatusLights ( IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn @@ -1550,19 +1557,55 @@ Returns: break; case SCANCODE_LEFT_SHIFT_MAKE: + if (!Extended) { + ConsoleIn->Shift = TRUE; + ConsoleIn->LeftShift = TRUE; + } + break; case SCANCODE_RIGHT_SHIFT_MAKE: if (!Extended) { ConsoleIn->Shift = TRUE; + ConsoleIn->RightShift = TRUE; } break; case SCANCODE_LEFT_SHIFT_BREAK: + if (!Extended) { + ConsoleIn->Shift = FALSE; + ConsoleIn->LeftShift = FALSE; + } else { + ConsoleIn->SysReq = FALSE; + } + break; case SCANCODE_RIGHT_SHIFT_BREAK: if (!Extended) { ConsoleIn->Shift = FALSE; + ConsoleIn->RightShift = FALSE; } break; + case SCANCODE_LEFT_LOGO_MAKE: + ConsoleIn->LeftLogo = TRUE; + break; + case SCANCODE_LEFT_LOGO_BREAK: + ConsoleIn->LeftLogo = FALSE; + break; + case SCANCODE_RIGHT_LOGO_MAKE: + ConsoleIn->RightLogo = TRUE; + break; + case SCANCODE_RIGHT_LOGO_BREAK: + ConsoleIn->RightLogo = FALSE; + break; + case SCANCODE_MENU_MAKE: + ConsoleIn->Menu = TRUE; + break; + case SCANCODE_MENU_BREAK: + ConsoleIn->Menu = FALSE; + break; + case SCANCODE_SYS_REQ_MAKE: + if (Extended) { + ConsoleIn->SysReq = TRUE; + } case SCANCODE_CAPS_LOCK_MAKE: ConsoleIn->CapsLock = (BOOLEAN)!ConsoleIn->CapsLock; UpdateStatusLights (ConsoleIn); @@ -1588,12 +1631,6 @@ Returns: } } // - // If this is the SysRq, ignore it - // - if (Extended && ScanCode == 0x37) { - return EFI_NOT_READY; - } - // // Treat Numeric Key Pad "/" specially // if (Extended && ScanCode == 0x35) { @@ -1609,6 +1646,14 @@ Returns: ConsoleIn->Key.ScanCode = ConvertKeyboardScanCodeToEfiKey[Index].EfiScanCode; if (ConsoleIn->Shift) { ConsoleIn->Key.UnicodeChar = ConvertKeyboardScanCodeToEfiKey[Index].ShiftUnicodeChar; + // + // Need not return associated shift state if a class of printable characters that + // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F' + // + if (ConsoleIn->Key.UnicodeChar >= 'A' && ConsoleIn->Key.UnicodeChar <= 'Z') { + ConsoleIn->LeftShift = FALSE; + ConsoleIn->RightShift = FALSE; + } } else { ConsoleIn->Key.UnicodeChar = ConvertKeyboardScanCodeToEfiKey[Index].UnicodeChar; } @@ -1655,6 +1700,43 @@ Returns: return EFI_NOT_READY; } + // + // Save the Shift/Toggle state + // + if (ConsoleIn->Ctrl) { + ConsoleIn->KeyState.KeyShiftState |= (Extended == TRUE) ? EFI_RIGHT_CONTROL_PRESSED : EFI_LEFT_CONTROL_PRESSED; + } + if (ConsoleIn->Alt) { + ConsoleIn->KeyState.KeyShiftState |= (Extended == TRUE) ? EFI_RIGHT_ALT_PRESSED : EFI_LEFT_ALT_PRESSED; + } + if (ConsoleIn->LeftShift) { + ConsoleIn->KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED; + } + if (ConsoleIn->RightShift) { + ConsoleIn->KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED; + } + if (ConsoleIn->LeftLogo) { + ConsoleIn->KeyState.KeyShiftState |= EFI_LEFT_LOGO_PRESSED; + } + if (ConsoleIn->RightLogo) { + ConsoleIn->KeyState.KeyShiftState |= EFI_RIGHT_LOGO_PRESSED; + } + if (ConsoleIn->Menu) { + ConsoleIn->KeyState.KeyShiftState |= EFI_MENU_KEY_PRESSED; + } + if (ConsoleIn->SysReq) { + ConsoleIn->KeyState.KeyShiftState |= EFI_SYS_REQ_PRESSED; + } + if (ConsoleIn->CapsLock) { + ConsoleIn->KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE; + } + if (ConsoleIn->NumLock) { + ConsoleIn->KeyState.KeyToggleState |= EFI_NUM_LOCK_ACTIVE; + } + if (ConsoleIn->ScrollLock) { + ConsoleIn->KeyState.KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE; + } + return EFI_SUCCESS; } @@ -1855,6 +1937,12 @@ Returns: ConsoleIn->CapsLock = FALSE; ConsoleIn->NumLock = FALSE; ConsoleIn->ScrollLock = FALSE; + ConsoleIn->LeftShift = FALSE; + ConsoleIn->RightShift = FALSE; + ConsoleIn->LeftLogo = FALSE; + ConsoleIn->RightLogo = FALSE; + ConsoleIn->Menu = FALSE; + ConsoleIn->SysReq = FALSE; // // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow, @@ -2040,8 +2128,8 @@ Returns: @param[in] BiosKeyboardPrivate Keyboard Private Data Structure - @retval TRUE Keyboard in System. - @retval FALSE Keyboard not in System. + @retval TRUE Keyboard in System. + @retval FALSE Keyboard not in System. **/ BOOLEAN EFIAPI diff --git a/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c b/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c index ab4ced939d..71cf8eed03 100644 --- a/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c +++ b/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c @@ -45,6 +45,122 @@ KeyboardCheckForKey ( IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This ); +STATIC +BOOLEAN +IsKeyRegistered ( + IN EFI_KEY_DATA *RegsiteredData, + IN EFI_KEY_DATA *InputData + ) +/*++ + +Routine Description: + +Arguments: + + RegsiteredData - A pointer to a buffer that is filled in with the keystroke + state data for the key that was registered. + InputData - A pointer to a buffer that is filled in with the keystroke + state data for the key that was pressed. + +Returns: + TRUE - Key be pressed matches a registered key. + FLASE - Match failed. + +--*/ +; +STATIC +EFI_STATUS +KeyboardReadKeyStrokeWorker ( + IN KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev, + OUT EFI_KEY_DATA *KeyData + ) +/*++ + + Routine Description: + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existance of a keystroke via WaitForEvent () call. + + Arguments: + ConsoleInDev - Ps2 Keyboard private structure + KeyData - A pointer to a buffer that is filled in with the keystroke + state data for the key that was pressed. + + Returns: + EFI_SUCCESS - The keystroke information was returned. + EFI_NOT_READY - There was no keystroke data availiable. + EFI_DEVICE_ERROR - The keystroke information was not returned due to + hardware errors. + EFI_INVALID_PARAMETER - KeyData is NULL. + +--*/ +{ + EFI_STATUS Status; + EFI_TPL OldTpl; + LIST_ENTRY *Link; + KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + EFI_KEY_DATA OriginalKeyData; + if (KeyData == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + if (ConsoleInDev->KeyboardErr) { + gBS->RestoreTPL (OldTpl); + return EFI_DEVICE_ERROR; + } + // + // If there's no key, just return + // + Status = KeyboardCheckForKey (&ConsoleInDev->ConIn); + if (EFI_ERROR (Status)) { + gBS->RestoreTPL (OldTpl); + return EFI_NOT_READY; + } + CopyMem (&KeyData->Key, &ConsoleInDev->Key, sizeof (EFI_INPUT_KEY)); + + ConsoleInDev->Key.ScanCode = SCAN_NULL; + ConsoleInDev->Key.UnicodeChar = 0x0000; + CopyMem (&KeyData->KeyState, &ConsoleInDev->KeyState, sizeof (EFI_KEY_STATE)); + + ConsoleInDev->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID; + ConsoleInDev->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID; + gBS->RestoreTPL (OldTpl); + // + //Switch the control value to their original characters. In KeyGetchar() the CTRL-Alpha characters have been switched to + // their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A), here switch them back for notification function. + // + CopyMem (&OriginalKeyData, KeyData, sizeof (EFI_KEY_DATA)); + if (ConsoleInDev->Ctrled) { + if (OriginalKeyData.Key.UnicodeChar >= 0x01 && OriginalKeyData.Key.UnicodeChar <= 0x1A) { + if (ConsoleInDev->CapsLock) { + OriginalKeyData.Key.UnicodeChar = (CHAR16)(OriginalKeyData.Key.UnicodeChar + 'A' - 1); + } else { + OriginalKeyData.Key.UnicodeChar = (CHAR16)(OriginalKeyData.Key.UnicodeChar + 'a' - 1); + } + } + } + // + // Invoke notification functions if exist + // + for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) { + CurrentNotify = CR ( + Link, + KEYBOARD_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + if (IsKeyRegistered (&CurrentNotify->KeyData, &OriginalKeyData)) { + CurrentNotify->KeyNotificationFn (&OriginalKeyData); + } + } + + return EFI_SUCCESS; +} + EFI_STATUS EFIAPI KeyboardEfiReset ( @@ -161,47 +277,17 @@ Returns: { EFI_STATUS Status; KEYBOARD_CONSOLE_IN_DEV *ConsoleIn; - EFI_TPL OldTpl; + EFI_KEY_DATA KeyData; ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This); - - // - // Enter critical section - // - OldTpl = gBS->RaiseTPL (TPL_NOTIFY); - - if (ConsoleIn->KeyboardErr) { - // - // Leave critical section and return - // - gBS->RestoreTPL (OldTpl); - - return EFI_DEVICE_ERROR; - } - // - // If there's no key, just return - // - Status = KeyboardCheckForKey (This); + Status = KeyboardReadKeyStrokeWorker (ConsoleIn, &KeyData); if (EFI_ERROR (Status)) { - // - // Leave critical section and return - // - gBS->RestoreTPL (OldTpl); - return EFI_NOT_READY; + return Status; } - Key->ScanCode = ConsoleIn->Key.ScanCode; - Key->UnicodeChar = ConsoleIn->Key.UnicodeChar; - - ConsoleIn->Key.ScanCode = SCAN_NULL; - ConsoleIn->Key.UnicodeChar = 0x0000; - - // - // Leave critical section and return - // - gBS->RestoreTPL (OldTpl); - + CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY)); return EFI_SUCCESS; + } VOID @@ -290,3 +376,435 @@ Returns: return EFI_SUCCESS; } + +STATIC +BOOLEAN +IsKeyRegistered ( + IN EFI_KEY_DATA *RegsiteredData, + IN EFI_KEY_DATA *InputData + ) +/*++ + +Routine Description: + +Arguments: + + RegsiteredData - A pointer to a buffer that is filled in with the keystroke + state data for the key that was registered. + InputData - A pointer to a buffer that is filled in with the keystroke + state data for the key that was pressed. + +Returns: + TRUE - Key be pressed matches a registered key. + FLASE - Match failed. + +--*/ +{ + ASSERT (RegsiteredData != NULL && InputData != NULL); + + if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) || + (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) { + return FALSE; + } + + // + // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored. + // + if (RegsiteredData->KeyState.KeyShiftState != 0 && + RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) { + return FALSE; + } + if (RegsiteredData->KeyState.KeyToggleState != 0 && + RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) { + return FALSE; + } + + return TRUE; + +} + +VOID +EFIAPI +KeyboardWaitForKeyEx ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event + Signal the event if there is key available + +Arguments: + +Returns: + +--*/ +{ + KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev; + + ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (Context); + KeyboardWaitForKey (Event, &ConsoleInDev->ConIn); + +} + +EFI_STATUS +EFIAPI +KeyboardEfiResetEx ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset the input device and optionaly run diagnostics + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - Driver may perform diagnostics on reset. + + Returns: + EFI_SUCCESS - The device was reset. + EFI_DEVICE_ERROR - The device is not functioning properly and could + not be reset. + +--*/ +{ + EFI_STATUS Status; + KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev; + EFI_TPL OldTpl; + + ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This); + if (ConsoleInDev->KeyboardErr) { + return EFI_DEVICE_ERROR; + } + + Status = ConsoleInDev->ConIn.Reset ( + &ConsoleInDev->ConIn, + ExtendedVerification + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + ConsoleInDev->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID; + ConsoleInDev->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID; + + gBS->RestoreTPL (OldTpl); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +KeyboardReadKeyStrokeEx ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + OUT EFI_KEY_DATA *KeyData + ) +/*++ + + Routine Description: + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existance of a keystroke via WaitForEvent () call. + + Arguments: + This - Protocol instance pointer. + KeyData - A pointer to a buffer that is filled in with the keystroke + state data for the key that was pressed. + + Returns: + EFI_SUCCESS - The keystroke information was returned. + EFI_NOT_READY - There was no keystroke data availiable. + EFI_DEVICE_ERROR - The keystroke information was not returned due to + hardware errors. + EFI_INVALID_PARAMETER - KeyData is NULL. + +--*/ +{ + KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev; + + if (KeyData == NULL) { + return EFI_INVALID_PARAMETER; + } + + ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This); + return KeyboardReadKeyStrokeWorker (ConsoleInDev, KeyData); + +} + +EFI_STATUS +EFIAPI +KeyboardSetState ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_KEY_TOGGLE_STATE *KeyToggleState + ) +/*++ + + Routine Description: + Set certain state for the input device. + + Arguments: + This - Protocol instance pointer. + KeyToggleState - A pointer to the EFI_KEY_TOGGLE_STATE to set the + state for the input device. + + Returns: + EFI_SUCCESS - The device state was set successfully. + EFI_DEVICE_ERROR - The device is not functioning correctly and could + not have the setting adjusted. + EFI_UNSUPPORTED - The device does not have the ability to set its state. + EFI_INVALID_PARAMETER - KeyToggleState is NULL. + +--*/ +{ + EFI_STATUS Status; + KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev; + EFI_TPL OldTpl; + + if (KeyToggleState == NULL) { + return EFI_INVALID_PARAMETER; + } + + ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This); + + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + if (ConsoleInDev->KeyboardErr) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + + if (((ConsoleInDev->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) || + ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) { + Status = EFI_UNSUPPORTED; + goto Exit; + } + + // + // Update the status light + // + ConsoleInDev->ScrollLock = FALSE; + ConsoleInDev->NumLock = FALSE; + ConsoleInDev->CapsLock = FALSE; + + if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) { + ConsoleInDev->ScrollLock = TRUE; + } + if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) { + ConsoleInDev->NumLock = TRUE; + } + if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) { + ConsoleInDev->CapsLock = TRUE; + } + + Status = UpdateStatusLights (ConsoleInDev); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + } + + ConsoleInDev->KeyState.KeyToggleState = *KeyToggleState; + +Exit: + // + // Leave critical section and return + // + gBS->RestoreTPL (OldTpl); + + return Status; + +} +EFI_STATUS +EFIAPI +KeyboardRegisterKeyNotify ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_KEY_DATA *KeyData, + IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, + OUT EFI_HANDLE *NotifyHandle + ) +/*++ + + Routine Description: + Register a notification function for a particular keystroke for the input device. + + Arguments: + This - Protocol instance pointer. + KeyData - A pointer to a buffer that is filled in with the keystroke + information data for the key that was pressed. + KeyNotificationFunction - Points to the function to be called when the key + sequence is typed specified by KeyData. + NotifyHandle - Points to the unique handle assigned to the registered notification. + + Returns: + EFI_SUCCESS - The notification function was registered successfully. + EFI_OUT_OF_RESOURCES - Unable to allocate resources for necesssary data structures. + EFI_INVALID_PARAMETER - KeyData or NotifyHandle is NULL. + +--*/ +{ + EFI_STATUS Status; + KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev; + EFI_TPL OldTpl; + LIST_ENTRY *Link; + KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify; + + if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) { + return EFI_INVALID_PARAMETER; + } + + ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This); + + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + // + // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. + // + for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) { + CurrentNotify = CR ( + Link, + KEYBOARD_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { + if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { + *NotifyHandle = CurrentNotify->NotifyHandle; + Status = EFI_SUCCESS; + goto Exit; + } + } + } + + // + // Allocate resource to save the notification function + // + NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY)); + if (NewNotify == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + NewNotify->Signature = KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE; + NewNotify->KeyNotificationFn = KeyNotificationFunction; + CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA)); + InsertTailList (&ConsoleInDev->NotifyList, &NewNotify->NotifyEntry); + + // + // Use gSimpleTextInExNotifyGuid to get a valid EFI_HANDLE + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &NewNotify->NotifyHandle, + &gSimpleTextInExNotifyGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + *NotifyHandle = NewNotify->NotifyHandle; + Status = EFI_SUCCESS; + +Exit: + // + // Leave critical section and return + // + gBS->RestoreTPL (OldTpl); + return Status; + +} + +EFI_STATUS +EFIAPI +KeyboardUnregisterKeyNotify ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_HANDLE NotificationHandle + ) +/*++ + + Routine Description: + Remove a registered notification function from a particular keystroke. + + Arguments: + This - Protocol instance pointer. + NotificationHandle - The handle of the notification function being unregistered. + + Returns: + EFI_SUCCESS - The notification function was unregistered successfully. + EFI_INVALID_PARAMETER - The NotificationHandle is invalid. + EFI_NOT_FOUND - Can not find the matching entry in database. + +--*/ +{ + EFI_STATUS Status; + KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev; + EFI_TPL OldTpl; + LIST_ENTRY *Link; + KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + + if (NotificationHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = gBS->OpenProtocol ( + NotificationHandle, + &gSimpleTextInExNotifyGuid, + NULL, + NULL, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This); + + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) { + CurrentNotify = CR ( + Link, + KEYBOARD_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + if (CurrentNotify->NotifyHandle == NotificationHandle) { + // + // Remove the notification function from NotifyList and free resources + // + RemoveEntryList (&CurrentNotify->NotifyEntry); + Status = gBS->UninstallMultipleProtocolInterfaces ( + CurrentNotify->NotifyHandle, + &gSimpleTextInExNotifyGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + gBS->FreePool (CurrentNotify); + Status = EFI_SUCCESS; + goto Exit; + } + } + + // + // Can not find the specified Notification Handle + // + Status = EFI_NOT_FOUND; +Exit: + // + // Leave critical section and return + // + gBS->RestoreTPL (OldTpl); + return Status; +} + diff --git a/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c b/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c index 4e39fa06d6..359d031ad2 100644 --- a/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c +++ b/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c @@ -44,9 +44,12 @@ KbdControllerDriverStop ( IN EFI_HANDLE *ChildHandleBuffer ); -// -// Global variables -// +STATIC +EFI_STATUS +KbdFreeNotifyList ( + IN OUT LIST_ENTRY *ListHead + ); + // // DriverBinding Protocol Instance // @@ -215,6 +218,13 @@ Returns: ConsoleIn->Alted = FALSE; ConsoleIn->DevicePath = ParentDevicePath; + ConsoleIn->ConInEx.Reset = KeyboardEfiResetEx; + ConsoleIn->ConInEx.ReadKeyStrokeEx = KeyboardReadKeyStrokeEx; + ConsoleIn->ConInEx.SetState = KeyboardSetState; + ConsoleIn->ConInEx.RegisterKeyNotify = KeyboardRegisterKeyNotify; + ConsoleIn->ConInEx.UnregisterKeyNotify = KeyboardUnregisterKeyNotify; + + InitializeListHead (&ConsoleIn->NotifyList); // // Setup the WaitForKey event // @@ -231,6 +241,20 @@ Returns: goto ErrorExit; } // + // Setup the WaitForKeyEx event + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + KeyboardWaitForKeyEx, + &(ConsoleIn->ConInEx), + &(ConsoleIn->ConInEx.WaitForKeyEx) + ); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR; + goto ErrorExit; + } // Setup a periodic timer, used for reading keystrokes at a fixed interval // Status = gBS->CreateEvent ( @@ -297,6 +321,8 @@ Returns: &Controller, &gEfiSimpleTextInProtocolGuid, &ConsoleIn->ConIn, + &gEfiSimpleTextInputExProtocolGuid, + &ConsoleIn->ConInEx, NULL ); if (EFI_ERROR (Status)) { @@ -325,7 +351,10 @@ ErrorExit: if ((ConsoleIn != NULL) && (ConsoleIn->TimerEvent != NULL)) { gBS->CloseEvent (ConsoleIn->TimerEvent); } - + if ((ConsoleIn != NULL) && (ConsoleIn->ConInEx.WaitForKeyEx != NULL)) { + gBS->CloseEvent (ConsoleIn->ConInEx.WaitForKeyEx); + } + KbdFreeNotifyList (&ConsoleIn->NotifyList); if ((ConsoleIn != NULL) && (ConsoleIn->ControllerNameTable != NULL)) { FreeUnicodeStringTable (ConsoleIn->ControllerNameTable); } @@ -401,7 +430,18 @@ KbdControllerDriverStop ( if (EFI_ERROR (Status)) { return Status; } - + Status = gBS->OpenProtocol ( + Controller, + &gEfiSimpleTextInputExProtocolGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (ConIn); // @@ -431,12 +471,15 @@ KbdControllerDriverStop ( Status = KeyboardRead (ConsoleIn, &Data);; } // - // Uninstall the Simple TextIn Protocol + // Uninstall the SimpleTextIn and SimpleTextInEx protocols // - Status = gBS->UninstallProtocolInterface ( + Status = gBS->UninstallMultipleProtocolInterfaces ( Controller, &gEfiSimpleTextInProtocolGuid, - &ConsoleIn->ConIn + &ConsoleIn->ConIn, + &gEfiSimpleTextInputExProtocolGuid, + &ConsoleIn->ConInEx, + NULL ); if (EFI_ERROR (Status)) { return Status; @@ -463,13 +506,55 @@ KbdControllerDriverStop ( gBS->CloseEvent ((ConsoleIn->ConIn).WaitForKey); (ConsoleIn->ConIn).WaitForKey = NULL; } - + if (ConsoleIn->ConInEx.WaitForKeyEx != NULL) { + gBS->CloseEvent (ConsoleIn->ConInEx.WaitForKeyEx); + ConsoleIn->ConInEx.WaitForKeyEx = NULL; + } + KbdFreeNotifyList (&ConsoleIn->NotifyList); FreeUnicodeStringTable (ConsoleIn->ControllerNameTable); gBS->FreePool (ConsoleIn); return EFI_SUCCESS; } +STATIC +EFI_STATUS +KbdFreeNotifyList ( + IN OUT LIST_ENTRY *ListHead + ) +/*++ + +Routine Description: + +Arguments: + + ListHead - The list head + +Returns: + + EFI_SUCCESS - Free the notify list successfully + EFI_INVALID_PARAMETER - ListHead is invalid. + +--*/ +{ + KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode; + + if (ListHead == NULL) { + return EFI_INVALID_PARAMETER; + } + while (!IsListEmpty (ListHead)) { + NotifyNode = CR ( + ListHead->ForwardLink, + KEYBOARD_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + RemoveEntryList (ListHead->ForwardLink); + gBS->FreePool (NotifyNode); + } + + return EFI_SUCCESS; +} /** The user Entry Point for module Ps2Keyboard. The user code starts with this function. diff --git a/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h b/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h index 4f1080fe1b..1eb2c5491c 100644 --- a/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h +++ b/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h @@ -1,5 +1,5 @@ /**@file - PS/2 keyboard driver header file + PS/2 keyboard driver header file Copyright (c) 2006 - 2007, Intel Corporation All rights reserved. This program and the accompanying materials @@ -19,6 +19,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include +#include #include #include #include @@ -30,18 +31,31 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include +#include // // Driver Private Data // #define KEYBOARD_BUFFER_MAX_COUNT 32 #define KEYBOARD_CONSOLE_IN_DEV_SIGNATURE EFI_SIGNATURE_32 ('k', 'k', 'e', 'y') +#define KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE EFI_SIGNATURE_32 ('k', 'c', 'e', 'n') + +typedef struct _KEYBOARD_CONSOLE_IN_EX_NOTIFY { + UINTN Signature; + EFI_HANDLE NotifyHandle; + EFI_KEY_DATA KeyData; + EFI_KEY_NOTIFY_FUNCTION KeyNotificationFn; + LIST_ENTRY NotifyEntry; +} KEYBOARD_CONSOLE_IN_EX_NOTIFY; + typedef struct { UINTN Signature; EFI_HANDLE Handle; EFI_SIMPLE_TEXT_INPUT_PROTOCOL ConIn; + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL ConInEx; EFI_ISA_IO_PROTOCOL *IsaIo; EFI_EVENT TimerEvent; @@ -51,6 +65,14 @@ typedef struct { UINT32 CommandRegisterAddress; EFI_INPUT_KEY Key; + EFI_KEY_STATE KeyState; + + BOOLEAN LeftShift; + BOOLEAN RightShift; + BOOLEAN LeftLogo; + BOOLEAN RightLogo; + BOOLEAN Menu; + BOOLEAN SysReq; BOOLEAN Ctrl; BOOLEAN Alt; @@ -81,9 +103,19 @@ typedef struct { EFI_UNICODE_STRING_TABLE *ControllerNameTable; EFI_DEVICE_PATH_PROTOCOL *DevicePath; + // + // Notification Function List + // + LIST_ENTRY NotifyList; } KEYBOARD_CONSOLE_IN_DEV; #define KEYBOARD_CONSOLE_IN_DEV_FROM_THIS(a) CR (a, KEYBOARD_CONSOLE_IN_DEV, ConIn, KEYBOARD_CONSOLE_IN_DEV_SIGNATURE) +#define TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS(a) \ + CR (a, \ + KEYBOARD_CONSOLE_IN_DEV, \ + ConInEx, \ + KEYBOARD_CONSOLE_IN_DEV_SIGNATURE \ + ) #define TABLE_END 0x0 @@ -94,10 +126,13 @@ extern EFI_DRIVER_BINDING_PROTOCOL gKeyboardControllerDriver; extern EFI_COMPONENT_NAME_PROTOCOL gPs2KeyboardComponentName; extern EFI_COMPONENT_NAME2_PROTOCOL gPs2KeyboardComponentName2; +extern EFI_GUID gSimpleTextInExNotifyGuid; + // // Driver entry point // EFI_STATUS +EFIAPI InstallPs2KeyboardDriver ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable @@ -144,11 +179,42 @@ Returns: #define SCANCODE_CAPS_LOCK_MAKE 0x3A #define SCANCODE_NUM_LOCK_MAKE 0x45 #define SCANCODE_SCROLL_LOCK_MAKE 0x46 -#define SCANCODE_MAX_MAKE 0x59 +#define SCANCODE_LEFT_LOGO_MAKE 0x5B //GUI key defined in Keyboard scan code +#define SCANCODE_LEFT_LOGO_BREAK 0xDB +#define SCANCODE_RIGHT_LOGO_MAKE 0x5C +#define SCANCODE_RIGHT_LOGO_BREAK 0xDC +#define SCANCODE_MENU_MAKE 0x5D //APPS key defined in Keyboard scan code +#define SCANCODE_MENU_BREAK 0xDD +#define SCANCODE_SYS_REQ_MAKE 0x37 +#define SCANCODE_MAX_MAKE 0x60 // // Other functions that are used among .c files // + +EFI_STATUS +UpdateStatusLights ( + IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn + ) +/*++ + +Routine Description: + + Show keyboard status light for ScrollLock, NumLock and CapsLock + according to indicators in ConsoleIn. + +Arguments: + + ConsoleIn - driver private structure + +Returns: + + EFI_SUCCESS - Show the status light successfully. + EFI_TIMEOUT - Timeout when operating read/write on registers. + +--*/ +; + EFI_STATUS KeyboardRead ( IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn, @@ -361,8 +427,8 @@ Returns: @param[in] BiosKeyboardPrivate Keyboard Private Data Structure - @retval TRUE Keyboard in System. - @retval FALSE Keyboard not in System. + @retval TRUE Keyboard in System. + @retval FALSE Keyboard not in System. **/ BOOLEAN EFIAPI @@ -370,4 +436,157 @@ CheckKeyboardConnect ( IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn ) ; + +VOID +EFIAPI +KeyboardWaitForKeyEx ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event + Signal the event if there is key available + +Arguments: + +Returns: + +--*/ +; + +// +// Simple Text Input Ex protocol function prototypes +// + +EFI_STATUS +EFIAPI +KeyboardEfiResetEx ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset the input device and optionaly run diagnostics + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - Driver may perform diagnostics on reset. + + Returns: + EFI_SUCCESS - The device was reset. + EFI_DEVICE_ERROR - The device is not functioning properly and could + not be reset. + +--*/ +; + +EFI_STATUS +EFIAPI +KeyboardReadKeyStrokeEx ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + OUT EFI_KEY_DATA *KeyData + ) +/*++ + + Routine Description: + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existance of a keystroke via WaitForEvent () call. + + Arguments: + This - Protocol instance pointer. + KeyData - A pointer to a buffer that is filled in with the keystroke + state data for the key that was pressed. + + Returns: + EFI_SUCCESS - The keystroke information was returned. + EFI_NOT_READY - There was no keystroke data availiable. + EFI_DEVICE_ERROR - The keystroke information was not returned due to + hardware errors. + EFI_INVALID_PARAMETER - KeyData is NULL. + +--*/ +; + +EFI_STATUS +EFIAPI +KeyboardSetState ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_KEY_TOGGLE_STATE *KeyToggleState + ) +/*++ + + Routine Description: + Set certain state for the input device. + + Arguments: + This - Protocol instance pointer. + KeyToggleState - A pointer to the EFI_KEY_TOGGLE_STATE to set the + state for the input device. + + Returns: + EFI_SUCCESS - The device state was set successfully. + EFI_DEVICE_ERROR - The device is not functioning correctly and could + not have the setting adjusted. + EFI_UNSUPPORTED - The device does not have the ability to set its state. + EFI_INVALID_PARAMETER - KeyToggleState is NULL. + +--*/ +; + +EFI_STATUS +EFIAPI +KeyboardRegisterKeyNotify ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_KEY_DATA *KeyData, + IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, + OUT EFI_HANDLE *NotifyHandle + ) +/*++ + + Routine Description: + Register a notification function for a particular keystroke for the input device. + + Arguments: + This - Protocol instance pointer. + KeyData - A pointer to a buffer that is filled in with the keystroke + information data for the key that was pressed. + KeyNotificationFunction - Points to the function to be called when the key + sequence is typed specified by KeyData. + NotifyHandle - Points to the unique handle assigned to the registered notification. + + Returns: + EFI_SUCCESS - The notification function was registered successfully. + EFI_OUT_OF_RESOURCES - Unable to allocate resources for necesssary data structures. + EFI_INVALID_PARAMETER - KeyData or NotifyHandle is NULL. + +--*/ +; + +EFI_STATUS +EFIAPI +KeyboardUnregisterKeyNotify ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_HANDLE NotificationHandle + ) +/*++ + + Routine Description: + Remove a registered notification function from a particular keystroke. + + Arguments: + This - Protocol instance pointer. + NotificationHandle - The handle of the notification function being unregistered. + + Returns: + EFI_SUCCESS - The notification function was unregistered successfully. + EFI_INVALID_PARAMETER - The NotificationHandle is invalid. + EFI_NOT_FOUND - Can not find the matching entry in database. + +--*/ +; + #endif diff --git a/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2keyboardDxe.inf b/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2keyboardDxe.inf index 6a8890613f..4aa2dae009 100644 --- a/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2keyboardDxe.inf +++ b/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2keyboardDxe.inf @@ -51,10 +51,16 @@ UefiBootServicesTableLib UefiLib UefiDriverEntryPoint + BaseLib + BaseMemoryLib [Protocols] gEfiPs2PolicyProtocolGuid # PROTOCOL TO_START gEfiIsaIoProtocolGuid # PROTOCOL TO_START gEfiSimpleTextInProtocolGuid # PROTOCOL BY_START + gEfiSimpleTextInputExProtocolGuid # PROTOCOL BY_START gEfiDevicePathProtocolGuid # PROTOCOL TO_START +[Guids] + gSimpleTextInExNotifyGuid # SOMETIMES_CONSUMED + -- 2.39.2