diff --git a/sys/Ds4Pdo.cpp b/sys/Ds4Pdo.cpp new file mode 100644 index 0000000..ea10704 --- /dev/null +++ b/sys/Ds4Pdo.cpp @@ -0,0 +1,218 @@ +#include "Ds4Pdo.hpp" +#include "trace.h" +#include "Ds4Pdo.tmh" +#define NTSTRSAFE_LIB +#include + + +using namespace ViGEm::Bus::Targets; + +PCWSTR EmulationTargetDS4::_deviceDescription = L"Virtual DualShock 4 Controller"; + +NTSTATUS EmulationTargetDS4::PrepareDevice(PWDFDEVICE_INIT DeviceInit, USHORT VendorId, USHORT ProductId, + PUNICODE_STRING DeviceId, PUNICODE_STRING DeviceDescription) +{ + NTSTATUS status; + UNICODE_STRING buffer; + + // + // TODO: implement usage! + // + UNREFERENCED_PARAMETER(VendorId); + UNREFERENCED_PARAMETER(ProductId); + + // 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; + } + + // Set hardware IDs + RtlUnicodeStringInit(&buffer, L"USB\\VID_054C&PID_05C4&REV_0100"); + + status = WdfPdoInitAddHardwareID(DeviceInit, &buffer); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "WdfPdoInitAddHardwareID failed with status %!STATUS!", + status); + return status; + } + + RtlUnicodeStringCopy(DeviceId, &buffer); + + RtlUnicodeStringInit(&buffer, L"USB\\VID_054C&PID_05C4"); + + status = WdfPdoInitAddHardwareID(DeviceInit, &buffer); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "WdfPdoInitAddHardwareID failed with status %!STATUS!", + status); + return status; + } + + // Set compatible IDs + RtlUnicodeStringInit(&buffer, L"USB\\Class_03&SubClass_00&Prot_00"); + + status = WdfPdoInitAddCompatibleID(DeviceInit, &buffer); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_DS4, + "WdfPdoInitAddCompatibleID (#01) failed with status %!STATUS!", + status); + return status; + } + + RtlUnicodeStringInit(&buffer, L"USB\\Class_03&SubClass_00"); + + 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"); + + 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 EmulationTargetDS4::PrepareHardware(WDFDEVICE Device) +{ + UNREFERENCED_PARAMETER(Device); + + return NTSTATUS(); +} + +NTSTATUS EmulationTargetDS4::InitContext(WDFDEVICE Device) +{ + UNREFERENCED_PARAMETER(Device); + + return NTSTATUS(); +} + +VOID 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 + + 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 + + 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) + + // 41 bytes + + // best guess: USB Standard Descriptor + }; + + RtlCopyBytes(Buffer, Ds4DescriptorData, Length); +} + +VOID EmulationTargetDS4::GetDeviceDescriptorType(PUSB_DEVICE_DESCRIPTOR pDescriptor, USHORT VendorId, USHORT ProductId) +{ + 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 = VendorId; + pDescriptor->idProduct = ProductId; + pDescriptor->bcdDevice = 0x0100; + pDescriptor->iManufacturer = 0x01; + pDescriptor->iProduct = 0x02; + pDescriptor->iSerialNumber = 0x00; + pDescriptor->bNumConfigurations = 0x01; +} + +VOID EmulationTargetDS4::SelectConfiguration(PUSBD_INTERFACE_INFORMATION pInfo) +{ + 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->Class = 0x03; // HID + pInfo->SubClass = 0x00; + pInfo->Protocol = 0x00; + + pInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)0xFFFF0000; + + 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; +} diff --git a/sys/Ds4Pdo.hpp b/sys/Ds4Pdo.hpp new file mode 100644 index 0000000..939b2b8 --- /dev/null +++ b/sys/Ds4Pdo.hpp @@ -0,0 +1,74 @@ +#pragma once + + +#include "EmulationTargetPDO.hpp" + +namespace ViGEm::Bus::Targets +{ + + + class EmulationTargetDS4 : public Core::EmulationTargetPDO + { + public: + EmulationTargetDS4() = default; + ~EmulationTargetDS4() = default; + + NTSTATUS PrepareDevice(PWDFDEVICE_INIT DeviceInit, USHORT VendorId, USHORT ProductId, + PUNICODE_STRING DeviceId, PUNICODE_STRING DeviceDescription) override; + + NTSTATUS PrepareHardware(WDFDEVICE Device) override; + + NTSTATUS InitContext(WDFDEVICE Device) override; + + VOID GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length) override; + + VOID GetDeviceDescriptorType(PUSB_DEVICE_DESCRIPTOR pDescriptor, USHORT VendorId, USHORT ProductId) override; + + VOID SelectConfiguration(PUSBD_INTERFACE_INFORMATION pInfo) override; + + private: + static PCWSTR _deviceDescription; + +#if defined(_X86_) + static const int XUSB_CONFIGURATION_SIZE = 0x00E4; +#else + static const int XUSB_CONFIGURATION_SIZE = 0x0130; +#endif + static const int XUSB_DESCRIPTOR_SIZE = 0x0099; + static const int XUSB_RUMBLE_SIZE = 0x08; + static const int XUSB_LEDSET_SIZE = 0x03; + static const int XUSB_LEDNUM_SIZE = 0x01; + static const int XUSB_INIT_STAGE_SIZE = 0x03; + static const int XUSB_BLOB_STORAGE_SIZE = 0x2A; + + + static const int HID_GET_FEATURE_REPORT_SIZE_0 = 0x31; + static const int HID_GET_FEATURE_REPORT_SIZE_1 = 0x25; + static const int HID_GET_FEATURE_REPORT_MAC_ADDRESSES_SIZE = 0x10; + + static const int HID_SET_FEATURE_REPORT_SIZE_0 = 0x17; + static const int HID_SET_FEATURE_REPORT_SIZE_1 = 0x11; + + static const int HID_REPORT_ID_0 = 0xA3; + static const int HID_REPORT_ID_1 = 0x02; + static const int HID_REPORT_MAC_ADDRESSES_ID = 0x12; + static const int HID_REPORT_ID_3 = 0x13; + static const int HID_REPORT_ID_4 = 0x14; + + static const int DS4_DESCRIPTOR_SIZE = 0x0029; +#if defined(_X86_) + static const int DS4_CONFIGURATION_SIZE = 0x0050; +#else + static const int DS4_CONFIGURATION_SIZE = 0x0070; +#endif + static const int DS4_HID_REPORT_DESCRIPTOR_SIZE = 0x01D3; + + static const int DS4_MANUFACTURER_NAME_LENGTH = 0x38; + static const int DS4_PRODUCT_NAME_LENGTH = 0x28; + static const int DS4_OUTPUT_BUFFER_OFFSET = 0x04; + static const int DS4_OUTPUT_BUFFER_LENGTH = 0x05; + + static const int DS4_REPORT_SIZE = 0x40; + static const int DS4_QUEUE_FLUSH_PERIOD = 0x05; + }; +} diff --git a/sys/ViGEmBus.vcxproj b/sys/ViGEmBus.vcxproj index 5c57547..404f092 100644 --- a/sys/ViGEmBus.vcxproj +++ b/sys/ViGEmBus.vcxproj @@ -189,6 +189,7 @@ + @@ -207,6 +208,7 @@ + diff --git a/sys/ViGEmBus.vcxproj.filters b/sys/ViGEmBus.vcxproj.filters index d13afda..10e2f03 100644 --- a/sys/ViGEmBus.vcxproj.filters +++ b/sys/ViGEmBus.vcxproj.filters @@ -81,6 +81,9 @@ Header Files + + Header Files\Targets + @@ -116,6 +119,9 @@ Source Files + + Source Files\Targets +