mirror of
https://github.com/nefarius/ViGEmBus.git
synced 2025-08-10 00:52:17 +00:00
Further porting over stuff
This commit is contained in:
234
sys/Ds4Pdo.cpp
234
sys/Ds4Pdo.cpp
@@ -3,6 +3,7 @@
|
||||
#include "Ds4Pdo.tmh"
|
||||
#define NTSTRSAFE_LIB
|
||||
#include <ntstrsafe.h>
|
||||
#include <hidclass.h>
|
||||
|
||||
|
||||
using namespace ViGEm::Bus::Targets;
|
||||
@@ -101,16 +102,230 @@ NTSTATUS EmulationTargetDS4::PrepareDevice(PWDFDEVICE_INIT DeviceInit, USHORT Ve
|
||||
|
||||
NTSTATUS EmulationTargetDS4::PrepareHardware(WDFDEVICE Device)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Device);
|
||||
|
||||
return NTSTATUS();
|
||||
WDF_QUERY_INTERFACE_CONFIG ifaceCfg;
|
||||
INTERFACE devinterfaceHid;
|
||||
|
||||
devinterfaceHid.Size = sizeof(INTERFACE);
|
||||
devinterfaceHid.Version = 1;
|
||||
devinterfaceHid.Context = (PVOID)Device;
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
NTSTATUS status = WdfDeviceAddQueryInterface(Device, &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
|
||||
};
|
||||
|
||||
// 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);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS EmulationTargetDS4::InitContext(WDFDEVICE Device)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Device);
|
||||
|
||||
return NTSTATUS();
|
||||
NTSTATUS status;
|
||||
|
||||
// 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);
|
||||
|
||||
// PDO is parent
|
||||
timerAttribs.ParentObject = Device;
|
||||
|
||||
// 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
|
||||
|
||||
// TODO: tidy up this region
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
RtlUnicodeStringInit(&valueName, L"TargetMacAddress");
|
||||
|
||||
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);
|
||||
|
||||
if (status == STATUS_OBJECT_NAME_NOT_FOUND)
|
||||
{
|
||||
GenerateRandomMacAddress(&this->TargetMacAddress);
|
||||
|
||||
status = WdfRegistryAssignValue(
|
||||
keySerial,
|
||||
&valueName,
|
||||
REG_BINARY,
|
||||
sizeof(MAC_ADDRESS),
|
||||
static_cast<PVOID>(&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);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID EmulationTargetDS4::GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length)
|
||||
@@ -216,3 +431,10 @@ VOID EmulationTargetDS4::SelectConfiguration(PUSBD_INTERFACE_INFORMATION pInfo)
|
||||
pInfo->Pipes[1].PipeHandle = (USBD_PIPE_HANDLE)0xFFFF0003;
|
||||
pInfo->Pipes[1].PipeFlags = 0x00;
|
||||
}
|
||||
|
||||
VOID EmulationTargetDS4::PendingUsbRequestsTimerFunc(
|
||||
_In_ WDFTIMER Timer
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Timer);
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
|
||||
#include "EmulationTargetPDO.hpp"
|
||||
#include <ViGEm/km/BusShared.h>
|
||||
#include "Util.h"
|
||||
|
||||
namespace ViGEm::Bus::Targets
|
||||
{
|
||||
|
||||
|
||||
{
|
||||
class EmulationTargetDS4 : public Core::EmulationTargetPDO
|
||||
{
|
||||
public:
|
||||
@@ -28,7 +28,7 @@ namespace ViGEm::Bus::Targets
|
||||
|
||||
private:
|
||||
static PCWSTR _deviceDescription;
|
||||
|
||||
|
||||
#if defined(_X86_)
|
||||
static const int XUSB_CONFIGURATION_SIZE = 0x00E4;
|
||||
#else
|
||||
@@ -70,5 +70,43 @@ namespace ViGEm::Bus::Targets
|
||||
|
||||
static const int DS4_REPORT_SIZE = 0x40;
|
||||
static const int DS4_QUEUE_FLUSH_PERIOD = 0x05;
|
||||
|
||||
//
|
||||
// HID Input Report buffer
|
||||
//
|
||||
UCHAR Report[DS4_REPORT_SIZE];
|
||||
|
||||
//
|
||||
// Output report cache
|
||||
//
|
||||
DS4_OUTPUT_REPORT OutputReport;
|
||||
|
||||
//
|
||||
// Timer for dispatching interrupt transfer
|
||||
//
|
||||
WDFTIMER PendingUsbInRequestsTimer;
|
||||
|
||||
//
|
||||
// Auto-generated MAC address of the target device
|
||||
//
|
||||
MAC_ADDRESS TargetMacAddress;
|
||||
|
||||
//
|
||||
// Default MAC address of the host (not used)
|
||||
//
|
||||
MAC_ADDRESS HostMacAddress;
|
||||
|
||||
static EVT_WDF_TIMER PendingUsbRequestsTimerFunc;
|
||||
};
|
||||
|
||||
//
|
||||
// DS4-specific device context data.
|
||||
//
|
||||
typedef struct _DS4_PDO_CONTEXT
|
||||
{
|
||||
EmulationTargetDS4* Context;
|
||||
|
||||
} DS4_PDO_CONTEXT, * PDS4_PDO_CONTEXT;
|
||||
|
||||
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DS4_PDO_CONTEXT, Ds4PdoGetContext)
|
||||
}
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
|
||||
#include <ntddk.h>
|
||||
#include <wdf.h>
|
||||
#include <ntintsafe.h>
|
||||
|
||||
#include <usb.h>
|
||||
#include <usbbusif.h>
|
||||
|
||||
#include <ViGEm/Common.h>
|
||||
|
||||
//
|
||||
// Some insane macro-magic =3
|
||||
//
|
||||
@@ -56,5 +59,40 @@ namespace ViGEm::Bus::Core
|
||||
IN OUT PUSBD_VERSION_INFORMATION VersionInformation,
|
||||
IN OUT PULONG HcdCapabilities
|
||||
);
|
||||
|
||||
//
|
||||
// Unique serial number of the device on the bus
|
||||
//
|
||||
ULONG SerialNo;
|
||||
|
||||
//
|
||||
// PID of the process creating this PDO
|
||||
//
|
||||
DWORD OwnerProcessId;
|
||||
|
||||
//
|
||||
// Device type this PDO is emulating
|
||||
//
|
||||
VIGEM_TARGET_TYPE TargetType;
|
||||
|
||||
//
|
||||
// If set, the vendor ID the emulated device is reporting
|
||||
//
|
||||
USHORT VendorId;
|
||||
|
||||
//
|
||||
// If set, the product ID the emulated device is reporting
|
||||
//
|
||||
USHORT ProductId;
|
||||
|
||||
//
|
||||
// Queue for incoming data interrupt transfer
|
||||
//
|
||||
WDFQUEUE PendingUsbInRequests;
|
||||
|
||||
//
|
||||
// Queue for inverted calls
|
||||
//
|
||||
WDFQUEUE PendingNotificationRequests;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -48,5 +48,9 @@ typedef struct _MAC_ADDRESS
|
||||
} MAC_ADDRESS, *PMAC_ADDRESS;
|
||||
|
||||
|
||||
EXTERN_C_START
|
||||
|
||||
VOID ReverseByteArray(PUCHAR Array, INT Length);
|
||||
VOID GenerateRandomMacAddress(PMAC_ADDRESS Address);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
@@ -224,22 +224,26 @@ NTSTATUS EmulationTargetXUSB::InitContext(WDFDEVICE Device)
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_XUSB, "Initializing XUSB context...");
|
||||
|
||||
PXUSB_DEVICE_DATA xusb = XusbPdoGetContext(Device);
|
||||
|
||||
RtlZeroMemory(xusb, sizeof(XUSB_DEVICE_DATA));
|
||||
|
||||
RtlZeroMemory(this->Rumble, ARRAYSIZE(this->Rumble));
|
||||
|
||||
// Is later overwritten by actual XInput slot
|
||||
xusb->LedNumber = -1;
|
||||
this->LedNumber = -1;
|
||||
|
||||
RtlZeroMemory(&this->Packet, sizeof(XUSB_INTERRUPT_IN_PACKET));
|
||||
// Packet size (20 bytes = 0x14)
|
||||
xusb->Packet.Size = 0x14;
|
||||
this->Packet.Size = 0x14;
|
||||
|
||||
this->ReportedCapabilities = FALSE;
|
||||
|
||||
this->InterruptInitStage = 0;
|
||||
|
||||
// Allocate blob storage
|
||||
NTSTATUS status = WdfMemoryCreate(
|
||||
&attributes,
|
||||
NonPagedPoolNx,
|
||||
XUSB_POOL_TAG,
|
||||
XUSB_BLOB_STORAGE_SIZE,
|
||||
&xusb->InterruptBlobStorage,
|
||||
&this->InterruptBlobStorage,
|
||||
reinterpret_cast<PVOID*>(&blobBuffer)
|
||||
);
|
||||
if (!NT_SUCCESS(status))
|
||||
@@ -279,7 +283,12 @@ NTSTATUS EmulationTargetXUSB::InitContext(WDFDEVICE Device)
|
||||
// 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);
|
||||
status = WdfIoQueueCreate(
|
||||
Device,
|
||||
&holdingInQueueConfig,
|
||||
WDF_NO_OBJECT_ATTRIBUTES,
|
||||
&this->HoldingUsbInRequests
|
||||
);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
|
||||
103
sys/XusbPdo.hpp
103
sys/XusbPdo.hpp
@@ -2,23 +2,12 @@
|
||||
|
||||
|
||||
#include "EmulationTargetPDO.hpp"
|
||||
#include <ViGEm/km/BusShared.h>
|
||||
|
||||
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;
|
||||
@@ -29,49 +18,7 @@ namespace ViGEm::Bus::Targets
|
||||
|
||||
} 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
|
||||
{
|
||||
@@ -115,5 +62,51 @@ namespace ViGEm::Bus::Targets
|
||||
static const int XUSB_BLOB_05_OFFSET = 0x20;
|
||||
static const int XUSB_BLOB_06_OFFSET = 0x23;
|
||||
static const int XUSB_BLOB_07_OFFSET = 0x26;
|
||||
|
||||
//
|
||||
// Rumble buffer
|
||||
//
|
||||
UCHAR Rumble[XUSB_RUMBLE_SIZE];
|
||||
|
||||
//
|
||||
// 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-specific device context data.
|
||||
//
|
||||
typedef struct _XUSB_PDO_CONTEXT
|
||||
{
|
||||
EmulationTargetXUSB* Context;
|
||||
|
||||
} XUSB_PDO_CONTEXT, * PXUSB_PDO_CONTEXT;
|
||||
|
||||
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(XUSB_PDO_CONTEXT, XusbPdoGetContext)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user