1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162 |
- /** @file
- VirtualKeyboard driver
- Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
- Copyright (c) 2018, Linaro Ltd. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "VirtualKeyboard.h"
- //
- // RAM Keyboard Driver Binding Protocol Instance
- //
- EFI_DRIVER_BINDING_PROTOCOL gVirtualKeyboardDriverBinding = {
- VirtualKeyboardDriverBindingSupported,
- VirtualKeyboardDriverBindingStart,
- VirtualKeyboardDriverBindingStop,
- 0x10,
- NULL,
- NULL
- };
- //
- // EFI Driver Binding Protocol Functions
- //
- /**
- Check whether the driver supports this device.
- @param This The Udriver binding protocol.
- @param Controller The controller handle to check.
- @param RemainingDevicePath The remaining device path.
- @retval EFI_SUCCESS The driver supports this controller.
- @retval other This device isn't supported.
- **/
- EFI_STATUS
- EFIAPI
- VirtualKeyboardDriverBindingSupported (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Controller,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
- )
- {
- EFI_STATUS Status;
- PLATFORM_VIRTUAL_KBD_PROTOCOL *PlatformVirtual;
- Status = gBS->OpenProtocol (
- Controller,
- &gPlatformVirtualKeyboardProtocolGuid,
- (VOID **)&PlatformVirtual,
- This->DriverBindingHandle,
- Controller,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- gBS->CloseProtocol (
- Controller,
- &gPlatformVirtualKeyboardProtocolGuid,
- This->DriverBindingHandle,
- Controller
- );
- return Status;
- }
- /**
- Starts the device with this driver.
- @param This The driver binding instance.
- @param Controller Handle of device to bind driver to.
- @param RemainingDevicePath Optional parameter use to pick a specific child
- device to start.
- @retval EFI_SUCCESS The controller is controlled by the driver.
- @retval Other This controller cannot be started.
- **/
- EFI_STATUS
- EFIAPI
- VirtualKeyboardDriverBindingStart (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Controller,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
- )
- {
- EFI_STATUS Status;
- VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
- PLATFORM_VIRTUAL_KBD_PROTOCOL *PlatformVirtual;
- Status = gBS->OpenProtocol (
- Controller,
- &gPlatformVirtualKeyboardProtocolGuid,
- (VOID **)&PlatformVirtual,
- This->DriverBindingHandle,
- Controller,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Allocate the private device structure
- //
- VirtualKeyboardPrivate = (VIRTUAL_KEYBOARD_DEV *)AllocateZeroPool (sizeof (VIRTUAL_KEYBOARD_DEV));
- if (VirtualKeyboardPrivate == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- //
- // Initialize the private device structure
- //
- VirtualKeyboardPrivate->Signature = VIRTUAL_KEYBOARD_DEV_SIGNATURE;
- VirtualKeyboardPrivate->Handle = Controller;
- VirtualKeyboardPrivate->PlatformVirtual = PlatformVirtual;
- VirtualKeyboardPrivate->Queue.Front = 0;
- VirtualKeyboardPrivate->Queue.Rear = 0;
- VirtualKeyboardPrivate->QueueForNotify.Front = 0;
- VirtualKeyboardPrivate->QueueForNotify.Rear = 0;
- VirtualKeyboardPrivate->SimpleTextIn.Reset = VirtualKeyboardReset;
- VirtualKeyboardPrivate->SimpleTextIn.ReadKeyStroke = VirtualKeyboardReadKeyStroke;
- VirtualKeyboardPrivate->SimpleTextInputEx.Reset = VirtualKeyboardResetEx;
- VirtualKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx = VirtualKeyboardReadKeyStrokeEx;
- VirtualKeyboardPrivate->SimpleTextInputEx.SetState = VirtualKeyboardSetState;
- VirtualKeyboardPrivate->SimpleTextInputEx.RegisterKeyNotify = VirtualKeyboardRegisterKeyNotify;
- VirtualKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = VirtualKeyboardUnregisterKeyNotify;
- InitializeListHead (&VirtualKeyboardPrivate->NotifyList);
- Status = PlatformVirtual->Register ();
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- //
- // Report that the keyboard is being enabled
- //
- REPORT_STATUS_CODE (
- EFI_PROGRESS_CODE,
- EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE
- );
- //
- // Setup the WaitForKey event
- //
- Status = gBS->CreateEvent (
- EVT_NOTIFY_WAIT,
- TPL_NOTIFY,
- VirtualKeyboardWaitForKey,
- &(VirtualKeyboardPrivate->SimpleTextIn),
- &((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey)
- );
- if (EFI_ERROR (Status)) {
- (VirtualKeyboardPrivate->SimpleTextIn).WaitForKey = NULL;
- goto Done;
- }
- Status = gBS->CreateEvent (
- EVT_NOTIFY_WAIT,
- TPL_NOTIFY,
- VirtualKeyboardWaitForKeyEx,
- &(VirtualKeyboardPrivate->SimpleTextInputEx),
- &(VirtualKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx)
- );
- if (EFI_ERROR (Status)) {
- VirtualKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx = NULL;
- goto Done;
- }
- //
- // Setup a periodic timer, used for reading keystrokes at a fixed interval
- //
- Status = gBS->CreateEvent (
- EVT_TIMER | EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- VirtualKeyboardTimerHandler,
- VirtualKeyboardPrivate,
- &VirtualKeyboardPrivate->TimerEvent
- );
- if (EFI_ERROR (Status)) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- Status = gBS->SetTimer (
- VirtualKeyboardPrivate->TimerEvent,
- TimerPeriodic,
- KEYBOARD_TIMER_INTERVAL
- );
- if (EFI_ERROR (Status)) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- KeyNotifyProcessHandler,
- VirtualKeyboardPrivate,
- &VirtualKeyboardPrivate->KeyNotifyProcessEvent
- );
- if (EFI_ERROR (Status)) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- //
- // Reset the keyboard device
- //
- Status = VirtualKeyboardPrivate->SimpleTextInputEx.Reset (
- &VirtualKeyboardPrivate->SimpleTextInputEx,
- FALSE
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "[KBD]Reset Failed. Status - %r\n", Status));
- goto Done;
- }
- //
- // Install protocol interfaces for the keyboard device.
- //
- Status = gBS->InstallMultipleProtocolInterfaces (
- &Controller,
- &gEfiSimpleTextInProtocolGuid,
- &VirtualKeyboardPrivate->SimpleTextIn,
- &gEfiSimpleTextInputExProtocolGuid,
- &VirtualKeyboardPrivate->SimpleTextInputEx,
- NULL
- );
- Done:
- if (EFI_ERROR (Status)) {
- if (VirtualKeyboardPrivate != NULL) {
- if ((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey != NULL) {
- gBS->CloseEvent ((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey);
- }
- if ((VirtualKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) {
- gBS->CloseEvent (
- (VirtualKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx
- );
- }
- if (VirtualKeyboardPrivate->KeyNotifyProcessEvent != NULL) {
- gBS->CloseEvent (VirtualKeyboardPrivate->KeyNotifyProcessEvent);
- }
- VirtualKeyboardFreeNotifyList (&VirtualKeyboardPrivate->NotifyList);
- if (VirtualKeyboardPrivate->TimerEvent != NULL) {
- gBS->CloseEvent (VirtualKeyboardPrivate->TimerEvent);
- }
- FreePool (VirtualKeyboardPrivate);
- }
- }
- gBS->CloseProtocol (
- Controller,
- &gPlatformVirtualKeyboardProtocolGuid,
- This->DriverBindingHandle,
- Controller
- );
- return Status;
- }
- /**
- Stop the device handled by this driver.
- @param This The driver binding protocol.
- @param Controller The controller to release.
- @param NumberOfChildren The number of handles in ChildHandleBuffer.
- @param ChildHandleBuffer The array of child handle.
- @retval EFI_SUCCESS The device was stopped.
- @retval EFI_DEVICE_ERROR The device could not be stopped due to a
- device error.
- @retval Others Fail to uninstall protocols attached on the
- device.
- **/
- EFI_STATUS
- EFIAPI
- VirtualKeyboardDriverBindingStop (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Controller,
- IN UINTN NumberOfChildren,
- IN EFI_HANDLE *ChildHandleBuffer
- )
- {
- return EFI_SUCCESS;
- }
- /**
- Enqueue the key.
- @param Queue The queue to be enqueued.
- @param KeyData The key data to be enqueued.
- @retval EFI_NOT_READY The queue is full.
- @retval EFI_SUCCESS Successfully enqueued the key data.
- **/
- EFI_STATUS
- Enqueue (
- IN SIMPLE_QUEUE *Queue,
- IN EFI_KEY_DATA *KeyData
- )
- {
- if ((Queue->Rear + 1) % QUEUE_MAX_COUNT == Queue->Front) {
- return EFI_NOT_READY;
- }
- CopyMem (&Queue->Buffer[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));
- Queue->Rear = (Queue->Rear + 1) % QUEUE_MAX_COUNT;
- return EFI_SUCCESS;
- }
- /**
- Dequeue the key.
- @param Queue The queue to be dequeued.
- @param KeyData The key data to be dequeued.
- @retval EFI_NOT_READY The queue is empty.
- @retval EFI_SUCCESS Successfully dequeued the key data.
- **/
- EFI_STATUS
- Dequeue (
- IN SIMPLE_QUEUE *Queue,
- IN EFI_KEY_DATA *KeyData
- )
- {
- if (Queue->Front == Queue->Rear) {
- return EFI_NOT_READY;
- }
- CopyMem (KeyData, &Queue->Buffer[Queue->Front], sizeof (EFI_KEY_DATA));
- Queue->Front = (Queue->Front + 1) % QUEUE_MAX_COUNT;
- return EFI_SUCCESS;
- }
- /**
- Check whether the queue is empty.
- @param Queue The queue to be checked.
- @retval EFI_NOT_READY The queue is empty.
- @retval EFI_SUCCESS The queue is not empty.
- **/
- EFI_STATUS
- CheckQueue (
- IN SIMPLE_QUEUE *Queue
- )
- {
- if (Queue->Front == Queue->Rear) {
- return EFI_NOT_READY;
- }
- return EFI_SUCCESS;
- }
- /**
- Check key buffer to get the key stroke status.
- @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.
- @retval EFI_SUCCESS A key is being pressed now.
- @retval Other No key is now pressed.
- **/
- EFI_STATUS
- EFIAPI
- VirtualKeyboardCheckForKey (
- IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This
- )
- {
- VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
- VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
- return CheckQueue (&VirtualKeyboardPrivate->Queue);
- }
- /**
- Free keyboard notify list.
- @param ListHead The list head
- @retval EFI_SUCCESS Free the notify list successfully
- @retval EFI_INVALID_PARAMETER ListHead is invalid.
- **/
- EFI_STATUS
- VirtualKeyboardFreeNotifyList (
- IN OUT LIST_ENTRY *ListHead
- )
- {
- VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
- if (ListHead == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- while (!IsListEmpty (ListHead)) {
- NotifyNode = CR (
- ListHead->ForwardLink,
- VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
- NotifyEntry,
- VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
- );
- RemoveEntryList (ListHead->ForwardLink);
- gBS->FreePool (NotifyNode);
- }
- return EFI_SUCCESS;
- }
- /**
- Judge whether is a registed key
- @param RegsiteredData A pointer to a buffer that is filled in with
- the keystroke state data for the key that was
- registered.
- @param InputData A pointer to a buffer that is filled in with
- the keystroke state data for the key that was
- pressed.
- @retval TRUE Key be pressed matches a registered key.
- @retval FALSE Match failed.
- **/
- BOOLEAN
- IsKeyRegistered (
- IN EFI_KEY_DATA *RegsiteredData,
- IN EFI_KEY_DATA *InputData
- )
- {
- 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;
- }
- /**
- Event notification function for SIMPLE_TEXT_IN.WaitForKey event
- Signal the event if there is key available
- @param Event the event object
- @param Context waiting context
- **/
- VOID
- EFIAPI
- VirtualKeyboardWaitForKey (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- //
- // Stall 1ms to give a chance to let other driver interrupt this routine
- // for their timer event.
- // e.g. UI setup or Shell, other drivers which are driven by timer event
- // will have a bad performance during this period,
- // e.g. usb keyboard driver.
- // Add a stall period can greatly increate other driver performance during
- // the WaitForKey is recursivly invoked. 1ms delay will make little impact
- // to the thunk keyboard driver, and user can not feel the delay at all when
- // input.
- //
- gBS->Stall (1000);
- //
- // Use TimerEvent callback function to check whether there's any key pressed
- //
- VirtualKeyboardTimerHandler (NULL, VIRTUAL_KEYBOARD_DEV_FROM_THIS (Context));
- if (!EFI_ERROR (VirtualKeyboardCheckForKey (Context))) {
- gBS->SignalEvent (Event);
- }
- }
- /**
- Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx
- event. Signal the event if there is key available
- @param Event event object
- @param Context waiting context
- **/
- VOID
- EFIAPI
- VirtualKeyboardWaitForKeyEx (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
- VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (Context);
- VirtualKeyboardWaitForKey (Event, &VirtualKeyboardPrivate->SimpleTextIn);
- }
- //
- // EFI Simple Text In Protocol Functions
- //
- /**
- Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE)
- then do some extra keyboard validations.
- @param This Pointer of simple text Protocol.
- @param ExtendedVerification Whether perform the extra validation of
- keyboard. True: perform; FALSE: skip.
- @retval EFI_SUCCESS The command byte is written successfully.
- @retval EFI_DEVICE_ERROR Errors occurred during resetting keyboard.
- **/
- EFI_STATUS
- EFIAPI
- VirtualKeyboardReset (
- IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
- IN BOOLEAN ExtendedVerification
- )
- {
- VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
- EFI_STATUS Status;
- EFI_TPL OldTpl;
- VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
- //
- // Raise TPL to avoid mouse operation impact
- //
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- if (VirtualKeyboardPrivate->PlatformVirtual &&
- VirtualKeyboardPrivate->PlatformVirtual->Reset)
- {
- Status = VirtualKeyboardPrivate->PlatformVirtual->Reset ();
- } else {
- Status = EFI_INVALID_PARAMETER;
- }
- //
- // resume priority of task level
- //
- gBS->RestoreTPL (OldTpl);
- return Status;
- }
- /**
- Reset the input device and optionally run diagnostics
- @param This Protocol instance pointer.
- @param ExtendedVerification Driver may perform diagnostics on reset.
- @retval EFI_SUCCESS The device was reset.
- @retval EFI_DEVICE_ERROR The device is not functioning properly and
- could not be reset.
- **/
- EFI_STATUS
- EFIAPI
- VirtualKeyboardResetEx (
- IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
- IN BOOLEAN ExtendedVerification
- )
- {
- VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
- EFI_STATUS Status;
- EFI_TPL OldTpl;
- VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
- Status = VirtualKeyboardPrivate->SimpleTextIn.Reset (
- &VirtualKeyboardPrivate->SimpleTextIn,
- ExtendedVerification
- );
- if (EFI_ERROR (Status)) {
- return EFI_DEVICE_ERROR;
- }
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- gBS->RestoreTPL (OldTpl);
- 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 VirtualKeyboardPrivate Virtualkeyboard 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
- KeyboardReadKeyStrokeWorker (
- IN VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate,
- OUT EFI_KEY_DATA *KeyData
- )
- {
- EFI_STATUS Status;
- EFI_TPL OldTpl;
- if (KeyData == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Use TimerEvent callback function to check whether there's any key pressed
- //
- //
- // Stall 1ms to give a chance to let other driver interrupt this routine for
- // their timer event.
- // e.g. OS loader, other drivers which are driven by timer event will have a
- // bad performance during this period,
- // e.g. usb keyboard driver.
- // Add a stall period can greatly increate other driver performance during
- // the WaitForKey is recursivly invoked. 1ms delay will make little impact
- // to the thunk keyboard driver, and user can not feel the delay at all when
- // input.
- //
- gBS->Stall (1000);
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- VirtualKeyboardTimerHandler (NULL, VirtualKeyboardPrivate);
- //
- // If there's no key, just return
- //
- Status = CheckQueue (&VirtualKeyboardPrivate->Queue);
- if (EFI_ERROR (Status)) {
- gBS->RestoreTPL (OldTpl);
- return EFI_NOT_READY;
- }
- Status = Dequeue (&VirtualKeyboardPrivate->Queue, KeyData);
- gBS->RestoreTPL (OldTpl);
- return EFI_SUCCESS;
- }
- /**
- Read out the scan code of the key that has just been stroked.
- @param This Pointer of simple text Protocol.
- @param Key Pointer for store the key that read out.
- @retval EFI_SUCCESS The key is read out successfully.
- @retval other The key reading failed.
- **/
- EFI_STATUS
- EFIAPI
- VirtualKeyboardReadKeyStroke (
- IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
- OUT EFI_INPUT_KEY *Key
- )
- {
- VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
- EFI_STATUS Status;
- EFI_KEY_DATA KeyData;
- VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
- Status = KeyboardReadKeyStrokeWorker (VirtualKeyboardPrivate, &KeyData);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Convert the Ctrl+[a-z] to Ctrl+[1-26]
- //
- if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
- if ((KeyData.Key.UnicodeChar >= L'a') &&
- (KeyData.Key.UnicodeChar <= L'z'))
- {
- KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar - L'a' + 1);
- } else if ((KeyData.Key.UnicodeChar >= L'A') &&
- (KeyData.Key.UnicodeChar <= L'Z'))
- {
- KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar - L'A' + 1);
- }
- }
- CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
- 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 This Protocol instance pointer.
- @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
- EFIAPI
- VirtualKeyboardReadKeyStrokeEx (
- IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
- OUT EFI_KEY_DATA *KeyData
- )
- {
- VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
- if (KeyData == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
- return KeyboardReadKeyStrokeWorker (VirtualKeyboardPrivate, KeyData);
- }
- /**
- Set certain state for the input device.
- @param This Protocol instance pointer.
- @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
- state for the input device.
- @retval EFI_SUCCESS The device state was set successfully.
- @retval EFI_DEVICE_ERROR The device is not functioning correctly and
- could not have the setting adjusted.
- @retval EFI_UNSUPPORTED The device does not have the ability to set
- its state.
- @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
- **/
- EFI_STATUS
- EFIAPI
- VirtualKeyboardSetState (
- IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
- IN EFI_KEY_TOGGLE_STATE *KeyToggleState
- )
- {
- if (KeyToggleState == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- return EFI_SUCCESS;
- }
- /**
- 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
- VirtualKeyboardRegisterKeyNotify (
- IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
- IN EFI_KEY_DATA *KeyData,
- IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
- OUT VOID **NotifyHandle
- )
- {
- EFI_STATUS Status;
- VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
- EFI_TPL OldTpl;
- VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;
- LIST_ENTRY *Link;
- VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
- if ((KeyData == NULL) ||
- (NotifyHandle == NULL) ||
- (KeyNotificationFunction == NULL))
- {
- return EFI_INVALID_PARAMETER;
- }
- VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
- //
- // Enter critical section
- //
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- //
- // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already
- // 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)) {
- if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
- *NotifyHandle = CurrentNotify;
- Status = EFI_SUCCESS;
- goto Exit;
- }
- }
- }
- //
- // Allocate resource to save the notification function
- //
- NewNotify = (VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *)AllocateZeroPool (sizeof (VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY));
- if (NewNotify == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Exit;
- }
- NewNotify->Signature = VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
- NewNotify->KeyNotificationFn = KeyNotificationFunction;
- CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
- InsertTailList (&VirtualKeyboardPrivate->NotifyList, &NewNotify->NotifyEntry);
- *NotifyHandle = NewNotify;
- Status = EFI_SUCCESS;
- Exit:
- //
- // Leave critical section and return
- //
- gBS->RestoreTPL (OldTpl);
- return Status;
- }
- /**
- Remove a registered notification function from a particular keystroke.
- @param This Protocol instance pointer.
- @param NotificationHandle The handle of the notification function
- being unregistered.
- @retval EFI_SUCCESS The notification function was unregistered
- successfully.
- @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
- **/
- EFI_STATUS
- EFIAPI
- VirtualKeyboardUnregisterKeyNotify (
- IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
- IN VOID *NotificationHandle
- )
- {
- EFI_STATUS Status;
- VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
- EFI_TPL OldTpl;
- LIST_ENTRY *Link;
- VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
- //
- // Check incoming notification handle
- //
- if (NotificationHandle == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- if (((VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *)NotificationHandle)->Signature !=
- VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE)
- {
- return EFI_INVALID_PARAMETER;
- }
- VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
- //
- // Enter critical section
- //
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- 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 (CurrentNotify == NotificationHandle) {
- //
- // Remove the notification function from NotifyList and free resources
- //
- RemoveEntryList (&CurrentNotify->NotifyEntry);
- Status = EFI_SUCCESS;
- goto Exit;
- }
- }
- //
- // Can not find the specified Notification Handle
- //
- Status = EFI_INVALID_PARAMETER;
- Exit:
- //
- // Leave critical section and return
- //
- gBS->RestoreTPL (OldTpl);
- return Status;
- }
- /**
- 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);
- }
- /**
- 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);
- }
- }
- }
- }
- /**
- The user Entry Point for module VirtualKeyboard. The user code starts with
- this function.
- @param[in] ImageHandle The firmware allocated handle for the EFI image.
- @param[in] SystemTable A pointer to the EFI System Table.
- @retval EFI_SUCCESS The entry point is executed successfully.
- @retval other Some error occurs when executing this entry point.
- **/
- EFI_STATUS
- EFIAPI
- InitializeVirtualKeyboard (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
- {
- EFI_STATUS Status;
- //
- // Install driver model protocol(s).
- //
- Status = EfiLibInstallDriverBindingComponentName2 (
- ImageHandle,
- SystemTable,
- &gVirtualKeyboardDriverBinding,
- ImageHandle,
- &gVirtualKeyboardComponentName,
- &gVirtualKeyboardComponentName2
- );
- ASSERT_EFI_ERROR (Status);
- return Status;
- }
|