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