]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.c
EmbeddedPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / EmbeddedPkg / Drivers / VirtualKeyboardDxe / VirtualKeyboard.c
1 /** @file
2 VirtualKeyboard driver
3
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2018, Linaro Ltd. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "VirtualKeyboard.h"
12
13 //
14 // RAM Keyboard Driver Binding Protocol Instance
15 //
16 EFI_DRIVER_BINDING_PROTOCOL gVirtualKeyboardDriverBinding = {
17 VirtualKeyboardDriverBindingSupported,
18 VirtualKeyboardDriverBindingStart,
19 VirtualKeyboardDriverBindingStop,
20 0x10,
21 NULL,
22 NULL
23 };
24
25 //
26 // EFI Driver Binding Protocol Functions
27 //
28
29 /**
30 Check whether the driver supports this device.
31
32 @param This The Udriver binding protocol.
33 @param Controller The controller handle to check.
34 @param RemainingDevicePath The remaining device path.
35
36 @retval EFI_SUCCESS The driver supports this controller.
37 @retval other This device isn't supported.
38
39 **/
40 EFI_STATUS
41 EFIAPI
42 VirtualKeyboardDriverBindingSupported (
43 IN EFI_DRIVER_BINDING_PROTOCOL *This,
44 IN EFI_HANDLE Controller,
45 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
46 )
47 {
48 EFI_STATUS Status;
49 PLATFORM_VIRTUAL_KBD_PROTOCOL *PlatformVirtual;
50
51 Status = gBS->OpenProtocol (
52 Controller,
53 &gPlatformVirtualKeyboardProtocolGuid,
54 (VOID **) &PlatformVirtual,
55 This->DriverBindingHandle,
56 Controller,
57 EFI_OPEN_PROTOCOL_BY_DRIVER
58 );
59 if (EFI_ERROR (Status)) {
60 return Status;
61 }
62 gBS->CloseProtocol (
63 Controller,
64 &gPlatformVirtualKeyboardProtocolGuid,
65 This->DriverBindingHandle,
66 Controller
67 );
68 return Status;
69 }
70
71 /**
72 Starts the device with this driver.
73
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
77 device to start.
78
79 @retval EFI_SUCCESS The controller is controlled by the driver.
80 @retval Other This controller cannot be started.
81
82 **/
83 EFI_STATUS
84 EFIAPI
85 VirtualKeyboardDriverBindingStart (
86 IN EFI_DRIVER_BINDING_PROTOCOL *This,
87 IN EFI_HANDLE Controller,
88 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
89 )
90 {
91 EFI_STATUS Status;
92 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
93 PLATFORM_VIRTUAL_KBD_PROTOCOL *PlatformVirtual;
94
95 Status = gBS->OpenProtocol (
96 Controller,
97 &gPlatformVirtualKeyboardProtocolGuid,
98 (VOID **) &PlatformVirtual,
99 This->DriverBindingHandle,
100 Controller,
101 EFI_OPEN_PROTOCOL_BY_DRIVER
102 );
103 if (EFI_ERROR (Status)) {
104 return Status;
105 }
106
107 //
108 // Allocate the private device structure
109 //
110 VirtualKeyboardPrivate = (VIRTUAL_KEYBOARD_DEV *) AllocateZeroPool (sizeof (VIRTUAL_KEYBOARD_DEV));
111 if (VirtualKeyboardPrivate == NULL) {
112 Status = EFI_OUT_OF_RESOURCES;
113 goto Done;
114 }
115
116 //
117 // Initialize the private device structure
118 //
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;
126
127 VirtualKeyboardPrivate->SimpleTextIn.Reset = VirtualKeyboardReset;
128 VirtualKeyboardPrivate->SimpleTextIn.ReadKeyStroke = VirtualKeyboardReadKeyStroke;
129
130 VirtualKeyboardPrivate->SimpleTextInputEx.Reset = VirtualKeyboardResetEx;
131 VirtualKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx = VirtualKeyboardReadKeyStrokeEx;
132 VirtualKeyboardPrivate->SimpleTextInputEx.SetState = VirtualKeyboardSetState;
133
134 VirtualKeyboardPrivate->SimpleTextInputEx.RegisterKeyNotify = VirtualKeyboardRegisterKeyNotify;
135 VirtualKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = VirtualKeyboardUnregisterKeyNotify;
136 InitializeListHead (&VirtualKeyboardPrivate->NotifyList);
137
138 Status = PlatformVirtual->Register ();
139 if (EFI_ERROR (Status)) {
140 goto Done;
141 }
142
143 //
144 // Report that the keyboard is being enabled
145 //
146 REPORT_STATUS_CODE (
147 EFI_PROGRESS_CODE,
148 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE
149 );
150
151 //
152 // Setup the WaitForKey event
153 //
154 Status = gBS->CreateEvent (
155 EVT_NOTIFY_WAIT,
156 TPL_NOTIFY,
157 VirtualKeyboardWaitForKey,
158 &(VirtualKeyboardPrivate->SimpleTextIn),
159 &((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey)
160 );
161 if (EFI_ERROR (Status)) {
162 (VirtualKeyboardPrivate->SimpleTextIn).WaitForKey = NULL;
163 goto Done;
164 }
165 Status = gBS->CreateEvent (
166 EVT_NOTIFY_WAIT,
167 TPL_NOTIFY,
168 VirtualKeyboardWaitForKeyEx,
169 &(VirtualKeyboardPrivate->SimpleTextInputEx),
170 &(VirtualKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx)
171 );
172 if (EFI_ERROR (Status)) {
173 VirtualKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx = NULL;
174 goto Done;
175 }
176
177 //
178 // Setup a periodic timer, used for reading keystrokes at a fixed interval
179 //
180 Status = gBS->CreateEvent (
181 EVT_TIMER | EVT_NOTIFY_SIGNAL,
182 TPL_NOTIFY,
183 VirtualKeyboardTimerHandler,
184 VirtualKeyboardPrivate,
185 &VirtualKeyboardPrivate->TimerEvent
186 );
187 if (EFI_ERROR (Status)) {
188 Status = EFI_OUT_OF_RESOURCES;
189 goto Done;
190 }
191
192 Status = gBS->SetTimer (
193 VirtualKeyboardPrivate->TimerEvent,
194 TimerPeriodic,
195 KEYBOARD_TIMER_INTERVAL
196 );
197 if (EFI_ERROR (Status)) {
198 Status = EFI_OUT_OF_RESOURCES;
199 goto Done;
200 }
201
202 Status = gBS->CreateEvent (
203 EVT_NOTIFY_SIGNAL,
204 TPL_CALLBACK,
205 KeyNotifyProcessHandler,
206 VirtualKeyboardPrivate,
207 &VirtualKeyboardPrivate->KeyNotifyProcessEvent
208 );
209 if (EFI_ERROR (Status)) {
210 Status = EFI_OUT_OF_RESOURCES;
211 goto Done;
212 }
213
214 //
215 // Reset the keyboard device
216 //
217 Status = VirtualKeyboardPrivate->SimpleTextInputEx.Reset (
218 &VirtualKeyboardPrivate->SimpleTextInputEx,
219 FALSE
220 );
221 if (EFI_ERROR (Status)) {
222 DEBUG ((DEBUG_ERROR, "[KBD]Reset Failed. Status - %r\n", Status));
223 goto Done;
224 }
225 //
226 // Install protocol interfaces for the keyboard device.
227 //
228 Status = gBS->InstallMultipleProtocolInterfaces (
229 &Controller,
230 &gEfiSimpleTextInProtocolGuid,
231 &VirtualKeyboardPrivate->SimpleTextIn,
232 &gEfiSimpleTextInputExProtocolGuid,
233 &VirtualKeyboardPrivate->SimpleTextInputEx,
234 NULL
235 );
236
237 Done:
238 if (EFI_ERROR (Status)) {
239 if (VirtualKeyboardPrivate != NULL) {
240 if ((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey != NULL) {
241 gBS->CloseEvent ((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey);
242 }
243
244 if ((VirtualKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) {
245 gBS->CloseEvent (
246 (VirtualKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx
247 );
248 }
249
250 if (VirtualKeyboardPrivate->KeyNotifyProcessEvent != NULL) {
251 gBS->CloseEvent (VirtualKeyboardPrivate->KeyNotifyProcessEvent);
252 }
253
254 VirtualKeyboardFreeNotifyList (&VirtualKeyboardPrivate->NotifyList);
255
256 if (VirtualKeyboardPrivate->TimerEvent != NULL) {
257 gBS->CloseEvent (VirtualKeyboardPrivate->TimerEvent);
258 }
259 FreePool (VirtualKeyboardPrivate);
260 }
261 }
262
263 gBS->CloseProtocol (
264 Controller,
265 &gPlatformVirtualKeyboardProtocolGuid,
266 This->DriverBindingHandle,
267 Controller
268 );
269
270 return Status;
271 }
272
273 /**
274 Stop the device handled by this driver.
275
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.
280
281 @retval EFI_SUCCESS The device was stopped.
282 @retval EFI_DEVICE_ERROR The device could not be stopped due to a
283 device error.
284 @retval Others Fail to uninstall protocols attached on the
285 device.
286
287 **/
288 EFI_STATUS
289 EFIAPI
290 VirtualKeyboardDriverBindingStop (
291 IN EFI_DRIVER_BINDING_PROTOCOL *This,
292 IN EFI_HANDLE Controller,
293 IN UINTN NumberOfChildren,
294 IN EFI_HANDLE *ChildHandleBuffer
295 )
296 {
297 return EFI_SUCCESS;
298 }
299
300
301 /**
302 Enqueue the key.
303
304 @param Queue The queue to be enqueued.
305 @param KeyData The key data to be enqueued.
306
307 @retval EFI_NOT_READY The queue is full.
308 @retval EFI_SUCCESS Successfully enqueued the key data.
309
310 **/
311 EFI_STATUS
312 Enqueue (
313 IN SIMPLE_QUEUE *Queue,
314 IN EFI_KEY_DATA *KeyData
315 )
316 {
317 if ((Queue->Rear + 1) % QUEUE_MAX_COUNT == Queue->Front) {
318 return EFI_NOT_READY;
319 }
320
321 CopyMem (&Queue->Buffer[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));
322 Queue->Rear = (Queue->Rear + 1) % QUEUE_MAX_COUNT;
323
324 return EFI_SUCCESS;
325 }
326
327 /**
328 Dequeue the key.
329
330 @param Queue The queue to be dequeued.
331 @param KeyData The key data to be dequeued.
332
333 @retval EFI_NOT_READY The queue is empty.
334 @retval EFI_SUCCESS Successfully dequeued the key data.
335
336 **/
337 EFI_STATUS
338 Dequeue (
339 IN SIMPLE_QUEUE *Queue,
340 IN EFI_KEY_DATA *KeyData
341 )
342 {
343 if (Queue->Front == Queue->Rear) {
344 return EFI_NOT_READY;
345 }
346
347 CopyMem (KeyData, &Queue->Buffer[Queue->Front], sizeof (EFI_KEY_DATA));
348 Queue->Front = (Queue->Front + 1) % QUEUE_MAX_COUNT;
349
350 return EFI_SUCCESS;
351 }
352
353 /**
354 Check whether the queue is empty.
355
356 @param Queue The queue to be checked.
357
358 @retval EFI_NOT_READY The queue is empty.
359 @retval EFI_SUCCESS The queue is not empty.
360
361 **/
362 EFI_STATUS
363 CheckQueue (
364 IN SIMPLE_QUEUE *Queue
365 )
366 {
367 if (Queue->Front == Queue->Rear) {
368 return EFI_NOT_READY;
369 }
370
371 return EFI_SUCCESS;
372 }
373
374 /**
375 Check key buffer to get the key stroke status.
376
377 @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.
378
379 @retval EFI_SUCCESS A key is being pressed now.
380 @retval Other No key is now pressed.
381
382 **/
383 EFI_STATUS
384 EFIAPI
385 VirtualKeyboardCheckForKey (
386 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This
387 )
388 {
389 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
390
391 VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
392
393 return CheckQueue (&VirtualKeyboardPrivate->Queue);
394 }
395
396 /**
397 Free keyboard notify list.
398
399 @param ListHead The list head
400
401 @retval EFI_SUCCESS Free the notify list successfully
402 @retval EFI_INVALID_PARAMETER ListHead is invalid.
403
404 **/
405 EFI_STATUS
406 VirtualKeyboardFreeNotifyList (
407 IN OUT LIST_ENTRY *ListHead
408 )
409 {
410 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
411
412 if (ListHead == NULL) {
413 return EFI_INVALID_PARAMETER;
414 }
415 while (!IsListEmpty (ListHead)) {
416 NotifyNode = CR (
417 ListHead->ForwardLink,
418 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
419 NotifyEntry,
420 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
421 );
422 RemoveEntryList (ListHead->ForwardLink);
423 gBS->FreePool (NotifyNode);
424 }
425
426 return EFI_SUCCESS;
427 }
428
429 /**
430 Judge whether is a registed key
431
432 @param RegsiteredData A pointer to a buffer that is filled in with
433 the keystroke state data for the key that was
434 registered.
435 @param InputData A pointer to a buffer that is filled in with
436 the keystroke state data for the key that was
437 pressed.
438
439 @retval TRUE Key be pressed matches a registered key.
440 @retval FLASE Match failed.
441
442 **/
443 BOOLEAN
444 IsKeyRegistered (
445 IN EFI_KEY_DATA *RegsiteredData,
446 IN EFI_KEY_DATA *InputData
447 )
448
449 {
450 ASSERT (RegsiteredData != NULL && InputData != NULL);
451
452 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||
453 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
454 return FALSE;
455 }
456
457 //
458 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means
459 // these state could be ignored.
460 //
461 if ((RegsiteredData->KeyState.KeyShiftState != 0) &&
462 (RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState)) {
463 return FALSE;
464 }
465 if ((RegsiteredData->KeyState.KeyToggleState != 0) &&
466 (RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState)) {
467 return FALSE;
468 }
469
470 return TRUE;
471
472 }
473
474 /**
475 Event notification function for SIMPLE_TEXT_IN.WaitForKey event
476 Signal the event if there is key available
477
478 @param Event the event object
479 @param Context waitting context
480
481 **/
482 VOID
483 EFIAPI
484 VirtualKeyboardWaitForKey (
485 IN EFI_EVENT Event,
486 IN VOID *Context
487 )
488 {
489 //
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
498 // input.
499 //
500 gBS->Stall (1000);
501 //
502 // Use TimerEvent callback function to check whether there's any key pressed
503 //
504 VirtualKeyboardTimerHandler (NULL, VIRTUAL_KEYBOARD_DEV_FROM_THIS (Context));
505
506 if (!EFI_ERROR (VirtualKeyboardCheckForKey (Context))) {
507 gBS->SignalEvent (Event);
508 }
509 }
510
511 /**
512 Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx
513 event. Signal the event if there is key available
514
515 @param Event event object
516 @param Context waiting context
517
518 **/
519 VOID
520 EFIAPI
521 VirtualKeyboardWaitForKeyEx (
522 IN EFI_EVENT Event,
523 IN VOID *Context
524 )
525
526 {
527 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
528
529 VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (Context);
530 VirtualKeyboardWaitForKey (Event, &VirtualKeyboardPrivate->SimpleTextIn);
531
532 }
533
534 //
535 // EFI Simple Text In Protocol Functions
536 //
537 /**
538 Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE)
539 then do some extra keyboard validations.
540
541 @param This Pointer of simple text Protocol.
542 @param ExtendedVerification Whether perform the extra validation of
543 keyboard. True: perform; FALSE: skip.
544
545 @retval EFI_SUCCESS The command byte is written successfully.
546 @retval EFI_DEVICE_ERROR Errors occurred during resetting keyboard.
547
548 **/
549 EFI_STATUS
550 EFIAPI
551 VirtualKeyboardReset (
552 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
553 IN BOOLEAN ExtendedVerification
554 )
555 {
556 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
557 EFI_STATUS Status;
558 EFI_TPL OldTpl;
559
560 VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
561
562 //
563 // Raise TPL to avoid mouse operation impact
564 //
565 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
566
567 if (VirtualKeyboardPrivate->PlatformVirtual &&
568 VirtualKeyboardPrivate->PlatformVirtual->Reset) {
569 Status = VirtualKeyboardPrivate->PlatformVirtual->Reset ();
570 } else {
571 Status = EFI_INVALID_PARAMETER;
572 }
573
574 //
575 // resume priority of task level
576 //
577 gBS->RestoreTPL (OldTpl);
578
579 return Status;
580 }
581
582 /**
583 Reset the input device and optionaly run diagnostics
584
585 @param This Protocol instance pointer.
586 @param ExtendedVerification Driver may perform diagnostics on reset.
587
588 @retval EFI_SUCCESS The device was reset.
589 @retval EFI_DEVICE_ERROR The device is not functioning properly and
590 could not be reset.
591
592 **/
593 EFI_STATUS
594 EFIAPI
595 VirtualKeyboardResetEx (
596 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
597 IN BOOLEAN ExtendedVerification
598 )
599 {
600 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
601 EFI_STATUS Status;
602 EFI_TPL OldTpl;
603
604 VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
605
606 Status = VirtualKeyboardPrivate->SimpleTextIn.Reset (
607 &VirtualKeyboardPrivate->SimpleTextIn,
608 ExtendedVerification
609 );
610 if (EFI_ERROR (Status)) {
611 return EFI_DEVICE_ERROR;
612 }
613
614 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
615
616 gBS->RestoreTPL (OldTpl);
617
618 return EFI_SUCCESS;
619
620 }
621
622 /**
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.
625
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
629 that was pressed.
630
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.
636
637 **/
638 EFI_STATUS
639 KeyboardReadKeyStrokeWorker (
640 IN VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate,
641 OUT EFI_KEY_DATA *KeyData
642 )
643 {
644 EFI_STATUS Status;
645 EFI_TPL OldTpl;
646 if (KeyData == NULL) {
647 return EFI_INVALID_PARAMETER;
648 }
649
650 //
651 // Use TimerEvent callback function to check whether there's any key pressed
652 //
653
654 //
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
663 // input.
664 //
665 gBS->Stall (1000);
666
667 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
668
669 VirtualKeyboardTimerHandler (NULL, VirtualKeyboardPrivate);
670 //
671 // If there's no key, just return
672 //
673 Status = CheckQueue (&VirtualKeyboardPrivate->Queue);
674 if (EFI_ERROR (Status)) {
675 gBS->RestoreTPL (OldTpl);
676 return EFI_NOT_READY;
677 }
678
679 Status = Dequeue (&VirtualKeyboardPrivate->Queue, KeyData);
680
681 gBS->RestoreTPL (OldTpl);
682
683 return EFI_SUCCESS;
684 }
685
686 /**
687 Read out the scan code of the key that has just been stroked.
688
689 @param This Pointer of simple text Protocol.
690 @param Key Pointer for store the key that read out.
691
692 @retval EFI_SUCCESS The key is read out successfully.
693 @retval other The key reading failed.
694
695 **/
696 EFI_STATUS
697 EFIAPI
698 VirtualKeyboardReadKeyStroke (
699 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
700 OUT EFI_INPUT_KEY *Key
701 )
702 {
703 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
704 EFI_STATUS Status;
705 EFI_KEY_DATA KeyData;
706
707 VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
708
709 Status = KeyboardReadKeyStrokeWorker (VirtualKeyboardPrivate, &KeyData);
710 if (EFI_ERROR (Status)) {
711 return Status;
712 }
713
714 //
715 // Convert the Ctrl+[a-z] to Ctrl+[1-26]
716 //
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);
724 }
725 }
726
727 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
728
729 return EFI_SUCCESS;
730 }
731
732 /**
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.
735
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.
739
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.
745
746 **/
747 EFI_STATUS
748 EFIAPI
749 VirtualKeyboardReadKeyStrokeEx (
750 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
751 OUT EFI_KEY_DATA *KeyData
752 )
753 {
754 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
755
756 if (KeyData == NULL) {
757 return EFI_INVALID_PARAMETER;
758 }
759
760 VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
761
762 return KeyboardReadKeyStrokeWorker (VirtualKeyboardPrivate, KeyData);
763
764 }
765
766 /**
767 Set certain state for the input device.
768
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.
772
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
777 its state.
778 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
779
780 **/
781 EFI_STATUS
782 EFIAPI
783 VirtualKeyboardSetState (
784 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
785 IN EFI_KEY_TOGGLE_STATE *KeyToggleState
786 )
787 {
788 if (KeyToggleState == NULL) {
789 return EFI_INVALID_PARAMETER;
790 }
791
792 return EFI_SUCCESS;
793 }
794
795 /**
796 Register a notification function for a particular keystroke for the
797 input device.
798
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
802 that was pressed.
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.
807
808
809 @retval EFI_SUCCESS The notification function was registered
810 successfully.
811 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary
812 data structures.
813 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
814
815 **/
816 EFI_STATUS
817 EFIAPI
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
823 )
824 {
825 EFI_STATUS Status;
826 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
827 EFI_TPL OldTpl;
828 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;
829 LIST_ENTRY *Link;
830 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
831
832 if (KeyData == NULL ||
833 NotifyHandle == NULL ||
834 KeyNotificationFunction == NULL) {
835 return EFI_INVALID_PARAMETER;
836 }
837
838 VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
839
840 //
841 // Enter critical section
842 //
843 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
844
845 //
846 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already
847 // registered.
848 //
849 for (Link = VirtualKeyboardPrivate->NotifyList.ForwardLink;
850 Link != &VirtualKeyboardPrivate->NotifyList;
851 Link = Link->ForwardLink) {
852 CurrentNotify = CR (
853 Link,
854 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
855 NotifyEntry,
856 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
857 );
858 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
859 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
860 *NotifyHandle = CurrentNotify;
861 Status = EFI_SUCCESS;
862 goto Exit;
863 }
864 }
865 }
866
867 //
868 // Allocate resource to save the notification function
869 //
870
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;
874 goto Exit;
875 }
876
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);
881
882 *NotifyHandle = NewNotify;
883 Status = EFI_SUCCESS;
884
885 Exit:
886 //
887 // Leave critical section and return
888 //
889 gBS->RestoreTPL (OldTpl);
890 return Status;
891
892 }
893
894 /**
895 Remove a registered notification function from a particular keystroke.
896
897 @param This Protocol instance pointer.
898 @param NotificationHandle The handle of the notification function
899 being unregistered.
900
901 @retval EFI_SUCCESS The notification function was unregistered
902 successfully.
903 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
904
905 **/
906 EFI_STATUS
907 EFIAPI
908 VirtualKeyboardUnregisterKeyNotify (
909 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
910 IN VOID *NotificationHandle
911 )
912 {
913 EFI_STATUS Status;
914 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
915 EFI_TPL OldTpl;
916 LIST_ENTRY *Link;
917 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
918
919 //
920 // Check incoming notification handle
921 //
922 if (NotificationHandle == NULL) {
923 return EFI_INVALID_PARAMETER;
924 }
925
926 if (((VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature !=
927 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE) {
928 return EFI_INVALID_PARAMETER;
929 }
930
931 VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
932
933 //
934 // Enter critical section
935 //
936 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
937
938 for (Link = VirtualKeyboardPrivate->NotifyList.ForwardLink;
939 Link != &VirtualKeyboardPrivate->NotifyList;
940 Link = Link->ForwardLink) {
941 CurrentNotify = CR (
942 Link,
943 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
944 NotifyEntry,
945 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
946 );
947 if (CurrentNotify == NotificationHandle) {
948 //
949 // Remove the notification function from NotifyList and free resources
950 //
951 RemoveEntryList (&CurrentNotify->NotifyEntry);
952
953 Status = EFI_SUCCESS;
954 goto Exit;
955 }
956 }
957
958 //
959 // Can not find the specified Notification Handle
960 //
961 Status = EFI_INVALID_PARAMETER;
962
963 Exit:
964 //
965 // Leave critical section and return
966 //
967 gBS->RestoreTPL (OldTpl);
968 return Status;
969 }
970
971 /**
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
977
978 @param Event The timer event
979 @param Context A KEYBOARD_CONSOLE_IN_DEV pointer
980
981 **/
982 VOID
983 EFIAPI
984 VirtualKeyboardTimerHandler (
985 IN EFI_EVENT Event,
986 IN VOID *Context
987 )
988 {
989 EFI_TPL OldTpl;
990 LIST_ENTRY *Link;
991 EFI_KEY_DATA KeyData;
992 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
993 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
994 VIRTUAL_KBD_KEY VirtualKey;
995
996 VirtualKeyboardPrivate = Context;
997
998 //
999 // Enter critical section
1000 //
1001 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1002
1003 if (VirtualKeyboardPrivate->PlatformVirtual &&
1004 VirtualKeyboardPrivate->PlatformVirtual->Query) {
1005 if (VirtualKeyboardPrivate->PlatformVirtual->Query (&VirtualKey) ==
1006 FALSE) {
1007 goto Exit;
1008 }
1009 // Found key
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);
1016 }
1017 } else {
1018 goto Exit;
1019 }
1020
1021 //
1022 // Signal KeyNotify process event if this key pressed matches any key registered.
1023 //
1024 for (Link = VirtualKeyboardPrivate->NotifyList.ForwardLink;
1025 Link != &VirtualKeyboardPrivate->NotifyList;
1026 Link = Link->ForwardLink) {
1027 CurrentNotify = CR (
1028 Link,
1029 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1030 NotifyEntry,
1031 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1032 );
1033 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
1034 //
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.
1038 //
1039 Enqueue (&VirtualKeyboardPrivate->QueueForNotify, &KeyData);
1040 gBS->SignalEvent (VirtualKeyboardPrivate->KeyNotifyProcessEvent);
1041 break;
1042 }
1043 }
1044
1045 Enqueue (&VirtualKeyboardPrivate->Queue, &KeyData);
1046
1047 Exit:
1048 //
1049 // Leave critical section and return
1050 //
1051 gBS->RestoreTPL (OldTpl);
1052 }
1053
1054 /**
1055 Process key notify.
1056
1057 @param Event Indicates the event that invoke this function.
1058 @param Context Indicates the calling context.
1059 **/
1060 VOID
1061 EFIAPI
1062 KeyNotifyProcessHandler (
1063 IN EFI_EVENT Event,
1064 IN VOID *Context
1065 )
1066 {
1067 EFI_STATUS Status;
1068 VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
1069 EFI_KEY_DATA KeyData;
1070 LIST_ENTRY *Link;
1071 LIST_ENTRY *NotifyList;
1072 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1073 EFI_TPL OldTpl;
1074
1075 VirtualKeyboardPrivate = (VIRTUAL_KEYBOARD_DEV *) Context;
1076
1077 //
1078 // Invoke notification functions.
1079 //
1080 NotifyList = &VirtualKeyboardPrivate->NotifyList;
1081 while (TRUE) {
1082 //
1083 // Enter critical section
1084 //
1085 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1086 Status = Dequeue (&VirtualKeyboardPrivate->QueueForNotify, &KeyData);
1087 //
1088 // Leave critical section
1089 //
1090 gBS->RestoreTPL (OldTpl);
1091 if (EFI_ERROR (Status)) {
1092 break;
1093 }
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,
1099 NotifyEntry,
1100 VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1101 );
1102 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
1103 CurrentNotify->KeyNotificationFn (&KeyData);
1104 }
1105 }
1106 }
1107 }
1108
1109 /**
1110 The user Entry Point for module VirtualKeyboard. The user code starts with
1111 this function.
1112
1113 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1114 @param[in] SystemTable A pointer to the EFI System Table.
1115
1116 @retval EFI_SUCCESS The entry point is executed successfully.
1117 @retval other Some error occurs when executing this entry point.
1118
1119 **/
1120 EFI_STATUS
1121 EFIAPI
1122 InitializeVirtualKeyboard(
1123 IN EFI_HANDLE ImageHandle,
1124 IN EFI_SYSTEM_TABLE *SystemTable
1125 )
1126 {
1127 EFI_STATUS Status;
1128
1129 //
1130 // Install driver model protocol(s).
1131 //
1132 Status = EfiLibInstallDriverBindingComponentName2 (
1133 ImageHandle,
1134 SystemTable,
1135 &gVirtualKeyboardDriverBinding,
1136 ImageHandle,
1137 &gVirtualKeyboardComponentName,
1138 &gVirtualKeyboardComponentName2
1139 );
1140 ASSERT_EFI_ERROR (Status);
1141
1142 return Status;
1143 }