diff --git a/sys/Ds4Pdo.cpp b/sys/Ds4Pdo.cpp index 735a3c9..7fd3756 100644 --- a/sys/Ds4Pdo.cpp +++ b/sys/Ds4Pdo.cpp @@ -11,909 +11,1003 @@ PCWSTR ViGEm::Bus::Targets::EmulationTargetDS4::_deviceDescription = L"Virtual D ViGEm::Bus::Targets::EmulationTargetDS4::EmulationTargetDS4() : EmulationTargetPDO(0x054C, 0x05C4) { - TargetType = DualShock4Wired; - UsbConfigurationDescriptionSize = DS4_DESCRIPTOR_SIZE; + TargetType = DualShock4Wired; + UsbConfigurationDescriptionSize = DS4_DESCRIPTOR_SIZE; } NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::PrepareDevice(PWDFDEVICE_INIT DeviceInit, - PUNICODE_STRING DeviceId, PUNICODE_STRING DeviceDescription) + PUNICODE_STRING DeviceId, PUNICODE_STRING DeviceDescription) { - NTSTATUS status; - UNICODE_STRING buffer; - - // prepare device description - status = RtlUnicodeStringInit(DeviceDescription, _deviceDescription); - if (!NT_SUCCESS(status)) - { - TraceEvents(TRACE_LEVEL_ERROR, - TRACE_DS4, - "RtlUnicodeStringInit failed with status %!STATUS!", - status); - return status; - } + NTSTATUS status; + UNICODE_STRING buffer; - // Set hardware IDs - RtlUnicodeStringInit(&buffer, L"USB\\VID_054C&PID_05C4&REV_0100"); + // prepare device description + status = RtlUnicodeStringInit(DeviceDescription, _deviceDescription); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "RtlUnicodeStringInit failed with status %!STATUS!", + status); + return status; + } - status = WdfPdoInitAddHardwareID(DeviceInit, &buffer); - if (!NT_SUCCESS(status)) - { - TraceEvents(TRACE_LEVEL_ERROR, - TRACE_DS4, - "WdfPdoInitAddHardwareID failed with status %!STATUS!", - status); - return status; - } + // Set hardware IDs + RtlUnicodeStringInit(&buffer, L"USB\\VID_054C&PID_05C4&REV_0100"); - RtlUnicodeStringCopy(DeviceId, &buffer); + status = WdfPdoInitAddHardwareID(DeviceInit, &buffer); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "WdfPdoInitAddHardwareID failed with status %!STATUS!", + status); + return status; + } - RtlUnicodeStringInit(&buffer, L"USB\\VID_054C&PID_05C4"); + RtlUnicodeStringCopy(DeviceId, &buffer); - status = WdfPdoInitAddHardwareID(DeviceInit, &buffer); - if (!NT_SUCCESS(status)) - { - TraceEvents(TRACE_LEVEL_ERROR, - TRACE_DS4, - "WdfPdoInitAddHardwareID failed with status %!STATUS!", - status); - return status; - } + RtlUnicodeStringInit(&buffer, L"USB\\VID_054C&PID_05C4"); - // Set compatible IDs - RtlUnicodeStringInit(&buffer, L"USB\\Class_03&SubClass_00&Prot_00"); + status = WdfPdoInitAddHardwareID(DeviceInit, &buffer); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "WdfPdoInitAddHardwareID failed with status %!STATUS!", + status); + return status; + } - status = WdfPdoInitAddCompatibleID(DeviceInit, &buffer); - if (!NT_SUCCESS(status)) - { - TraceEvents(TRACE_LEVEL_ERROR, - TRACE_DS4, - "WdfPdoInitAddCompatibleID (#01) failed with status %!STATUS!", - status); - return status; - } + // Set compatible IDs + RtlUnicodeStringInit(&buffer, L"USB\\Class_03&SubClass_00&Prot_00"); - RtlUnicodeStringInit(&buffer, L"USB\\Class_03&SubClass_00"); + status = WdfPdoInitAddCompatibleID(DeviceInit, &buffer); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "WdfPdoInitAddCompatibleID (#01) failed with status %!STATUS!", + status); + return status; + } - status = WdfPdoInitAddCompatibleID(DeviceInit, &buffer); - if (!NT_SUCCESS(status)) - { - TraceEvents(TRACE_LEVEL_ERROR, - TRACE_DS4, - "WdfPdoInitAddCompatibleID (#02) failed with status %!STATUS!", - status); - return status; - } + RtlUnicodeStringInit(&buffer, L"USB\\Class_03&SubClass_00"); - RtlUnicodeStringInit(&buffer, L"USB\\Class_03"); + status = WdfPdoInitAddCompatibleID(DeviceInit, &buffer); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "WdfPdoInitAddCompatibleID (#02) failed with status %!STATUS!", + status); + return status; + } - status = WdfPdoInitAddCompatibleID(DeviceInit, &buffer); - if (!NT_SUCCESS(status)) - { - TraceEvents(TRACE_LEVEL_ERROR, - TRACE_DS4, - "WdfPdoInitAddCompatibleID (#03) failed with status %!STATUS!", - status); - return status; - } + RtlUnicodeStringInit(&buffer, L"USB\\Class_03"); - return STATUS_SUCCESS; + status = WdfPdoInitAddCompatibleID(DeviceInit, &buffer); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "WdfPdoInitAddCompatibleID (#03) failed with status %!STATUS!", + status); + return status; + } + + return STATUS_SUCCESS; } NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::PrepareHardware() { WDF_QUERY_INTERFACE_CONFIG ifaceCfg; - INTERFACE devinterfaceHid; + INTERFACE devinterfaceHid; - devinterfaceHid.Size = sizeof(INTERFACE); - devinterfaceHid.Version = 1; - devinterfaceHid.Context = static_cast(this->PdoDevice); + devinterfaceHid.Size = sizeof(INTERFACE); + devinterfaceHid.Version = 1; + devinterfaceHid.Context = static_cast(this->PdoDevice); - devinterfaceHid.InterfaceReference = WdfDeviceInterfaceReferenceNoOp; - devinterfaceHid.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp; + devinterfaceHid.InterfaceReference = WdfDeviceInterfaceReferenceNoOp; + devinterfaceHid.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp; - // Expose GUID_DEVINTERFACE_HID so HIDUSB can initialize - WDF_QUERY_INTERFACE_CONFIG_INIT( - &ifaceCfg, - (PINTERFACE)&devinterfaceHid, - &GUID_DEVINTERFACE_HID, - NULL - ); + // Expose GUID_DEVINTERFACE_HID so HIDUSB can initialize + WDF_QUERY_INTERFACE_CONFIG_INIT( + &ifaceCfg, + (PINTERFACE)&devinterfaceHid, + &GUID_DEVINTERFACE_HID, + NULL + ); - NTSTATUS status = WdfDeviceAddQueryInterface(this->PdoDevice, &ifaceCfg); - if (!NT_SUCCESS(status)) - { - TraceEvents(TRACE_LEVEL_ERROR, - TRACE_DS4, - "WdfDeviceAddQueryInterface failed with status %!STATUS!", - status); - return status; - } + NTSTATUS status = WdfDeviceAddQueryInterface(this->PdoDevice, &ifaceCfg); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "WdfDeviceAddQueryInterface failed with status %!STATUS!", + status); + return status; + } - // Set default HID input report (everything zero`d) - UCHAR DefaultHidReport[DS4_REPORT_SIZE] = - { - 0x01, 0x82, 0x7F, 0x7E, 0x80, 0x08, 0x00, 0x58, - 0x00, 0x00, 0xFD, 0x63, 0x06, 0x03, 0x00, 0xFE, - 0xFF, 0xFC, 0xFF, 0x79, 0xFD, 0x1B, 0x14, 0xD1, - 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, - 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 - }; + // Set default HID input report (everything zero`d) + UCHAR DefaultHidReport[DS4_REPORT_SIZE] = + { + 0x01, 0x82, 0x7F, 0x7E, 0x80, 0x08, 0x00, 0x58, + 0x00, 0x00, 0xFD, 0x63, 0x06, 0x03, 0x00, 0xFE, + 0xFF, 0xFC, 0xFF, 0x79, 0xFD, 0x1B, 0x14, 0xD1, + 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 + }; - // Initialize HID reports to defaults - RtlCopyBytes(this->Report, DefaultHidReport, DS4_REPORT_SIZE); - RtlZeroMemory(&this->OutputReport, sizeof(DS4_OUTPUT_REPORT)); + // Initialize HID reports to defaults + RtlCopyBytes(this->Report, DefaultHidReport, DS4_REPORT_SIZE); + RtlZeroMemory(&this->OutputReport, sizeof(DS4_OUTPUT_REPORT)); - // Start pending IRP queue flush timer - WdfTimerStart(this->PendingUsbInRequestsTimer, DS4_QUEUE_FLUSH_PERIOD); + // Start pending IRP queue flush timer + WdfTimerStart(this->PendingUsbInRequestsTimer, DS4_QUEUE_FLUSH_PERIOD); - return STATUS_SUCCESS; + return STATUS_SUCCESS; } NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::InitContext() { - NTSTATUS status; + NTSTATUS status; - // Initialize periodic timer - WDF_TIMER_CONFIG timerConfig; - WDF_TIMER_CONFIG_INIT_PERIODIC( - &timerConfig, - PendingUsbRequestsTimerFunc, - DS4_QUEUE_FLUSH_PERIOD - ); + // Initialize periodic timer + WDF_TIMER_CONFIG timerConfig; + WDF_TIMER_CONFIG_INIT_PERIODIC( + &timerConfig, + PendingUsbRequestsTimerFunc, + DS4_QUEUE_FLUSH_PERIOD + ); - // Timer object attributes - WDF_OBJECT_ATTRIBUTES timerAttribs; - WDF_OBJECT_ATTRIBUTES_INIT(&timerAttribs); + // Timer object attributes + WDF_OBJECT_ATTRIBUTES timerAttribs; + WDF_OBJECT_ATTRIBUTES_INIT(&timerAttribs); - // PDO is parent - timerAttribs.ParentObject = this->PdoDevice; + // PDO is parent + timerAttribs.ParentObject = this->PdoDevice; - // Create timer - status = WdfTimerCreate( - &timerConfig, - &timerAttribs, - &this->PendingUsbInRequestsTimer - ); - if (!NT_SUCCESS(status)) - { - TraceEvents(TRACE_LEVEL_ERROR, - TRACE_DS4, - "WdfTimerCreate failed with status %!STATUS!", - status); - return status; - } + // Create timer + status = WdfTimerCreate( + &timerConfig, + &timerAttribs, + &this->PendingUsbInRequestsTimer + ); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "WdfTimerCreate failed with status %!STATUS!", + status); + return status; + } - // Load/generate MAC address + // Load/generate MAC address - // TODO: tidy up this region + // TODO: tidy up this region - WDFKEY keyParams, keyTargets, keyDS, keySerial; - UNICODE_STRING keyName, valueName; + WDFKEY keyParams, keyTargets, keyDS, keySerial; + UNICODE_STRING keyName, valueName; - status = WdfDriverOpenParametersRegistryKey( - WdfGetDriver(), - STANDARD_RIGHTS_ALL, - WDF_NO_OBJECT_ATTRIBUTES, - &keyParams - ); - if (!NT_SUCCESS(status)) - { - TraceEvents(TRACE_LEVEL_ERROR, - TRACE_DS4, - "WdfDriverOpenParametersRegistryKey failed with status %!STATUS!", - status); - return status; - } + status = WdfDriverOpenParametersRegistryKey( + WdfGetDriver(), + STANDARD_RIGHTS_ALL, + WDF_NO_OBJECT_ATTRIBUTES, + &keyParams + ); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "WdfDriverOpenParametersRegistryKey failed with status %!STATUS!", + status); + return status; + } - RtlUnicodeStringInit(&keyName, L"Targets"); + RtlUnicodeStringInit(&keyName, L"Targets"); - status = WdfRegistryCreateKey( - keyParams, - &keyName, - KEY_ALL_ACCESS, - REG_OPTION_NON_VOLATILE, - NULL, - WDF_NO_OBJECT_ATTRIBUTES, - &keyTargets - ); - if (!NT_SUCCESS(status)) - { - TraceEvents(TRACE_LEVEL_ERROR, - TRACE_DS4, - "WdfRegistryCreateKey failed with status %!STATUS!", - status); - return status; - } + status = WdfRegistryCreateKey( + keyParams, + &keyName, + KEY_ALL_ACCESS, + REG_OPTION_NON_VOLATILE, + NULL, + WDF_NO_OBJECT_ATTRIBUTES, + &keyTargets + ); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "WdfRegistryCreateKey failed with status %!STATUS!", + status); + return status; + } - RtlUnicodeStringInit(&keyName, L"DualShock"); + RtlUnicodeStringInit(&keyName, L"DualShock"); - status = WdfRegistryCreateKey( - keyTargets, - &keyName, - KEY_ALL_ACCESS, - REG_OPTION_NON_VOLATILE, - NULL, - WDF_NO_OBJECT_ATTRIBUTES, - &keyDS - ); - if (!NT_SUCCESS(status)) - { - TraceEvents(TRACE_LEVEL_ERROR, - TRACE_DS4, - "WdfRegistryCreateKey failed with status %!STATUS!", - status); - return status; - } + status = WdfRegistryCreateKey( + keyTargets, + &keyName, + KEY_ALL_ACCESS, + REG_OPTION_NON_VOLATILE, + NULL, + WDF_NO_OBJECT_ATTRIBUTES, + &keyDS + ); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "WdfRegistryCreateKey failed with status %!STATUS!", + status); + return status; + } - DECLARE_UNICODE_STRING_SIZE(serialPath, 4); - RtlUnicodeStringPrintf(&serialPath, L"%04d", this->SerialNo); + DECLARE_UNICODE_STRING_SIZE(serialPath, 4); + RtlUnicodeStringPrintf(&serialPath, L"%04d", this->SerialNo); - status = WdfRegistryCreateKey( - keyDS, - &serialPath, - KEY_ALL_ACCESS, - REG_OPTION_NON_VOLATILE, - NULL, - WDF_NO_OBJECT_ATTRIBUTES, - &keySerial - ); - if (!NT_SUCCESS(status)) - { - TraceEvents(TRACE_LEVEL_ERROR, - TRACE_DS4, - "WdfRegistryCreateKey failed with status %!STATUS!", - status); - return status; - } + status = WdfRegistryCreateKey( + keyDS, + &serialPath, + KEY_ALL_ACCESS, + REG_OPTION_NON_VOLATILE, + NULL, + WDF_NO_OBJECT_ATTRIBUTES, + &keySerial + ); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "WdfRegistryCreateKey failed with status %!STATUS!", + status); + return status; + } - RtlUnicodeStringInit(&valueName, L"TargetMacAddress"); + RtlUnicodeStringInit(&valueName, L"TargetMacAddress"); - status = WdfRegistryQueryValue( - keySerial, - &valueName, - sizeof(MAC_ADDRESS), - &this->TargetMacAddress, - NULL, - NULL - ); + status = WdfRegistryQueryValue( + keySerial, + &valueName, + sizeof(MAC_ADDRESS), + &this->TargetMacAddress, + NULL, + NULL + ); - TraceEvents(TRACE_LEVEL_INFORMATION, - TRACE_DS4, - "MAC-Address: %02X:%02X:%02X:%02X:%02X:%02X\n", - this->TargetMacAddress.Vendor0, - this->TargetMacAddress.Vendor1, - this->TargetMacAddress.Vendor2, - this->TargetMacAddress.Nic0, - this->TargetMacAddress.Nic1, - this->TargetMacAddress.Nic2); + TraceEvents(TRACE_LEVEL_INFORMATION, + TRACE_DS4, + "MAC-Address: %02X:%02X:%02X:%02X:%02X:%02X\n", + this->TargetMacAddress.Vendor0, + this->TargetMacAddress.Vendor1, + this->TargetMacAddress.Vendor2, + this->TargetMacAddress.Nic0, + this->TargetMacAddress.Nic1, + this->TargetMacAddress.Nic2); - if (status == STATUS_OBJECT_NAME_NOT_FOUND) - { - GenerateRandomMacAddress(&this->TargetMacAddress); + if (status == STATUS_OBJECT_NAME_NOT_FOUND) + { + GenerateRandomMacAddress(&this->TargetMacAddress); - status = WdfRegistryAssignValue( - keySerial, - &valueName, - REG_BINARY, - sizeof(MAC_ADDRESS), - static_cast(&this->TargetMacAddress) - ); - if (!NT_SUCCESS(status)) - { - TraceEvents(TRACE_LEVEL_ERROR, - TRACE_DS4, - "WdfRegistryAssignValue failed with status %!STATUS!", - status); - return status; - } - } - else if (!NT_SUCCESS(status)) - { - TraceEvents(TRACE_LEVEL_ERROR, - TRACE_DS4, - "WdfRegistryQueryValue failed with status %!STATUS!", - status); - return status; - } + status = WdfRegistryAssignValue( + keySerial, + &valueName, + REG_BINARY, + sizeof(MAC_ADDRESS), + static_cast(&this->TargetMacAddress) + ); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "WdfRegistryAssignValue failed with status %!STATUS!", + status); + return status; + } + } + else if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "WdfRegistryQueryValue failed with status %!STATUS!", + status); + return status; + } - WdfRegistryClose(keySerial); - WdfRegistryClose(keyDS); - WdfRegistryClose(keyTargets); - WdfRegistryClose(keyParams); + WdfRegistryClose(keySerial); + WdfRegistryClose(keyDS); + WdfRegistryClose(keyTargets); + WdfRegistryClose(keyParams); - return STATUS_SUCCESS; + return STATUS_SUCCESS; } VOID ViGEm::Bus::Targets::EmulationTargetDS4::GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length) { - UCHAR Ds4DescriptorData[DS4_DESCRIPTOR_SIZE] = - { - 0x09, // bLength - 0x02, // bDescriptorType (Configuration) - 0x29, 0x00, // wTotalLength 41 - 0x01, // bNumInterfaces 1 - 0x01, // bConfigurationValue - 0x00, // iConfiguration (String Index) - 0xC0, // bmAttributes Self Powered - 0xFA, // bMaxPower 500mA + UCHAR Ds4DescriptorData[DS4_DESCRIPTOR_SIZE] = + { + 0x09, // bLength + 0x02, // bDescriptorType (Configuration) + 0x29, 0x00, // wTotalLength 41 + 0x01, // bNumInterfaces 1 + 0x01, // bConfigurationValue + 0x00, // iConfiguration (String Index) + 0xC0, // bmAttributes Self Powered + 0xFA, // bMaxPower 500mA - 0x09, // bLength - 0x04, // bDescriptorType (Interface) - 0x00, // bInterfaceNumber 0 - 0x00, // bAlternateSetting - 0x02, // bNumEndpoints 2 - 0x03, // bInterfaceClass - 0x00, // bInterfaceSubClass - 0x00, // bInterfaceProtocol - 0x00, // iInterface (String Index) + 0x09, // bLength + 0x04, // bDescriptorType (Interface) + 0x00, // bInterfaceNumber 0 + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints 2 + 0x03, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0x00, // iInterface (String Index) - 0x09, // bLength - 0x21, // bDescriptorType (HID) - 0x11, 0x01, // bcdHID 1.11 - 0x00, // bCountryCode - 0x01, // bNumDescriptors - 0x22, // bDescriptorType[0] (HID) - 0xD3, 0x01, // wDescriptorLength[0] 467 + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0xD3, 0x01, // wDescriptorLength[0] 467 - 0x07, // bLength - 0x05, // bDescriptorType (Endpoint) - 0x84, // bEndpointAddress (IN/D2H) - 0x03, // bmAttributes (Interrupt) - 0x40, 0x00, // wMaxPacketSize 64 - 0x05, // bInterval 5 (unit depends on device speed) + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x84, // bEndpointAddress (IN/D2H) + 0x03, // bmAttributes (Interrupt) + 0x40, 0x00, // wMaxPacketSize 64 + 0x05, // bInterval 5 (unit depends on device speed) - 0x07, // bLength - 0x05, // bDescriptorType (Endpoint) - 0x03, // bEndpointAddress (OUT/H2D) - 0x03, // bmAttributes (Interrupt) - 0x40, 0x00, // wMaxPacketSize 64 - 0x05, // bInterval 5 (unit depends on device speed) + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x03, // bEndpointAddress (OUT/H2D) + 0x03, // bmAttributes (Interrupt) + 0x40, 0x00, // wMaxPacketSize 64 + 0x05, // bInterval 5 (unit depends on device speed) - // 41 bytes + // 41 bytes - // best guess: USB Standard Descriptor - }; + // best guess: USB Standard Descriptor + }; - RtlCopyBytes(Buffer, Ds4DescriptorData, Length); + RtlCopyBytes(Buffer, Ds4DescriptorData, Length); } VOID ViGEm::Bus::Targets::EmulationTargetDS4::GetDeviceDescriptorType(PUSB_DEVICE_DESCRIPTOR pDescriptor) { - pDescriptor->bLength = 0x12; - pDescriptor->bDescriptorType = USB_DEVICE_DESCRIPTOR_TYPE; - pDescriptor->bcdUSB = 0x0200; // USB v2.0 - pDescriptor->bDeviceClass = 0x00; // per Interface - pDescriptor->bDeviceSubClass = 0x00; - pDescriptor->bDeviceProtocol = 0x00; - pDescriptor->bMaxPacketSize0 = 0x40; - pDescriptor->idVendor = this->VendorId; - pDescriptor->idProduct = this->ProductId; - pDescriptor->bcdDevice = 0x0100; - pDescriptor->iManufacturer = 0x01; - pDescriptor->iProduct = 0x02; - pDescriptor->iSerialNumber = 0x00; - pDescriptor->bNumConfigurations = 0x01; + pDescriptor->bLength = 0x12; + pDescriptor->bDescriptorType = USB_DEVICE_DESCRIPTOR_TYPE; + pDescriptor->bcdUSB = 0x0200; // USB v2.0 + pDescriptor->bDeviceClass = 0x00; // per Interface + pDescriptor->bDeviceSubClass = 0x00; + pDescriptor->bDeviceProtocol = 0x00; + pDescriptor->bMaxPacketSize0 = 0x40; + pDescriptor->idVendor = this->VendorId; + pDescriptor->idProduct = this->ProductId; + pDescriptor->bcdDevice = 0x0100; + pDescriptor->iManufacturer = 0x01; + pDescriptor->iProduct = 0x02; + pDescriptor->iSerialNumber = 0x00; + pDescriptor->bNumConfigurations = 0x01; } NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::SelectConfiguration(PURB Urb) { - if (Urb->UrbHeader.Length < DS4_CONFIGURATION_SIZE) - { - TraceEvents(TRACE_LEVEL_WARNING, - TRACE_USBPDO, - ">> >> >> URB_FUNCTION_SELECT_CONFIGURATION: Invalid ConfigurationDescriptor"); - return STATUS_INVALID_PARAMETER; - } - - PUSBD_INTERFACE_INFORMATION pInfo = &Urb->UrbSelectConfiguration.Interface; - - TraceEvents(TRACE_LEVEL_VERBOSE, - TRACE_DS4, - ">> >> >> URB_FUNCTION_SELECT_CONFIGURATION: Length %d, Interface %d, Alternate %d, Pipes %d", - (int)pInfo->Length, - (int)pInfo->InterfaceNumber, - (int)pInfo->AlternateSetting, - pInfo->NumberOfPipes); + if (Urb->UrbHeader.Length < DS4_CONFIGURATION_SIZE) + { + TraceEvents(TRACE_LEVEL_WARNING, + TRACE_USBPDO, + ">> >> >> URB_FUNCTION_SELECT_CONFIGURATION: Invalid ConfigurationDescriptor"); + return STATUS_INVALID_PARAMETER; + } - pInfo->Class = 0x03; // HID - pInfo->SubClass = 0x00; - pInfo->Protocol = 0x00; + PUSBD_INTERFACE_INFORMATION pInfo = &Urb->UrbSelectConfiguration.Interface; - pInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)0xFFFF0000; + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_DS4, + ">> >> >> URB_FUNCTION_SELECT_CONFIGURATION: Length %d, Interface %d, Alternate %d, Pipes %d", + (int)pInfo->Length, + (int)pInfo->InterfaceNumber, + (int)pInfo->AlternateSetting, + pInfo->NumberOfPipes); - pInfo->Pipes[0].MaximumTransferSize = 0x00400000; - pInfo->Pipes[0].MaximumPacketSize = 0x40; - pInfo->Pipes[0].EndpointAddress = 0x84; - pInfo->Pipes[0].Interval = 0x05; - pInfo->Pipes[0].PipeType = (USBD_PIPE_TYPE)0x03; - pInfo->Pipes[0].PipeHandle = (USBD_PIPE_HANDLE)0xFFFF0084; - pInfo->Pipes[0].PipeFlags = 0x00; + pInfo->Class = 0x03; // HID + pInfo->SubClass = 0x00; + pInfo->Protocol = 0x00; - pInfo->Pipes[1].MaximumTransferSize = 0x00400000; - pInfo->Pipes[1].MaximumPacketSize = 0x40; - pInfo->Pipes[1].EndpointAddress = 0x03; - pInfo->Pipes[1].Interval = 0x05; - pInfo->Pipes[1].PipeType = (USBD_PIPE_TYPE)0x03; - pInfo->Pipes[1].PipeHandle = (USBD_PIPE_HANDLE)0xFFFF0003; - pInfo->Pipes[1].PipeFlags = 0x00; + pInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)0xFFFF0000; - return STATUS_SUCCESS; + pInfo->Pipes[0].MaximumTransferSize = 0x00400000; + pInfo->Pipes[0].MaximumPacketSize = 0x40; + pInfo->Pipes[0].EndpointAddress = 0x84; + pInfo->Pipes[0].Interval = 0x05; + pInfo->Pipes[0].PipeType = (USBD_PIPE_TYPE)0x03; + pInfo->Pipes[0].PipeHandle = (USBD_PIPE_HANDLE)0xFFFF0084; + pInfo->Pipes[0].PipeFlags = 0x00; + + pInfo->Pipes[1].MaximumTransferSize = 0x00400000; + pInfo->Pipes[1].MaximumPacketSize = 0x40; + pInfo->Pipes[1].EndpointAddress = 0x03; + pInfo->Pipes[1].Interval = 0x05; + pInfo->Pipes[1].PipeType = (USBD_PIPE_TYPE)0x03; + pInfo->Pipes[1].PipeHandle = (USBD_PIPE_HANDLE)0xFFFF0003; + pInfo->Pipes[1].PipeFlags = 0x00; + + return STATUS_SUCCESS; } void ViGEm::Bus::Targets::EmulationTargetDS4::AbortPipe() { - // Higher driver shutting down, emptying PDOs queues - WdfTimerStop(this->PendingUsbInRequestsTimer, TRUE); + // Higher driver shutting down, emptying PDOs queues + WdfTimerStop(this->PendingUsbInRequestsTimer, TRUE); } NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::UsbClassInterface(PURB Urb) { - struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST* pRequest = &Urb->UrbControlVendorClassRequest; + struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST* pRequest = &Urb->UrbControlVendorClassRequest; - TraceEvents(TRACE_LEVEL_VERBOSE, - TRACE_USBPDO, - ">> >> >> URB_FUNCTION_CLASS_INTERFACE"); - TraceEvents(TRACE_LEVEL_VERBOSE, - TRACE_USBPDO, - ">> >> >> TransferFlags = 0x%X, Request = 0x%X, Value = 0x%X, Index = 0x%X, BufLen = %d", - pRequest->TransferFlags, - pRequest->Request, - pRequest->Value, - pRequest->Index, - pRequest->TransferBufferLength); + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_USBPDO, + ">> >> >> URB_FUNCTION_CLASS_INTERFACE"); + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_USBPDO, + ">> >> >> TransferFlags = 0x%X, Request = 0x%X, Value = 0x%X, Index = 0x%X, BufLen = %d", + pRequest->TransferFlags, + pRequest->Request, + pRequest->Value, + pRequest->Index, + pRequest->TransferBufferLength); switch (pRequest->Request) { case HID_REQUEST_GET_REPORT: { - UCHAR reportId = hid_get_report_id(pRequest); - UCHAR reportType = hid_get_report_type(pRequest); + UCHAR reportId = hid_get_report_id(pRequest); + UCHAR reportType = hid_get_report_type(pRequest); - TraceEvents(TRACE_LEVEL_VERBOSE, - TRACE_USBPDO, - ">> >> >> >> GET_REPORT(%d): %d", - reportType, reportId); + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_USBPDO, + ">> >> >> >> GET_REPORT(%d): %d", + reportType, reportId); - switch (reportType) - { - case HID_REPORT_TYPE_FEATURE: - { - switch (reportId) - { - case HID_REPORT_ID_0: - { - // Source: http://eleccelerator.com/wiki/index.php?title=DualShock_4#Class_Requests - UCHAR Response[] = - { - 0xA3, 0x41, 0x75, 0x67, 0x20, 0x20, 0x33, 0x20, - 0x32, 0x30, 0x31, 0x33, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x30, 0x37, 0x3A, 0x30, 0x31, 0x3A, 0x31, - 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x31, 0x03, 0x00, 0x00, - 0x00, 0x49, 0x00, 0x05, 0x00, 0x00, 0x80, 0x03, - 0x00 - }; + switch (reportType) + { + case HID_REPORT_TYPE_FEATURE: + { + switch (reportId) + { + case HID_REPORT_ID_0: + { + // Source: http://eleccelerator.com/wiki/index.php?title=DualShock_4#Class_Requests + UCHAR Response[] = + { + 0xA3, 0x41, 0x75, 0x67, 0x20, 0x20, 0x33, 0x20, + 0x32, 0x30, 0x31, 0x33, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x37, 0x3A, 0x30, 0x31, 0x3A, 0x31, + 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x31, 0x03, 0x00, 0x00, + 0x00, 0x49, 0x00, 0x05, 0x00, 0x00, 0x80, 0x03, + 0x00 + }; - pRequest->TransferBufferLength = ARRAYSIZE(Response); - RtlCopyBytes(pRequest->TransferBuffer, Response, ARRAYSIZE(Response)); + pRequest->TransferBufferLength = ARRAYSIZE(Response); + RtlCopyBytes(pRequest->TransferBuffer, Response, ARRAYSIZE(Response)); - break; - } - case HID_REPORT_ID_1: - { - // Source: http://eleccelerator.com/wiki/index.php?title=DualShock_4#Class_Requests - UCHAR Response[] = - { - 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, - 0x22, 0x7B, 0xDD, 0xB2, 0x22, 0x47, 0xDD, 0xBD, - 0x22, 0x43, 0xDD, 0x1C, 0x02, 0x1C, 0x02, 0x7F, - 0x1E, 0x2E, 0xDF, 0x60, 0x1F, 0x4C, 0xE0, 0x3A, - 0x1D, 0xC6, 0xDE, 0x08, 0x00 - }; + break; + } + case HID_REPORT_ID_1: + { + // Source: http://eleccelerator.com/wiki/index.php?title=DualShock_4#Class_Requests + UCHAR Response[] = + { + 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, + 0x22, 0x7B, 0xDD, 0xB2, 0x22, 0x47, 0xDD, 0xBD, + 0x22, 0x43, 0xDD, 0x1C, 0x02, 0x1C, 0x02, 0x7F, + 0x1E, 0x2E, 0xDF, 0x60, 0x1F, 0x4C, 0xE0, 0x3A, + 0x1D, 0xC6, 0xDE, 0x08, 0x00 + }; - pRequest->TransferBufferLength = ARRAYSIZE(Response); - RtlCopyBytes(pRequest->TransferBuffer, Response, ARRAYSIZE(Response)); + pRequest->TransferBufferLength = ARRAYSIZE(Response); + RtlCopyBytes(pRequest->TransferBuffer, Response, ARRAYSIZE(Response)); - break; - } - case HID_REPORT_MAC_ADDRESSES_ID: - { - // Source: http://eleccelerator.com/wiki/index.php?title=DualShock_4#Class_Requests - UCHAR Response[] = - { - 0x12, 0x8B, 0x09, 0x07, 0x6D, 0x66, 0x1C, 0x08, - 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; + break; + } + case HID_REPORT_MAC_ADDRESSES_ID: + { + // Source: http://eleccelerator.com/wiki/index.php?title=DualShock_4#Class_Requests + UCHAR Response[] = + { + 0x12, 0x8B, 0x09, 0x07, 0x6D, 0x66, 0x1C, 0x08, + 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; - // Insert (auto-generated) target MAC address into response - RtlCopyBytes(Response + 1, &this->TargetMacAddress, sizeof(MAC_ADDRESS)); - // Adjust byte order - ReverseByteArray(Response + 1, sizeof(MAC_ADDRESS)); + // Insert (auto-generated) target MAC address into response + RtlCopyBytes(Response + 1, &this->TargetMacAddress, sizeof(MAC_ADDRESS)); + // Adjust byte order + ReverseByteArray(Response + 1, sizeof(MAC_ADDRESS)); - // Insert (auto-generated) host MAC address into response - RtlCopyBytes(Response + 10, &this->HostMacAddress, sizeof(MAC_ADDRESS)); - // Adjust byte order - ReverseByteArray(Response + 10, sizeof(MAC_ADDRESS)); + // Insert (auto-generated) host MAC address into response + RtlCopyBytes(Response + 10, &this->HostMacAddress, sizeof(MAC_ADDRESS)); + // Adjust byte order + ReverseByteArray(Response + 10, sizeof(MAC_ADDRESS)); - pRequest->TransferBufferLength = ARRAYSIZE(Response); - RtlCopyBytes(pRequest->TransferBuffer, Response, ARRAYSIZE(Response)); + pRequest->TransferBufferLength = ARRAYSIZE(Response); + RtlCopyBytes(pRequest->TransferBuffer, Response, ARRAYSIZE(Response)); - break; - } - default: - break; - } - break; - } - default: - break; - } + break; + } + default: + break; + } + break; + } + default: + break; + } - break; + break; } case HID_REQUEST_SET_REPORT: { - UCHAR reportId = hid_get_report_id(pRequest); - UCHAR reportType = hid_get_report_type(pRequest); + UCHAR reportId = hid_get_report_id(pRequest); + UCHAR reportType = hid_get_report_type(pRequest); - TraceEvents(TRACE_LEVEL_VERBOSE, - TRACE_USBPDO, - ">> >> >> >> SET_REPORT(%d): %d", - reportType, reportId); + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_USBPDO, + ">> >> >> >> SET_REPORT(%d): %d", + reportType, reportId); - switch (reportType) - { - case HID_REPORT_TYPE_FEATURE: - { - switch (reportId) - { - case HID_REPORT_ID_3: - { - // Source: http://eleccelerator.com/wiki/index.php?title=DualShock_4#Class_Requests - UCHAR Response[] = - { - 0x13, 0xAC, 0x9E, 0x17, 0x94, 0x05, 0xB0, 0x56, - 0xE8, 0x81, 0x38, 0x08, 0x06, 0x51, 0x41, 0xC0, - 0x7F, 0x12, 0xAA, 0xD9, 0x66, 0x3C, 0xCE - }; + switch (reportType) + { + case HID_REPORT_TYPE_FEATURE: + { + switch (reportId) + { + case HID_REPORT_ID_3: + { + // Source: http://eleccelerator.com/wiki/index.php?title=DualShock_4#Class_Requests + UCHAR Response[] = + { + 0x13, 0xAC, 0x9E, 0x17, 0x94, 0x05, 0xB0, 0x56, + 0xE8, 0x81, 0x38, 0x08, 0x06, 0x51, 0x41, 0xC0, + 0x7F, 0x12, 0xAA, 0xD9, 0x66, 0x3C, 0xCE + }; - pRequest->TransferBufferLength = ARRAYSIZE(Response); - RtlCopyBytes(pRequest->TransferBuffer, Response, ARRAYSIZE(Response)); + pRequest->TransferBufferLength = ARRAYSIZE(Response); + RtlCopyBytes(pRequest->TransferBuffer, Response, ARRAYSIZE(Response)); - break; - } - case HID_REPORT_ID_4: - { - // Source: http://eleccelerator.com/wiki/index.php?title=DualShock_4#Class_Requests - UCHAR Response[] = - { - 0x14, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00 - }; + break; + } + case HID_REPORT_ID_4: + { + // Source: http://eleccelerator.com/wiki/index.php?title=DualShock_4#Class_Requests + UCHAR Response[] = + { + 0x14, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 + }; - pRequest->TransferBufferLength = ARRAYSIZE(Response); - RtlCopyBytes(pRequest->TransferBuffer, Response, ARRAYSIZE(Response)); + pRequest->TransferBufferLength = ARRAYSIZE(Response); + RtlCopyBytes(pRequest->TransferBuffer, Response, ARRAYSIZE(Response)); - break; - } - default: - break; - } - break; - } - default: - break; - } + break; + } + default: + break; + } + break; + } + default: + break; + } - break; + break; } default: - break; + break; } - return STATUS_SUCCESS; + return STATUS_SUCCESS; } NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::UsbGetDescriptorFromInterface(PURB Urb) { - NTSTATUS status = STATUS_INVALID_PARAMETER; - UCHAR Ds4HidReportDescriptor[] = - { - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x05, // Usage (Game Pad) - 0xA1, 0x01, // Collection (Application) - 0x85, 0x01, // Report ID (1) - 0x09, 0x30, // Usage (X) - 0x09, 0x31, // Usage (Y) - 0x09, 0x32, // Usage (Z) - 0x09, 0x35, // Usage (Rz) - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x75, 0x08, // Report Size (8) - 0x95, 0x04, // Report Count (4) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x09, 0x39, // Usage (Hat switch) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x07, // Logical Maximum (7) - 0x35, 0x00, // Physical Minimum (0) - 0x46, 0x3B, 0x01, // Physical Maximum (315) - 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) - 0x75, 0x04, // Report Size (4) - 0x95, 0x01, // Report Count (1) - 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) - 0x65, 0x00, // Unit (None) - 0x05, 0x09, // Usage Page (Button) - 0x19, 0x01, // Usage Minimum (0x01) - 0x29, 0x0E, // Usage Maximum (0x0E) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x75, 0x01, // Report Size (1) - 0x95, 0x0E, // Report Count (14) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) - 0x09, 0x20, // Usage (0x20) - 0x75, 0x06, // Report Size (6) - 0x95, 0x01, // Report Count (1) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x7F, // Logical Maximum (127) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x33, // Usage (Rx) - 0x09, 0x34, // Usage (Ry) - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x75, 0x08, // Report Size (8) - 0x95, 0x02, // Report Count (2) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) - 0x09, 0x21, // Usage (0x21) - 0x95, 0x36, // Report Count (54) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x85, 0x05, // Report ID (5) - 0x09, 0x22, // Usage (0x22) - 0x95, 0x1F, // Report Count (31) - 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x04, // Report ID (4) - 0x09, 0x23, // Usage (0x23) - 0x95, 0x24, // Report Count (36) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x02, // Report ID (2) - 0x09, 0x24, // Usage (0x24) - 0x95, 0x24, // Report Count (36) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x08, // Report ID (8) - 0x09, 0x25, // Usage (0x25) - 0x95, 0x03, // Report Count (3) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x10, // Report ID (16) - 0x09, 0x26, // Usage (0x26) - 0x95, 0x04, // Report Count (4) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x11, // Report ID (17) - 0x09, 0x27, // Usage (0x27) - 0x95, 0x02, // Report Count (2) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x12, // Report ID (18) - 0x06, 0x02, 0xFF, // Usage Page (Vendor Defined 0xFF02) - 0x09, 0x21, // Usage (0x21) - 0x95, 0x0F, // Report Count (15) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x13, // Report ID (19) - 0x09, 0x22, // Usage (0x22) - 0x95, 0x16, // Report Count (22) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x14, // Report ID (20) - 0x06, 0x05, 0xFF, // Usage Page (Vendor Defined 0xFF05) - 0x09, 0x20, // Usage (0x20) - 0x95, 0x10, // Report Count (16) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x15, // Report ID (21) - 0x09, 0x21, // Usage (0x21) - 0x95, 0x2C, // Report Count (44) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x06, 0x80, 0xFF, // Usage Page (Vendor Defined 0xFF80) - 0x85, 0x80, // Report ID (128) - 0x09, 0x20, // Usage (0x20) - 0x95, 0x06, // Report Count (6) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x81, // Report ID (129) - 0x09, 0x21, // Usage (0x21) - 0x95, 0x06, // Report Count (6) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x82, // Report ID (130) - 0x09, 0x22, // Usage (0x22) - 0x95, 0x05, // Report Count (5) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x83, // Report ID (131) - 0x09, 0x23, // Usage (0x23) - 0x95, 0x01, // Report Count (1) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x84, // Report ID (132) - 0x09, 0x24, // Usage (0x24) - 0x95, 0x04, // Report Count (4) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x85, // Report ID (133) - 0x09, 0x25, // Usage (0x25) - 0x95, 0x06, // Report Count (6) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x86, // Report ID (134) - 0x09, 0x26, // Usage (0x26) - 0x95, 0x06, // Report Count (6) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x87, // Report ID (135) - 0x09, 0x27, // Usage (0x27) - 0x95, 0x23, // Report Count (35) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x88, // Report ID (136) - 0x09, 0x28, // Usage (0x28) - 0x95, 0x22, // Report Count (34) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x89, // Report ID (137) - 0x09, 0x29, // Usage (0x29) - 0x95, 0x02, // Report Count (2) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x90, // Report ID (144) - 0x09, 0x30, // Usage (0x30) - 0x95, 0x05, // Report Count (5) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x91, // Report ID (145) - 0x09, 0x31, // Usage (0x31) - 0x95, 0x03, // Report Count (3) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x92, // Report ID (146) - 0x09, 0x32, // Usage (0x32) - 0x95, 0x03, // Report Count (3) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0x93, // Report ID (147) - 0x09, 0x33, // Usage (0x33) - 0x95, 0x0C, // Report Count (12) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xA0, // Report ID (160) - 0x09, 0x40, // Usage (0x40) - 0x95, 0x06, // Report Count (6) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xA1, // Report ID (161) - 0x09, 0x41, // Usage (0x41) - 0x95, 0x01, // Report Count (1) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xA2, // Report ID (162) - 0x09, 0x42, // Usage (0x42) - 0x95, 0x01, // Report Count (1) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xA3, // Report ID (163) - 0x09, 0x43, // Usage (0x43) - 0x95, 0x30, // Report Count (48) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xA4, // Report ID (164) - 0x09, 0x44, // Usage (0x44) - 0x95, 0x0D, // Report Count (13) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xA5, // Report ID (165) - 0x09, 0x45, // Usage (0x45) - 0x95, 0x15, // Report Count (21) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xA6, // Report ID (166) - 0x09, 0x46, // Usage (0x46) - 0x95, 0x15, // Report Count (21) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xF0, // Report ID (240) - 0x09, 0x47, // Usage (0x47) - 0x95, 0x3F, // Report Count (63) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xF1, // Report ID (241) - 0x09, 0x48, // Usage (0x48) - 0x95, 0x3F, // Report Count (63) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xF2, // Report ID (242) - 0x09, 0x49, // Usage (0x49) - 0x95, 0x0F, // Report Count (15) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xA7, // Report ID (167) - 0x09, 0x4A, // Usage (0x4A) - 0x95, 0x01, // Report Count (1) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xA8, // Report ID (168) - 0x09, 0x4B, // Usage (0x4B) - 0x95, 0x01, // Report Count (1) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xA9, // Report ID (169) - 0x09, 0x4C, // Usage (0x4C) - 0x95, 0x08, // Report Count (8) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xAA, // Report ID (170) - 0x09, 0x4E, // Usage (0x4E) - 0x95, 0x01, // Report Count (1) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xAB, // Report ID (171) - 0x09, 0x4F, // Usage (0x4F) - 0x95, 0x39, // Report Count (57) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xAC, // Report ID (172) - 0x09, 0x50, // Usage (0x50) - 0x95, 0x39, // Report Count (57) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xAD, // Report ID (173) - 0x09, 0x51, // Usage (0x51) - 0x95, 0x0B, // Report Count (11) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xAE, // Report ID (174) - 0x09, 0x52, // Usage (0x52) - 0x95, 0x01, // Report Count (1) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xAF, // Report ID (175) - 0x09, 0x53, // Usage (0x53) - 0x95, 0x02, // Report Count (2) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x85, 0xB0, // Report ID (176) - 0x09, 0x54, // Usage (0x54) - 0x95, 0x3F, // Report Count (63) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - }; + NTSTATUS status = STATUS_INVALID_PARAMETER; + UCHAR Ds4HidReportDescriptor[] = + { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x05, // Usage (Game Pad) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x01, // Report ID (1) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x35, // Usage (Rz) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x75, 0x08, // Report Size (8) + 0x95, 0x04, // Report Count (4) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x39, // Usage (Hat switch) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x07, // Logical Maximum (7) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) + 0x65, 0x00, // Unit (None) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0E, // Usage Maximum (0x0E) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0E, // Report Count (14) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x09, 0x20, // Usage (0x20) + 0x75, 0x06, // Report Size (6) + 0x95, 0x01, // Report Count (1) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x7F, // Logical Maximum (127) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x33, // Usage (Rx) + 0x09, 0x34, // Usage (Ry) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x75, 0x08, // Report Size (8) + 0x95, 0x02, // Report Count (2) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x09, 0x21, // Usage (0x21) + 0x95, 0x36, // Report Count (54) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x85, 0x05, // Report ID (5) + 0x09, 0x22, // Usage (0x22) + 0x95, 0x1F, // Report Count (31) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x04, // Report ID (4) + 0x09, 0x23, // Usage (0x23) + 0x95, 0x24, // Report Count (36) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x02, // Report ID (2) + 0x09, 0x24, // Usage (0x24) + 0x95, 0x24, // Report Count (36) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x08, // Report ID (8) + 0x09, 0x25, // Usage (0x25) + 0x95, 0x03, // Report Count (3) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x10, // Report ID (16) + 0x09, 0x26, // Usage (0x26) + 0x95, 0x04, // Report Count (4) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x11, // Report ID (17) + 0x09, 0x27, // Usage (0x27) + 0x95, 0x02, // Report Count (2) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x12, // Report ID (18) + 0x06, 0x02, 0xFF, // Usage Page (Vendor Defined 0xFF02) + 0x09, 0x21, // Usage (0x21) + 0x95, 0x0F, // Report Count (15) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x13, // Report ID (19) + 0x09, 0x22, // Usage (0x22) + 0x95, 0x16, // Report Count (22) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x14, // Report ID (20) + 0x06, 0x05, 0xFF, // Usage Page (Vendor Defined 0xFF05) + 0x09, 0x20, // Usage (0x20) + 0x95, 0x10, // Report Count (16) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x15, // Report ID (21) + 0x09, 0x21, // Usage (0x21) + 0x95, 0x2C, // Report Count (44) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x06, 0x80, 0xFF, // Usage Page (Vendor Defined 0xFF80) + 0x85, 0x80, // Report ID (128) + 0x09, 0x20, // Usage (0x20) + 0x95, 0x06, // Report Count (6) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x81, // Report ID (129) + 0x09, 0x21, // Usage (0x21) + 0x95, 0x06, // Report Count (6) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x82, // Report ID (130) + 0x09, 0x22, // Usage (0x22) + 0x95, 0x05, // Report Count (5) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x83, // Report ID (131) + 0x09, 0x23, // Usage (0x23) + 0x95, 0x01, // Report Count (1) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x84, // Report ID (132) + 0x09, 0x24, // Usage (0x24) + 0x95, 0x04, // Report Count (4) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x85, // Report ID (133) + 0x09, 0x25, // Usage (0x25) + 0x95, 0x06, // Report Count (6) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x86, // Report ID (134) + 0x09, 0x26, // Usage (0x26) + 0x95, 0x06, // Report Count (6) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x87, // Report ID (135) + 0x09, 0x27, // Usage (0x27) + 0x95, 0x23, // Report Count (35) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x88, // Report ID (136) + 0x09, 0x28, // Usage (0x28) + 0x95, 0x22, // Report Count (34) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x89, // Report ID (137) + 0x09, 0x29, // Usage (0x29) + 0x95, 0x02, // Report Count (2) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x90, // Report ID (144) + 0x09, 0x30, // Usage (0x30) + 0x95, 0x05, // Report Count (5) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x91, // Report ID (145) + 0x09, 0x31, // Usage (0x31) + 0x95, 0x03, // Report Count (3) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x92, // Report ID (146) + 0x09, 0x32, // Usage (0x32) + 0x95, 0x03, // Report Count (3) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x93, // Report ID (147) + 0x09, 0x33, // Usage (0x33) + 0x95, 0x0C, // Report Count (12) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA0, // Report ID (160) + 0x09, 0x40, // Usage (0x40) + 0x95, 0x06, // Report Count (6) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA1, // Report ID (161) + 0x09, 0x41, // Usage (0x41) + 0x95, 0x01, // Report Count (1) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA2, // Report ID (162) + 0x09, 0x42, // Usage (0x42) + 0x95, 0x01, // Report Count (1) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA3, // Report ID (163) + 0x09, 0x43, // Usage (0x43) + 0x95, 0x30, // Report Count (48) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA4, // Report ID (164) + 0x09, 0x44, // Usage (0x44) + 0x95, 0x0D, // Report Count (13) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA5, // Report ID (165) + 0x09, 0x45, // Usage (0x45) + 0x95, 0x15, // Report Count (21) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA6, // Report ID (166) + 0x09, 0x46, // Usage (0x46) + 0x95, 0x15, // Report Count (21) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xF0, // Report ID (240) + 0x09, 0x47, // Usage (0x47) + 0x95, 0x3F, // Report Count (63) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xF1, // Report ID (241) + 0x09, 0x48, // Usage (0x48) + 0x95, 0x3F, // Report Count (63) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xF2, // Report ID (242) + 0x09, 0x49, // Usage (0x49) + 0x95, 0x0F, // Report Count (15) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA7, // Report ID (167) + 0x09, 0x4A, // Usage (0x4A) + 0x95, 0x01, // Report Count (1) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA8, // Report ID (168) + 0x09, 0x4B, // Usage (0x4B) + 0x95, 0x01, // Report Count (1) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA9, // Report ID (169) + 0x09, 0x4C, // Usage (0x4C) + 0x95, 0x08, // Report Count (8) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xAA, // Report ID (170) + 0x09, 0x4E, // Usage (0x4E) + 0x95, 0x01, // Report Count (1) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xAB, // Report ID (171) + 0x09, 0x4F, // Usage (0x4F) + 0x95, 0x39, // Report Count (57) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xAC, // Report ID (172) + 0x09, 0x50, // Usage (0x50) + 0x95, 0x39, // Report Count (57) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xAD, // Report ID (173) + 0x09, 0x51, // Usage (0x51) + 0x95, 0x0B, // Report Count (11) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xAE, // Report ID (174) + 0x09, 0x52, // Usage (0x52) + 0x95, 0x01, // Report Count (1) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xAF, // Report ID (175) + 0x09, 0x53, // Usage (0x53) + 0x95, 0x02, // Report Count (2) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xB0, // Report ID (176) + 0x09, 0x54, // Usage (0x54) + 0x95, 0x3F, // Report Count (63) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + }; - struct _URB_CONTROL_DESCRIPTOR_REQUEST* pRequest = &Urb->UrbControlDescriptorRequest; + struct _URB_CONTROL_DESCRIPTOR_REQUEST* pRequest = &Urb->UrbControlDescriptorRequest; - TraceEvents(TRACE_LEVEL_VERBOSE, - TRACE_USBPDO, - ">> >> >> _URB_CONTROL_DESCRIPTOR_REQUEST: Buffer Length %d", - pRequest->TransferBufferLength); + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_USBPDO, + ">> >> >> _URB_CONTROL_DESCRIPTOR_REQUEST: Buffer Length %d", + pRequest->TransferBufferLength); - if (pRequest->TransferBufferLength >= ARRAYSIZE(Ds4HidReportDescriptor)) - { - RtlCopyMemory(pRequest->TransferBuffer, Ds4HidReportDescriptor, ARRAYSIZE(Ds4HidReportDescriptor)); - status = STATUS_SUCCESS; - } + if (pRequest->TransferBufferLength >= ARRAYSIZE(Ds4HidReportDescriptor)) + { + RtlCopyMemory(pRequest->TransferBuffer, Ds4HidReportDescriptor, ARRAYSIZE(Ds4HidReportDescriptor)); + status = STATUS_SUCCESS; - return status; + // + // Notify client library that PDO is ready + // + KeSetEvent(&this->PdoBootNotificationEvent, 0, FALSE); + } + + return status; } NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::UsbSelectInterface(PURB Urb) { - UNREFERENCED_PARAMETER(Urb); - - return STATUS_NOT_IMPLEMENTED; + UNREFERENCED_PARAMETER(Urb); + + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::UsbGetStringDescriptorType(PURB Urb) +{ + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_USBPDO, + "Index = %d", + Urb->UrbControlDescriptorRequest.Index); + + switch (Urb->UrbControlDescriptorRequest.Index) + { + case 0: + { + // "American English" + UCHAR LangId[] = + { + 0x04, 0x03, 0x09, 0x04 + }; + + Urb->UrbControlDescriptorRequest.TransferBufferLength = ARRAYSIZE(LangId); + RtlCopyBytes(Urb->UrbControlDescriptorRequest.TransferBuffer, LangId, ARRAYSIZE(LangId)); + + break; + } + case 1: + { + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_USBPDO, + "LanguageId = 0x%X", + Urb->UrbControlDescriptorRequest.LanguageId); + + if (Urb->UrbControlDescriptorRequest.TransferBufferLength < DS4_MANUFACTURER_NAME_LENGTH) + { + auto pDesc = static_cast(Urb->UrbControlDescriptorRequest.TransferBuffer); + pDesc->bLength = DS4_MANUFACTURER_NAME_LENGTH; + break; + } + + // "Sony Computer Entertainment" + UCHAR ManufacturerString[DS4_MANUFACTURER_NAME_LENGTH] = + { + 0x38, 0x03, 0x53, 0x00, 0x6F, 0x00, 0x6E, 0x00, + 0x79, 0x00, 0x20, 0x00, 0x43, 0x00, 0x6F, 0x00, + 0x6D, 0x00, 0x70, 0x00, 0x75, 0x00, 0x74, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x45, 0x00, + 0x6E, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, + 0x74, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6E, 0x00, + 0x6D, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x74, 0x00 + }; + + Urb->UrbControlDescriptorRequest.TransferBufferLength = DS4_MANUFACTURER_NAME_LENGTH; + RtlCopyBytes(Urb->UrbControlDescriptorRequest.TransferBuffer, ManufacturerString, DS4_MANUFACTURER_NAME_LENGTH); + + break; + } + case 2: + { + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_USBPDO, + "LanguageId = 0x%X", + Urb->UrbControlDescriptorRequest.LanguageId); + + if (Urb->UrbControlDescriptorRequest.TransferBufferLength < DS4_PRODUCT_NAME_LENGTH) + { + auto pDesc = static_cast(Urb->UrbControlDescriptorRequest.TransferBuffer); + pDesc->bLength = DS4_PRODUCT_NAME_LENGTH; + break; + } + + // "Wireless Controller" + UCHAR ProductString[DS4_PRODUCT_NAME_LENGTH] = + { + 0x28, 0x03, 0x57, 0x00, 0x69, 0x00, 0x72, 0x00, + 0x65, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x73, 0x00, + 0x73, 0x00, 0x20, 0x00, 0x43, 0x00, 0x6F, 0x00, + 0x6E, 0x00, 0x74, 0x00, 0x72, 0x00, 0x6F, 0x00, + 0x6C, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x72, 0x00 + }; + + Urb->UrbControlDescriptorRequest.TransferBufferLength = DS4_PRODUCT_NAME_LENGTH; + RtlCopyBytes(Urb->UrbControlDescriptorRequest.TransferBuffer, ProductString, DS4_PRODUCT_NAME_LENGTH); + + break; + } + default: + break; + } + + return STATUS_SUCCESS; } VOID ViGEm::Bus::Targets::EmulationTargetDS4::PendingUsbRequestsTimerFunc( - _In_ WDFTIMER Timer + _In_ WDFTIMER Timer ) { auto ctx = reinterpret_cast(Core::EmulationTargetPdoGetContext(WdfTimerGetParentObject(Timer))); WDFREQUEST usbRequest; - PIRP pendingIrp; - PIO_STACK_LOCATION irpStack; + PIRP pendingIrp; + PIO_STACK_LOCATION irpStack; - TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_DS4, "%!FUNC! Entry"); + TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_DS4, "%!FUNC! Entry"); - // Get pending USB request - NTSTATUS status = WdfIoQueueRetrieveNextRequest(ctx->PendingUsbInRequests, &usbRequest); + // Get pending USB request + NTSTATUS status = WdfIoQueueRetrieveNextRequest(ctx->PendingUsbInRequests, &usbRequest); - if (NT_SUCCESS(status)) - { - // Get pending IRP - pendingIrp = WdfRequestWdmGetIrp(usbRequest); - irpStack = IoGetCurrentIrpStackLocation(pendingIrp); + if (NT_SUCCESS(status)) + { + // Get pending IRP + pendingIrp = WdfRequestWdmGetIrp(usbRequest); + irpStack = IoGetCurrentIrpStackLocation(pendingIrp); - // Get USB request block - PURB urb = (PURB)irpStack->Parameters.Others.Argument1; + // Get USB request block + PURB urb = (PURB)irpStack->Parameters.Others.Argument1; - // Get transfer buffer - PUCHAR Buffer = (PUCHAR)urb->UrbBulkOrInterruptTransfer.TransferBuffer; - // Set buffer length to report size - urb->UrbBulkOrInterruptTransfer.TransferBufferLength = DS4_REPORT_SIZE; + // Get transfer buffer + PUCHAR Buffer = (PUCHAR)urb->UrbBulkOrInterruptTransfer.TransferBuffer; + // Set buffer length to report size + urb->UrbBulkOrInterruptTransfer.TransferBufferLength = DS4_REPORT_SIZE; - // Copy cached report to transfer buffer - if (Buffer) - RtlCopyBytes(Buffer, ctx->Report, DS4_REPORT_SIZE); + // Copy cached report to transfer buffer + if (Buffer) + RtlCopyBytes(Buffer, ctx->Report, DS4_REPORT_SIZE); - // Complete pending request - WdfRequestComplete(usbRequest, status); - } + // Complete pending request + WdfRequestComplete(usbRequest, status); + } - TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DS4, "%!FUNC! Exit with status %!STATUS!", status); + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DS4, "%!FUNC! Exit with status %!STATUS!", status); } diff --git a/sys/Ds4Pdo.hpp b/sys/Ds4Pdo.hpp index 5cae258..2b08483 100644 --- a/sys/Ds4Pdo.hpp +++ b/sys/Ds4Pdo.hpp @@ -42,6 +42,7 @@ namespace ViGEm::Bus::Targets NTSTATUS UsbClassInterface(PURB Urb) override; NTSTATUS UsbGetDescriptorFromInterface(PURB Urb) override; NTSTATUS UsbSelectInterface(PURB Urb) override; + NTSTATUS UsbGetStringDescriptorType(PURB Urb) override; private: static PCWSTR _deviceDescription; diff --git a/sys/EmulationTargetPDO.cpp b/sys/EmulationTargetPDO.cpp index 43b3084..d4bd197 100644 --- a/sys/EmulationTargetPDO.cpp +++ b/sys/EmulationTargetPDO.cpp @@ -457,7 +457,7 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl( PIRP irp; PURB urb; PIO_STACK_LOCATION irpStack; - PUCHAR blobBuffer; + //PUCHAR blobBuffer; TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_BUSPDO, "%!FUNC! Entry"); @@ -465,7 +465,263 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl( irp = WdfRequestWdmGetIrp(Request); irpStack = IoGetCurrentIrpStackLocation(irp); - - - WdfRequestComplete(Request, STATUS_UNSUCCESSFUL); + switch (IoControlCode) + { + case IOCTL_INTERNAL_USB_SUBMIT_URB: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> IOCTL_INTERNAL_USB_SUBMIT_URB"); + + urb = static_cast(URB_FROM_IRP(irp)); + + switch (urb->UrbHeader.Function) + { + case URB_FUNCTION_CONTROL_TRANSFER: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> >> URB_FUNCTION_CONTROL_TRANSFER"); + + //switch (urb->UrbControlTransfer.SetupPacket[6]) + //{ + //case 0x04: + // if (pdoData->TargetType == Xbox360Wired) + // { + // pXusbData = XusbGetData(hDevice); + // blobBuffer = WdfMemoryGetBuffer(pXusbData->InterruptBlobStorage, NULL); + // // + // // Xenon magic + // // + // RtlCopyMemory( + // urb->UrbControlTransfer.TransferBuffer, + // &blobBuffer[XUSB_BLOB_07_OFFSET], + // 0x04 + // ); + // status = STATUS_SUCCESS; + // } + // break; + //case 0x14: + // // + // // This is some weird USB 1.0 condition and _must fail_ + // // + // urb->UrbControlTransfer.Hdr.Status = USBD_STATUS_STALL_PID; + // status = STATUS_UNSUCCESSFUL; + // break; + //case 0x08: + // // + // // This is some weird USB 1.0 condition and _must fail_ + // // + // urb->UrbControlTransfer.Hdr.Status = USBD_STATUS_STALL_PID; + // status = STATUS_UNSUCCESSFUL; + // break; + //default: + // status = STATUS_SUCCESS; + // break; + //} + + break; + + case URB_FUNCTION_CONTROL_TRANSFER_EX: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> >> URB_FUNCTION_CONTROL_TRANSFER_EX"); + + status = STATUS_UNSUCCESSFUL; + + break; + + case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> >> URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER"); + + //status = UsbPdo_BulkOrInterruptTransfer(urb, hDevice, Request); + + break; + + case URB_FUNCTION_SELECT_CONFIGURATION: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> >> URB_FUNCTION_SELECT_CONFIGURATION"); + + status = ctx->Target->UsbSelectConfiguration(urb); + + break; + + case URB_FUNCTION_SELECT_INTERFACE: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> >> URB_FUNCTION_SELECT_INTERFACE"); + + status = ctx->Target->UsbSelectInterface(urb); + + break; + + case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> >> URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE"); + + switch (urb->UrbControlDescriptorRequest.DescriptorType) + { + case USB_DEVICE_DESCRIPTOR_TYPE: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> >> >> USB_DEVICE_DESCRIPTOR_TYPE"); + + ctx->Target->GetDeviceDescriptorType(static_cast(urb->UrbControlDescriptorRequest.TransferBuffer)); + + break; + + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> >> >> USB_CONFIGURATION_DESCRIPTOR_TYPE"); + + status = ctx->Target->UsbGetConfigurationDescriptorType(urb); + + break; + + case USB_STRING_DESCRIPTOR_TYPE: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> >> >> USB_STRING_DESCRIPTOR_TYPE"); + + status = ctx->Target->UsbGetStringDescriptorType(urb); + + break; + + default: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> >> >> Unknown descriptor type"); + + break; + } + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + "<< <<"); + + break; + + case URB_FUNCTION_GET_STATUS_FROM_DEVICE: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> >> URB_FUNCTION_GET_STATUS_FROM_DEVICE"); + + // Defaults always succeed + status = STATUS_SUCCESS; + + break; + + case URB_FUNCTION_ABORT_PIPE: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> >> URB_FUNCTION_ABORT_PIPE"); + + ctx->Target->UsbAbortPipe(); + + break; + + case URB_FUNCTION_CLASS_INTERFACE: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> >> URB_FUNCTION_CLASS_INTERFACE"); + + status = ctx->Target->UsbClassInterface(urb); + + break; + + case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> >> URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE"); + + status = ctx->Target->UsbGetDescriptorFromInterface(urb); + + break; + + default: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> >> Unknown function: 0x%X", + urb->UrbHeader.Function); + + break; + } + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + "<<"); + + break; + + case IOCTL_INTERNAL_USB_GET_PORT_STATUS: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> IOCTL_INTERNAL_USB_GET_PORT_STATUS"); + + // We report the (virtual) port as always active + *(unsigned long*)irpStack->Parameters.Others.Argument1 = USBD_PORT_ENABLED | USBD_PORT_CONNECTED; + + status = STATUS_SUCCESS; + + break; + + case IOCTL_INTERNAL_USB_RESET_PORT: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> IOCTL_INTERNAL_USB_RESET_PORT"); + + // Sure, why not ;) + status = STATUS_SUCCESS; + + break; + + case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION"); + + // TODO: implement + // This happens if the I/O latency is too high so HIDUSB aborts communication. + status = STATUS_SUCCESS; + + break; + + default: + + TraceEvents(TRACE_LEVEL_VERBOSE, + TRACE_BUSPDO, + ">> Unknown I/O control code 0x%X", + IoControlCode); + + break; + } + + if (status != STATUS_PENDING) + { + WdfRequestComplete(Request, status); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_BUSPDO, "%!FUNC! Exit with status %!STATUS!", status); } diff --git a/sys/EmulationTargetPDO.hpp b/sys/EmulationTargetPDO.hpp index ff26707..4f549c3 100644 --- a/sys/EmulationTargetPDO.hpp +++ b/sys/EmulationTargetPDO.hpp @@ -66,6 +66,8 @@ namespace ViGEm::Bus::Core virtual NTSTATUS UsbSelectInterface(PURB Urb) = 0; + virtual NTSTATUS UsbGetStringDescriptorType(PURB Urb) = 0; + protected: static const ULONG _maxHardwareIdLength = 0xFF; diff --git a/sys/XusbPdo.cpp b/sys/XusbPdo.cpp index a524c6a..28f491b 100644 --- a/sys/XusbPdo.cpp +++ b/sys/XusbPdo.cpp @@ -701,3 +701,10 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::UsbSelectInterface(PURB Urb) return STATUS_INVALID_PARAMETER; } + +NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::UsbGetStringDescriptorType(PURB Urb) +{ + UNREFERENCED_PARAMETER(Urb); + + return STATUS_NOT_IMPLEMENTED; +} diff --git a/sys/XusbPdo.hpp b/sys/XusbPdo.hpp index 80b14f0..4bceb5c 100644 --- a/sys/XusbPdo.hpp +++ b/sys/XusbPdo.hpp @@ -41,6 +41,7 @@ namespace ViGEm::Bus::Targets NTSTATUS UsbClassInterface(PURB Urb) override; NTSTATUS UsbGetDescriptorFromInterface(PURB Urb) override; NTSTATUS UsbSelectInterface(PURB Urb) override; + NTSTATUS UsbGetStringDescriptorType(PURB Urb) override; private: static PCWSTR _deviceDescription;