Ported majority of XUSB stuff over to C++

This commit is contained in:
Benjamin Höglinger-Stelzer
2020-05-08 22:43:46 +02:00
parent bd074d93fd
commit 07c97094f8
10 changed files with 883 additions and 0 deletions

38
sys/CRTCPP.hpp Normal file
View File

@@ -0,0 +1,38 @@
#pragma once
#include <ntifs.h>
constexpr auto cpp_pool_tag = 'EGiV';
#ifdef _AMD64_
static void* operator new(size_t lBlockSize)
{
return ExAllocatePoolWithTag(NonPagedPoolNx, lBlockSize, cpp_pool_tag);
}
static void operator delete(void* p)
{
if (p == nullptr)
{
return;
}
ExFreePoolWithTag(p, cpp_pool_tag);
}
#else
static void* __CRTDECL operator new(size_t lBlockSize)
{
return ExAllocatePoolWithTag(NonPagedPoolNx, lBlockSize, CPP_POOL_TAG);
}
static void __CRTDECL operator delete(void* p)
{
if (!p)
{
return;
}
ExFreePoolWithTag(p, CPP_POOL_TAG);
}
#endif

View File

@@ -0,0 +1,58 @@
#include "EmulationTargetPDO.hpp"
using namespace ViGEm::Bus::Core;
BOOLEAN USB_BUSIFFN EmulationTargetPDO::UsbIsDeviceHighSpeed(IN PVOID BusContext)
{
UNREFERENCED_PARAMETER(BusContext);
return TRUE;
}
NTSTATUS USB_BUSIFFN EmulationTargetPDO::UsbQueryBusInformation(IN PVOID BusContext, IN ULONG Level,
IN OUT PVOID BusInformationBuffer,
IN OUT PULONG BusInformationBufferLength,
OUT PULONG BusInformationActualLength)
{
UNREFERENCED_PARAMETER(BusContext);
UNREFERENCED_PARAMETER(Level);
UNREFERENCED_PARAMETER(BusInformationBuffer);
UNREFERENCED_PARAMETER(BusInformationBufferLength);
UNREFERENCED_PARAMETER(BusInformationActualLength);
return STATUS_UNSUCCESSFUL;
}
NTSTATUS USB_BUSIFFN EmulationTargetPDO::UsbSubmitIsoOutUrb(IN PVOID BusContext, IN PURB Urb)
{
UNREFERENCED_PARAMETER(BusContext);
UNREFERENCED_PARAMETER(Urb);
return STATUS_UNSUCCESSFUL;
}
NTSTATUS USB_BUSIFFN EmulationTargetPDO::UsbQueryBusTime(IN PVOID BusContext, IN OUT PULONG CurrentUsbFrame)
{
UNREFERENCED_PARAMETER(BusContext);
UNREFERENCED_PARAMETER(CurrentUsbFrame);
return STATUS_UNSUCCESSFUL;
}
VOID USB_BUSIFFN EmulationTargetPDO::UsbGetUSBDIVersion(IN PVOID BusContext,
IN OUT PUSBD_VERSION_INFORMATION VersionInformation,
IN OUT PULONG HcdCapabilities)
{
UNREFERENCED_PARAMETER(BusContext);
if (VersionInformation != nullptr)
{
VersionInformation->USBDI_Version = 0x500; /* Usbport */
VersionInformation->Supported_USB_Version = 0x200; /* USB 2.0 */
}
if (HcdCapabilities != nullptr)
{
*HcdCapabilities = 0;
}
}

View File

@@ -0,0 +1,60 @@
#pragma once
#include <ntddk.h>
#include <wdf.h>
#include <usb.h>
#include <usbbusif.h>
//
// Some insane macro-magic =3
//
#define P99_PROTECT(...) __VA_ARGS__
#define COPY_BYTE_ARRAY(_dst_, _bytes_) do {BYTE b[] = _bytes_; \
RtlCopyMemory(_dst_, b, RTL_NUMBER_OF_V1(b)); } while (0)
namespace ViGEm::Bus::Core
{
class EmulationTargetPDO
{
public:
EmulationTargetPDO() = default;
virtual ~EmulationTargetPDO() = default;
virtual NTSTATUS PrepareDevice(PWDFDEVICE_INIT DeviceInit, USHORT VendorId, USHORT ProductId,
PUNICODE_STRING DeviceId, PUNICODE_STRING DeviceDescription) = 0;
virtual NTSTATUS PrepareHardware(WDFDEVICE Device) = 0;
virtual NTSTATUS InitContext(WDFDEVICE Device) = 0;
virtual VOID GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length) = 0;
virtual VOID GetDeviceDescriptorType(PUSB_DEVICE_DESCRIPTOR pDescriptor, USHORT VendorId, USHORT ProductId) = 0;
virtual VOID SelectConfiguration(PUSBD_INTERFACE_INFORMATION pInfo) = 0;
protected:
static const ULONG _maxHardwareIdLength = 0xFF;
static BOOLEAN USB_BUSIFFN UsbIsDeviceHighSpeed(IN PVOID BusContext);
static NTSTATUS USB_BUSIFFN UsbQueryBusInformation(
IN PVOID BusContext,
IN ULONG Level,
IN OUT PVOID BusInformationBuffer,
IN OUT PULONG BusInformationBufferLength,
OUT PULONG BusInformationActualLength
);
static NTSTATUS USB_BUSIFFN UsbSubmitIsoOutUrb(IN PVOID BusContext, IN PURB Urb);
static NTSTATUS USB_BUSIFFN UsbQueryBusTime(IN PVOID BusContext, IN OUT PULONG CurrentUsbFrame);
static VOID USB_BUSIFFN UsbGetUSBDIVersion(
IN PVOID BusContext,
IN OUT PUSBD_VERSION_INFORMATION VersionInformation,
IN OUT PULONG HcdCapabilities
);
};
}

BIN
sys/RCa08996 Normal file

Binary file not shown.

View File

@@ -171,6 +171,7 @@
<WppRecorderEnabled>true</WppRecorderEnabled>
<WppEnabled>true</WppEnabled>
<WppScanConfigurationData>trace.h</WppScanConfigurationData>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
@@ -186,13 +187,16 @@
<ClInclude Include="busenum.h" />
<ClInclude Include="ByteArray.h" />
<ClInclude Include="Context.h" />
<ClInclude Include="CRTCPP.hpp" />
<ClInclude Include="Ds4.h" />
<ClInclude Include="EmulationTargetPDO.hpp" />
<ClInclude Include="Queue.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="trace.h" />
<ClInclude Include="UsbPdo.h" />
<ClInclude Include="Util.h" />
<ClInclude Include="Xusb.h" />
<ClInclude Include="XusbPdo.hpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ViGEmBus.rc" />
@@ -203,10 +207,12 @@
<ClCompile Include="ByteArray.c" />
<ClCompile Include="Driver.c" />
<ClCompile Include="Ds4.c" />
<ClCompile Include="EmulationTargetPDO.cpp" />
<ClCompile Include="Queue.c" />
<ClCompile Include="UsbPdo.c" />
<ClCompile Include="Util.c" />
<ClCompile Include="xusb.c" />
<ClCompile Include="XusbPdo.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@@ -20,6 +20,12 @@
<Filter Include="Header Files\Common">
<UniqueIdentifier>{bbf85b1d-5a75-4302-af4e-46627fcf0d78}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Targets">
<UniqueIdentifier>{b00da32a-ce46-490d-9e77-95bb90925995}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Targets">
<UniqueIdentifier>{3a87fd70-9882-47c4-a23b-50dd0b42b0f8}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<Inf Include="ViGEmBus.inf">
@@ -66,6 +72,15 @@
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="XusbPdo.hpp">
<Filter>Header Files\Targets</Filter>
</ClInclude>
<ClInclude Include="EmulationTargetPDO.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CRTCPP.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="busenum.c">
@@ -95,6 +110,12 @@
<ClCompile Include="ByteArray.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="XusbPdo.cpp">
<Filter>Source Files\Targets</Filter>
</ClCompile>
<ClCompile Include="EmulationTargetPDO.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ViGEmBus.rc">

View File

@@ -117,6 +117,7 @@ typedef struct _XUSB_DEVICE_DATA
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(XUSB_DEVICE_DATA, XusbGetData)
EXTERN_C_START
NTSTATUS
Bus_XusbSubmitReport(
@@ -136,3 +137,5 @@ VOID Xusb_GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length);
VOID Xusb_GetDeviceDescriptorType(PUSB_DEVICE_DESCRIPTOR pDescriptor, PPDO_DEVICE_DATA pCommon);
VOID Xusb_SelectConfiguration(PUSBD_INTERFACE_INFORMATION pInfo);
NTSTATUS Xusb_GetUserIndex(WDFDEVICE Device, PXUSB_GET_USER_INDEX Request);
EXTERN_C_END

574
sys/XusbPdo.cpp Normal file
View File

@@ -0,0 +1,574 @@
#include "XusbPdo.hpp"
#include "trace.h"
#include "XusbPdo.tmh"
#define NTSTRSAFE_LIB
#include <ntstrsafe.h>
#include <wdmguid.h>
using namespace ViGEm::Bus::Targets;
PCWSTR EmulationTargetXUSB::_deviceDescription = L"Virtual Xbox 360 Controller";
NTSTATUS EmulationTargetXUSB::PrepareDevice(PWDFDEVICE_INIT DeviceInit, USHORT VendorId,
USHORT ProductId, PUNICODE_STRING DeviceId,
PUNICODE_STRING DeviceDescription)
{
NTSTATUS status;
DECLARE_UNICODE_STRING_SIZE(buffer, _maxHardwareIdLength);
// prepare device description
status = RtlUnicodeStringInit(DeviceDescription, _deviceDescription);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_XUSB,
"RtlUnicodeStringInit failed with status %!STATUS!",
status);
return status;
}
// Set hardware ID
RtlUnicodeStringPrintf(&buffer, L"USB\\VID_%04X&PID_%04X", VendorId, ProductId);
RtlUnicodeStringCopy(DeviceId, &buffer);
status = WdfPdoInitAddHardwareID(DeviceInit, &buffer);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_XUSB,
"WdfPdoInitAddHardwareID failed with status %!STATUS!",
status);
return status;
}
// Set compatible IDs
RtlUnicodeStringInit(&buffer, L"USB\\MS_COMP_XUSB10");
status = WdfPdoInitAddCompatibleID(DeviceInit, &buffer);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_XUSB,
"WdfPdoInitAddCompatibleID #1 failed with status %!STATUS!",
status);
return status;
}
RtlUnicodeStringInit(&buffer, L"USB\\Class_FF&SubClass_5D&Prot_01");
status = WdfPdoInitAddCompatibleID(DeviceInit, &buffer);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_XUSB,
"WdfPdoInitAddCompatibleID #2 failed with status %!STATUS!",
status);
return status;
}
RtlUnicodeStringInit(&buffer, L"USB\\Class_FF&SubClass_5D");
status = WdfPdoInitAddCompatibleID(DeviceInit, &buffer);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_XUSB,
"WdfPdoInitAddCompatibleID #3 failed with status %!STATUS!",
status);
return status;
}
RtlUnicodeStringInit(&buffer, L"USB\\Class_FF");
status = WdfPdoInitAddCompatibleID(DeviceInit, &buffer);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_XUSB,
"WdfPdoInitAddCompatibleID #4 failed with status %!STATUS!",
status);
return status;
}
return STATUS_SUCCESS;
}
NTSTATUS EmulationTargetXUSB::PrepareHardware(WDFDEVICE Device)
{
WDF_QUERY_INTERFACE_CONFIG ifaceCfg;
INTERFACE dummyIface;
dummyIface.Size = sizeof(INTERFACE);
dummyIface.Version = 1;
dummyIface.Context = static_cast<PVOID>(Device);
dummyIface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
dummyIface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
/* XUSB.sys will query for the following three "dummy" interfaces
* BUT WONT USE IT so we just expose them to satisfy initialization. (TODO: Check if still valid!)
*/
// Dummy PNP_LOCATION
WDF_QUERY_INTERFACE_CONFIG_INIT(
&ifaceCfg,
static_cast<PINTERFACE>(&dummyIface),
&GUID_PNP_LOCATION_INTERFACE,
nullptr
);
NTSTATUS status = WdfDeviceAddQueryInterface(Device, &ifaceCfg);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_XUSB,
"Couldn't register PNP_LOCATION dummy interface %!GUID! (WdfDeviceAddQueryInterface failed with status %!STATUS!)",
&GUID_PNP_LOCATION_INTERFACE,
status);
return status;
}
// Dummy D3COLD_SUPPORT
WDF_QUERY_INTERFACE_CONFIG_INIT(
&ifaceCfg,
static_cast<PINTERFACE>(&dummyIface),
&GUID_D3COLD_SUPPORT_INTERFACE,
nullptr
);
status = WdfDeviceAddQueryInterface(Device, &ifaceCfg);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_XUSB,
"Couldn't register D3COLD_SUPPORT dummy interface %!GUID! (WdfDeviceAddQueryInterface failed with status %!STATUS!)",
&GUID_D3COLD_SUPPORT_INTERFACE,
status);
return status;
}
// Dummy REENUMERATE_SELF_INTERFACE_STANDARD
WDF_QUERY_INTERFACE_CONFIG_INIT(
&ifaceCfg,
static_cast<PINTERFACE>(&dummyIface),
&GUID_REENUMERATE_SELF_INTERFACE_STANDARD,
nullptr
);
status = WdfDeviceAddQueryInterface(Device, &ifaceCfg);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_XUSB,
"Couldn't register REENUM_SELF_STD dummy interface %!GUID! (WdfDeviceAddQueryInterface failed with status %!STATUS!)",
&GUID_REENUMERATE_SELF_INTERFACE_STANDARD,
status);
return status;
}
// Expose USB_BUS_INTERFACE_USBDI_GUID
// This interface actually IS used
USB_BUS_INTERFACE_USBDI_V1 xusbInterface;
xusbInterface.Size = sizeof(USB_BUS_INTERFACE_USBDI_V1);
xusbInterface.Version = USB_BUSIF_USBDI_VERSION_1;
xusbInterface.BusContext = static_cast<PVOID>(Device);
xusbInterface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
xusbInterface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
xusbInterface.SubmitIsoOutUrb = UsbSubmitIsoOutUrb;
xusbInterface.GetUSBDIVersion = UsbGetUSBDIVersion;
xusbInterface.QueryBusTime = UsbQueryBusTime;
xusbInterface.QueryBusInformation = UsbQueryBusInformation;
xusbInterface.IsDeviceHighSpeed = UsbIsDeviceHighSpeed;
WDF_QUERY_INTERFACE_CONFIG_INIT(
&ifaceCfg,
reinterpret_cast<PINTERFACE>(&xusbInterface),
&USB_BUS_INTERFACE_USBDI_GUID,
nullptr
);
status = WdfDeviceAddQueryInterface(Device, &ifaceCfg);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_XUSB,
"WdfDeviceAddQueryInterface failed with status %!STATUS!",
status);
return status;
}
return STATUS_SUCCESS;
}
NTSTATUS EmulationTargetXUSB::InitContext(WDFDEVICE Device)
{
WDF_OBJECT_ATTRIBUTES attributes;
PUCHAR blobBuffer;
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.ParentObject = Device;
TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_XUSB, "Initializing XUSB context...");
PXUSB_DEVICE_DATA xusb = XusbPdoGetContext(Device);
RtlZeroMemory(xusb, sizeof(XUSB_DEVICE_DATA));
// Is later overwritten by actual XInput slot
xusb->LedNumber = -1;
// Packet size (20 bytes = 0x14)
xusb->Packet.Size = 0x14;
// Allocate blob storage
NTSTATUS status = WdfMemoryCreate(
&attributes,
NonPagedPoolNx,
XUSB_POOL_TAG,
XUSB_BLOB_STORAGE_SIZE,
&xusb->InterruptBlobStorage,
reinterpret_cast<PVOID*>(&blobBuffer)
);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_XUSB,
"WdfMemoryCreate failed with status %!STATUS!",
status);
return status;
}
// Fill blob storage
COPY_BYTE_ARRAY(blobBuffer, P99_PROTECT({
// 0
0x01, 0x03, 0x0E,
// 1
0x02, 0x03, 0x00,
// 2
0x03, 0x03, 0x03,
// 3
0x08, 0x03, 0x00,
// 4
0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xf2,
0xb3, 0xf8, 0x49, 0xf3, 0xb0, 0xfc, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
// 5
0x01, 0x03, 0x03,
// 6
0x05, 0x03, 0x00,
// 7
0x31, 0x3F, 0xCF, 0xDC
}));
// I/O Queue for pending IRPs
WDF_IO_QUEUE_CONFIG holdingInQueueConfig;
// Create and assign queue for unhandled interrupt requests
WDF_IO_QUEUE_CONFIG_INIT(&holdingInQueueConfig, WdfIoQueueDispatchManual);
status = WdfIoQueueCreate(Device, &holdingInQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &xusb->HoldingUsbInRequests);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_XUSB,
"WdfIoQueueCreate (HoldingUsbInRequests) failed with status %!STATUS!",
status);
return status;
}
return STATUS_SUCCESS;
}
VOID EmulationTargetXUSB::GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length)
{
UCHAR XusbDescriptorData[XUSB_DESCRIPTOR_SIZE] =
{
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x99, 0x00, // wTotalLength 153
0x04, // bNumInterfaces 4
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0xA0, // bmAttributes Remote Wakeup
0xFA, // bMaxPower 500mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x02, // bNumEndpoints 2
0xFF, // bInterfaceClass
0x5D, // bInterfaceSubClass
0x01, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x11, // bLength
0x21, // bDescriptorType (HID)
0x00, 0x01, // bcdHID 1.00
0x01, // bCountryCode
0x25, // bNumDescriptors
0x81, // bDescriptorType[0] (Unknown 0x81)
0x14, 0x00, // wDescriptorLength[0] 20
0x00, // bDescriptorType[1] (Unknown 0x00)
0x00, 0x00, // wDescriptorLength[1] 0
0x13, // bDescriptorType[2] (Unknown 0x13)
0x01, 0x08, // wDescriptorLength[2] 2049
0x00, // bDescriptorType[3] (Unknown 0x00)
0x00,
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x20, 0x00, // wMaxPacketSize 32
0x04, // bInterval 4 (unit depends on device speed)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x01, // bEndpointAddress (OUT/H2D)
0x03, // bmAttributes (Interrupt)
0x20, 0x00, // wMaxPacketSize 32
0x08, // bInterval 8 (unit depends on device speed)
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x01, // bInterfaceNumber 1
0x00, // bAlternateSetting
0x04, // bNumEndpoints 4
0xFF, // bInterfaceClass
0x5D, // bInterfaceSubClass
0x03, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x1B, // bLength
0x21, // bDescriptorType (HID)
0x00, 0x01, // bcdHID 1.00
0x01, // bCountryCode
0x01, // bNumDescriptors
0x82, // bDescriptorType[0] (Unknown 0x82)
0x40, 0x01, // wDescriptorLength[0] 320
0x02, 0x20, 0x16, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x82, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x20, 0x00, // wMaxPacketSize 32
0x02, // bInterval 2 (unit depends on device speed)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x02, // bEndpointAddress (OUT/H2D)
0x03, // bmAttributes (Interrupt)
0x20, 0x00, // wMaxPacketSize 32
0x04, // bInterval 4 (unit depends on device speed)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x83, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x20, 0x00, // wMaxPacketSize 32
0x40, // bInterval 64 (unit depends on device speed)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x03, // bEndpointAddress (OUT/H2D)
0x03, // bmAttributes (Interrupt)
0x20, 0x00, // wMaxPacketSize 32
0x10, // bInterval 16 (unit depends on device speed)
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x02, // bInterfaceNumber 2
0x00, // bAlternateSetting
0x01, // bNumEndpoints 1
0xFF, // bInterfaceClass
0x5D, // bInterfaceSubClass
0x02, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x21, // bDescriptorType (HID)
0x00, 0x01, // bcdHID 1.00
0x01, // bCountryCode
0x22, // bNumDescriptors
0x84, // bDescriptorType[0] (Unknown 0x84)
0x07, 0x00, // wDescriptorLength[0] 7
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x84, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x20, 0x00, // wMaxPacketSize 32
0x10, // bInterval 16 (unit depends on device speed)
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x03, // bInterfaceNumber 3
0x00, // bAlternateSetting
0x00, // bNumEndpoints 0
0xFF, // bInterfaceClass
0xFD, // bInterfaceSubClass
0x13, // bInterfaceProtocol
0x04, // iInterface (String Index)
0x06, // bLength
0x41, // bDescriptorType (Unknown)
0x00, 0x01, 0x01, 0x03,
// 153 bytes
// best guess: USB Standard Descriptor
};
RtlCopyBytes(Buffer, XusbDescriptorData, Length);
}
VOID EmulationTargetXUSB::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 = 0xFF;
pDescriptor->bDeviceSubClass = 0xFF;
pDescriptor->bDeviceProtocol = 0xFF;
pDescriptor->bMaxPacketSize0 = 0x08;
pDescriptor->idVendor = VendorId;
pDescriptor->idProduct = ProductId;
pDescriptor->bcdDevice = 0x0114;
pDescriptor->iManufacturer = 0x01;
pDescriptor->iProduct = 0x02;
pDescriptor->iSerialNumber = 0x03;
pDescriptor->bNumConfigurations = 0x01;
}
VOID EmulationTargetXUSB::SelectConfiguration(PUSBD_INTERFACE_INFORMATION pInfo)
{
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_XUSB,
">> >> >> 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 = 0xFF;
pInfo->SubClass = 0x5D;
pInfo->Protocol = 0x01;
pInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)0xFFFF0000;
pInfo->Pipes[0].MaximumTransferSize = 0x00400000;
pInfo->Pipes[0].MaximumPacketSize = 0x20;
pInfo->Pipes[0].EndpointAddress = 0x81;
pInfo->Pipes[0].Interval = 0x04;
pInfo->Pipes[0].PipeType = (USBD_PIPE_TYPE)0x03;
pInfo->Pipes[0].PipeHandle = (USBD_PIPE_HANDLE)0xFFFF0081;
pInfo->Pipes[0].PipeFlags = 0x00;
pInfo->Pipes[1].MaximumTransferSize = 0x00400000;
pInfo->Pipes[1].MaximumPacketSize = 0x20;
pInfo->Pipes[1].EndpointAddress = 0x01;
pInfo->Pipes[1].Interval = 0x08;
pInfo->Pipes[1].PipeType = (USBD_PIPE_TYPE)0x03;
pInfo->Pipes[1].PipeHandle = (USBD_PIPE_HANDLE)0xFFFF0001;
pInfo->Pipes[1].PipeFlags = 0x00;
pInfo = (PUSBD_INTERFACE_INFORMATION)((PCHAR)pInfo + pInfo->Length);
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_XUSB,
">> >> >> 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 = 0xFF;
pInfo->SubClass = 0x5D;
pInfo->Protocol = 0x03;
pInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)0xFFFF0000;
pInfo->Pipes[0].MaximumTransferSize = 0x00400000;
pInfo->Pipes[0].MaximumPacketSize = 0x20;
pInfo->Pipes[0].EndpointAddress = 0x82;
pInfo->Pipes[0].Interval = 0x04;
pInfo->Pipes[0].PipeType = (USBD_PIPE_TYPE)0x03;
pInfo->Pipes[0].PipeHandle = (USBD_PIPE_HANDLE)0xFFFF0082;
pInfo->Pipes[0].PipeFlags = 0x00;
pInfo->Pipes[1].MaximumTransferSize = 0x00400000;
pInfo->Pipes[1].MaximumPacketSize = 0x20;
pInfo->Pipes[1].EndpointAddress = 0x02;
pInfo->Pipes[1].Interval = 0x08;
pInfo->Pipes[1].PipeType = (USBD_PIPE_TYPE)0x03;
pInfo->Pipes[1].PipeHandle = (USBD_PIPE_HANDLE)0xFFFF0002;
pInfo->Pipes[1].PipeFlags = 0x00;
pInfo->Pipes[2].MaximumTransferSize = 0x00400000;
pInfo->Pipes[2].MaximumPacketSize = 0x20;
pInfo->Pipes[2].EndpointAddress = 0x83;
pInfo->Pipes[2].Interval = 0x08;
pInfo->Pipes[2].PipeType = (USBD_PIPE_TYPE)0x03;
pInfo->Pipes[2].PipeHandle = (USBD_PIPE_HANDLE)0xFFFF0083;
pInfo->Pipes[2].PipeFlags = 0x00;
pInfo->Pipes[3].MaximumTransferSize = 0x00400000;
pInfo->Pipes[3].MaximumPacketSize = 0x20;
pInfo->Pipes[3].EndpointAddress = 0x03;
pInfo->Pipes[3].Interval = 0x08;
pInfo->Pipes[3].PipeType = (USBD_PIPE_TYPE)0x03;
pInfo->Pipes[3].PipeHandle = (USBD_PIPE_HANDLE)0xFFFF0003;
pInfo->Pipes[3].PipeFlags = 0x00;
pInfo = (PUSBD_INTERFACE_INFORMATION)((PCHAR)pInfo + pInfo->Length);
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_XUSB,
">> >> >> 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 = 0xFF;
pInfo->SubClass = 0x5D;
pInfo->Protocol = 0x02;
pInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)0xFFFF0000;
pInfo->Pipes[0].MaximumTransferSize = 0x00400000;
pInfo->Pipes[0].MaximumPacketSize = 0x20;
pInfo->Pipes[0].EndpointAddress = 0x84;
pInfo->Pipes[0].Interval = 0x04;
pInfo->Pipes[0].PipeType = (USBD_PIPE_TYPE)0x03;
pInfo->Pipes[0].PipeHandle = (USBD_PIPE_HANDLE)0xFFFF0084;
pInfo->Pipes[0].PipeFlags = 0x00;
pInfo = (PUSBD_INTERFACE_INFORMATION)((PCHAR)pInfo + pInfo->Length);
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_XUSB,
">> >> >> 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 = 0xFF;
pInfo->SubClass = 0xFD;
pInfo->Protocol = 0x13;
pInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)0xFFFF0000;
}

119
sys/XusbPdo.hpp Normal file
View File

@@ -0,0 +1,119 @@
#pragma once
#include "EmulationTargetPDO.hpp"
namespace ViGEm::Bus::Targets
{
constexpr auto XUSB_POOL_TAG = 'EGiV';
typedef struct _XUSB_REPORT
{
USHORT wButtons;
BYTE bLeftTrigger;
BYTE bRightTrigger;
SHORT sThumbLX;
SHORT sThumbLY;
SHORT sThumbRX;
SHORT sThumbRY;
} XUSB_REPORT, * PXUSB_REPORT;
typedef struct _XUSB_INTERRUPT_IN_PACKET
{
UCHAR Id;
UCHAR Size;
XUSB_REPORT Report;
} XUSB_INTERRUPT_IN_PACKET, * PXUSB_INTERRUPT_IN_PACKET;
//
// XUSB-specific device context data.
//
typedef struct _XUSB_DEVICE_DATA
{
//
// Rumble buffer
//
UCHAR Rumble[0x08];
//
// LED number (represents XInput slot index)
//
CHAR LedNumber;
//
// Report packet
//
XUSB_INTERRUPT_IN_PACKET Packet;
//
// Queue for incoming control interrupt transfer
//
WDFQUEUE HoldingUsbInRequests;
//
// Required for XInputGetCapabilities to work
//
BOOLEAN ReportedCapabilities;
//
// Required for XInputGetCapabilities to work
//
ULONG InterruptInitStage;
//
// Storage of binary blobs (packets) for PDO initialization
//
WDFMEMORY InterruptBlobStorage;
} XUSB_DEVICE_DATA, * PXUSB_DEVICE_DATA;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(XUSB_DEVICE_DATA, XusbPdoGetContext)
class EmulationTargetXUSB : public Core::EmulationTargetPDO
{
public:
EmulationTargetXUSB() = default;
~EmulationTargetXUSB() = default;
NTSTATUS PrepareDevice(PWDFDEVICE_INIT DeviceInit, USHORT VendorId, USHORT ProductId,
PUNICODE_STRING DeviceId, PUNICODE_STRING DeviceDescription);
NTSTATUS PrepareHardware(WDFDEVICE Device);
NTSTATUS InitContext(WDFDEVICE Device);
VOID GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length);
VOID GetDeviceDescriptorType(PUSB_DEVICE_DESCRIPTOR pDescriptor, USHORT VendorId, USHORT ProductId);
VOID SelectConfiguration(PUSBD_INTERFACE_INFORMATION pInfo);
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 XUSB_BLOB_00_OFFSET = 0x00;
static const int XUSB_BLOB_01_OFFSET = 0x03;
static const int XUSB_BLOB_02_OFFSET = 0x06;
static const int XUSB_BLOB_03_OFFSET = 0x09;
static const int XUSB_BLOB_04_OFFSET = 0x0C;
static const int XUSB_BLOB_05_OFFSET = 0x20;
static const int XUSB_BLOB_06_OFFSET = 0x23;
static const int XUSB_BLOB_07_OFFSET = 0x26;
};
}

View File

@@ -29,6 +29,8 @@
#include <wdmguid.h>
#include "xusb.tmh"
EXTERN_C_START
NTSTATUS Xusb_PreparePdo(
PWDFDEVICE_INIT DeviceInit,
USHORT VendorId,
@@ -637,3 +639,5 @@ NTSTATUS Xusb_GetUserIndex(WDFDEVICE Device, PXUSB_GET_USER_INDEX Request)
return status;
}
EXTERN_C_END