• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   USB Keyboard Driver that manages USB keyboard and produces Simple Text Input
3   Protocol and Simple Text Input Ex Protocol.
4 
5 Copyright (c) 2004 - 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 #include "EfiKey.h"
17 #include "KeyBoard.h"
18 
19 //
20 // USB Keyboard Driver Global Variables
21 //
22 EFI_DRIVER_BINDING_PROTOCOL gUsbKeyboardDriverBinding = {
23   USBKeyboardDriverBindingSupported,
24   USBKeyboardDriverBindingStart,
25   USBKeyboardDriverBindingStop,
26   0xa,
27   NULL,
28   NULL
29 };
30 
31 /**
32   Entrypoint of USB Keyboard Driver.
33 
34   This function is the entrypoint of USB Keyboard Driver. It installs Driver Binding
35   Protocols together with Component Name Protocols.
36 
37   @param  ImageHandle       The firmware allocated handle for the EFI image.
38   @param  SystemTable       A pointer to the EFI System Table.
39 
40   @retval EFI_SUCCESS       The entry point is executed successfully.
41 
42 **/
43 EFI_STATUS
44 EFIAPI
USBKeyboardDriverBindingEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)45 USBKeyboardDriverBindingEntryPoint (
46   IN EFI_HANDLE           ImageHandle,
47   IN EFI_SYSTEM_TABLE     *SystemTable
48   )
49 {
50   EFI_STATUS              Status;
51 
52   Status = EfiLibInstallDriverBindingComponentName2 (
53              ImageHandle,
54              SystemTable,
55              &gUsbKeyboardDriverBinding,
56              ImageHandle,
57              &gUsbKeyboardComponentName,
58              &gUsbKeyboardComponentName2
59              );
60   ASSERT_EFI_ERROR (Status);
61 
62   return EFI_SUCCESS;
63 }
64 
65 /**
66   Check whether USB keyboard driver supports this device.
67 
68   @param  This                   The USB keyboard driver binding protocol.
69   @param  Controller             The controller handle to check.
70   @param  RemainingDevicePath    The remaining device path.
71 
72   @retval EFI_SUCCESS            The driver supports this controller.
73   @retval other                  This device isn't supported.
74 
75 **/
76 EFI_STATUS
77 EFIAPI
USBKeyboardDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)78 USBKeyboardDriverBindingSupported (
79   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
80   IN EFI_HANDLE                     Controller,
81   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
82   )
83 {
84   EFI_STATUS          Status;
85   EFI_USB_IO_PROTOCOL *UsbIo;
86 
87   //
88   // Check if USB I/O Protocol is attached on the controller handle.
89   //
90   Status = gBS->OpenProtocol (
91                   Controller,
92                   &gEfiUsbIoProtocolGuid,
93                   (VOID **) &UsbIo,
94                   This->DriverBindingHandle,
95                   Controller,
96                   EFI_OPEN_PROTOCOL_BY_DRIVER
97                   );
98   if (EFI_ERROR (Status)) {
99     return Status;
100   }
101 
102   //
103   // Use the USB I/O Protocol interface to check whether Controller is
104   // a keyboard device that can be managed by this driver.
105   //
106   Status = EFI_SUCCESS;
107 
108   if (!IsUSBKeyboard (UsbIo)) {
109     Status = EFI_UNSUPPORTED;
110   }
111 
112   gBS->CloseProtocol (
113          Controller,
114          &gEfiUsbIoProtocolGuid,
115          This->DriverBindingHandle,
116          Controller
117          );
118 
119   return Status;
120 }
121 
122 /**
123   Starts the keyboard device with this driver.
124 
125   This function produces Simple Text Input Protocol and Simple Text Input Ex Protocol,
126   initializes the keyboard device, and submit Asynchronous Interrupt Transfer to manage
127   this keyboard device.
128 
129   @param  This                   The USB keyboard driver binding instance.
130   @param  Controller             Handle of device to bind driver to.
131   @param  RemainingDevicePath    Optional parameter use to pick a specific child
132                                  device to start.
133 
134   @retval EFI_SUCCESS            The controller is controlled by the usb keyboard driver.
135   @retval EFI_UNSUPPORTED        No interrupt endpoint can be found.
136   @retval Other                  This controller cannot be started.
137 
138 **/
139 EFI_STATUS
140 EFIAPI
USBKeyboardDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)141 USBKeyboardDriverBindingStart (
142   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
143   IN EFI_HANDLE                     Controller,
144   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
145   )
146 {
147   EFI_STATUS                    Status;
148   EFI_USB_IO_PROTOCOL           *UsbIo;
149   USB_KB_DEV                    *UsbKeyboardDevice;
150   UINT8                         EndpointNumber;
151   EFI_USB_ENDPOINT_DESCRIPTOR   EndpointDescriptor;
152   UINT8                         Index;
153   UINT8                         EndpointAddr;
154   UINT8                         PollingInterval;
155   UINT8                         PacketSize;
156   BOOLEAN                       Found;
157   EFI_TPL                       OldTpl;
158 
159   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
160   //
161   // Open USB I/O Protocol
162   //
163   Status = gBS->OpenProtocol (
164                   Controller,
165                   &gEfiUsbIoProtocolGuid,
166                   (VOID **) &UsbIo,
167                   This->DriverBindingHandle,
168                   Controller,
169                   EFI_OPEN_PROTOCOL_BY_DRIVER
170                   );
171   if (EFI_ERROR (Status)) {
172     goto ErrorExit1;
173   }
174 
175   UsbKeyboardDevice = AllocateZeroPool (sizeof (USB_KB_DEV));
176   ASSERT (UsbKeyboardDevice != NULL);
177 
178   //
179   // Get the Device Path Protocol on Controller's handle
180   //
181   Status = gBS->OpenProtocol (
182                   Controller,
183                   &gEfiDevicePathProtocolGuid,
184                   (VOID **) &UsbKeyboardDevice->DevicePath,
185                   This->DriverBindingHandle,
186                   Controller,
187                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
188                   );
189 
190   if (EFI_ERROR (Status)) {
191     goto ErrorExit;
192   }
193   //
194   // Report that the USB keyboard is being enabled
195   //
196   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
197     EFI_PROGRESS_CODE,
198     (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE),
199     UsbKeyboardDevice->DevicePath
200     );
201 
202   //
203   // This is pretty close to keyboard detection, so log progress
204   //
205   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
206     EFI_PROGRESS_CODE,
207     (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT),
208     UsbKeyboardDevice->DevicePath
209     );
210 
211   UsbKeyboardDevice->UsbIo = UsbIo;
212 
213   //
214   // Get interface & endpoint descriptor
215   //
216   UsbIo->UsbGetInterfaceDescriptor (
217            UsbIo,
218            &UsbKeyboardDevice->InterfaceDescriptor
219            );
220 
221   EndpointNumber = UsbKeyboardDevice->InterfaceDescriptor.NumEndpoints;
222 
223   //
224   // Traverse endpoints to find interrupt endpoint
225   //
226   Found = FALSE;
227   for (Index = 0; Index < EndpointNumber; Index++) {
228 
229     UsbIo->UsbGetEndpointDescriptor (
230              UsbIo,
231              Index,
232              &EndpointDescriptor
233              );
234 
235     if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) {
236       //
237       // We only care interrupt endpoint here
238       //
239       CopyMem(&UsbKeyboardDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor));
240       Found = TRUE;
241       break;
242     }
243   }
244 
245   if (!Found) {
246     //
247     // Report Status Code to indicate that there is no USB keyboard
248     //
249     REPORT_STATUS_CODE (
250       EFI_ERROR_CODE | EFI_ERROR_MINOR,
251       (EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED)
252       );
253     //
254     // No interrupt endpoint found, then return unsupported.
255     //
256     Status = EFI_UNSUPPORTED;
257     goto ErrorExit;
258   }
259 
260   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
261     EFI_PROGRESS_CODE,
262     (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DETECTED),
263     UsbKeyboardDevice->DevicePath
264     );
265 
266   UsbKeyboardDevice->Signature                  = USB_KB_DEV_SIGNATURE;
267   UsbKeyboardDevice->SimpleInput.Reset          = USBKeyboardReset;
268   UsbKeyboardDevice->SimpleInput.ReadKeyStroke  = USBKeyboardReadKeyStroke;
269 
270   UsbKeyboardDevice->SimpleInputEx.Reset               = USBKeyboardResetEx;
271   UsbKeyboardDevice->SimpleInputEx.ReadKeyStrokeEx     = USBKeyboardReadKeyStrokeEx;
272   UsbKeyboardDevice->SimpleInputEx.SetState            = USBKeyboardSetState;
273   UsbKeyboardDevice->SimpleInputEx.RegisterKeyNotify   = USBKeyboardRegisterKeyNotify;
274   UsbKeyboardDevice->SimpleInputEx.UnregisterKeyNotify = USBKeyboardUnregisterKeyNotify;
275 
276   InitializeListHead (&UsbKeyboardDevice->NotifyList);
277 
278   Status = gBS->CreateEvent (
279                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
280                   TPL_NOTIFY,
281                   USBKeyboardTimerHandler,
282                   UsbKeyboardDevice,
283                   &UsbKeyboardDevice->TimerEvent
284                   );
285   if (!EFI_ERROR (Status)) {
286     Status = gBS->SetTimer (UsbKeyboardDevice->TimerEvent, TimerPeriodic, KEYBOARD_TIMER_INTERVAL);
287   }
288   if (EFI_ERROR (Status)) {
289     goto ErrorExit;
290   }
291 
292   Status = gBS->CreateEvent (
293                   EVT_NOTIFY_WAIT,
294                   TPL_NOTIFY,
295                   USBKeyboardWaitForKey,
296                   UsbKeyboardDevice,
297                   &(UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx)
298                   );
299 
300   if (EFI_ERROR (Status)) {
301     goto ErrorExit;
302   }
303 
304   Status = gBS->CreateEvent (
305                   EVT_NOTIFY_WAIT,
306                   TPL_NOTIFY,
307                   USBKeyboardWaitForKey,
308                   UsbKeyboardDevice,
309                   &(UsbKeyboardDevice->SimpleInput.WaitForKey)
310                   );
311   if (EFI_ERROR (Status)) {
312     goto ErrorExit;
313   }
314 
315   Status = gBS->CreateEvent (
316                   EVT_NOTIFY_SIGNAL,
317                   TPL_CALLBACK,
318                   KeyNotifyProcessHandler,
319                   UsbKeyboardDevice,
320                   &UsbKeyboardDevice->KeyNotifyProcessEvent
321                   );
322   if (EFI_ERROR (Status)) {
323     goto ErrorExit;
324   }
325 
326   //
327   // Install Simple Text Input Protocol and Simple Text Input Ex Protocol
328   // for the USB keyboard device.
329   // USB keyboard is a hot plug device, and expected to work immediately
330   // when plugging into system, other conventional console devices could
331   // distinguish it by its device path.
332   //
333   Status = gBS->InstallMultipleProtocolInterfaces (
334                   &Controller,
335                   &gEfiSimpleTextInProtocolGuid,
336                   &UsbKeyboardDevice->SimpleInput,
337                   &gEfiSimpleTextInputExProtocolGuid,
338                   &UsbKeyboardDevice->SimpleInputEx,
339                   NULL
340                   );
341   if (EFI_ERROR (Status)) {
342     goto ErrorExit;
343   }
344 
345   UsbKeyboardDevice->ControllerHandle = Controller;
346   Status = InitKeyboardLayout (UsbKeyboardDevice);
347   if (EFI_ERROR (Status)) {
348     gBS->UninstallMultipleProtocolInterfaces (
349       Controller,
350       &gEfiSimpleTextInProtocolGuid,
351       &UsbKeyboardDevice->SimpleInput,
352       &gEfiSimpleTextInputExProtocolGuid,
353       &UsbKeyboardDevice->SimpleInputEx,
354       NULL
355       );
356     goto ErrorExit;
357   }
358 
359 
360   //
361   // Reset USB Keyboard Device exhaustively.
362   //
363   Status = UsbKeyboardDevice->SimpleInputEx.Reset (
364                                             &UsbKeyboardDevice->SimpleInputEx,
365                                             TRUE
366                                             );
367   if (EFI_ERROR (Status)) {
368     gBS->UninstallMultipleProtocolInterfaces (
369            Controller,
370            &gEfiSimpleTextInProtocolGuid,
371            &UsbKeyboardDevice->SimpleInput,
372            &gEfiSimpleTextInputExProtocolGuid,
373            &UsbKeyboardDevice->SimpleInputEx,
374            NULL
375            );
376     goto ErrorExit;
377   }
378 
379   //
380   // Submit Asynchronous Interrupt Transfer to manage this device.
381   //
382   EndpointAddr    = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress;
383   PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval;
384   PacketSize      = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize);
385 
386   Status = UsbIo->UsbAsyncInterruptTransfer (
387                     UsbIo,
388                     EndpointAddr,
389                     TRUE,
390                     PollingInterval,
391                     PacketSize,
392                     KeyboardHandler,
393                     UsbKeyboardDevice
394                     );
395 
396   if (EFI_ERROR (Status)) {
397     gBS->UninstallMultipleProtocolInterfaces (
398            Controller,
399            &gEfiSimpleTextInProtocolGuid,
400            &UsbKeyboardDevice->SimpleInput,
401            &gEfiSimpleTextInputExProtocolGuid,
402            &UsbKeyboardDevice->SimpleInputEx,
403            NULL
404            );
405     goto ErrorExit;
406   }
407 
408   UsbKeyboardDevice->ControllerNameTable = NULL;
409   AddUnicodeString2 (
410     "eng",
411     gUsbKeyboardComponentName.SupportedLanguages,
412     &UsbKeyboardDevice->ControllerNameTable,
413     L"Generic Usb Keyboard",
414     TRUE
415     );
416   AddUnicodeString2 (
417     "en",
418     gUsbKeyboardComponentName2.SupportedLanguages,
419     &UsbKeyboardDevice->ControllerNameTable,
420     L"Generic Usb Keyboard",
421     FALSE
422     );
423 
424   gBS->RestoreTPL (OldTpl);
425   return EFI_SUCCESS;
426 
427 //
428 // Error handler
429 //
430 ErrorExit:
431   if (UsbKeyboardDevice != NULL) {
432     if (UsbKeyboardDevice->TimerEvent != NULL) {
433       gBS->CloseEvent (UsbKeyboardDevice->TimerEvent);
434     }
435     if (UsbKeyboardDevice->SimpleInput.WaitForKey != NULL) {
436       gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
437     }
438     if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) {
439       gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
440     }
441     if (UsbKeyboardDevice->KeyNotifyProcessEvent != NULL) {
442       gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent);
443     }
444     if (UsbKeyboardDevice->KeyboardLayoutEvent != NULL) {
445       ReleaseKeyboardLayoutResources (UsbKeyboardDevice);
446       gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);
447     }
448     FreePool (UsbKeyboardDevice);
449     UsbKeyboardDevice = NULL;
450   }
451   gBS->CloseProtocol (
452          Controller,
453          &gEfiUsbIoProtocolGuid,
454          This->DriverBindingHandle,
455          Controller
456          );
457 
458 ErrorExit1:
459   gBS->RestoreTPL (OldTpl);
460 
461   return Status;
462 
463 }
464 
465 
466 /**
467   Stop the USB keyboard device handled by this driver.
468 
469   @param  This                   The USB keyboard driver binding protocol.
470   @param  Controller             The controller to release.
471   @param  NumberOfChildren       The number of handles in ChildHandleBuffer.
472   @param  ChildHandleBuffer      The array of child handle.
473 
474   @retval EFI_SUCCESS            The device was stopped.
475   @retval EFI_UNSUPPORTED        Simple Text In Protocol or Simple Text In Ex Protocol
476                                  is not installed on Controller.
477   @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.
478   @retval Others                 Fail to uninstall protocols attached on the device.
479 
480 **/
481 EFI_STATUS
482 EFIAPI
USBKeyboardDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)483 USBKeyboardDriverBindingStop (
484   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
485   IN  EFI_HANDLE                     Controller,
486   IN  UINTN                          NumberOfChildren,
487   IN  EFI_HANDLE                     *ChildHandleBuffer
488   )
489 {
490   EFI_STATUS                     Status;
491   EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleInput;
492   USB_KB_DEV                     *UsbKeyboardDevice;
493 
494   Status = gBS->OpenProtocol (
495                   Controller,
496                   &gEfiSimpleTextInProtocolGuid,
497                   (VOID **) &SimpleInput,
498                   This->DriverBindingHandle,
499                   Controller,
500                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
501                   );
502   if (EFI_ERROR (Status)) {
503     return EFI_UNSUPPORTED;
504   }
505 
506   Status = gBS->OpenProtocol (
507                   Controller,
508                   &gEfiSimpleTextInputExProtocolGuid,
509                   NULL,
510                   This->DriverBindingHandle,
511                   Controller,
512                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
513                   );
514   if (EFI_ERROR (Status)) {
515     return EFI_UNSUPPORTED;
516   }
517 
518   UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput);
519 
520   //
521   // The key data input from this device will be disabled.
522   //
523   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
524     EFI_PROGRESS_CODE,
525     (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE),
526     UsbKeyboardDevice->DevicePath
527     );
528 
529   //
530   // Delete the Asynchronous Interrupt Transfer from this device
531   //
532   UsbKeyboardDevice->UsbIo->UsbAsyncInterruptTransfer (
533                               UsbKeyboardDevice->UsbIo,
534                               UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
535                               FALSE,
536                               UsbKeyboardDevice->IntEndpointDescriptor.Interval,
537                               0,
538                               NULL,
539                               NULL
540                               );
541 
542   gBS->CloseProtocol (
543          Controller,
544          &gEfiUsbIoProtocolGuid,
545          This->DriverBindingHandle,
546          Controller
547          );
548 
549   Status = gBS->UninstallMultipleProtocolInterfaces (
550                   Controller,
551                   &gEfiSimpleTextInProtocolGuid,
552                   &UsbKeyboardDevice->SimpleInput,
553                   &gEfiSimpleTextInputExProtocolGuid,
554                   &UsbKeyboardDevice->SimpleInputEx,
555                   NULL
556                   );
557   //
558   // Free all resources.
559   //
560   gBS->CloseEvent (UsbKeyboardDevice->TimerEvent);
561   gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer);
562   gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent);
563   gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
564   gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
565   gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent);
566   KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList);
567 
568   ReleaseKeyboardLayoutResources (UsbKeyboardDevice);
569   gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);
570 
571   if (UsbKeyboardDevice->ControllerNameTable != NULL) {
572     FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable);
573   }
574 
575   DestroyQueue (&UsbKeyboardDevice->UsbKeyQueue);
576   DestroyQueue (&UsbKeyboardDevice->EfiKeyQueue);
577   DestroyQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify);
578 
579   FreePool (UsbKeyboardDevice);
580 
581   return Status;
582 }
583 
584 /**
585   Internal function to read the next keystroke from the keyboard buffer.
586 
587   @param  UsbKeyboardDevice       USB keyboard's private structure.
588   @param  KeyData                 A pointer to buffer to hold the keystroke
589                                   data for the key that was pressed.
590 
591   @retval EFI_SUCCESS             The keystroke information was returned.
592   @retval EFI_NOT_READY           There was no keystroke data availiable.
593   @retval EFI_DEVICE_ERROR        The keystroke information was not returned due to
594                                   hardware errors.
595   @retval EFI_INVALID_PARAMETER   KeyData is NULL.
596   @retval Others                  Fail to translate keycode into EFI_INPUT_KEY
597 
598 **/
599 EFI_STATUS
USBKeyboardReadKeyStrokeWorker(IN OUT USB_KB_DEV * UsbKeyboardDevice,OUT EFI_KEY_DATA * KeyData)600 USBKeyboardReadKeyStrokeWorker (
601   IN OUT USB_KB_DEV                 *UsbKeyboardDevice,
602      OUT EFI_KEY_DATA               *KeyData
603   )
604 {
605   if (KeyData == NULL) {
606     return EFI_INVALID_PARAMETER;
607   }
608 
609   if (IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {
610     return EFI_NOT_READY;
611   }
612 
613   Dequeue (&UsbKeyboardDevice->EfiKeyQueue, KeyData, sizeof (*KeyData));
614 
615   return EFI_SUCCESS;
616 }
617 
618 /**
619   Reset the input device and optionally run diagnostics
620 
621   There are 2 types of reset for USB keyboard.
622   For non-exhaustive reset, only keyboard buffer is cleared.
623   For exhaustive reset, in addition to clearance of keyboard buffer, the hardware status
624   is also re-initialized.
625 
626   @param  This                 Protocol instance pointer.
627   @param  ExtendedVerification Driver may perform diagnostics on reset.
628 
629   @retval EFI_SUCCESS          The device was reset.
630   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could not be reset.
631 
632 **/
633 EFI_STATUS
634 EFIAPI
USBKeyboardReset(IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL * This,IN BOOLEAN ExtendedVerification)635 USBKeyboardReset (
636   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL   *This,
637   IN  BOOLEAN                          ExtendedVerification
638   )
639 {
640   EFI_STATUS          Status;
641   USB_KB_DEV          *UsbKeyboardDevice;
642 
643   UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
644 
645   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
646     EFI_PROGRESS_CODE,
647     (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET),
648     UsbKeyboardDevice->DevicePath
649     );
650 
651   //
652   // Non-exhaustive reset:
653   // only reset private data structures.
654   //
655   if (!ExtendedVerification) {
656     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
657       EFI_PROGRESS_CODE,
658       (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER),
659       UsbKeyboardDevice->DevicePath
660       );
661     //
662     // Clear the key buffer of this USB keyboard
663     //
664     InitQueue (&UsbKeyboardDevice->UsbKeyQueue, sizeof (USB_KEY));
665     InitQueue (&UsbKeyboardDevice->EfiKeyQueue, sizeof (EFI_KEY_DATA));
666     InitQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify, sizeof (EFI_KEY_DATA));
667 
668     return EFI_SUCCESS;
669   }
670 
671   //
672   // Exhaustive reset
673   //
674   Status = InitUSBKeyboard (UsbKeyboardDevice);
675   if (EFI_ERROR (Status)) {
676     return EFI_DEVICE_ERROR;
677   }
678 
679   return EFI_SUCCESS;
680 }
681 
682 
683 /**
684   Reads the next keystroke from the input device.
685 
686   @param  This                 The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.
687   @param  Key                  A pointer to a buffer that is filled in with the keystroke
688                                information for the key that was pressed.
689 
690   @retval EFI_SUCCESS          The keystroke information was returned.
691   @retval EFI_NOT_READY        There was no keystroke data availiable.
692   @retval EFI_DEVICE_ERROR     The keystroke information was not returned due to
693                                hardware errors.
694 
695 **/
696 EFI_STATUS
697 EFIAPI
USBKeyboardReadKeyStroke(IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL * This,OUT EFI_INPUT_KEY * Key)698 USBKeyboardReadKeyStroke (
699   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL   *This,
700   OUT EFI_INPUT_KEY                    *Key
701   )
702 {
703   USB_KB_DEV   *UsbKeyboardDevice;
704   EFI_STATUS   Status;
705   EFI_KEY_DATA KeyData;
706 
707   UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
708 
709   //
710   // Considering if the partial keystroke is enabled, there maybe a partial
711   // keystroke in the queue, so here skip the partial keystroke and get the
712   // next key from the queue
713   //
714   while (1) {
715     Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData);
716     if (EFI_ERROR (Status)) {
717       return Status;
718     }
719     //
720     // SimpleTextIn Protocol doesn't support partial keystroke;
721     //
722     if (KeyData.Key.ScanCode == CHAR_NULL && KeyData.Key.UnicodeChar == SCAN_NULL) {
723       continue;
724     }
725     //
726     // Translate the CTRL-Alpha characters to their corresponding control value
727     // (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
728     //
729     if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
730       if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {
731         KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);
732       } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {
733         KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);
734       }
735     }
736 
737     CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
738     return EFI_SUCCESS;
739   }
740 }
741 
742 
743 /**
744   Event notification function registered for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx
745   and EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey.
746 
747   @param  Event        Event to be signaled when a key is pressed.
748   @param  Context      Points to USB_KB_DEV instance.
749 
750 **/
751 VOID
752 EFIAPI
USBKeyboardWaitForKey(IN EFI_EVENT Event,IN VOID * Context)753 USBKeyboardWaitForKey (
754   IN  EFI_EVENT               Event,
755   IN  VOID                    *Context
756   )
757 {
758   USB_KB_DEV  *UsbKeyboardDevice;
759   EFI_KEY_DATA KeyData;
760   EFI_TPL      OldTpl;
761 
762   UsbKeyboardDevice = (USB_KB_DEV *) Context;
763 
764   //
765   // Enter critical section
766   //
767   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
768 
769   //
770   // WaitforKey doesn't suppor the partial key.
771   // Considering if the partial keystroke is enabled, there maybe a partial
772   // keystroke in the queue, so here skip the partial keystroke and get the
773   // next key from the queue
774   //
775   while (!IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {
776     //
777     // If there is pending key, signal the event.
778     //
779     CopyMem (
780       &KeyData,
781       UsbKeyboardDevice->EfiKeyQueue.Buffer[UsbKeyboardDevice->EfiKeyQueue.Head],
782       sizeof (EFI_KEY_DATA)
783       );
784     if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
785       Dequeue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (EFI_KEY_DATA));
786       continue;
787     }
788     gBS->SignalEvent (Event);
789     break;
790   }
791   //
792   // Leave critical section and return
793   //
794   gBS->RestoreTPL (OldTpl);
795 }
796 
797 /**
798   Timer handler to convert the key from USB.
799 
800   @param  Event                    Indicates the event that invoke this function.
801   @param  Context                  Indicates the calling context.
802 **/
803 VOID
804 EFIAPI
USBKeyboardTimerHandler(IN EFI_EVENT Event,IN VOID * Context)805 USBKeyboardTimerHandler (
806   IN  EFI_EVENT                 Event,
807   IN  VOID                      *Context
808   )
809 {
810   EFI_STATUS                    Status;
811   USB_KB_DEV                    *UsbKeyboardDevice;
812   UINT8                         KeyCode;
813   EFI_KEY_DATA                  KeyData;
814 
815   UsbKeyboardDevice = (USB_KB_DEV *) Context;
816 
817   //
818   // Fetch raw data from the USB keyboard buffer,
819   // and translate it into USB keycode.
820   //
821   Status = USBParseKey (UsbKeyboardDevice, &KeyCode);
822   if (EFI_ERROR (Status)) {
823     return ;
824   }
825 
826   //
827   // Translate saved USB keycode into EFI_INPUT_KEY
828   //
829   Status = UsbKeyCodeToEfiInputKey (UsbKeyboardDevice, KeyCode, &KeyData);
830   if (EFI_ERROR (Status)) {
831     return ;
832   }
833 
834   //
835   // Insert to the EFI Key queue
836   //
837   Enqueue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (KeyData));
838 }
839 
840 /**
841   Free keyboard notify list.
842 
843   @param  NotifyList              The keyboard notify list to free.
844 
845   @retval EFI_SUCCESS             Free the notify list successfully.
846   @retval EFI_INVALID_PARAMETER   NotifyList is NULL.
847 
848 **/
849 EFI_STATUS
KbdFreeNotifyList(IN OUT LIST_ENTRY * NotifyList)850 KbdFreeNotifyList (
851   IN OUT LIST_ENTRY           *NotifyList
852   )
853 {
854   KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
855   LIST_ENTRY                    *Link;
856 
857   if (NotifyList == NULL) {
858     return EFI_INVALID_PARAMETER;
859   }
860   while (!IsListEmpty (NotifyList)) {
861     Link = GetFirstNode (NotifyList);
862     NotifyNode = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
863     RemoveEntryList (Link);
864     FreePool (NotifyNode);
865   }
866 
867   return EFI_SUCCESS;
868 }
869 
870 /**
871   Check whether the pressed key matches a registered key or not.
872 
873   @param  RegsiteredData    A pointer to keystroke data for the key that was registered.
874   @param  InputData         A pointer to keystroke data for the key that was pressed.
875 
876   @retval TRUE              Key pressed matches a registered key.
877   @retval FLASE             Key pressed does not matches a registered key.
878 
879 **/
880 BOOLEAN
IsKeyRegistered(IN EFI_KEY_DATA * RegsiteredData,IN EFI_KEY_DATA * InputData)881 IsKeyRegistered (
882   IN EFI_KEY_DATA  *RegsiteredData,
883   IN EFI_KEY_DATA  *InputData
884   )
885 {
886   ASSERT (RegsiteredData != NULL && InputData != NULL);
887 
888   if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
889       (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
890     return FALSE;
891   }
892 
893   //
894   // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
895   //
896   if (RegsiteredData->KeyState.KeyShiftState != 0 &&
897       RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
898     return FALSE;
899   }
900   if (RegsiteredData->KeyState.KeyToggleState != 0 &&
901       RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
902     return FALSE;
903   }
904 
905   return TRUE;
906 }
907 
908 //
909 // Simple Text Input Ex protocol functions
910 //
911 /**
912   Resets the input device hardware.
913 
914   The Reset() function resets the input device hardware. As part
915   of initialization process, the firmware/device will make a quick
916   but reasonable attempt to verify that the device is functioning.
917   If the ExtendedVerification flag is TRUE the firmware may take
918   an extended amount of time to verify the device is operating on
919   reset. Otherwise the reset operation is to occur as quickly as
920   possible. The hardware verification process is not defined by
921   this specification and is left up to the platform firmware or
922   driver to implement.
923 
924   @param This                 A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
925 
926   @param ExtendedVerification Indicates that the driver may perform a more exhaustive
927                               verification operation of the device during reset.
928 
929   @retval EFI_SUCCESS         The device was reset.
930   @retval EFI_DEVICE_ERROR    The device is not functioning correctly and could not be reset.
931 
932 **/
933 EFI_STATUS
934 EFIAPI
USBKeyboardResetEx(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN BOOLEAN ExtendedVerification)935 USBKeyboardResetEx (
936   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
937   IN BOOLEAN                            ExtendedVerification
938   )
939 {
940   EFI_STATUS                Status;
941   USB_KB_DEV                *UsbKeyboardDevice;
942 
943   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
944 
945   Status = UsbKeyboardDevice->SimpleInput.Reset (&UsbKeyboardDevice->SimpleInput, ExtendedVerification);
946   if (EFI_ERROR (Status)) {
947     return EFI_DEVICE_ERROR;
948   }
949 
950   UsbKeyboardDevice->KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID;
951   UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
952 
953   return EFI_SUCCESS;
954 
955 }
956 
957 /**
958   Reads the next keystroke from the input device.
959 
960   @param  This                   Protocol instance pointer.
961   @param  KeyData                A pointer to a buffer that is filled in with the keystroke
962                                  state data for the key that was pressed.
963 
964   @retval EFI_SUCCESS            The keystroke information was returned.
965   @retval EFI_NOT_READY          There was no keystroke data available.
966   @retval EFI_DEVICE_ERROR       The keystroke information was not returned due to
967                                  hardware errors.
968   @retval EFI_INVALID_PARAMETER  KeyData is NULL.
969 
970 **/
971 EFI_STATUS
972 EFIAPI
USBKeyboardReadKeyStrokeEx(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,OUT EFI_KEY_DATA * KeyData)973 USBKeyboardReadKeyStrokeEx (
974   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
975   OUT EFI_KEY_DATA                      *KeyData
976   )
977 {
978   USB_KB_DEV                        *UsbKeyboardDevice;
979 
980   if (KeyData == NULL) {
981     return EFI_INVALID_PARAMETER;
982   }
983 
984   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
985 
986   return USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, KeyData);
987 
988 }
989 
990 /**
991   Set certain state for the input device.
992 
993   @param  This                    Protocol instance pointer.
994   @param  KeyToggleState          A pointer to the EFI_KEY_TOGGLE_STATE to set the
995                                   state for the input device.
996 
997   @retval EFI_SUCCESS             The device state was set appropriately.
998   @retval EFI_DEVICE_ERROR        The device is not functioning correctly and could
999                                   not have the setting adjusted.
1000   @retval EFI_UNSUPPORTED         The device does not support the ability to have its state set.
1001   @retval EFI_INVALID_PARAMETER   KeyToggleState is NULL.
1002 
1003 **/
1004 EFI_STATUS
1005 EFIAPI
USBKeyboardSetState(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN EFI_KEY_TOGGLE_STATE * KeyToggleState)1006 USBKeyboardSetState (
1007   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
1008   IN EFI_KEY_TOGGLE_STATE               *KeyToggleState
1009   )
1010 {
1011   USB_KB_DEV                        *UsbKeyboardDevice;
1012 
1013   if (KeyToggleState == NULL) {
1014     return EFI_INVALID_PARAMETER;
1015   }
1016 
1017   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1018 
1019   if (((UsbKeyboardDevice->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) ||
1020       ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) {
1021     return EFI_UNSUPPORTED;
1022   }
1023 
1024   //
1025   // Update the status light
1026   //
1027 
1028   UsbKeyboardDevice->ScrollOn   = FALSE;
1029   UsbKeyboardDevice->NumLockOn  = FALSE;
1030   UsbKeyboardDevice->CapsOn     = FALSE;
1031   UsbKeyboardDevice->IsSupportPartialKey = FALSE;
1032 
1033   if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
1034     UsbKeyboardDevice->ScrollOn = TRUE;
1035   }
1036   if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
1037     UsbKeyboardDevice->NumLockOn = TRUE;
1038   }
1039   if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
1040     UsbKeyboardDevice->CapsOn = TRUE;
1041   }
1042   if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {
1043     UsbKeyboardDevice->IsSupportPartialKey = TRUE;
1044   }
1045 
1046   SetKeyLED (UsbKeyboardDevice);
1047 
1048   UsbKeyboardDevice->KeyState.KeyToggleState = *KeyToggleState;
1049 
1050   return EFI_SUCCESS;
1051 
1052 }
1053 
1054 /**
1055   Register a notification function for a particular keystroke for the input device.
1056 
1057   @param  This                        Protocol instance pointer.
1058   @param  KeyData                     A pointer to a buffer that is filled in with the keystroke
1059                                       information data for the key that was pressed.
1060   @param  KeyNotificationFunction     Points to the function to be called when the key
1061                                       sequence is typed specified by KeyData.
1062   @param  NotifyHandle                Points to the unique handle assigned to the registered notification.
1063 
1064   @retval EFI_SUCCESS                 The notification function was registered successfully.
1065   @retval EFI_OUT_OF_RESOURCES        Unable to allocate resources for necessary data structures.
1066   @retval EFI_INVALID_PARAMETER       KeyData or NotifyHandle or KeyNotificationFunction is NULL.
1067 
1068 **/
1069 EFI_STATUS
1070 EFIAPI
USBKeyboardRegisterKeyNotify(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN EFI_KEY_DATA * KeyData,IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,OUT VOID ** NotifyHandle)1071 USBKeyboardRegisterKeyNotify (
1072   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
1073   IN  EFI_KEY_DATA                       *KeyData,
1074   IN  EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,
1075   OUT VOID                               **NotifyHandle
1076   )
1077 {
1078   USB_KB_DEV                        *UsbKeyboardDevice;
1079   KEYBOARD_CONSOLE_IN_EX_NOTIFY     *NewNotify;
1080   LIST_ENTRY                        *Link;
1081   LIST_ENTRY                        *NotifyList;
1082   KEYBOARD_CONSOLE_IN_EX_NOTIFY     *CurrentNotify;
1083 
1084   if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
1085     return EFI_INVALID_PARAMETER;
1086   }
1087 
1088   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1089 
1090   //
1091   // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
1092   //
1093   NotifyList = &UsbKeyboardDevice->NotifyList;
1094 
1095   for (Link = GetFirstNode (NotifyList);
1096        !IsNull (NotifyList, Link);
1097        Link = GetNextNode (NotifyList, Link)) {
1098     CurrentNotify = CR (
1099                       Link,
1100                       KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1101                       NotifyEntry,
1102                       USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1103                       );
1104     if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
1105       if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
1106         *NotifyHandle = CurrentNotify;
1107         return EFI_SUCCESS;
1108       }
1109     }
1110   }
1111 
1112   //
1113   // Allocate resource to save the notification function
1114   //
1115   NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));
1116   if (NewNotify == NULL) {
1117     return EFI_OUT_OF_RESOURCES;
1118   }
1119 
1120   NewNotify->Signature         = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
1121   NewNotify->KeyNotificationFn = KeyNotificationFunction;
1122   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
1123   InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry);
1124 
1125 
1126   *NotifyHandle = NewNotify;
1127 
1128   return EFI_SUCCESS;
1129 
1130 }
1131 
1132 /**
1133   Remove a registered notification function from a particular keystroke.
1134 
1135   @param  This                      Protocol instance pointer.
1136   @param  NotificationHandle        The handle of the notification function being unregistered.
1137 
1138   @retval EFI_SUCCESS              The notification function was unregistered successfully.
1139   @retval EFI_INVALID_PARAMETER    The NotificationHandle is invalid
1140 
1141 **/
1142 EFI_STATUS
1143 EFIAPI
USBKeyboardUnregisterKeyNotify(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN VOID * NotificationHandle)1144 USBKeyboardUnregisterKeyNotify (
1145   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
1146   IN VOID                               *NotificationHandle
1147   )
1148 {
1149   USB_KB_DEV                        *UsbKeyboardDevice;
1150   KEYBOARD_CONSOLE_IN_EX_NOTIFY     *CurrentNotify;
1151   LIST_ENTRY                        *Link;
1152   LIST_ENTRY                        *NotifyList;
1153 
1154   if (NotificationHandle == NULL) {
1155     return EFI_INVALID_PARAMETER;
1156   }
1157 
1158   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1159 
1160   //
1161   // Traverse notify list of USB keyboard and remove the entry of NotificationHandle.
1162   //
1163   NotifyList = &UsbKeyboardDevice->NotifyList;
1164   for (Link = GetFirstNode (NotifyList);
1165        !IsNull (NotifyList, Link);
1166        Link = GetNextNode (NotifyList, Link)) {
1167     CurrentNotify = CR (
1168                       Link,
1169                       KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1170                       NotifyEntry,
1171                       USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1172                       );
1173     if (CurrentNotify == NotificationHandle) {
1174       //
1175       // Remove the notification function from NotifyList and free resources
1176       //
1177       RemoveEntryList (&CurrentNotify->NotifyEntry);
1178 
1179       FreePool (CurrentNotify);
1180       return EFI_SUCCESS;
1181     }
1182   }
1183 
1184   //
1185   // Cannot find the matching entry in database.
1186   //
1187   return EFI_INVALID_PARAMETER;
1188 }
1189 
1190 /**
1191   Process key notify.
1192 
1193   @param  Event                 Indicates the event that invoke this function.
1194   @param  Context               Indicates the calling context.
1195 **/
1196 VOID
1197 EFIAPI
KeyNotifyProcessHandler(IN EFI_EVENT Event,IN VOID * Context)1198 KeyNotifyProcessHandler (
1199   IN  EFI_EVENT                 Event,
1200   IN  VOID                      *Context
1201   )
1202 {
1203   EFI_STATUS                    Status;
1204   USB_KB_DEV                    *UsbKeyboardDevice;
1205   EFI_KEY_DATA                  KeyData;
1206   LIST_ENTRY                    *Link;
1207   LIST_ENTRY                    *NotifyList;
1208   KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1209   EFI_TPL                       OldTpl;
1210 
1211   UsbKeyboardDevice = (USB_KB_DEV *) Context;
1212 
1213   //
1214   // Invoke notification functions.
1215   //
1216   NotifyList = &UsbKeyboardDevice->NotifyList;
1217   while (TRUE) {
1218     //
1219     // Enter critical section
1220     //
1221     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1222     Status = Dequeue (&UsbKeyboardDevice->EfiKeyQueueForNotify, &KeyData, sizeof (KeyData));
1223     //
1224     // Leave critical section
1225     //
1226     gBS->RestoreTPL (OldTpl);
1227     if (EFI_ERROR (Status)) {
1228       break;
1229     }
1230     for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
1231       CurrentNotify = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
1232       if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
1233         CurrentNotify->KeyNotificationFn (&KeyData);
1234       }
1235     }
1236   }
1237 }
1238 
1239