Added IOCTL_DS4_AWAIT_OUTPUT

Added DMF support to PDO
This commit is contained in:
Benjamin Höglinger-Stelzer
2022-08-06 11:50:26 +02:00
parent dbe41ff10f
commit 9441b25e0c
11 changed files with 605 additions and 353 deletions

View File

@@ -1,2 +1,4 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=PEMULATION/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=PPDO/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Xusb/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -31,7 +31,7 @@ SOFTWARE.
//
// {96E42B22-F5E9-42F8-B043-ED0F932F014F}
DEFINE_GUID(GUID_DEVINTERFACE_BUSENUM_VIGEM,
0x96E42B22, 0xF5E9, 0x42F8, 0xB0, 0x43, 0xED, 0x0F, 0x93, 0x2F, 0x01, 0x4F);
0x96E42B22, 0xF5E9, 0x42F8, 0xB0, 0x43, 0xED, 0x0F, 0x93, 0x2F, 0x01, 0x4F);
#pragma once
@@ -71,6 +71,7 @@ DEFINE_GUID(GUID_DEVINTERFACE_BUSENUM_VIGEM,
//#define IOCTL_XGIP_SUBMIT_REPORT BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x204)
//#define IOCTL_XGIP_SUBMIT_INTERRUPT BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x205)
#define IOCTL_XUSB_GET_USER_INDEX BUSENUM_RW_IOCTL(IOCTL_VIGEM_BASE + 0x206)
#define IOCTL_DS4_AWAIT_OUTPUT BUSENUM_RW_IOCTL(IOCTL_VIGEM_BASE + 0x207)
//
@@ -84,47 +85,47 @@ DEFINE_GUID(GUID_DEVINTERFACE_BUSENUM_VIGEM,
//
typedef struct _VIGEM_PLUGIN_TARGET
{
//
// sizeof (struct _BUSENUM_HARDWARE)
//
IN ULONG Size;
//
// sizeof (struct _BUSENUM_HARDWARE)
//
IN ULONG Size;
//
// Serial number of target device.
//
IN ULONG SerialNo;
//
// Serial number of target device.
//
IN ULONG SerialNo;
//
// Type of the target device to emulate.
//
VIGEM_TARGET_TYPE TargetType;
//
// Type of the target device to emulate.
//
VIGEM_TARGET_TYPE TargetType;
//
// If set, the vendor ID the emulated device is reporting
//
USHORT VendorId;
//
// If set, the vendor ID the emulated device is reporting
//
USHORT VendorId;
//
// If set, the product ID the emulated device is reporting
//
USHORT ProductId;
//
// If set, the product ID the emulated device is reporting
//
USHORT ProductId;
} VIGEM_PLUGIN_TARGET, *PVIGEM_PLUGIN_TARGET;
} VIGEM_PLUGIN_TARGET, * PVIGEM_PLUGIN_TARGET;
//
// Initializes a VIGEM_PLUGIN_TARGET structure.
//
VOID FORCEINLINE VIGEM_PLUGIN_TARGET_INIT(
_Out_ PVIGEM_PLUGIN_TARGET PlugIn,
_In_ ULONG SerialNo,
_In_ VIGEM_TARGET_TYPE TargetType
_Out_ PVIGEM_PLUGIN_TARGET PlugIn,
_In_ ULONG SerialNo,
_In_ VIGEM_TARGET_TYPE TargetType
)
{
RtlZeroMemory(PlugIn, sizeof(VIGEM_PLUGIN_TARGET));
RtlZeroMemory(PlugIn, sizeof(VIGEM_PLUGIN_TARGET));
PlugIn->Size = sizeof(VIGEM_PLUGIN_TARGET);
PlugIn->SerialNo = SerialNo;
PlugIn->TargetType = TargetType;
PlugIn->Size = sizeof(VIGEM_PLUGIN_TARGET);
PlugIn->SerialNo = SerialNo;
PlugIn->TargetType = TargetType;
}
#pragma endregion
@@ -136,30 +137,30 @@ VOID FORCEINLINE VIGEM_PLUGIN_TARGET_INIT(
//
typedef struct _VIGEM_UNPLUG_TARGET
{
//
// sizeof (struct _REMOVE_HARDWARE)
//
IN ULONG Size;
//
// sizeof (struct _REMOVE_HARDWARE)
//
IN ULONG Size;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// Serial number of target device.
//
ULONG SerialNo;
} VIGEM_UNPLUG_TARGET, *PVIGEM_UNPLUG_TARGET;
} VIGEM_UNPLUG_TARGET, * PVIGEM_UNPLUG_TARGET;
//
// Initializes a VIGEM_UNPLUG_TARGET structure.
//
VOID FORCEINLINE VIGEM_UNPLUG_TARGET_INIT(
_Out_ PVIGEM_UNPLUG_TARGET UnPlug,
_In_ ULONG SerialNo
_Out_ PVIGEM_UNPLUG_TARGET UnPlug,
_In_ ULONG SerialNo
)
{
RtlZeroMemory(UnPlug, sizeof(VIGEM_UNPLUG_TARGET));
RtlZeroMemory(UnPlug, sizeof(VIGEM_UNPLUG_TARGET));
UnPlug->Size = sizeof(VIGEM_UNPLUG_TARGET);
UnPlug->SerialNo = SerialNo;
UnPlug->Size = sizeof(VIGEM_UNPLUG_TARGET);
UnPlug->SerialNo = SerialNo;
}
#pragma endregion
@@ -168,21 +169,21 @@ VOID FORCEINLINE VIGEM_UNPLUG_TARGET_INIT(
typedef struct _VIGEM_CHECK_VERSION
{
IN ULONG Size;
IN ULONG Size;
IN ULONG Version;
IN ULONG Version;
} VIGEM_CHECK_VERSION, *PVIGEM_CHECK_VERSION;
} VIGEM_CHECK_VERSION, * PVIGEM_CHECK_VERSION;
VOID FORCEINLINE VIGEM_CHECK_VERSION_INIT(
_Out_ PVIGEM_CHECK_VERSION CheckVersion,
_In_ ULONG Version
_Out_ PVIGEM_CHECK_VERSION CheckVersion,
_In_ ULONG Version
)
{
RtlZeroMemory(CheckVersion, sizeof(VIGEM_CHECK_VERSION));
RtlZeroMemory(CheckVersion, sizeof(VIGEM_CHECK_VERSION));
CheckVersion->Size = sizeof(VIGEM_CHECK_VERSION);
CheckVersion->Version = Version;
CheckVersion->Size = sizeof(VIGEM_CHECK_VERSION);
CheckVersion->Version = Version;
}
#pragma endregion
@@ -191,21 +192,21 @@ VOID FORCEINLINE VIGEM_CHECK_VERSION_INIT(
typedef struct _VIGEM_WAIT_DEVICE_READY
{
IN ULONG Size;
IN ULONG Size;
IN ULONG SerialNo;
IN ULONG SerialNo;
} VIGEM_WAIT_DEVICE_READY, * PVIGEM_WAIT_DEVICE_READY;
VOID FORCEINLINE VIGEM_WAIT_DEVICE_READY_INIT(
_Out_ PVIGEM_WAIT_DEVICE_READY WaitReady,
_In_ ULONG SerialNo
_Out_ PVIGEM_WAIT_DEVICE_READY WaitReady,
_In_ ULONG SerialNo
)
{
RtlZeroMemory(WaitReady, sizeof(VIGEM_WAIT_DEVICE_READY));
RtlZeroMemory(WaitReady, sizeof(VIGEM_WAIT_DEVICE_READY));
WaitReady->Size = sizeof(VIGEM_WAIT_DEVICE_READY);
WaitReady->SerialNo = SerialNo;
WaitReady->Size = sizeof(VIGEM_WAIT_DEVICE_READY);
WaitReady->SerialNo = SerialNo;
}
#pragma endregion
@@ -217,45 +218,45 @@ VOID FORCEINLINE VIGEM_WAIT_DEVICE_READY_INIT(
//
typedef struct _XUSB_REQUEST_NOTIFICATION
{
//
// sizeof(struct _XUSB_REQUEST_NOTIFICATION)
//
ULONG Size;
//
// sizeof(struct _XUSB_REQUEST_NOTIFICATION)
//
ULONG Size;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// Vibration intensity value of the large motor (0-255).
//
UCHAR LargeMotor;
//
// Vibration intensity value of the large motor (0-255).
//
UCHAR LargeMotor;
//
// Vibration intensity value of the small motor (0-255).
//
UCHAR SmallMotor;
//
// Vibration intensity value of the small motor (0-255).
//
UCHAR SmallMotor;
//
// Index number of the slot/LED that XUSB.sys has assigned.
//
UCHAR LedNumber;
//
// Index number of the slot/LED that XUSB.sys has assigned.
//
UCHAR LedNumber;
} XUSB_REQUEST_NOTIFICATION, *PXUSB_REQUEST_NOTIFICATION;
} XUSB_REQUEST_NOTIFICATION, * PXUSB_REQUEST_NOTIFICATION;
//
// Initializes a XUSB_REQUEST_NOTIFICATION structure.
//
VOID FORCEINLINE XUSB_REQUEST_NOTIFICATION_INIT(
_Out_ PXUSB_REQUEST_NOTIFICATION Request,
_In_ ULONG SerialNo
_Out_ PXUSB_REQUEST_NOTIFICATION Request,
_In_ ULONG SerialNo
)
{
RtlZeroMemory(Request, sizeof(XUSB_REQUEST_NOTIFICATION));
RtlZeroMemory(Request, sizeof(XUSB_REQUEST_NOTIFICATION));
Request->Size = sizeof(XUSB_REQUEST_NOTIFICATION);
Request->SerialNo = SerialNo;
Request->Size = sizeof(XUSB_REQUEST_NOTIFICATION);
Request->SerialNo = SerialNo;
}
//
@@ -263,68 +264,68 @@ VOID FORCEINLINE XUSB_REQUEST_NOTIFICATION_INIT(
//
typedef struct _XUSB_SUBMIT_REPORT
{
//
// sizeof(struct _XUSB_SUBMIT_REPORT)
//
ULONG Size;
//
// sizeof(struct _XUSB_SUBMIT_REPORT)
//
ULONG Size;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// Report to submit to the target device.
//
XUSB_REPORT Report;
//
// Report to submit to the target device.
//
XUSB_REPORT Report;
} XUSB_SUBMIT_REPORT, *PXUSB_SUBMIT_REPORT;
} XUSB_SUBMIT_REPORT, * PXUSB_SUBMIT_REPORT;
//
// Initializes an XUSB report.
//
VOID FORCEINLINE XUSB_SUBMIT_REPORT_INIT(
_Out_ PXUSB_SUBMIT_REPORT Report,
_In_ ULONG SerialNo
_Out_ PXUSB_SUBMIT_REPORT Report,
_In_ ULONG SerialNo
)
{
RtlZeroMemory(Report, sizeof(XUSB_SUBMIT_REPORT));
RtlZeroMemory(Report, sizeof(XUSB_SUBMIT_REPORT));
Report->Size = sizeof(XUSB_SUBMIT_REPORT);
Report->SerialNo = SerialNo;
Report->Size = sizeof(XUSB_SUBMIT_REPORT);
Report->SerialNo = SerialNo;
}
typedef struct _XUSB_GET_USER_INDEX
{
//
// sizeof(struct _XUSB_GET_USER_INDEX)
//
ULONG Size;
//
// sizeof(struct _XUSB_GET_USER_INDEX)
//
ULONG Size;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// User index of target device.
//
OUT ULONG UserIndex;
//
// User index of target device.
//
OUT ULONG UserIndex;
} XUSB_GET_USER_INDEX, *PXUSB_GET_USER_INDEX;
} XUSB_GET_USER_INDEX, * PXUSB_GET_USER_INDEX;
//
// Initializes XUSB_GET_USER_INDEX structure.
//
VOID FORCEINLINE XUSB_GET_USER_INDEX_INIT(
_Out_ PXUSB_GET_USER_INDEX GetRequest,
_In_ ULONG SerialNo
_Out_ PXUSB_GET_USER_INDEX GetRequest,
_In_ ULONG SerialNo
)
{
RtlZeroMemory(GetRequest, sizeof(XUSB_GET_USER_INDEX));
RtlZeroMemory(GetRequest, sizeof(XUSB_GET_USER_INDEX));
GetRequest->Size = sizeof(XUSB_GET_USER_INDEX);
GetRequest->SerialNo = SerialNo;
GetRequest->Size = sizeof(XUSB_GET_USER_INDEX);
GetRequest->SerialNo = SerialNo;
}
#pragma endregion
@@ -333,57 +334,57 @@ VOID FORCEINLINE XUSB_GET_USER_INDEX_INIT(
typedef struct _DS4_OUTPUT_REPORT
{
//
// Vibration intensity value of the small motor (0-255).
//
UCHAR SmallMotor;
//
// Vibration intensity value of the small motor (0-255).
//
UCHAR SmallMotor;
//
// Vibration intensity value of the large motor (0-255).
//
UCHAR LargeMotor;
//
// Vibration intensity value of the large motor (0-255).
//
UCHAR LargeMotor;
//
// Color values of the Lightbar.
//
DS4_LIGHTBAR_COLOR LightbarColor;
//
// Color values of the Lightbar.
//
DS4_LIGHTBAR_COLOR LightbarColor;
} DS4_OUTPUT_REPORT, *PDS4_OUTPUT_REPORT;
} DS4_OUTPUT_REPORT, * PDS4_OUTPUT_REPORT;
//
// Data structure used in IOCTL_DS4_REQUEST_NOTIFICATION requests.
//
typedef struct _DS4_REQUEST_NOTIFICATION
{
//
// sizeof(struct _XUSB_REQUEST_NOTIFICATION)
//
ULONG Size;
//
// sizeof(struct _XUSB_REQUEST_NOTIFICATION)
//
ULONG Size;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// The HID output report
//
DS4_OUTPUT_REPORT Report;
//
// The HID output report
//
DS4_OUTPUT_REPORT Report;
} DS4_REQUEST_NOTIFICATION, *PDS4_REQUEST_NOTIFICATION;
} DS4_REQUEST_NOTIFICATION, * PDS4_REQUEST_NOTIFICATION;
//
// Initializes a DS4_REQUEST_NOTIFICATION structure.
//
VOID FORCEINLINE DS4_REQUEST_NOTIFICATION_INIT(
_Out_ PDS4_REQUEST_NOTIFICATION Request,
_In_ ULONG SerialNo
_Out_ PDS4_REQUEST_NOTIFICATION Request,
_In_ ULONG SerialNo
)
{
RtlZeroMemory(Request, sizeof(DS4_REQUEST_NOTIFICATION));
RtlZeroMemory(Request, sizeof(DS4_REQUEST_NOTIFICATION));
Request->Size = sizeof(DS4_REQUEST_NOTIFICATION);
Request->SerialNo = SerialNo;
Request->Size = sizeof(DS4_REQUEST_NOTIFICATION);
Request->SerialNo = SerialNo;
}
//
@@ -391,37 +392,37 @@ VOID FORCEINLINE DS4_REQUEST_NOTIFICATION_INIT(
//
typedef struct _DS4_SUBMIT_REPORT
{
//
// sizeof(struct _DS4_SUBMIT_REPORT)
//
ULONG Size;
//
// sizeof(struct _DS4_SUBMIT_REPORT)
//
ULONG Size;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// HID Input report
//
DS4_REPORT Report;
//
// HID Input report
//
DS4_REPORT Report;
} DS4_SUBMIT_REPORT, *PDS4_SUBMIT_REPORT;
} DS4_SUBMIT_REPORT, * PDS4_SUBMIT_REPORT;
//
// Initializes a DualShock 4 report.
//
VOID FORCEINLINE DS4_SUBMIT_REPORT_INIT(
_Out_ PDS4_SUBMIT_REPORT Report,
_In_ ULONG SerialNo
_Out_ PDS4_SUBMIT_REPORT Report,
_In_ ULONG SerialNo
)
{
RtlZeroMemory(Report, sizeof(DS4_SUBMIT_REPORT));
RtlZeroMemory(Report, sizeof(DS4_SUBMIT_REPORT));
Report->Size = sizeof(DS4_SUBMIT_REPORT);
Report->SerialNo = SerialNo;
Report->Size = sizeof(DS4_SUBMIT_REPORT);
Report->SerialNo = SerialNo;
DS4_REPORT_INIT(&Report->Report);
DS4_REPORT_INIT(&Report->Report);
}
#include <pshpack1.h>
@@ -431,20 +432,20 @@ VOID FORCEINLINE DS4_SUBMIT_REPORT_INIT(
//
typedef struct _DS4_SUBMIT_REPORT_EX
{
//
// sizeof(struct _DS4_SUBMIT_REPORT_EX)
//
_In_ ULONG Size;
//
// sizeof(struct _DS4_SUBMIT_REPORT_EX)
//
_In_ ULONG Size;
//
// Serial number of target device.
//
_In_ ULONG SerialNo;
//
// Serial number of target device.
//
_In_ ULONG SerialNo;
//
// Full size HID report excluding fixed Report ID.
//
_In_ DS4_REPORT_EX Report;
//
// Full size HID report excluding fixed Report ID.
//
_In_ DS4_REPORT_EX Report;
} DS4_SUBMIT_REPORT_EX, * PDS4_SUBMIT_REPORT_EX;
@@ -454,14 +455,53 @@ typedef struct _DS4_SUBMIT_REPORT_EX
// Initializes a DualShock 4 extended report.
//
VOID FORCEINLINE DS4_SUBMIT_REPORT_EX_INIT(
_Out_ PDS4_SUBMIT_REPORT_EX Report,
_In_ ULONG SerialNo
_Out_ PDS4_SUBMIT_REPORT_EX Report,
_In_ ULONG SerialNo
)
{
RtlZeroMemory(Report, sizeof(DS4_SUBMIT_REPORT_EX));
RtlZeroMemory(Report, sizeof(DS4_SUBMIT_REPORT_EX));
Report->Size = sizeof(DS4_SUBMIT_REPORT_EX);
Report->SerialNo = SerialNo;
Report->Size = sizeof(DS4_SUBMIT_REPORT_EX);
Report->SerialNo = SerialNo;
}
#pragma endregion
typedef struct _DS4_AWAIT_OUTPUT_BUFFER
{
//
// The output report buffer
//
_Out_ UCHAR Buffer[64];
} DS4_AWAIT_OUTPUT_BUFFER, *PDS4_AWAIT_OUTPUT_BUFFER;
typedef struct _DS4_AWAIT_OUTPUT
{
//
// sizeof(struct _DS4_SUBMIT_REPORT_EX)
//
_In_ ULONG Size;
//
// Serial number of target device.
//
_In_ ULONG SerialNo;
//
// The output report buffer
//
_Out_ DS4_AWAIT_OUTPUT_BUFFER Report;
} DS4_AWAIT_OUTPUT, * PDS4_AWAIT_OUTPUT;
VOID FORCEINLINE DS4_AWAIT_OUTPUT_INIT(
_Out_ PDS4_AWAIT_OUTPUT Output,
_In_ ULONG SerialNo
)
{
RtlZeroMemory(Output, sizeof(DS4_AWAIT_OUTPUT));
Output->Size = sizeof(DS4_AWAIT_OUTPUT);
Output->SerialNo = SerialNo;
}

View File

@@ -70,6 +70,7 @@ IoctlHandler_IoctlRecord ViGEmBus_IoctlSpecification[] =
{IOCTL_DS4_SUBMIT_REPORT, sizeof(DS4_SUBMIT_REPORT), 0, Bus_Ds4SubmitReportHandler},
{IOCTL_DS4_REQUEST_NOTIFICATION, sizeof(DS4_REQUEST_NOTIFICATION), sizeof(DS4_REQUEST_NOTIFICATION), Bus_Ds4RequestNotificationHandler},
{IOCTL_XUSB_GET_USER_INDEX, sizeof(XUSB_GET_USER_INDEX), sizeof(XUSB_GET_USER_INDEX), Bus_XusbGetUserIndexHandler},
{IOCTL_DS4_AWAIT_OUTPUT, sizeof(DS4_AWAIT_OUTPUT), sizeof(DS4_AWAIT_OUTPUT), Bus_Ds4AwaitOutputHandler},
};
//

View File

@@ -144,7 +144,7 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::PdoPrepareDevice(PWDFDEVICE_IN
status);
return status;
}
return STATUS_SUCCESS;
}
@@ -192,162 +192,160 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::PdoInitContext()
// PDO is parent
timerAttribs.ParentObject = this->_PdoDevice;
// Create timer
status = WdfTimerCreate(
&timerConfig,
&timerAttribs,
&this->_PendingUsbInRequestsTimer
);
if (!NT_SUCCESS(status))
do
{
TraceError(
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))
{
TraceError(
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,
nullptr,
WDF_NO_OBJECT_ATTRIBUTES,
&keyTargets
);
if (!NT_SUCCESS(status))
{
TraceError(
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,
nullptr,
WDF_NO_OBJECT_ATTRIBUTES,
&keyDS
);
if (!NT_SUCCESS(status))
{
TraceError(
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,
nullptr,
WDF_NO_OBJECT_ATTRIBUTES,
&keySerial
);
if (!NT_SUCCESS(status))
{
TraceError(
TRACE_DS4,
"WdfRegistryCreateKey failed with status %!STATUS!",
status);
return status;
}
RtlUnicodeStringInit(&valueName, L"TargetMacAddress");
status = WdfRegistryQueryValue(
keySerial,
&valueName,
sizeof(MAC_ADDRESS),
&this->_TargetMacAddress,
nullptr,
nullptr
);
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))
// Create timer
if (!NT_SUCCESS(status = WdfTimerCreate(
&timerConfig,
&timerAttribs,
&this->_PendingUsbInRequestsTimer
)))
{
TraceError(
TRACE_DS4,
"WdfRegistryAssignValue failed with status %!STATUS!",
"WdfTimerCreate failed with status %!STATUS!",
status);
return status;
break;
}
}
else if (!NT_SUCCESS(status))
{
TraceError(
// Load/generate MAC address
//
// TODO: tidy up this region
//
WDFKEY keyParams, keyTargets, keyDS, keySerial;
UNICODE_STRING keyName, valueName;
if (!NT_SUCCESS(status = WdfDriverOpenParametersRegistryKey(
WdfGetDriver(),
STANDARD_RIGHTS_ALL,
WDF_NO_OBJECT_ATTRIBUTES,
&keyParams
)))
{
TraceError(
TRACE_DS4,
"WdfDriverOpenParametersRegistryKey failed with status %!STATUS!",
status);
break;
}
RtlUnicodeStringInit(&keyName, L"Targets");
if (!NT_SUCCESS(status = WdfRegistryCreateKey(
keyParams,
&keyName,
KEY_ALL_ACCESS,
REG_OPTION_NON_VOLATILE,
nullptr,
WDF_NO_OBJECT_ATTRIBUTES,
&keyTargets
)))
{
TraceError(
TRACE_DS4,
"WdfRegistryCreateKey failed with status %!STATUS!",
status);
break;
}
RtlUnicodeStringInit(&keyName, L"DualShock");
if (!NT_SUCCESS(status = WdfRegistryCreateKey(
keyTargets,
&keyName,
KEY_ALL_ACCESS,
REG_OPTION_NON_VOLATILE,
nullptr,
WDF_NO_OBJECT_ATTRIBUTES,
&keyDS
)))
{
TraceError(
TRACE_DS4,
"WdfRegistryCreateKey failed with status %!STATUS!",
status);
break;
}
DECLARE_UNICODE_STRING_SIZE(serialPath, 4);
RtlUnicodeStringPrintf(&serialPath, L"%04d", this->_SerialNo);
if (!NT_SUCCESS(status = WdfRegistryCreateKey(
keyDS,
&serialPath,
KEY_ALL_ACCESS,
REG_OPTION_NON_VOLATILE,
nullptr,
WDF_NO_OBJECT_ATTRIBUTES,
&keySerial
)))
{
TraceError(
TRACE_DS4,
"WdfRegistryCreateKey failed with status %!STATUS!",
status);
break;
}
RtlUnicodeStringInit(&valueName, L"TargetMacAddress");
status = WdfRegistryQueryValue(
keySerial,
&valueName,
sizeof(MAC_ADDRESS),
&this->_TargetMacAddress,
nullptr,
nullptr
);
TraceEvents(TRACE_LEVEL_INFORMATION,
TRACE_DS4,
"WdfRegistryQueryValue failed with status %!STATUS!",
status);
return status;
}
"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);
WdfRegistryClose(keySerial);
WdfRegistryClose(keyDS);
WdfRegistryClose(keyTargets);
WdfRegistryClose(keyParams);
if (status == STATUS_OBJECT_NAME_NOT_FOUND)
{
GenerateRandomMacAddress(&this->_TargetMacAddress);
return STATUS_SUCCESS;
if (!NT_SUCCESS(status = WdfRegistryAssignValue(
keySerial,
&valueName,
REG_BINARY,
sizeof(MAC_ADDRESS),
static_cast<PVOID>(&this->_TargetMacAddress)
)))
{
TraceError(
TRACE_DS4,
"WdfRegistryAssignValue failed with status %!STATUS!",
status);
break;
}
}
else if (!NT_SUCCESS(status))
{
TraceError(
TRACE_DS4,
"WdfRegistryQueryValue failed with status %!STATUS!",
status);
break;
}
WdfRegistryClose(keySerial);
WdfRegistryClose(keyDS);
WdfRegistryClose(keyTargets);
WdfRegistryClose(keyParams);
} while (FALSE);
return status;
}
VOID ViGEm::Bus::Targets::EmulationTargetDS4::GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length)
@@ -999,8 +997,8 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::UsbGetStringDescriptorType(PUR
NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::UsbBulkOrInterruptTransfer(_URB_BULK_OR_INTERRUPT_TRANSFER* pTransfer, WDFREQUEST Request)
{
NTSTATUS status = STATUS_SUCCESS;
WDFREQUEST notifyRequest;
NTSTATUS status = STATUS_SUCCESS;
WDFREQUEST notifyRequest;
// Data coming FROM us TO higher driver
if (pTransfer->TransferFlags & USBD_TRANSFER_DIRECTION_IN
@@ -1023,6 +1021,20 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::UsbBulkOrInterruptTransfer(_UR
static_cast<PUCHAR>(pTransfer->TransferBuffer) + DS4_OUTPUT_BUFFER_OFFSET,
DS4_OUTPUT_BUFFER_LENGTH);
if (!NT_SUCCESS(status = DMF_NotifyUserWithRequestMultiple_DataBroadcast(
this->_OutputReportNotify,
pTransfer->TransferBuffer,
sizeof(DS4_AWAIT_OUTPUT_BUFFER),
STATUS_SUCCESS
)))
{
TraceError(
TRACE_USBPDO,
"DMF_NotifyUserWithRequestMultiple_DataBroadcast failed with status %!STATUS!",
status
);
}
if (NT_SUCCESS(WdfIoQueueRetrieveNextRequest(
this->_PendingNotificationRequests,
&notifyRequest)))
@@ -1328,3 +1340,64 @@ VOID ViGEm::Bus::Targets::EmulationTargetDS4::PendingUsbRequestsTimerFunc(
TraceVerbose(TRACE_DS4, "%!FUNC! Exit with status %!STATUS!", status);
}
VOID ViGEm::Bus::Targets::EmulationTargetDS4::EvtUserNotifyRequestComplete(
_In_ DMFMODULE DmfModule,
_In_ WDFREQUEST Request,
_In_opt_ ULONG_PTR Context,
_In_ NTSTATUS NtStatus
)
{
UNREFERENCED_PARAMETER(DmfModule);
FuncEntry(TRACE_DS4);
PDS4_AWAIT_OUTPUT pNotify = NULL;
size_t bufLen = 0;
const PUCHAR pBuffer = reinterpret_cast<PUCHAR>(Context);
if (NT_SUCCESS(WdfRequestRetrieveOutputBuffer(
Request,
sizeof(DS4_AWAIT_OUTPUT),
reinterpret_cast<PVOID*>(&pNotify),
&bufLen
)))
{
RtlCopyMemory(pNotify->Report.Buffer, pBuffer, sizeof(DS4_AWAIT_OUTPUT_BUFFER));
WdfRequestSetInformation(Request, sizeof(DS4_AWAIT_OUTPUT));
}
WdfRequestComplete(Request, NtStatus);
FuncExitNoReturn(TRACE_DS4);
}
NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::OutputReportRequestProcess(WDFREQUEST Request) const
{
return DMF_NotifyUserWithRequestMultiple_RequestProcess(
this->_OutputReportNotify,
Request
);
}
VOID ViGEm::Bus::Targets::EmulationTargetDS4::DmfDeviceModulesAdd(_In_ PDMFMODULE_INIT DmfModuleInit)
{
DMF_CONFIG_NotifyUserWithRequestMultiple notifyConfig;
DMF_MODULE_ATTRIBUTES moduleAttributes;
DMF_CONFIG_NotifyUserWithRequestMultiple_AND_ATTRIBUTES_INIT(&notifyConfig, &moduleAttributes);
notifyConfig.MaximumNumberOfPendingRequests = 64 * 2;
notifyConfig.SizeOfDataBuffer = sizeof(DS4_AWAIT_OUTPUT_BUFFER);
notifyConfig.MaximumNumberOfPendingDataBuffers = 64;
notifyConfig.ModeType.Modes.ReplayLastMessageToNewClients = TRUE;
notifyConfig.CompletionCallback = EvtUserNotifyRequestComplete;
DMF_DmfModuleAdd(
DmfModuleInit,
&moduleAttributes,
WDF_NO_OBJECT_ATTRIBUTES,
&this->_OutputReportNotify
);
}

View File

@@ -53,7 +53,7 @@ namespace ViGEm::Bus::Targets
UCHAR Nic1;
UCHAR Nic2;
} MAC_ADDRESS, * PMAC_ADDRESS;
constexpr unsigned char hid_get_report_id(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST* pReq)
{
return pReq->Value & 0xFF;
@@ -70,8 +70,8 @@ namespace ViGEm::Bus::Targets
EmulationTargetDS4(ULONG Serial, LONG SessionId, USHORT VendorId = 0x054C, USHORT ProductId = 0x05C4);
NTSTATUS PdoPrepareDevice(PWDFDEVICE_INIT DeviceInit,
PUNICODE_STRING DeviceId,
PUNICODE_STRING DeviceDescription) override;
PUNICODE_STRING DeviceId,
PUNICODE_STRING DeviceDescription) override;
NTSTATUS PdoPrepareHardware() override;
@@ -84,21 +84,23 @@ namespace ViGEm::Bus::Targets
NTSTATUS SelectConfiguration(PURB Urb) override;
void AbortPipe() override;
NTSTATUS UsbClassInterface(PURB Urb) override;
NTSTATUS UsbGetDescriptorFromInterface(PURB Urb) override;
NTSTATUS UsbSelectInterface(PURB Urb) override;
NTSTATUS UsbGetStringDescriptorType(PURB Urb) override;
NTSTATUS UsbBulkOrInterruptTransfer(_URB_BULK_OR_INTERRUPT_TRANSFER* pTransfer, WDFREQUEST Request) override;
NTSTATUS UsbControlTransfer(PURB Urb) override;
NTSTATUS SubmitReportImpl(PVOID NewReport) override;
NTSTATUS OutputReportRequestProcess(WDFREQUEST Request) const;
private:
static EVT_WDF_TIMER PendingUsbRequestsTimerFunc;
@@ -106,8 +108,12 @@ namespace ViGEm::Bus::Targets
static VOID GenerateRandomMacAddress(PMAC_ADDRESS Address);
static EVT_DMF_NotifyUserWithRequest_Complete EvtUserNotifyRequestComplete;
protected:
void ProcessPendingNotification(WDFQUEUE Queue) override;
void DmfDeviceModulesAdd(_In_ PDMFMODULE_INIT DmfModuleInit) override;
private:
static PCWSTR _deviceDescription;
@@ -159,6 +165,11 @@ namespace ViGEm::Bus::Targets
//
// Default MAC address of the host (not used)
//
MAC_ADDRESS _HostMacAddress;
MAC_ADDRESS _HostMacAddress;
//
// User-mode notification on new output report
//
DMFMODULE _OutputReportNotify;
};
}

View File

@@ -57,6 +57,8 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
WDF_IO_QUEUE_CONFIG usbInQueueConfig;
WDF_IO_QUEUE_CONFIG notificationsQueueConfig;
PEMULATION_TARGET_PDO_CONTEXT pPdoContext;
PDMFDEVICE_INIT dmfDeviceInit = NULL;
DMF_EVENT_CALLBACKS dmfEventCallbacks;
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSPDO, "%!FUNC! Entry");
@@ -74,6 +76,22 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
do
{
dmfDeviceInit = DMF_DmfDeviceInitAllocate(DeviceInit);
if (dmfDeviceInit == NULL)
{
TraceError(
TRACE_BUSPDO,
"DMF_DmfDeviceInitAllocate failed"
);
status = STATUS_NO_MEMORY;
break;
}
DMF_DmfDeviceInitHookPnpPowerEventCallbacks(dmfDeviceInit, NULL);
DMF_DmfDeviceInitHookFileObjectConfig(dmfDeviceInit, NULL);
DMF_DmfDeviceInitHookPowerPolicyEventCallbacks(dmfDeviceInit, NULL);
#pragma region Prepare PDO
status = this->PdoPrepareDevice(DeviceInit, &deviceId, &deviceDescription);
@@ -272,6 +290,8 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
defaultPdoQueueConfig.EvtIoInternalDeviceControl = EvtIoInternalDeviceControl;
DMF_DmfDeviceInitHookQueueConfig(dmfDeviceInit, &defaultPdoQueueConfig);
status = WdfIoQueueCreate(
this->_PdoDevice,
&defaultPdoQueueConfig,
@@ -311,8 +331,41 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
WdfDeviceSetPowerCapabilities(this->_PdoDevice, &this->_PowerCapabilities);
#pragma endregion
#pragma region DMF Initialization
DMF_EVENT_CALLBACKS_INIT(&dmfEventCallbacks);
dmfEventCallbacks.EvtDmfDeviceModulesAdd = DmfDeviceModulesAdd;
DMF_DmfDeviceInitSetEventCallbacks(dmfDeviceInit, &dmfEventCallbacks);
if (!NT_SUCCESS(status = DMF_ModulesCreate(
this->_PdoDevice,
&dmfDeviceInit
)))
{
TraceEvents(
TRACE_LEVEL_ERROR,
TRACE_DS4,
"DMF_ModulesCreate failed with status %!STATUS!",
status
);
break;
}
#pragma endregion
} while (FALSE);
if (dmfDeviceInit)
{
DMF_DmfDeviceInitFree(&dmfDeviceInit);
}
if (!NT_SUCCESS(status) && this->_PdoDevice != nullptr)
{
WdfObjectDelete(this->_PdoDevice);
}
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSPDO, "%!FUNC! Exit with status %!STATUS!", status);
return status;
@@ -824,7 +877,6 @@ BOOLEAN ViGEm::Bus::Core::EmulationTargetPDO::EvtChildListIdentificationDescript
return (lhs->SerialNo == rhs->SerialNo) ? TRUE : FALSE;
}
NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::EnqueueWaitDeviceReady(WDFDEVICE ParentDevice, ULONG SerialNo,
WDFREQUEST Request)
{
@@ -1177,3 +1229,10 @@ void ViGEm::Bus::Core::EmulationTargetPDO::EvtWdfIoPendingNotificationQueueState
pThis->ProcessPendingNotification(Queue);
}
VOID ViGEm::Bus::Core::EmulationTargetPDO::DmfDeviceModulesAdd(_In_ WDFDEVICE Device, _In_ PDMFMODULE_INIT DmfModuleInit)
{
const auto pThis = static_cast<EmulationTargetPDO*>(EmulationTargetPdoGetContext(Device)->Target);
pThis->DmfDeviceModulesAdd(DmfModuleInit);
}

View File

@@ -138,7 +138,7 @@ namespace ViGEm::Bus::Core
);
NTSTATUS EnqueueWaitDeviceReady(WDFREQUEST Request);
HANDLE _WaitDeviceReadyCompletionWorkerThreadHandle{};
protected:
@@ -147,7 +147,7 @@ namespace ViGEm::Bus::Core
static const int MAX_INSTANCE_ID_LEN = 80;
static const size_t MAX_OUT_BUFFER_QUEUE_COUNT = 64;
static const size_t MAX_OUT_BUFFER_QUEUE_SIZE = 128;
static PCWSTR _deviceLocation;
@@ -181,7 +181,9 @@ namespace ViGEm::Bus::Core
static VOID WaitDeviceReadyCompletionWorkerRoutine(IN PVOID StartContext);
static VOID DumpAsHex(PCSTR Prefix, PVOID Buffer, ULONG BufferLength);
static VOID DmfDeviceModulesAdd(_In_ WDFDEVICE Device, _In_ PDMFMODULE_INIT DmfModuleInit);
virtual VOID GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length) = 0;
virtual NTSTATUS SelectConfiguration(PURB Urb) = 0;
@@ -192,6 +194,8 @@ namespace ViGEm::Bus::Core
virtual VOID ProcessPendingNotification(WDFQUEUE Queue) = 0;
virtual void DmfDeviceModulesAdd(_In_ PDMFMODULE_INIT DmfModuleInit) = 0;
//
// PNP Capabilities may differ from device to device
//
@@ -266,6 +270,11 @@ namespace ViGEm::Bus::Core
// Queue for interrupt out requests delivered to user-land
//
DMFMODULE _UsbInterruptOutBufferQueue{};
//
// DMF event callbacks
//
DMF_EVENT_CALLBACKS _DmfEventCallbacks;
};
typedef struct _PDO_IDENTIFICATION_DESCRIPTION

View File

@@ -486,4 +486,54 @@ exit:
return status;
}
NTSTATUS
Bus_Ds4AwaitOutputHandler(
_In_ DMFMODULE DmfModule,
_In_ WDFQUEUE Queue,
_In_ WDFREQUEST Request,
_In_ ULONG IoctlCode,
_In_reads_(InputBufferSize) VOID* InputBuffer,
_In_ size_t InputBufferSize,
_Out_writes_(OutputBufferSize) VOID* OutputBuffer,
_In_ size_t OutputBufferSize,
_Out_ size_t* BytesReturned
)
{
UNREFERENCED_PARAMETER(DmfModule);
UNREFERENCED_PARAMETER(Request);
UNREFERENCED_PARAMETER(IoctlCode);
UNREFERENCED_PARAMETER(OutputBufferSize);
UNREFERENCED_PARAMETER(InputBufferSize);
UNREFERENCED_PARAMETER(OutputBuffer);
UNREFERENCED_PARAMETER(BytesReturned);
FuncEntry(TRACE_QUEUE);
NTSTATUS status;
EmulationTargetPDO* pdo;
PDS4_AWAIT_OUTPUT pDs4AwaitOut = (PDS4_AWAIT_OUTPUT)InputBuffer;
// This request only supports a single PDO at a time
if (pDs4AwaitOut->SerialNo == 0)
{
status = STATUS_INVALID_PARAMETER;
goto exit;
}
if (!EmulationTargetPDO::GetPdoByTypeAndSerial(WdfIoQueueGetDevice(Queue), DualShock4Wired, pDs4AwaitOut->SerialNo, &pdo))
{
status = STATUS_DEVICE_DOES_NOT_EXIST;
goto exit;
}
status = static_cast<EmulationTargetDS4*>(pdo)->OutputReportRequestProcess(Request);
status = NT_SUCCESS(status) ? STATUS_PENDING : status;
exit:
FuncExit(TRACE_QUEUE, "status=%!STATUS!", status);
return status;
}
EXTERN_C_END

View File

@@ -46,5 +46,6 @@ EVT_DMF_IoctlHandler_Callback Bus_XusbRequestNotificationHandler;
EVT_DMF_IoctlHandler_Callback Bus_Ds4SubmitReportHandler;
EVT_DMF_IoctlHandler_Callback Bus_Ds4RequestNotificationHandler;
EVT_DMF_IoctlHandler_Callback Bus_XusbGetUserIndexHandler;
EVT_DMF_IoctlHandler_Callback Bus_Ds4AwaitOutputHandler;
EXTERN_C_END

View File

@@ -1138,3 +1138,8 @@ void ViGEm::Bus::Targets::EmulationTargetXUSB::ProcessPendingNotification(WDFQUE
TraceVerbose(TRACE_BUSENUM, "%!FUNC! Exit");
}
VOID ViGEm::Bus::Targets::EmulationTargetXUSB::DmfDeviceModulesAdd(_In_ PDMFMODULE_INIT DmfModuleInit)
{
UNREFERENCED_PARAMETER(DmfModuleInit);
}

View File

@@ -99,6 +99,7 @@ namespace ViGEm::Bus::Targets
protected:
void ProcessPendingNotification(WDFQUEUE Queue) override;
void DmfDeviceModulesAdd(_In_ PDMFMODULE_INIT DmfModuleInit) override;
private:
static PCWSTR _deviceDescription;