04e3365f9e6d8533b28c4002c19fb86d257e66d0
[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 - 2017, 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
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
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
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
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
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
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
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
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
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
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
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
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. If KeyData.Key,
537 KeyData.KeyState.KeyToggleState and KeyData.KeyState.KeyShiftState are 0,
538 then any incomplete keystroke will trigger a notification of the KeyNotificationFunction.
539 @param KeyNotificationFunction Points to the function to be called when the key
540 sequence is typed specified by KeyData. This notification function
541 should be called at <=TPL_CALLBACK.
542 @param NotifyHandle Points to the unique handle assigned to the registered notification.
543
544 @retval EFI_SUCCESS The notification function was registered successfully.
545 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures.
546 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle or KeyNotificationFunction is NULL.
547
548 **/
549 EFI_STATUS
550 EFIAPI
551 KeyboardRegisterKeyNotify (
552 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
553 IN EFI_KEY_DATA *KeyData,
554 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
555 OUT VOID **NotifyHandle
556 )
557 {
558 EFI_STATUS Status;
559 KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev;
560 EFI_TPL OldTpl;
561 LIST_ENTRY *Link;
562 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
563 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;
564
565 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
566 return EFI_INVALID_PARAMETER;
567 }
568
569 ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
570
571 //
572 // Enter critical section
573 //
574 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
575
576 //
577 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
578 //
579 for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) {
580 CurrentNotify = CR (
581 Link,
582 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
583 NotifyEntry,
584 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
585 );
586 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
587 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
588 *NotifyHandle = CurrentNotify;
589 Status = EFI_SUCCESS;
590 goto Exit;
591 }
592 }
593 }
594
595 //
596 // Allocate resource to save the notification function
597 //
598 NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));
599 if (NewNotify == NULL) {
600 Status = EFI_OUT_OF_RESOURCES;
601 goto Exit;
602 }
603
604 NewNotify->Signature = KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
605 NewNotify->KeyNotificationFn = KeyNotificationFunction;
606 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
607 InsertTailList (&ConsoleInDev->NotifyList, &NewNotify->NotifyEntry);
608
609 *NotifyHandle = NewNotify;
610 Status = EFI_SUCCESS;
611
612 Exit:
613 //
614 // Leave critical section and return
615 //
616 gBS->RestoreTPL (OldTpl);
617 return Status;
618
619 }
620
621 /**
622 Remove a registered notification function from a particular keystroke.
623
624 @param This Protocol instance pointer.
625 @param NotificationHandle The handle of the notification function being unregistered.
626
627
628 @retval EFI_SUCCESS The notification function was unregistered successfully.
629 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
630
631 **/
632 EFI_STATUS
633 EFIAPI
634 KeyboardUnregisterKeyNotify (
635 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
636 IN VOID *NotificationHandle
637 )
638 {
639 EFI_STATUS Status;
640 KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev;
641 EFI_TPL OldTpl;
642 LIST_ENTRY *Link;
643 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
644
645 if (NotificationHandle == NULL) {
646 return EFI_INVALID_PARAMETER;
647 }
648
649 ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
650
651 //
652 // Enter critical section
653 //
654 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
655
656 for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) {
657 CurrentNotify = CR (
658 Link,
659 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
660 NotifyEntry,
661 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
662 );
663 if (CurrentNotify == NotificationHandle) {
664 //
665 // Remove the notification function from NotifyList and free resources
666 //
667 RemoveEntryList (&CurrentNotify->NotifyEntry);
668
669 gBS->FreePool (CurrentNotify);
670 Status = EFI_SUCCESS;
671 goto Exit;
672 }
673 }
674
675 //
676 // Can not find the specified Notification Handle
677 //
678 Status = EFI_INVALID_PARAMETER;
679 Exit:
680 //
681 // Leave critical section and return
682 //
683 gBS->RestoreTPL (OldTpl);
684 return Status;
685 }
686
687 /**
688 Process key notify.
689
690 @param Event Indicates the event that invoke this function.
691 @param Context Indicates the calling context.
692 **/
693 VOID
694 EFIAPI
695 KeyNotifyProcessHandler (
696 IN EFI_EVENT Event,
697 IN VOID *Context
698 )
699 {
700 EFI_STATUS Status;
701 KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
702 EFI_KEY_DATA KeyData;
703 LIST_ENTRY *Link;
704 LIST_ENTRY *NotifyList;
705 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
706 EFI_TPL OldTpl;
707
708 ConsoleIn = (KEYBOARD_CONSOLE_IN_DEV *) Context;
709
710 //
711 // Invoke notification functions.
712 //
713 NotifyList = &ConsoleIn->NotifyList;
714 while (TRUE) {
715 //
716 // Enter critical section
717 //
718 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
719 Status = PopEfikeyBufHead (&ConsoleIn->EfiKeyQueueForNotify, &KeyData);
720 //
721 // Leave critical section
722 //
723 gBS->RestoreTPL (OldTpl);
724 if (EFI_ERROR (Status)) {
725 break;
726 }
727 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
728 CurrentNotify = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
729 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
730 CurrentNotify->KeyNotificationFn (&KeyData);
731 }
732 }
733 }
734 }
735