mirror of
https://github.com/nefarius/ViGEmBus.git
synced 2025-08-10 00:52:17 +00:00
Implemented new DS4 output report feature
This commit is contained in:
2
sdk
2
sdk
Submodule sdk updated: da1ed30414...16d9c40aae
@@ -70,7 +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},
|
||||
{IOCTL_DS4_AWAIT_OUTPUT_AVAILABLE, sizeof(DS4_AWAIT_OUTPUT), sizeof(DS4_AWAIT_OUTPUT), Bus_Ds4AwaitOutputHandler},
|
||||
};
|
||||
|
||||
//
|
||||
@@ -319,10 +319,10 @@ DmfDeviceModulesAdd(
|
||||
_In_ PDMFMODULE_INIT DmfModuleInit
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Device);
|
||||
|
||||
FuncEntry(TRACE_DRIVER);
|
||||
|
||||
PFDO_DEVICE_DATA pDevCtx = FdoGetData(Device);
|
||||
|
||||
DMF_MODULE_ATTRIBUTES moduleAttributes;
|
||||
DMF_CONFIG_IoctlHandler ioctlHandlerConfig;
|
||||
DMF_CONFIG_IoctlHandler_AND_ATTRIBUTES_INIT(&ioctlHandlerConfig, &moduleAttributes);
|
||||
@@ -339,6 +339,22 @@ DmfDeviceModulesAdd(
|
||||
NULL
|
||||
);
|
||||
|
||||
DMF_CONFIG_NotifyUserWithRequestMultiple notifyConfig;
|
||||
DMF_CONFIG_NotifyUserWithRequestMultiple_AND_ATTRIBUTES_INIT(¬ifyConfig, &moduleAttributes);
|
||||
|
||||
notifyConfig.MaximumNumberOfPendingRequests = 64 * 2;
|
||||
notifyConfig.SizeOfDataBuffer = sizeof(DS4_AWAIT_OUTPUT);
|
||||
notifyConfig.MaximumNumberOfPendingDataBuffers = 64;
|
||||
notifyConfig.ModeType.Modes.ReplayLastMessageToNewClients = FALSE;
|
||||
notifyConfig.CompletionCallback = Bus_EvtUserNotifyRequestComplete;
|
||||
|
||||
DMF_DmfModuleAdd(
|
||||
DmfModuleInit,
|
||||
&moduleAttributes,
|
||||
WDF_NO_OBJECT_ATTRIBUTES,
|
||||
&pDevCtx->UserNotification
|
||||
);
|
||||
|
||||
FuncExitNoReturn(TRACE_DRIVER);
|
||||
}
|
||||
#pragma code_seg()
|
||||
@@ -547,4 +563,31 @@ Return Value:
|
||||
|
||||
}
|
||||
|
||||
void Bus_EvtUserNotifyRequestComplete(
|
||||
_In_ DMFMODULE DmfModule,
|
||||
_In_ WDFREQUEST Request,
|
||||
_In_opt_ ULONG_PTR Context,
|
||||
_In_ NTSTATUS NtStatus
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(DmfModule);
|
||||
|
||||
auto pOutput = reinterpret_cast<PDS4_AWAIT_OUTPUT>(Context);
|
||||
PDS4_AWAIT_OUTPUT pNotify = NULL;
|
||||
size_t length = 0;
|
||||
|
||||
if (NT_SUCCESS(WdfRequestRetrieveOutputBuffer(
|
||||
Request,
|
||||
sizeof(DS4_AWAIT_OUTPUT),
|
||||
reinterpret_cast<PVOID*>(&pNotify),
|
||||
&length)))
|
||||
{
|
||||
RtlCopyMemory(pNotify, pOutput, sizeof(DS4_AWAIT_OUTPUT));
|
||||
|
||||
WdfRequestSetInformation(Request, sizeof(DS4_AWAIT_OUTPUT));
|
||||
}
|
||||
|
||||
WdfRequestComplete(Request, NtStatus);
|
||||
}
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
15
sys/Driver.h
15
sys/Driver.h
@@ -65,6 +65,11 @@ typedef struct _FDO_DEVICE_DATA
|
||||
//
|
||||
LONG NextSessionId;
|
||||
|
||||
//
|
||||
// Notification DMF module
|
||||
//
|
||||
DMFMODULE UserNotification;
|
||||
|
||||
} FDO_DEVICE_DATA, * PFDO_DEVICE_DATA;
|
||||
|
||||
#define FDO_FIRST_SESSION_ID 100
|
||||
@@ -77,7 +82,8 @@ WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DEVICE_DATA, FdoGetData)
|
||||
typedef struct _FDO_FILE_DATA
|
||||
{
|
||||
//
|
||||
// SessionId associated with file handle. Used to map file handles to emulated gamepad devices
|
||||
// SessionId associated with file handle.
|
||||
// Used to map file handles to emulated gamepad devices.
|
||||
//
|
||||
LONG SessionId;
|
||||
|
||||
@@ -111,6 +117,13 @@ DmfDeviceModulesAdd(
|
||||
_In_ PDMFMODULE_INIT DmfModuleInit
|
||||
);
|
||||
|
||||
void Bus_EvtUserNotifyRequestComplete(
|
||||
_In_ DMFMODULE DmfModule,
|
||||
_In_ WDFREQUEST Request,
|
||||
_In_opt_ ULONG_PTR Context,
|
||||
_In_ NTSTATUS NtStatus
|
||||
);
|
||||
|
||||
#pragma region Bus enumeration-specific functions
|
||||
|
||||
NTSTATUS
|
||||
|
||||
@@ -144,7 +144,7 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::PdoPrepareDevice(PWDFDEVICE_IN
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -342,9 +342,9 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::PdoInitContext()
|
||||
WdfRegistryClose(keyDS);
|
||||
WdfRegistryClose(keyTargets);
|
||||
WdfRegistryClose(keyParams);
|
||||
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -1021,10 +1021,21 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::UsbBulkOrInterruptTransfer(_UR
|
||||
static_cast<PUCHAR>(pTransfer->TransferBuffer) + DS4_OUTPUT_BUFFER_OFFSET,
|
||||
DS4_OUTPUT_BUFFER_LENGTH);
|
||||
|
||||
|
||||
this->_AwaitOutputCache.Size = sizeof(DS4_AWAIT_OUTPUT);
|
||||
this->_AwaitOutputCache.SerialNo = this->_SerialNo;
|
||||
RtlCopyMemory(
|
||||
this->_AwaitOutputCache.Report.Buffer,
|
||||
pTransfer->TransferBuffer,
|
||||
pTransfer->TransferBufferLength <= sizeof(DS4_OUTPUT_BUFFER)
|
||||
? pTransfer->TransferBufferLength
|
||||
: sizeof(DS4_OUTPUT_BUFFER)
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status = DMF_NotifyUserWithRequestMultiple_DataBroadcast(
|
||||
this->_OutputReportNotify,
|
||||
pTransfer->TransferBuffer,
|
||||
sizeof(DS4_AWAIT_OUTPUT_BUFFER),
|
||||
&this->_AwaitOutputCache,
|
||||
sizeof(DS4_AWAIT_OUTPUT),
|
||||
STATUS_SUCCESS
|
||||
)))
|
||||
{
|
||||
@@ -1035,6 +1046,7 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::UsbBulkOrInterruptTransfer(_UR
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (NT_SUCCESS(WdfIoQueueRetrieveNextRequest(
|
||||
this->_PendingNotificationRequests,
|
||||
¬ifyRequest)))
|
||||
@@ -1341,63 +1353,12 @@ 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 auto 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
|
||||
);
|
||||
UNREFERENCED_PARAMETER(DmfModuleInit);
|
||||
}
|
||||
|
||||
VOID ViGEm::Bus::Targets::EmulationTargetDS4::SetOutputReportNotifyModule(DMFMODULE Module)
|
||||
{
|
||||
this->_OutputReportNotify = Module;
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace ViGEm::Bus::Targets
|
||||
|
||||
NTSTATUS SubmitReportImpl(PVOID NewReport) override;
|
||||
|
||||
NTSTATUS OutputReportRequestProcess(WDFREQUEST Request) const;
|
||||
VOID SetOutputReportNotifyModule(DMFMODULE Module);
|
||||
|
||||
private:
|
||||
static EVT_WDF_TIMER PendingUsbRequestsTimerFunc;
|
||||
@@ -108,8 +108,6 @@ namespace ViGEm::Bus::Targets
|
||||
|
||||
static VOID GenerateRandomMacAddress(PMAC_ADDRESS Address);
|
||||
|
||||
static EVT_DMF_NotifyUserWithRequest_Complete EvtUserNotifyRequestComplete;
|
||||
|
||||
protected:
|
||||
void ProcessPendingNotification(WDFQUEUE Queue) override;
|
||||
|
||||
@@ -171,5 +169,10 @@ namespace ViGEm::Bus::Targets
|
||||
// User-mode notification on new output report
|
||||
//
|
||||
DMFMODULE _OutputReportNotify;
|
||||
|
||||
//
|
||||
// Memory for full output report request
|
||||
//
|
||||
DS4_AWAIT_OUTPUT _AwaitOutputCache;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -499,7 +499,7 @@ Bus_Ds4AwaitOutputHandler(
|
||||
_Out_ size_t* BytesReturned
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(DmfModule);
|
||||
UNREFERENCED_PARAMETER(Queue);
|
||||
UNREFERENCED_PARAMETER(IoctlCode);
|
||||
UNREFERENCED_PARAMETER(OutputBufferSize);
|
||||
UNREFERENCED_PARAMETER(InputBufferSize);
|
||||
@@ -509,8 +509,8 @@ Bus_Ds4AwaitOutputHandler(
|
||||
FuncEntry(TRACE_QUEUE);
|
||||
|
||||
NTSTATUS status;
|
||||
EmulationTargetPDO* pdo;
|
||||
PDS4_AWAIT_OUTPUT pDs4AwaitOut = (PDS4_AWAIT_OUTPUT)InputBuffer;
|
||||
PFDO_DEVICE_DATA pDevCtx = FdoGetData(DMF_ParentDeviceGet(DmfModule));
|
||||
|
||||
// This request only supports a single PDO at a time
|
||||
if (pDs4AwaitOut->SerialNo == 0)
|
||||
@@ -519,14 +519,14 @@ Bus_Ds4AwaitOutputHandler(
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!EmulationTargetPDO::GetPdoByTypeAndSerial(WdfIoQueueGetDevice(Queue), DualShock4Wired, pDs4AwaitOut->SerialNo, &pdo))
|
||||
if (!NT_SUCCESS(status = DMF_NotifyUserWithRequestMultiple_RequestProcess(
|
||||
pDevCtx->UserNotification,
|
||||
Request
|
||||
)))
|
||||
{
|
||||
status = STATUS_DEVICE_DOES_NOT_EXIST;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status = static_cast<EmulationTargetDS4*>(pdo)->OutputReportRequestProcess(Request);
|
||||
|
||||
status = NT_SUCCESS(status) ? STATUS_PENDING : status;
|
||||
|
||||
exit:
|
||||
|
||||
@@ -189,6 +189,11 @@ EXTERN_C NTSTATUS Bus_PlugInDevice(
|
||||
goto pluginEnd;
|
||||
}
|
||||
|
||||
if (plugIn->TargetType == DualShock4Wired)
|
||||
{
|
||||
static_cast<EmulationTargetDS4*>(description.Target)->SetOutputReportNotifyModule(FdoGetData(Device)->UserNotification);
|
||||
}
|
||||
|
||||
status = WdfChildListAddOrUpdateChildDescriptionAsPresent(
|
||||
WdfFdoGetDefaultChildList(Device),
|
||||
&description.Header,
|
||||
|
||||
Reference in New Issue
Block a user