From 66aa04e4e3a0b84369cbb483a78c4113b619663a Mon Sep 17 00:00:00 2001 From: qhuang8 Date: Fri, 19 Oct 2007 02:35:29 +0000 Subject: [PATCH] Update to support EFI_SIMPLE_INPUT_EX protocol git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@4178 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf | 5 +- MdeModulePkg/Bus/Usb/UsbKbDxe/efikey.c | 634 ++++++++++++++++-- MdeModulePkg/Bus/Usb/UsbKbDxe/efikey.h | 170 ++++- MdeModulePkg/Bus/Usb/UsbKbDxe/keyboard.c | 210 +++++- .../Console/ConSplitterDxe/ConSplitter.c | 565 ++++++++++++++++ .../Console/ConSplitterDxe/ConSplitter.h | 185 ++++- .../Console/ConSplitterDxe/ConSplitterDxe.inf | 2 + .../Universal/Console/TerminalDxe/Terminal.c | 88 ++- .../Universal/Console/TerminalDxe/Terminal.h | 179 ++++- .../Console/TerminalDxe/TerminalConIn.c | 436 +++++++++++- .../Console/TerminalDxe/TerminalDxe.inf | 4 +- 11 files changed, 2386 insertions(+), 92 deletions(-) diff --git a/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf b/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf index 34017086a4..a075c0e1ab 100644 --- a/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf +++ b/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf @@ -55,16 +55,17 @@ DebugLib PcdLib UsbLib - + BaseLib [Guids] gEfiHotPlugDeviceGuid # ALWAYS_CONSUMED - + gSimpleTextInExNotifyGuid # ALWAYS_CONSUMED [Protocols] gEfiUsbIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED gEfiSimpleTextInProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiSimpleTextInputExProtocolGuid # PROTOCOL ALWAYS_CONSUMED [FixedPcd] gEfiMdePkgTokenSpaceGuid.PcdStatusCodeValueKeyboardEnable diff --git a/MdeModulePkg/Bus/Usb/UsbKbDxe/efikey.c b/MdeModulePkg/Bus/Usb/UsbKbDxe/efikey.c index 62fec041c3..eee3827c23 100644 --- a/MdeModulePkg/Bus/Usb/UsbKbDxe/efikey.c +++ b/MdeModulePkg/Bus/Usb/UsbKbDxe/efikey.c @@ -100,6 +100,18 @@ USBKeyboardCheckForKey ( EFI_GUID gEfiUsbKeyboardDriverGuid = { 0xa05f5f78, 0xfb3, 0x4d10, {0x90, 0x90, 0xac, 0x4, 0x6e, 0xeb, 0x7c, 0x3c} }; +STATIC +EFI_STATUS +KbdFreeNotifyList ( + IN OUT LIST_ENTRY *ListHead + ); +STATIC +BOOLEAN +IsKeyRegistered ( + IN EFI_KEY_DATA *RegsiteredData, + IN EFI_KEY_DATA *InputData + ); + // // USB Keyboard Driver Global Variables @@ -349,6 +361,27 @@ USBKeyboardDriverBindingStart ( UsbKeyboardDevice->Signature = USB_KB_DEV_SIGNATURE; UsbKeyboardDevice->SimpleInput.Reset = USBKeyboardReset; UsbKeyboardDevice->SimpleInput.ReadKeyStroke = USBKeyboardReadKeyStroke; + + UsbKeyboardDevice->SimpleInputEx.Reset = USBKeyboardResetEx; + UsbKeyboardDevice->SimpleInputEx.ReadKeyStrokeEx = USBKeyboardReadKeyStrokeEx; + UsbKeyboardDevice->SimpleInputEx.SetState = USBKeyboardSetState; + UsbKeyboardDevice->SimpleInputEx.RegisterKeyNotify = USBKeyboardRegisterKeyNotify; + UsbKeyboardDevice->SimpleInputEx.UnregisterKeyNotify = USBKeyboardUnregisterKeyNotify; + + InitializeListHead (&UsbKeyboardDevice->NotifyList); + + Status = gBS->CreateEvent ( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + USBKeyboardWaitForKey, + UsbKeyboardDevice, + &(UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx) + ); + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + Status = gBS->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY, @@ -380,6 +413,8 @@ USBKeyboardDriverBindingStart ( &Controller, &gEfiSimpleTextInProtocolGuid, &UsbKeyboardDevice->SimpleInput, + &gEfiSimpleTextInputExProtocolGuid, + &UsbKeyboardDevice->SimpleInputEx, &gEfiHotPlugDeviceGuid, NULL, NULL @@ -405,13 +440,15 @@ USBKeyboardDriverBindingStart ( ); if (EFI_ERROR (Status)) { gBS->UninstallMultipleProtocolInterfaces ( - Controller, - &gEfiSimpleTextInProtocolGuid, - &UsbKeyboardDevice->SimpleInput, - &gEfiHotPlugDeviceGuid, - NULL, - NULL - ); + Controller, + &gEfiSimpleTextInProtocolGuid, + &UsbKeyboardDevice->SimpleInput, + &gEfiSimpleTextInputExProtocolGuid, + &UsbKeyboardDevice->SimpleInputEx, + &gEfiHotPlugDeviceGuid, + NULL, + NULL + ); gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); gBS->FreePool (UsbKeyboardDevice); gBS->CloseProtocol ( @@ -442,13 +479,15 @@ USBKeyboardDriverBindingStart ( if (EFI_ERROR (Status)) { gBS->UninstallMultipleProtocolInterfaces ( - Controller, - &gEfiSimpleTextInProtocolGuid, - &UsbKeyboardDevice->SimpleInput, - &gEfiHotPlugDeviceGuid, - NULL, - NULL - ); + Controller, + &gEfiSimpleTextInProtocolGuid, + &UsbKeyboardDevice->SimpleInput, + &gEfiSimpleTextInputExProtocolGuid, + &UsbKeyboardDevice->SimpleInputEx, + &gEfiHotPlugDeviceGuid, + NULL, + NULL + ); gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); gBS->FreePool (UsbKeyboardDevice); gBS->CloseProtocol ( @@ -478,6 +517,27 @@ USBKeyboardDriverBindingStart ( return EFI_SUCCESS; + +ErrorExit: + if (UsbKeyboardDevice != NULL) { + if (UsbKeyboardDevice->SimpleInput.WaitForKey != NULL) { + gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); + } + if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) { + gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx); + } + KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList); + gBS->FreePool (UsbKeyboardDevice); + UsbKeyboardDevice = NULL; + } + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } @@ -518,7 +578,17 @@ USBKeyboardDriverBindingStop ( if (EFI_ERROR (Status)) { return EFI_UNSUPPORTED; } - + Status = gBS->OpenProtocol ( + Controller, + &gEfiSimpleTextInputExProtocolGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } // // Get USB_KB_DEV instance. // @@ -565,6 +635,8 @@ USBKeyboardDriverBindingStop ( Controller, &gEfiSimpleTextInProtocolGuid, &UsbKeyboardDevice->SimpleInput, + &gEfiSimpleTextInputExProtocolGuid, + &UsbKeyboardDevice->SimpleInputEx, &gEfiHotPlugDeviceGuid, NULL, NULL @@ -575,6 +647,8 @@ USBKeyboardDriverBindingStop ( gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer); gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent); gBS->CloseEvent ((UsbKeyboardDevice->SimpleInput).WaitForKey); + gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx); + KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList); if (UsbKeyboardDevice->ControllerNameTable != NULL) { FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable); @@ -586,20 +660,107 @@ USBKeyboardDriverBindingStop ( } +STATIC +EFI_STATUS +USBKeyboardReadKeyStrokeWorker ( + IN USB_KB_DEV *UsbKeyboardDevice, + 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. -/** - Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset() function. + Arguments: + UsbKeyboardDevice - Usb keyboard private structure. + KeyData - A pointer to a buffer that is filled in with the keystroke + state data for the key that was pressed. - This The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance. - ExtendedVerification - Indicates that the driver may perform a more exhaustive - verification operation of the device during reset. + 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. - @retval EFI_SUCCESS Success - @retval EFI_DEVICE_ERROR Hardware Error +--*/ +{ -**/ + EFI_STATUS Status; + UINT8 KeyChar; + LIST_ENTRY *Link; + KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + EFI_KEY_DATA OriginalKeyData; + + if (KeyData == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // if there is no saved ASCII byte, fetch it + // by calling USBKeyboardCheckForKey(). + // + if (UsbKeyboardDevice->CurKeyChar == 0) { + Status = USBKeyboardCheckForKey (UsbKeyboardDevice); + if (EFI_ERROR (Status)) { + return Status; + } + } + + KeyData->Key.UnicodeChar = 0; + KeyData->Key.ScanCode = SCAN_NULL; + + KeyChar = UsbKeyboardDevice->CurKeyChar; + + UsbKeyboardDevice->CurKeyChar = 0; + + // + // Translate saved ASCII byte into EFI_INPUT_KEY + // + Status = USBKeyCodeToEFIScanCode (UsbKeyboardDevice, KeyChar, &KeyData->Key); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem (&KeyData->KeyState, &UsbKeyboardDevice->KeyState, sizeof (KeyData->KeyState)); + + UsbKeyboardDevice->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID; + UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID; + + // + //Switch the control value to their original characters. In USBKeyCodeToEFIScanCode() 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 (UsbKeyboardDevice->CtrlOn) { + if (OriginalKeyData.Key.UnicodeChar >= 0x01 && OriginalKeyData.Key.UnicodeChar <= 0x1A) { + if (UsbKeyboardDevice->CapsOn) { + 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 = UsbKeyboardDevice->NotifyList.ForwardLink; Link != &UsbKeyboardDevice->NotifyList; Link = Link->ForwardLink) { + CurrentNotify = CR ( + Link, + KEYBOARD_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + if (IsKeyRegistered (&CurrentNotify->KeyData, &OriginalKeyData)) { + CurrentNotify->KeyNotificationFn (&OriginalKeyData); + } + } + + return EFI_SUCCESS; + +} EFI_STATUS EFIAPI USBKeyboardReset ( @@ -668,36 +829,20 @@ USBKeyboardReadKeyStroke ( OUT EFI_INPUT_KEY *Key ) { - USB_KB_DEV *UsbKeyboardDevice; - EFI_STATUS Status; - UINT8 KeyChar; + USB_KB_DEV *UsbKeyboardDevice; + EFI_STATUS Status; + EFI_KEY_DATA KeyData; UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This); - // - // if there is no saved ASCII byte, fetch it - // by calling USBKeyboardCheckForKey(). - // - if (UsbKeyboardDevice->CurKeyChar == 0) { - Status = USBKeyboardCheckForKey (UsbKeyboardDevice); - if (EFI_ERROR (Status)) { - return Status; - } + Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData); + if (EFI_ERROR (Status)) { + return Status; } - Key->UnicodeChar = 0; - Key->ScanCode = SCAN_NULL; + CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY)); - KeyChar = UsbKeyboardDevice->CurKeyChar; - - UsbKeyboardDevice->CurKeyChar = 0; - - // - // Translate saved ASCII byte into EFI_INPUT_KEY - // - Status = USBKeyCodeToEFIScanCode (UsbKeyboardDevice, KeyChar, Key); - - return Status; + return EFI_SUCCESS; } @@ -792,3 +937,396 @@ KbdReportStatusCode ( DevicePath ); } +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, + USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + RemoveEntryList (ListHead->ForwardLink); + gBS->FreePool (NotifyNode); + } + + 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; + +} + +// +// Simple Text Input Ex protocol functions +// +EFI_STATUS +EFIAPI +USBKeyboardResetEx ( + 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; + USB_KB_DEV *UsbKeyboardDevice; + EFI_TPL OldTpl; + + + UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); + + Status = UsbKeyboardDevice->SimpleInput.Reset (&UsbKeyboardDevice->SimpleInput, ExtendedVerification); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + UsbKeyboardDevice->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID; + UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID; + gBS->RestoreTPL (OldTpl); + + return EFI_SUCCESS; + +} + +EFI_STATUS +EFIAPI +USBKeyboardReadKeyStrokeEx ( + 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. + +--*/ +{ + USB_KB_DEV *UsbKeyboardDevice; + + if (KeyData == NULL) { + return EFI_INVALID_PARAMETER; + } + + UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); + + return USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, KeyData); + +} + +EFI_STATUS +EFIAPI +USBKeyboardSetState ( + 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. + +--*/ +{ + USB_KB_DEV *UsbKeyboardDevice; + + if (KeyToggleState == NULL) { + return EFI_INVALID_PARAMETER; + } + + UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); + + if (((UsbKeyboardDevice->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) || + ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) { + return EFI_UNSUPPORTED; + } + + // + // Update the status light + // + + UsbKeyboardDevice->ScrollOn = 0; + UsbKeyboardDevice->NumLockOn = 0; + UsbKeyboardDevice->CapsOn = 0; + + if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) { + UsbKeyboardDevice->ScrollOn = 1; + } + if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) { + UsbKeyboardDevice->NumLockOn = 1; + } + if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) { + UsbKeyboardDevice->CapsOn = 1; + } + + SetKeyLED (UsbKeyboardDevice); + + UsbKeyboardDevice->KeyState.KeyToggleState = *KeyToggleState; + + return EFI_SUCCESS; + +} + +EFI_STATUS +EFIAPI +USBKeyboardRegisterKeyNotify ( + 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. + +--*/ +{ + USB_KB_DEV *UsbKeyboardDevice; + EFI_STATUS Status; + KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify; + LIST_ENTRY *Link; + KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + + if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) { + return EFI_INVALID_PARAMETER; + } + + UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); + + // + // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. + // + for (Link = UsbKeyboardDevice->NotifyList.ForwardLink; Link != &UsbKeyboardDevice->NotifyList; Link = Link->ForwardLink) { + CurrentNotify = CR ( + Link, + KEYBOARD_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { + if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { + *NotifyHandle = CurrentNotify->NotifyHandle; + return EFI_SUCCESS; + } + } + } + + // + // Allocate resource to save the notification function + // + NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY)); + if (NewNotify == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + NewNotify->Signature = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE; + NewNotify->KeyNotificationFn = KeyNotificationFunction; + CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA)); + InsertTailList (&UsbKeyboardDevice->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; + + return EFI_SUCCESS; + +} + +EFI_STATUS +EFIAPI +USBKeyboardUnregisterKeyNotify ( + 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. + +--*/ +{ + USB_KB_DEV *UsbKeyboardDevice; + EFI_STATUS Status; + KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + LIST_ENTRY *Link; + + if (NotificationHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); + + Status = gBS->OpenProtocol ( + NotificationHandle, + &gSimpleTextInExNotifyGuid, + NULL, + NULL, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + for (Link = UsbKeyboardDevice->NotifyList.ForwardLink; Link != &UsbKeyboardDevice->NotifyList; Link = Link->ForwardLink) { + CurrentNotify = CR ( + Link, + KEYBOARD_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + USB_KB_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); + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + diff --git a/MdeModulePkg/Bus/Usb/UsbKbDxe/efikey.h b/MdeModulePkg/Bus/Usb/UsbKbDxe/efikey.h index 710ec7c19e..bab22a3b88 100644 --- a/MdeModulePkg/Bus/Usb/UsbKbDxe/efikey.h +++ b/MdeModulePkg/Bus/Usb/UsbKbDxe/efikey.h @@ -26,6 +26,7 @@ Revision History #include #include +#include #include #include #include @@ -40,7 +41,7 @@ Revision History #include #include #include - +#include #include @@ -69,12 +70,22 @@ typedef struct { } USB_KB_BUFFER; #define USB_KB_DEV_SIGNATURE EFI_SIGNATURE_32 ('u', 'k', 'b', 'd') +#define USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE EFI_SIGNATURE_32 ('u', 'k', 'b', 'x') + +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_DEVICE_PATH_PROTOCOL *DevicePath; EFI_EVENT DelayedRecoveryEvent; EFI_SIMPLE_TEXT_INPUT_PROTOCOL SimpleInput; - EFI_USB_IO_PROTOCOL *UsbIo; + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL SimpleInputEx; + EFI_USB_IO_PROTOCOL *UsbIo; EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; EFI_USB_ENDPOINT_DESCRIPTOR IntEndpointDescriptor; @@ -93,7 +104,23 @@ typedef struct { EFI_EVENT RepeatTimer; EFI_UNICODE_STRING_TABLE *ControllerNameTable; + + UINT8 LeftCtrlOn; + UINT8 LeftAltOn; + UINT8 LeftShiftOn; + UINT8 LeftLogoOn; + UINT8 RightCtrlOn; + UINT8 RightAltOn; + UINT8 RightShiftOn; + UINT8 RightLogoOn; + UINT8 MenuKeyOn; + UINT8 SysReqOn; + EFI_KEY_STATE KeyState; + // + // Notification function list + // + LIST_ENTRY NotifyList; } USB_KB_DEV; // @@ -103,6 +130,7 @@ extern EFI_DRIVER_BINDING_PROTOCOL gUsbKeyboardDriverBinding; extern EFI_COMPONENT_NAME_PROTOCOL gUsbKeyboardComponentName; extern EFI_COMPONENT_NAME2_PROTOCOL gUsbKeyboardComponentName2; extern EFI_GUID gEfiUsbKeyboardDriverGuid; +extern EFI_GUID gSimpleTextInExNotifyGuid; VOID KbdReportStatusCode ( @@ -113,6 +141,9 @@ KbdReportStatusCode ( #define USB_KB_DEV_FROM_THIS(a) \ CR(a, USB_KB_DEV, SimpleInput, USB_KB_DEV_SIGNATURE) +#define TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS(a) \ + CR(a, USB_KB_DEV, SimpleInputEx, USB_KB_DEV_SIGNATURE) + #define MOD_CONTROL_L 0x01 #define MOD_CONTROL_R 0x10 @@ -128,7 +159,7 @@ typedef struct { UINT8 Key; } KB_MODIFIER; -#define USB_KEYCODE_MAX_MAKE 0x64 +#define USB_KEYCODE_MAX_MAKE 0x7E #define USBKBD_VALID_KEYCODE(key) ((UINT8) (key) > 3) @@ -138,4 +169,137 @@ typedef struct { UINT8 ScrollLock : 1; UINT8 Resrvd : 5; } LED_MAP; + +// +// Simple Text Input Ex protocol functions +// +EFI_STATUS +EFIAPI +USBKeyboardResetEx ( + 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 +USBKeyboardReadKeyStrokeEx ( + 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 +USBKeyboardSetState ( + 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 +USBKeyboardRegisterKeyNotify ( + 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 +USBKeyboardUnregisterKeyNotify ( + 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/MdeModulePkg/Bus/Usb/UsbKbDxe/keyboard.c b/MdeModulePkg/Bus/Usb/UsbKbDxe/keyboard.c index 9ad1bcef24..87179a4c6b 100644 --- a/MdeModulePkg/Bus/Usb/UsbKbDxe/keyboard.c +++ b/MdeModulePkg/Bus/Usb/UsbKbDxe/keyboard.c @@ -94,8 +94,8 @@ UINT8 KeyConvertionTable[USB_KEYCODE_MAX_MAKE][3] = { { SCAN_F8, 0x00, 0x00 }, // 0x41 { SCAN_F9, 0x00, 0x00 }, // 0x42 { SCAN_F10, 0x00, 0x00 }, // 0x43 - { SCAN_F11, 0x00, 0x00 }, // 0x44 F11 - { SCAN_F12, 0x00, 0x00 }, // 0x45 F12 + { SCAN_F11, 0x00, 0x00 }, // 0x44 F11 + { SCAN_F12, 0x00, 0x00 }, // 0x45 F12 { SCAN_NULL, 0x00, 0x00 }, // 0x46 PrintScreen { SCAN_NULL, 0x00, 0x00 }, // 0x47 Scroll Lock { SCAN_NULL, 0x00, 0x00 }, // 0x48 Pause @@ -129,7 +129,22 @@ UINT8 KeyConvertionTable[USB_KEYCODE_MAX_MAKE][3] = { { SCAN_NULL, '\\', '|' }, // 0x64 Keyboard Non-US \ and | { SCAN_NULL, 0x00, 0x00 }, // 0x65 Keyboard Application { SCAN_NULL, 0x00, 0x00 }, // 0x66 Keyboard Power - { SCAN_NULL, '=' , '=' } // 0x67 Keypad = + { SCAN_NULL, '=' , '=' }, // 0x67 Keypad = + { SCAN_F13, 0x00, 0x00 }, // 0x68 + { SCAN_F14, 0x00, 0x00 }, // 0x69 + { SCAN_F15, 0x00, 0x00 }, // 0x6A + { SCAN_F16, 0x00, 0x00 }, // 0x6B + { SCAN_F17, 0x00, 0x00 }, // 0x6C + { SCAN_F18, 0x00, 0x00 }, // 0x6D + { SCAN_F19, 0x00, 0x00 }, // 0x6E + { SCAN_F20, 0x00, 0x00 }, // 0x6F + { SCAN_F21, 0x00, 0x00 }, // 0x70 + { SCAN_F22, 0x00, 0x00 }, // 0x71 + { SCAN_F23, 0x00, 0x00 }, // 0x72 + { SCAN_F24, 0x00, 0x00 }, // 0x73 + { SCAN_MUTE, 0x00, 0x00 }, // 0x7F + { SCAN_VOLUME_UP, 0x00, 0x00 }, // 0x80 + { SCAN_VOLUME_DOWN, 0x00, 0x00 }, // 0x81 }; STATIC KB_MODIFIER KB_Mod[8] = { @@ -140,7 +155,7 @@ STATIC KB_MODIFIER KB_Mod[8] = { { MOD_ALT_L, 0xe2 }, // 11100010 { MOD_ALT_R, 0xe6 }, // 11100110 { MOD_WIN_L, 0xe3 }, // 11100011 - { MOD_WIN_R, 0xe7 } // 11100111 + { MOD_WIN_R, 0xe7 }, // 11100111 }; @@ -286,6 +301,17 @@ InitUSBKeyboard ( UsbKeyboardDevice->NumLockOn = 0; UsbKeyboardDevice->CapsOn = 0; UsbKeyboardDevice->ScrollOn = 0; + + UsbKeyboardDevice->LeftCtrlOn = 0; + UsbKeyboardDevice->LeftAltOn = 0; + UsbKeyboardDevice->LeftShiftOn = 0; + UsbKeyboardDevice->LeftLogoOn = 0; + UsbKeyboardDevice->RightCtrlOn = 0; + UsbKeyboardDevice->RightAltOn = 0; + UsbKeyboardDevice->RightShiftOn = 0; + UsbKeyboardDevice->RightLogoOn = 0; + UsbKeyboardDevice->MenuKeyOn = 0; + UsbKeyboardDevice->SysReqOn = 0; // // Sync the initial state of lights @@ -675,21 +701,65 @@ USBParseKey ( if (!UsbKey.Down) { switch (UsbKey.KeyCode) { + // + // CTRL release + // case 0xe0: + UsbKeyboardDevice->LeftCtrlOn = 0; + UsbKeyboardDevice->CtrlOn = 0; + break; case 0xe4: + UsbKeyboardDevice->RightCtrlOn = 0; UsbKeyboardDevice->CtrlOn = 0; break; + // + // Shift release + // case 0xe1: + UsbKeyboardDevice->LeftShiftOn = 0; + UsbKeyboardDevice->ShiftOn = 0; + break; case 0xe5: + UsbKeyboardDevice->RightShiftOn = 0; UsbKeyboardDevice->ShiftOn = 0; break; + // + // Alt release + // case 0xe2: + UsbKeyboardDevice->LeftAltOn = 0; + UsbKeyboardDevice->AltOn = 0; + break; case 0xe6: + UsbKeyboardDevice->RightAltOn = 0; UsbKeyboardDevice->AltOn = 0; break; + // + // Logo release + // + case 0xe3: + UsbKeyboardDevice->LeftLogoOn = 0; + break; + case 0xe7: + UsbKeyboardDevice->RightLogoOn = 0; + break; + + // + // Menu key (App/Apps) release + // + case 0x65: + UsbKeyboardDevice->MenuKeyOn = 0; + break; + + // + // SysReq release + // + case 0x46: + UsbKeyboardDevice->SysReqOn = 0; + break; default: break; } @@ -703,51 +773,95 @@ USBParseKey ( switch (UsbKey.KeyCode) { case 0xe0: + UsbKeyboardDevice->LeftCtrlOn = 1; + UsbKeyboardDevice->CtrlOn = 1; + continue; + break; case 0xe4: + UsbKeyboardDevice->RightCtrlOn = 1; UsbKeyboardDevice->CtrlOn = 1; continue; break; + // + // Shift press + // case 0xe1: + UsbKeyboardDevice->LeftShiftOn = 1; + UsbKeyboardDevice->ShiftOn = 1; + continue; + break; case 0xe5: + UsbKeyboardDevice->RightShiftOn = 1; UsbKeyboardDevice->ShiftOn = 1; continue; break; + // + // Alt press + // case 0xe2: + UsbKeyboardDevice->LeftAltOn = 1; + UsbKeyboardDevice->AltOn = 1; + continue; + break; case 0xe6: + UsbKeyboardDevice->RightAltOn = 1; UsbKeyboardDevice->AltOn = 1; continue; break; + // + // Logo press + // case 0xe3: + UsbKeyboardDevice->LeftLogoOn = 1; + continue; + break; case 0xe7: + UsbKeyboardDevice->RightLogoOn = 1; continue; break; + // + // Menu key (App/Apps) press + // + case 0x65: + UsbKeyboardDevice->MenuKeyOn = 1; + continue; + break; + + // + // SysReq press + // + case 0x46: + UsbKeyboardDevice->SysReqOn = 1; + continue; + break; + case 0x53: UsbKeyboardDevice->NumLockOn ^= 1; - // - // Turn on the NumLock light on KB - // + // + // Turn on the NumLock light on KB + // SetKeyLED (UsbKeyboardDevice); continue; break; case 0x39: UsbKeyboardDevice->CapsOn ^= 1; - // - // Turn on the CapsLock light on KB - // + // + // Turn on the CapsLock light on KB + // SetKeyLED (UsbKeyboardDevice); continue; break; case 0x47: UsbKeyboardDevice->ScrollOn ^= 1; - // - // Turn on the ScrollLock light on KB - // + // + // Turn on the ScrollLock light on KB + // SetKeyLED (UsbKeyboardDevice); continue; break; @@ -757,18 +871,14 @@ USBParseKey ( // keys are not valid EFI key // - case 0x46: - // - // fall through // + // PrintScreen/SysRq key and Application key + // Should be handled by UEFI2.1 compliant code + case 0x48: // // fall through // - case 0x65: - // - // fall through - // case 0x66: // // fall through @@ -834,11 +944,26 @@ USBKeyCodeToEFIScanCode ( return EFI_NOT_READY; } + // + // Undefined entries from 0x74 to 0x7E + // + if (KeyChar > USB_KEYCODE_MAX_MAKE) { + Index = (UINT8) (Index - 11); + } + Key->ScanCode = KeyConvertionTable[Index][0]; if (UsbKeyboardDevice->ShiftOn) { Key->UnicodeChar = KeyConvertionTable[Index][2]; + // + // 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 (Key->UnicodeChar >= 'A' && Key->UnicodeChar <= 'Z') { + UsbKeyboardDevice->LeftShiftOn = 0; + UsbKeyboardDevice->RightShiftOn = 0; + } } else { @@ -885,6 +1010,51 @@ USBKeyCodeToEFIScanCode ( return EFI_NOT_READY; } + + // + // Save Shift/Toggle state + // + if (UsbKeyboardDevice->LeftCtrlOn == 1) { + UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_LEFT_CONTROL_PRESSED; + } + if (UsbKeyboardDevice->RightCtrlOn == 1) { + UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED; + } + if (UsbKeyboardDevice->LeftAltOn == 1) { + UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_LEFT_ALT_PRESSED; + } + if (UsbKeyboardDevice->RightAltOn == 1) { + UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_RIGHT_ALT_PRESSED; + } + if (UsbKeyboardDevice->LeftShiftOn == 1) { + UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED; + } + if (UsbKeyboardDevice->RightShiftOn == 1) { + UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED; + } + if (UsbKeyboardDevice->LeftLogoOn == 1) { + UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_LEFT_LOGO_PRESSED; + } + if (UsbKeyboardDevice->RightLogoOn == 1) { + UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_RIGHT_LOGO_PRESSED; + } + if (UsbKeyboardDevice->MenuKeyOn == 1) { + UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_MENU_KEY_PRESSED; + } + if (UsbKeyboardDevice->SysReqOn == 1) { + UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_SYS_REQ_PRESSED; + } + + if (UsbKeyboardDevice->ScrollOn == 1) { + UsbKeyboardDevice->KeyState.KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE; + } + if (UsbKeyboardDevice->NumLockOn == 1) { + UsbKeyboardDevice->KeyState.KeyToggleState |= EFI_NUM_LOCK_ACTIVE; + } + if (UsbKeyboardDevice->CapsOn == 1) { + UsbKeyboardDevice->KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE; + } + return EFI_SUCCESS; } diff --git a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c index dc391e33bc..93edf82ed6 100644 --- a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c +++ b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c @@ -43,6 +43,21 @@ STATIC TEXT_IN_SPLITTER_PRIVATE_DATA mConIn = { 0, (EFI_SIMPLE_TEXT_INPUT_PROTOCOL **) NULL, 0, + { + ConSplitterTextInResetEx, + ConSplitterTextInReadKeyStrokeEx, + (EFI_EVENT) NULL, + ConSplitterTextInSetState, + ConSplitterTextInRegisterKeyNotify, + ConSplitterTextInUnregisterKeyNotify + }, + 0, + (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL **) NULL, + 0, + { + (struct _LIST_ENTRY *) NULL, + (struct _LIST_ENTRY *) NULL + }, { ConSplitterSimplePointerReset, @@ -367,6 +382,8 @@ Returns: &mConIn.VirtualHandle, &gEfiSimpleTextInProtocolGuid, &mConIn.TextIn, + &gEfiSimpleTextInputExProtocolGuid, + &mConIn.TextInEx, &gEfiSimplePointerProtocolGuid, &mConIn.SimplePointer, &gEfiPrimaryConsoleInDeviceGuid, @@ -514,6 +531,30 @@ Returns: ); ASSERT_EFI_ERROR (Status); + // + // Buffer for Simple Text Input Ex Protocol + // + Status = ConSplitterGrowBuffer ( + sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *), + &ConInPrivate->TextInExListCount, + (VOID **) &ConInPrivate->TextInExList + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + Status = gBS->CreateEvent ( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + ConSplitterTextInWaitForKey, + ConInPrivate, + &ConInPrivate->TextInEx.WaitForKeyEx + ); + ASSERT_EFI_ERROR (Status); + + InitializeListHead (&ConInPrivate->NotifyList); + + ConInPrivate->SimplePointer.Mode = &ConInPrivate->SimplePointerMode; Status = ConSplitterGrowBuffer ( @@ -898,6 +939,7 @@ Returns: { EFI_STATUS Status; EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn; + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx; // // Start ConSplitter on ControllerHandle, and create the virtual @@ -915,6 +957,23 @@ Returns: return Status; } + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleTextInputExProtocolGuid, + (VOID **) &TextInEx, + This->DriverBindingHandle, + mConIn.VirtualHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = ConSplitterTextInExAddDevice (&mConIn, TextInEx); + if (EFI_ERROR (Status)) { + return Status; + } + return ConSplitterTextInAddDevice (&mConIn, TextIn); } @@ -1195,10 +1254,29 @@ Returns: EFI_STATUS Status; EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn; + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx; if (NumberOfChildren == 0) { return EFI_SUCCESS; } + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleTextInputExProtocolGuid, + (VOID **) &TextInEx, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = ConSplitterTextInExDeleteDevice (&mConIn, TextInEx); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = ConSplitterStop ( This, ControllerHandle, @@ -1512,6 +1590,66 @@ Returns: return EFI_NOT_FOUND; } +EFI_STATUS +ConSplitterTextInExAddDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx + ) +{ + EFI_STATUS Status; + + // + // If the TextInEx List is full, enlarge it by calling growbuffer(). + // + if (Private->CurrentNumberOfExConsoles >= Private->TextInExListCount) { + Status = ConSplitterGrowBuffer ( + sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *), + &Private->TextInExListCount, + (VOID **) &Private->TextInExList + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + } + // + // Add the new text-in device data structure into the Text In List. + // + Private->TextInExList[Private->CurrentNumberOfExConsoles] = TextInEx; + Private->CurrentNumberOfExConsoles++; + + // + // Extra CheckEvent added to reduce the double CheckEvent() in UI.c + // + gBS->CheckEvent (TextInEx->WaitForKeyEx); + + return EFI_SUCCESS; +} + +EFI_STATUS +ConSplitterTextInExDeleteDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx + ) +{ + UINTN Index; + // + // Remove the specified text-in device data structure from the Text In List, + // and rearrange the remaining data structures in the Text In List. + // + for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { + if (Private->TextInExList[Index] == TextInEx) { + for (Index = Index; Index < Private->CurrentNumberOfExConsoles - 1; Index++) { + Private->TextInExList[Index] = Private->TextInExList[Index + 1]; + } + + Private->CurrentNumberOfExConsoles--; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + EFI_STATUS ConSplitterSimplePointerAddDevice ( IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, @@ -2760,6 +2898,433 @@ Returns: } } + +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; + +} + +// +// Simple Text Input Ex protocol functions +// + +EFI_STATUS +EFIAPI +ConSplitterTextInResetEx ( + 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; + EFI_STATUS ReturnStatus; + TEXT_IN_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + + Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + Private->KeyEventSignalState = FALSE; + + // + // return the worst status met + // + for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfExConsoles; Index++) { + Status = Private->TextInExList[Index]->Reset ( + Private->TextInExList[Index], + ExtendedVerification + ); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + + return ReturnStatus; + +} + +EFI_STATUS +EFIAPI +ConSplitterTextInReadKeyStrokeEx ( + 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. + +--*/ +{ + TEXT_IN_SPLITTER_PRIVATE_DATA *Private; + EFI_STATUS Status; + UINTN Index; + EFI_KEY_DATA CurrentKeyData; + + + if (KeyData == NULL) { + return EFI_INVALID_PARAMETER; + } + + Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + if (Private->PasswordEnabled) { + // + // If StdIn Locked return not ready + // + return EFI_NOT_READY; + } + + Private->KeyEventSignalState = FALSE; + + KeyData->Key.UnicodeChar = 0; + KeyData->Key.ScanCode = SCAN_NULL; + + // + // if no physical console input device exists, return EFI_NOT_READY; + // if any physical console input device has key input, + // return the key and EFI_SUCCESS. + // + for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { + Status = Private->TextInExList[Index]->ReadKeyStrokeEx ( + Private->TextInExList[Index], + &CurrentKeyData + ); + if (!EFI_ERROR (Status)) { + CopyMem (KeyData, &CurrentKeyData, sizeof (CurrentKeyData)); + return Status; + } + } + + return EFI_NOT_READY; +} + +EFI_STATUS +EFIAPI +ConSplitterTextInSetState ( + 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. + +--*/ +{ + TEXT_IN_SPLITTER_PRIVATE_DATA *Private; + EFI_STATUS Status; + UINTN Index; + + if (KeyToggleState == NULL) { + return EFI_INVALID_PARAMETER; + } + + Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + // + // if no physical console input device exists, return EFI_SUCCESS; + // otherwise return the status of setting state of physical console input device + // + for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { + Status = Private->TextInExList[Index]->SetState ( + Private->TextInExList[Index], + KeyToggleState + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +EFIAPI +ConSplitterTextInRegisterKeyNotify ( + 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. + +--*/ +{ + TEXT_IN_SPLITTER_PRIVATE_DATA *Private; + EFI_STATUS Status; + UINTN Index; + TEXT_IN_EX_SPLITTER_NOTIFY *NewNotify; + LIST_ENTRY *Link; + TEXT_IN_EX_SPLITTER_NOTIFY *CurrentNotify; + + + if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) { + return EFI_INVALID_PARAMETER; + } + + Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + // + // if no physical console input device exists, + // return EFI_SUCCESS directly. + // + if (Private->CurrentNumberOfExConsoles <= 0) { + return EFI_SUCCESS; + } + + // + // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. + // + for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) { + CurrentNotify = CR ( + Link, + TEXT_IN_EX_SPLITTER_NOTIFY, + NotifyEntry, + TEXT_IN_EX_SPLITTER_NOTIFY_SIGNATURE + ); + if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { + if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { + *NotifyHandle = CurrentNotify->NotifyHandle; + return EFI_SUCCESS; + } + } + } + + // + // Allocate resource to save the notification function + // + NewNotify = (TEXT_IN_EX_SPLITTER_NOTIFY *) AllocateZeroPool (sizeof (TEXT_IN_EX_SPLITTER_NOTIFY)); + if (NewNotify == NULL) { + return EFI_OUT_OF_RESOURCES; + } + NewNotify->NotifyHandleList = (EFI_HANDLE *) AllocateZeroPool (sizeof (EFI_HANDLE) * Private->CurrentNumberOfExConsoles); + if (NewNotify->NotifyHandleList == NULL) { + gBS->FreePool (NewNotify); + return EFI_OUT_OF_RESOURCES; + } + NewNotify->Signature = TEXT_IN_EX_SPLITTER_NOTIFY_SIGNATURE; + NewNotify->KeyNotificationFn = KeyNotificationFunction; + CopyMem (&NewNotify->KeyData, KeyData, sizeof (KeyData)); + + // + // Return the wrong status of registering key notify of + // physical console input device if meet problems + // + for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { + Status = Private->TextInExList[Index]->RegisterKeyNotify ( + Private->TextInExList[Index], + KeyData, + KeyNotificationFunction, + &NewNotify->NotifyHandleList[Index] + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (NewNotify->NotifyHandleList); + gBS->FreePool (NewNotify); + return Status; + } + } + + // + // Use gSimpleTextInExNotifyGuid to get a valid EFI_HANDLE + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &NewNotify->NotifyHandle, + &gSimpleTextInExNotifyGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + InsertTailList (&mConIn.NotifyList, &NewNotify->NotifyEntry); + + *NotifyHandle = NewNotify->NotifyHandle; + + return EFI_SUCCESS; + +} + +EFI_STATUS +EFIAPI +ConSplitterTextInUnregisterKeyNotify ( + 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. + +--*/ +{ + TEXT_IN_SPLITTER_PRIVATE_DATA *Private; + EFI_STATUS Status; + UINTN Index; + TEXT_IN_EX_SPLITTER_NOTIFY *CurrentNotify; + LIST_ENTRY *Link; + + 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; + } + + Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + // + // if no physical console input device exists, + // return EFI_SUCCESS directly. + // + if (Private->CurrentNumberOfExConsoles <= 0) { + return EFI_SUCCESS; + } + + for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) { + CurrentNotify = CR (Link, TEXT_IN_EX_SPLITTER_NOTIFY, NotifyEntry, TEXT_IN_EX_SPLITTER_NOTIFY_SIGNATURE); + if (CurrentNotify->NotifyHandle == NotificationHandle) { + for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { + Status = Private->TextInExList[Index]->UnregisterKeyNotify ( + Private->TextInExList[Index], + CurrentNotify->NotifyHandleList[Index] + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + RemoveEntryList (&CurrentNotify->NotifyEntry); + Status = gBS->UninstallMultipleProtocolInterfaces ( + CurrentNotify->NotifyHandle, + &gSimpleTextInExNotifyGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + gBS->FreePool (CurrentNotify->NotifyHandleList); + gBS->FreePool (CurrentNotify); + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; + +} + + + EFI_STATUS EFIAPI ConSplitterSimplePointerReset ( diff --git a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.h b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.h index 2bcf5a29e8..4a71bb6294 100644 --- a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.h +++ b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.h @@ -24,6 +24,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include #include #include #include @@ -53,6 +54,8 @@ extern EFI_DRIVER_BINDING_PROTOCOL gConSplitterStdErrDriverBinding; extern EFI_COMPONENT_NAME_PROTOCOL gConSplitterStdErrComponentName; extern EFI_COMPONENT_NAME2_PROTOCOL gConSplitterStdErrComponentName2; +extern EFI_GUID gSimpleTextInExNotifyGuid; + // These definitions were in the old Hii protocol, but are not in the new UEFI // version. So they are defined locally. #define UNICODE_NARROW_CHAR 0xFFF0 @@ -76,6 +79,16 @@ typedef struct { // #define TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('T', 'i', 'S', 'p') +#define TEXT_IN_EX_SPLITTER_NOTIFY_SIGNATURE EFI_SIGNATURE_32 ('T', 'i', 'S', 'n') + +typedef struct _TEXT_IN_EX_SPLITTER_NOTIFY { + UINTN Signature; + EFI_HANDLE *NotifyHandleList; + EFI_HANDLE NotifyHandle; + EFI_KEY_DATA KeyData; + EFI_KEY_NOTIFY_FUNCTION KeyNotificationFn; + LIST_ENTRY NotifyEntry; +} TEXT_IN_EX_SPLITTER_NOTIFY; typedef struct { UINT64 Signature; EFI_HANDLE VirtualHandle; @@ -85,6 +98,13 @@ typedef struct { EFI_SIMPLE_TEXT_INPUT_PROTOCOL **TextInList; UINTN TextInListCount; + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL TextInEx; + UINTN CurrentNumberOfExConsoles; + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL **TextInExList; + UINTN TextInExListCount; + LIST_ENTRY NotifyList; + + EFI_SIMPLE_POINTER_PROTOCOL SimplePointer; EFI_SIMPLE_POINTER_MODE SimplePointerMode; UINTN CurrentNumberOfPointers; @@ -114,6 +134,19 @@ typedef struct { SimplePointer, \ TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE \ ) +#define TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS(a) \ + CR (a, \ + TEXT_IN_SPLITTER_PRIVATE_DATA, \ + TextInEx, \ + TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE \ + ) + +#define TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_ABSOLUTE_POINTER_THIS(a) \ + CR (a, \ + TEXT_IN_SPLITTER_PRIVATE_DATA, \ + AbsolutePointer, \ + TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE \ + ) // // Private data for the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL splitter @@ -770,7 +803,151 @@ ConSplitterTextInReadKeyStroke ( OUT EFI_INPUT_KEY *Key ) ; +EFI_STATUS +ConSplitterTextInExAddDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx + ) +; +EFI_STATUS +ConSplitterTextInExDeleteDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx + ) +; + +// +// Simple Text Input Ex protocol function prototypes +// + +EFI_STATUS +EFIAPI +ConSplitterTextInResetEx ( + 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 +ConSplitterTextInReadKeyStrokeEx ( + 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 +ConSplitterTextInSetState ( + 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 +ConSplitterTextInRegisterKeyNotify ( + 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 +ConSplitterTextInUnregisterKeyNotify ( + 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. + +--*/ +; VOID EFIAPI ConSplitterTextInWaitForKey ( @@ -945,10 +1122,10 @@ ConSpliterConsoleControlSetMode ( EFI_STATUS EFIAPI ConSpliterGraphicsOutputQueryMode ( - IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, - IN UINT32 ModeNumber, - OUT UINTN *SizeOfInfo, - OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber, + OUT UINTN *SizeOfInfo, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info ) ; diff --git a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf index c7e4079e89..9a781a5a65 100644 --- a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf +++ b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf @@ -67,11 +67,13 @@ gEfiPrimaryConsoleOutDeviceGuid # ALWAYS_PRODUCED gEfiPrimaryConsoleInDeviceGuid # ALWAYS_PRODUCED gEfiPrimaryStandardErrorDeviceGuid # ALWAYS_PRODUCED + gSimpleTextInExNotifyGuid # ALWAYS_PRODUCED [Protocols] gEfiConsoleControlProtocolGuid # PROTOCOL ALWAYS_PRODUCED gEfiSimplePointerProtocolGuid # PROTOCOL ALWAYS_PRODUCED gEfiSimpleTextInProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiSimpleTextInputExProtocolGuid # PROTOCOL ALWAYS_PRODUCED gEfiSimpleTextOutProtocolGuid # PROTOCOL ALWAYS_PRODUCED gEfiGraphicsOutputProtocolGuid # PROTOCOL ALWAYS_PRODUCED gEfiUgaDrawProtocolGuid # PROTOCOL ALWAYS_PRODUCED diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c index 4e2f650964..aaeca12100 100644 --- a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c +++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c @@ -22,6 +22,12 @@ Revision History: #include "Terminal.h" +STATIC +EFI_STATUS +TerminalFreeNotifyList ( + IN OUT LIST_ENTRY *ListHead + ); + // // Globals // @@ -94,7 +100,19 @@ TERMINAL_DEV gTerminalDevTemplate = { NULL, INPUT_STATE_DEFAULT, RESET_STATE_DEFAULT, - FALSE + FALSE, + { // SimpleTextInputEx + TerminalConInResetEx, + TerminalConInReadKeyStrokeEx, + NULL, + TerminalConInSetState, + TerminalConInRegisterKeyNotify, + TerminalConInUnregisterKeyNotify, + }, + { + NULL, + NULL, + } }; @@ -381,6 +399,19 @@ TerminalDriverBindingStart ( TerminalDevice->TerminalType = TerminalType; TerminalDevice->SerialIo = SerialIo; + InitializeListHead (&TerminalDevice->NotifyList); + Status = gBS->CreateEvent ( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + TerminalConInWaitForKeyEx, + &TerminalDevice->SimpleInputEx, + &TerminalDevice->SimpleInputEx.WaitForKeyEx + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + Status = gBS->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY, @@ -391,7 +422,6 @@ TerminalDriverBindingStart ( if (EFI_ERROR (Status)) { goto Error; } - // // initialize the FIFO buffer used for accommodating // the pre-read pending characters @@ -405,6 +435,7 @@ TerminalDriverBindingStart ( // keystroke response performance issue // Mode = TerminalDevice->SerialIo->Mode; + SerialInTimeOut = 0; if (Mode->BaudRate != 0) { SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate; @@ -578,6 +609,8 @@ TerminalDriverBindingStart ( TerminalDevice->DevicePath, &gEfiSimpleTextInProtocolGuid, &TerminalDevice->SimpleInput, + &gEfiSimpleTextInputExProtocolGuid, + &TerminalDevice->SimpleInputEx, &gEfiSimpleTextOutProtocolGuid, &TerminalDevice->SimpleTextOutput, NULL @@ -655,6 +688,12 @@ Error: gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey); } + if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) { + gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx); + } + + TerminalFreeNotifyList (&TerminalDevice->NotifyList); + if (TerminalDevice->ControllerNameTable != NULL) { FreeUnicodeStringTable (TerminalDevice->ControllerNameTable); } @@ -809,6 +848,8 @@ TerminalDriverBindingStop ( ChildHandleBuffer[Index], &gEfiSimpleTextInProtocolGuid, &TerminalDevice->SimpleInput, + &gEfiSimpleTextInputExProtocolGuid, + &TerminalDevice->SimpleInputEx, &gEfiSimpleTextOutProtocolGuid, &TerminalDevice->SimpleTextOutput, &gEfiDevicePathProtocolGuid, @@ -851,6 +892,8 @@ TerminalDriverBindingStop ( gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut); gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey); + gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx); + TerminalFreeNotifyList (&TerminalDevice->NotifyList); FreePool (TerminalDevice->DevicePath); FreePool (TerminalDevice); } @@ -868,6 +911,47 @@ TerminalDriverBindingStop ( return EFI_SUCCESS; } +STATIC +EFI_STATUS +TerminalFreeNotifyList ( + 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. + +--*/ +{ + TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode; + + if (ListHead == NULL) { + return EFI_INVALID_PARAMETER; + } + while (!IsListEmpty (ListHead)) { + NotifyNode = CR ( + ListHead->ForwardLink, + TERMINAL_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + RemoveEntryList (ListHead->ForwardLink); + gBS->FreePool (NotifyNode); + } + + return EFI_SUCCESS; +} + + + VOID TerminalUpdateConsoleDevVariable ( IN CHAR16 *VariableName, diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h index 0ae1c431f3..b352c66991 100644 --- a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h +++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h @@ -30,6 +30,7 @@ Revision History #include #include #include +#include #include #include #include @@ -42,7 +43,7 @@ Revision History #include #include #include - +#include #define RAW_FIFO_MAX_NUMBER 256 @@ -68,6 +69,15 @@ typedef struct { #define TERMINAL_DEV_SIGNATURE EFI_SIGNATURE_32 ('t', 'm', 'n', 'l') +#define TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE EFI_SIGNATURE_32 ('t', 'm', 'e', 'n') + +typedef struct _TERMINAL_CONSOLE_IN_EX_NOTIFY { + UINTN Signature; + EFI_HANDLE NotifyHandle; + EFI_KEY_DATA KeyData; + EFI_KEY_NOTIFY_FUNCTION KeyNotificationFn; + LIST_ENTRY NotifyEntry; +} TERMINAL_CONSOLE_IN_EX_NOTIFY; typedef struct { UINTN Signature; EFI_HANDLE Handle; @@ -94,6 +104,8 @@ typedef struct { // to indicate whether the Esc could be sent or not. // BOOLEAN OutputEscChar; + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL SimpleInputEx; + LIST_ENTRY NotifyList; } TERMINAL_DEV; #define INPUT_STATE_DEFAULT 0x00 @@ -109,6 +121,7 @@ typedef struct { #define TERMINAL_CON_IN_DEV_FROM_THIS(a) CR (a, TERMINAL_DEV, SimpleInput, TERMINAL_DEV_SIGNATURE) #define TERMINAL_CON_OUT_DEV_FROM_THIS(a) CR (a, TERMINAL_DEV, SimpleTextOutput, TERMINAL_DEV_SIGNATURE) +#define TERMINAL_CON_IN_EX_DEV_FROM_THIS(a) CR (a, TERMINAL_DEV, SimpleInputEx, TERMINAL_DEV_SIGNATURE) typedef union { UINT8 Utf8_1; @@ -153,6 +166,7 @@ extern EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding; extern EFI_COMPONENT_NAME_PROTOCOL gTerminalComponentName; extern EFI_COMPONENT_NAME2_PROTOCOL gTerminalComponentName2; +extern EFI_GUID gSimpleTextInExNotifyGuid; // // Prototypes // @@ -180,6 +194,169 @@ TerminalConInReadKeyStroke ( ) ; + +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. + +--*/ +; + +VOID +EFIAPI +TerminalConInWaitForKeyEx ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; +// +// Simple Text Input Ex protocol prototypes +// + +EFI_STATUS +EFIAPI +TerminalConInResetEx ( + 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 +TerminalConInReadKeyStrokeEx ( + 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 +TerminalConInSetState ( + 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 +TerminalConInRegisterKeyNotify ( + 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 +TerminalConInUnregisterKeyNotify ( + 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. + +--*/ +; + VOID EFIAPI TerminalConInWaitForKey ( diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c index 2d76e38c33..4b3eb37023 100644 --- a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c +++ b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c @@ -1,6 +1,6 @@ /**@file - Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol. - + Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol. + Copyright (c) 2006 - 2007 Intel Corporation.
All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -15,6 +15,78 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "Terminal.h" +STATIC +EFI_STATUS +ReadKeyStrokeWorker ( + IN TERMINAL_DEV *TerminalDevice, + 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: + TerminalDevice - Terminal driver 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; + LIST_ENTRY *Link; + TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + + if (KeyData == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Initialize *Key to nonsense value. + // + KeyData->Key.ScanCode = SCAN_NULL; + KeyData->Key.UnicodeChar = 0; + + Status = TerminalConInCheckForKey (&TerminalDevice->SimpleInput); + if (EFI_ERROR (Status)) { + return EFI_NOT_READY; + } + + if (!EfiKeyFiFoRemoveOneKey (TerminalDevice, &KeyData->Key)) { + return EFI_NOT_READY; + } + + KeyData->KeyState.KeyShiftState = 0; + KeyData->KeyState.KeyToggleState = 0; + + // + // Invoke notification functions if exist + // + for (Link = TerminalDevice->NotifyList.ForwardLink; Link != &TerminalDevice->NotifyList; Link = Link->ForwardLink) { + CurrentNotify = CR ( + Link, + TERMINAL_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { + CurrentNotify->KeyNotificationFn (KeyData); + } + } + + return EFI_SUCCESS; + +} + + EFI_STATUS EFIAPI TerminalConInReset ( @@ -111,28 +183,358 @@ TerminalConInReadKeyStroke ( { TERMINAL_DEV *TerminalDevice; EFI_STATUS Status; + EFI_KEY_DATA KeyData; - // - // Initialize *Key to nonsense value. - // - Key->ScanCode = SCAN_NULL; - Key->UnicodeChar = 0; // // get TERMINAL_DEV from "This" parameter. // TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This); - Status = TerminalConInCheckForKey (This); + Status = ReadKeyStrokeWorker (TerminalDevice, &KeyData); if (EFI_ERROR (Status)) { - return EFI_NOT_READY; + return Status; } - EfiKeyFiFoRemoveOneKey (TerminalDevice, Key); + CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY)); return EFI_SUCCESS; } + +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; + } + + return TRUE; +} + + +VOID +EFIAPI +TerminalConInWaitForKeyEx ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + Routine Description: + + Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event + Signal the event if there is key available + + Arguments: + + Event - Indicates the event that invoke this function. + + Context - Indicates the calling context. + + Returns: + + N/A + +--*/ +{ + TERMINAL_DEV *TerminalDevice; + + TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (Context); + + TerminalConInWaitForKey (Event, &TerminalDevice->SimpleInput); + +} + +// +// Simple Text Input Ex protocol functions +// + +EFI_STATUS +EFIAPI +TerminalConInResetEx ( + 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; + TERMINAL_DEV *TerminalDevice; + + TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); + + Status = TerminalDevice->SimpleInput.Reset (&TerminalDevice->SimpleInput, ExtendedVerification); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +EFIAPI +TerminalConInReadKeyStrokeEx ( + 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. + +--*/ +{ + TERMINAL_DEV *TerminalDevice; + + if (KeyData == NULL) { + return EFI_INVALID_PARAMETER; + } + + TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); + + return ReadKeyStrokeWorker (TerminalDevice, KeyData); + +} + +EFI_STATUS +EFIAPI +TerminalConInSetState ( + 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. + +--*/ +{ + if (KeyToggleState == NULL) { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +TerminalConInRegisterKeyNotify ( + 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; + TERMINAL_DEV *TerminalDevice; + TERMINAL_CONSOLE_IN_EX_NOTIFY *NewNotify; + LIST_ENTRY *Link; + TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + + if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) { + return EFI_INVALID_PARAMETER; + } + + TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); + + // + // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. + // + for (Link = TerminalDevice->NotifyList.ForwardLink; Link != &TerminalDevice->NotifyList; Link = Link->ForwardLink) { + CurrentNotify = CR ( + Link, + TERMINAL_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { + if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { + *NotifyHandle = CurrentNotify->NotifyHandle; + return EFI_SUCCESS; + } + } + } + + // + // Allocate resource to save the notification function + // + NewNotify = (TERMINAL_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (TERMINAL_CONSOLE_IN_EX_NOTIFY)); + if (NewNotify == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + NewNotify->Signature = TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE; + NewNotify->KeyNotificationFn = KeyNotificationFunction; + CopyMem (&NewNotify->KeyData, KeyData, sizeof (KeyData)); + InsertTailList (&TerminalDevice->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; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +TerminalConInUnregisterKeyNotify ( + 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; + TERMINAL_DEV *TerminalDevice; + LIST_ENTRY *Link; + TERMINAL_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; + } + + TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This); + + for (Link = TerminalDevice->NotifyList.ForwardLink; Link != &TerminalDevice->NotifyList; Link = Link->ForwardLink) { + CurrentNotify = CR ( + Link, + TERMINAL_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + TERMINAL_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); + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + + VOID TranslateRawDataToEfiKey ( IN TERMINAL_DEV *TerminalDevice @@ -787,7 +1189,9 @@ Symbols used in table below | F9 | 0x13 | ESC [ U | ESC 9 | ESC O p | | F10 | 0x14 | ESC [ V | ESC 0 | ESC O M | | Escape | 0x17 | ESC | ESC | ESC | -+=========+======+===========+==========+=========+ +| F11 | 0x15 | | ESC ! | | +| F12 | 0x16 | | ESC @ | | ++=========+======+===========+==========+==========+ Special Mappings ================ @@ -882,6 +1286,12 @@ ESC R ESC r ESC R = Reset System case '0': Key.ScanCode = SCAN_F10; break; + case '!': + Key.ScanCode = SCAN_F11; + break; + case '@': + Key.ScanCode = SCAN_F12; + break; case 'h': Key.ScanCode = SCAN_HOME; break; @@ -1150,6 +1560,10 @@ ESC R ESC r ESC R = Reset System if (UnicodeChar == ESC) { TerminalDevice->InputState = INPUT_STATE_ESC; } + + if (UnicodeChar == CSI) { + TerminalDevice->InputState = INPUT_STATE_CSI; + } if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) { Status = gBS->SetTimer( diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf index 2e279f2a39..78446862e8 100644 --- a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf +++ b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf @@ -58,6 +58,7 @@ UefiDriverEntryPoint DebugLib PcdLib + BaseLib [Guids] gEfiGlobalVariableGuid # SOMETIMES_CONSUMED L"ErrOutDev" @@ -65,13 +66,14 @@ gEfiVT100Guid # SOMETIMES_CONSUMED gEfiVT100PlusGuid # SOMETIMES_CONSUMED gEfiPcAnsiGuid # SOMETIMES_CONSUMED - + gSimpleTextInExNotifyGuid # SOMETIMES_CONSUMED [Protocols] gEfiHotPlugDeviceGuid # PROTOCOL SOMETIMES_CONSUMED gEfiSerialIoProtocolGuid # PROTOCOL TO_START gEfiDevicePathProtocolGuid # PROTOCOL TO_START gEfiSimpleTextInProtocolGuid # PROTOCOL BY_START + gEfiSimpleTextInputExProtocolGuid # PROTOCOL BY_START gEfiSimpleTextOutProtocolGuid # PROTOCOL BY_START [Pcd]