mirror of
https://github.com/nefarius/ViGEmBus.git
synced 2025-08-10 00:52:17 +00:00
Ported majority of XUSB stuff over to C++
This commit is contained in:
38
sys/CRTCPP.hpp
Normal file
38
sys/CRTCPP.hpp
Normal 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
|
||||
58
sys/EmulationTargetPDO.cpp
Normal file
58
sys/EmulationTargetPDO.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
60
sys/EmulationTargetPDO.hpp
Normal file
60
sys/EmulationTargetPDO.hpp
Normal 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
BIN
sys/RCa08996
Normal file
Binary file not shown.
@@ -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">
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
574
sys/XusbPdo.cpp
Normal 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
119
sys/XusbPdo.hpp
Normal 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;
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user