mirror of
https://github.com/nefarius/ViGEmBus.git
synced 2025-08-10 00:52:17 +00:00
Implementing new notification logic
This commit is contained in:
@@ -1056,6 +1056,29 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::UsbBulkOrInterruptTransfer(_UR
|
||||
status);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PVOID clientBuffer, contextBuffer;
|
||||
|
||||
if (NT_SUCCESS(DMF_BufferQueue_Fetch(
|
||||
this->_UsbInterruptOutBufferQueue,
|
||||
&clientBuffer,
|
||||
&contextBuffer
|
||||
)))
|
||||
{
|
||||
RtlCopyMemory(
|
||||
clientBuffer,
|
||||
&this->_OutputReport,
|
||||
DS4_OUTPUT_BUFFER_LENGTH
|
||||
);
|
||||
|
||||
*static_cast<size_t*>(contextBuffer) = DS4_OUTPUT_BUFFER_LENGTH;
|
||||
|
||||
TraceDbg(TRACE_USBPDO, "Queued %Iu bytes", DS4_OUTPUT_BUFFER_LENGTH);
|
||||
|
||||
DMF_BufferQueue_Enqueue(this->_UsbInterruptOutBufferQueue, clientBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -1195,6 +1218,10 @@ VOID ViGEm::Bus::Targets::EmulationTargetDS4::GenerateRandomMacAddress(PMAC_ADDR
|
||||
Address->Nic2 = RtlRandomEx(&seed) % 0xFF;
|
||||
}
|
||||
|
||||
void ViGEm::Bus::Targets::EmulationTargetDS4::ProcessPendingNotification(WDFQUEUE Queue)
|
||||
{
|
||||
}
|
||||
|
||||
VOID ViGEm::Bus::Targets::EmulationTargetDS4::PendingUsbRequestsTimerFunc(
|
||||
_In_ WDFTIMER Timer
|
||||
)
|
||||
|
||||
@@ -105,7 +105,10 @@ namespace ViGEm::Bus::Targets
|
||||
static VOID ReverseByteArray(PUCHAR Array, INT Length);
|
||||
|
||||
static VOID GenerateRandomMacAddress(PMAC_ADDRESS Address);
|
||||
|
||||
|
||||
protected:
|
||||
void ProcessPendingNotification(WDFQUEUE Queue) override;
|
||||
private:
|
||||
static PCWSTR _deviceDescription;
|
||||
|
||||
static const int HID_REQUEST_GET_REPORT = 0x01;
|
||||
|
||||
@@ -255,6 +255,20 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
|
||||
break;
|
||||
}
|
||||
|
||||
status = WdfIoQueueReadyNotify(
|
||||
this->_PendingNotificationRequests,
|
||||
EvtWdfIoPendingNotificationQueueState,
|
||||
this
|
||||
);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfIoQueueReadyNotify (PendingNotificationRequests) failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Default I/O queue setup
|
||||
@@ -465,6 +479,8 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoPrepare(WDFDEVICE ParentDevice
|
||||
NTSTATUS status;
|
||||
WDF_OBJECT_ATTRIBUTES attributes;
|
||||
WDF_IO_QUEUE_CONFIG plugInQueueConfig;
|
||||
DMF_MODULE_ATTRIBUTES moduleAttributes;
|
||||
DMF_CONFIG_BufferQueue dmfBufferCfg;
|
||||
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
|
||||
attributes.ParentObject = ParentDevice;
|
||||
@@ -486,6 +502,41 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoPrepare(WDFDEVICE ParentDevice
|
||||
status);
|
||||
}
|
||||
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
|
||||
attributes.ParentObject = ParentDevice;
|
||||
|
||||
DMF_CONFIG_BufferQueue_AND_ATTRIBUTES_INIT(
|
||||
&dmfBufferCfg,
|
||||
&moduleAttributes
|
||||
);
|
||||
|
||||
// Don't auto-grow; start dropping packets on overrun
|
||||
dmfBufferCfg.SourceSettings.EnableLookAside = FALSE;
|
||||
// Maximum number of buffers to be filled and kept queued
|
||||
dmfBufferCfg.SourceSettings.BufferCount = MAX_OUT_BUFFER_QUEUE_COUNT;
|
||||
// Maximum byte count per buffer
|
||||
dmfBufferCfg.SourceSettings.BufferSize = MAX_OUT_BUFFER_QUEUE_SIZE;
|
||||
// Field to store real buffer content length
|
||||
dmfBufferCfg.SourceSettings.BufferContextSize = sizeof(size_t);
|
||||
// "Expensive" memory ;)
|
||||
dmfBufferCfg.SourceSettings.PoolType = NonPagedPoolNx;
|
||||
|
||||
status = DMF_BufferQueue_Create(
|
||||
ParentDevice,
|
||||
&moduleAttributes,
|
||||
&attributes,
|
||||
&this->_UsbInterruptOutBufferQueue
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"DMF_BufferQueue_Create failed with status %!STATUS!",
|
||||
status
|
||||
);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -1117,3 +1168,13 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
|
||||
TraceDbg(TRACE_BUSPDO, "%!FUNC! Exit with status %!STATUS!", status);
|
||||
}
|
||||
|
||||
void ViGEm::Bus::Core::EmulationTargetPDO::EvtWdfIoPendingNotificationQueueState(
|
||||
WDFQUEUE Queue,
|
||||
WDFCONTEXT Context
|
||||
)
|
||||
{
|
||||
const auto pThis = static_cast<EmulationTargetPDO*>(Context);
|
||||
|
||||
pThis->ProcessPendingNotification(Queue);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#pragma warning(disable:5040)
|
||||
#include <DmfModules.Library.h>
|
||||
#pragma warning(default:5040)
|
||||
#include <ntddk.h>
|
||||
#include <wdf.h>
|
||||
#include <ntintsafe.h>
|
||||
@@ -43,7 +46,6 @@
|
||||
#include <usbbusif.h>
|
||||
|
||||
#include <ViGEm/Common.h>
|
||||
#include <initguid.h>
|
||||
|
||||
//
|
||||
// Some insane macro-magic =3
|
||||
@@ -144,6 +146,10 @@ 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;
|
||||
|
||||
static BOOLEAN USB_BUSIFFN UsbInterfaceIsDeviceHighSpeed(IN PVOID BusContext);
|
||||
@@ -170,8 +176,12 @@ namespace ViGEm::Bus::Core
|
||||
|
||||
static EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl;
|
||||
|
||||
static EVT_WDF_IO_QUEUE_STATE EvtWdfIoPendingNotificationQueueState;
|
||||
|
||||
static VOID WaitDeviceReadyCompletionWorkerRoutine(IN PVOID StartContext);
|
||||
|
||||
static VOID DumpAsHex(PCSTR Prefix, PVOID Buffer, ULONG BufferLength);
|
||||
|
||||
virtual VOID GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length) = 0;
|
||||
|
||||
virtual NTSTATUS SelectConfiguration(PURB Urb) = 0;
|
||||
@@ -180,7 +190,7 @@ namespace ViGEm::Bus::Core
|
||||
|
||||
virtual NTSTATUS SubmitReportImpl(PVOID NewReport) = 0;
|
||||
|
||||
static VOID DumpAsHex(PCSTR Prefix, PVOID Buffer, ULONG BufferLength);
|
||||
virtual VOID ProcessPendingNotification(WDFQUEUE Queue) = 0;
|
||||
|
||||
//
|
||||
// PNP Capabilities may differ from device to device
|
||||
@@ -251,6 +261,11 @@ namespace ViGEm::Bus::Core
|
||||
// Signals the bus that PDO is ready to receive data
|
||||
//
|
||||
KEVENT _PdoBootNotificationEvent;
|
||||
|
||||
//
|
||||
// Queue for interrupt out requests delivered to user-land
|
||||
//
|
||||
DMFMODULE _UsbInterruptOutBufferQueue{};
|
||||
};
|
||||
|
||||
typedef struct _PDO_IDENTIFICATION_DESCRIPTION
|
||||
|
||||
@@ -814,6 +814,8 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::UsbBulkOrInterruptTransfer(_U
|
||||
pTransfer->TransferFlags,
|
||||
pTransfer->TransferBufferLength);
|
||||
|
||||
#pragma region Cache values
|
||||
|
||||
if (pTransfer->TransferBufferLength == XUSB_LEDSET_SIZE) // Led
|
||||
{
|
||||
auto Buffer = static_cast<PUCHAR>(pTransfer->TransferBuffer);
|
||||
@@ -835,12 +837,12 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::UsbBulkOrInterruptTransfer(_U
|
||||
TRACE_USBPDO,
|
||||
"-- LED Number: %d",
|
||||
this->_LedNumber);
|
||||
|
||||
//
|
||||
// Notify client library that PDO is ready
|
||||
//
|
||||
KeSetEvent(&this->_PdoBootNotificationEvent, 0, FALSE);
|
||||
}
|
||||
|
||||
//
|
||||
// Notify client library that PDO is ready
|
||||
//
|
||||
KeSetEvent(&this->_PdoBootNotificationEvent, 0, FALSE);
|
||||
}
|
||||
|
||||
// Extract rumble (vibration) information
|
||||
@@ -863,12 +865,17 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::UsbBulkOrInterruptTransfer(_U
|
||||
RtlCopyBytes(this->_Rumble, Buffer, pTransfer->TransferBufferLength);
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
// Notify user-mode process that new data is available
|
||||
status = WdfIoQueueRetrieveNextRequest(this->_PendingNotificationRequests, ¬ifyRequest);
|
||||
status = WdfIoQueueRetrieveNextRequest(
|
||||
this->_PendingNotificationRequests,
|
||||
¬ifyRequest
|
||||
);
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
PXUSB_REQUEST_NOTIFICATION notify = NULL;
|
||||
PXUSB_REQUEST_NOTIFICATION notify = nullptr;
|
||||
|
||||
status = WdfRequestRetrieveOutputBuffer(
|
||||
notifyRequest,
|
||||
@@ -891,17 +898,33 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::UsbBulkOrInterruptTransfer(_U
|
||||
else
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_USBPDO,
|
||||
"WdfRequestRetrieveOutputBuffer failed with status %!STATUS!",
|
||||
status);
|
||||
TRACE_USBPDO,
|
||||
"WdfRequestRetrieveOutputBuffer failed with status %!STATUS!",
|
||||
status);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_WARNING,
|
||||
TRACE_USBPDO,
|
||||
"!! WdfIoQueueRetrieveNextRequest failed with status %!STATUS!",
|
||||
status);
|
||||
PVOID clientBuffer, contextBuffer;
|
||||
|
||||
if (NT_SUCCESS(DMF_BufferQueue_Fetch(
|
||||
this->_UsbInterruptOutBufferQueue,
|
||||
&clientBuffer,
|
||||
&contextBuffer
|
||||
)) && pTransfer->TransferBufferLength <= MAX_OUT_BUFFER_QUEUE_SIZE)
|
||||
{
|
||||
RtlCopyMemory(
|
||||
clientBuffer,
|
||||
pTransfer->TransferBuffer,
|
||||
pTransfer->TransferBufferLength
|
||||
);
|
||||
|
||||
*static_cast<size_t*>(contextBuffer) = pTransfer->TransferBufferLength;
|
||||
|
||||
TraceDbg(TRACE_USBPDO, "Queued %Iu bytes", pTransfer->TransferBufferLength);
|
||||
|
||||
DMF_BufferQueue_Enqueue(this->_UsbInterruptOutBufferQueue, clientBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -1023,3 +1046,40 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::GetUserIndex(PULONG UserIndex
|
||||
// and need to fail this request with a distinct status.
|
||||
return STATUS_INVALID_DEVICE_OBJECT_PARAMETER;
|
||||
}
|
||||
|
||||
void ViGEm::Bus::Targets::EmulationTargetXUSB::ProcessPendingNotification(WDFQUEUE Queue)
|
||||
{
|
||||
NTSTATUS status;
|
||||
WDFREQUEST request;
|
||||
PVOID clientBuffer, contextBuffer;
|
||||
|
||||
//
|
||||
// No buffer available to answer the request with, leave queued
|
||||
//
|
||||
if (DMF_BufferQueue_Count(this->_UsbInterruptOutBufferQueue) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (NT_SUCCESS(WdfIoQueueRetrieveNextRequest(Queue, &request)))
|
||||
{
|
||||
status = DMF_BufferQueue_Dequeue(
|
||||
this->_UsbInterruptOutBufferQueue,
|
||||
&clientBuffer,
|
||||
&contextBuffer
|
||||
);
|
||||
|
||||
//
|
||||
// Shouldn't happen, but if so, error out
|
||||
//
|
||||
if(!NT_SUCCESS(status))
|
||||
{
|
||||
WdfRequestComplete(request, status);
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// TODO: finish implementation
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,9 @@ namespace ViGEm::Bus::Targets
|
||||
NTSTATUS SubmitReportImpl(PVOID NewReport) override;
|
||||
|
||||
NTSTATUS GetUserIndex(PULONG UserIndex) const;
|
||||
|
||||
|
||||
protected:
|
||||
void ProcessPendingNotification(WDFQUEUE Queue) override;
|
||||
private:
|
||||
static PCWSTR _deviceDescription;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user