1 /** @file
2 
3 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution.  The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8 
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 Module Name:
13 
14   WinNtGopInput.c
15 
16 Abstract:
17 
18   This file produces the Simple Text In for an Gop window.
19 
20   This stuff is linked at the hip to the Window, since the window
21   processing is done in a thread kicked off in WinNtGopImplementation.c
22 
23   Since the window information is processed in an other thread we need
24   a keyboard Queue to pass data about. The Simple Text In code just
25   takes data off the Queue. The WinProc message loop takes keyboard input
26   and places it in the Queue.
27 
28 
29 **/
30 
31 
32 #include "WinNtGop.h"
33 
34 
35 /**
36   TODO: Add function description
37 
38   @param  Private               TODO: add argument description
39 
40   @retval EFI_SUCCESS           TODO: Add description for return value
41 
42 **/
43 EFI_STATUS
GopPrivateCreateQ(IN GOP_PRIVATE_DATA * Private,IN GOP_QUEUE_FIXED * Queue)44 GopPrivateCreateQ (
45   IN  GOP_PRIVATE_DATA    *Private,
46   IN  GOP_QUEUE_FIXED     *Queue
47   )
48 {
49   Private->WinNtThunk->InitializeCriticalSection (&Queue->Cs);
50   Queue->Front = 0;
51   Queue->Rear  = 0;
52   return EFI_SUCCESS;
53 }
54 
55 
56 /**
57   TODO: Add function description
58 
59   @param  Private               TODO: add argument description
60 
61   @retval EFI_SUCCESS           TODO: Add description for return value
62 
63 **/
64 EFI_STATUS
GopPrivateDestroyQ(IN GOP_PRIVATE_DATA * Private,IN GOP_QUEUE_FIXED * Queue)65 GopPrivateDestroyQ (
66   IN  GOP_PRIVATE_DATA    *Private,
67   IN  GOP_QUEUE_FIXED     *Queue
68   )
69 {
70   Queue->Front = 0;
71   Queue->Rear  = 0;
72   Private->WinNtThunk->DeleteCriticalSection (&Queue->Cs);
73   return EFI_SUCCESS;
74 }
75 
76 
77 /**
78   TODO: Add function description
79 
80   @param  Private               TODO: add argument description
81   @param  Key                   TODO: add argument description
82 
83   @retval EFI_NOT_READY         TODO: Add description for return value
84   @retval EFI_SUCCESS           TODO: Add description for return value
85 
86 **/
87 EFI_STATUS
GopPrivateAddQ(IN GOP_PRIVATE_DATA * Private,IN GOP_QUEUE_FIXED * Queue,IN EFI_KEY_DATA * KeyData)88 GopPrivateAddQ (
89   IN GOP_PRIVATE_DATA     *Private,
90   IN GOP_QUEUE_FIXED      *Queue,
91   IN EFI_KEY_DATA         *KeyData
92   )
93 {
94   Private->WinNtThunk->EnterCriticalSection (&Queue->Cs);
95 
96   if ((Queue->Rear + 1) % MAX_Q == Queue->Front) {
97     Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);
98     return EFI_NOT_READY;
99   }
100 
101   CopyMem (&Queue->Q[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));
102   Queue->Rear           = (Queue->Rear + 1) % MAX_Q;
103 
104   Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);
105   return EFI_SUCCESS;
106 }
107 
108 
109 /**
110   TODO: Add function description
111 
112   @param  Private               TODO: add argument description
113   @param  Key                   TODO: add argument description
114 
115   @retval EFI_NOT_READY         TODO: Add description for return value
116   @retval EFI_SUCCESS           TODO: Add description for return value
117 
118 **/
119 EFI_STATUS
GopPrivateDeleteQ(IN GOP_PRIVATE_DATA * Private,IN GOP_QUEUE_FIXED * Queue,OUT EFI_KEY_DATA * Key)120 GopPrivateDeleteQ (
121   IN  GOP_PRIVATE_DATA    *Private,
122   IN  GOP_QUEUE_FIXED     *Queue,
123   OUT EFI_KEY_DATA        *Key
124   )
125 {
126   Private->WinNtThunk->EnterCriticalSection (&Queue->Cs);
127 
128   if (Queue->Front == Queue->Rear) {
129     Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);
130     return EFI_NOT_READY;
131   }
132 
133   CopyMem (Key, &Queue->Q[Queue->Front], sizeof (EFI_KEY_DATA));
134   Queue->Front  = (Queue->Front + 1) % MAX_Q;
135 
136   if (Key->Key.ScanCode == SCAN_NULL && Key->Key.UnicodeChar == CHAR_NULL) {
137     if (!Private->IsPartialKeySupport) {
138       //
139       // If partial keystrok is not enabled, don't return the partial keystroke.
140       //
141       Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);
142       ZeroMem (Key, sizeof (EFI_KEY_DATA));
143       return EFI_NOT_READY;
144     }
145   }
146   Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);
147   return EFI_SUCCESS;
148 }
149 
150 
151 /**
152   TODO: Add function description
153 
154   @param  Private               TODO: add argument description
155 
156   @retval EFI_NOT_READY         TODO: Add description for return value
157   @retval EFI_SUCCESS           TODO: Add description for return value
158 
159 **/
160 EFI_STATUS
GopPrivateCheckQ(IN GOP_QUEUE_FIXED * Queue)161 GopPrivateCheckQ (
162   IN  GOP_QUEUE_FIXED     *Queue
163   )
164 {
165   if (Queue->Front == Queue->Rear) {
166     return EFI_NOT_READY;
167   }
168 
169   return EFI_SUCCESS;
170 }
171 
172 BOOLEAN
GopPrivateIsKeyRegistered(IN EFI_KEY_DATA * RegsiteredData,IN EFI_KEY_DATA * InputData)173 GopPrivateIsKeyRegistered (
174   IN EFI_KEY_DATA  *RegsiteredData,
175   IN EFI_KEY_DATA  *InputData
176   )
177 /*++
178 
179 Routine Description:
180 
181 Arguments:
182 
183   RegsiteredData    - A pointer to a buffer that is filled in with the keystroke
184                       state data for the key that was registered.
185   InputData         - A pointer to a buffer that is filled in with the keystroke
186                       state data for the key that was pressed.
187 
188 Returns:
189   TRUE              - Key be pressed matches a registered key.
190   FLASE             - Match failed.
191 
192 --*/
193 {
194   ASSERT (RegsiteredData != NULL && InputData != NULL);
195 
196   if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
197       (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
198     return FALSE;
199   }
200 
201   //
202   // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
203   //
204   if (RegsiteredData->KeyState.KeyShiftState != 0 &&
205       RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
206     return FALSE;
207   }
208   if (RegsiteredData->KeyState.KeyToggleState != 0 &&
209       RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
210     return FALSE;
211   }
212 
213   return TRUE;
214 
215 }
216 
217 
218 VOID
GopPrivateInvokeRegisteredFunction(IN GOP_PRIVATE_DATA * Private,IN EFI_KEY_DATA * KeyData)219 GopPrivateInvokeRegisteredFunction (
220   IN GOP_PRIVATE_DATA                     *Private,
221   IN EFI_KEY_DATA                         *KeyData
222   )
223 /*++
224 
225 Routine Description:
226 
227   This function updates the status light of NumLock, ScrollLock and CapsLock.
228 
229 Arguments:
230 
231   Private       - The private structure of WinNt Gop device.
232   KeyData       - A pointer to a buffer that is filled in with the keystroke
233                   state data for the key that was pressed.
234 
235 Returns:
236 
237   EFI_SUCCESS   - The status light is updated successfully.
238 
239 --*/
240 {
241   LIST_ENTRY                          *Link;
242   WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY  *CurrentNotify;
243 
244   for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
245     CurrentNotify = CR (
246                       Link,
247                       WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY,
248                       NotifyEntry,
249                       WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE
250                       );
251     if (GopPrivateIsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
252       CurrentNotify->KeyNotificationFn (KeyData);
253     }
254   }
255 }
256 
257 VOID
WinNtGopSimpleTextInTimerHandler(IN EFI_EVENT Event,IN VOID * Context)258 WinNtGopSimpleTextInTimerHandler (
259   IN EFI_EVENT  Event,
260   IN VOID       *Context
261   )
262 {
263   GOP_PRIVATE_DATA  *Private;
264   EFI_KEY_DATA      KeyData;
265 
266   Private = (GOP_PRIVATE_DATA *)Context;
267   while (GopPrivateDeleteQ (Private, &Private->QueueForNotify, &KeyData) == EFI_SUCCESS) {
268     GopPrivateInvokeRegisteredFunction (Private, &KeyData);
269   }
270 }
271 
272 /**
273   TODO: Add function description
274 
275   @param  Private               TODO: add argument description
276   @param  Key                   TODO: add argument description
277 
278   @retval EFI_NOT_READY         TODO: Add description for return value
279   @retval EFI_SUCCESS           TODO: Add description for return value
280 
281 **/
282 EFI_STATUS
GopPrivateAddKey(IN GOP_PRIVATE_DATA * Private,IN EFI_INPUT_KEY Key)283 GopPrivateAddKey (
284   IN  GOP_PRIVATE_DATA    *Private,
285   IN  EFI_INPUT_KEY       Key
286   )
287 {
288   EFI_KEY_DATA            KeyData;
289 
290   KeyData.Key = Key;
291 
292   KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID;
293   KeyData.KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
294 
295   //
296   // Record Key shift state and toggle state
297   //
298   if (Private->LeftCtrl) {
299     KeyData.KeyState.KeyShiftState  |= EFI_LEFT_CONTROL_PRESSED;
300   }
301   if (Private->RightCtrl) {
302     KeyData.KeyState.KeyShiftState  |= EFI_RIGHT_CONTROL_PRESSED;
303   }
304   if (Private->LeftAlt) {
305     KeyData.KeyState.KeyShiftState  |= EFI_LEFT_ALT_PRESSED;
306   }
307   if (Private->RightAlt) {
308     KeyData.KeyState.KeyShiftState  |= EFI_RIGHT_ALT_PRESSED;
309   }
310   if (Private->LeftShift) {
311     KeyData.KeyState.KeyShiftState  |= EFI_LEFT_SHIFT_PRESSED;
312   }
313   if (Private->RightShift) {
314     KeyData.KeyState.KeyShiftState  |= EFI_RIGHT_SHIFT_PRESSED;
315   }
316   if (Private->LeftLogo) {
317     KeyData.KeyState.KeyShiftState  |= EFI_LEFT_LOGO_PRESSED;
318   }
319   if (Private->RightLogo) {
320     KeyData.KeyState.KeyShiftState  |= EFI_RIGHT_LOGO_PRESSED;
321   }
322   if (Private->Menu) {
323     KeyData.KeyState.KeyShiftState  |= EFI_MENU_KEY_PRESSED;
324   }
325   if (Private->SysReq) {
326     KeyData.KeyState.KeyShiftState  |= EFI_SYS_REQ_PRESSED;
327   }
328   if (Private->CapsLock) {
329     KeyData.KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;
330   }
331   if (Private->NumLock) {
332     KeyData.KeyState.KeyToggleState |= EFI_NUM_LOCK_ACTIVE;
333   }
334   if (Private->ScrollLock) {
335     KeyData.KeyState.KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;
336   }
337   if (Private->IsPartialKeySupport) {
338     KeyData.KeyState.KeyToggleState |= EFI_KEY_STATE_EXPOSED;
339   }
340 
341   //
342   // Convert Ctrl+[1-26] to Ctrl+[A-Z]
343   //
344   if ((Private->LeftCtrl || Private->RightCtrl) &&
345       (KeyData.Key.UnicodeChar >= 1) && (KeyData.Key.UnicodeChar <= 26)
346      ) {
347     if ((Private->LeftShift || Private->RightShift) == Private->CapsLock) {
348       KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar + L'a' - 1);
349     } else {
350       KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar + L'A' - 1);
351     }
352   }
353 
354   //
355   // Unmask the Shift bit for printable char
356   //
357   if (((KeyData.Key.UnicodeChar >= L'a') && (KeyData.Key.UnicodeChar <= L'z')) ||
358       ((KeyData.Key.UnicodeChar >= L'A') && (KeyData.Key.UnicodeChar <= L'Z'))
359      ) {
360     KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);
361   }
362 
363   GopPrivateAddQ (Private, &Private->QueueForNotify, &KeyData);
364 
365   GopPrivateAddQ (Private, &Private->QueueForRead, &KeyData);
366 
367   return EFI_SUCCESS;
368 }
369 
370 EFI_STATUS
GopPrivateUpdateStatusLight(IN GOP_PRIVATE_DATA * Private)371 GopPrivateUpdateStatusLight (
372   IN GOP_PRIVATE_DATA                     *Private
373   )
374 /*++
375 
376 Routine Description:
377 
378   This function updates the status light of NumLock, ScrollLock and CapsLock.
379 
380 Arguments:
381 
382   Private       - The private structure of WinNt console In/Out.
383 
384 Returns:
385 
386   EFI_SUCCESS   - The status light is updated successfully.
387 
388 --*/
389 {
390   //
391   // BUGBUG:Only SendInput/keybd_event function can toggle
392   // NumLock, CapsLock and ScrollLock keys.
393   // Neither of these functions is included in EFI_WIN_NT_THUNK_PROTOCOL.
394   // Thus, return immediately without operation.
395   //
396   return EFI_SUCCESS;
397 
398 }
399 
400 
401 EFI_STATUS
GopPrivateResetWorker(IN GOP_PRIVATE_DATA * Private)402 GopPrivateResetWorker (
403   IN GOP_PRIVATE_DATA                     *Private
404   )
405 /*++
406 
407 Routine Description:
408 
409   This function is a worker function for SimpleTextIn/SimpleTextInEx.Reset().
410 
411 Arguments:
412 
413   Private     - WinNT GOP private structure
414 
415 Returns:
416 
417   EFI_SUCCESS - Reset successfully
418 
419 --*/
420 {
421   EFI_KEY_DATA      KeyData;
422   EFI_TPL           OldTpl;
423 
424   //
425   // Enter critical section
426   //
427   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
428 
429   //
430   // A reset is draining the Queue
431   //
432   while (GopPrivateDeleteQ (Private, &Private->QueueForRead, &KeyData) == EFI_SUCCESS)
433     ;
434   while (GopPrivateDeleteQ (Private, &Private->QueueForNotify, &KeyData) == EFI_SUCCESS)
435     ;
436 
437   Private->LeftShift               = FALSE;
438   Private->RightShift              = FALSE;
439   Private->LeftAlt                 = FALSE;
440   Private->RightAlt                = FALSE;
441   Private->LeftCtrl                = FALSE;
442   Private->RightCtrl               = FALSE;
443   Private->LeftLogo                = FALSE;
444   Private->RightLogo               = FALSE;
445   Private->Menu                    = FALSE;
446   Private->SysReq                  = FALSE;
447 
448   Private->CapsLock                = FALSE;
449   Private->NumLock                 = FALSE;
450   Private->ScrollLock              = FALSE;
451   Private->IsPartialKeySupport     = FALSE;
452 
453   Private->KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID;
454   Private->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
455 
456   //
457   // Leave critical section and return
458   //
459   gBS->RestoreTPL (OldTpl);
460 
461   return EFI_SUCCESS;
462 }
463 
464 EFI_STATUS
GopPrivateReadKeyStrokeWorker(IN GOP_PRIVATE_DATA * Private,OUT EFI_KEY_DATA * KeyData)465 GopPrivateReadKeyStrokeWorker (
466   IN GOP_PRIVATE_DATA                   *Private,
467   OUT EFI_KEY_DATA                      *KeyData
468   )
469 /*++
470 
471   Routine Description:
472     Reads the next keystroke from the input device. The WaitForKey Event can
473     be used to test for existance of a keystroke via WaitForEvent () call.
474 
475   Arguments:
476     Private    - The private structure of WinNt Gop device.
477     KeyData    - A pointer to a buffer that is filled in with the keystroke
478                  state data for the key that was pressed.
479 
480   Returns:
481     EFI_SUCCESS           - The keystroke information was returned.
482     EFI_NOT_READY         - There was no keystroke data availiable.
483     EFI_DEVICE_ERROR      - The keystroke information was not returned due to
484                             hardware errors.
485     EFI_INVALID_PARAMETER - KeyData is NULL.
486 
487 --*/
488 {
489   EFI_STATUS                      Status;
490   EFI_TPL                         OldTpl;
491 
492   if (KeyData == NULL) {
493     return EFI_INVALID_PARAMETER;
494   }
495 
496   //
497   // Enter critical section
498   //
499   OldTpl  = gBS->RaiseTPL (TPL_NOTIFY);
500 
501   //
502   // Call hot key callback before telling caller there is a key available
503   //
504   WinNtGopSimpleTextInTimerHandler (NULL, Private);
505 
506   Status  = GopPrivateCheckQ (&Private->QueueForRead);
507   if (!EFI_ERROR (Status)) {
508     //
509     // If a Key press exists try and read it.
510     //
511     Status = GopPrivateDeleteQ (Private, &Private->QueueForRead, KeyData);
512     if (!EFI_ERROR (Status)) {
513       //
514       // If partial keystroke is not enabled, check whether it is value key. If not return
515       // EFI_NOT_READY.
516       //
517       if (!Private->IsPartialKeySupport) {
518         if (KeyData->Key.ScanCode == SCAN_NULL && KeyData->Key.UnicodeChar == CHAR_NULL) {
519           Status = EFI_NOT_READY;
520         }
521       }
522     }
523   }
524 
525   //
526   // Leave critical section and return
527   //
528   gBS->RestoreTPL (OldTpl);
529 
530   return Status;
531 
532 }
533 
534 
535 //
536 // Simple Text In implementation.
537 //
538 
539 
540 /**
541   TODO: Add function description
542 
543   @param  This                  TODO: add argument description
544   @param  ExtendedVerification  TODO: add argument description
545 
546   @retval EFI_SUCCESS           TODO: Add description for return value
547 
548 **/
549 EFI_STATUS
550 EFIAPI
WinNtGopSimpleTextInReset(IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL * This,IN BOOLEAN ExtendedVerification)551 WinNtGopSimpleTextInReset (
552   IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL          *This,
553   IN BOOLEAN                              ExtendedVerification
554   )
555 {
556   GOP_PRIVATE_DATA  *Private;
557 
558   Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_THIS (This);
559 
560   return GopPrivateResetWorker (Private);
561 }
562 
563 
564 /**
565   TODO: Add function description
566 
567   @param  This                  TODO: add argument description
568   @param  Key                   TODO: add argument description
569 
570   @return TODO: add return values
571 
572 **/
573 EFI_STATUS
574 EFIAPI
WinNtGopSimpleTextInReadKeyStroke(IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL * This,OUT EFI_INPUT_KEY * Key)575 WinNtGopSimpleTextInReadKeyStroke (
576   IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL          *This,
577   OUT EFI_INPUT_KEY                       *Key
578   )
579 {
580   GOP_PRIVATE_DATA  *Private;
581   EFI_STATUS        Status;
582   EFI_KEY_DATA      KeyData;
583 
584   Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_THIS (This);
585   //
586   // Considering if the partial keystroke is enabled, there maybe a partial
587   // keystroke in the queue, so here skip the partial keystroke and get the
588   // next key from the queue
589   //
590   while (1) {
591     Status = GopPrivateReadKeyStrokeWorker (Private, &KeyData);
592     if (EFI_ERROR (Status)) {
593       return Status;
594     }
595     if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
596       continue;
597     }
598     //
599     // Convert Ctrl+[A-Z] to Ctrl+[1-26]
600     //
601     if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
602       if ((KeyData.Key.UnicodeChar >= L'a') && (KeyData.Key.UnicodeChar <= L'z')) {
603         KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);
604       } else if ((KeyData.Key.UnicodeChar >= L'A') && (KeyData.Key.UnicodeChar <= L'Z')) {
605         KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);
606       }
607     }
608     CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
609     return EFI_SUCCESS;
610   }
611 }
612 
613 
614 /**
615   TODO: Add function description
616 
617   @param  Event                 TODO: add argument description
618   @param  Context               TODO: add argument description
619 
620   @return TODO: add return values
621 
622 **/
623 VOID
624 EFIAPI
WinNtGopSimpleTextInWaitForKey(IN EFI_EVENT Event,IN VOID * Context)625 WinNtGopSimpleTextInWaitForKey (
626   IN EFI_EVENT          Event,
627   IN VOID               *Context
628   )
629 {
630   GOP_PRIVATE_DATA  *Private;
631   EFI_STATUS        Status;
632   EFI_TPL           OldTpl;
633   EFI_KEY_DATA      KeyData;
634 
635   Private = (GOP_PRIVATE_DATA *) Context;
636 
637   //
638   // Enter critical section
639   //
640   OldTpl  = gBS->RaiseTPL (TPL_NOTIFY);
641 
642   //
643   // Call hot key callback before telling caller there is a key available
644   //
645   WinNtGopSimpleTextInTimerHandler (NULL, Private);
646 
647   //
648   // WaitforKey doesn't suppor the partial key.
649   // Considering if the partial keystroke is enabled, there maybe a partial
650   // keystroke in the queue, so here skip the partial keystroke and get the
651   // next key from the queue
652   //
653   while (1) {
654     Status  = GopPrivateCheckQ (&Private->QueueForRead);
655     if (!EFI_ERROR (Status)) {
656       //
657       // If a there is a key in the queue and it is not partial keystroke,  signal event.
658       //
659       if (Private->QueueForRead.Q[Private->QueueForRead.Front].Key.ScanCode == SCAN_NULL &&
660         Private->QueueForRead.Q[Private->QueueForRead.Front].Key.UnicodeChar == CHAR_NULL) {
661         GopPrivateDeleteQ (Private,&Private->QueueForRead,&KeyData);
662         continue;
663       }
664       gBS->SignalEvent (Event);
665     } else {
666       //
667       // We need to sleep or NT will schedule this thread with such high
668       // priority that WinProc thread will never run and we will not see
669       // keyboard input. This Sleep makes the syste run 10x faster, so don't
670       // remove it.
671       //
672       Private->WinNtThunk->Sleep (1);
673     }
674     break;
675   }
676 
677   //
678   // Leave critical section and return
679   //
680   gBS->RestoreTPL (OldTpl);
681 }
682 
683 //
684 // Simple Text Input Ex protocol functions
685 //
686 
687 EFI_STATUS
688 EFIAPI
WinNtGopSimpleTextInExResetEx(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN BOOLEAN ExtendedVerification)689 WinNtGopSimpleTextInExResetEx (
690   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
691   IN BOOLEAN                            ExtendedVerification
692   )
693 /*++
694 
695   Routine Description:
696     Reset the input device and optionaly run diagnostics
697 
698   Arguments:
699     This                 - Protocol instance pointer.
700     ExtendedVerification - Driver may perform diagnostics on reset.
701 
702   Returns:
703     EFI_SUCCESS           - The device was reset.
704 
705 --*/
706 {
707   GOP_PRIVATE_DATA *Private;
708 
709   Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);
710 
711   return GopPrivateResetWorker (Private);
712 }
713 
714 EFI_STATUS
715 EFIAPI
WinNtGopSimpleTextInExReadKeyStrokeEx(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,OUT EFI_KEY_DATA * KeyData)716 WinNtGopSimpleTextInExReadKeyStrokeEx (
717   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
718   OUT EFI_KEY_DATA                      *KeyData
719   )
720 /*++
721 
722   Routine Description:
723     Reads the next keystroke from the input device. The WaitForKey Event can
724     be used to test for existance of a keystroke via WaitForEvent () call.
725 
726   Arguments:
727     This       - Protocol instance pointer.
728     KeyData    - A pointer to a buffer that is filled in with the keystroke
729                  state data for the key that was pressed.
730 
731   Returns:
732     EFI_SUCCESS           - The keystroke information was returned.
733     EFI_NOT_READY         - There was no keystroke data availiable.
734     EFI_DEVICE_ERROR      - The keystroke information was not returned due to
735                             hardware errors.
736     EFI_INVALID_PARAMETER - KeyData is NULL.
737 
738 --*/
739 {
740   GOP_PRIVATE_DATA *Private;
741 
742   if (KeyData == NULL) {
743     return EFI_INVALID_PARAMETER;
744   }
745 
746   Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);
747 
748   return GopPrivateReadKeyStrokeWorker (Private, KeyData);
749 
750 }
751 
752 EFI_STATUS
753 EFIAPI
WinNtGopSimpleTextInExSetState(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN EFI_KEY_TOGGLE_STATE * KeyToggleState)754 WinNtGopSimpleTextInExSetState (
755   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
756   IN EFI_KEY_TOGGLE_STATE               *KeyToggleState
757   )
758 /*++
759 
760   Routine Description:
761     Set certain state for the input device.
762 
763   Arguments:
764     This                  - Protocol instance pointer.
765     KeyToggleState        - A pointer to the EFI_KEY_TOGGLE_STATE to set the
766                             state for the input device.
767 
768   Returns:
769     EFI_SUCCESS           - The device state was set successfully.
770     EFI_DEVICE_ERROR      - The device is not functioning correctly and could
771                             not have the setting adjusted.
772     EFI_UNSUPPORTED       - The device does not have the ability to set its state.
773     EFI_INVALID_PARAMETER - KeyToggleState is NULL.
774 
775 --*/
776 {
777   EFI_STATUS                      Status;
778   GOP_PRIVATE_DATA                *Private;
779 
780   if (KeyToggleState == NULL) {
781     return EFI_INVALID_PARAMETER;
782   }
783 
784   Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);
785 
786   if (((Private->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) ||
787       ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) {
788     return EFI_UNSUPPORTED;
789   }
790 
791   Private->ScrollLock          = FALSE;
792   Private->NumLock             = FALSE;
793   Private->CapsLock            = FALSE;
794   Private->IsPartialKeySupport = FALSE;
795 
796   if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
797     Private->ScrollLock = TRUE;
798   }
799   if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
800     Private->NumLock = TRUE;
801   }
802   if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
803     Private->CapsLock = TRUE;
804   }
805   if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {
806     Private->IsPartialKeySupport = TRUE;
807   }
808 
809   Status = GopPrivateUpdateStatusLight (Private);
810   if (EFI_ERROR (Status)) {
811     return EFI_DEVICE_ERROR;
812   }
813 
814   Private->KeyState.KeyToggleState = *KeyToggleState;
815   return EFI_SUCCESS;
816 
817 }
818 
819 EFI_STATUS
820 EFIAPI
WinNtGopSimpleTextInExRegisterKeyNotify(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN EFI_KEY_DATA * KeyData,IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,OUT VOID ** NotifyHandle)821 WinNtGopSimpleTextInExRegisterKeyNotify (
822   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
823   IN EFI_KEY_DATA                       *KeyData,
824   IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,
825   OUT VOID                              **NotifyHandle
826   )
827 /*++
828 
829   Routine Description:
830     Register a notification function for a particular keystroke for the input device.
831 
832   Arguments:
833     This                    - Protocol instance pointer.
834     KeyData                 - A pointer to a buffer that is filled in with the keystroke
835                               information data for the key that was pressed.
836     KeyNotificationFunction - Points to the function to be called when the key
837                               sequence is typed specified by KeyData.
838     NotifyHandle            - Points to the unique handle assigned to the registered notification.
839 
840   Returns:
841     EFI_SUCCESS             - The notification function was registered successfully.
842     EFI_OUT_OF_RESOURCES    - Unable to allocate resources for necesssary data structures.
843     EFI_INVALID_PARAMETER   - KeyData or NotifyHandle is NULL.
844 
845 --*/
846 {
847   GOP_PRIVATE_DATA                   *Private;
848   WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *CurrentNotify;
849   LIST_ENTRY                         *Link;
850   WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *NewNotify;
851 
852   if (KeyData == NULL || KeyNotificationFunction == NULL || NotifyHandle == NULL) {
853     return EFI_INVALID_PARAMETER;
854   }
855 
856   Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);
857 
858   //
859   // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
860   //
861   for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
862     CurrentNotify = CR (
863                       Link,
864                       WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY,
865                       NotifyEntry,
866                       WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE
867                       );
868     if (GopPrivateIsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
869       if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
870         *NotifyHandle = CurrentNotify;
871         return EFI_SUCCESS;
872       }
873     }
874   }
875 
876   //
877   // Allocate resource to save the notification function
878   //
879   NewNotify = (WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *) AllocateZeroPool (sizeof (WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY));
880   if (NewNotify == NULL) {
881     return EFI_OUT_OF_RESOURCES;
882   }
883 
884   NewNotify->Signature         = WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE;
885   NewNotify->KeyNotificationFn = KeyNotificationFunction;
886   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
887   InsertTailList (&Private->NotifyList, &NewNotify->NotifyEntry);
888 
889   *NotifyHandle = NewNotify;
890 
891   return EFI_SUCCESS;
892 
893 }
894 
895 EFI_STATUS
896 EFIAPI
WinNtGopSimpleTextInExUnregisterKeyNotify(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN VOID * NotificationHandle)897 WinNtGopSimpleTextInExUnregisterKeyNotify (
898   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
899   IN VOID                               *NotificationHandle
900   )
901 /*++
902 
903   Routine Description:
904     Remove a registered notification function from a particular keystroke.
905 
906   Arguments:
907     This                    - Protocol instance pointer.
908     NotificationHandle      - The handle of the notification function being unregistered.
909 
910   Returns:
911     EFI_SUCCESS             - The notification function was unregistered successfully.
912     EFI_INVALID_PARAMETER   - The NotificationHandle is invalid.
913 
914 --*/
915 {
916   GOP_PRIVATE_DATA                   *Private;
917   LIST_ENTRY                         *Link;
918   WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *CurrentNotify;
919 
920   if (NotificationHandle == NULL) {
921     return EFI_INVALID_PARAMETER;
922   }
923 
924   Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);
925 
926   for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
927     CurrentNotify = CR (
928                       Link,
929                       WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY,
930                       NotifyEntry,
931                       WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE
932                       );
933     if (CurrentNotify == NotificationHandle) {
934       //
935       // Remove the notification function from NotifyList and free resources
936       //
937       RemoveEntryList (&CurrentNotify->NotifyEntry);
938 
939       gBS->FreePool (CurrentNotify);
940       return EFI_SUCCESS;
941     }
942   }
943 
944   //
945   // Can not find the specified Notification Handle
946   //
947   return EFI_INVALID_PARAMETER;
948 }
949 
950 
951 /**
952   TODO: Add function description
953 
954   @param  Private               TODO: add argument description
955 
956   @return TODO: add return values
957 
958 **/
959 EFI_STATUS
WinNtGopInitializeSimpleTextInForWindow(IN GOP_PRIVATE_DATA * Private)960 WinNtGopInitializeSimpleTextInForWindow (
961   IN  GOP_PRIVATE_DATA    *Private
962   )
963 {
964   EFI_STATUS  Status;
965 
966   GopPrivateCreateQ (Private, &Private->QueueForRead);
967   GopPrivateCreateQ (Private, &Private->QueueForNotify);
968 
969   //
970   // Initialize Simple Text In protoocol
971   //
972   Private->SimpleTextIn.Reset         = WinNtGopSimpleTextInReset;
973   Private->SimpleTextIn.ReadKeyStroke = WinNtGopSimpleTextInReadKeyStroke;
974 
975   Status = gBS->CreateEvent (
976                   EVT_NOTIFY_WAIT,
977                   TPL_NOTIFY,
978                   WinNtGopSimpleTextInWaitForKey,
979                   Private,
980                   &Private->SimpleTextIn.WaitForKey
981                   );
982 
983 
984   Private->SimpleTextInEx.Reset               = WinNtGopSimpleTextInExResetEx;
985   Private->SimpleTextInEx.ReadKeyStrokeEx     = WinNtGopSimpleTextInExReadKeyStrokeEx;
986   Private->SimpleTextInEx.SetState            = WinNtGopSimpleTextInExSetState;
987   Private->SimpleTextInEx.RegisterKeyNotify   = WinNtGopSimpleTextInExRegisterKeyNotify;
988   Private->SimpleTextInEx.UnregisterKeyNotify = WinNtGopSimpleTextInExUnregisterKeyNotify;
989 
990   Private->SimpleTextInEx.Reset (&Private->SimpleTextInEx, FALSE);
991 
992   InitializeListHead (&Private->NotifyList);
993 
994   Status = gBS->CreateEvent (
995                   EVT_NOTIFY_WAIT,
996                   TPL_NOTIFY,
997                   WinNtGopSimpleTextInWaitForKey,
998                   Private,
999                   &Private->SimpleTextInEx.WaitForKeyEx
1000                   );
1001   ASSERT_EFI_ERROR (Status);
1002 
1003   //
1004   // Create the Timer to trigger hot key notifications
1005   //
1006   Status = gBS->CreateEvent (
1007                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
1008                   TPL_NOTIFY,
1009                   WinNtGopSimpleTextInTimerHandler,
1010                   Private,
1011                   &Private->TimerEvent
1012                   );
1013   ASSERT_EFI_ERROR (Status);
1014 
1015   Status = gBS->SetTimer (
1016                   Private->TimerEvent,
1017                   TimerPeriodic,
1018                   KEYBOARD_TIMER_INTERVAL
1019                   );
1020   ASSERT_EFI_ERROR (Status);
1021 
1022   return Status;
1023 }
1024 
1025 
1026 
1027 /**
1028   TODO: Add function description
1029 
1030   @param  Private               TODO: add argument description
1031 
1032   @retval EFI_SUCCESS           TODO: Add description for return value
1033 
1034 **/
1035 EFI_STATUS
WinNtGopDestroySimpleTextInForWindow(IN GOP_PRIVATE_DATA * Private)1036 WinNtGopDestroySimpleTextInForWindow (
1037   IN  GOP_PRIVATE_DATA    *Private
1038   )
1039 {
1040   gBS->CloseEvent (Private->TimerEvent);
1041 
1042   GopPrivateDestroyQ (Private, &Private->QueueForRead);
1043   GopPrivateDestroyQ (Private, &Private->QueueForNotify);
1044 
1045   return EFI_SUCCESS;
1046 }
1047