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 - 2012, 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   //
316   // Install Simple Text Input Protocol and Simple Text Input Ex Protocol
317   // for the USB keyboard device.
318   // USB keyboard is a hot plug device, and expected to work immediately
319   // when plugging into system, other conventional console devices could
320   // distinguish it by its device path.
321   //
322   Status = gBS->InstallMultipleProtocolInterfaces (
323                   &Controller,
324                   &gEfiSimpleTextInProtocolGuid,
325                   &UsbKeyboardDevice->SimpleInput,
326                   &gEfiSimpleTextInputExProtocolGuid,
327                   &UsbKeyboardDevice->SimpleInputEx,
328                   NULL
329                   );
330   if (EFI_ERROR (Status)) {
331     goto ErrorExit;
332   }
333 
334   UsbKeyboardDevice->ControllerHandle = Controller;
335   Status = InitKeyboardLayout (UsbKeyboardDevice);
336   if (EFI_ERROR (Status)) {
337     gBS->UninstallMultipleProtocolInterfaces (
338       Controller,
339       &gEfiSimpleTextInProtocolGuid,
340       &UsbKeyboardDevice->SimpleInput,
341       &gEfiSimpleTextInputExProtocolGuid,
342       &UsbKeyboardDevice->SimpleInputEx,
343       NULL
344       );
345     goto ErrorExit;
346   }
347 
348 
349   //
350   // Reset USB Keyboard Device exhaustively.
351   //
352   Status = UsbKeyboardDevice->SimpleInputEx.Reset (
353                                             &UsbKeyboardDevice->SimpleInputEx,
354                                             TRUE
355                                             );
356   if (EFI_ERROR (Status)) {
357     gBS->UninstallMultipleProtocolInterfaces (
358            Controller,
359            &gEfiSimpleTextInProtocolGuid,
360            &UsbKeyboardDevice->SimpleInput,
361            &gEfiSimpleTextInputExProtocolGuid,
362            &UsbKeyboardDevice->SimpleInputEx,
363            NULL
364            );
365     goto ErrorExit;
366   }
367 
368   //
369   // Submit Asynchronous Interrupt Transfer to manage this device.
370   //
371   EndpointAddr    = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress;
372   PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval;
373   PacketSize      = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize);
374 
375   Status = UsbIo->UsbAsyncInterruptTransfer (
376                     UsbIo,
377                     EndpointAddr,
378                     TRUE,
379                     PollingInterval,
380                     PacketSize,
381                     KeyboardHandler,
382                     UsbKeyboardDevice
383                     );
384 
385   if (EFI_ERROR (Status)) {
386     gBS->UninstallMultipleProtocolInterfaces (
387            Controller,
388            &gEfiSimpleTextInProtocolGuid,
389            &UsbKeyboardDevice->SimpleInput,
390            &gEfiSimpleTextInputExProtocolGuid,
391            &UsbKeyboardDevice->SimpleInputEx,
392            NULL
393            );
394     goto ErrorExit;
395   }
396 
397   UsbKeyboardDevice->ControllerNameTable = NULL;
398   AddUnicodeString2 (
399     "eng",
400     gUsbKeyboardComponentName.SupportedLanguages,
401     &UsbKeyboardDevice->ControllerNameTable,
402     L"Generic Usb Keyboard",
403     TRUE
404     );
405   AddUnicodeString2 (
406     "en",
407     gUsbKeyboardComponentName2.SupportedLanguages,
408     &UsbKeyboardDevice->ControllerNameTable,
409     L"Generic Usb Keyboard",
410     FALSE
411     );
412 
413   gBS->RestoreTPL (OldTpl);
414   return EFI_SUCCESS;
415 
416 //
417 // Error handler
418 //
419 ErrorExit:
420   if (UsbKeyboardDevice != NULL) {
421     if (UsbKeyboardDevice->TimerEvent != NULL) {
422       gBS->CloseEvent (UsbKeyboardDevice->TimerEvent);
423     }
424     if (UsbKeyboardDevice->SimpleInput.WaitForKey != NULL) {
425       gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
426     }
427     if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) {
428       gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
429     }
430     if (UsbKeyboardDevice->KeyboardLayoutEvent != NULL) {
431       ReleaseKeyboardLayoutResources (UsbKeyboardDevice);
432       gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);
433     }
434     FreePool (UsbKeyboardDevice);
435     UsbKeyboardDevice = NULL;
436   }
437   gBS->CloseProtocol (
438          Controller,
439          &gEfiUsbIoProtocolGuid,
440          This->DriverBindingHandle,
441          Controller
442          );
443 
444 ErrorExit1:
445   gBS->RestoreTPL (OldTpl);
446 
447   return Status;
448 
449 }
450 
451 
452 /**
453   Stop the USB keyboard device handled by this driver.
454 
455   @param  This                   The USB keyboard driver binding protocol.
456   @param  Controller             The controller to release.
457   @param  NumberOfChildren       The number of handles in ChildHandleBuffer.
458   @param  ChildHandleBuffer      The array of child handle.
459 
460   @retval EFI_SUCCESS            The device was stopped.
461   @retval EFI_UNSUPPORTED        Simple Text In Protocol or Simple Text In Ex Protocol
462                                  is not installed on Controller.
463   @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.
464   @retval Others                 Fail to uninstall protocols attached on the device.
465 
466 **/
467 EFI_STATUS
468 EFIAPI
USBKeyboardDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)469 USBKeyboardDriverBindingStop (
470   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
471   IN  EFI_HANDLE                     Controller,
472   IN  UINTN                          NumberOfChildren,
473   IN  EFI_HANDLE                     *ChildHandleBuffer
474   )
475 {
476   EFI_STATUS                     Status;
477   EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleInput;
478   USB_KB_DEV                     *UsbKeyboardDevice;
479 
480   Status = gBS->OpenProtocol (
481                   Controller,
482                   &gEfiSimpleTextInProtocolGuid,
483                   (VOID **) &SimpleInput,
484                   This->DriverBindingHandle,
485                   Controller,
486                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
487                   );
488   if (EFI_ERROR (Status)) {
489     return EFI_UNSUPPORTED;
490   }
491 
492   Status = gBS->OpenProtocol (
493                   Controller,
494                   &gEfiSimpleTextInputExProtocolGuid,
495                   NULL,
496                   This->DriverBindingHandle,
497                   Controller,
498                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
499                   );
500   if (EFI_ERROR (Status)) {
501     return EFI_UNSUPPORTED;
502   }
503 
504   UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput);
505 
506   //
507   // The key data input from this device will be disabled.
508   //
509   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
510     EFI_PROGRESS_CODE,
511     (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE),
512     UsbKeyboardDevice->DevicePath
513     );
514 
515   //
516   // Delete the Asynchronous Interrupt Transfer from this device
517   //
518   UsbKeyboardDevice->UsbIo->UsbAsyncInterruptTransfer (
519                               UsbKeyboardDevice->UsbIo,
520                               UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
521                               FALSE,
522                               UsbKeyboardDevice->IntEndpointDescriptor.Interval,
523                               0,
524                               NULL,
525                               NULL
526                               );
527 
528   gBS->CloseProtocol (
529          Controller,
530          &gEfiUsbIoProtocolGuid,
531          This->DriverBindingHandle,
532          Controller
533          );
534 
535   Status = gBS->UninstallMultipleProtocolInterfaces (
536                   Controller,
537                   &gEfiSimpleTextInProtocolGuid,
538                   &UsbKeyboardDevice->SimpleInput,
539                   &gEfiSimpleTextInputExProtocolGuid,
540                   &UsbKeyboardDevice->SimpleInputEx,
541                   NULL
542                   );
543   //
544   // Free all resources.
545   //
546   gBS->CloseEvent (UsbKeyboardDevice->TimerEvent);
547   gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer);
548   gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent);
549   gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
550   gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
551   KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList);
552 
553   ReleaseKeyboardLayoutResources (UsbKeyboardDevice);
554   gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);
555 
556   if (UsbKeyboardDevice->ControllerNameTable != NULL) {
557     FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable);
558   }
559 
560   DestroyQueue (&UsbKeyboardDevice->UsbKeyQueue);
561   DestroyQueue (&UsbKeyboardDevice->EfiKeyQueue);
562 
563   FreePool (UsbKeyboardDevice);
564 
565   return Status;
566 }
567 
568 /**
569   Internal function to read the next keystroke from the keyboard buffer.
570 
571   @param  UsbKeyboardDevice       USB keyboard's private structure.
572   @param  KeyData                 A pointer to buffer to hold the keystroke
573                                   data for the key that was pressed.
574 
575   @retval EFI_SUCCESS             The keystroke information was returned.
576   @retval EFI_NOT_READY           There was no keystroke data availiable.
577   @retval EFI_DEVICE_ERROR        The keystroke information was not returned due to
578                                   hardware errors.
579   @retval EFI_INVALID_PARAMETER   KeyData is NULL.
580   @retval Others                  Fail to translate keycode into EFI_INPUT_KEY
581 
582 **/
583 EFI_STATUS
USBKeyboardReadKeyStrokeWorker(IN OUT USB_KB_DEV * UsbKeyboardDevice,OUT EFI_KEY_DATA * KeyData)584 USBKeyboardReadKeyStrokeWorker (
585   IN OUT USB_KB_DEV                 *UsbKeyboardDevice,
586      OUT EFI_KEY_DATA               *KeyData
587   )
588 {
589   if (KeyData == NULL) {
590     return EFI_INVALID_PARAMETER;
591   }
592 
593   if (IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {
594     return EFI_NOT_READY;
595   }
596 
597   Dequeue (&UsbKeyboardDevice->EfiKeyQueue, KeyData, sizeof (*KeyData));
598 
599   return EFI_SUCCESS;
600 }
601 
602 /**
603   Reset the input device and optionally run diagnostics
604 
605   There are 2 types of reset for USB keyboard.
606   For non-exhaustive reset, only keyboard buffer is cleared.
607   For exhaustive reset, in addition to clearance of keyboard buffer, the hardware status
608   is also re-initialized.
609 
610   @param  This                 Protocol instance pointer.
611   @param  ExtendedVerification Driver may perform diagnostics on reset.
612 
613   @retval EFI_SUCCESS          The device was reset.
614   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could not be reset.
615 
616 **/
617 EFI_STATUS
618 EFIAPI
USBKeyboardReset(IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL * This,IN BOOLEAN ExtendedVerification)619 USBKeyboardReset (
620   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL   *This,
621   IN  BOOLEAN                          ExtendedVerification
622   )
623 {
624   EFI_STATUS          Status;
625   USB_KB_DEV          *UsbKeyboardDevice;
626 
627   UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
628 
629   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
630     EFI_PROGRESS_CODE,
631     (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET),
632     UsbKeyboardDevice->DevicePath
633     );
634 
635   //
636   // Non-exhaustive reset:
637   // only reset private data structures.
638   //
639   if (!ExtendedVerification) {
640     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
641       EFI_PROGRESS_CODE,
642       (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER),
643       UsbKeyboardDevice->DevicePath
644       );
645     //
646     // Clear the key buffer of this USB keyboard
647     //
648     InitQueue (&UsbKeyboardDevice->UsbKeyQueue, sizeof (USB_KEY));
649     InitQueue (&UsbKeyboardDevice->EfiKeyQueue, sizeof (EFI_KEY_DATA));
650 
651     return EFI_SUCCESS;
652   }
653 
654   //
655   // Exhaustive reset
656   //
657   Status = InitUSBKeyboard (UsbKeyboardDevice);
658   if (EFI_ERROR (Status)) {
659     return EFI_DEVICE_ERROR;
660   }
661 
662   return EFI_SUCCESS;
663 }
664 
665 
666 /**
667   Reads the next keystroke from the input device.
668 
669   @param  This                 The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.
670   @param  Key                  A pointer to a buffer that is filled in with the keystroke
671                                information for the key that was pressed.
672 
673   @retval EFI_SUCCESS          The keystroke information was returned.
674   @retval EFI_NOT_READY        There was no keystroke data availiable.
675   @retval EFI_DEVICE_ERROR     The keystroke information was not returned due to
676                                hardware errors.
677 
678 **/
679 EFI_STATUS
680 EFIAPI
USBKeyboardReadKeyStroke(IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL * This,OUT EFI_INPUT_KEY * Key)681 USBKeyboardReadKeyStroke (
682   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL   *This,
683   OUT EFI_INPUT_KEY                    *Key
684   )
685 {
686   USB_KB_DEV   *UsbKeyboardDevice;
687   EFI_STATUS   Status;
688   EFI_KEY_DATA KeyData;
689 
690   UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
691 
692   //
693   // Considering if the partial keystroke is enabled, there maybe a partial
694   // keystroke in the queue, so here skip the partial keystroke and get the
695   // next key from the queue
696   //
697   while (1) {
698     Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData);
699     if (EFI_ERROR (Status)) {
700       return Status;
701     }
702     //
703     // SimpleTextIn Protocol doesn't support partial keystroke;
704     //
705     if (KeyData.Key.ScanCode == CHAR_NULL && KeyData.Key.UnicodeChar == SCAN_NULL) {
706       continue;
707     }
708     //
709     // Translate the CTRL-Alpha characters to their corresponding control value
710     // (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
711     //
712     if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
713       if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {
714         KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);
715       } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {
716         KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);
717       }
718     }
719 
720     CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
721     return EFI_SUCCESS;
722   }
723 }
724 
725 
726 /**
727   Event notification function registered for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx
728   and EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey.
729 
730   @param  Event        Event to be signaled when a key is pressed.
731   @param  Context      Points to USB_KB_DEV instance.
732 
733 **/
734 VOID
735 EFIAPI
USBKeyboardWaitForKey(IN EFI_EVENT Event,IN VOID * Context)736 USBKeyboardWaitForKey (
737   IN  EFI_EVENT               Event,
738   IN  VOID                    *Context
739   )
740 {
741   USB_KB_DEV  *UsbKeyboardDevice;
742   EFI_KEY_DATA KeyData;
743   EFI_TPL      OldTpl;
744 
745   UsbKeyboardDevice = (USB_KB_DEV *) Context;
746 
747   //
748   // Enter critical section
749   //
750   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
751 
752   //
753   // WaitforKey doesn't suppor the partial key.
754   // Considering if the partial keystroke is enabled, there maybe a partial
755   // keystroke in the queue, so here skip the partial keystroke and get the
756   // next key from the queue
757   //
758   while (!IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {
759     //
760     // If there is pending key, signal the event.
761     //
762     CopyMem (
763       &KeyData,
764       UsbKeyboardDevice->EfiKeyQueue.Buffer[UsbKeyboardDevice->EfiKeyQueue.Head],
765       sizeof (EFI_KEY_DATA)
766       );
767     if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
768       Dequeue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (EFI_KEY_DATA));
769       continue;
770     }
771     gBS->SignalEvent (Event);
772     break;
773   }
774   //
775   // Leave critical section and return
776   //
777   gBS->RestoreTPL (OldTpl);
778 }
779 
780 /**
781   Timer handler to convert the key from USB.
782 
783   @param  Event                    Indicates the event that invoke this function.
784   @param  Context                  Indicates the calling context.
785 **/
786 VOID
787 EFIAPI
USBKeyboardTimerHandler(IN EFI_EVENT Event,IN VOID * Context)788 USBKeyboardTimerHandler (
789   IN  EFI_EVENT                 Event,
790   IN  VOID                      *Context
791   )
792 {
793   EFI_STATUS                    Status;
794   USB_KB_DEV                    *UsbKeyboardDevice;
795   UINT8                         KeyCode;
796   EFI_KEY_DATA                  KeyData;
797 
798   UsbKeyboardDevice = (USB_KB_DEV *) Context;
799 
800   //
801   // Fetch raw data from the USB keyboard buffer,
802   // and translate it into USB keycode.
803   //
804   Status = USBParseKey (UsbKeyboardDevice, &KeyCode);
805   if (EFI_ERROR (Status)) {
806     return ;
807   }
808 
809   //
810   // Translate saved USB keycode into EFI_INPUT_KEY
811   //
812   Status = UsbKeyCodeToEfiInputKey (UsbKeyboardDevice, KeyCode, &KeyData);
813   if (EFI_ERROR (Status)) {
814     return ;
815   }
816 
817   //
818   // Insert to the EFI Key queue
819   //
820   Enqueue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (KeyData));
821 }
822 
823 /**
824   Free keyboard notify list.
825 
826   @param  NotifyList              The keyboard notify list to free.
827 
828   @retval EFI_SUCCESS             Free the notify list successfully.
829   @retval EFI_INVALID_PARAMETER   NotifyList is NULL.
830 
831 **/
832 EFI_STATUS
KbdFreeNotifyList(IN OUT LIST_ENTRY * NotifyList)833 KbdFreeNotifyList (
834   IN OUT LIST_ENTRY           *NotifyList
835   )
836 {
837   KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
838   LIST_ENTRY                    *Link;
839 
840   if (NotifyList == NULL) {
841     return EFI_INVALID_PARAMETER;
842   }
843   while (!IsListEmpty (NotifyList)) {
844     Link = GetFirstNode (NotifyList);
845     NotifyNode = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
846     RemoveEntryList (Link);
847     FreePool (NotifyNode);
848   }
849 
850   return EFI_SUCCESS;
851 }
852 
853 /**
854   Check whether the pressed key matches a registered key or not.
855 
856   @param  RegsiteredData    A pointer to keystroke data for the key that was registered.
857   @param  InputData         A pointer to keystroke data for the key that was pressed.
858 
859   @retval TRUE              Key pressed matches a registered key.
860   @retval FLASE             Key pressed does not matches a registered key.
861 
862 **/
863 BOOLEAN
IsKeyRegistered(IN EFI_KEY_DATA * RegsiteredData,IN EFI_KEY_DATA * InputData)864 IsKeyRegistered (
865   IN EFI_KEY_DATA  *RegsiteredData,
866   IN EFI_KEY_DATA  *InputData
867   )
868 {
869   ASSERT (RegsiteredData != NULL && InputData != NULL);
870 
871   if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
872       (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
873     return FALSE;
874   }
875 
876   //
877   // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
878   //
879   if (RegsiteredData->KeyState.KeyShiftState != 0 &&
880       RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
881     return FALSE;
882   }
883   if (RegsiteredData->KeyState.KeyToggleState != 0 &&
884       RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
885     return FALSE;
886   }
887 
888   return TRUE;
889 }
890 
891 //
892 // Simple Text Input Ex protocol functions
893 //
894 /**
895   Resets the input device hardware.
896 
897   The Reset() function resets the input device hardware. As part
898   of initialization process, the firmware/device will make a quick
899   but reasonable attempt to verify that the device is functioning.
900   If the ExtendedVerification flag is TRUE the firmware may take
901   an extended amount of time to verify the device is operating on
902   reset. Otherwise the reset operation is to occur as quickly as
903   possible. The hardware verification process is not defined by
904   this specification and is left up to the platform firmware or
905   driver to implement.
906 
907   @param This                 A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
908 
909   @param ExtendedVerification Indicates that the driver may perform a more exhaustive
910                               verification operation of the device during reset.
911 
912   @retval EFI_SUCCESS         The device was reset.
913   @retval EFI_DEVICE_ERROR    The device is not functioning correctly and could not be reset.
914 
915 **/
916 EFI_STATUS
917 EFIAPI
USBKeyboardResetEx(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN BOOLEAN ExtendedVerification)918 USBKeyboardResetEx (
919   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
920   IN BOOLEAN                            ExtendedVerification
921   )
922 {
923   EFI_STATUS                Status;
924   USB_KB_DEV                *UsbKeyboardDevice;
925 
926   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
927 
928   Status = UsbKeyboardDevice->SimpleInput.Reset (&UsbKeyboardDevice->SimpleInput, ExtendedVerification);
929   if (EFI_ERROR (Status)) {
930     return EFI_DEVICE_ERROR;
931   }
932 
933   UsbKeyboardDevice->KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID;
934   UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
935 
936   return EFI_SUCCESS;
937 
938 }
939 
940 /**
941   Reads the next keystroke from the input device.
942 
943   @param  This                   Protocol instance pointer.
944   @param  KeyData                A pointer to a buffer that is filled in with the keystroke
945                                  state data for the key that was pressed.
946 
947   @retval EFI_SUCCESS            The keystroke information was returned.
948   @retval EFI_NOT_READY          There was no keystroke data available.
949   @retval EFI_DEVICE_ERROR       The keystroke information was not returned due to
950                                  hardware errors.
951   @retval EFI_INVALID_PARAMETER  KeyData is NULL.
952 
953 **/
954 EFI_STATUS
955 EFIAPI
USBKeyboardReadKeyStrokeEx(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,OUT EFI_KEY_DATA * KeyData)956 USBKeyboardReadKeyStrokeEx (
957   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
958   OUT EFI_KEY_DATA                      *KeyData
959   )
960 {
961   USB_KB_DEV                        *UsbKeyboardDevice;
962 
963   if (KeyData == NULL) {
964     return EFI_INVALID_PARAMETER;
965   }
966 
967   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
968 
969   return USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, KeyData);
970 
971 }
972 
973 /**
974   Set certain state for the input device.
975 
976   @param  This                    Protocol instance pointer.
977   @param  KeyToggleState          A pointer to the EFI_KEY_TOGGLE_STATE to set the
978                                   state for the input device.
979 
980   @retval EFI_SUCCESS             The device state was set appropriately.
981   @retval EFI_DEVICE_ERROR        The device is not functioning correctly and could
982                                   not have the setting adjusted.
983   @retval EFI_UNSUPPORTED         The device does not support the ability to have its state set.
984   @retval EFI_INVALID_PARAMETER   KeyToggleState is NULL.
985 
986 **/
987 EFI_STATUS
988 EFIAPI
USBKeyboardSetState(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN EFI_KEY_TOGGLE_STATE * KeyToggleState)989 USBKeyboardSetState (
990   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
991   IN EFI_KEY_TOGGLE_STATE               *KeyToggleState
992   )
993 {
994   USB_KB_DEV                        *UsbKeyboardDevice;
995 
996   if (KeyToggleState == NULL) {
997     return EFI_INVALID_PARAMETER;
998   }
999 
1000   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1001 
1002   if (((UsbKeyboardDevice->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) ||
1003       ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) {
1004     return EFI_UNSUPPORTED;
1005   }
1006 
1007   //
1008   // Update the status light
1009   //
1010 
1011   UsbKeyboardDevice->ScrollOn   = FALSE;
1012   UsbKeyboardDevice->NumLockOn  = FALSE;
1013   UsbKeyboardDevice->CapsOn     = FALSE;
1014   UsbKeyboardDevice->IsSupportPartialKey = FALSE;
1015 
1016   if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
1017     UsbKeyboardDevice->ScrollOn = TRUE;
1018   }
1019   if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
1020     UsbKeyboardDevice->NumLockOn = TRUE;
1021   }
1022   if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
1023     UsbKeyboardDevice->CapsOn = TRUE;
1024   }
1025   if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {
1026     UsbKeyboardDevice->IsSupportPartialKey = TRUE;
1027   }
1028 
1029   SetKeyLED (UsbKeyboardDevice);
1030 
1031   UsbKeyboardDevice->KeyState.KeyToggleState = *KeyToggleState;
1032 
1033   return EFI_SUCCESS;
1034 
1035 }
1036 
1037 /**
1038   Register a notification function for a particular keystroke for the input device.
1039 
1040   @param  This                        Protocol instance pointer.
1041   @param  KeyData                     A pointer to a buffer that is filled in with the keystroke
1042                                       information data for the key that was pressed.
1043   @param  KeyNotificationFunction     Points to the function to be called when the key
1044                                       sequence is typed specified by KeyData.
1045   @param  NotifyHandle                Points to the unique handle assigned to the registered notification.
1046 
1047   @retval EFI_SUCCESS                 The notification function was registered successfully.
1048   @retval EFI_OUT_OF_RESOURCES        Unable to allocate resources for necessary data structures.
1049   @retval EFI_INVALID_PARAMETER       KeyData or NotifyHandle or KeyNotificationFunction is NULL.
1050 
1051 **/
1052 EFI_STATUS
1053 EFIAPI
USBKeyboardRegisterKeyNotify(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN EFI_KEY_DATA * KeyData,IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,OUT VOID ** NotifyHandle)1054 USBKeyboardRegisterKeyNotify (
1055   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
1056   IN  EFI_KEY_DATA                       *KeyData,
1057   IN  EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,
1058   OUT VOID                               **NotifyHandle
1059   )
1060 {
1061   USB_KB_DEV                        *UsbKeyboardDevice;
1062   KEYBOARD_CONSOLE_IN_EX_NOTIFY     *NewNotify;
1063   LIST_ENTRY                        *Link;
1064   LIST_ENTRY                        *NotifyList;
1065   KEYBOARD_CONSOLE_IN_EX_NOTIFY     *CurrentNotify;
1066 
1067   if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
1068     return EFI_INVALID_PARAMETER;
1069   }
1070 
1071   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1072 
1073   //
1074   // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
1075   //
1076   NotifyList = &UsbKeyboardDevice->NotifyList;
1077 
1078   for (Link = GetFirstNode (NotifyList);
1079        !IsNull (NotifyList, Link);
1080        Link = GetNextNode (NotifyList, Link)) {
1081     CurrentNotify = CR (
1082                       Link,
1083                       KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1084                       NotifyEntry,
1085                       USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1086                       );
1087     if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
1088       if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
1089         *NotifyHandle = CurrentNotify;
1090         return EFI_SUCCESS;
1091       }
1092     }
1093   }
1094 
1095   //
1096   // Allocate resource to save the notification function
1097   //
1098   NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));
1099   if (NewNotify == NULL) {
1100     return EFI_OUT_OF_RESOURCES;
1101   }
1102 
1103   NewNotify->Signature         = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
1104   NewNotify->KeyNotificationFn = KeyNotificationFunction;
1105   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
1106   InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry);
1107 
1108 
1109   *NotifyHandle = NewNotify;
1110 
1111   return EFI_SUCCESS;
1112 
1113 }
1114 
1115 /**
1116   Remove a registered notification function from a particular keystroke.
1117 
1118   @param  This                      Protocol instance pointer.
1119   @param  NotificationHandle        The handle of the notification function being unregistered.
1120 
1121   @retval EFI_SUCCESS              The notification function was unregistered successfully.
1122   @retval EFI_INVALID_PARAMETER    The NotificationHandle is invalid
1123 
1124 **/
1125 EFI_STATUS
1126 EFIAPI
USBKeyboardUnregisterKeyNotify(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * This,IN VOID * NotificationHandle)1127 USBKeyboardUnregisterKeyNotify (
1128   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
1129   IN VOID                               *NotificationHandle
1130   )
1131 {
1132   USB_KB_DEV                        *UsbKeyboardDevice;
1133   KEYBOARD_CONSOLE_IN_EX_NOTIFY     *CurrentNotify;
1134   LIST_ENTRY                        *Link;
1135   LIST_ENTRY                        *NotifyList;
1136 
1137   if (NotificationHandle == NULL) {
1138     return EFI_INVALID_PARAMETER;
1139   }
1140 
1141   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1142 
1143   //
1144   // Traverse notify list of USB keyboard and remove the entry of NotificationHandle.
1145   //
1146   NotifyList = &UsbKeyboardDevice->NotifyList;
1147   for (Link = GetFirstNode (NotifyList);
1148        !IsNull (NotifyList, Link);
1149        Link = GetNextNode (NotifyList, Link)) {
1150     CurrentNotify = CR (
1151                       Link,
1152                       KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1153                       NotifyEntry,
1154                       USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1155                       );
1156     if (CurrentNotify == NotificationHandle) {
1157       //
1158       // Remove the notification function from NotifyList and free resources
1159       //
1160       RemoveEntryList (&CurrentNotify->NotifyEntry);
1161 
1162       FreePool (CurrentNotify);
1163       return EFI_SUCCESS;
1164     }
1165   }
1166 
1167   //
1168   // Cannot find the matching entry in database.
1169   //
1170   return EFI_INVALID_PARAMETER;
1171 }
1172 
1173