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