/** Register a notification function for a particular keystroke for the input device. @param This Protocol instance pointer. @param KeyData A pointer to a buffer that is filled in with the keystroke information data for the key that was pressed. @param KeyNotificationFunction Points to the function to be called when the key sequence is typed specified by KeyData. @param NotifyHandle Points to the unique handle assigned to the registered notification. @retval EFI_SUCCESS The notification function was registered successfully. @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data structures. @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle 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 ) { TERMINAL_DEV *TerminalDevice; TERMINAL_CONSOLE_IN_EX_NOTIFY *NewNotify; LIST_ENTRY *Link; LIST_ENTRY *NotifyList; 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. // NotifyList = &TerminalDevice->NotifyList; for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) { 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; NewNotify->NotifyHandle = (EFI_HANDLE) NewNotify; CopyMem (&NewNotify->KeyData, KeyData, sizeof (KeyData)); InsertTailList (&TerminalDevice->NotifyList, &NewNotify->NotifyEntry); *NotifyHandle = NewNotify->NotifyHandle; return EFI_SUCCESS; }
/** Reads the next keystroke from the input device. The WaitForKey Event can be used to test for existence of a keystroke via WaitForEvent () call. @param TerminalDevice Terminal driver private structure @param KeyData A pointer to a buffer that is filled in with the keystroke state data for the key that was pressed. @retval EFI_SUCCESS The keystroke information was returned. @retval EFI_NOT_READY There was no keystroke data available. @retval EFI_DEVICE_ERROR The keystroke information was not returned due to hardware errors. @retval EFI_INVALID_PARAMETER KeyData is NULL. **/ EFI_STATUS ReadKeyStrokeWorker ( IN TERMINAL_DEV *TerminalDevice, OUT EFI_KEY_DATA *KeyData ) { EFI_STATUS Status; LIST_ENTRY *Link; LIST_ENTRY *NotifyList; 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 // NotifyList = &TerminalDevice->NotifyList; for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) { 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; }
/** 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; VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; EFI_KEY_DATA KeyData; LIST_ENTRY *Link; LIST_ENTRY *NotifyList; VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; EFI_TPL OldTpl; VirtualKeyboardPrivate = (VIRTUAL_KEYBOARD_DEV *) Context; // // Invoke notification functions. // NotifyList = &VirtualKeyboardPrivate->NotifyList; while (TRUE) { // // Enter critical section // OldTpl = gBS->RaiseTPL (TPL_NOTIFY); Status = Dequeue (&VirtualKeyboardPrivate->QueueForNotify, &KeyData); // // Leave critical section // gBS->RestoreTPL (OldTpl); if (EFI_ERROR (Status)) { break; } for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) { CurrentNotify = CR (Link, VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE ); if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { CurrentNotify->KeyNotificationFn (&KeyData); } } } }
/** Insert one pre-fetched key into the FIFO buffer. @param TerminalDevice Terminal driver private structure. @param Key The key will be input. @retval TRUE If insert successfully. @retval FLASE If FIFO buffer is full before key insertion, and the key is lost. **/ BOOLEAN EfiKeyFiFoInsertOneKey ( TERMINAL_DEV *TerminalDevice, EFI_INPUT_KEY *Key ) { UINT8 Tail; LIST_ENTRY *Link; LIST_ENTRY *NotifyList; TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify; EFI_KEY_DATA KeyData; Tail = TerminalDevice->EfiKeyFiFo->Tail; CopyMem (&KeyData.Key, Key, sizeof (EFI_INPUT_KEY)); KeyData.KeyState.KeyShiftState = 0; KeyData.KeyState.KeyToggleState = 0; // // Invoke notification functions if exist // NotifyList = &TerminalDevice->NotifyList; for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) { CurrentNotify = CR ( Link, TERMINAL_CONSOLE_IN_EX_NOTIFY, NotifyEntry, TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE ); if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { CurrentNotify->KeyNotificationFn (&KeyData); } } if (IsEfiKeyFiFoFull (TerminalDevice)) { // // Efi Key FIFO is full // return FALSE; } CopyMem (&TerminalDevice->EfiKeyFiFo->Data[Tail], Key, sizeof (EFI_INPUT_KEY)); TerminalDevice->EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1)); return TRUE; }
/** Register a notification function for a particular keystroke for the input device. @param This Protocol instance pointer. @param KeyData A pointer to a buffer that is filled in with the keystroke information data for the key that was pressed. @param KeyNotificationFunction Points to the function to be called when the key sequence is typed specified by KeyData. @param NotifyHandle Points to the unique handle assigned to the registered notification. @retval EFI_SUCCESS The notification function was registered successfully. @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures. @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle or KeyNotificationFunction 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 ) { 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; NewNotify->NotifyHandle = (EFI_HANDLE) NewNotify; CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA)); InsertTailList (&ConsoleInDev->NotifyList, &NewNotify->NotifyEntry); *NotifyHandle = NewNotify->NotifyHandle; Status = EFI_SUCCESS; Exit: // // Leave critical section and return // gBS->RestoreTPL (OldTpl); return Status; }
/** Reads the next keystroke from the input device. The WaitForKey Event can be used to test for existance of a keystroke via WaitForEvent () call. @param ConsoleInDev Ps2 Keyboard private structure @param KeyData A pointer to a buffer that is filled in with the keystroke state data for the key that was pressed. @retval EFI_SUCCESS The keystroke information was returned. @retval EFI_NOT_READY There was no keystroke data availiable. @retval EFI_DEVICE_ERROR The keystroke information was not returned due to hardware errors. @retval EFI_INVALID_PARAMETER KeyData is NULL. **/ EFI_STATUS KeyboardReadKeyStrokeWorker ( IN KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev, OUT EFI_KEY_DATA *KeyData ) { 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 + L'A' - 1); } else { OriginalKeyData.Key.UnicodeChar = (CHAR16)(OriginalKeyData.Key.UnicodeChar + L'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; }
/** Timer event handler: read a series of scancodes from 8042 and put them into memory scancode buffer. it read as much scancodes to either fill the memory buffer or empty the keyboard buffer. It is registered as running under TPL_NOTIFY @param Event The timer event @param Context A KEYBOARD_CONSOLE_IN_DEV pointer **/ VOID EFIAPI VirtualKeyboardTimerHandler ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_TPL OldTpl; LIST_ENTRY *Link; EFI_KEY_DATA KeyData; VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; VIRTUAL_KBD_KEY VirtualKey; VirtualKeyboardPrivate = Context; // // Enter critical section // OldTpl = gBS->RaiseTPL (TPL_NOTIFY); if (VirtualKeyboardPrivate->PlatformVirtual && VirtualKeyboardPrivate->PlatformVirtual->Query) { if (VirtualKeyboardPrivate->PlatformVirtual->Query (&VirtualKey) == FALSE) { goto Exit; } // Found key KeyData.Key.ScanCode = VirtualKey.Key.ScanCode; KeyData.Key.UnicodeChar = VirtualKey.Key.UnicodeChar; KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID; KeyData.KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID; if (VirtualKeyboardPrivate->PlatformVirtual->Clear) { VirtualKeyboardPrivate->PlatformVirtual->Clear (&VirtualKey); } } else { goto Exit; } // // Signal KeyNotify process event if this key pressed matches any key registered. // for (Link = VirtualKeyboardPrivate->NotifyList.ForwardLink; Link != &VirtualKeyboardPrivate->NotifyList; Link = Link->ForwardLink) { CurrentNotify = CR ( Link, VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE ); if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { // // The key notification function needs to run at TPL_CALLBACK // while current TPL is TPL_NOTIFY. It will be invoked in // KeyNotifyProcessHandler() which runs at TPL_CALLBACK. // Enqueue (&VirtualKeyboardPrivate->QueueForNotify, &KeyData); gBS->SignalEvent (VirtualKeyboardPrivate->KeyNotifyProcessEvent); break; } } Enqueue (&VirtualKeyboardPrivate->Queue, &KeyData); Exit: // // Leave critical section and return // gBS->RestoreTPL (OldTpl); }