Further porting over stuff

This commit is contained in:
Benjamin Höglinger-Stelzer
2020-05-10 17:03:01 +02:00
parent 5864b91c09
commit 6ebef069d5
6 changed files with 377 additions and 73 deletions

View File

@@ -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);
}

View File

@@ -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)
}

View File

@@ -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;
};
}

View File

@@ -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

View File

@@ -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,

View File

@@ -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)
}