diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe')
7 files changed, 2062 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/ComponentName.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/ComponentName.c new file mode 100644 index 00000000..fff6fa69 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/ComponentName.c @@ -0,0 +1,218 @@ +/** @file + UEFI Component Name(2) protocol implementation for USB Mouse driver. + +Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "UsbMouse.h" + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbMouseComponentName = { + UsbMouseComponentNameGetDriverName, + UsbMouseComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbMouseComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UsbMouseComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UsbMouseComponentNameGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUsbMouseDriverNameTable[] = { + { "eng;en", L"Usb Mouse Driver" }, + { NULL , NULL } +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + @param Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + @param DriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +UsbMouseComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mUsbMouseDriverNameTable, + DriverName, + (BOOLEAN)(This == &gUsbMouseComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + @param ControllerHandle The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + @param ChildHandle The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + @param Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + @param ControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +UsbMouseComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + USB_MOUSE_DEV *UsbMouseDev; + EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol; + EFI_USB_IO_PROTOCOL *UsbIoProtocol; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Check Controller's handle + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIoProtocol, + gUsbMouseDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (!EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + gUsbMouseDriverBinding.DriverBindingHandle, + ControllerHandle + ); + + return EFI_UNSUPPORTED; + } + + if (Status != EFI_ALREADY_STARTED) { + return EFI_UNSUPPORTED; + } + // + // Get the device context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimplePointerProtocolGuid, + (VOID **) &SimplePointerProtocol, + gUsbMouseDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + UsbMouseDev = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (SimplePointerProtocol); + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + UsbMouseDev->ControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gUsbMouseComponentName) + ); + +} diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/MouseHid.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/MouseHid.c new file mode 100644 index 00000000..5b03879a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/MouseHid.c @@ -0,0 +1,275 @@ +/** @file + Helper functions to parse HID report descriptor and items. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UsbMouse.h" + + +/** + Get next HID item from report descriptor. + + This function retrieves next HID item from report descriptor, according to + the start position. + According to USB HID Specification, An item is piece of information + about the device. All items have a one-byte prefix that contains + the item tag, item type, and item size. + There are two basic types of items: short items and long items. + If the item is a short item, its optional data size may be 0, 1, 2, or 4 bytes. + Only short item is supported here. + + @param StartPos Start position of the HID item to get. + @param EndPos End position of the range to get the next HID item. + @param HidItem Buffer for the HID Item to return. + + @return Pointer to end of the HID item returned. + NULL if no HID item retrieved. + +**/ +UINT8 * +GetNextHidItem ( + IN UINT8 *StartPos, + IN UINT8 *EndPos, + OUT HID_ITEM *HidItem + ) +{ + UINT8 Temp; + + if (EndPos <= StartPos) { + return NULL; + } + + Temp = *StartPos; + StartPos++; + + // + // Bit format of prefix byte: + // Bits 0-1: Size + // Bits 2-3: Type + // Bits 4-7: Tag + // + HidItem->Type = BitFieldRead8 (Temp, 2, 3); + HidItem->Tag = BitFieldRead8 (Temp, 4, 7); + + if (HidItem->Tag == HID_ITEM_TAG_LONG) { + // + // Long Items are not supported, although we try to parse it. + // + HidItem->Format = HID_ITEM_FORMAT_LONG; + + if ((EndPos - StartPos) >= 2) { + HidItem->Size = *StartPos++; + HidItem->Tag = *StartPos++; + + if ((EndPos - StartPos) >= HidItem->Size) { + HidItem->Data.LongData = StartPos; + StartPos += HidItem->Size; + return StartPos; + } + } + } else { + HidItem->Format = HID_ITEM_FORMAT_SHORT; + HidItem->Size = BitFieldRead8 (Temp, 0, 1); + + switch (HidItem->Size) { + case 0: + // + // No data + // + return StartPos; + + case 1: + // + // 1-byte data + // + if ((EndPos - StartPos) >= 1) { + HidItem->Data.Uint8 = *StartPos++; + return StartPos; + } + + case 2: + // + // 2-byte data + // + if ((EndPos - StartPos) >= 2) { + CopyMem (&HidItem->Data.Uint16, StartPos, sizeof (UINT16)); + StartPos += 2; + return StartPos; + } + + case 3: + // + // 4-byte data, adjust size + // + HidItem->Size = 4; + if ((EndPos - StartPos) >= 4) { + CopyMem (&HidItem->Data.Uint32, StartPos, sizeof (UINT32)); + StartPos += 4; + return StartPos; + } + } + } + + return NULL; +} + + +/** + Get data from HID item. + + This function retrieves data from HID item. + It only supports short items, which has 4 types of data: + 0, 1, 2, or 4 bytes. + + @param HidItem Pointer to the HID item. + + @return The data of HID item. + +**/ +UINT32 +GetItemData ( + IN HID_ITEM *HidItem + ) +{ + // + // Get data from HID item. + // + switch (HidItem->Size) { + case 1: + return HidItem->Data.Uint8; + case 2: + return HidItem->Data.Uint16; + case 4: + return HidItem->Data.Uint32; + } + return 0; +} + +/** + Parse HID item from report descriptor. + + There are three item types: Main, Global, and Local. + This function parses these types of HID items according + to tag info. + + @param UsbMouse The instance of USB_MOUSE_DEV + @param HidItem The HID item to parse + +**/ +VOID +ParseHidItem ( + IN USB_MOUSE_DEV *UsbMouse, + IN HID_ITEM *HidItem + ) +{ + UINT8 Data; + + switch (HidItem->Type) { + + case HID_ITEM_TYPE_MAIN: + // + // we don't care any main items, just skip + // + return; + + case HID_ITEM_TYPE_GLOBAL: + // + // For global items, we only care Usage Page tag for Button Page here + // + if (HidItem->Tag == HID_GLOBAL_ITEM_TAG_USAGE_PAGE) { + Data = (UINT8) GetItemData (HidItem); + if (Data == 0x09) { + // + // Button Page + // + UsbMouse->PrivateData.ButtonDetected = TRUE; + } + } + return; + + case HID_ITEM_TYPE_LOCAL: + if (HidItem->Size == 0) { + // + // No expected data for local item + // + return ; + } + + Data = (UINT8) GetItemData (HidItem); + + switch (HidItem->Tag) { + case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: + if (UsbMouse->PrivateData.ButtonDetected) { + UsbMouse->PrivateData.ButtonMinIndex = Data; + } + return ; + + case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: + { + if (UsbMouse->PrivateData.ButtonDetected) { + UsbMouse->PrivateData.ButtonMaxIndex = Data; + } + return ; + } + + default: + return; + } + } +} + + +/** + Parse Mouse Report Descriptor. + + According to USB HID Specification, report descriptors are + composed of pieces of information. Each piece of information + is called an Item. This function retrieves each item from + the report descriptor and updates USB_MOUSE_DEV. + + @param UsbMouse The instance of USB_MOUSE_DEV + @param ReportDescriptor Report descriptor to parse + @param ReportSize Report descriptor size + + @retval EFI_SUCCESS Report descriptor successfully parsed. + @retval EFI_UNSUPPORTED Report descriptor contains long item. + +**/ +EFI_STATUS +ParseMouseReportDescriptor ( + OUT USB_MOUSE_DEV *UsbMouse, + IN UINT8 *ReportDescriptor, + IN UINTN ReportSize + ) +{ + UINT8 *DescriptorEnd; + UINT8 *Ptr; + HID_ITEM HidItem; + + DescriptorEnd = ReportDescriptor + ReportSize; + + Ptr = GetNextHidItem (ReportDescriptor, DescriptorEnd, &HidItem); + while (Ptr != NULL) { + if (HidItem.Format != HID_ITEM_FORMAT_SHORT) { + // + // Long Item is not supported at current HID revision + // + return EFI_UNSUPPORTED; + } + + ParseHidItem (UsbMouse, &HidItem); + + Ptr = GetNextHidItem (Ptr, DescriptorEnd, &HidItem); + } + + UsbMouse->NumberOfButtons = (UINT8) (UsbMouse->PrivateData.ButtonMaxIndex - UsbMouse->PrivateData.ButtonMinIndex + 1); + UsbMouse->XLogicMax = 127; + UsbMouse->YLogicMax = 127; + UsbMouse->XLogicMin = -127; + UsbMouse->YLogicMin = -127; + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.c new file mode 100644 index 00000000..e8055107 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.c @@ -0,0 +1,999 @@ +/** @file + USB Mouse Driver that manages USB mouse and produces Simple Pointer Protocol. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UsbMouse.h" + +EFI_DRIVER_BINDING_PROTOCOL gUsbMouseDriverBinding = { + USBMouseDriverBindingSupported, + USBMouseDriverBindingStart, + USBMouseDriverBindingStop, + 0xa, + NULL, + NULL +}; + +/** + Entrypoint of USB Mouse 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 +USBMouseDriverBindingEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gUsbMouseDriverBinding, + ImageHandle, + &gUsbMouseComponentName, + &gUsbMouseComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + + +/** + Check whether USB mouse driver supports this device. + + @param This The USB mouse 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 +USBMouseDriverBindingSupported ( + 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 Simple Pointer Protocol, and submits Asynchronous Interrupt + Transfer to manage the USB mouse device. + + @param This The USB mouse 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 +USBMouseDriverBindingStart ( + 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_DEV *UsbMouseDevice; + 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; + } + + UsbMouseDevice = AllocateZeroPool (sizeof (USB_MOUSE_DEV)); + ASSERT (UsbMouseDevice != NULL); + + UsbMouseDevice->UsbIo = UsbIo; + UsbMouseDevice->Signature = USB_MOUSE_DEV_SIGNATURE; + + // + // Get the Device Path Protocol on Controller's handle + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &UsbMouseDevice->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), + UsbMouseDevice->DevicePath + ); + + // + // Get interface & endpoint descriptor + // + UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &UsbMouseDevice->InterfaceDescriptor + ); + + EndpointNumber = UsbMouseDevice->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(&UsbMouseDevice->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), + UsbMouseDevice->DevicePath + ); + + Status = InitializeUsbMouseDevice (UsbMouseDevice); + 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), + UsbMouseDevice->DevicePath + ); + + goto ErrorExit; + } + + // + // Initialize and install EFI Simple Pointer Protocol. + // + UsbMouseDevice->SimplePointerProtocol.GetState = GetMouseState; + UsbMouseDevice->SimplePointerProtocol.Reset = UsbMouseReset; + UsbMouseDevice->SimplePointerProtocol.Mode = &UsbMouseDevice->Mode; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + UsbMouseWaitForInput, + UsbMouseDevice, + &((UsbMouseDevice->SimplePointerProtocol).WaitForInput) + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + Status = gBS->InstallProtocolInterface ( + &Controller, + &gEfiSimplePointerProtocolGuid, + EFI_NATIVE_INTERFACE, + &UsbMouseDevice->SimplePointerProtocol + ); + + 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), + UsbMouseDevice->DevicePath + ); + + // + // Submit Asynchronous Interrupt Transfer to manage this device. + // + EndpointAddr = UsbMouseDevice->IntEndpointDescriptor.EndpointAddress; + PollingInterval = UsbMouseDevice->IntEndpointDescriptor.Interval; + PacketSize = (UINT8) (UsbMouseDevice->IntEndpointDescriptor.MaxPacketSize); + + Status = UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + EndpointAddr, + TRUE, + PollingInterval, + PacketSize, + OnMouseInterruptComplete, + UsbMouseDevice + ); + + if (EFI_ERROR (Status)) { + // + // If submit error, uninstall that interface + // + gBS->UninstallProtocolInterface ( + Controller, + &gEfiSimplePointerProtocolGuid, + &UsbMouseDevice->SimplePointerProtocol + ); + goto ErrorExit; + } + + UsbMouseDevice->ControllerNameTable = NULL; + AddUnicodeString2 ( + "eng", + gUsbMouseComponentName.SupportedLanguages, + &UsbMouseDevice->ControllerNameTable, + L"Generic Usb Mouse", + TRUE + ); + AddUnicodeString2 ( + "en", + gUsbMouseComponentName2.SupportedLanguages, + &UsbMouseDevice->ControllerNameTable, + L"Generic Usb Mouse", + FALSE + ); + + gBS->RestoreTPL (OldTpl); + + return EFI_SUCCESS; + +// +// Error handler +// +ErrorExit: + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + if (UsbMouseDevice != NULL) { + if ((UsbMouseDevice->SimplePointerProtocol).WaitForInput != NULL) { + gBS->CloseEvent ((UsbMouseDevice->SimplePointerProtocol).WaitForInput); + } + + FreePool (UsbMouseDevice); + UsbMouseDevice = NULL; + } + } + +ErrorExit1: + gBS->RestoreTPL (OldTpl); + return Status; +} + + +/** + Stop the USB mouse device handled by this driver. + + @param This The USB mouse 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 Simple Pointer Protocol is not installed on Controller. + @retval Others Fail to uninstall protocols attached on the device. + +**/ +EFI_STATUS +EFIAPI +USBMouseDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + USB_MOUSE_DEV *UsbMouseDevice; + EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol; + EFI_USB_IO_PROTOCOL *UsbIo; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiSimplePointerProtocolGuid, + (VOID **) &SimplePointerProtocol, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + UsbMouseDevice = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (SimplePointerProtocol); + + UsbIo = UsbMouseDevice->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), + UsbMouseDevice->DevicePath + ); + + // + // Delete the Asynchronous Interrupt Transfer from this device + // + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + UsbMouseDevice->IntEndpointDescriptor.EndpointAddress, + FALSE, + UsbMouseDevice->IntEndpointDescriptor.Interval, + 0, + NULL, + NULL + ); + + Status = gBS->UninstallProtocolInterface ( + Controller, + &gEfiSimplePointerProtocolGuid, + &UsbMouseDevice->SimplePointerProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // + // Free all resources. + // + gBS->CloseEvent (UsbMouseDevice->SimplePointerProtocol.WaitForInput); + + if (UsbMouseDevice->DelayedRecoveryEvent != NULL) { + gBS->CloseEvent (UsbMouseDevice->DelayedRecoveryEvent); + UsbMouseDevice->DelayedRecoveryEvent = NULL; + } + + if (UsbMouseDevice->ControllerNameTable != NULL) { + FreeUnicodeStringTable (UsbMouseDevice->ControllerNameTable); + } + + FreePool (UsbMouseDevice); + + 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_DEV. Then it sets indefinite idle + rate for the device. Finally it creates event for delayed recovery, + which deals with device error. + + @param UsbMouseDev 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 OUT USB_MOUSE_DEV *UsbMouseDev + ) +{ + 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 = UsbMouseDev->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 == UsbMouseDev->InterfaceDescriptor.InterfaceNumber) && + (((USB_INTERFACE_DESCRIPTOR *)Head)->AlternateSetting == UsbMouseDev->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, + UsbMouseDev->InterfaceDescriptor.InterfaceNumber, + MouseHidDesc->HidClassDesc[0].DescriptorLength, + ReportDesc + ); + + if (EFI_ERROR (Status)) { + FreePool (Buf); + FreePool (ReportDesc); + return Status; + } + + // + // Parse report descriptor + // + Status = ParseMouseReportDescriptor ( + UsbMouseDev, + ReportDesc, + MouseHidDesc->HidClassDesc[0].DescriptorLength + ); + + if (EFI_ERROR (Status)) { + FreePool (Buf); + FreePool (ReportDesc); + return Status; + } + + // + // Check the presence of left and right buttons, + // and initialize fields of EFI_SIMPLE_POINTER_MODE. + // + if (UsbMouseDev->NumberOfButtons >= 1) { + UsbMouseDev->Mode.LeftButton = TRUE; + } + if (UsbMouseDev->NumberOfButtons > 1) { + UsbMouseDev->Mode.RightButton = TRUE; + } + UsbMouseDev->Mode.ResolutionX = 8; + UsbMouseDev->Mode.ResolutionY = 8; + UsbMouseDev->Mode.ResolutionZ = 0; + + // + // Set boot protocol for the USB mouse. + // This driver only supports boot protocol. + // + UsbGetProtocolRequest ( + UsbIo, + UsbMouseDev->InterfaceDescriptor.InterfaceNumber, + &Protocol + ); + if (Protocol != BOOT_PROTOCOL) { + Status = UsbSetProtocolRequest ( + UsbIo, + UsbMouseDev->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 (UsbMouseDev->DelayedRecoveryEvent != NULL) { + gBS->CloseEvent (UsbMouseDev->DelayedRecoveryEvent); + UsbMouseDev->DelayedRecoveryEvent = 0; + } + + gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + USBMouseRecoveryHandler, + UsbMouseDev, + &UsbMouseDev->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_DEV *UsbMouseDevice; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 EndpointAddr; + UINT32 UsbResult; + + UsbMouseDevice = (USB_MOUSE_DEV *) Context; + UsbIo = UsbMouseDevice->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), + UsbMouseDevice->DevicePath + ); + + if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + EndpointAddr = UsbMouseDevice->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, + UsbMouseDevice->IntEndpointDescriptor.EndpointAddress, + FALSE, + 0, + 0, + NULL, + NULL + ); + // + // EFI_USB_INTERRUPT_DELAY is defined in USB standard for error handling. + // + gBS->SetTimer ( + UsbMouseDevice->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; + } + + UsbMouseDevice->StateChanged = TRUE; + + UsbMouseDevice->State.LeftButton = (BOOLEAN) ((*(UINT8 *) Data & BIT0) != 0); + UsbMouseDevice->State.RightButton = (BOOLEAN) ((*(UINT8 *) Data & BIT1) != 0); + UsbMouseDevice->State.RelativeMovementX += *((INT8 *) Data + 1); + UsbMouseDevice->State.RelativeMovementY += *((INT8 *) Data + 2); + + if (DataLength > 3) { + UsbMouseDevice->State.RelativeMovementZ += *((INT8 *) Data + 3); + } + + return EFI_SUCCESS; +} + +/** + Retrieves the current state of a pointer device. + + @param This A pointer to the EFI_SIMPLE_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 MouseState is NULL. + +**/ +EFI_STATUS +EFIAPI +GetMouseState ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + OUT EFI_SIMPLE_POINTER_STATE *MouseState + ) +{ + USB_MOUSE_DEV *MouseDev; + + if (MouseState == NULL) { + return EFI_INVALID_PARAMETER; + } + + MouseDev = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (This); + + if (!MouseDev->StateChanged) { + return EFI_NOT_READY; + } + + // + // Retrieve mouse state from USB_MOUSE_DEV, which was filled by OnMouseInterruptComplete() + // + CopyMem ( + MouseState, + &MouseDev->State, + sizeof (EFI_SIMPLE_POINTER_STATE) + ); + + // + // Clear previous move state + // + MouseDev->State.RelativeMovementX = 0; + MouseDev->State.RelativeMovementY = 0; + MouseDev->State.RelativeMovementZ = 0; + + MouseDev->StateChanged = FALSE; + + return EFI_SUCCESS; +} + + +/** + Resets the pointer device hardware. + + @param This A pointer to the EFI_SIMPLE_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 +UsbMouseReset ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + USB_MOUSE_DEV *UsbMouseDevice; + + UsbMouseDevice = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (This); + + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_MOUSE | EFI_P_PC_RESET), + UsbMouseDevice->DevicePath + ); + + // + // Clear mouse state. + // + ZeroMem ( + &UsbMouseDevice->State, + sizeof (EFI_SIMPLE_POINTER_STATE) + ); + UsbMouseDevice->StateChanged = FALSE; + + return EFI_SUCCESS; +} + +/** + Event notification function for EFI_SIMPLE_POINTER_PROTOCOL.WaitForInput event. + + @param Event Event to be signaled when there's input from mouse. + @param Context Points to USB_MOUSE_DEV instance. + +**/ +VOID +EFIAPI +UsbMouseWaitForInput ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + USB_MOUSE_DEV *UsbMouseDev; + + UsbMouseDev = (USB_MOUSE_DEV *) Context; + + // + // If there's input from mouse, signal the event. + // + if (UsbMouseDev->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_DEV instance. + +**/ +VOID +EFIAPI +USBMouseRecoveryHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + USB_MOUSE_DEV *UsbMouseDev; + EFI_USB_IO_PROTOCOL *UsbIo; + + UsbMouseDev = (USB_MOUSE_DEV *) Context; + + UsbIo = UsbMouseDev->UsbIo; + + // + // Re-submit Asynchronous Interrupt Transfer for recovery. + // + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + UsbMouseDev->IntEndpointDescriptor.EndpointAddress, + TRUE, + UsbMouseDev->IntEndpointDescriptor.Interval, + UsbMouseDev->IntEndpointDescriptor.MaxPacketSize, + OnMouseInterruptComplete, + UsbMouseDev + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.h b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.h new file mode 100644 index 00000000..84ff97a4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.h @@ -0,0 +1,465 @@ +/** @file + Helper routine and corresponding data struct used by USB Mouse Driver. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_USB_MOUSE_H_ +#define _EFI_USB_MOUSE_H_ + + +#include <Uefi.h> + +#include <Protocol/SimplePointer.h> +#include <Protocol/UsbIo.h> +#include <Protocol/DevicePath.h> + +#include <Library/ReportStatusCodeLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiUsbLib.h> +#include <Library/DebugLib.h> + +#include <IndustryStandard/Usb.h> + +#define CLASS_HID 3 +#define SUBCLASS_BOOT 1 +#define PROTOCOL_MOUSE 2 + +#define BOOT_PROTOCOL 0 +#define REPORT_PROTOCOL 1 + +#define USB_MOUSE_DEV_SIGNATURE SIGNATURE_32 ('u', 'm', 'o', 'u') + +// +// A common header for usb standard descriptor. +// Each stand descriptor has a length and type. +// +#pragma pack(1) +typedef struct { + UINT8 Len; + UINT8 Type; +} USB_DESC_HEAD; +#pragma pack() + +/// +/// Button range and status +/// +typedef struct { + BOOLEAN ButtonDetected; + UINT8 ButtonMinIndex; + UINT8 ButtonMaxIndex; + UINT8 Reserved; +} USB_MOUSE_BUTTON_DATA; + +/// +/// Device instance of USB mouse. +/// +typedef struct { + UINTN Signature; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_EVENT DelayedRecoveryEvent; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + EFI_USB_ENDPOINT_DESCRIPTOR IntEndpointDescriptor; + UINT8 NumberOfButtons; + INT32 XLogicMax; + INT32 XLogicMin; + INT32 YLogicMax; + INT32 YLogicMin; + EFI_SIMPLE_POINTER_PROTOCOL SimplePointerProtocol; + EFI_SIMPLE_POINTER_STATE State; + EFI_SIMPLE_POINTER_MODE Mode; + BOOLEAN StateChanged; + USB_MOUSE_BUTTON_DATA PrivateData; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; +} USB_MOUSE_DEV; + +/// +/// General HID Item structure +/// + +typedef union { + UINT8 Uint8; + UINT16 Uint16; + UINT32 Uint32; + INT8 Int8; + INT16 Int16; + INT32 Int32; + UINT8 *LongData; +} HID_DATA; + +typedef struct { + UINT16 Format; + UINT8 Size; + UINT8 Type; + UINT8 Tag; + HID_DATA Data; +} HID_ITEM; + +#define USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL(a) \ + CR(a, USB_MOUSE_DEV, SimplePointerProtocol, USB_MOUSE_DEV_SIGNATURE) + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gUsbMouseDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gUsbMouseComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gUsbMouseComponentName2; + +// +// Functions of Driver Binding Protocol +// + +/** + Check whether USB mouse driver supports this device. + + @param This The USB mouse 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 +USBMouseDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Starts the mouse device with this driver. + + This function consumes USB I/O Protocol, initializes USB mouse device, + installs Simple Pointer Protocol, and submits Asynchronous Interrupt + Transfer to manage the USB mouse device. + + @param This The USB mouse 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 +USBMouseDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Stop the USB mouse device handled by this driver. + + @param This The USB mouse 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 Simple Pointer Protocol is not installed on Controller. + @retval Others Fail to uninstall protocols attached on the device. + +**/ +EFI_STATUS +EFIAPI +USBMouseDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// EFI Component Name Functions +// + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + @param Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + @param DriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +UsbMouseComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + @param ControllerHandle The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + @param ChildHandle The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + @param Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + @param ControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +UsbMouseComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +// +// Functions of EFI_SIMPLE_POINTER_PROTOCOL +// + +/** + Retrieves the current state of a pointer device. + + @param This A pointer to the EFI_SIMPLE_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 MouseState is NULL. + +**/ +EFI_STATUS +EFIAPI +GetMouseState ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + OUT EFI_SIMPLE_POINTER_STATE *MouseState + ); + +/** + Resets the pointer device hardware. + + @param This A pointer to the EFI_SIMPLE_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 +UsbMouseReset ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Event notification function for SIMPLE_POINTER.WaitForInput event. + + @param Event Event to be signaled when there's input from mouse. + @param Context Points to USB_MOUSE_DEV instance. + +**/ +VOID +EFIAPI +UsbMouseWaitForInput ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +// +// Internal worker functions +// + +/** + 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 + ); + +/** + Initialize the USB mouse device. + + This function retrieves and parses HID report descriptor, and + initializes state of USB_MOUSE_DEV. Then it sets indefinite idle + rate for the device. Finally it creates event for delayed recovery, + which deals with device error. + + @param UsbMouseDev 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 OUT USB_MOUSE_DEV *UsbMouseDev + ); + +/** + 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 + ); + +/** + 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_DEV instance. + +**/ +VOID +EFIAPI +USBMouseRecoveryHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Parse Mouse Report Descriptor. + + According to USB HID Specification, report descriptors are + composed of pieces of information. Each piece of information + is called an Item. This function retrieves each item from + the report descriptor and updates USB_MOUSE_DEV. + + @param UsbMouse The instance of USB_MOUSE_DEV + @param ReportDescriptor Report descriptor to parse + @param ReportSize Report descriptor size + + @retval EFI_SUCCESS Report descriptor successfully parsed. + @retval EFI_UNSUPPORTED Report descriptor contains long item. + +**/ +EFI_STATUS +ParseMouseReportDescriptor ( + OUT USB_MOUSE_DEV *UsbMouse, + IN UINT8 *ReportDescriptor, + IN UINTN ReportSize + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.inf b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.inf new file mode 100644 index 00000000..3b2f5a12 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.inf @@ -0,0 +1,66 @@ +## @file +# USB Mouse Driver that manages USB mouse and produces Simple Pointer Protocol. +# +# USB Mouse Driver consumes USB I/O Protocol and Device Path Protocol, and produces +# Simple Pointer Protocol on USB mouse devices. +# It manages the USB mouse device via Asynchronous Interrupt Transfer of USB I/O Protocol, +# and parses the data according to USB HID Specification. +# This module refers to following specifications: +# 1. Universal Serial Bus HID Firmware Specification, ver 1.11 +# 2. UEFI Specification, v2.1 +# +# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = UsbMouseDxe + MODULE_UNI_FILE = UsbMouseDxe.uni + FILE_GUID = 2D2E62AA-9ECF-43b7-8219-94E7FC713DFE + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = USBMouseDriverBindingEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# +# DRIVER_BINDING = gUsbMouseDriverBinding +# COMPONENT_NAME = gUsbMouseComponentName +# COMPONENT_NAME2 = gUsbMouseComponentName2 +# + +[Sources] + ComponentName.c + MouseHid.c + UsbMouse.c + UsbMouse.h + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + BaseMemoryLib + ReportStatusCodeLib + UefiUsbLib + +[Protocols] + gEfiUsbIoProtocolGuid ## TO_START + gEfiDevicePathProtocolGuid ## TO_START + gEfiSimplePointerProtocolGuid ## BY_START + +# [Event] +# EVENT_TYPE_RELATIVE_TIMER ## CONSUMES +# + +[UserExtensions.TianoCore."ExtraFiles"] + UsbMouseDxeExtra.uni diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.uni new file mode 100644 index 00000000..70df7c6c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.uni @@ -0,0 +1,25 @@ +// /** @file
+// USB Mouse Driver that manages USB mouse and produces Simple Pointer Protocol.
+//
+// USB Mouse Driver consumes USB I/O Protocol and Device Path Protocol, and produces
+// Simple Pointer Protocol on USB mouse devices.
+// It manages the USB mouse device via Asynchronous Interrupt Transfer of USB I/O Protocol,
+// and parses the data according to USB HID Specification.
+// This module refers to following specifications:
+// 1. Universal Serial Bus HID Firmware Specification, ver 1.11
+// 2. UEFI Specification, v2.1
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Manages USB mouse and produces Simple Pointer Protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "USB Mouse Driver consumes USB I/O Protocol and Device Path Protocol, and produces Simple Pointer Protocol on USB mouse devices. It manages the USB mouse device via Asynchronous Interrupt Transfer of USB I/O Protocol, and parses the data according to USB HID Specification.<BR><BR>\n"
+ "This module refers to following specifications:<BR>\n"
+ "1. Universal Serial Bus HID Firmware Specification, ver 1.11<BR>\n"
+ "2. UEFI Specification, v2.1<BR>"
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxeExtra.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxeExtra.uni new file mode 100644 index 00000000..fcabd21a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxeExtra.uni @@ -0,0 +1,14 @@ +// /** @file
+// UsbMouseDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"USB Mouse DXE Driver"
+
+
|