diff --git a/ViGEmBus.sln.DotSettings b/ViGEmBus.sln.DotSettings
index b110456..dbd4b03 100644
--- a/ViGEmBus.sln.DotSettings
+++ b/ViGEmBus.sln.DotSettings
@@ -1,2 +1,4 @@
+ True
+ True
True
\ No newline at end of file
diff --git a/sdk/include/ViGEm/km/BusShared.h b/sdk/include/ViGEm/km/BusShared.h
index 92ee477..3b9fd1d 100644
--- a/sdk/include/ViGEm/km/BusShared.h
+++ b/sdk/include/ViGEm/km/BusShared.h
@@ -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
@@ -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;
+}
diff --git a/sys/Driver.cpp b/sys/Driver.cpp
index e6ccd8e..6a23390 100644
--- a/sys/Driver.cpp
+++ b/sys/Driver.cpp
@@ -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},
};
//
diff --git a/sys/Ds4Pdo.cpp b/sys/Ds4Pdo.cpp
index e4bc1f1..8b66622 100644
--- a/sys/Ds4Pdo.cpp
+++ b/sys/Ds4Pdo.cpp
@@ -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(&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(&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(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,
¬ifyRequest)))
@@ -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(Context);
+
+ if (NT_SUCCESS(WdfRequestRetrieveOutputBuffer(
+ Request,
+ sizeof(DS4_AWAIT_OUTPUT),
+ reinterpret_cast(&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(¬ifyConfig, &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
+ );
+}
diff --git a/sys/Ds4Pdo.hpp b/sys/Ds4Pdo.hpp
index 7094d9d..d2371cb 100644
--- a/sys/Ds4Pdo.hpp
+++ b/sys/Ds4Pdo.hpp
@@ -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;
};
}
diff --git a/sys/EmulationTargetPDO.cpp b/sys/EmulationTargetPDO.cpp
index a878f51..604421c 100644
--- a/sys/EmulationTargetPDO.cpp
+++ b/sys/EmulationTargetPDO.cpp
@@ -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(EmulationTargetPdoGetContext(Device)->Target);
+
+ pThis->DmfDeviceModulesAdd(DmfModuleInit);
+}
diff --git a/sys/EmulationTargetPDO.hpp b/sys/EmulationTargetPDO.hpp
index 6c019d8..926c698 100644
--- a/sys/EmulationTargetPDO.hpp
+++ b/sys/EmulationTargetPDO.hpp
@@ -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
diff --git a/sys/Queue.cpp b/sys/Queue.cpp
index 9563489..7f531dc 100644
--- a/sys/Queue.cpp
+++ b/sys/Queue.cpp
@@ -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(pdo)->OutputReportRequestProcess(Request);
+
+ status = NT_SUCCESS(status) ? STATUS_PENDING : status;
+
+exit:
+ FuncExit(TRACE_QUEUE, "status=%!STATUS!", status);
+
+ return status;
+}
+
EXTERN_C_END
diff --git a/sys/Queue.hpp b/sys/Queue.hpp
index 4b0fea6..48c941d 100644
--- a/sys/Queue.hpp
+++ b/sys/Queue.hpp
@@ -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
diff --git a/sys/XusbPdo.cpp b/sys/XusbPdo.cpp
index 7355fe6..614922e 100644
--- a/sys/XusbPdo.cpp
+++ b/sys/XusbPdo.cpp
@@ -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);
+}
diff --git a/sys/XusbPdo.hpp b/sys/XusbPdo.hpp
index 4bc2e64..9afb022 100644
--- a/sys/XusbPdo.hpp
+++ b/sys/XusbPdo.hpp
@@ -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;