mirror of
https://github.com/nefarius/ViGEmBus.git
synced 2025-08-10 00:52:17 +00:00
Porting over common USB logic
This commit is contained in:
@@ -27,7 +27,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
EXTERN_C_START
|
||||
|
||||
//
|
||||
// Used to identify children in the device list of the bus.
|
||||
@@ -196,4 +195,3 @@ typedef struct _FDO_PLUGIN_REQUEST_DATA
|
||||
|
||||
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_PLUGIN_REQUEST_DATA, PluginRequestGetData)
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
#include <ntstrsafe.h>
|
||||
#include <hidclass.h>
|
||||
|
||||
#include "Ds4.h"
|
||||
|
||||
|
||||
PCWSTR ViGEm::Bus::Targets::EmulationTargetDS4::_deviceDescription = L"Virtual DualShock 4 Controller";
|
||||
|
||||
ViGEm::Bus::Targets::EmulationTargetDS4::EmulationTargetDS4() : EmulationTargetPDO(0x054C, 0x05C4)
|
||||
{
|
||||
TargetType = DualShock4Wired;
|
||||
}
|
||||
|
||||
NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::PrepareDevice(PWDFDEVICE_INIT DeviceInit,
|
||||
@@ -97,14 +99,14 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::PrepareDevice(PWDFDEVICE_INIT
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::PrepareHardware(WDFDEVICE Device)
|
||||
NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::PrepareHardware()
|
||||
{
|
||||
WDF_QUERY_INTERFACE_CONFIG ifaceCfg;
|
||||
INTERFACE devinterfaceHid;
|
||||
|
||||
devinterfaceHid.Size = sizeof(INTERFACE);
|
||||
devinterfaceHid.Version = 1;
|
||||
devinterfaceHid.Context = (PVOID)Device;
|
||||
devinterfaceHid.Context = static_cast<PVOID>(this->PdoDevice);
|
||||
|
||||
devinterfaceHid.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
|
||||
devinterfaceHid.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
|
||||
@@ -117,7 +119,7 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::PrepareHardware(WDFDEVICE Devi
|
||||
NULL
|
||||
);
|
||||
|
||||
NTSTATUS status = WdfDeviceAddQueryInterface(Device, &ifaceCfg);
|
||||
NTSTATUS status = WdfDeviceAddQueryInterface(this->PdoDevice, &ifaceCfg);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
@@ -150,7 +152,7 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::PrepareHardware(WDFDEVICE Devi
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::InitContext(WDFDEVICE Device)
|
||||
NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::InitContext()
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
@@ -167,7 +169,7 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::InitContext(WDFDEVICE Device)
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&timerAttribs);
|
||||
|
||||
// PDO is parent
|
||||
timerAttribs.ParentObject = Device;
|
||||
timerAttribs.ParentObject = this->PdoDevice;
|
||||
|
||||
// Create timer
|
||||
status = WdfTimerCreate(
|
||||
@@ -433,5 +435,38 @@ VOID ViGEm::Bus::Targets::EmulationTargetDS4::PendingUsbRequestsTimerFunc(
|
||||
_In_ WDFTIMER Timer
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Timer);
|
||||
auto ctx = reinterpret_cast<EmulationTargetDS4*>(Core::EmulationTargetPdoGetContext(WdfTimerGetParentObject(Timer)));
|
||||
|
||||
WDFREQUEST usbRequest;
|
||||
PIRP pendingIrp;
|
||||
PIO_STACK_LOCATION irpStack;
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_DS4, "%!FUNC! Entry");
|
||||
|
||||
// Get pending USB request
|
||||
NTSTATUS status = WdfIoQueueRetrieveNextRequest(ctx->PendingUsbInRequests, &usbRequest);
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
// Get pending IRP
|
||||
pendingIrp = WdfRequestWdmGetIrp(usbRequest);
|
||||
irpStack = IoGetCurrentIrpStackLocation(pendingIrp);
|
||||
|
||||
// Get USB request block
|
||||
PURB urb = (PURB)irpStack->Parameters.Others.Argument1;
|
||||
|
||||
// Get transfer buffer
|
||||
PUCHAR Buffer = (PUCHAR)urb->UrbBulkOrInterruptTransfer.TransferBuffer;
|
||||
// Set buffer length to report size
|
||||
urb->UrbBulkOrInterruptTransfer.TransferBufferLength = DS4_REPORT_SIZE;
|
||||
|
||||
// Copy cached report to transfer buffer
|
||||
if (Buffer)
|
||||
RtlCopyBytes(Buffer, ctx->Report, DS4_REPORT_SIZE);
|
||||
|
||||
// Complete pending request
|
||||
WdfRequestComplete(usbRequest, status);
|
||||
}
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DS4, "%!FUNC! Exit with status %!STATUS!", status);
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ namespace ViGEm::Bus::Targets
|
||||
PUNICODE_STRING DeviceId,
|
||||
PUNICODE_STRING DeviceDescription) override;
|
||||
|
||||
NTSTATUS PrepareHardware(WDFDEVICE Device) override;
|
||||
NTSTATUS PrepareHardware() override;
|
||||
|
||||
NTSTATUS InitContext(WDFDEVICE Device) override;
|
||||
NTSTATUS InitContext() override;
|
||||
|
||||
VOID GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length) override;
|
||||
|
||||
@@ -87,14 +87,4 @@ namespace ViGEm::Bus::Targets
|
||||
|
||||
static EVT_WDF_TIMER PendingUsbRequestsTimerFunc;
|
||||
};
|
||||
|
||||
//
|
||||
// DS4-specific device context data.
|
||||
//
|
||||
typedef struct _DS4_PDO_CONTEXT
|
||||
{
|
||||
EmulationTargetDS4* Context;
|
||||
} DS4_PDO_CONTEXT, *PDS4_PDO_CONTEXT;
|
||||
|
||||
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DS4_PDO_CONTEXT, Ds4PdoGetContext)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,305 @@
|
||||
#include "EmulationTargetPDO.hpp"
|
||||
#include "CRTCPP.hpp"
|
||||
#include "trace.h"
|
||||
#include "EmulationTargetPDO.tmh"
|
||||
#define NTSTRSAFE_LIB
|
||||
#include <ntstrsafe.h>
|
||||
#include <usbiodef.h>
|
||||
|
||||
|
||||
PCWSTR ViGEm::Bus::Core::EmulationTargetPDO::_deviceLocation = L"Virtual Gamepad Emulation Bus";
|
||||
|
||||
NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::CreateDevice(WDFDEVICE Device, PWDFDEVICE_INIT DeviceInit, PPDO_IDENTIFICATION_DESCRIPTION Description)
|
||||
{
|
||||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||
WDF_DEVICE_PNP_CAPABILITIES pnpCaps;
|
||||
WDF_DEVICE_POWER_CAPABILITIES powerCaps;
|
||||
WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
|
||||
WDF_OBJECT_ATTRIBUTES pdoAttributes;
|
||||
WDF_IO_QUEUE_CONFIG defaultPdoQueueConfig;
|
||||
WDFQUEUE defaultPdoQueue;
|
||||
UNICODE_STRING deviceDescription;
|
||||
WDF_OBJECT_ATTRIBUTES attributes;
|
||||
WDF_IO_QUEUE_CONFIG usbInQueueConfig;
|
||||
WDF_IO_QUEUE_CONFIG notificationsQueueConfig;
|
||||
|
||||
DECLARE_CONST_UNICODE_STRING(deviceLocation, L"Virtual Gamepad Emulation Bus");
|
||||
DECLARE_UNICODE_STRING_SIZE(buffer, MAX_INSTANCE_ID_LEN);
|
||||
// reserve space for device id
|
||||
DECLARE_UNICODE_STRING_SIZE(deviceId, MAX_INSTANCE_ID_LEN);
|
||||
|
||||
UNREFERENCED_PARAMETER(Description);
|
||||
UNREFERENCED_PARAMETER(Device);
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
// set device type
|
||||
WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER);
|
||||
// Bus is power policy owner
|
||||
WdfDeviceInitSetPowerPolicyOwnership(DeviceInit, FALSE);
|
||||
|
||||
do
|
||||
{
|
||||
#pragma region Enter RAW device mode
|
||||
|
||||
status = WdfPdoInitAssignRawDevice(DeviceInit, &GUID_DEVCLASS_VIGEM_RAWPDO);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfPdoInitAssignRawDevice failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
WdfDeviceInitSetCharacteristics(DeviceInit, FILE_AUTOGENERATED_DEVICE_NAME, TRUE);
|
||||
|
||||
status = WdfDeviceInitAssignSDDLString(DeviceInit, &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfDeviceInitAssignSDDLString failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Prepare PDO
|
||||
|
||||
status = this->PrepareDevice(DeviceInit, &deviceId, &deviceDescription);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
break;
|
||||
|
||||
// set device id
|
||||
status = WdfPdoInitAssignDeviceID(DeviceInit, &deviceId);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfPdoInitAssignDeviceID failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
// prepare instance id
|
||||
status = RtlUnicodeStringPrintf(&buffer, L"%02d", this->SerialNo);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"RtlUnicodeStringPrintf failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
// set instance id
|
||||
status = WdfPdoInitAssignInstanceID(DeviceInit, &buffer);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfPdoInitAssignInstanceID failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
// set device description (for English operating systems)
|
||||
status = WdfPdoInitAddDeviceText(DeviceInit, &deviceDescription, &deviceLocation, 0x409);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfPdoInitAddDeviceText failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
// default locale is English
|
||||
// TODO: add more locales
|
||||
WdfPdoInitSetDefaultLocale(DeviceInit, 0x409);
|
||||
|
||||
#pragma region PNP/Power event callbacks
|
||||
|
||||
WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
|
||||
|
||||
pnpPowerCallbacks.EvtDevicePrepareHardware = EvtDevicePrepareHardware;
|
||||
|
||||
WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
// NOTE: not utilized at the moment
|
||||
WdfPdoInitAllowForwardingRequestToParent(DeviceInit);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Create PDO
|
||||
|
||||
// Add common device data context
|
||||
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, EMULATION_TARGET_PDO_CONTEXT);
|
||||
|
||||
status = WdfDeviceCreate(&DeviceInit, &pdoAttributes, &this->PdoDevice);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfDeviceCreate failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
"Created PDO 0x%p",
|
||||
this->PdoDevice);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Expose USB Interface
|
||||
|
||||
status = WdfDeviceCreateDeviceInterface(
|
||||
Device,
|
||||
const_cast<LPGUID>(&GUID_DEVINTERFACE_USB_DEVICE),
|
||||
NULL
|
||||
);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfDeviceCreateDeviceInterface failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Set PDO contexts
|
||||
|
||||
status = this->InitContext();
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"Couldn't initialize additional contexts: %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Create Queues & Locks
|
||||
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
|
||||
attributes.ParentObject = this->PdoDevice;
|
||||
|
||||
// Create and assign queue for incoming interrupt transfer
|
||||
WDF_IO_QUEUE_CONFIG_INIT(&usbInQueueConfig, WdfIoQueueDispatchManual);
|
||||
|
||||
status = WdfIoQueueCreate(
|
||||
this->PdoDevice,
|
||||
&usbInQueueConfig,
|
||||
WDF_NO_OBJECT_ATTRIBUTES,
|
||||
&this->PendingUsbInRequests
|
||||
);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfIoQueueCreate (PendingUsbInRequests) failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
// Create and assign queue for user-land notification requests
|
||||
WDF_IO_QUEUE_CONFIG_INIT(¬ificationsQueueConfig, WdfIoQueueDispatchManual);
|
||||
|
||||
status = WdfIoQueueCreate(
|
||||
Device,
|
||||
¬ificationsQueueConfig,
|
||||
WDF_NO_OBJECT_ATTRIBUTES,
|
||||
&this->PendingNotificationRequests
|
||||
);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfIoQueueCreate (PendingNotificationRequests) failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Default I/O queue setup
|
||||
|
||||
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&defaultPdoQueueConfig, WdfIoQueueDispatchParallel);
|
||||
|
||||
defaultPdoQueueConfig.EvtIoInternalDeviceControl = EvtIoInternalDeviceControl;
|
||||
|
||||
status = WdfIoQueueCreate(
|
||||
this->PdoDevice,
|
||||
&defaultPdoQueueConfig,
|
||||
WDF_NO_OBJECT_ATTRIBUTES,
|
||||
&defaultPdoQueue
|
||||
);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfIoQueueCreate (Default) failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region PNP capabilities
|
||||
|
||||
WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps);
|
||||
|
||||
pnpCaps.Removable = WdfTrue;
|
||||
pnpCaps.EjectSupported = WdfTrue;
|
||||
pnpCaps.SurpriseRemovalOK = WdfTrue;
|
||||
|
||||
pnpCaps.Address = this->SerialNo;
|
||||
pnpCaps.UINumber = this->SerialNo;
|
||||
|
||||
WdfDeviceSetPnpCapabilities(this->PdoDevice, &pnpCaps);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Power capabilities
|
||||
|
||||
WDF_DEVICE_POWER_CAPABILITIES_INIT(&powerCaps);
|
||||
|
||||
powerCaps.DeviceD1 = WdfTrue;
|
||||
powerCaps.WakeFromD1 = WdfTrue;
|
||||
powerCaps.DeviceWake = PowerDeviceD1;
|
||||
|
||||
powerCaps.DeviceState[PowerSystemWorking] = PowerDeviceD0;
|
||||
powerCaps.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
|
||||
powerCaps.DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
|
||||
powerCaps.DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
|
||||
powerCaps.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
|
||||
powerCaps.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
|
||||
|
||||
WdfDeviceSetPowerCapabilities(this->PdoDevice, &powerCaps);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSPDO, "%!FUNC! Exit with status %!STATUS!", status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#pragma region USB Interface Functions
|
||||
|
||||
BOOLEAN USB_BUSIFFN ViGEm::Bus::Core::EmulationTargetPDO::UsbIsDeviceHighSpeed(IN PVOID BusContext)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(BusContext);
|
||||
@@ -10,9 +308,9 @@ BOOLEAN USB_BUSIFFN ViGEm::Bus::Core::EmulationTargetPDO::UsbIsDeviceHighSpeed(I
|
||||
}
|
||||
|
||||
NTSTATUS USB_BUSIFFN ViGEm::Bus::Core::EmulationTargetPDO::UsbQueryBusInformation(IN PVOID BusContext, IN ULONG Level,
|
||||
IN OUT PVOID BusInformationBuffer,
|
||||
IN OUT PULONG BusInformationBufferLength,
|
||||
OUT PULONG BusInformationActualLength)
|
||||
IN OUT PVOID BusInformationBuffer,
|
||||
IN OUT PULONG BusInformationBufferLength,
|
||||
OUT PULONG BusInformationActualLength)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(BusContext);
|
||||
UNREFERENCED_PARAMETER(Level);
|
||||
@@ -40,8 +338,8 @@ NTSTATUS USB_BUSIFFN ViGEm::Bus::Core::EmulationTargetPDO::UsbQueryBusTime(IN PV
|
||||
}
|
||||
|
||||
VOID USB_BUSIFFN ViGEm::Bus::Core::EmulationTargetPDO::UsbGetUSBDIVersion(IN PVOID BusContext,
|
||||
IN OUT PUSBD_VERSION_INFORMATION VersionInformation,
|
||||
IN OUT PULONG HcdCapabilities)
|
||||
IN OUT PUSBD_VERSION_INFORMATION VersionInformation,
|
||||
IN OUT PULONG HcdCapabilities)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(BusContext);
|
||||
|
||||
@@ -57,6 +355,38 @@ VOID USB_BUSIFFN ViGEm::Bus::Core::EmulationTargetPDO::UsbGetUSBDIVersion(IN PVO
|
||||
}
|
||||
}
|
||||
|
||||
ViGEm::Bus::Core::EmulationTargetPDO::EmulationTargetPDO(USHORT VID, USHORT PID): VendorId(VID), ProductId(PID)
|
||||
#pragma endregion
|
||||
|
||||
ViGEm::Bus::Core::EmulationTargetPDO::EmulationTargetPDO(USHORT VID, USHORT PID) : VendorId(VID), ProductId(PID)
|
||||
{
|
||||
}
|
||||
|
||||
NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::EvtDevicePrepareHardware(
|
||||
_In_ WDFDEVICE Device,
|
||||
_In_ WDFCMRESLIST ResourcesRaw,
|
||||
_In_ WDFCMRESLIST ResourcesTranslated
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(ResourcesRaw);
|
||||
UNREFERENCED_PARAMETER(ResourcesTranslated);
|
||||
|
||||
const auto ctx = EmulationTargetPdoGetContext(Device);
|
||||
|
||||
return ctx->Target->PrepareHardware();
|
||||
}
|
||||
|
||||
VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
_In_ WDFQUEUE Queue,
|
||||
_In_ WDFREQUEST Request,
|
||||
_In_ size_t OutputBufferLength,
|
||||
_In_ size_t InputBufferLength,
|
||||
_In_ ULONG IoControlCode
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Queue);
|
||||
UNREFERENCED_PARAMETER(OutputBufferLength);
|
||||
UNREFERENCED_PARAMETER(InputBufferLength);
|
||||
UNREFERENCED_PARAMETER(IoControlCode);
|
||||
|
||||
WdfRequestComplete(Request, STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,12 @@
|
||||
|
||||
namespace ViGEm::Bus::Core
|
||||
{
|
||||
// {A8BA2D1F-894F-464A-B0CE-7A0C8FD65DF1}
|
||||
DEFINE_GUID(GUID_DEVCLASS_VIGEM_RAWPDO,
|
||||
0xA8BA2D1F, 0x894F, 0x464A, 0xB0, 0xCE, 0x7A, 0x0C, 0x8F, 0xD6, 0x5D, 0xF1);
|
||||
|
||||
typedef struct _PDO_IDENTIFICATION_DESCRIPTION* PPDO_IDENTIFICATION_DESCRIPTION;
|
||||
|
||||
class EmulationTargetPDO
|
||||
{
|
||||
public:
|
||||
@@ -25,21 +31,27 @@ namespace ViGEm::Bus::Core
|
||||
|
||||
virtual ~EmulationTargetPDO() = default;
|
||||
|
||||
virtual NTSTATUS PrepareDevice(PWDFDEVICE_INIT DeviceInit,
|
||||
virtual NTSTATUS PrepareDevice(PWDFDEVICE_INIT DeviceInit,
|
||||
PUNICODE_STRING DeviceId, PUNICODE_STRING DeviceDescription) = 0;
|
||||
|
||||
virtual NTSTATUS PrepareHardware(WDFDEVICE Device) = 0;
|
||||
virtual NTSTATUS PrepareHardware() = 0;
|
||||
|
||||
virtual NTSTATUS InitContext(WDFDEVICE Device) = 0;
|
||||
virtual NTSTATUS InitContext() = 0;
|
||||
|
||||
virtual VOID GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length) = 0;
|
||||
|
||||
virtual VOID GetDeviceDescriptorType(PUSB_DEVICE_DESCRIPTOR pDescriptor) = 0;
|
||||
|
||||
virtual VOID SelectConfiguration(PUSBD_INTERFACE_INFORMATION pInfo) = 0;
|
||||
|
||||
NTSTATUS CreateDevice(_In_ WDFDEVICE Device,
|
||||
_In_ PWDFDEVICE_INIT DeviceInit,
|
||||
_In_ PPDO_IDENTIFICATION_DESCRIPTION Description);
|
||||
protected:
|
||||
static const ULONG _maxHardwareIdLength = 0xFF;
|
||||
|
||||
static PCWSTR _deviceLocation;
|
||||
|
||||
static BOOLEAN USB_BUSIFFN UsbIsDeviceHighSpeed(IN PVOID BusContext);
|
||||
|
||||
static NTSTATUS USB_BUSIFFN UsbQueryBusInformation(
|
||||
@@ -60,44 +72,69 @@ namespace ViGEm::Bus::Core
|
||||
IN OUT PULONG HcdCapabilities
|
||||
);
|
||||
|
||||
//
|
||||
// Unique serial number of the device on the bus
|
||||
//
|
||||
ULONG SerialNo{};
|
||||
static EVT_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware;
|
||||
|
||||
//
|
||||
// PID of the process creating this PDO
|
||||
//
|
||||
DWORD OwnerProcessId{};
|
||||
static EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl;
|
||||
|
||||
//
|
||||
// Device type this PDO is emulating
|
||||
//
|
||||
VIGEM_TARGET_TYPE TargetType;
|
||||
static const int MAX_INSTANCE_ID_LEN = 80;
|
||||
|
||||
//
|
||||
// If set, the vendor ID the emulated device is reporting
|
||||
//
|
||||
USHORT VendorId{};
|
||||
//
|
||||
// Unique serial number of the device on the bus
|
||||
//
|
||||
ULONG SerialNo{};
|
||||
|
||||
//
|
||||
// If set, the product ID the emulated device is reporting
|
||||
//
|
||||
USHORT ProductId{};
|
||||
//
|
||||
// PID of the process creating this PDO
|
||||
//
|
||||
DWORD OwnerProcessId{};
|
||||
|
||||
//
|
||||
// Queue for incoming data interrupt transfer
|
||||
//
|
||||
WDFQUEUE PendingUsbInRequests{};
|
||||
//
|
||||
// Device type this PDO is emulating
|
||||
//
|
||||
VIGEM_TARGET_TYPE TargetType;
|
||||
|
||||
//
|
||||
// Queue for inverted calls
|
||||
//
|
||||
WDFQUEUE PendingNotificationRequests{};
|
||||
//
|
||||
// If set, the vendor ID the emulated device is reporting
|
||||
//
|
||||
USHORT VendorId{};
|
||||
|
||||
//
|
||||
// If set, the product ID the emulated device is reporting
|
||||
//
|
||||
USHORT ProductId{};
|
||||
|
||||
//
|
||||
// Queue for incoming data interrupt transfer
|
||||
//
|
||||
WDFQUEUE PendingUsbInRequests{};
|
||||
|
||||
//
|
||||
// Queue for inverted calls
|
||||
//
|
||||
WDFQUEUE PendingNotificationRequests{};
|
||||
|
||||
//
|
||||
// This child objects' device object
|
||||
//
|
||||
WDFDEVICE PdoDevice;
|
||||
|
||||
//
|
||||
// Signals the bus that PDO is ready to receive data
|
||||
//
|
||||
KEVENT PdoBootNotificationEvent;
|
||||
};
|
||||
|
||||
typedef struct _PDO_IDENTIFICATION_DESCRIPTION
|
||||
{
|
||||
EmulationTargetPDO* Context;
|
||||
WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Header;
|
||||
|
||||
EmulationTargetPDO* Target;
|
||||
} PDO_IDENTIFICATION_DESCRIPTION, *PPDO_IDENTIFICATION_DESCRIPTION;
|
||||
|
||||
typedef struct _EMULATION_TARGET_PDO_CONTEXT
|
||||
{
|
||||
EmulationTargetPDO* Target;
|
||||
} EMULATION_TARGET_PDO_CONTEXT, *PEMULATION_TARGET_PDO_CONTEXT;
|
||||
|
||||
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(EMULATION_TARGET_PDO_CONTEXT, EmulationTargetPdoGetContext)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ PCWSTR ViGEm::Bus::Targets::EmulationTargetXUSB::_deviceDescription = L"Virtual
|
||||
|
||||
ViGEm::Bus::Targets::EmulationTargetXUSB::EmulationTargetXUSB() : EmulationTargetPDO(0x045E, 0x028E)
|
||||
{
|
||||
TargetType = Xbox360Wired;
|
||||
}
|
||||
|
||||
NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::PrepareDevice(PWDFDEVICE_INIT DeviceInit, PUNICODE_STRING DeviceId,
|
||||
@@ -98,7 +99,7 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::PrepareDevice(PWDFDEVICE_INIT
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::PrepareHardware(WDFDEVICE Device)
|
||||
NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::PrepareHardware()
|
||||
{
|
||||
WDF_QUERY_INTERFACE_CONFIG ifaceCfg;
|
||||
|
||||
@@ -106,7 +107,7 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::PrepareHardware(WDFDEVICE Dev
|
||||
|
||||
dummyIface.Size = sizeof(INTERFACE);
|
||||
dummyIface.Version = 1;
|
||||
dummyIface.Context = static_cast<PVOID>(Device);
|
||||
dummyIface.Context = static_cast<PVOID>(this->PdoDevice);
|
||||
|
||||
dummyIface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
|
||||
dummyIface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
|
||||
@@ -124,7 +125,7 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::PrepareHardware(WDFDEVICE Dev
|
||||
nullptr
|
||||
);
|
||||
|
||||
NTSTATUS status = WdfDeviceAddQueryInterface(Device, &ifaceCfg);
|
||||
NTSTATUS status = WdfDeviceAddQueryInterface(this->PdoDevice, &ifaceCfg);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
@@ -145,7 +146,7 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::PrepareHardware(WDFDEVICE Dev
|
||||
nullptr
|
||||
);
|
||||
|
||||
status = WdfDeviceAddQueryInterface(Device, &ifaceCfg);
|
||||
status = WdfDeviceAddQueryInterface(this->PdoDevice, &ifaceCfg);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
@@ -166,7 +167,7 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::PrepareHardware(WDFDEVICE Dev
|
||||
nullptr
|
||||
);
|
||||
|
||||
status = WdfDeviceAddQueryInterface(Device, &ifaceCfg);
|
||||
status = WdfDeviceAddQueryInterface(this->PdoDevice, &ifaceCfg);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
@@ -185,7 +186,7 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::PrepareHardware(WDFDEVICE Dev
|
||||
|
||||
xusbInterface.Size = sizeof(USB_BUS_INTERFACE_USBDI_V1);
|
||||
xusbInterface.Version = USB_BUSIF_USBDI_VERSION_1;
|
||||
xusbInterface.BusContext = static_cast<PVOID>(Device);
|
||||
xusbInterface.BusContext = static_cast<PVOID>(this->PdoDevice);
|
||||
|
||||
xusbInterface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
|
||||
xusbInterface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
|
||||
@@ -203,7 +204,7 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::PrepareHardware(WDFDEVICE Dev
|
||||
nullptr
|
||||
);
|
||||
|
||||
status = WdfDeviceAddQueryInterface(Device, &ifaceCfg);
|
||||
status = WdfDeviceAddQueryInterface(this->PdoDevice, &ifaceCfg);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
@@ -216,13 +217,13 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::PrepareHardware(WDFDEVICE Dev
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::InitContext(WDFDEVICE Device)
|
||||
NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::InitContext()
|
||||
{
|
||||
WDF_OBJECT_ATTRIBUTES attributes;
|
||||
PUCHAR blobBuffer;
|
||||
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
|
||||
attributes.ParentObject = Device;
|
||||
attributes.ParentObject = this->PdoDevice;
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_XUSB, "Initializing XUSB context...");
|
||||
|
||||
@@ -286,7 +287,7 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::InitContext(WDFDEVICE Device)
|
||||
WDF_IO_QUEUE_CONFIG_INIT(&holdingInQueueConfig, WdfIoQueueDispatchManual);
|
||||
|
||||
status = WdfIoQueueCreate(
|
||||
Device,
|
||||
this->PdoDevice,
|
||||
&holdingInQueueConfig,
|
||||
WDF_NO_OBJECT_ATTRIBUTES,
|
||||
&this->HoldingUsbInRequests
|
||||
|
||||
@@ -26,9 +26,9 @@ namespace ViGEm::Bus::Targets
|
||||
NTSTATUS PrepareDevice(PWDFDEVICE_INIT DeviceInit,
|
||||
PUNICODE_STRING DeviceId, PUNICODE_STRING DeviceDescription) override;
|
||||
|
||||
NTSTATUS PrepareHardware(WDFDEVICE Device) override;
|
||||
NTSTATUS PrepareHardware() override;
|
||||
|
||||
NTSTATUS InitContext(WDFDEVICE Device) override;
|
||||
NTSTATUS InitContext() override;
|
||||
|
||||
VOID GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length) override;
|
||||
|
||||
@@ -95,14 +95,4 @@ namespace ViGEm::Bus::Targets
|
||||
//
|
||||
WDFMEMORY InterruptBlobStorage;
|
||||
};
|
||||
|
||||
//
|
||||
// XUSB-specific device context data.
|
||||
//
|
||||
typedef struct _XUSB_PDO_CONTEXT
|
||||
{
|
||||
EmulationTargetXUSB* Context;
|
||||
} XUSB_PDO_CONTEXT, *PXUSB_PDO_CONTEXT;
|
||||
|
||||
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(XUSB_PDO_CONTEXT, XusbPdoGetContext)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user