]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c
MdeModulePkg/Usb/EfiKey: Fix endpoint selection
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbKbDxe / EfiKey.c
index 001158018fe80227fa1a73222c49816082694268..ccb389067a615142bb48d655a6304d5d1c8fa3cd 100644 (file)
@@ -2,14 +2,8 @@
   USB Keyboard Driver that manages USB keyboard and produces Simple Text Input\r
   Protocol and Simple Text Input Ex Protocol.\r
 \r
-Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution.  The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -221,7 +215,7 @@ USBKeyboardDriverBindingStart (
   EndpointNumber = UsbKeyboardDevice->InterfaceDescriptor.NumEndpoints;\r
 \r
   //\r
-  // Traverse endpoints to find interrupt endpoint\r
+  // Traverse endpoints to find interrupt endpoint IN\r
   //\r
   Found = FALSE;\r
   for (Index = 0; Index < EndpointNumber; Index++) {\r
@@ -232,7 +226,8 @@ USBKeyboardDriverBindingStart (
              &EndpointDescriptor\r
              );\r
 \r
-    if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) {\r
+    if (((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) &&\r
+        ((EndpointDescriptor.EndpointAddress & USB_ENDPOINT_DIR_IN) != 0)) {\r
       //\r
       // We only care interrupt endpoint here\r
       //\r
@@ -244,12 +239,25 @@ USBKeyboardDriverBindingStart (
 \r
   if (!Found) {\r
     //\r
+    // Report Status Code to indicate that there is no USB keyboard\r
+    //\r
+    REPORT_STATUS_CODE (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      (EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED)\r
+      );\r
+    //\r
     // No interrupt endpoint found, then return unsupported.\r
     //\r
     Status = EFI_UNSUPPORTED;\r
     goto ErrorExit;\r
   }\r
 \r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DETECTED),\r
+    UsbKeyboardDevice->DevicePath\r
+    );\r
+\r
   UsbKeyboardDevice->Signature                  = USB_KB_DEV_SIGNATURE;\r
   UsbKeyboardDevice->SimpleInput.Reset          = USBKeyboardReset;\r
   UsbKeyboardDevice->SimpleInput.ReadKeyStroke  = USBKeyboardReadKeyStroke;\r
@@ -299,6 +307,17 @@ USBKeyboardDriverBindingStart (
     goto ErrorExit;\r
   }\r
 \r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  KeyNotifyProcessHandler,\r
+                  UsbKeyboardDevice,\r
+                  &UsbKeyboardDevice->KeyNotifyProcessEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ErrorExit;\r
+  }\r
+\r
   //\r
   // Install Simple Text Input Protocol and Simple Text Input Ex Protocol\r
   // for the USB keyboard device.\r
@@ -414,6 +433,9 @@ ErrorExit:
     if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) {\r
       gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);\r
     }\r
+    if (UsbKeyboardDevice->KeyNotifyProcessEvent != NULL) {\r
+      gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent);\r
+    }\r
     if (UsbKeyboardDevice->KeyboardLayoutEvent != NULL) {\r
       ReleaseKeyboardLayoutResources (UsbKeyboardDevice);\r
       gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);\r
@@ -535,6 +557,7 @@ USBKeyboardDriverBindingStop (
   gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent);\r
   gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);\r
   gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);\r
+  gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent);\r
   KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList);\r
 \r
   ReleaseKeyboardLayoutResources (UsbKeyboardDevice);\r
@@ -546,6 +569,7 @@ USBKeyboardDriverBindingStop (
 \r
   DestroyQueue (&UsbKeyboardDevice->UsbKeyQueue);\r
   DestroyQueue (&UsbKeyboardDevice->EfiKeyQueue);\r
+  DestroyQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify);\r
 \r
   FreePool (UsbKeyboardDevice);\r
 \r
@@ -578,6 +602,8 @@ USBKeyboardReadKeyStrokeWorker (
   }\r
 \r
   if (IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {\r
+    ZeroMem (&KeyData->Key, sizeof (KeyData->Key));\r
+    InitializeKeyState (UsbKeyboardDevice, &KeyData->KeyState);\r
     return EFI_NOT_READY;\r
   }\r
 \r
@@ -634,6 +660,7 @@ USBKeyboardReset (
     //\r
     InitQueue (&UsbKeyboardDevice->UsbKeyQueue, sizeof (USB_KEY));\r
     InitQueue (&UsbKeyboardDevice->EfiKeyQueue, sizeof (EFI_KEY_DATA));\r
+    InitQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify, sizeof (EFI_KEY_DATA));\r
 \r
     return EFI_SUCCESS;\r
   }\r
@@ -733,9 +760,9 @@ USBKeyboardWaitForKey (
 \r
   //\r
   // Enter critical section\r
-  //  \r
+  //\r
   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
-  \r
+\r
   //\r
   // WaitforKey doesn't suppor the partial key.\r
   // Considering if the partial keystroke is enabled, there maybe a partial\r
@@ -1025,10 +1052,14 @@ USBKeyboardSetState (
   Register a notification function for a particular keystroke for the input device.\r
 \r
   @param  This                        Protocol instance pointer.\r
-  @param  KeyData                     A pointer to a buffer that is filled in with the keystroke\r
-                                      information data for the key that was pressed.\r
+  @param  KeyData                     A pointer to a buffer that is filled in with\r
+                                      the keystroke information for the key that was\r
+                                      pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState\r
+                                      and KeyData.KeyState.KeyShiftState are 0, then any incomplete\r
+                                      keystroke will trigger a notification of the KeyNotificationFunction.\r
   @param  KeyNotificationFunction     Points to the function to be called when the key\r
-                                      sequence is typed specified by KeyData.\r
+                                      sequence is typed specified by KeyData. This notification function\r
+                                      should be called at <=TPL_CALLBACK.\r
   @param  NotifyHandle                Points to the unique handle assigned to the registered notification.\r
 \r
   @retval EFI_SUCCESS                 The notification function was registered successfully.\r
@@ -1042,7 +1073,7 @@ USBKeyboardRegisterKeyNotify (
   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
   IN  EFI_KEY_DATA                       *KeyData,\r
   IN  EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,\r
-  OUT EFI_HANDLE                         *NotifyHandle\r
+  OUT VOID                               **NotifyHandle\r
   )\r
 {\r
   USB_KB_DEV                        *UsbKeyboardDevice;\r
@@ -1073,7 +1104,7 @@ USBKeyboardRegisterKeyNotify (
                       );\r
     if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {\r
       if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {\r
-        *NotifyHandle = CurrentNotify->NotifyHandle;\r
+        *NotifyHandle = CurrentNotify;\r
         return EFI_SUCCESS;\r
       }\r
     }\r
@@ -1089,12 +1120,11 @@ USBKeyboardRegisterKeyNotify (
 \r
   NewNotify->Signature         = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE;\r
   NewNotify->KeyNotificationFn = KeyNotificationFunction;\r
-  NewNotify->NotifyHandle      = (EFI_HANDLE) NewNotify;\r
   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));\r
   InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry);\r
 \r
 \r
-  *NotifyHandle = NewNotify->NotifyHandle;\r
+  *NotifyHandle = NewNotify;\r
 \r
   return EFI_SUCCESS;\r
 \r
@@ -1114,7 +1144,7 @@ EFI_STATUS
 EFIAPI\r
 USBKeyboardUnregisterKeyNotify (\r
   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
-  IN EFI_HANDLE                         NotificationHandle\r
+  IN VOID                               *NotificationHandle\r
   )\r
 {\r
   USB_KB_DEV                        *UsbKeyboardDevice;\r
@@ -1141,7 +1171,7 @@ USBKeyboardUnregisterKeyNotify (
                       NotifyEntry,\r
                       USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
                       );\r
-    if (CurrentNotify->NotifyHandle == NotificationHandle) {\r
+    if (CurrentNotify == NotificationHandle) {\r
       //\r
       // Remove the notification function from NotifyList and free resources\r
       //\r
@@ -1158,3 +1188,52 @@ USBKeyboardUnregisterKeyNotify (
   return EFI_INVALID_PARAMETER;\r
 }\r
 \r
+/**\r
+  Process key notify.\r
+\r
+  @param  Event                 Indicates the event that invoke this function.\r
+  @param  Context               Indicates the calling context.\r
+**/\r
+VOID\r
+EFIAPI\r
+KeyNotifyProcessHandler (\r
+  IN  EFI_EVENT                 Event,\r
+  IN  VOID                      *Context\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  USB_KB_DEV                    *UsbKeyboardDevice;\r
+  EFI_KEY_DATA                  KeyData;\r
+  LIST_ENTRY                    *Link;\r
+  LIST_ENTRY                    *NotifyList;\r
+  KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
+  EFI_TPL                       OldTpl;\r
+\r
+  UsbKeyboardDevice = (USB_KB_DEV *) Context;\r
+\r
+  //\r
+  // Invoke notification functions.\r
+  //\r
+  NotifyList = &UsbKeyboardDevice->NotifyList;\r
+  while (TRUE) {\r
+    //\r
+    // Enter critical section\r
+    //\r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+    Status = Dequeue (&UsbKeyboardDevice->EfiKeyQueueForNotify, &KeyData, sizeof (KeyData));\r
+    //\r
+    // Leave critical section\r
+    //\r
+    gBS->RestoreTPL (OldTpl);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {\r
+      CurrentNotify = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);\r
+      if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {\r
+        CurrentNotify->KeyNotificationFn (&KeyData);\r
+      }\r
+    }\r
+  }\r
+}\r
+\r