1 /** @file
2   Routines implements SIMPLE_TEXT_IN protocol's interfaces based on 8042 interfaces
3   provided by Ps2KbdCtrller.c.
4 
5 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 
17 #include "Ps2Keyboard.h"
18 
19 /**
20   Check whether the EFI key buffer is empty.
21 
22   @param Queue     Pointer to instance of EFI_KEY_QUEUE.
23 
24   @retval TRUE    The EFI key buffer is empty.
25   @retval FALSE   The EFI key buffer isn't empty.
26 **/
27 BOOLEAN
IsEfikeyBufEmpty(IN EFI_KEY_QUEUE * Queue)28 IsEfikeyBufEmpty (
29   IN  EFI_KEY_QUEUE         *Queue
30   )
31 {
32   return (BOOLEAN) (Queue->Head == Queue->Tail);
33 }
34 
35 /**
36   Read & remove one key data from the EFI key buffer.
37 
38   @param Queue     Pointer to instance of EFI_KEY_QUEUE.
39   @param KeyData   Receive the key data.
40 
41   @retval EFI_SUCCESS   The key data is popped successfully.
42   @retval EFI_NOT_READY There is no key data available.
43 **/
44 EFI_STATUS
PopEfikeyBufHead(IN EFI_KEY_QUEUE * Queue,OUT EFI_KEY_DATA * KeyData OPTIONAL)45 PopEfikeyBufHead (
46   IN  EFI_KEY_QUEUE         *Queue,
47   OUT EFI_KEY_DATA          *KeyData OPTIONAL
48   )
49 {
50   if (IsEfikeyBufEmpty (Queue)) {
51     return EFI_NOT_READY;
52   }
53   //
54   // Retrieve and remove the values
55   //
56   if (KeyData != NULL) {
57     CopyMem (KeyData, &Queue->Buffer[Queue->Head], sizeof (EFI_KEY_DATA));
58   }
59   Queue->Head = (Queue->Head + 1) % KEYBOARD_EFI_KEY_MAX_COUNT;
60   return EFI_SUCCESS;
61 }
62 
63 /**
64   Push one key data to the EFI key buffer.
65 
66   @param Queue     Pointer to instance of EFI_KEY_QUEUE.
67   @param KeyData   The key data to push.
68 **/
69 VOID
PushEfikeyBufTail(IN EFI_KEY_QUEUE * Queue,IN EFI_KEY_DATA * KeyData)70 PushEfikeyBufTail (
71   IN  EFI_KEY_QUEUE         *Queue,
72   IN  EFI_KEY_DATA          *KeyData
73   )
74 {
75   if ((Queue->Tail + 1) % KEYBOARD_EFI_KEY_MAX_COUNT == Queue->Head) {
76     //
77     // If Queue is full, pop the one from head.
78     //
79     PopEfikeyBufHead (Queue, NULL);
80   }
81   CopyMem (&Queue->Buffer[Queue->Tail], KeyData, sizeof (EFI_KEY_DATA));
82   Queue->Tail = (Queue->Tail + 1) % KEYBOARD_EFI_KEY_MAX_COUNT;
83 }
84 
85 /**
86   Judge whether is a registed key
87 
88   @param RegsiteredData       A pointer to a buffer that is filled in with the keystroke
89                               state data for the key that was registered.
90   @param InputData            A pointer to a buffer that is filled in with the keystroke
91                               state data for the key that was pressed.
92 
93   @retval TRUE                Key be pressed matches a registered key.
94   @retval FLASE               Match failed.
95 
96 **/
97 BOOLEAN
IsKeyRegistered(IN EFI_KEY_DATA * RegsiteredData,IN EFI_KEY_DATA * InputData)98 IsKeyRegistered (
99   IN EFI_KEY_DATA  *RegsiteredData,
100   IN EFI_KEY_DATA  *InputData
101   )
102 
103 {
104   ASSERT (RegsiteredData != NULL && InputData != NULL);
105 
106   if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
107       (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
108     return FALSE;
109   }
110 
111   //
112   // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
113   //
114   if (RegsiteredData->KeyState.KeyShiftState != 0 &&
115       RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
116     return FALSE;
117   }
118   if (RegsiteredData->KeyState.KeyToggleState != 0 &&
119       RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
120     return FALSE;
121   }
122 
123   return TRUE;
124 
125 }
126 
127 /**
128     Reads the next keystroke from the input device. The WaitForKey Event can
129     be used to test for existance of a keystroke via WaitForEvent () call.
130 
131     @param ConsoleInDev          Ps2 Keyboard private structure
132     @param KeyData               A pointer to a buffer that is filled in with the keystroke
133                                  state data for the key that was pressed.
134 
135 
136     @retval EFI_SUCCESS             The keystroke information was returned.
137     @retval EFI_NOT_READY           There was no keystroke data availiable.
138     @retval EFI_DEVICE_ERROR        The keystroke information was not returned due to
139                                     hardware errors.
140     @retval EFI_INVALID_PARAMETER   KeyData is NULL.
141 
142 **/
143 EFI_STATUS
KeyboardReadKeyStrokeWorker(IN KEYBOARD_CONSOLE_IN_DEV * ConsoleInDev,OUT EFI_KEY_DATA * KeyData)144 KeyboardReadKeyStrokeWorker (
145   IN  KEYBOARD_CONSOLE_IN_DEV           *ConsoleInDev,
146   OUT EFI_KEY_DATA                      *KeyData
147   )
148 
149 {
150   EFI_STATUS                            Status;
151   EFI_TPL                               OldTpl;
152 
153   if (KeyData == NULL) {
154     return EFI_INVALID_PARAMETER;
155   }
156 
157   //
158   // Enter critical section
159   //
160   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
161 
162   KeyboardTimerHandler (NULL, ConsoleInDev);
163 
164   if (ConsoleInDev->KeyboardErr) {
165     Status = EFI_DEVICE_ERROR;
166   } else {
167     Status = PopEfikeyBufHead (&ConsoleInDev->EfiKeyQueue, KeyData);
168   }
169 
170   gBS->RestoreTPL (OldTpl);
171   return Status;
172 }
173 
174 /**
175   Perform 8042 controller and keyboard initialization which implement SIMPLE_TEXT_IN.Reset()
176 
177   @param This                 Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
178   @param ExtendedVerification Indicate that the driver may perform a more
179                               exhaustive verification operation of the device during
180                               reset, now this par is ignored in this driver
181 
182 **/
183 EFI_STATUS
184 EFIAPI
KeyboardEfiReset(IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL * This,IN BOOLEAN ExtendedVerification)185 KeyboardEfiReset (
186   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
187   IN  BOOLEAN                         ExtendedVerification
188   )
189 {
190   EFI_STATUS              Status;
191   KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
192   EFI_TPL                 OldTpl;
193 
194   ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
195   if (ConsoleIn->KeyboardErr) {
196     return EFI_DEVICE_ERROR;
197   }
198 
199   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
200     EFI_PROGRESS_CODE,
201     EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET,
202     ConsoleIn->DevicePath
203     );
204 
205   //
206   // Enter critical section
207   //
208   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
209 
210   //
211   // Call InitKeyboard to initialize the keyboard
212   //
213   Status = InitKeyboard (ConsoleIn, ExtendedVerification);
214   if (EFI_ERROR (Status)) {
215     //
216     // Leave critical section and return
217     //
218     gBS->RestoreTPL (OldTpl);
219     return EFI_DEVICE_ERROR;
220   }
221 
222   //
223   // Leave critical section and return
224   //
225   gBS->RestoreTPL (OldTpl);
226 
227   //
228   // Report the status If a stuck key was detected
229   //
230   if (KeyReadStatusRegister (ConsoleIn) & 0x01) {
231     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
232       EFI_ERROR_CODE | EFI_ERROR_MINOR,
233       EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_EC_STUCK_KEY,
234       ConsoleIn->DevicePath
235       );
236   }
237   //
238   // Report the status If keyboard is locked
239   //
240   if ((KeyReadStatusRegister (ConsoleIn) & 0x10) == 0) {
241     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
242       EFI_ERROR_CODE | EFI_ERROR_MINOR,
243       EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_EC_LOCKED,
244       ConsoleIn->DevicePath
245       );
246   }
247 
248   return EFI_SUCCESS;
249 }
250 
251 /**
252   Retrieve key values for driver user which implement SIMPLE_TEXT_IN.ReadKeyStroke().
253 
254   @param This    Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
255   @param Key     The output buffer for key value
256 
257   @retval EFI_SUCCESS success to read key stroke
258 **/
259 EFI_STATUS
260 EFIAPI
KeyboardReadKeyStroke(IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL * This,OUT EFI_INPUT_KEY * Key)261 KeyboardReadKeyStroke (
262   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
263   OUT EFI_INPUT_KEY                   *Key
264   )
265 {
266   EFI_STATUS              Status;
267   KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
268   EFI_KEY_DATA            KeyData;
269 
270   ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
271 
272   //
273   // Considering if the partial keystroke is enabled, there maybe a partial
274   // keystroke in the queue, so here skip the partial keystroke and get the
275   // next key from the queue
276   //
277   while (1) {
278     //
279     // If there is no pending key, then return.
280     //
281     Status = KeyboardReadKeyStrokeWorker (ConsoleIn, &KeyData);
282     if (EFI_ERROR (Status)) {
283       return Status;
284     }
285     //
286     // If it is partial keystroke, skip it.
287     //
288     if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
289       continue;
290     }
291     //
292     // Translate the CTRL-Alpha characters to their corresponding control value
293     // (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
294     //
295     if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
296       if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {
297         KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);
298       } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {
299         KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);
300       }
301     }
302 
303     CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
304     return EFI_SUCCESS;
305   }
306 }
307 
308 /**
309   Event notification function for SIMPLE_TEXT_IN.WaitForKey event
310   Signal the event if there is key available
311 
312   @param Event    the event object
313   @param Context  waitting context
314 
315 **/
316 VOID
317 EFIAPI
KeyboardWaitForKey(IN EFI_EVENT Event,IN VOID * Context)318 KeyboardWaitForKey (
319   IN  EFI_EVENT               Event,
320   IN  VOID                    *Context
321   )
322 {
323   EFI_TPL                     OldTpl;
324   KEYBOARD_CONSOLE_IN_DEV     *ConsoleIn;
325   EFI_KEY_DATA                KeyData;
326 
327   ConsoleIn = (KEYBOARD_CONSOLE_IN_DEV *) Context;
328 
329   //
330   // Enter critical section
331   //
332   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
333 
334   KeyboardTimerHandler (NULL, ConsoleIn);
335 
336   if (!ConsoleIn->KeyboardErr) {
337     //
338     // WaitforKey doesn't suppor the partial key.
339     // Considering if the partial keystroke is enabled, there maybe a partial
340     // keystroke in the queue, so here skip the partial keystroke and get the
341     // next key from the queue
342     //
343     while (!IsEfikeyBufEmpty (&ConsoleIn->EfiKeyQueue)) {
344       CopyMem (
345         &KeyData,
346         &(ConsoleIn->EfiKeyQueue.Buffer[ConsoleIn->EfiKeyQueue.Head]),
347         sizeof (EFI_KEY_DATA)
348         );
349       if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
350         PopEfikeyBufHead (&ConsoleIn->EfiKeyQueue, &KeyData);
351         continue;
352       }
353       //
354       // if there is pending value key, signal the event.
355       //
356       gBS->SignalEvent (Event);
357       break;
358     }
359   }
360   //
361   // Leave critical section and return
362   //
363   gBS->RestoreTPL (OldTpl);
364 }
365 
366 /**
367   Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
368   Signal the event if there is key available
369 
370   @param Event    event object
371   @param Context  waiting context
372 
373 **/
374 VOID
375 EFIAPI
KeyboardWaitForKeyEx(IN EFI_EVENT Event,IN VOID * Context)376 KeyboardWaitForKeyEx (
377   IN  EFI_EVENT               Event,
378   IN  VOID                    *Context
379   )
380 
381 {
382   KeyboardWaitForKey (Event, Context);
383 }
384 
385 /**
386   Reset the input device and optionaly run diagnostics
387 
388   @param This                     Protocol instance pointer.
389   @param ExtendedVerification     Driver may perform diagnostics on reset.
390 
391   @retval EFI_SUCCESS             The device was reset.
392   @retval EFI_DEVICE_ERROR        The device is not functioning properly and could
393                                   not be reset.
394 
395 **/
396 EFI_STATUS
397 EFIAPI
KeyboardEfiResetEx(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN BOOLEAN ExtendedVerification)398 KeyboardEfiResetEx (
399   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
400   IN BOOLEAN                            ExtendedVerification
401   )
402 
403 {
404   KEYBOARD_CONSOLE_IN_DEV               *ConsoleInDev;
405 
406   ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
407 
408   return ConsoleInDev->ConIn.Reset (
409                                &ConsoleInDev->ConIn,
410                                ExtendedVerification
411                                );
412 }
413 
414 /**
415     Reads the next keystroke from the input device. The WaitForKey Event can
416     be used to test for existance of a keystroke via WaitForEvent () call.
417 
418 
419     @param This         Protocol instance pointer.
420     @param KeyData      A pointer to a buffer that is filled in with the keystroke
421                         state data for the key that was pressed.
422 
423     @retval EFI_SUCCESS           The keystroke information was returned.
424     @retval EFI_NOT_READY         There was no keystroke data availiable.
425     @retval EFI_DEVICE_ERROR      The keystroke information was not returned due to
426                                   hardware errors.
427     @retval EFI_INVALID_PARAMETER KeyData is NULL.
428 
429 **/
430 EFI_STATUS
431 EFIAPI
KeyboardReadKeyStrokeEx(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,OUT EFI_KEY_DATA * KeyData)432 KeyboardReadKeyStrokeEx (
433   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
434   OUT EFI_KEY_DATA                      *KeyData
435   )
436 
437 {
438   KEYBOARD_CONSOLE_IN_DEV               *ConsoleInDev;
439 
440   if (KeyData == NULL) {
441     return EFI_INVALID_PARAMETER;
442   }
443 
444   ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
445   return KeyboardReadKeyStrokeWorker (ConsoleInDev, KeyData);
446 }
447 
448 /**
449   Set certain state for the input device.
450 
451   @param This               Protocol instance pointer.
452   @param KeyToggleState     A pointer to the EFI_KEY_TOGGLE_STATE to set the
453                             state for the input device.
454 
455   @retval EFI_SUCCESS           The device state was set successfully.
456   @retval EFI_DEVICE_ERROR      The device is not functioning correctly and could
457                                 not have the setting adjusted.
458   @retval EFI_UNSUPPORTED       The device does not have the ability to set its state.
459   @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
460 
461 **/
462 EFI_STATUS
463 EFIAPI
KeyboardSetState(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN EFI_KEY_TOGGLE_STATE * KeyToggleState)464 KeyboardSetState (
465   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
466   IN EFI_KEY_TOGGLE_STATE               *KeyToggleState
467   )
468 
469 {
470   EFI_STATUS                            Status;
471   KEYBOARD_CONSOLE_IN_DEV               *ConsoleInDev;
472   EFI_TPL                               OldTpl;
473 
474   if (KeyToggleState == NULL) {
475     return EFI_INVALID_PARAMETER;
476   }
477 
478   ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
479 
480   //
481   // Enter critical section
482   //
483   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
484 
485   if (ConsoleInDev->KeyboardErr) {
486     Status = EFI_DEVICE_ERROR;
487     goto Exit;
488   }
489 
490   if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) {
491     Status = EFI_UNSUPPORTED;
492     goto Exit;
493   }
494 
495   //
496   // Update the status light
497   //
498   ConsoleInDev->ScrollLock          = FALSE;
499   ConsoleInDev->NumLock             = FALSE;
500   ConsoleInDev->CapsLock            = FALSE;
501   ConsoleInDev->IsSupportPartialKey = FALSE;
502 
503   if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
504     ConsoleInDev->ScrollLock = TRUE;
505   }
506   if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
507     ConsoleInDev->NumLock = TRUE;
508   }
509   if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
510     ConsoleInDev->CapsLock = TRUE;
511   }
512   if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {
513     ConsoleInDev->IsSupportPartialKey = TRUE;
514   }
515 
516   Status = UpdateStatusLights (ConsoleInDev);
517   if (EFI_ERROR (Status)) {
518     Status = EFI_DEVICE_ERROR;
519   }
520 
521 Exit:
522   //
523   // Leave critical section and return
524   //
525   gBS->RestoreTPL (OldTpl);
526 
527   return Status;
528 
529 }
530 
531 /**
532     Register a notification function for a particular keystroke for the input device.
533 
534     @param This                       Protocol instance pointer.
535     @param KeyData                    A pointer to a buffer that is filled in with the keystroke
536                                       information data for the key that was pressed.
537     @param KeyNotificationFunction    Points to the function to be called when the key
538                                       sequence is typed specified by KeyData.
539     @param NotifyHandle               Points to the unique handle assigned to the registered notification.
540 
541     @retval EFI_SUCCESS               The notification function was registered successfully.
542     @retval EFI_OUT_OF_RESOURCES      Unable to allocate resources for necesssary data structures.
543     @retval EFI_INVALID_PARAMETER     KeyData or NotifyHandle or KeyNotificationFunction is NULL.
544 
545 **/
546 EFI_STATUS
547 EFIAPI
KeyboardRegisterKeyNotify(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN EFI_KEY_DATA * KeyData,IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,OUT VOID ** NotifyHandle)548 KeyboardRegisterKeyNotify (
549   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
550   IN EFI_KEY_DATA                       *KeyData,
551   IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,
552   OUT VOID                              **NotifyHandle
553   )
554 {
555   EFI_STATUS                            Status;
556   KEYBOARD_CONSOLE_IN_DEV               *ConsoleInDev;
557   EFI_TPL                               OldTpl;
558   LIST_ENTRY                            *Link;
559   KEYBOARD_CONSOLE_IN_EX_NOTIFY         *CurrentNotify;
560   KEYBOARD_CONSOLE_IN_EX_NOTIFY         *NewNotify;
561 
562   if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
563     return EFI_INVALID_PARAMETER;
564   }
565 
566   ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
567 
568   //
569   // Enter critical section
570   //
571   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
572 
573   //
574   // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
575   //
576   for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) {
577     CurrentNotify = CR (
578                       Link,
579                       KEYBOARD_CONSOLE_IN_EX_NOTIFY,
580                       NotifyEntry,
581                       KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
582                       );
583     if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
584       if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
585         *NotifyHandle = CurrentNotify;
586         Status = EFI_SUCCESS;
587         goto Exit;
588       }
589     }
590   }
591 
592   //
593   // Allocate resource to save the notification function
594   //
595   NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));
596   if (NewNotify == NULL) {
597     Status = EFI_OUT_OF_RESOURCES;
598     goto Exit;
599   }
600 
601   NewNotify->Signature         = KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
602   NewNotify->KeyNotificationFn = KeyNotificationFunction;
603   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
604   InsertTailList (&ConsoleInDev->NotifyList, &NewNotify->NotifyEntry);
605 
606   *NotifyHandle                = NewNotify;
607   Status                       = EFI_SUCCESS;
608 
609 Exit:
610   //
611   // Leave critical section and return
612   //
613   gBS->RestoreTPL (OldTpl);
614   return Status;
615 
616 }
617 
618 /**
619     Remove a registered notification function from a particular keystroke.
620 
621     @param This                       Protocol instance pointer.
622     @param NotificationHandle         The handle of the notification function being unregistered.
623 
624 
625     @retval EFI_SUCCESS               The notification function was unregistered successfully.
626     @retval EFI_INVALID_PARAMETER     The NotificationHandle is invalid.
627 
628 **/
629 EFI_STATUS
630 EFIAPI
KeyboardUnregisterKeyNotify(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN VOID * NotificationHandle)631 KeyboardUnregisterKeyNotify (
632   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
633   IN VOID                               *NotificationHandle
634   )
635 {
636   EFI_STATUS                            Status;
637   KEYBOARD_CONSOLE_IN_DEV               *ConsoleInDev;
638   EFI_TPL                               OldTpl;
639   LIST_ENTRY                            *Link;
640   KEYBOARD_CONSOLE_IN_EX_NOTIFY         *CurrentNotify;
641 
642   if (NotificationHandle == NULL) {
643     return EFI_INVALID_PARAMETER;
644   }
645 
646   ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
647 
648   //
649   // Enter critical section
650   //
651   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
652 
653   for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) {
654     CurrentNotify = CR (
655                       Link,
656                       KEYBOARD_CONSOLE_IN_EX_NOTIFY,
657                       NotifyEntry,
658                       KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
659                       );
660     if (CurrentNotify == NotificationHandle) {
661       //
662       // Remove the notification function from NotifyList and free resources
663       //
664       RemoveEntryList (&CurrentNotify->NotifyEntry);
665 
666       gBS->FreePool (CurrentNotify);
667       Status = EFI_SUCCESS;
668       goto Exit;
669     }
670   }
671 
672   //
673   // Can not find the specified Notification Handle
674   //
675   Status = EFI_INVALID_PARAMETER;
676 Exit:
677   //
678   // Leave critical section and return
679   //
680   gBS->RestoreTPL (OldTpl);
681   return Status;
682 }
683 
684