mirror of
https://github.com/nefarius/ViGEmBus.git
synced 2025-08-10 00:52:17 +00:00
Added IOCTL_DS4_AWAIT_OUTPUT
Added DMF support to PDO
This commit is contained in:
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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},
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
373
sys/Ds4Pdo.cpp
373
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<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,
|
||||
¬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<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(¬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
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user