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