4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2018, Linaro Ltd. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "VirtualKeyboard.h"
14 // RAM Keyboard Driver Binding Protocol Instance
16 EFI_DRIVER_BINDING_PROTOCOL gVirtualKeyboardDriverBinding
= {
17 VirtualKeyboardDriverBindingSupported
,
18 VirtualKeyboardDriverBindingStart
,
19 VirtualKeyboardDriverBindingStop
,
26 // EFI Driver Binding Protocol Functions
30 Check whether the driver supports this device.
32 @param This The Udriver binding protocol.
33 @param Controller The controller handle to check.
34 @param RemainingDevicePath The remaining device path.
36 @retval EFI_SUCCESS The driver supports this controller.
37 @retval other This device isn't supported.
42 VirtualKeyboardDriverBindingSupported (
43 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
44 IN EFI_HANDLE Controller
,
45 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
49 PLATFORM_VIRTUAL_KBD_PROTOCOL
*PlatformVirtual
;
51 Status
= gBS
->OpenProtocol (
53 &gPlatformVirtualKeyboardProtocolGuid
,
54 (VOID
**) &PlatformVirtual
,
55 This
->DriverBindingHandle
,
57 EFI_OPEN_PROTOCOL_BY_DRIVER
59 if (EFI_ERROR (Status
)) {
64 &gPlatformVirtualKeyboardProtocolGuid
,
65 This
->DriverBindingHandle
,
72 Starts the device with this driver.
74 @param This The driver binding instance.
75 @param Controller Handle of device to bind driver to.
76 @param RemainingDevicePath Optional parameter use to pick a specific child
79 @retval EFI_SUCCESS The controller is controlled by the driver.
80 @retval Other This controller cannot be started.
85 VirtualKeyboardDriverBindingStart (
86 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
87 IN EFI_HANDLE Controller
,
88 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
92 VIRTUAL_KEYBOARD_DEV
*VirtualKeyboardPrivate
;
93 PLATFORM_VIRTUAL_KBD_PROTOCOL
*PlatformVirtual
;
95 Status
= gBS
->OpenProtocol (
97 &gPlatformVirtualKeyboardProtocolGuid
,
98 (VOID
**) &PlatformVirtual
,
99 This
->DriverBindingHandle
,
101 EFI_OPEN_PROTOCOL_BY_DRIVER
103 if (EFI_ERROR (Status
)) {
108 // Allocate the private device structure
110 VirtualKeyboardPrivate
= (VIRTUAL_KEYBOARD_DEV
*) AllocateZeroPool (sizeof (VIRTUAL_KEYBOARD_DEV
));
111 if (VirtualKeyboardPrivate
== NULL
) {
112 Status
= EFI_OUT_OF_RESOURCES
;
117 // Initialize the private device structure
119 VirtualKeyboardPrivate
->Signature
= VIRTUAL_KEYBOARD_DEV_SIGNATURE
;
120 VirtualKeyboardPrivate
->Handle
= Controller
;
121 VirtualKeyboardPrivate
->PlatformVirtual
= PlatformVirtual
;
122 VirtualKeyboardPrivate
->Queue
.Front
= 0;
123 VirtualKeyboardPrivate
->Queue
.Rear
= 0;
124 VirtualKeyboardPrivate
->QueueForNotify
.Front
= 0;
125 VirtualKeyboardPrivate
->QueueForNotify
.Rear
= 0;
127 VirtualKeyboardPrivate
->SimpleTextIn
.Reset
= VirtualKeyboardReset
;
128 VirtualKeyboardPrivate
->SimpleTextIn
.ReadKeyStroke
= VirtualKeyboardReadKeyStroke
;
130 VirtualKeyboardPrivate
->SimpleTextInputEx
.Reset
= VirtualKeyboardResetEx
;
131 VirtualKeyboardPrivate
->SimpleTextInputEx
.ReadKeyStrokeEx
= VirtualKeyboardReadKeyStrokeEx
;
132 VirtualKeyboardPrivate
->SimpleTextInputEx
.SetState
= VirtualKeyboardSetState
;
134 VirtualKeyboardPrivate
->SimpleTextInputEx
.RegisterKeyNotify
= VirtualKeyboardRegisterKeyNotify
;
135 VirtualKeyboardPrivate
->SimpleTextInputEx
.UnregisterKeyNotify
= VirtualKeyboardUnregisterKeyNotify
;
136 InitializeListHead (&VirtualKeyboardPrivate
->NotifyList
);
138 Status
= PlatformVirtual
->Register ();
139 if (EFI_ERROR (Status
)) {
144 // Report that the keyboard is being enabled
148 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_ENABLE
152 // Setup the WaitForKey event
154 Status
= gBS
->CreateEvent (
157 VirtualKeyboardWaitForKey
,
158 &(VirtualKeyboardPrivate
->SimpleTextIn
),
159 &((VirtualKeyboardPrivate
->SimpleTextIn
).WaitForKey
)
161 if (EFI_ERROR (Status
)) {
162 (VirtualKeyboardPrivate
->SimpleTextIn
).WaitForKey
= NULL
;
165 Status
= gBS
->CreateEvent (
168 VirtualKeyboardWaitForKeyEx
,
169 &(VirtualKeyboardPrivate
->SimpleTextInputEx
),
170 &(VirtualKeyboardPrivate
->SimpleTextInputEx
.WaitForKeyEx
)
172 if (EFI_ERROR (Status
)) {
173 VirtualKeyboardPrivate
->SimpleTextInputEx
.WaitForKeyEx
= NULL
;
178 // Setup a periodic timer, used for reading keystrokes at a fixed interval
180 Status
= gBS
->CreateEvent (
181 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
183 VirtualKeyboardTimerHandler
,
184 VirtualKeyboardPrivate
,
185 &VirtualKeyboardPrivate
->TimerEvent
187 if (EFI_ERROR (Status
)) {
188 Status
= EFI_OUT_OF_RESOURCES
;
192 Status
= gBS
->SetTimer (
193 VirtualKeyboardPrivate
->TimerEvent
,
195 KEYBOARD_TIMER_INTERVAL
197 if (EFI_ERROR (Status
)) {
198 Status
= EFI_OUT_OF_RESOURCES
;
202 Status
= gBS
->CreateEvent (
205 KeyNotifyProcessHandler
,
206 VirtualKeyboardPrivate
,
207 &VirtualKeyboardPrivate
->KeyNotifyProcessEvent
209 if (EFI_ERROR (Status
)) {
210 Status
= EFI_OUT_OF_RESOURCES
;
215 // Reset the keyboard device
217 Status
= VirtualKeyboardPrivate
->SimpleTextInputEx
.Reset (
218 &VirtualKeyboardPrivate
->SimpleTextInputEx
,
221 if (EFI_ERROR (Status
)) {
222 DEBUG ((DEBUG_ERROR
, "[KBD]Reset Failed. Status - %r\n", Status
));
226 // Install protocol interfaces for the keyboard device.
228 Status
= gBS
->InstallMultipleProtocolInterfaces (
230 &gEfiSimpleTextInProtocolGuid
,
231 &VirtualKeyboardPrivate
->SimpleTextIn
,
232 &gEfiSimpleTextInputExProtocolGuid
,
233 &VirtualKeyboardPrivate
->SimpleTextInputEx
,
238 if (EFI_ERROR (Status
)) {
239 if (VirtualKeyboardPrivate
!= NULL
) {
240 if ((VirtualKeyboardPrivate
->SimpleTextIn
).WaitForKey
!= NULL
) {
241 gBS
->CloseEvent ((VirtualKeyboardPrivate
->SimpleTextIn
).WaitForKey
);
244 if ((VirtualKeyboardPrivate
->SimpleTextInputEx
).WaitForKeyEx
!= NULL
) {
246 (VirtualKeyboardPrivate
->SimpleTextInputEx
).WaitForKeyEx
250 if (VirtualKeyboardPrivate
->KeyNotifyProcessEvent
!= NULL
) {
251 gBS
->CloseEvent (VirtualKeyboardPrivate
->KeyNotifyProcessEvent
);
254 VirtualKeyboardFreeNotifyList (&VirtualKeyboardPrivate
->NotifyList
);
256 if (VirtualKeyboardPrivate
->TimerEvent
!= NULL
) {
257 gBS
->CloseEvent (VirtualKeyboardPrivate
->TimerEvent
);
259 FreePool (VirtualKeyboardPrivate
);
265 &gPlatformVirtualKeyboardProtocolGuid
,
266 This
->DriverBindingHandle
,
274 Stop the device handled by this driver.
276 @param This The driver binding protocol.
277 @param Controller The controller to release.
278 @param NumberOfChildren The number of handles in ChildHandleBuffer.
279 @param ChildHandleBuffer The array of child handle.
281 @retval EFI_SUCCESS The device was stopped.
282 @retval EFI_DEVICE_ERROR The device could not be stopped due to a
284 @retval Others Fail to uninstall protocols attached on the
290 VirtualKeyboardDriverBindingStop (
291 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
292 IN EFI_HANDLE Controller
,
293 IN UINTN NumberOfChildren
,
294 IN EFI_HANDLE
*ChildHandleBuffer
304 @param Queue The queue to be enqueued.
305 @param KeyData The key data to be enqueued.
307 @retval EFI_NOT_READY The queue is full.
308 @retval EFI_SUCCESS Successfully enqueued the key data.
313 IN SIMPLE_QUEUE
*Queue
,
314 IN EFI_KEY_DATA
*KeyData
317 if ((Queue
->Rear
+ 1) % QUEUE_MAX_COUNT
== Queue
->Front
) {
318 return EFI_NOT_READY
;
321 CopyMem (&Queue
->Buffer
[Queue
->Rear
], KeyData
, sizeof (EFI_KEY_DATA
));
322 Queue
->Rear
= (Queue
->Rear
+ 1) % QUEUE_MAX_COUNT
;
330 @param Queue The queue to be dequeued.
331 @param KeyData The key data to be dequeued.
333 @retval EFI_NOT_READY The queue is empty.
334 @retval EFI_SUCCESS Successfully dequeued the key data.
339 IN SIMPLE_QUEUE
*Queue
,
340 IN EFI_KEY_DATA
*KeyData
343 if (Queue
->Front
== Queue
->Rear
) {
344 return EFI_NOT_READY
;
347 CopyMem (KeyData
, &Queue
->Buffer
[Queue
->Front
], sizeof (EFI_KEY_DATA
));
348 Queue
->Front
= (Queue
->Front
+ 1) % QUEUE_MAX_COUNT
;
354 Check whether the queue is empty.
356 @param Queue The queue to be checked.
358 @retval EFI_NOT_READY The queue is empty.
359 @retval EFI_SUCCESS The queue is not empty.
364 IN SIMPLE_QUEUE
*Queue
367 if (Queue
->Front
== Queue
->Rear
) {
368 return EFI_NOT_READY
;
375 Check key buffer to get the key stroke status.
377 @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.
379 @retval EFI_SUCCESS A key is being pressed now.
380 @retval Other No key is now pressed.
385 VirtualKeyboardCheckForKey (
386 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
389 VIRTUAL_KEYBOARD_DEV
*VirtualKeyboardPrivate
;
391 VirtualKeyboardPrivate
= VIRTUAL_KEYBOARD_DEV_FROM_THIS (This
);
393 return CheckQueue (&VirtualKeyboardPrivate
->Queue
);
397 Free keyboard notify list.
399 @param ListHead The list head
401 @retval EFI_SUCCESS Free the notify list successfully
402 @retval EFI_INVALID_PARAMETER ListHead is invalid.
406 VirtualKeyboardFreeNotifyList (
407 IN OUT LIST_ENTRY
*ListHead
410 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NotifyNode
;
412 if (ListHead
== NULL
) {
413 return EFI_INVALID_PARAMETER
;
415 while (!IsListEmpty (ListHead
)) {
417 ListHead
->ForwardLink
,
418 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
420 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
422 RemoveEntryList (ListHead
->ForwardLink
);
423 gBS
->FreePool (NotifyNode
);
430 Judge whether is a registed key
432 @param RegsiteredData A pointer to a buffer that is filled in with
433 the keystroke state data for the key that was
435 @param InputData A pointer to a buffer that is filled in with
436 the keystroke state data for the key that was
439 @retval TRUE Key be pressed matches a registered key.
440 @retval FLASE Match failed.
445 IN EFI_KEY_DATA
*RegsiteredData
,
446 IN EFI_KEY_DATA
*InputData
450 ASSERT (RegsiteredData
!= NULL
&& InputData
!= NULL
);
452 if ((RegsiteredData
->Key
.ScanCode
!= InputData
->Key
.ScanCode
) ||
453 (RegsiteredData
->Key
.UnicodeChar
!= InputData
->Key
.UnicodeChar
)) {
458 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means
459 // these state could be ignored.
461 if ((RegsiteredData
->KeyState
.KeyShiftState
!= 0) &&
462 (RegsiteredData
->KeyState
.KeyShiftState
!= InputData
->KeyState
.KeyShiftState
)) {
465 if ((RegsiteredData
->KeyState
.KeyToggleState
!= 0) &&
466 (RegsiteredData
->KeyState
.KeyToggleState
!= InputData
->KeyState
.KeyToggleState
)) {
475 Event notification function for SIMPLE_TEXT_IN.WaitForKey event
476 Signal the event if there is key available
478 @param Event the event object
479 @param Context waitting context
484 VirtualKeyboardWaitForKey (
490 // Stall 1ms to give a chance to let other driver interrupt this routine
491 // for their timer event.
492 // e.g. UI setup or Shell, other drivers which are driven by timer event
493 // will have a bad performance during this period,
494 // e.g. usb keyboard driver.
495 // Add a stall period can greatly increate other driver performance during
496 // the WaitForKey is recursivly invoked. 1ms delay will make little impact
497 // to the thunk keyboard driver, and user can not feel the delay at all when
502 // Use TimerEvent callback function to check whether there's any key pressed
504 VirtualKeyboardTimerHandler (NULL
, VIRTUAL_KEYBOARD_DEV_FROM_THIS (Context
));
506 if (!EFI_ERROR (VirtualKeyboardCheckForKey (Context
))) {
507 gBS
->SignalEvent (Event
);
512 Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx
513 event. Signal the event if there is key available
515 @param Event event object
516 @param Context waiting context
521 VirtualKeyboardWaitForKeyEx (
527 VIRTUAL_KEYBOARD_DEV
*VirtualKeyboardPrivate
;
529 VirtualKeyboardPrivate
= TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (Context
);
530 VirtualKeyboardWaitForKey (Event
, &VirtualKeyboardPrivate
->SimpleTextIn
);
535 // EFI Simple Text In Protocol Functions
538 Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE)
539 then do some extra keyboard validations.
541 @param This Pointer of simple text Protocol.
542 @param ExtendedVerification Whether perform the extra validation of
543 keyboard. True: perform; FALSE: skip.
545 @retval EFI_SUCCESS The command byte is written successfully.
546 @retval EFI_DEVICE_ERROR Errors occurred during resetting keyboard.
551 VirtualKeyboardReset (
552 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
553 IN BOOLEAN ExtendedVerification
556 VIRTUAL_KEYBOARD_DEV
*VirtualKeyboardPrivate
;
560 VirtualKeyboardPrivate
= VIRTUAL_KEYBOARD_DEV_FROM_THIS (This
);
563 // Raise TPL to avoid mouse operation impact
565 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
567 if (VirtualKeyboardPrivate
->PlatformVirtual
&&
568 VirtualKeyboardPrivate
->PlatformVirtual
->Reset
) {
569 Status
= VirtualKeyboardPrivate
->PlatformVirtual
->Reset ();
571 Status
= EFI_INVALID_PARAMETER
;
575 // resume priority of task level
577 gBS
->RestoreTPL (OldTpl
);
583 Reset the input device and optionaly run diagnostics
585 @param This Protocol instance pointer.
586 @param ExtendedVerification Driver may perform diagnostics on reset.
588 @retval EFI_SUCCESS The device was reset.
589 @retval EFI_DEVICE_ERROR The device is not functioning properly and
595 VirtualKeyboardResetEx (
596 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
597 IN BOOLEAN ExtendedVerification
600 VIRTUAL_KEYBOARD_DEV
*VirtualKeyboardPrivate
;
604 VirtualKeyboardPrivate
= TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This
);
606 Status
= VirtualKeyboardPrivate
->SimpleTextIn
.Reset (
607 &VirtualKeyboardPrivate
->SimpleTextIn
,
610 if (EFI_ERROR (Status
)) {
611 return EFI_DEVICE_ERROR
;
614 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
616 gBS
->RestoreTPL (OldTpl
);
623 Reads the next keystroke from the input device. The WaitForKey Event can
624 be used to test for existance of a keystroke via WaitForEvent () call.
626 @param VirtualKeyboardPrivate Virtualkeyboard driver private structure.
627 @param KeyData A pointer to a buffer that is filled in
628 with the keystroke state data for the key
631 @retval EFI_SUCCESS The keystroke information was returned.
632 @retval EFI_NOT_READY There was no keystroke data availiable.
633 @retval EFI_DEVICE_ERROR The keystroke information was not returned
634 due to hardware errors.
635 @retval EFI_INVALID_PARAMETER KeyData is NULL.
639 KeyboardReadKeyStrokeWorker (
640 IN VIRTUAL_KEYBOARD_DEV
*VirtualKeyboardPrivate
,
641 OUT EFI_KEY_DATA
*KeyData
646 if (KeyData
== NULL
) {
647 return EFI_INVALID_PARAMETER
;
651 // Use TimerEvent callback function to check whether there's any key pressed
655 // Stall 1ms to give a chance to let other driver interrupt this routine for
656 // their timer event.
657 // e.g. OS loader, other drivers which are driven by timer event will have a
658 // bad performance during this period,
659 // e.g. usb keyboard driver.
660 // Add a stall period can greatly increate other driver performance during
661 // the WaitForKey is recursivly invoked. 1ms delay will make little impact
662 // to the thunk keyboard driver, and user can not feel the delay at all when
667 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
669 VirtualKeyboardTimerHandler (NULL
, VirtualKeyboardPrivate
);
671 // If there's no key, just return
673 Status
= CheckQueue (&VirtualKeyboardPrivate
->Queue
);
674 if (EFI_ERROR (Status
)) {
675 gBS
->RestoreTPL (OldTpl
);
676 return EFI_NOT_READY
;
679 Status
= Dequeue (&VirtualKeyboardPrivate
->Queue
, KeyData
);
681 gBS
->RestoreTPL (OldTpl
);
687 Read out the scan code of the key that has just been stroked.
689 @param This Pointer of simple text Protocol.
690 @param Key Pointer for store the key that read out.
692 @retval EFI_SUCCESS The key is read out successfully.
693 @retval other The key reading failed.
698 VirtualKeyboardReadKeyStroke (
699 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
700 OUT EFI_INPUT_KEY
*Key
703 VIRTUAL_KEYBOARD_DEV
*VirtualKeyboardPrivate
;
705 EFI_KEY_DATA KeyData
;
707 VirtualKeyboardPrivate
= VIRTUAL_KEYBOARD_DEV_FROM_THIS (This
);
709 Status
= KeyboardReadKeyStrokeWorker (VirtualKeyboardPrivate
, &KeyData
);
710 if (EFI_ERROR (Status
)) {
715 // Convert the Ctrl+[a-z] to Ctrl+[1-26]
717 if ((KeyData
.KeyState
.KeyShiftState
& (EFI_LEFT_CONTROL_PRESSED
| EFI_RIGHT_CONTROL_PRESSED
)) != 0) {
718 if (KeyData
.Key
.UnicodeChar
>= L
'a' &&
719 KeyData
.Key
.UnicodeChar
<= L
'z') {
720 KeyData
.Key
.UnicodeChar
= (CHAR16
) (KeyData
.Key
.UnicodeChar
- L
'a' + 1);
721 } else if (KeyData
.Key
.UnicodeChar
>= L
'A' &&
722 KeyData
.Key
.UnicodeChar
<= L
'Z') {
723 KeyData
.Key
.UnicodeChar
= (CHAR16
) (KeyData
.Key
.UnicodeChar
- L
'A' + 1);
727 CopyMem (Key
, &KeyData
.Key
, sizeof (EFI_INPUT_KEY
));
733 Reads the next keystroke from the input device. The WaitForKey Event can
734 be used to test for existance of a keystroke via WaitForEvent () call.
736 @param This Protocol instance pointer.
737 @param KeyData A pointer to a buffer that is filled in with the
738 keystroke state data for the key that was pressed.
740 @retval EFI_SUCCESS The keystroke information was returned.
741 @retval EFI_NOT_READY There was no keystroke data availiable.
742 @retval EFI_DEVICE_ERROR The keystroke information was not returned
743 due to hardware errors.
744 @retval EFI_INVALID_PARAMETER KeyData is NULL.
749 VirtualKeyboardReadKeyStrokeEx (
750 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
751 OUT EFI_KEY_DATA
*KeyData
754 VIRTUAL_KEYBOARD_DEV
*VirtualKeyboardPrivate
;
756 if (KeyData
== NULL
) {
757 return EFI_INVALID_PARAMETER
;
760 VirtualKeyboardPrivate
= TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This
);
762 return KeyboardReadKeyStrokeWorker (VirtualKeyboardPrivate
, KeyData
);
767 Set certain state for the input device.
769 @param This Protocol instance pointer.
770 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
771 state for the input device.
773 @retval EFI_SUCCESS The device state was set successfully.
774 @retval EFI_DEVICE_ERROR The device is not functioning correctly and
775 could not have the setting adjusted.
776 @retval EFI_UNSUPPORTED The device does not have the ability to set
778 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
783 VirtualKeyboardSetState (
784 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
785 IN EFI_KEY_TOGGLE_STATE
*KeyToggleState
788 if (KeyToggleState
== NULL
) {
789 return EFI_INVALID_PARAMETER
;
796 Register a notification function for a particular keystroke for the
799 @param This Protocol instance pointer.
800 @param KeyData A pointer to a buffer that is filled in with
801 the keystroke information data for the key
803 @param KeyNotificationFunction Points to the function to be called when the
804 key sequence is typed specified by KeyData.
805 @param NotifyHandle Points to the unique handle assigned to the
806 registered notification.
809 @retval EFI_SUCCESS The notification function was registered
811 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary
813 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
818 VirtualKeyboardRegisterKeyNotify (
819 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
820 IN EFI_KEY_DATA
*KeyData
,
821 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction
,
822 OUT VOID
**NotifyHandle
826 VIRTUAL_KEYBOARD_DEV
*VirtualKeyboardPrivate
;
828 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NewNotify
;
830 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
832 if (KeyData
== NULL
||
833 NotifyHandle
== NULL
||
834 KeyNotificationFunction
== NULL
) {
835 return EFI_INVALID_PARAMETER
;
838 VirtualKeyboardPrivate
= TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This
);
841 // Enter critical section
843 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
846 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already
849 for (Link
= VirtualKeyboardPrivate
->NotifyList
.ForwardLink
;
850 Link
!= &VirtualKeyboardPrivate
->NotifyList
;
851 Link
= Link
->ForwardLink
) {
854 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
856 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
858 if (IsKeyRegistered (&CurrentNotify
->KeyData
, KeyData
)) {
859 if (CurrentNotify
->KeyNotificationFn
== KeyNotificationFunction
) {
860 *NotifyHandle
= CurrentNotify
;
861 Status
= EFI_SUCCESS
;
868 // Allocate resource to save the notification function
871 NewNotify
= (VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*) AllocateZeroPool (sizeof (VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY
));
872 if (NewNotify
== NULL
) {
873 Status
= EFI_OUT_OF_RESOURCES
;
877 NewNotify
->Signature
= VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
;
878 NewNotify
->KeyNotificationFn
= KeyNotificationFunction
;
879 CopyMem (&NewNotify
->KeyData
, KeyData
, sizeof (EFI_KEY_DATA
));
880 InsertTailList (&VirtualKeyboardPrivate
->NotifyList
, &NewNotify
->NotifyEntry
);
882 *NotifyHandle
= NewNotify
;
883 Status
= EFI_SUCCESS
;
887 // Leave critical section and return
889 gBS
->RestoreTPL (OldTpl
);
895 Remove a registered notification function from a particular keystroke.
897 @param This Protocol instance pointer.
898 @param NotificationHandle The handle of the notification function
901 @retval EFI_SUCCESS The notification function was unregistered
903 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
908 VirtualKeyboardUnregisterKeyNotify (
909 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
910 IN VOID
*NotificationHandle
914 VIRTUAL_KEYBOARD_DEV
*VirtualKeyboardPrivate
;
917 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
920 // Check incoming notification handle
922 if (NotificationHandle
== NULL
) {
923 return EFI_INVALID_PARAMETER
;
926 if (((VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*) NotificationHandle
)->Signature
!=
927 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
) {
928 return EFI_INVALID_PARAMETER
;
931 VirtualKeyboardPrivate
= TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This
);
934 // Enter critical section
936 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
938 for (Link
= VirtualKeyboardPrivate
->NotifyList
.ForwardLink
;
939 Link
!= &VirtualKeyboardPrivate
->NotifyList
;
940 Link
= Link
->ForwardLink
) {
943 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
945 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
947 if (CurrentNotify
== NotificationHandle
) {
949 // Remove the notification function from NotifyList and free resources
951 RemoveEntryList (&CurrentNotify
->NotifyEntry
);
953 Status
= EFI_SUCCESS
;
959 // Can not find the specified Notification Handle
961 Status
= EFI_INVALID_PARAMETER
;
965 // Leave critical section and return
967 gBS
->RestoreTPL (OldTpl
);
972 Timer event handler: read a series of scancodes from 8042
973 and put them into memory scancode buffer.
974 it read as much scancodes to either fill
975 the memory buffer or empty the keyboard buffer.
976 It is registered as running under TPL_NOTIFY
978 @param Event The timer event
979 @param Context A KEYBOARD_CONSOLE_IN_DEV pointer
984 VirtualKeyboardTimerHandler (
991 EFI_KEY_DATA KeyData
;
992 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
993 VIRTUAL_KEYBOARD_DEV
*VirtualKeyboardPrivate
;
994 VIRTUAL_KBD_KEY VirtualKey
;
996 VirtualKeyboardPrivate
= Context
;
999 // Enter critical section
1001 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1003 if (VirtualKeyboardPrivate
->PlatformVirtual
&&
1004 VirtualKeyboardPrivate
->PlatformVirtual
->Query
) {
1005 if (VirtualKeyboardPrivate
->PlatformVirtual
->Query (&VirtualKey
) ==
1010 KeyData
.Key
.ScanCode
= VirtualKey
.Key
.ScanCode
;
1011 KeyData
.Key
.UnicodeChar
= VirtualKey
.Key
.UnicodeChar
;
1012 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
;
1013 KeyData
.KeyState
.KeyToggleState
= EFI_TOGGLE_STATE_VALID
;
1014 if (VirtualKeyboardPrivate
->PlatformVirtual
->Clear
) {
1015 VirtualKeyboardPrivate
->PlatformVirtual
->Clear (&VirtualKey
);
1022 // Signal KeyNotify process event if this key pressed matches any key registered.
1024 for (Link
= VirtualKeyboardPrivate
->NotifyList
.ForwardLink
;
1025 Link
!= &VirtualKeyboardPrivate
->NotifyList
;
1026 Link
= Link
->ForwardLink
) {
1027 CurrentNotify
= CR (
1029 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
1031 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1033 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
1035 // The key notification function needs to run at TPL_CALLBACK
1036 // while current TPL is TPL_NOTIFY. It will be invoked in
1037 // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.
1039 Enqueue (&VirtualKeyboardPrivate
->QueueForNotify
, &KeyData
);
1040 gBS
->SignalEvent (VirtualKeyboardPrivate
->KeyNotifyProcessEvent
);
1045 Enqueue (&VirtualKeyboardPrivate
->Queue
, &KeyData
);
1049 // Leave critical section and return
1051 gBS
->RestoreTPL (OldTpl
);
1057 @param Event Indicates the event that invoke this function.
1058 @param Context Indicates the calling context.
1062 KeyNotifyProcessHandler (
1068 VIRTUAL_KEYBOARD_DEV
*VirtualKeyboardPrivate
;
1069 EFI_KEY_DATA KeyData
;
1071 LIST_ENTRY
*NotifyList
;
1072 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
1075 VirtualKeyboardPrivate
= (VIRTUAL_KEYBOARD_DEV
*) Context
;
1078 // Invoke notification functions.
1080 NotifyList
= &VirtualKeyboardPrivate
->NotifyList
;
1083 // Enter critical section
1085 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1086 Status
= Dequeue (&VirtualKeyboardPrivate
->QueueForNotify
, &KeyData
);
1088 // Leave critical section
1090 gBS
->RestoreTPL (OldTpl
);
1091 if (EFI_ERROR (Status
)) {
1094 for (Link
= GetFirstNode (NotifyList
);
1095 !IsNull (NotifyList
, Link
);
1096 Link
= GetNextNode (NotifyList
, Link
)) {
1097 CurrentNotify
= CR (Link
,
1098 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
1100 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1102 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
1103 CurrentNotify
->KeyNotificationFn (&KeyData
);
1110 The user Entry Point for module VirtualKeyboard. The user code starts with
1113 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1114 @param[in] SystemTable A pointer to the EFI System Table.
1116 @retval EFI_SUCCESS The entry point is executed successfully.
1117 @retval other Some error occurs when executing this entry point.
1122 InitializeVirtualKeyboard(
1123 IN EFI_HANDLE ImageHandle
,
1124 IN EFI_SYSTEM_TABLE
*SystemTable
1130 // Install driver model protocol(s).
1132 Status
= EfiLibInstallDriverBindingComponentName2 (
1135 &gVirtualKeyboardDriverBinding
,
1137 &gVirtualKeyboardComponentName
,
1138 &gVirtualKeyboardComponentName2
1140 ASSERT_EFI_ERROR (Status
);