]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c
MdeModulePkg: Add Ps2KeyboardDxe driver.
[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 - 2016, 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.
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
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
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