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