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