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