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