mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-28 12:25:19 +01:00
7c0aa811ec
Signed-off-by: Sergey Isakov <isakov-sl@bk.ru>
1018 lines
31 KiB
C
1018 lines
31 KiB
C
/** @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 Portocol, intializes 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
|
|
//
|
|
Found = FALSE;
|
|
for (Index = 0; Index < EndpointNumber; Index++) {
|
|
UsbIo->UsbGetEndpointDescriptor (
|
|
UsbIo,
|
|
Index,
|
|
&EndpointDescriptor
|
|
);
|
|
|
|
if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) {
|
|
//
|
|
// 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
|
|
);
|
|
}
|