diff --git a/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c b/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c index eeb7de34ab..f92521046f 100644 --- a/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c +++ b/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c @@ -1420,7 +1420,7 @@ KeyGetchar ( } // - // Invoke notification functions if exist + // Signal KeyNotify process event if this key pressed matches any key registered. // for (Link = GetFirstNode (&ConsoleIn->NotifyList); !IsNull (&ConsoleIn->NotifyList, Link); Link = GetNextNode (&ConsoleIn->NotifyList, Link)) { CurrentNotify = CR ( @@ -1430,7 +1430,13 @@ KeyGetchar ( KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE ); if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { - CurrentNotify->KeyNotificationFn (&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. + // + PushEfikeyBufTail (&ConsoleIn->EfiKeyQueueForNotify, &KeyData); + gBS->SignalEvent (ConsoleIn->KeyNotifyProcessEvent); } } @@ -1629,6 +1635,8 @@ InitKeyboard ( ConsoleIn->ScancodeQueue.Tail = 0; ConsoleIn->EfiKeyQueue.Head = 0; ConsoleIn->EfiKeyQueue.Tail = 0; + ConsoleIn->EfiKeyQueueForNotify.Head = 0; + ConsoleIn->EfiKeyQueueForNotify.Tail = 0; // // Reset the status indicators diff --git a/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c b/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c index f6ccd9598f..bc58fe2f8c 100644 --- a/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c +++ b/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c @@ -681,3 +681,52 @@ Exit: return Status; } +/** + 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; + KEYBOARD_CONSOLE_IN_DEV *ConsoleIn; + EFI_KEY_DATA KeyData; + LIST_ENTRY *Link; + LIST_ENTRY *NotifyList; + KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + EFI_TPL OldTpl; + + ConsoleIn = (KEYBOARD_CONSOLE_IN_DEV *) Context; + + // + // Invoke notification functions. + // + NotifyList = &ConsoleIn->NotifyList; + while (TRUE) { + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + Status = PopEfikeyBufHead (&ConsoleIn->EfiKeyQueueForNotify, &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, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE); + if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { + CurrentNotify->KeyNotificationFn (&KeyData); + } + } + } +} + diff --git a/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c b/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c index 4df1b890e6..6121d29fb7 100644 --- a/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c +++ b/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c @@ -351,6 +351,19 @@ KbdControllerDriverStart ( goto ErrorExit; } + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + KeyNotifyProcessHandler, + ConsoleIn, + &ConsoleIn->KeyNotifyProcessEvent + ); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR; + goto ErrorExit; + } + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT, @@ -430,6 +443,9 @@ ErrorExit: if ((ConsoleIn != NULL) && (ConsoleIn->ConInEx.WaitForKeyEx != NULL)) { gBS->CloseEvent (ConsoleIn->ConInEx.WaitForKeyEx); } + if ((ConsoleIn != NULL) && (ConsoleIn->KeyNotifyProcessEvent != NULL)) { + gBS->CloseEvent (ConsoleIn->KeyNotifyProcessEvent); + } KbdFreeNotifyList (&ConsoleIn->NotifyList); if ((ConsoleIn != NULL) && (ConsoleIn->ControllerNameTable != NULL)) { FreeUnicodeStringTable (ConsoleIn->ControllerNameTable); @@ -570,6 +586,10 @@ KbdControllerDriverStop ( gBS->CloseEvent (ConsoleIn->ConInEx.WaitForKeyEx); ConsoleIn->ConInEx.WaitForKeyEx = NULL; } + if (ConsoleIn->KeyNotifyProcessEvent != NULL) { + gBS->CloseEvent (ConsoleIn->KeyNotifyProcessEvent); + ConsoleIn->KeyNotifyProcessEvent = NULL; + } KbdFreeNotifyList (&ConsoleIn->NotifyList); FreeUnicodeStringTable (ConsoleIn->ControllerNameTable); gBS->FreePool (ConsoleIn); diff --git a/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h b/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h index d0aecfb087..e41c1980fc 100644 --- a/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h +++ b/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h @@ -105,6 +105,7 @@ typedef struct { // SCAN_CODE_QUEUE ScancodeQueue; EFI_KEY_QUEUE EfiKeyQueue; + EFI_KEY_QUEUE EfiKeyQueueForNotify; // // Error state @@ -118,6 +119,7 @@ typedef struct { // Notification Function List // LIST_ENTRY NotifyList; + EFI_EVENT KeyNotifyProcessEvent; } KEYBOARD_CONSOLE_IN_DEV; #define KEYBOARD_CONSOLE_IN_DEV_FROM_THIS(a) CR (a, KEYBOARD_CONSOLE_IN_DEV, ConIn, KEYBOARD_CONSOLE_IN_DEV_SIGNATURE) @@ -268,6 +270,19 @@ KeyGetchar ( IN OUT KEYBOARD_CONSOLE_IN_DEV *ConsoleIn ); +/** + 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 + ); + /** Perform 8042 controller and keyboard Initialization. If ExtendedVerification is TRUE, do additional test for