]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c
MdeModulePkg/UsbBusDxe: Add UsbControlTransfer() error check
[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
3652f990 5Copyright (c) 2006 - 2017, 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
168 }\r
169\r
170 gBS->RestoreTPL (OldTpl);\r
171 return Status;\r
172}\r
173\r
174/**\r
175 Perform 8042 controller and keyboard initialization which implement SIMPLE_TEXT_IN.Reset()\r
176\r
177 @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL\r
178 @param ExtendedVerification Indicate that the driver may perform a more\r
179 exhaustive verification operation of the device during\r
180 reset, now this par is ignored in this driver\r
181\r
182**/\r
183EFI_STATUS\r
184EFIAPI\r
185KeyboardEfiReset (\r
186 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,\r
187 IN BOOLEAN ExtendedVerification\r
188 )\r
189{\r
190 EFI_STATUS Status;\r
191 KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;\r
192 EFI_TPL OldTpl;\r
193\r
194 ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);\r
195 if (ConsoleIn->KeyboardErr) {\r
196 return EFI_DEVICE_ERROR;\r
197 }\r
198\r
199 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
200 EFI_PROGRESS_CODE,\r
201 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET,\r
202 ConsoleIn->DevicePath\r
203 );\r
204\r
205 //\r
206 // Enter critical section\r
207 //\r
208 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
209\r
210 //\r
211 // Call InitKeyboard to initialize the keyboard\r
212 //\r
213 Status = InitKeyboard (ConsoleIn, ExtendedVerification);\r
214 if (EFI_ERROR (Status)) {\r
215 //\r
216 // Leave critical section and return\r
217 //\r
218 gBS->RestoreTPL (OldTpl);\r
219 return EFI_DEVICE_ERROR;\r
220 }\r
221\r
222 //\r
223 // Leave critical section and return\r
224 //\r
225 gBS->RestoreTPL (OldTpl);\r
226\r
227 //\r
228 // Report the status If a stuck key was detected\r
229 //\r
230 if (KeyReadStatusRegister (ConsoleIn) & 0x01) {\r
231 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
232 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
233 EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_EC_STUCK_KEY,\r
234 ConsoleIn->DevicePath\r
235 );\r
236 }\r
237 //\r
238 // Report the status If keyboard is locked\r
239 //\r
240 if ((KeyReadStatusRegister (ConsoleIn) & 0x10) == 0) {\r
241 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
242 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
243 EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_EC_LOCKED,\r
244 ConsoleIn->DevicePath\r
245 );\r
246 }\r
247\r
248 return EFI_SUCCESS;\r
249}\r
250\r
251/**\r
252 Retrieve key values for driver user which implement SIMPLE_TEXT_IN.ReadKeyStroke().\r
253\r
254 @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL\r
255 @param Key The output buffer for key value\r
256\r
257 @retval EFI_SUCCESS success to read key stroke\r
258**/\r
259EFI_STATUS\r
260EFIAPI\r
261KeyboardReadKeyStroke (\r
262 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,\r
263 OUT EFI_INPUT_KEY *Key\r
264 )\r
265{\r
266 EFI_STATUS Status;\r
267 KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;\r
268 EFI_KEY_DATA KeyData;\r
269\r
270 ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);\r
271\r
272 //\r
273 // Considering if the partial keystroke is enabled, there maybe a partial\r
274 // keystroke in the queue, so here skip the partial keystroke and get the\r
275 // next key from the queue\r
276 //\r
277 while (1) {\r
278 //\r
279 // If there is no pending key, then return.\r
280 //\r
281 Status = KeyboardReadKeyStrokeWorker (ConsoleIn, &KeyData);\r
282 if (EFI_ERROR (Status)) {\r
283 return Status;\r
284 }\r
285 //\r
286 // If it is partial keystroke, skip it.\r
287 //\r
288 if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {\r
289 continue;\r
290 }\r
291 //\r
292 // Translate the CTRL-Alpha characters to their corresponding control value\r
293 // (ctrl-a = 0x0001 through ctrl-Z = 0x001A)\r
294 //\r
295 if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {\r
296 if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {\r
297 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);\r
298 } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {\r
299 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);\r
300 }\r
301 }\r
302\r
303 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
304 return EFI_SUCCESS;\r
305 }\r
306}\r
307\r
308/**\r
309 Event notification function for SIMPLE_TEXT_IN.WaitForKey event\r
310 Signal the event if there is key available\r
311\r
312 @param Event the event object\r
313 @param Context waitting context\r
314\r
315**/\r
316VOID\r
317EFIAPI\r
318KeyboardWaitForKey (\r
319 IN EFI_EVENT Event,\r
320 IN VOID *Context\r
321 )\r
322{\r
323 EFI_TPL OldTpl;\r
324 KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;\r
325 EFI_KEY_DATA KeyData;\r
326\r
327 ConsoleIn = (KEYBOARD_CONSOLE_IN_DEV *) Context;\r
328\r
329 //\r
330 // Enter critical section\r
331 //\r
332 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
333\r
334 KeyboardTimerHandler (NULL, ConsoleIn);\r
335\r
336 if (!ConsoleIn->KeyboardErr) {\r
337 //\r
338 // WaitforKey doesn't suppor the partial key.\r
339 // Considering if the partial keystroke is enabled, there maybe a partial\r
340 // keystroke in the queue, so here skip the partial keystroke and get the\r
341 // next key from the queue\r
342 //\r
343 while (!IsEfikeyBufEmpty (&ConsoleIn->EfiKeyQueue)) {\r
344 CopyMem (\r
345 &KeyData,\r
346 &(ConsoleIn->EfiKeyQueue.Buffer[ConsoleIn->EfiKeyQueue.Head]),\r
347 sizeof (EFI_KEY_DATA)\r
348 );\r
349 if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {\r
350 PopEfikeyBufHead (&ConsoleIn->EfiKeyQueue, &KeyData);\r
351 continue;\r
352 }\r
353 //\r
354 // if there is pending value key, signal the event.\r
355 //\r
356 gBS->SignalEvent (Event);\r
357 break;\r
358 }\r
359 }\r
360 //\r
361 // Leave critical section and return\r
362 //\r
363 gBS->RestoreTPL (OldTpl);\r
364}\r
365\r
366/**\r
367 Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event\r
368 Signal the event if there is key available\r
369\r
370 @param Event event object\r
371 @param Context waiting context\r
372\r
373**/\r
374VOID\r
375EFIAPI\r
376KeyboardWaitForKeyEx (\r
377 IN EFI_EVENT Event,\r
378 IN VOID *Context\r
379 )\r
380\r
381{\r
382 KeyboardWaitForKey (Event, Context);\r
383}\r
384\r
385/**\r
386 Reset the input device and optionaly run diagnostics\r
387\r
388 @param This Protocol instance pointer.\r
389 @param ExtendedVerification Driver may perform diagnostics on reset.\r
390\r
391 @retval EFI_SUCCESS The device was reset.\r
392 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
393 not be reset.\r
394\r
395**/\r
396EFI_STATUS\r
397EFIAPI\r
398KeyboardEfiResetEx (\r
399 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
400 IN BOOLEAN ExtendedVerification\r
401 )\r
402\r
403{\r
404 KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev;\r
405\r
406 ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);\r
407\r
408 return ConsoleInDev->ConIn.Reset (\r
409 &ConsoleInDev->ConIn,\r
410 ExtendedVerification\r
411 );\r
412}\r
413\r
414/**\r
415 Reads the next keystroke from the input device. The WaitForKey Event can\r
416 be used to test for existance of a keystroke via WaitForEvent () call.\r
417\r
418\r
419 @param This Protocol instance pointer.\r
420 @param KeyData A pointer to a buffer that is filled in with the keystroke\r
421 state data for the key that was pressed.\r
422\r
423 @retval EFI_SUCCESS The keystroke information was returned.\r
424 @retval EFI_NOT_READY There was no keystroke data availiable.\r
425 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to\r
426 hardware errors.\r
427 @retval EFI_INVALID_PARAMETER KeyData is NULL.\r
428\r
429**/\r
430EFI_STATUS\r
431EFIAPI\r
432KeyboardReadKeyStrokeEx (\r
433 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
434 OUT EFI_KEY_DATA *KeyData\r
435 )\r
436\r
437{\r
438 KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev;\r
439\r
440 if (KeyData == NULL) {\r
441 return EFI_INVALID_PARAMETER;\r
442 }\r
443\r
444 ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);\r
445 return KeyboardReadKeyStrokeWorker (ConsoleInDev, KeyData);\r
446}\r
447\r
448/**\r
449 Set certain state for the input device.\r
450\r
451 @param This Protocol instance pointer.\r
452 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the\r
453 state for the input device.\r
454\r
455 @retval EFI_SUCCESS The device state was set successfully.\r
456 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could\r
457 not have the setting adjusted.\r
458 @retval EFI_UNSUPPORTED The device does not have the ability to set its state.\r
459 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.\r
460\r
461**/\r
462EFI_STATUS\r
463EFIAPI\r
464KeyboardSetState (\r
465 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
466 IN EFI_KEY_TOGGLE_STATE *KeyToggleState\r
467 )\r
468\r
469{\r
470 EFI_STATUS Status;\r
471 KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev;\r
472 EFI_TPL OldTpl;\r
473\r
474 if (KeyToggleState == NULL) {\r
475 return EFI_INVALID_PARAMETER;\r
476 }\r
477\r
478 ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);\r
479\r
480 //\r
481 // Enter critical section\r
482 //\r
483 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
484\r
485 if (ConsoleInDev->KeyboardErr) {\r
486 Status = EFI_DEVICE_ERROR;\r
487 goto Exit;\r
488 }\r
489\r
490 if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) {\r
491 Status = EFI_UNSUPPORTED;\r
492 goto Exit;\r
493 }\r
494\r
495 //\r
496 // Update the status light\r
497 //\r
498 ConsoleInDev->ScrollLock = FALSE;\r
499 ConsoleInDev->NumLock = FALSE;\r
500 ConsoleInDev->CapsLock = FALSE;\r
501 ConsoleInDev->IsSupportPartialKey = FALSE;\r
502\r
503 if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {\r
504 ConsoleInDev->ScrollLock = TRUE;\r
505 }\r
506 if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {\r
507 ConsoleInDev->NumLock = TRUE;\r
508 }\r
509 if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {\r
510 ConsoleInDev->CapsLock = TRUE;\r
511 }\r
512 if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {\r
513 ConsoleInDev->IsSupportPartialKey = TRUE;\r
514 }\r
515\r
516 Status = UpdateStatusLights (ConsoleInDev);\r
517 if (EFI_ERROR (Status)) {\r
518 Status = EFI_DEVICE_ERROR;\r
519 }\r
520\r
521Exit:\r
522 //\r
523 // Leave critical section and return\r
524 //\r
525 gBS->RestoreTPL (OldTpl);\r
526\r
527 return Status;\r
528\r
529}\r
530\r
531/**\r
532 Register a notification function for a particular keystroke for the input device.\r
533\r
534 @param This Protocol instance pointer.\r
535 @param KeyData A pointer to a buffer that is filled in with the keystroke\r
3652f990
DB
536 information data for the key that was pressed. If KeyData.Key,\r
537 KeyData.KeyState.KeyToggleState and KeyData.KeyState.KeyShiftState are 0,\r
538 then any incomplete keystroke will trigger a notification of the KeyNotificationFunction.\r
4aa68cbc 539 @param KeyNotificationFunction Points to the function to be called when the key\r
3652f990
DB
540 sequence is typed specified by KeyData. This notification function\r
541 should be called at <=TPL_CALLBACK.\r
4aa68cbc
RN
542 @param NotifyHandle Points to the unique handle assigned to the registered notification.\r
543\r
544 @retval EFI_SUCCESS The notification function was registered successfully.\r
545 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures.\r
546 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle or KeyNotificationFunction is NULL.\r
547\r
548**/\r
549EFI_STATUS\r
550EFIAPI\r
551KeyboardRegisterKeyNotify (\r
552 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
553 IN EFI_KEY_DATA *KeyData,\r
554 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,\r
555 OUT VOID **NotifyHandle\r
556 )\r
557{\r
558 EFI_STATUS Status;\r
559 KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev;\r
560 EFI_TPL OldTpl;\r
561 LIST_ENTRY *Link;\r
562 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
563 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;\r
564\r
565 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {\r
566 return EFI_INVALID_PARAMETER;\r
567 }\r
568\r
569 ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);\r
570\r
571 //\r
572 // Enter critical section\r
573 //\r
574 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
575\r
576 //\r
577 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.\r
578 //\r
579 for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) {\r
580 CurrentNotify = CR (\r
581 Link,\r
582 KEYBOARD_CONSOLE_IN_EX_NOTIFY,\r
583 NotifyEntry,\r
584 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
585 );\r
586 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {\r
587 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {\r
588 *NotifyHandle = CurrentNotify;\r
589 Status = EFI_SUCCESS;\r
590 goto Exit;\r
591 }\r
592 }\r
593 }\r
594\r
595 //\r
596 // Allocate resource to save the notification function\r
597 //\r
598 NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));\r
599 if (NewNotify == NULL) {\r
600 Status = EFI_OUT_OF_RESOURCES;\r
601 goto Exit;\r
602 }\r
603\r
604 NewNotify->Signature = KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;\r
605 NewNotify->KeyNotificationFn = KeyNotificationFunction;\r
606 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));\r
607 InsertTailList (&ConsoleInDev->NotifyList, &NewNotify->NotifyEntry);\r
608\r
609 *NotifyHandle = NewNotify;\r
610 Status = EFI_SUCCESS;\r
611\r
612Exit:\r
613 //\r
614 // Leave critical section and return\r
615 //\r
616 gBS->RestoreTPL (OldTpl);\r
617 return Status;\r
618\r
619}\r
620\r
621/**\r
622 Remove a registered notification function from a particular keystroke.\r
623\r
624 @param This Protocol instance pointer.\r
625 @param NotificationHandle The handle of the notification function being unregistered.\r
626\r
627\r
628 @retval EFI_SUCCESS The notification function was unregistered successfully.\r
629 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.\r
630\r
631**/\r
632EFI_STATUS\r
633EFIAPI\r
634KeyboardUnregisterKeyNotify (\r
635 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
636 IN VOID *NotificationHandle\r
637 )\r
638{\r
639 EFI_STATUS Status;\r
640 KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev;\r
641 EFI_TPL OldTpl;\r
642 LIST_ENTRY *Link;\r
643 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
644\r
645 if (NotificationHandle == NULL) {\r
646 return EFI_INVALID_PARAMETER;\r
647 }\r
648\r
649 ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);\r
650\r
651 //\r
652 // Enter critical section\r
653 //\r
654 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
655\r
656 for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) {\r
657 CurrentNotify = CR (\r
658 Link,\r
659 KEYBOARD_CONSOLE_IN_EX_NOTIFY,\r
660 NotifyEntry,\r
661 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
662 );\r
663 if (CurrentNotify == NotificationHandle) {\r
664 //\r
665 // Remove the notification function from NotifyList and free resources\r
666 //\r
667 RemoveEntryList (&CurrentNotify->NotifyEntry);\r
668\r
669 gBS->FreePool (CurrentNotify);\r
670 Status = EFI_SUCCESS;\r
671 goto Exit;\r
672 }\r
673 }\r
674\r
675 //\r
676 // Can not find the specified Notification Handle\r
677 //\r
678 Status = EFI_INVALID_PARAMETER;\r
679Exit:\r
680 //\r
681 // Leave critical section and return\r
682 //\r
683 gBS->RestoreTPL (OldTpl);\r
684 return Status;\r
685}\r
686\r
35dadd7c
SZ
687/**\r
688 Process key notify.\r
689\r
690 @param Event Indicates the event that invoke this function.\r
691 @param Context Indicates the calling context.\r
692**/\r
693VOID\r
694EFIAPI\r
695KeyNotifyProcessHandler (\r
696 IN EFI_EVENT Event,\r
697 IN VOID *Context\r
698 )\r
699{\r
700 EFI_STATUS Status;\r
701 KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;\r
702 EFI_KEY_DATA KeyData;\r
703 LIST_ENTRY *Link;\r
704 LIST_ENTRY *NotifyList;\r
705 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
706 EFI_TPL OldTpl;\r
707\r
708 ConsoleIn = (KEYBOARD_CONSOLE_IN_DEV *) Context;\r
709\r
710 //\r
711 // Invoke notification functions.\r
712 //\r
713 NotifyList = &ConsoleIn->NotifyList;\r
714 while (TRUE) {\r
715 //\r
716 // Enter critical section\r
717 // \r
718 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
719 Status = PopEfikeyBufHead (&ConsoleIn->EfiKeyQueueForNotify, &KeyData);\r
720 //\r
721 // Leave critical section\r
722 //\r
723 gBS->RestoreTPL (OldTpl);\r
724 if (EFI_ERROR (Status)) {\r
725 break;\r
726 }\r
727 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {\r
728 CurrentNotify = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE);\r
729 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {\r
730 CurrentNotify->KeyNotificationFn (&KeyData);\r
731 }\r
732 }\r
733 }\r
734}\r
735\r