X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FBus%2FUsb%2FUsbKbDxe%2FEfiKey.c;h=ccb389067a615142bb48d655a6304d5d1c8fa3cd;hb=f9c2c71ed69ca1d92687a55d3ef947cfb4413b3e;hp=b971903a2dd85e1c170a2c191e6e0d9f8dd38ebf;hpb=a7022cec4e8b46d7f2bfc1ee84333cf6e71e633b;p=mirror_edk2.git diff --git a/MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c b/MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c index b971903a2d..ccb389067a 100644 --- a/MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c +++ b/MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c @@ -1,200 +1,15 @@ /** @file + USB Keyboard Driver that manages USB keyboard and produces Simple Text Input + Protocol and Simple Text Input Ex Protocol. - USB Keyboard Driver that includes the implementation of interface. - -Copyright (c) 2004 - 2008, Intel Corporation -All rights reserved. This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "EfiKey.h" #include "KeyBoard.h" -/** - The Usb Keyboard Driver Entry Point. - - @param ImageHandle The driver image handle. - @param SystemTable The system table. - - @return EFI_SUCCESS The component name protocol is installed. - @return Others Failed to install. - -**/ -EFI_STATUS -EFIAPI -USBKeyboardDriverBindingEntryPoint ( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE *SystemTable - ); - -/** - Check whether USB keyboard driver support this device. - - @param This The USB keyboard driver binding protocol. - @param Controller The controller handle to check. - @param RemainingDevicePath The remaining device path. - - @retval EFI_SUCCESS The driver supports this controller. - @retval EFI_UNSUPPORTED This device isn't supported. -**/ -EFI_STATUS -EFIAPI -USBKeyboardDriverBindingSupported ( - IN EFI_DRIVER_BINDING_PROTOCOL *This, - IN EFI_HANDLE Controller, - IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath - ); - -/** - Start running driver on the controller. - - @param This The USB keyboard driver binding instance. - @param Controller The controller to check. - @param RemainingDevicePath The remaining device patch. - - @retval EFI_SUCCESS The controller is controlled by the usb keyboard driver. - @return Other The keyboard driver doesn't support this controller. - -**/ -EFI_STATUS -EFIAPI -USBKeyboardDriverBindingStart ( - IN EFI_DRIVER_BINDING_PROTOCOL *This, - IN EFI_HANDLE Controller, - IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath - ); - -/** - Stop handle the controller by this USB keyboard driver. - - @param This The USB keyboard driver binding protocol. - @param Controller The controller to release. - @param NumberOfChildren The number of handles in ChildHandleBuffer. - @param ChildHandleBuffer The array of child handle. - - @retval EFI_SUCCESS The controller or children are stopped. - @retval EFI_DEVICE_ERROR Failed to stop the driver. - -**/ -EFI_STATUS -EFIAPI -USBKeyboardDriverBindingStop ( - IN EFI_DRIVER_BINDING_PROTOCOL *This, - IN EFI_HANDLE Controller, - IN UINTN NumberOfChildren, - IN EFI_HANDLE *ChildHandleBuffer - ); - -/** - Reset Usb Keyboard. - - @param This The protocol instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL. - @param ExtendedVerification Whether completely reset keyboard or not. - - @retval EFI_SUCCESS Reset keyboard successfully. - @retval EFI_DEVICE_ERROR Reset keyboard failed. - -**/ -EFI_STATUS -EFIAPI -USBKeyboardReset ( - IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, - IN BOOLEAN ExtendedVerification - ); - -/** - Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke() function. - - @param This The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance. - @param Key A pointer to a buffer that is filled in with the keystroke - information for the key that was pressed. - - @retval EFI_SUCCESS Read key stroke successfully. - @retval Other Read key stroke failed. - -**/ -EFI_STATUS -EFIAPI -USBKeyboardReadKeyStroke ( - IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, - OUT EFI_INPUT_KEY *Key - ); - -/** - Handler function for WaitForKey event. - - @param Event Event to be signaled when a key is pressed. - @param Context Points to USB_KB_DEV instance. - - @return None. -**/ -VOID -EFIAPI -USBKeyboardWaitForKey ( - IN EFI_EVENT Event, - IN VOID *Context - ); - -/** - Check whether there is key pending. - - @param UsbKeyboardDevice The USB_KB_DEV instance. - - @retval EFI_SUCCESS Have key pending to read. - @retval Other Parse key failed. - -**/ -EFI_STATUS -EFIAPI -USBKeyboardCheckForKey ( - IN USB_KB_DEV *UsbKeyboardDevice - ); - -EFI_GUID gEfiUsbKeyboardDriverGuid = { - 0xa05f5f78, 0xfb3, 0x4d10, {0x90, 0x90, 0xac, 0x4, 0x6e, 0xeb, 0x7c, 0x3c} -}; - -/** - Free keyboard notify list. - - @param ListHead The list head. - - @retval EFI_SUCCESS Free the notify list successfully. - @retval EFI_INVALID_PARAMETER ListHead is invalid. - -**/ -EFI_STATUS -EFIAPI -KbdFreeNotifyList ( - IN OUT LIST_ENTRY *ListHead - ); - -/** - Whether the pressed key matches a registered key or not. - - @param RegsiteredData A pointer to a buffer that is filled in with the keystroke - state data for the key that was registered. - @param InputData A pointer to a buffer that is filled in with the keystroke - state data for the key that was pressed. - - @retval TRUE Key pressed matches a registered key. - @retval FLASE Match failed. - -**/ -BOOLEAN -EFIAPI -IsKeyRegistered ( - IN EFI_KEY_DATA *RegsiteredData, - IN EFI_KEY_DATA *InputData - ); - - // // USB Keyboard Driver Global Variables // @@ -208,13 +23,15 @@ EFI_DRIVER_BINDING_PROTOCOL gUsbKeyboardDriverBinding = { }; /** - The Usb Keyboard Driver Entry Point. + Entrypoint of USB Keyboard Driver. + + This function is the entrypoint of USB Keyboard Driver. It installs Driver Binding + Protocols together with Component Name Protocols. - @param ImageHandle The driver image handle. - @param SystemTable The system table. + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. - @return EFI_SUCCESS The component name protocol is installed. - @return Others Failed to install. + @retval EFI_SUCCESS The entry point is executed successfully. **/ EFI_STATUS @@ -224,25 +41,31 @@ USBKeyboardDriverBindingEntryPoint ( IN EFI_SYSTEM_TABLE *SystemTable ) { - return EfiLibInstallDriverBindingComponentName2 ( - ImageHandle, - SystemTable, - &gUsbKeyboardDriverBinding, - ImageHandle, - &gUsbKeyboardComponentName, - &gUsbKeyboardComponentName2 - ); + EFI_STATUS Status; + + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gUsbKeyboardDriverBinding, + ImageHandle, + &gUsbKeyboardComponentName, + &gUsbKeyboardComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; } /** - Check whether USB keyboard driver support this device. + Check whether USB keyboard driver supports this device. @param This The USB keyboard driver binding protocol. @param Controller The controller handle to check. @param RemainingDevicePath The remaining device path. @retval EFI_SUCCESS The driver supports this controller. - @retval EFI_UNSUPPORTED This device isn't supported. + @retval other This device isn't supported. + **/ EFI_STATUS EFIAPI @@ -252,28 +75,27 @@ USBKeyboardDriverBindingSupported ( IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { - EFI_STATUS OpenStatus; - EFI_USB_IO_PROTOCOL *UsbIo; EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; // - // Check if USB_IO protocol is attached on the controller handle. + // Check if USB I/O Protocol is attached on the controller handle. // - OpenStatus = gBS->OpenProtocol ( - Controller, - &gEfiUsbIoProtocolGuid, - (VOID **) &UsbIo, - This->DriverBindingHandle, - Controller, - EFI_OPEN_PROTOCOL_BY_DRIVER - ); - if (EFI_ERROR (OpenStatus)) { - return OpenStatus; + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; } // - // Use the USB I/O protocol interface to check whether the Controller is - // the Keyboard controller that can be managed by this driver. + // Use the USB I/O Protocol interface to check whether Controller is + // a keyboard device that can be managed by this driver. // Status = EFI_SUCCESS; @@ -282,24 +104,30 @@ USBKeyboardDriverBindingSupported ( } gBS->CloseProtocol ( - Controller, - &gEfiUsbIoProtocolGuid, - This->DriverBindingHandle, - Controller - ); + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); return Status; } /** - Start running driver on the controller. + Starts the keyboard device with this driver. + + This function produces Simple Text Input Protocol and Simple Text Input Ex Protocol, + initializes the keyboard device, and submit Asynchronous Interrupt Transfer to manage + this keyboard device. @param This The USB keyboard driver binding instance. - @param Controller The controller to check. - @param RemainingDevicePath The remaining device patch. + @param Controller Handle of device to bind driver to. + @param RemainingDevicePath Optional parameter use to pick a specific child + device to start. @retval EFI_SUCCESS The controller is controlled by the usb keyboard driver. - @return Other The keyboard driver doesn't support this controller. + @retval EFI_UNSUPPORTED No interrupt endpoint can be found. + @retval Other This controller cannot be started. **/ EFI_STATUS @@ -320,12 +148,11 @@ USBKeyboardDriverBindingStart ( UINT8 PollingInterval; UINT8 PacketSize; BOOLEAN Found; + EFI_TPL OldTpl; - UsbKeyboardDevice = NULL; - Found = FALSE; - + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); // - // Open USB_IO Protocol + // Open USB I/O Protocol // Status = gBS->OpenProtocol ( Controller, @@ -336,19 +163,12 @@ USBKeyboardDriverBindingStart ( EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status)) { - return Status; + goto ErrorExit1; } UsbKeyboardDevice = AllocateZeroPool (sizeof (USB_KB_DEV)); - if (UsbKeyboardDevice == NULL) { - gBS->CloseProtocol ( - Controller, - &gEfiUsbIoProtocolGuid, - This->DriverBindingHandle, - Controller - ); - return EFI_OUT_OF_RESOURCES; - } + ASSERT (UsbKeyboardDevice != NULL); + // // Get the Device Path Protocol on Controller's handle // @@ -362,79 +182,82 @@ USBKeyboardDriverBindingStart ( ); if (EFI_ERROR (Status)) { - gBS->FreePool (UsbKeyboardDevice); - gBS->CloseProtocol ( - Controller, - &gEfiUsbIoProtocolGuid, - This->DriverBindingHandle, - Controller - ); - return Status; + goto ErrorExit; } // - // Report that the usb keyboard is being enabled + // Report that the USB keyboard is being enabled // - KbdReportStatusCode ( - UsbKeyboardDevice->DevicePath, + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, - PcdGet32 (PcdStatusCodeValueKeyboardEnable) + (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE), + UsbKeyboardDevice->DevicePath ); // // This is pretty close to keyboard detection, so log progress // - KbdReportStatusCode ( - UsbKeyboardDevice->DevicePath, + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, - PcdGet32 (PcdStatusCodeValueKeyboardPresenceDetect) + (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT), + UsbKeyboardDevice->DevicePath ); - // - // Initialize UsbKeyboardDevice - // UsbKeyboardDevice->UsbIo = UsbIo; // // Get interface & endpoint descriptor // UsbIo->UsbGetInterfaceDescriptor ( - UsbIo, - &UsbKeyboardDevice->InterfaceDescriptor - ); + UsbIo, + &UsbKeyboardDevice->InterfaceDescriptor + ); EndpointNumber = UsbKeyboardDevice->InterfaceDescriptor.NumEndpoints; + // + // Traverse endpoints to find interrupt endpoint IN + // + Found = FALSE; for (Index = 0; Index < EndpointNumber; Index++) { UsbIo->UsbGetEndpointDescriptor ( - UsbIo, - Index, - &EndpointDescriptor - ); + UsbIo, + Index, + &EndpointDescriptor + ); - if ((EndpointDescriptor.Attributes & 0x03) == 0x03) { + if (((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) && + ((EndpointDescriptor.EndpointAddress & USB_ENDPOINT_DIR_IN) != 0)) { // // We only care interrupt endpoint here // CopyMem(&UsbKeyboardDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor)); Found = TRUE; + break; } } if (!Found) { // + // Report Status Code to indicate that there is no USB keyboard + // + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED) + ); + // // No interrupt endpoint found, then return unsupported. // - gBS->FreePool (UsbKeyboardDevice); - gBS->CloseProtocol ( - Controller, - &gEfiUsbIoProtocolGuid, - This->DriverBindingHandle, - Controller - ); - return EFI_UNSUPPORTED; + Status = EFI_UNSUPPORTED; + goto ErrorExit; } + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DETECTED), + UsbKeyboardDevice->DevicePath + ); + UsbKeyboardDevice->Signature = USB_KB_DEV_SIGNATURE; UsbKeyboardDevice->SimpleInput.Reset = USBKeyboardReset; UsbKeyboardDevice->SimpleInput.ReadKeyStroke = USBKeyboardReadKeyStroke; @@ -443,23 +266,32 @@ USBKeyboardDriverBindingStart ( UsbKeyboardDevice->SimpleInputEx.ReadKeyStrokeEx = USBKeyboardReadKeyStrokeEx; UsbKeyboardDevice->SimpleInputEx.SetState = USBKeyboardSetState; UsbKeyboardDevice->SimpleInputEx.RegisterKeyNotify = USBKeyboardRegisterKeyNotify; - UsbKeyboardDevice->SimpleInputEx.UnregisterKeyNotify = USBKeyboardUnregisterKeyNotify; - + UsbKeyboardDevice->SimpleInputEx.UnregisterKeyNotify = USBKeyboardUnregisterKeyNotify; + InitializeListHead (&UsbKeyboardDevice->NotifyList); - + Status = gBS->CreateEvent ( - EVT_NOTIFY_WAIT, + EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_NOTIFY, - USBKeyboardWaitForKey, + USBKeyboardTimerHandler, UsbKeyboardDevice, - &(UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx) + &UsbKeyboardDevice->TimerEvent ); - + if (!EFI_ERROR (Status)) { + Status = gBS->SetTimer (UsbKeyboardDevice->TimerEvent, TimerPeriodic, KEYBOARD_TIMER_INTERVAL); + } if (EFI_ERROR (Status)) { goto ErrorExit; } - Status = InitKeyboardLayout (UsbKeyboardDevice); + Status = gBS->CreateEvent ( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + USBKeyboardWaitForKey, + UsbKeyboardDevice, + &(UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx) + ); + if (EFI_ERROR (Status)) { goto ErrorExit; } @@ -471,25 +303,27 @@ USBKeyboardDriverBindingStart ( UsbKeyboardDevice, &(UsbKeyboardDevice->SimpleInput.WaitForKey) ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + KeyNotifyProcessHandler, + UsbKeyboardDevice, + &UsbKeyboardDevice->KeyNotifyProcessEvent + ); if (EFI_ERROR (Status)) { - gBS->FreePool (UsbKeyboardDevice); - gBS->CloseProtocol ( - Controller, - &gEfiUsbIoProtocolGuid, - This->DriverBindingHandle, - Controller - ); - return Status; + goto ErrorExit; } // - // Install simple txt in protocol interface - // for the usb keyboard device. - // Usb keyboard is a hot plug device, and expected to work immediately - // when plugging into system, so a HotPlugDeviceGuid is installed onto - // the usb keyboard device handle, to distinguish it from other conventional - // console devices. + // Install Simple Text Input Protocol and Simple Text Input Ex Protocol + // for the USB keyboard device. + // USB keyboard is a hot plug device, and expected to work immediately + // when plugging into system, other conventional console devices could + // distinguish it by its device path. // Status = gBS->InstallMultipleProtocolInterfaces ( &Controller, @@ -497,27 +331,32 @@ USBKeyboardDriverBindingStart ( &UsbKeyboardDevice->SimpleInput, &gEfiSimpleTextInputExProtocolGuid, &UsbKeyboardDevice->SimpleInputEx, - &gEfiHotPlugDeviceGuid, - NULL, NULL ); if (EFI_ERROR (Status)) { - gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); - gBS->FreePool (UsbKeyboardDevice); - gBS->CloseProtocol ( - Controller, - &gEfiUsbIoProtocolGuid, - This->DriverBindingHandle, - Controller - ); - return Status; + goto ErrorExit; + } + + UsbKeyboardDevice->ControllerHandle = Controller; + Status = InitKeyboardLayout (UsbKeyboardDevice); + if (EFI_ERROR (Status)) { + gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiSimpleTextInProtocolGuid, + &UsbKeyboardDevice->SimpleInput, + &gEfiSimpleTextInputExProtocolGuid, + &UsbKeyboardDevice->SimpleInputEx, + NULL + ); + goto ErrorExit; } + // - // Reset USB Keyboard Device + // Reset USB Keyboard Device exhaustively. // - Status = UsbKeyboardDevice->SimpleInput.Reset ( - &UsbKeyboardDevice->SimpleInput, + Status = UsbKeyboardDevice->SimpleInputEx.Reset ( + &UsbKeyboardDevice->SimpleInputEx, TRUE ); if (EFI_ERROR (Status)) { @@ -527,22 +366,13 @@ USBKeyboardDriverBindingStart ( &UsbKeyboardDevice->SimpleInput, &gEfiSimpleTextInputExProtocolGuid, &UsbKeyboardDevice->SimpleInputEx, - &gEfiHotPlugDeviceGuid, - NULL, NULL ); - gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); - gBS->FreePool (UsbKeyboardDevice); - gBS->CloseProtocol ( - Controller, - &gEfiUsbIoProtocolGuid, - This->DriverBindingHandle, - Controller - ); - return Status; + goto ErrorExit; } + // - // submit async interrupt transfer + // Submit Asynchronous Interrupt Transfer to manage this device. // EndpointAddr = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress; PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval; @@ -559,26 +389,15 @@ USBKeyboardDriverBindingStart ( ); if (EFI_ERROR (Status)) { - gBS->UninstallMultipleProtocolInterfaces ( Controller, &gEfiSimpleTextInProtocolGuid, &UsbKeyboardDevice->SimpleInput, &gEfiSimpleTextInputExProtocolGuid, &UsbKeyboardDevice->SimpleInputEx, - &gEfiHotPlugDeviceGuid, - NULL, NULL ); - gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); - gBS->FreePool (UsbKeyboardDevice); - gBS->CloseProtocol ( - Controller, - &gEfiUsbIoProtocolGuid, - This->DriverBindingHandle, - Controller - ); - return Status; + goto ErrorExit; } UsbKeyboardDevice->ControllerNameTable = NULL; @@ -597,19 +416,31 @@ USBKeyboardDriverBindingStart ( FALSE ); - + gBS->RestoreTPL (OldTpl); return EFI_SUCCESS; +// +// Error handler +// ErrorExit: if (UsbKeyboardDevice != NULL) { + if (UsbKeyboardDevice->TimerEvent != NULL) { + gBS->CloseEvent (UsbKeyboardDevice->TimerEvent); + } if (UsbKeyboardDevice->SimpleInput.WaitForKey != NULL) { gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); } if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) { gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx); } - KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList); - gBS->FreePool (UsbKeyboardDevice); + if (UsbKeyboardDevice->KeyNotifyProcessEvent != NULL) { + gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent); + } + if (UsbKeyboardDevice->KeyboardLayoutEvent != NULL) { + ReleaseKeyboardLayoutResources (UsbKeyboardDevice); + gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent); + } + FreePool (UsbKeyboardDevice); UsbKeyboardDevice = NULL; } gBS->CloseProtocol ( @@ -618,21 +449,28 @@ ErrorExit: This->DriverBindingHandle, Controller ); + +ErrorExit1: + gBS->RestoreTPL (OldTpl); + return Status; } /** - Stop handle the controller by this USB keyboard driver. + Stop the USB keyboard device handled by this driver. @param This The USB keyboard driver binding protocol. @param Controller The controller to release. @param NumberOfChildren The number of handles in ChildHandleBuffer. @param ChildHandleBuffer The array of child handle. - @retval EFI_SUCCESS The controller or children are stopped. - @retval EFI_DEVICE_ERROR Failed to stop the driver. + @retval EFI_SUCCESS The device was stopped. + @retval EFI_UNSUPPORTED Simple Text In Protocol or Simple Text In Ex Protocol + is not installed on Controller. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + @retval Others Fail to uninstall protocols attached on the device. **/ EFI_STATUS @@ -644,9 +482,9 @@ USBKeyboardDriverBindingStop ( IN EFI_HANDLE *ChildHandleBuffer ) { - EFI_STATUS Status; + EFI_STATUS Status; EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleInput; - USB_KB_DEV *UsbKeyboardDevice; + USB_KB_DEV *UsbKeyboardDevice; Status = gBS->OpenProtocol ( Controller, @@ -659,6 +497,7 @@ USBKeyboardDriverBindingStop ( if (EFI_ERROR (Status)) { return EFI_UNSUPPORTED; } + Status = gBS->OpenProtocol ( Controller, &gEfiSimpleTextInputExProtocolGuid, @@ -670,30 +509,20 @@ USBKeyboardDriverBindingStop ( if (EFI_ERROR (Status)) { return EFI_UNSUPPORTED; } - // - // Get USB_KB_DEV instance. - // - UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput); - gBS->CloseProtocol ( - Controller, - &gEfiSimpleTextInProtocolGuid, - This->DriverBindingHandle, - Controller - ); + UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput); // - // Uninstall the Asyn Interrupt Transfer from this device - // will disable the key data input from this device + // The key data input from this device will be disabled. // - KbdReportStatusCode ( - UsbKeyboardDevice->DevicePath, + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, - PcdGet32 (PcdStatusCodeValueKeyboardDisable) + (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE), + UsbKeyboardDevice->DevicePath ); // - // Destroy asynchronous interrupt transfer + // Delete the Asynchronous Interrupt Transfer from this device // UsbKeyboardDevice->UsbIo->UsbAsyncInterruptTransfer ( UsbKeyboardDevice->UsbIo, @@ -706,11 +535,11 @@ USBKeyboardDriverBindingStop ( ); gBS->CloseProtocol ( - Controller, - &gEfiUsbIoProtocolGuid, - This->DriverBindingHandle, - Controller - ); + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); Status = gBS->UninstallMultipleProtocolInterfaces ( Controller, @@ -718,18 +547,18 @@ USBKeyboardDriverBindingStop ( &UsbKeyboardDevice->SimpleInput, &gEfiSimpleTextInputExProtocolGuid, &UsbKeyboardDevice->SimpleInputEx, - &gEfiHotPlugDeviceGuid, - NULL, NULL ); // - // free all the resources. + // Free all resources. // + gBS->CloseEvent (UsbKeyboardDevice->TimerEvent); gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer); gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent); - gBS->CloseEvent ((UsbKeyboardDevice->SimpleInput).WaitForKey); - gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx); - KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList); + gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); + gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx); + gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent); + KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList); ReleaseKeyboardLayoutResources (UsbKeyboardDevice); gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent); @@ -738,125 +567,71 @@ USBKeyboardDriverBindingStop ( FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable); } - gBS->FreePool (UsbKeyboardDevice); + DestroyQueue (&UsbKeyboardDevice->UsbKeyQueue); + DestroyQueue (&UsbKeyboardDevice->EfiKeyQueue); + DestroyQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify); - return Status; + FreePool (UsbKeyboardDevice); + return Status; } /** - Reads the next keystroke from the input device. The WaitForKey Event can - be used to test for existance of a keystroke via WaitForEvent () call. + Internal function to read the next keystroke from the keyboard buffer. - @param UsbKeyboardDevice Usb keyboard's private structure. - @param KeyData A pointer to a buffer that is filled in with the keystroke - state data for the key that was pressed. + @param UsbKeyboardDevice USB keyboard's private structure. + @param KeyData A pointer to buffer to hold the keystroke + data for the key that was pressed. - @return EFI_SUCCESS The keystroke information was returned. - @return EFI_NOT_READY There was no keystroke data availiable. - @return EFI_DEVICE_ERROR The keystroke information was not returned due to + @retval EFI_SUCCESS The keystroke information was returned. + @retval EFI_NOT_READY There was no keystroke data availiable. + @retval EFI_DEVICE_ERROR The keystroke information was not returned due to hardware errors. - @return EFI_INVALID_PARAMETER KeyData is NULL. + @retval EFI_INVALID_PARAMETER KeyData is NULL. + @retval Others Fail to translate keycode into EFI_INPUT_KEY **/ EFI_STATUS -EFIAPI USBKeyboardReadKeyStrokeWorker ( - IN USB_KB_DEV *UsbKeyboardDevice, - OUT EFI_KEY_DATA *KeyData + IN OUT USB_KB_DEV *UsbKeyboardDevice, + OUT EFI_KEY_DATA *KeyData ) { - - EFI_STATUS Status; - UINT8 KeyChar; - LIST_ENTRY *Link; - KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; - EFI_KEY_DATA OriginalKeyData; - if (KeyData == NULL) { return EFI_INVALID_PARAMETER; } - // - // if there is no saved ASCII byte, fetch it - // by calling USBKeyboardCheckForKey(). - // - if (UsbKeyboardDevice->CurKeyChar == 0) { - Status = USBKeyboardCheckForKey (UsbKeyboardDevice); - if (EFI_ERROR (Status)) { - return Status; - } + if (IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) { + ZeroMem (&KeyData->Key, sizeof (KeyData->Key)); + InitializeKeyState (UsbKeyboardDevice, &KeyData->KeyState); + return EFI_NOT_READY; } - KeyData->Key.UnicodeChar = 0; - KeyData->Key.ScanCode = SCAN_NULL; - - KeyChar = UsbKeyboardDevice->CurKeyChar; - - UsbKeyboardDevice->CurKeyChar = 0; - - // - // Translate saved ASCII byte into EFI_INPUT_KEY - // - Status = USBKeyCodeToEFIScanCode (UsbKeyboardDevice, KeyChar, &KeyData->Key); - if (EFI_ERROR (Status)) { - return Status; - } - - CopyMem (&KeyData->KeyState, &UsbKeyboardDevice->KeyState, sizeof (KeyData->KeyState)); - - UsbKeyboardDevice->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID; - UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID; - - // - //Switch the control value to their original characters. In USBKeyCodeToEFIScanCode() the CTRL-Alpha characters have been switched to - // their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A), here switch them back for notification function. - // - CopyMem (&OriginalKeyData, KeyData, sizeof (EFI_KEY_DATA)); - if (UsbKeyboardDevice->CtrlOn != 0) { - if (OriginalKeyData.Key.UnicodeChar >= 0x01 && OriginalKeyData.Key.UnicodeChar <= 0x1A) { - if (UsbKeyboardDevice->CapsOn != 0) { - OriginalKeyData.Key.UnicodeChar = (CHAR16)(OriginalKeyData.Key.UnicodeChar + 'A' - 1); - } else { - OriginalKeyData.Key.UnicodeChar = (CHAR16)(OriginalKeyData.Key.UnicodeChar + 'a' - 1); - } - } - } - - // - // Invoke notification functions if exist - // - for (Link = UsbKeyboardDevice->NotifyList.ForwardLink; Link != &UsbKeyboardDevice->NotifyList; Link = Link->ForwardLink) { - CurrentNotify = CR ( - Link, - KEYBOARD_CONSOLE_IN_EX_NOTIFY, - NotifyEntry, - USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE - ); - if (IsKeyRegistered (&CurrentNotify->KeyData, &OriginalKeyData)) { - CurrentNotify->KeyNotificationFn (&OriginalKeyData); - } - } + Dequeue (&UsbKeyboardDevice->EfiKeyQueue, KeyData, sizeof (*KeyData)); return EFI_SUCCESS; - } /** - Reset Usb Keyboard. + Reset the input device and optionally run diagnostics + + There are 2 types of reset for USB keyboard. + For non-exhaustive reset, only keyboard buffer is cleared. + For exhaustive reset, in addition to clearance of keyboard buffer, the hardware status + is also re-initialized. - @param This The protocol instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL. - @param ExtendedVerification Whether completely reset keyboard or not. + @param This Protocol instance pointer. + @param ExtendedVerification Driver may perform diagnostics on reset. - @retval EFI_SUCCESS Reset keyboard successfully. - @retval EFI_DEVICE_ERROR Reset keyboard failed. + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The device is not functioning properly and could not be reset. **/ EFI_STATUS EFIAPI USBKeyboardReset ( IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, - IN BOOLEAN ExtendedVerification + IN BOOLEAN ExtendedVerification ) { EFI_STATUS Status; @@ -864,36 +639,36 @@ USBKeyboardReset ( UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This); - KbdReportStatusCode ( - UsbKeyboardDevice->DevicePath, + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, - PcdGet32 (PcdStatusCodeValueKeyboardReset) + (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET), + UsbKeyboardDevice->DevicePath ); // - // Non Exhaustive reset: + // Non-exhaustive reset: // only reset private data structures. // if (!ExtendedVerification) { - // - // Clear the key buffer of this Usb keyboard - // - KbdReportStatusCode ( - UsbKeyboardDevice->DevicePath, + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, - PcdGet32 (PcdStatusCodeValueKeyboardClearBuffer) + (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER), + UsbKeyboardDevice->DevicePath ); + // + // Clear the key buffer of this USB keyboard + // + InitQueue (&UsbKeyboardDevice->UsbKeyQueue, sizeof (USB_KEY)); + InitQueue (&UsbKeyboardDevice->EfiKeyQueue, sizeof (EFI_KEY_DATA)); + InitQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify, sizeof (EFI_KEY_DATA)); - InitUSBKeyBuffer (&(UsbKeyboardDevice->KeyboardBuffer)); - UsbKeyboardDevice->CurKeyChar = 0; return EFI_SUCCESS; } // // Exhaustive reset // - Status = InitUSBKeyboard (UsbKeyboardDevice); - UsbKeyboardDevice->CurKeyChar = 0; + Status = InitUSBKeyboard (UsbKeyboardDevice); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } @@ -903,21 +678,23 @@ USBKeyboardReset ( /** - Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke() function. + Reads the next keystroke from the input device. @param This The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance. @param Key A pointer to a buffer that is filled in with the keystroke information for the key that was pressed. - @retval EFI_SUCCESS Read key stroke successfully. - @retval Other Read key stroke failed. + @retval EFI_SUCCESS The keystroke information was returned. + @retval EFI_NOT_READY There was no keystroke data availiable. + @retval EFI_DEVICE_ERROR The keystroke information was not returned due to + hardware errors. **/ EFI_STATUS EFIAPI USBKeyboardReadKeyStroke ( IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, - OUT EFI_INPUT_KEY *Key + OUT EFI_INPUT_KEY *Key ) { USB_KB_DEV *UsbKeyboardDevice; @@ -926,25 +703,47 @@ USBKeyboardReadKeyStroke ( UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This); - Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData); - if (EFI_ERROR (Status)) { - return Status; - } - - CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY)); - - return EFI_SUCCESS; + // + // Considering if the partial keystroke is enabled, there maybe a partial + // keystroke in the queue, so here skip the partial keystroke and get the + // next key from the queue + // + while (1) { + Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData); + if (EFI_ERROR (Status)) { + return Status; + } + // + // SimpleTextIn Protocol doesn't support partial keystroke; + // + if (KeyData.Key.ScanCode == CHAR_NULL && KeyData.Key.UnicodeChar == SCAN_NULL) { + continue; + } + // + // Translate the CTRL-Alpha characters to their corresponding control value + // (ctrl-a = 0x0001 through ctrl-Z = 0x001A) + // + if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) { + if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') { + KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1); + } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') { + KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1); + } + } + CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY)); + return EFI_SUCCESS; + } } /** - Handler function for WaitForKey event. + Event notification function registered for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx + and EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey. @param Event Event to be signaled when a key is pressed. @param Context Points to USB_KB_DEV instance. - @return None. **/ VOID EFIAPI @@ -954,167 +753,178 @@ USBKeyboardWaitForKey ( ) { USB_KB_DEV *UsbKeyboardDevice; + EFI_KEY_DATA KeyData; + EFI_TPL OldTpl; UsbKeyboardDevice = (USB_KB_DEV *) Context; - if (UsbKeyboardDevice->CurKeyChar == 0) { + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); - if (EFI_ERROR (USBKeyboardCheckForKey (UsbKeyboardDevice))) { - return ; + // + // WaitforKey doesn't suppor the partial key. + // Considering if the partial keystroke is enabled, there maybe a partial + // keystroke in the queue, so here skip the partial keystroke and get the + // next key from the queue + // + while (!IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) { + // + // If there is pending key, signal the event. + // + CopyMem ( + &KeyData, + UsbKeyboardDevice->EfiKeyQueue.Buffer[UsbKeyboardDevice->EfiKeyQueue.Head], + sizeof (EFI_KEY_DATA) + ); + if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) { + Dequeue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (EFI_KEY_DATA)); + continue; } + gBS->SignalEvent (Event); + break; } // - // If has key pending, signal the event. + // Leave critical section and return // - gBS->SignalEvent (Event); + gBS->RestoreTPL (OldTpl); } - /** - Check whether there is key pending. - - @param UsbKeyboardDevice The USB_KB_DEV instance. - - @retval EFI_SUCCESS Have key pending to read. - @retval Other Parse key failed. + Timer handler to convert the key from USB. + @param Event Indicates the event that invoke this function. + @param Context Indicates the calling context. **/ -EFI_STATUS +VOID EFIAPI -USBKeyboardCheckForKey ( - IN USB_KB_DEV *UsbKeyboardDevice +USBKeyboardTimerHandler ( + IN EFI_EVENT Event, + IN VOID *Context ) { - EFI_STATUS Status; - UINT8 KeyChar; + EFI_STATUS Status; + USB_KB_DEV *UsbKeyboardDevice; + UINT8 KeyCode; + EFI_KEY_DATA KeyData; + + UsbKeyboardDevice = (USB_KB_DEV *) Context; // - // Fetch raw data from the USB keyboard input, - // and translate it into ASCII data. + // Fetch raw data from the USB keyboard buffer, + // and translate it into USB keycode. // - Status = USBParseKey (UsbKeyboardDevice, &KeyChar); + Status = USBParseKey (UsbKeyboardDevice, &KeyCode); if (EFI_ERROR (Status)) { - return Status; + return ; } - UsbKeyboardDevice->CurKeyChar = KeyChar; - return EFI_SUCCESS; -} - -/** - Report Status Code in Usb Keyboard Driver. - - @param DevicePath Use this to get Device Path. - @param CodeType Status Code Type. - @param CodeValue Status Code Value. - - @return None. - -**/ -VOID -EFIAPI -KbdReportStatusCode ( - IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, - IN EFI_STATUS_CODE_TYPE CodeType, - IN EFI_STATUS_CODE_VALUE Value - ) -{ + // + // Translate saved USB keycode into EFI_INPUT_KEY + // + Status = UsbKeyCodeToEfiInputKey (UsbKeyboardDevice, KeyCode, &KeyData); + if (EFI_ERROR (Status)) { + return ; + } - REPORT_STATUS_CODE_WITH_DEVICE_PATH ( - CodeType, - Value, - DevicePath - ); + // + // Insert to the EFI Key queue + // + Enqueue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (KeyData)); } /** Free keyboard notify list. - @param ListHead The list head. + @param NotifyList The keyboard notify list to free. @retval EFI_SUCCESS Free the notify list successfully. - @retval EFI_INVALID_PARAMETER ListHead is invalid. + @retval EFI_INVALID_PARAMETER NotifyList is NULL. **/ EFI_STATUS -EFIAPI KbdFreeNotifyList ( - IN OUT LIST_ENTRY *ListHead + IN OUT LIST_ENTRY *NotifyList ) { KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode; + LIST_ENTRY *Link; - if (ListHead == NULL) { + if (NotifyList == NULL) { return EFI_INVALID_PARAMETER; } - while (!IsListEmpty (ListHead)) { - NotifyNode = CR ( - ListHead->ForwardLink, - KEYBOARD_CONSOLE_IN_EX_NOTIFY, - NotifyEntry, - USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE - ); - RemoveEntryList (ListHead->ForwardLink); - gBS->FreePool (NotifyNode); + while (!IsListEmpty (NotifyList)) { + Link = GetFirstNode (NotifyList); + NotifyNode = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE); + RemoveEntryList (Link); + FreePool (NotifyNode); } - + return EFI_SUCCESS; } /** - Whether the pressed key matches a registered key or not. + Check whether the pressed key matches a registered key or not. - @param RegsiteredData A pointer to a buffer that is filled in with the keystroke - state data for the key that was registered. - @param InputData A pointer to a buffer that is filled in with the keystroke - state data for the key that was pressed. + @param RegsiteredData A pointer to keystroke data for the key that was registered. + @param InputData A pointer to keystroke data for the key that was pressed. @retval TRUE Key pressed matches a registered key. - @retval FLASE Match failed. + @retval FLASE Key pressed does not matches a registered key. **/ BOOLEAN -EFIAPI IsKeyRegistered ( IN EFI_KEY_DATA *RegsiteredData, IN EFI_KEY_DATA *InputData ) { ASSERT (RegsiteredData != NULL && InputData != NULL); - + if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) || (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) { - return FALSE; - } - + return FALSE; + } + // // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored. // if (RegsiteredData->KeyState.KeyShiftState != 0 && RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) { - return FALSE; - } + return FALSE; + } if (RegsiteredData->KeyState.KeyToggleState != 0 && RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) { - return FALSE; - } - - return TRUE; + return FALSE; + } + return TRUE; } // -// Simple Text Input Ex protocol functions +// Simple Text Input Ex protocol functions // /** - The extension routine to reset the input device. + Resets the input device hardware. + + The Reset() function resets the input device hardware. As part + of initialization process, the firmware/device will make a quick + but reasonable attempt to verify that the device is functioning. + If the ExtendedVerification flag is TRUE the firmware may take + an extended amount of time to verify the device is operating on + reset. Otherwise the reset operation is to occur as quickly as + possible. The hardware verification process is not defined by + this specification and is left up to the platform firmware or + driver to implement. - @param This Protocol instance pointer. - @param ExtendedVerification Driver may perform diagnostics on reset. + @param This A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance. - @retval EFI_SUCCESS The device was reset. - @retval EFI_DEVICE_ERROR The device is not functioning properly and could - not be reset. + @param ExtendedVerification Indicates that the driver may perform a more exhaustive + verification operation of the device during reset. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The device is not functioning correctly and could not be reset. **/ EFI_STATUS @@ -1126,8 +936,6 @@ USBKeyboardResetEx ( { EFI_STATUS Status; USB_KB_DEV *UsbKeyboardDevice; - EFI_TPL OldTpl; - UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); @@ -1136,26 +944,25 @@ USBKeyboardResetEx ( return EFI_DEVICE_ERROR; } - OldTpl = gBS->RaiseTPL (TPL_NOTIFY); UsbKeyboardDevice->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID; UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID; - gBS->RestoreTPL (OldTpl); return EFI_SUCCESS; } /** - Reads the next keystroke from the input device. The WaitForKey Event can - be used to test for existance of a keystroke via WaitForEvent () call. + Reads the next keystroke from the input device. - @param This Protocol instance pointer. - @param KeyData A pointer to a buffer that is filled in with the keystroke - state data for the key that was pressed. + @param This Protocol instance pointer. + @param KeyData A pointer to a buffer that is filled in with the keystroke + state data for the key that was pressed. - @return EFI_SUCCESS The keystroke information was returned successfully. - @retval EFI_INVALID_PARAMETER KeyData is NULL. - @retval Other Read key stroke information failed. + @retval EFI_SUCCESS The keystroke information was returned. + @retval EFI_NOT_READY There was no keystroke data available. + @retval EFI_DEVICE_ERROR The keystroke information was not returned due to + hardware errors. + @retval EFI_INVALID_PARAMETER KeyData is NULL. **/ EFI_STATUS @@ -1174,7 +981,7 @@ USBKeyboardReadKeyStrokeEx ( UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); return USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, KeyData); - + } /** @@ -1184,8 +991,10 @@ USBKeyboardReadKeyStrokeEx ( @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the state for the input device. - @retval EFI_SUCCESS The device state was set successfully. - @retval EFI_UNSUPPORTED The device does not have the ability to set its state. + @retval EFI_SUCCESS The device state was set appropriately. + @retval EFI_DEVICE_ERROR The device is not functioning correctly and could + not have the setting adjusted. + @retval EFI_UNSUPPORTED The device does not support the ability to have its state set. @retval EFI_INVALID_PARAMETER KeyToggleState is NULL. **/ @@ -1213,18 +1022,22 @@ USBKeyboardSetState ( // Update the status light // - UsbKeyboardDevice->ScrollOn = 0; - UsbKeyboardDevice->NumLockOn = 0; - UsbKeyboardDevice->CapsOn = 0; - + UsbKeyboardDevice->ScrollOn = FALSE; + UsbKeyboardDevice->NumLockOn = FALSE; + UsbKeyboardDevice->CapsOn = FALSE; + UsbKeyboardDevice->IsSupportPartialKey = FALSE; + if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) { - UsbKeyboardDevice->ScrollOn = 1; + UsbKeyboardDevice->ScrollOn = TRUE; } if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) { - UsbKeyboardDevice->NumLockOn = 1; + UsbKeyboardDevice->NumLockOn = TRUE; } if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) { - UsbKeyboardDevice->CapsOn = 1; + UsbKeyboardDevice->CapsOn = TRUE; + } + if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) { + UsbKeyboardDevice->IsSupportPartialKey = TRUE; } SetKeyLED (UsbKeyboardDevice); @@ -1232,22 +1045,26 @@ USBKeyboardSetState ( UsbKeyboardDevice->KeyState.KeyToggleState = *KeyToggleState; return EFI_SUCCESS; - + } /** Register a notification function for a particular keystroke for the input device. @param This Protocol instance pointer. - @param KeyData A pointer to a buffer that is filled in with the keystroke - information data for the key that was pressed. + @param KeyData A pointer to a buffer that is filled in with + the keystroke information for the key that was + pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState + and KeyData.KeyState.KeyShiftState are 0, then any incomplete + keystroke will trigger a notification of the KeyNotificationFunction. @param KeyNotificationFunction Points to the function to be called when the key - sequence is typed specified by KeyData. + sequence is typed specified by KeyData. This notification function + should be called at <=TPL_CALLBACK. @param NotifyHandle Points to the unique handle assigned to the registered notification. @retval EFI_SUCCESS The notification function was registered successfully. - @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures. - @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL. + @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data structures. + @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle or KeyNotificationFunction is NULL. **/ EFI_STATUS @@ -1256,14 +1073,14 @@ USBKeyboardRegisterKeyNotify ( IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, IN EFI_KEY_DATA *KeyData, IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, - OUT EFI_HANDLE *NotifyHandle + OUT VOID **NotifyHandle ) { USB_KB_DEV *UsbKeyboardDevice; - EFI_STATUS Status; KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify; LIST_ENTRY *Link; - KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + LIST_ENTRY *NotifyList; + KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) { return EFI_INVALID_PARAMETER; @@ -1274,49 +1091,43 @@ USBKeyboardRegisterKeyNotify ( // // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. // - for (Link = UsbKeyboardDevice->NotifyList.ForwardLink; Link != &UsbKeyboardDevice->NotifyList; Link = Link->ForwardLink) { + NotifyList = &UsbKeyboardDevice->NotifyList; + + for (Link = GetFirstNode (NotifyList); + !IsNull (NotifyList, Link); + Link = GetNextNode (NotifyList, Link)) { CurrentNotify = CR ( - Link, - KEYBOARD_CONSOLE_IN_EX_NOTIFY, - NotifyEntry, + Link, + KEYBOARD_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE ); - if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { + if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { - *NotifyHandle = CurrentNotify->NotifyHandle; + *NotifyHandle = CurrentNotify; return EFI_SUCCESS; } } } - + // // Allocate resource to save the notification function - // + // NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY)); if (NewNotify == NULL) { return EFI_OUT_OF_RESOURCES; } - NewNotify->Signature = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE; + NewNotify->Signature = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE; NewNotify->KeyNotificationFn = KeyNotificationFunction; CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA)); InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry); - // - // Use gSimpleTextInExNotifyGuid to get a valid EFI_HANDLE - // - Status = gBS->InstallMultipleProtocolInterfaces ( - &NewNotify->NotifyHandle, - &gSimpleTextInExNotifyGuid, - NULL, - NULL - ); - ASSERT_EFI_ERROR (Status); - - *NotifyHandle = NewNotify->NotifyHandle; - + + *NotifyHandle = NewNotify; + return EFI_SUCCESS; - + } /** @@ -1326,65 +1137,103 @@ USBKeyboardRegisterKeyNotify ( @param NotificationHandle The handle of the notification function being unregistered. @retval EFI_SUCCESS The notification function was unregistered successfully. - @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid or opening gSimpleTextInExNotifyGuid - on NotificationHandle fails. - @retval EFI_NOT_FOUND Can not find the matching entry in database. + @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid **/ EFI_STATUS EFIAPI USBKeyboardUnregisterKeyNotify ( IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - IN EFI_HANDLE NotificationHandle + IN VOID *NotificationHandle ) { USB_KB_DEV *UsbKeyboardDevice; - EFI_STATUS Status; KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; LIST_ENTRY *Link; + LIST_ENTRY *NotifyList; if (NotificationHandle == NULL) { return EFI_INVALID_PARAMETER; - } - - UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); - - Status = gBS->OpenProtocol ( - NotificationHandle, - &gSimpleTextInExNotifyGuid, - NULL, - NULL, - NULL, - EFI_OPEN_PROTOCOL_TEST_PROTOCOL - ); - if (EFI_ERROR (Status)) { - return EFI_INVALID_PARAMETER; } - for (Link = UsbKeyboardDevice->NotifyList.ForwardLink; Link != &UsbKeyboardDevice->NotifyList; Link = Link->ForwardLink) { + UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This); + + // + // Traverse notify list of USB keyboard and remove the entry of NotificationHandle. + // + NotifyList = &UsbKeyboardDevice->NotifyList; + for (Link = GetFirstNode (NotifyList); + !IsNull (NotifyList, Link); + Link = GetNextNode (NotifyList, Link)) { CurrentNotify = CR ( - Link, - KEYBOARD_CONSOLE_IN_EX_NOTIFY, - NotifyEntry, + Link, + KEYBOARD_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE - ); - if (CurrentNotify->NotifyHandle == NotificationHandle) { + ); + if (CurrentNotify == NotificationHandle) { // // Remove the notification function from NotifyList and free resources // - RemoveEntryList (&CurrentNotify->NotifyEntry); - Status = gBS->UninstallMultipleProtocolInterfaces ( - CurrentNotify->NotifyHandle, - &gSimpleTextInExNotifyGuid, - NULL, - NULL - ); - ASSERT_EFI_ERROR (Status); - gBS->FreePool (CurrentNotify); + RemoveEntryList (&CurrentNotify->NotifyEntry); + + FreePool (CurrentNotify); return EFI_SUCCESS; } } - return EFI_NOT_FOUND; + // + // Cannot find the matching entry in database. + // + return EFI_INVALID_PARAMETER; +} + +/** + Process key notify. + + @param Event Indicates the event that invoke this function. + @param Context Indicates the calling context. +**/ +VOID +EFIAPI +KeyNotifyProcessHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + USB_KB_DEV *UsbKeyboardDevice; + EFI_KEY_DATA KeyData; + LIST_ENTRY *Link; + LIST_ENTRY *NotifyList; + KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + EFI_TPL OldTpl; + + UsbKeyboardDevice = (USB_KB_DEV *) Context; + + // + // Invoke notification functions. + // + NotifyList = &UsbKeyboardDevice->NotifyList; + while (TRUE) { + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + Status = Dequeue (&UsbKeyboardDevice->EfiKeyQueueForNotify, &KeyData, sizeof (KeyData)); + // + // Leave critical section + // + gBS->RestoreTPL (OldTpl); + if (EFI_ERROR (Status)) { + break; + } + for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) { + CurrentNotify = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE); + if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { + CurrentNotify->KeyNotificationFn (&KeyData); + } + } + } }