summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.c1018
1 files changed, 1018 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.c
new file mode 100644
index 00000000..a4049a47
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.c
@@ -0,0 +1,1018 @@
+/** @file
+ USB Mouse Driver that manages USB mouse and produces Absolute Pointer Protocol.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMouseAbsolutePointer.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gUsbMouseAbsolutePointerDriverBinding = {
+ USBMouseAbsolutePointerDriverBindingSupported,
+ USBMouseAbsolutePointerDriverBindingStart,
+ USBMouseAbsolutePointerDriverBindingStop,
+ 0x1,
+ NULL,
+ NULL
+};
+
+/**
+ Entrypoint of USB Mouse Absolute Pointer Driver.
+
+ This function is the entrypoint of USB Mouse Driver. It installs Driver Binding
+ Protocols together with Component Name Protocols.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMouseAbsolutePointerDriverBindingEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gUsbMouseAbsolutePointerDriverBinding,
+ ImageHandle,
+ &gUsbMouseAbsolutePointerComponentName,
+ &gUsbMouseAbsolutePointerComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check whether USB Mouse Absolute Pointer Driver supports this device.
+
+ @param This The 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 other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMouseAbsolutePointerDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+
+ 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 Controller is
+ // a mouse device that can be managed by this driver.
+ //
+ Status = EFI_SUCCESS;
+ if (!IsUsbMouse (UsbIo)) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ Starts the mouse device with this driver.
+
+ This function consumes USB I/O Protocol, initializes USB mouse device,
+ installs Absolute Pointer Protocol, and submits Asynchronous Interrupt
+ Transfer to manage the USB mouse device.
+
+ @param This The driver binding instance.
+ @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 This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_ALREADY_STARTED This driver has been started.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMouseAbsolutePointerDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDevice;
+ UINT8 EndpointNumber;
+ EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
+ UINT8 Index;
+ UINT8 EndpointAddr;
+ UINT8 PollingInterval;
+ UINT8 PacketSize;
+ BOOLEAN Found;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ //
+ // Open USB I/O Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit1;
+ }
+
+ UsbMouseAbsolutePointerDevice = AllocateZeroPool (sizeof (USB_MOUSE_ABSOLUTE_POINTER_DEV));
+ ASSERT (UsbMouseAbsolutePointerDevice != NULL);
+
+ UsbMouseAbsolutePointerDevice->UsbIo = UsbIo;
+ UsbMouseAbsolutePointerDevice->Signature = USB_MOUSE_ABSOLUTE_POINTER_DEV_SIGNATURE;
+
+ //
+ // Get the Device Path Protocol on Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UsbMouseAbsolutePointerDevice->DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Report Status Code here since USB mouse will be detected next.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_PC_PRESENCE_DETECT),
+ UsbMouseAbsolutePointerDevice->DevicePath
+ );
+
+ //
+ // Get interface & endpoint descriptor
+ //
+ UsbIo->UsbGetInterfaceDescriptor (
+ UsbIo,
+ &UsbMouseAbsolutePointerDevice->InterfaceDescriptor
+ );
+
+ EndpointNumber = UsbMouseAbsolutePointerDevice->InterfaceDescriptor.NumEndpoints;
+
+ //
+ // Traverse endpoints to find interrupt endpoint IN
+ //
+ Found = FALSE;
+ for (Index = 0; Index < EndpointNumber; Index++) {
+ UsbIo->UsbGetEndpointDescriptor (
+ UsbIo,
+ Index,
+ &EndpointDescriptor
+ );
+
+ if (((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) &&
+ ((EndpointDescriptor.EndpointAddress & USB_ENDPOINT_DIR_IN) != 0)) {
+ //
+ // We only care interrupt endpoint here
+ //
+ CopyMem (&UsbMouseAbsolutePointerDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor));
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (!Found) {
+ //
+ // Report Status Code to indicate that there is no USB mouse
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_EC_NOT_DETECTED)
+ );
+ //
+ // No interrupt endpoint found, then return unsupported.
+ //
+ Status = EFI_UNSUPPORTED;
+ goto ErrorExit;
+ }
+
+ //
+ // Report Status Code here since USB mouse has be detected.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_PC_DETECTED),
+ UsbMouseAbsolutePointerDevice->DevicePath
+ );
+
+ Status = InitializeUsbMouseDevice (UsbMouseAbsolutePointerDevice);
+ if (EFI_ERROR (Status)) {
+ //
+ // Fail to initialize USB mouse device.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INTERFACE_ERROR),
+ UsbMouseAbsolutePointerDevice->DevicePath
+ );
+
+ goto ErrorExit;
+ }
+
+ //
+ // Initialize and install EFI Absolute Pointer Protocol.
+ //
+ UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol.GetState = GetMouseAbsolutePointerState;
+ UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol.Reset = UsbMouseAbsolutePointerReset;
+ UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol.Mode = &UsbMouseAbsolutePointerDevice->Mode;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ UsbMouseAbsolutePointerWaitForInput,
+ UsbMouseAbsolutePointerDevice,
+ &((UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol).WaitForInput)
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiAbsolutePointerProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // The next step would be submitting Asynchronous Interrupt Transfer on this mouse device.
+ // After that we will be able to get key data from it. Thus this is deemed as
+ // the enable action of the mouse, so report status code accordingly.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_PC_ENABLE),
+ UsbMouseAbsolutePointerDevice->DevicePath
+ );
+
+ //
+ // Submit Asynchronous Interrupt Transfer to manage this device.
+ //
+ EndpointAddr = UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress;
+ PollingInterval = UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.Interval;
+ PacketSize = (UINT8) (UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.MaxPacketSize);
+
+ Status = UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ EndpointAddr,
+ TRUE,
+ PollingInterval,
+ PacketSize,
+ OnMouseInterruptComplete,
+ UsbMouseAbsolutePointerDevice
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // If submit error, uninstall that interface
+ //
+ gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiAbsolutePointerProtocolGuid,
+ &UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol
+ );
+ goto ErrorExit;
+ }
+
+ UsbMouseAbsolutePointerDevice->ControllerNameTable = NULL;
+ AddUnicodeString2 (
+ "eng",
+ gUsbMouseAbsolutePointerComponentName.SupportedLanguages,
+ &UsbMouseAbsolutePointerDevice->ControllerNameTable,
+ L"Generic Usb Mouse Absolute Pointer",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gUsbMouseAbsolutePointerComponentName2.SupportedLanguages,
+ &UsbMouseAbsolutePointerDevice->ControllerNameTable,
+ L"Generic Usb Mouse Absolute Pointer",
+ FALSE
+ );
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+
+//
+// Error handler
+//
+ErrorExit:
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if (UsbMouseAbsolutePointerDevice != NULL) {
+ if ((UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol).WaitForInput != NULL) {
+ gBS->CloseEvent ((UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol).WaitForInput);
+ }
+
+ FreePool (UsbMouseAbsolutePointerDevice);
+ UsbMouseAbsolutePointerDevice = NULL;
+ }
+ }
+
+ErrorExit1:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Stop the USB mouse device handled by this driver.
+
+ @param This The 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 device was stopped.
+ @retval EFI_UNSUPPORTED Absolute Pointer Protocol is not installed on Controller.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMouseAbsolutePointerDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDevice;
+ EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointerProtocol;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiAbsolutePointerProtocolGuid,
+ (VOID **) &AbsolutePointerProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ UsbMouseAbsolutePointerDevice = USB_MOUSE_ABSOLUTE_POINTER_DEV_FROM_MOUSE_PROTOCOL (AbsolutePointerProtocol);
+
+ UsbIo = UsbMouseAbsolutePointerDevice->UsbIo;
+
+ //
+ // The key data input from this device will be disabled.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_PC_DISABLE),
+ UsbMouseAbsolutePointerDevice->DevicePath
+ );
+
+ //
+ // Delete the Asynchronous Interrupt Transfer from this device
+ //
+ UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress,
+ FALSE,
+ UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.Interval,
+ 0,
+ NULL,
+ NULL
+ );
+
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiAbsolutePointerProtocolGuid,
+ &UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Free all resources.
+ //
+ gBS->CloseEvent (UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol.WaitForInput);
+
+ if (UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent != NULL) {
+ gBS->CloseEvent (UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent);
+ UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent = NULL;
+ }
+
+ if (UsbMouseAbsolutePointerDevice->ControllerNameTable != NULL) {
+ FreeUnicodeStringTable (UsbMouseAbsolutePointerDevice->ControllerNameTable);
+ }
+
+ FreePool (UsbMouseAbsolutePointerDevice);
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ Uses USB I/O to check whether the device is a USB mouse device.
+
+ @param UsbIo Pointer to a USB I/O protocol instance.
+
+ @retval TRUE Device is a USB mouse device.
+ @retval FALSE Device is a not USB mouse device.
+
+**/
+BOOLEAN
+IsUsbMouse (
+ IN EFI_USB_IO_PROTOCOL *UsbIo
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+
+ //
+ // Get the default interface descriptor
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (
+ UsbIo,
+ &InterfaceDescriptor
+ );
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if ((InterfaceDescriptor.InterfaceClass == CLASS_HID) &&
+ (InterfaceDescriptor.InterfaceSubClass == SUBCLASS_BOOT) &&
+ (InterfaceDescriptor.InterfaceProtocol == PROTOCOL_MOUSE)
+ ) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Initialize the USB mouse device.
+
+ This function retrieves and parses HID report descriptor, and
+ initializes state of USB_MOUSE_ABSOLUTE_POINTER_DEV. Then it sets indefinite idle
+ rate for the device. Finally it creates event for delayed recovery,
+ which deals with device error.
+
+ @param UsbMouseAbsolutePointerDev Device instance to be initialized.
+
+ @retval EFI_SUCCESS USB mouse device successfully initialized.
+ @retval EFI_UNSUPPORTED HID descriptor type is not report descriptor.
+ @retval Other USB mouse device was not initialized successfully.
+
+**/
+EFI_STATUS
+InitializeUsbMouseDevice (
+ IN USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDev
+ )
+{
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINT8 Protocol;
+ EFI_STATUS Status;
+ EFI_USB_HID_DESCRIPTOR *MouseHidDesc;
+ UINT8 *ReportDesc;
+ EFI_USB_CONFIG_DESCRIPTOR ConfigDesc;
+ VOID *Buf;
+ UINT32 TransferResult;
+ UINT16 Total;
+ USB_DESC_HEAD *Head;
+ BOOLEAN Start;
+
+ UsbIo = UsbMouseAbsolutePointerDev->UsbIo;
+
+ //
+ // Get the current configuration descriptor. Note that it doesn't include other descriptors.
+ //
+ Status = UsbIo->UsbGetConfigDescriptor (
+ UsbIo,
+ &ConfigDesc
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // By issuing Get_Descriptor(Configuration) request with total length, we get the Configuration descriptor,
+ // all Interface descriptors, all Endpoint descriptors, and the HID descriptor for each interface.
+ //
+ Buf = AllocateZeroPool (ConfigDesc.TotalLength);
+ if (Buf == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = UsbGetDescriptor (
+ UsbIo,
+ (UINT16)((USB_DESC_TYPE_CONFIG << 8) | (ConfigDesc.ConfigurationValue - 1)),
+ 0,
+ ConfigDesc.TotalLength,
+ Buf,
+ &TransferResult
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Buf);
+ return Status;
+ }
+
+ Total = 0;
+ Start = FALSE;
+ Head = (USB_DESC_HEAD *)Buf;
+ MouseHidDesc = NULL;
+
+ //
+ // Get HID descriptor from the receipt of Get_Descriptor(Configuration) request.
+ // This algorithm is based on the fact that the HID descriptor shall be interleaved
+ // between the interface and endpoint descriptors for HID interfaces.
+ //
+ while (Total < ConfigDesc.TotalLength) {
+ if (Head->Type == USB_DESC_TYPE_INTERFACE) {
+ if ((((USB_INTERFACE_DESCRIPTOR *)Head)->InterfaceNumber == UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber) &&
+ (((USB_INTERFACE_DESCRIPTOR *)Head)->AlternateSetting == UsbMouseAbsolutePointerDev->InterfaceDescriptor.AlternateSetting)) {
+ Start = TRUE;
+ }
+ }
+ if (Start && (Head->Type == USB_DESC_TYPE_ENDPOINT)) {
+ break;
+ }
+ if (Start && (Head->Type == USB_DESC_TYPE_HID)) {
+ MouseHidDesc = (EFI_USB_HID_DESCRIPTOR *)Head;
+ break;
+ }
+ Total = Total + (UINT16)Head->Len;
+ Head = (USB_DESC_HEAD*)((UINT8 *)Buf + Total);
+ }
+
+ if (MouseHidDesc == NULL) {
+ FreePool (Buf);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get report descriptor
+ //
+ if (MouseHidDesc->HidClassDesc[0].DescriptorType != USB_DESC_TYPE_REPORT) {
+ FreePool (Buf);
+ return EFI_UNSUPPORTED;
+ }
+
+ ReportDesc = AllocateZeroPool (MouseHidDesc->HidClassDesc[0].DescriptorLength);
+ ASSERT (ReportDesc != NULL);
+
+ Status = UsbGetReportDescriptor (
+ UsbIo,
+ UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber,
+ MouseHidDesc->HidClassDesc[0].DescriptorLength,
+ ReportDesc
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Buf);
+ FreePool (ReportDesc);
+ return Status;
+ }
+
+ //
+ // Parse report descriptor
+ //
+ Status = ParseMouseReportDescriptor (
+ UsbMouseAbsolutePointerDev,
+ ReportDesc,
+ MouseHidDesc->HidClassDesc[0].DescriptorLength
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Buf);
+ FreePool (ReportDesc);
+ return Status;
+ }
+
+ UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxX = 1024;
+ UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxY = 1024;
+ UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxZ = 0;
+ UsbMouseAbsolutePointerDev->Mode.AbsoluteMinX = 0;
+ UsbMouseAbsolutePointerDev->Mode.AbsoluteMinY = 0;
+ UsbMouseAbsolutePointerDev->Mode.AbsoluteMinZ = 0;
+ UsbMouseAbsolutePointerDev->Mode.Attributes = 0x3;
+
+ //
+ // Let the cursor's starting position is in the center of the screen.
+ //
+ UsbMouseAbsolutePointerDev->State.CurrentX =
+ DivU64x32 (UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxX + UsbMouseAbsolutePointerDev->Mode.AbsoluteMinX, 2);
+ UsbMouseAbsolutePointerDev->State.CurrentY =
+ DivU64x32 (UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxY + UsbMouseAbsolutePointerDev->Mode.AbsoluteMinY, 2);
+
+ //
+ // Set boot protocol for the USB mouse.
+ // This driver only supports boot protocol.
+ //
+ UsbGetProtocolRequest (
+ UsbIo,
+ UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber,
+ &Protocol
+ );
+ if (Protocol != BOOT_PROTOCOL) {
+ Status = UsbSetProtocolRequest (
+ UsbIo,
+ UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber,
+ BOOT_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Buf);
+ FreePool (ReportDesc);
+ return Status;
+ }
+ }
+
+ FreePool (Buf);
+ FreePool (ReportDesc);
+
+ //
+ // Create event for delayed recovery, which deals with device error.
+ //
+ if (UsbMouseAbsolutePointerDev->DelayedRecoveryEvent != NULL) {
+ gBS->CloseEvent (UsbMouseAbsolutePointerDev->DelayedRecoveryEvent);
+ UsbMouseAbsolutePointerDev->DelayedRecoveryEvent = 0;
+ }
+
+ gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ USBMouseRecoveryHandler,
+ UsbMouseAbsolutePointerDev,
+ &UsbMouseAbsolutePointerDev->DelayedRecoveryEvent
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Handler function for USB mouse's asynchronous interrupt transfer.
+
+ This function is the handler function for USB mouse's asynchronous interrupt transfer
+ to manage the mouse. It parses data returned from asynchronous interrupt transfer, and
+ get button and movement state.
+
+ @param Data A pointer to a buffer that is filled with key data which is
+ retrieved via asynchronous interrupt transfer.
+ @param DataLength Indicates the size of the data buffer.
+ @param Context Pointing to USB_KB_DEV instance.
+ @param Result Indicates the result of the asynchronous interrupt transfer.
+
+ @retval EFI_SUCCESS Asynchronous interrupt transfer is handled successfully.
+ @retval EFI_DEVICE_ERROR Hardware error occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+OnMouseInterruptComplete (
+ IN VOID *Data,
+ IN UINTN DataLength,
+ IN VOID *Context,
+ IN UINT32 Result
+ )
+{
+ USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDevice;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINT8 EndpointAddr;
+ UINT32 UsbResult;
+
+ UsbMouseAbsolutePointerDevice = (USB_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
+ UsbIo = UsbMouseAbsolutePointerDevice->UsbIo;
+
+ if (Result != EFI_USB_NOERROR) {
+ //
+ // Some errors happen during the process
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INPUT_ERROR),
+ UsbMouseAbsolutePointerDevice->DevicePath
+ );
+
+ if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) {
+ EndpointAddr = UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress;
+
+ UsbClearEndpointHalt (
+ UsbIo,
+ EndpointAddr,
+ &UsbResult
+ );
+ }
+
+ //
+ // Delete & Submit this interrupt again
+ // Handler of DelayedRecoveryEvent triggered by timer will re-submit the interrupt.
+ //
+ UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress,
+ FALSE,
+ 0,
+ 0,
+ NULL,
+ NULL
+ );
+ //
+ // EFI_USB_INTERRUPT_DELAY is defined in USB standard for error handling.
+ //
+ gBS->SetTimer (
+ UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent,
+ TimerRelative,
+ EFI_USB_INTERRUPT_DELAY
+ );
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // If no error and no data, just return EFI_SUCCESS.
+ //
+ if (DataLength == 0 || Data == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check mouse Data
+ // USB HID Specification specifies following data format:
+ // Byte Bits Description
+ // 0 0 Button 1
+ // 1 Button 2
+ // 2 Button 3
+ // 4 to 7 Device-specific
+ // 1 0 to 7 X displacement
+ // 2 0 to 7 Y displacement
+ // 3 to n 0 to 7 Device specific (optional)
+ //
+ if (DataLength < 3) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ UsbMouseAbsolutePointerDevice->StateChanged = TRUE;
+
+ UsbMouseAbsolutePointerDevice->State.ActiveButtons = *(UINT8 *) Data & (BIT0 | BIT1 | BIT2);
+
+ UsbMouseAbsolutePointerDevice->State.CurrentX =
+ MIN (
+ MAX ((INT64) UsbMouseAbsolutePointerDevice->State.CurrentX + *((INT8 *) Data + 1),
+ (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinX),
+ (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxX
+ );
+ UsbMouseAbsolutePointerDevice->State.CurrentY =
+ MIN (
+ MAX ((INT64) UsbMouseAbsolutePointerDevice->State.CurrentY + *((INT8 *) Data + 2),
+ (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinY),
+ (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxY
+ );
+ if (DataLength > 3) {
+ UsbMouseAbsolutePointerDevice->State.CurrentZ =
+ MIN (
+ MAX ((INT64) UsbMouseAbsolutePointerDevice->State.CurrentZ + *((INT8 *) Data + 1),
+ (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinZ),
+ (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxZ
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieves the current state of a pointer device.
+
+ @param This A pointer to the EFI_ABSOLUTE_POINTER_PROTOCOL instance.
+ @param MouseState A pointer to the state information on the pointer device.
+
+ @retval EFI_SUCCESS The state of the pointer device was returned in State.
+ @retval EFI_NOT_READY The state of the pointer device has not changed since the last call to
+ GetState().
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to retrieve the pointer device's
+ current state.
+ @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetMouseAbsolutePointerState (
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *This,
+ OUT EFI_ABSOLUTE_POINTER_STATE *State
+ )
+{
+ USB_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev;
+
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MouseAbsolutePointerDev = USB_MOUSE_ABSOLUTE_POINTER_DEV_FROM_MOUSE_PROTOCOL (This);
+
+ if (!MouseAbsolutePointerDev->StateChanged) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Retrieve mouse state from USB_MOUSE_ABSOLUTE_POINTER_DEV,
+ // which was filled by OnMouseInterruptComplete()
+ //
+ CopyMem (
+ State,
+ &MouseAbsolutePointerDev->State,
+ sizeof (EFI_ABSOLUTE_POINTER_STATE)
+ );
+
+ MouseAbsolutePointerDev->StateChanged = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Resets the pointer device hardware.
+
+ @param This A pointer to the EFI_ABSOLUTE_POINTER_PROTOCOL instance.
+ @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
+EFIAPI
+UsbMouseAbsolutePointerReset (
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDevice;
+
+ UsbMouseAbsolutePointerDevice = USB_MOUSE_ABSOLUTE_POINTER_DEV_FROM_MOUSE_PROTOCOL (This);
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_PC_RESET),
+ UsbMouseAbsolutePointerDevice->DevicePath
+ );
+
+ //
+ // Clear mouse state.
+ //
+ ZeroMem (
+ &UsbMouseAbsolutePointerDevice->State,
+ sizeof (EFI_ABSOLUTE_POINTER_STATE)
+ );
+
+ //
+ // Let the cursor's starting position is in the center of the screen.
+ //
+ UsbMouseAbsolutePointerDevice->State.CurrentX =
+ DivU64x32 (UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxX + UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinX, 2);
+ UsbMouseAbsolutePointerDevice->State.CurrentY =
+ DivU64x32 (UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxY + UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinY, 2);
+
+ UsbMouseAbsolutePointerDevice->StateChanged = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Event notification function for EFI_ABSOLUTE_POINTER_PROTOCOL.WaitForInput event.
+
+ @param Event Event to be signaled when there's input from mouse.
+ @param Context Points to USB_MOUSE_ABSOLUTE_POINTER_DEV instance.
+
+**/
+VOID
+EFIAPI
+UsbMouseAbsolutePointerWaitForInput (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDev;
+
+ UsbMouseAbsolutePointerDev = (USB_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
+
+ //
+ // If there's input from mouse, signal the event.
+ //
+ if (UsbMouseAbsolutePointerDev->StateChanged) {
+ gBS->SignalEvent (Event);
+ }
+}
+
+/**
+ Handler for Delayed Recovery event.
+
+ This function is the handler for Delayed Recovery event triggered
+ by timer.
+ After a device error occurs, the event would be triggered
+ with interval of EFI_USB_INTERRUPT_DELAY. EFI_USB_INTERRUPT_DELAY
+ is defined in USB standard for error handling.
+
+ @param Event The Delayed Recovery event.
+ @param Context Points to the USB_MOUSE_ABSOLUTE_POINTER_DEV instance.
+
+**/
+VOID
+EFIAPI
+USBMouseRecoveryHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDev;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+
+ UsbMouseAbsolutePointerDev = (USB_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
+
+ UsbIo = UsbMouseAbsolutePointerDev->UsbIo;
+
+ //
+ // Re-submit Asynchronous Interrupt Transfer for recovery.
+ //
+ UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ UsbMouseAbsolutePointerDev->IntEndpointDescriptor.EndpointAddress,
+ TRUE,
+ UsbMouseAbsolutePointerDev->IntEndpointDescriptor.Interval,
+ UsbMouseAbsolutePointerDev->IntEndpointDescriptor.MaxPacketSize,
+ OnMouseInterruptComplete,
+ UsbMouseAbsolutePointerDev
+ );
+}