mirror of
https://github.com/nefarius/ViGEmBus.git
synced 2025-08-10 00:52:17 +00:00
Implemented new plugin request tracking
This commit is contained in:
@@ -48,7 +48,6 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
|
||||
WDFQUEUE defaultPdoQueue;
|
||||
UNICODE_STRING deviceDescription;
|
||||
WDF_OBJECT_ATTRIBUTES attributes;
|
||||
WDF_IO_QUEUE_CONFIG plugInQueueConfig;
|
||||
WDF_IO_QUEUE_CONFIG usbInQueueConfig;
|
||||
WDF_IO_QUEUE_CONFIG notificationsQueueConfig;
|
||||
PEMULATION_TARGET_PDO_CONTEXT pPdoContext;
|
||||
@@ -77,9 +76,9 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfPdoInitAssignRawDevice failed with status %!STATUS!",
|
||||
status);
|
||||
TRACE_BUSPDO,
|
||||
"WdfPdoInitAssignRawDevice failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -89,9 +88,9 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfDeviceInitAssignSDDLString failed with status %!STATUS!",
|
||||
status);
|
||||
TRACE_BUSPDO,
|
||||
"WdfDeviceInitAssignSDDLString failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -109,9 +108,9 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfPdoInitAssignDeviceID failed with status %!STATUS!",
|
||||
status);
|
||||
TRACE_BUSPDO,
|
||||
"WdfPdoInitAssignDeviceID failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -120,9 +119,9 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"RtlUnicodeStringPrintf failed with status %!STATUS!",
|
||||
status);
|
||||
TRACE_BUSPDO,
|
||||
"RtlUnicodeStringPrintf failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -131,9 +130,9 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfPdoInitAssignInstanceID failed with status %!STATUS!",
|
||||
status);
|
||||
TRACE_BUSPDO,
|
||||
"WdfPdoInitAssignInstanceID failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -142,9 +141,9 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfPdoInitAddDeviceText failed with status %!STATUS!",
|
||||
status);
|
||||
TRACE_BUSPDO,
|
||||
"WdfPdoInitAddDeviceText failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -178,16 +177,16 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfDeviceCreate failed with status %!STATUS!",
|
||||
status);
|
||||
TRACE_BUSPDO,
|
||||
"WdfDeviceCreate failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
"Created PDO 0x%p",
|
||||
this->_PdoDevice);
|
||||
TRACE_BUSPDO,
|
||||
"Created PDO 0x%p",
|
||||
this->_PdoDevice);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
@@ -201,9 +200,9 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfDeviceCreateDeviceInterface failed with status %!STATUS!",
|
||||
status);
|
||||
TRACE_BUSPDO,
|
||||
"WdfDeviceCreateDeviceInterface failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -222,40 +221,19 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"Couldn't initialize additional contexts: %!STATUS!",
|
||||
status);
|
||||
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(&plugInQueueConfig, WdfIoQueueDispatchManual);
|
||||
|
||||
status = WdfIoQueueCreate(
|
||||
ParentDevice,
|
||||
&plugInQueueConfig,
|
||||
WDF_NO_OBJECT_ATTRIBUTES,
|
||||
&this->_PendingPlugInRequests
|
||||
);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfIoQueueCreate (PendingPlugInRequests) failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
|
||||
attributes.ParentObject = this->_PdoDevice;
|
||||
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
|
||||
attributes.ParentObject = this->_PdoDevice;
|
||||
|
||||
// Create and assign queue for incoming interrupt transfer
|
||||
WDF_IO_QUEUE_CONFIG_INIT(&usbInQueueConfig, WdfIoQueueDispatchManual);
|
||||
|
||||
@@ -268,15 +246,15 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfIoQueueCreate (PendingUsbInRequests) failed with status %!STATUS!",
|
||||
status);
|
||||
TRACE_BUSPDO,
|
||||
"WdfIoQueueCreate (PendingUsbInRequests) failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
|
||||
attributes.ParentObject = this->_PdoDevice;
|
||||
|
||||
|
||||
// Create and assign queue for user-land notification requests
|
||||
WDF_IO_QUEUE_CONFIG_INIT(¬ificationsQueueConfig, WdfIoQueueDispatchManual);
|
||||
|
||||
@@ -289,19 +267,19 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfIoQueueCreate (PendingNotificationRequests) failed with status %!STATUS!",
|
||||
status);
|
||||
TRACE_BUSPDO,
|
||||
"WdfIoQueueCreate (PendingNotificationRequests) failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Default I/O queue setup
|
||||
|
||||
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
|
||||
attributes.ParentObject = this->_PdoDevice;
|
||||
|
||||
|
||||
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&defaultPdoQueueConfig, WdfIoQueueDispatchParallel);
|
||||
|
||||
defaultPdoQueueConfig.EvtIoInternalDeviceControl = EvtIoInternalDeviceControl;
|
||||
@@ -315,9 +293,9 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfIoQueueCreate (Default) failed with status %!STATUS!",
|
||||
status);
|
||||
TRACE_BUSPDO,
|
||||
"WdfIoQueueCreate (Default) failed with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -356,8 +334,7 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
|
||||
WdfDeviceSetPowerCapabilities(this->_PdoDevice, &powerCaps);
|
||||
|
||||
#pragma endregion
|
||||
}
|
||||
while (FALSE);
|
||||
} while (FALSE);
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSPDO, "%!FUNC! Exit with status %!STATUS!", status);
|
||||
|
||||
@@ -372,6 +349,12 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtDeviceContextCleanup(
|
||||
|
||||
const auto ctx = EmulationTargetPdoGetContext(Device);
|
||||
|
||||
//
|
||||
// This queues parent is the FDO so explicitly free memory
|
||||
//
|
||||
WdfIoQueuePurgeSynchronously(ctx->Target->_PendingPlugInRequests);
|
||||
WdfObjectDelete(ctx->Target->_PendingPlugInRequests);
|
||||
|
||||
//
|
||||
// PDO device object getting disposed, free context object
|
||||
//
|
||||
@@ -380,28 +363,18 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtDeviceContextCleanup(
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_BUSPDO, "%!FUNC! Exit");
|
||||
}
|
||||
|
||||
VOID ViGEm::Bus::Core::EmulationTargetPDO::SetSerial(ULONG Serial)
|
||||
{
|
||||
this->_SerialNo = Serial;
|
||||
}
|
||||
|
||||
ULONG ViGEm::Bus::Core::EmulationTargetPDO::GetSerial() const
|
||||
{
|
||||
return this->_SerialNo;
|
||||
}
|
||||
|
||||
NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::SubmitReport(PVOID NewReport)
|
||||
{
|
||||
return (this->IsOwnerProcess())
|
||||
? this->SubmitReportImpl(NewReport)
|
||||
: STATUS_ACCESS_DENIED;
|
||||
? this->SubmitReportImpl(NewReport)
|
||||
: STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::EnqueueNotification(WDFREQUEST Request) const
|
||||
{
|
||||
return (this->IsOwnerProcess())
|
||||
? WdfRequestForwardToIoQueue(Request, this->_PendingNotificationRequests)
|
||||
: STATUS_ACCESS_DENIED;
|
||||
? WdfRequestForwardToIoQueue(Request, this->_PendingNotificationRequests)
|
||||
: STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
bool ViGEm::Bus::Core::EmulationTargetPDO::IsOwnerProcess() const
|
||||
@@ -414,6 +387,88 @@ VIGEM_TARGET_TYPE ViGEm::Bus::Core::EmulationTargetPDO::GetType() const
|
||||
return this->_TargetType;
|
||||
}
|
||||
|
||||
NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::EnqueuePlugin(WDFREQUEST Request)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
if (!this->IsOwnerProcess())
|
||||
{
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (!this->_PendingPlugInRequests)
|
||||
{
|
||||
return STATUS_INVALID_DEVICE_STATE;
|
||||
}
|
||||
|
||||
status = WdfRequestForwardToIoQueue(Request, this->_PendingPlugInRequests);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfRequestForwardToIoQueue failed with status %!STATUS!",
|
||||
status
|
||||
);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
OBJECT_ATTRIBUTES threadOb;
|
||||
|
||||
InitializeObjectAttributes(&threadOb, NULL,
|
||||
OBJ_KERNEL_HANDLE, NULL, NULL);
|
||||
|
||||
status = PsCreateSystemThread(&_PluginRequestCompletionWorkerThreadHandle,
|
||||
static_cast<ACCESS_MASK>(0L),
|
||||
&threadOb,
|
||||
nullptr,
|
||||
nullptr,
|
||||
PluginRequestCompletionWorkerRoutine,
|
||||
this
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"PsCreateSystemThread failed with status %!STATUS!",
|
||||
status
|
||||
);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoPrepare(WDFDEVICE ParentDevice)
|
||||
{
|
||||
NTSTATUS status;
|
||||
WDF_OBJECT_ATTRIBUTES attributes;
|
||||
WDF_IO_QUEUE_CONFIG plugInQueueConfig;
|
||||
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
|
||||
attributes.ParentObject = ParentDevice;
|
||||
|
||||
// Create and assign queue for incoming interrupt transfer
|
||||
WDF_IO_QUEUE_CONFIG_INIT(&plugInQueueConfig, WdfIoQueueDispatchManual);
|
||||
|
||||
status = WdfIoQueueCreate(
|
||||
ParentDevice,
|
||||
&plugInQueueConfig,
|
||||
WDF_NO_OBJECT_ATTRIBUTES,
|
||||
&this->_PendingPlugInRequests
|
||||
);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSPDO,
|
||||
"WdfIoQueueCreate (PendingPlugInRequests) failed with status %!STATUS!",
|
||||
status);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
unsigned long ViGEm::Bus::Core::EmulationTargetPDO::current_process_id()
|
||||
{
|
||||
return static_cast<DWORD>(reinterpret_cast<DWORD_PTR>(PsGetCurrentProcessId()) & 0xFFFFFFFF);
|
||||
@@ -461,9 +516,9 @@ NTSTATUS USB_BUSIFFN ViGEm::Bus::Core::EmulationTargetPDO::UsbInterfaceQueryBusT
|
||||
}
|
||||
|
||||
VOID USB_BUSIFFN ViGEm::Bus::Core::EmulationTargetPDO::UsbInterfaceGetUSBDIVersion(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);
|
||||
|
||||
@@ -479,8 +534,76 @@ VOID USB_BUSIFFN ViGEm::Bus::Core::EmulationTargetPDO::UsbInterfaceGetUSBDIVersi
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma endregion
|
||||
|
||||
VOID ViGEm::Bus::Core::EmulationTargetPDO::PluginRequestCompletionWorkerRoutine(IN PVOID StartContext)
|
||||
{
|
||||
const auto ctx = static_cast<EmulationTargetPDO*>(StartContext);
|
||||
|
||||
WDFREQUEST pluginRequest;
|
||||
LARGE_INTEGER timeout;
|
||||
timeout.QuadPart = WDF_REL_TIMEOUT_IN_SEC(1);;
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION,
|
||||
TRACE_BUSPDO,
|
||||
"Waiting for 1 second to complete PDO boot..."
|
||||
);
|
||||
|
||||
NTSTATUS status = KeWaitForSingleObject(
|
||||
&ctx->_PdoBootNotificationEvent,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
&timeout
|
||||
);
|
||||
|
||||
do
|
||||
{
|
||||
//
|
||||
// Fetch pending request (there has to be one at this point)
|
||||
//
|
||||
if (!NT_SUCCESS(WdfIoQueueRetrieveNextRequest(ctx->_PendingPlugInRequests, &pluginRequest)))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_WARNING,
|
||||
TRACE_BUSPDO,
|
||||
"No pending plugin request available"
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
if (status == STATUS_TIMEOUT)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_WARNING,
|
||||
TRACE_BUSPDO,
|
||||
"Plugin request timed out, completing with error"
|
||||
);
|
||||
|
||||
//
|
||||
// We haven't hit a path where the event gets signaled, report error
|
||||
//
|
||||
WdfRequestComplete(pluginRequest, STATUS_DEVICE_HARDWARE_ERROR);
|
||||
break;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION,
|
||||
TRACE_BUSPDO,
|
||||
"Plugin request completed successfully"
|
||||
);
|
||||
|
||||
//
|
||||
// Event triggered in time, complete with success
|
||||
//
|
||||
WdfRequestComplete(pluginRequest, STATUS_SUCCESS);
|
||||
break;
|
||||
}
|
||||
} while (FALSE);
|
||||
|
||||
KeClearEvent(&ctx->_PdoBootNotificationEvent);
|
||||
}
|
||||
|
||||
void ViGEm::Bus::Core::EmulationTargetPDO::UsbAbortPipe()
|
||||
{
|
||||
this->AbortPipe();
|
||||
@@ -518,15 +641,15 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::UsbGetConfigurationDescriptorType
|
||||
NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::UsbSelectConfiguration(PURB Urb)
|
||||
{
|
||||
TraceDbg(
|
||||
TRACE_USBPDO,
|
||||
">> >> >> URB_FUNCTION_SELECT_CONFIGURATION: TotalLength %d",
|
||||
Urb->UrbHeader.Length);
|
||||
TRACE_USBPDO,
|
||||
">> >> >> URB_FUNCTION_SELECT_CONFIGURATION: TotalLength %d",
|
||||
Urb->UrbHeader.Length);
|
||||
|
||||
if (Urb->UrbHeader.Length == sizeof(struct _URB_SELECT_CONFIGURATION))
|
||||
{
|
||||
TraceDbg(
|
||||
TRACE_USBPDO,
|
||||
">> >> >> URB_FUNCTION_SELECT_CONFIGURATION: NULL ConfigurationDescriptor");
|
||||
TRACE_USBPDO,
|
||||
">> >> >> URB_FUNCTION_SELECT_CONFIGURATION: NULL ConfigurationDescriptor");
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -535,9 +658,9 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::UsbSelectConfiguration(PURB Urb)
|
||||
|
||||
ViGEm::Bus::Core::EmulationTargetPDO::
|
||||
EmulationTargetPDO(ULONG Serial, LONG SessionId, USHORT VendorId, USHORT ProductId) : _SerialNo(Serial),
|
||||
_SessionId(SessionId),
|
||||
_VendorId(VendorId),
|
||||
_ProductId(ProductId)
|
||||
_SessionId(SessionId),
|
||||
_VendorId(VendorId),
|
||||
_ProductId(ProductId)
|
||||
{
|
||||
this->_OwnerProcessId = current_process_id();
|
||||
KeInitializeEvent(&this->_PdoBootNotificationEvent, NotificationEvent, FALSE);
|
||||
@@ -571,7 +694,8 @@ bool ViGEm::Bus::Core::EmulationTargetPDO::GetPdoBySerial(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ViGEm::Bus::Core::EmulationTargetPDO::GetPdoByTypeAndSerial(IN WDFDEVICE ParentDevice, IN VIGEM_TARGET_TYPE Type, IN ULONG SerialNo, OUT EmulationTargetPDO** Object)
|
||||
bool ViGEm::Bus::Core::EmulationTargetPDO::GetPdoByTypeAndSerial(IN WDFDEVICE ParentDevice, IN VIGEM_TARGET_TYPE Type,
|
||||
IN ULONG SerialNo, OUT EmulationTargetPDO** Object)
|
||||
{
|
||||
return (GetPdoBySerial(ParentDevice, SerialNo, Object) && (*Object)->GetType() == Type);
|
||||
}
|
||||
@@ -625,8 +749,8 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
case IOCTL_INTERNAL_USB_SUBMIT_URB:
|
||||
|
||||
TraceDbg(
|
||||
TRACE_BUSPDO,
|
||||
">> IOCTL_INTERNAL_USB_SUBMIT_URB");
|
||||
TRACE_BUSPDO,
|
||||
">> IOCTL_INTERNAL_USB_SUBMIT_URB");
|
||||
|
||||
urb = static_cast<PURB>(URB_FROM_IRP(irp));
|
||||
|
||||
@@ -635,8 +759,8 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
case URB_FUNCTION_CONTROL_TRANSFER:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_CONTROL_TRANSFER");
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_CONTROL_TRANSFER");
|
||||
|
||||
status = ctx->Target->UsbControlTransfer(urb);
|
||||
|
||||
@@ -645,8 +769,8 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
case URB_FUNCTION_CONTROL_TRANSFER_EX:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_CONTROL_TRANSFER_EX");
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_CONTROL_TRANSFER_EX");
|
||||
|
||||
status = STATUS_UNSUCCESSFUL;
|
||||
|
||||
@@ -665,8 +789,8 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
case URB_FUNCTION_SELECT_CONFIGURATION:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_SELECT_CONFIGURATION");
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_SELECT_CONFIGURATION");
|
||||
|
||||
status = ctx->Target->UsbSelectConfiguration(urb);
|
||||
|
||||
@@ -675,8 +799,8 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
case URB_FUNCTION_SELECT_INTERFACE:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_SELECT_INTERFACE");
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_SELECT_INTERFACE");
|
||||
|
||||
status = ctx->Target->UsbSelectInterface(urb);
|
||||
|
||||
@@ -685,16 +809,16 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE");
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE");
|
||||
|
||||
switch (urb->UrbControlDescriptorRequest.DescriptorType)
|
||||
{
|
||||
case USB_DEVICE_DESCRIPTOR_TYPE:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> >> >> USB_DEVICE_DESCRIPTOR_TYPE");
|
||||
TRACE_BUSPDO,
|
||||
">> >> >> USB_DEVICE_DESCRIPTOR_TYPE");
|
||||
|
||||
status = ctx->Target->UsbGetDeviceDescriptorType(
|
||||
static_cast<PUSB_DEVICE_DESCRIPTOR>(urb->UrbControlDescriptorRequest.TransferBuffer));
|
||||
@@ -704,8 +828,8 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
case USB_CONFIGURATION_DESCRIPTOR_TYPE:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> >> >> USB_CONFIGURATION_DESCRIPTOR_TYPE");
|
||||
TRACE_BUSPDO,
|
||||
">> >> >> USB_CONFIGURATION_DESCRIPTOR_TYPE");
|
||||
|
||||
status = ctx->Target->UsbGetConfigurationDescriptorType(urb);
|
||||
|
||||
@@ -714,8 +838,8 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
case USB_STRING_DESCRIPTOR_TYPE:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> >> >> USB_STRING_DESCRIPTOR_TYPE");
|
||||
TRACE_BUSPDO,
|
||||
">> >> >> USB_STRING_DESCRIPTOR_TYPE");
|
||||
|
||||
status = ctx->Target->UsbGetStringDescriptorType(urb);
|
||||
|
||||
@@ -724,23 +848,23 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
default:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> >> >> Unknown descriptor type");
|
||||
TRACE_BUSPDO,
|
||||
">> >> >> Unknown descriptor type");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
TraceDbg(
|
||||
TRACE_BUSPDO,
|
||||
"<< <<");
|
||||
TRACE_BUSPDO,
|
||||
"<< <<");
|
||||
|
||||
break;
|
||||
|
||||
case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_GET_STATUS_FROM_DEVICE");
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_GET_STATUS_FROM_DEVICE");
|
||||
|
||||
// Defaults always succeed
|
||||
status = STATUS_SUCCESS;
|
||||
@@ -750,8 +874,8 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
case URB_FUNCTION_ABORT_PIPE:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_ABORT_PIPE");
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_ABORT_PIPE");
|
||||
|
||||
ctx->Target->UsbAbortPipe();
|
||||
|
||||
@@ -760,8 +884,8 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
case URB_FUNCTION_CLASS_INTERFACE:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_CLASS_INTERFACE");
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_CLASS_INTERFACE");
|
||||
|
||||
status = ctx->Target->UsbClassInterface(urb);
|
||||
|
||||
@@ -770,8 +894,8 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE");
|
||||
TRACE_BUSPDO,
|
||||
">> >> URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE");
|
||||
|
||||
status = ctx->Target->UsbGetDescriptorFromInterface(urb);
|
||||
|
||||
@@ -780,24 +904,24 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
default:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> >> Unknown function: 0x%X",
|
||||
urb->UrbHeader.Function);
|
||||
TRACE_BUSPDO,
|
||||
">> >> Unknown function: 0x%X",
|
||||
urb->UrbHeader.Function);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
TraceDbg(
|
||||
TRACE_BUSPDO,
|
||||
"<<");
|
||||
TRACE_BUSPDO,
|
||||
"<<");
|
||||
|
||||
break;
|
||||
|
||||
case IOCTL_INTERNAL_USB_GET_PORT_STATUS:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> IOCTL_INTERNAL_USB_GET_PORT_STATUS");
|
||||
TRACE_BUSPDO,
|
||||
">> IOCTL_INTERNAL_USB_GET_PORT_STATUS");
|
||||
|
||||
// We report the (virtual) port as always active
|
||||
*static_cast<unsigned long*>(irpStack->Parameters.Others.Argument1) = USBD_PORT_ENABLED | USBD_PORT_CONNECTED;
|
||||
@@ -809,8 +933,8 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
case IOCTL_INTERNAL_USB_RESET_PORT:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> IOCTL_INTERNAL_USB_RESET_PORT");
|
||||
TRACE_BUSPDO,
|
||||
">> IOCTL_INTERNAL_USB_RESET_PORT");
|
||||
|
||||
// Sure, why not ;)
|
||||
status = STATUS_SUCCESS;
|
||||
@@ -820,8 +944,8 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION");
|
||||
TRACE_BUSPDO,
|
||||
">> IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION");
|
||||
|
||||
// TODO: implement?
|
||||
// This happens if the I/O latency is too high so HIDUSB aborts communication.
|
||||
@@ -832,9 +956,9 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtIoInternalDeviceControl(
|
||||
default:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSPDO,
|
||||
">> Unknown I/O control code 0x%X",
|
||||
IoControlCode);
|
||||
TRACE_BUSPDO,
|
||||
">> Unknown I/O control code 0x%X",
|
||||
IoControlCode);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -72,10 +72,6 @@ namespace ViGEm::Bus::Core
|
||||
NTSTATUS PdoCreateDevice(_In_ WDFDEVICE ParentDevice,
|
||||
_In_ PWDFDEVICE_INIT DeviceInit);
|
||||
|
||||
VOID SetSerial(ULONG Serial);
|
||||
|
||||
ULONG GetSerial() const;
|
||||
|
||||
bool operator==(EmulationTargetPDO& other) const
|
||||
{
|
||||
return (other._SerialNo == this->_SerialNo);
|
||||
@@ -110,6 +106,10 @@ namespace ViGEm::Bus::Core
|
||||
|
||||
VIGEM_TARGET_TYPE GetType() const;
|
||||
|
||||
NTSTATUS EnqueuePlugin(WDFREQUEST Request);
|
||||
|
||||
NTSTATUS PdoPrepare(WDFDEVICE ParentDevice);
|
||||
|
||||
private:
|
||||
static unsigned long current_process_id();
|
||||
|
||||
@@ -121,6 +121,8 @@ namespace ViGEm::Bus::Core
|
||||
OUT EmulationTargetPDO** Object
|
||||
);
|
||||
|
||||
HANDLE _PluginRequestCompletionWorkerThreadHandle{};
|
||||
|
||||
protected:
|
||||
static const ULONG _maxHardwareIdLength = 0xFF;
|
||||
|
||||
@@ -150,6 +152,8 @@ namespace ViGEm::Bus::Core
|
||||
|
||||
static EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl;
|
||||
|
||||
static VOID PluginRequestCompletionWorkerRoutine(IN PVOID StartContext);
|
||||
|
||||
static const int MAX_INSTANCE_ID_LEN = 80;
|
||||
|
||||
virtual VOID GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length) = 0;
|
||||
@@ -209,16 +213,16 @@ namespace ViGEm::Bus::Core
|
||||
// This child objects' device object
|
||||
//
|
||||
WDFDEVICE _PdoDevice{};
|
||||
|
||||
//
|
||||
// Configuration descriptor size
|
||||
//
|
||||
ULONG _UsbConfigurationDescriptionSize{};
|
||||
|
||||
//
|
||||
// Signals the bus that PDO is ready to receive data
|
||||
//
|
||||
KEVENT _PdoBootNotificationEvent;
|
||||
|
||||
//
|
||||
// Configuration descriptor size
|
||||
//
|
||||
ULONG _UsbConfigurationDescriptionSize{};
|
||||
};
|
||||
|
||||
typedef struct _PDO_IDENTIFICATION_DESCRIPTION
|
||||
|
||||
@@ -213,6 +213,9 @@
|
||||
<ClCompile Include="Util.c" />
|
||||
<ClCompile Include="XusbPdo.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="cpp.hint" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
||||
@@ -110,4 +110,7 @@
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="cpp.hint" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
525
sys/busenum.cpp
525
sys/busenum.cpp
@@ -46,324 +46,331 @@ using ViGEm::Bus::Targets::EmulationTargetDS4;
|
||||
// Simulates a device plug-in event.
|
||||
//
|
||||
EXTERN_C NTSTATUS Bus_PlugInDevice(
|
||||
_In_ WDFDEVICE Device,
|
||||
_In_ WDFREQUEST Request,
|
||||
_In_ BOOLEAN IsInternal,
|
||||
_Out_ size_t* Transferred)
|
||||
_In_ WDFDEVICE Device,
|
||||
_In_ WDFREQUEST Request,
|
||||
_In_ BOOLEAN IsInternal,
|
||||
_Out_ size_t* Transferred)
|
||||
{
|
||||
PDO_IDENTIFICATION_DESCRIPTION description;
|
||||
NTSTATUS status;
|
||||
PVIGEM_PLUGIN_TARGET plugIn;
|
||||
WDFFILEOBJECT fileObject;
|
||||
PFDO_FILE_DATA pFileData;
|
||||
size_t length = 0;
|
||||
NTSTATUS status;
|
||||
PVIGEM_PLUGIN_TARGET plugIn;
|
||||
WDFFILEOBJECT fileObject;
|
||||
PFDO_FILE_DATA pFileData;
|
||||
size_t length = 0;
|
||||
|
||||
UNREFERENCED_PARAMETER(IsInternal);
|
||||
|
||||
PAGED_CODE();
|
||||
UNREFERENCED_PARAMETER(IsInternal);
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSENUM, "%!FUNC! Entry");
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSENUM, "%!FUNC! Entry");
|
||||
|
||||
status = WdfRequestRetrieveInputBuffer(
|
||||
Request,
|
||||
sizeof(VIGEM_PLUGIN_TARGET),
|
||||
reinterpret_cast<PVOID*>(&plugIn),
|
||||
&length
|
||||
);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"WdfRequestRetrieveInputBuffer failed with status %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
status = WdfRequestRetrieveInputBuffer(
|
||||
Request,
|
||||
sizeof(VIGEM_PLUGIN_TARGET),
|
||||
reinterpret_cast<PVOID*>(&plugIn),
|
||||
&length
|
||||
);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"WdfRequestRetrieveInputBuffer failed with status %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
if ((sizeof(VIGEM_PLUGIN_TARGET) != plugIn->Size) || (length != plugIn->Size))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"sizeof(VIGEM_PLUGIN_TARGET) buffer size mismatch [%d != %d]",
|
||||
sizeof(VIGEM_PLUGIN_TARGET), plugIn->Size);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
if ((sizeof(VIGEM_PLUGIN_TARGET) != plugIn->Size) || (length != plugIn->Size))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"sizeof(VIGEM_PLUGIN_TARGET) buffer size mismatch [%d != %d]",
|
||||
sizeof(VIGEM_PLUGIN_TARGET), plugIn->Size);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (plugIn->SerialNo == 0)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"Serial no. 0 not allowed");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
if (plugIn->SerialNo == 0)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"Serial no. 0 not allowed");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
*Transferred = length;
|
||||
*Transferred = length;
|
||||
|
||||
fileObject = WdfRequestGetFileObject(Request);
|
||||
if (fileObject == NULL)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"WdfRequestGetFileObject failed to fetch WDFFILEOBJECT from request 0x%p",
|
||||
Request);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
fileObject = WdfRequestGetFileObject(Request);
|
||||
if (fileObject == NULL)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"WdfRequestGetFileObject failed to fetch WDFFILEOBJECT from request 0x%p",
|
||||
Request);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
pFileData = FileObjectGetData(fileObject);
|
||||
if (pFileData == NULL)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"FileObjectGetData failed to get context data for 0x%p",
|
||||
fileObject);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
pFileData = FileObjectGetData(fileObject);
|
||||
if (pFileData == NULL)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"FileObjectGetData failed to get context data for 0x%p",
|
||||
fileObject);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize the description with the information about the newly
|
||||
// plugged in device.
|
||||
//
|
||||
WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&description.Header, sizeof(description));
|
||||
//
|
||||
// Initialize the description with the information about the newly
|
||||
// plugged in device.
|
||||
//
|
||||
WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&description.Header, sizeof(description));
|
||||
|
||||
description.SerialNo = plugIn->SerialNo;
|
||||
description.SessionId = pFileData->SessionId;
|
||||
|
||||
// Set default IDs if supplied values are invalid
|
||||
if (plugIn->VendorId == 0 || plugIn->ProductId == 0)
|
||||
{
|
||||
switch (plugIn->TargetType)
|
||||
{
|
||||
case Xbox360Wired:
|
||||
description.SerialNo = plugIn->SerialNo;
|
||||
description.SessionId = pFileData->SessionId;
|
||||
|
||||
description.Target = new EmulationTargetXUSB(plugIn->SerialNo, pFileData->SessionId);
|
||||
// Set default IDs if supplied values are invalid
|
||||
if (plugIn->VendorId == 0 || plugIn->ProductId == 0)
|
||||
{
|
||||
switch (plugIn->TargetType)
|
||||
{
|
||||
case Xbox360Wired:
|
||||
|
||||
break;
|
||||
case DualShock4Wired:
|
||||
description.Target = new EmulationTargetXUSB(plugIn->SerialNo, pFileData->SessionId);
|
||||
|
||||
description.Target = new EmulationTargetDS4(plugIn->SerialNo, pFileData->SessionId);
|
||||
break;
|
||||
case DualShock4Wired:
|
||||
|
||||
break;
|
||||
default:
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (plugIn->TargetType)
|
||||
{
|
||||
case Xbox360Wired:
|
||||
description.Target = new EmulationTargetDS4(plugIn->SerialNo, pFileData->SessionId);
|
||||
|
||||
description.Target = new EmulationTargetXUSB(
|
||||
plugIn->SerialNo,
|
||||
pFileData->SessionId,
|
||||
plugIn->VendorId,
|
||||
plugIn->ProductId
|
||||
);
|
||||
break;
|
||||
default:
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (plugIn->TargetType)
|
||||
{
|
||||
case Xbox360Wired:
|
||||
|
||||
break;
|
||||
case DualShock4Wired:
|
||||
description.Target = new EmulationTargetXUSB(
|
||||
plugIn->SerialNo,
|
||||
pFileData->SessionId,
|
||||
plugIn->VendorId,
|
||||
plugIn->ProductId
|
||||
);
|
||||
|
||||
description.Target = new EmulationTargetDS4(
|
||||
plugIn->SerialNo,
|
||||
pFileData->SessionId,
|
||||
plugIn->VendorId,
|
||||
plugIn->ProductId
|
||||
);
|
||||
break;
|
||||
case DualShock4Wired:
|
||||
|
||||
break;
|
||||
default:
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
description.Target = new EmulationTargetDS4(
|
||||
plugIn->SerialNo,
|
||||
pFileData->SessionId,
|
||||
plugIn->VendorId,
|
||||
plugIn->ProductId
|
||||
);
|
||||
|
||||
status = WdfChildListAddOrUpdateChildDescriptionAsPresent(
|
||||
WdfFdoGetDefaultChildList(Device),
|
||||
&description.Header,
|
||||
NULL
|
||||
);
|
||||
break;
|
||||
default:
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"WdfChildListAddOrUpdateChildDescriptionAsPresent failed with status %!STATUS!",
|
||||
status);
|
||||
if (!NT_SUCCESS(description.Target->PdoPrepare(Device)))
|
||||
{
|
||||
goto pluginEnd;
|
||||
}
|
||||
|
||||
goto pluginEnd;
|
||||
}
|
||||
status = WdfChildListAddOrUpdateChildDescriptionAsPresent(
|
||||
WdfFdoGetDefaultChildList(Device),
|
||||
&description.Header,
|
||||
NULL
|
||||
);
|
||||
|
||||
//
|
||||
// The requested serial number is already in use
|
||||
//
|
||||
if (status == STATUS_OBJECT_NAME_EXISTS)
|
||||
{
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"WdfChildListAddOrUpdateChildDescriptionAsPresent failed with status %!STATUS!",
|
||||
status);
|
||||
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"The described PDO already exists (%!STATUS!)",
|
||||
status);
|
||||
goto pluginEnd;
|
||||
}
|
||||
|
||||
goto pluginEnd;
|
||||
}
|
||||
//
|
||||
// The requested serial number is already in use
|
||||
//
|
||||
if (status == STATUS_OBJECT_NAME_EXISTS)
|
||||
{
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
//status = NT_SUCCESS(status) ? STATUS_PENDING : status;
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"The described PDO already exists (%!STATUS!)",
|
||||
status);
|
||||
|
||||
goto pluginEnd;
|
||||
}
|
||||
|
||||
status = description.Target->EnqueuePlugin(Request);
|
||||
|
||||
status = NT_SUCCESS(status) ? STATUS_PENDING : status;
|
||||
|
||||
pluginEnd:
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSENUM, "%!FUNC! Exit with status %!STATUS!", status);
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSENUM, "%!FUNC! Exit with status %!STATUS!", status);
|
||||
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Simulates a device unplug event.
|
||||
//
|
||||
EXTERN_C NTSTATUS Bus_UnPlugDevice(
|
||||
_In_ WDFDEVICE Device,
|
||||
_In_ WDFREQUEST Request,
|
||||
_In_ BOOLEAN IsInternal,
|
||||
_Out_ size_t* Transferred)
|
||||
_In_ WDFDEVICE Device,
|
||||
_In_ WDFREQUEST Request,
|
||||
_In_ BOOLEAN IsInternal,
|
||||
_Out_ size_t* Transferred)
|
||||
{
|
||||
NTSTATUS status;
|
||||
WDFDEVICE hChild;
|
||||
WDFCHILDLIST list;
|
||||
WDF_CHILD_LIST_ITERATOR iterator;
|
||||
WDF_CHILD_RETRIEVE_INFO childInfo;
|
||||
PDO_IDENTIFICATION_DESCRIPTION description;
|
||||
BOOLEAN unplugAll;
|
||||
PVIGEM_UNPLUG_TARGET unPlug;
|
||||
WDFFILEOBJECT fileObject;
|
||||
PFDO_FILE_DATA pFileData = NULL;
|
||||
size_t length = 0;
|
||||
|
||||
PAGED_CODE();
|
||||
NTSTATUS status;
|
||||
WDFDEVICE hChild;
|
||||
WDFCHILDLIST list;
|
||||
WDF_CHILD_LIST_ITERATOR iterator;
|
||||
WDF_CHILD_RETRIEVE_INFO childInfo;
|
||||
PDO_IDENTIFICATION_DESCRIPTION description;
|
||||
BOOLEAN unplugAll;
|
||||
PVIGEM_UNPLUG_TARGET unPlug;
|
||||
WDFFILEOBJECT fileObject;
|
||||
PFDO_FILE_DATA pFileData = NULL;
|
||||
size_t length = 0;
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSENUM, "%!FUNC! Entry");
|
||||
PAGED_CODE();
|
||||
|
||||
status = WdfRequestRetrieveInputBuffer(
|
||||
Request,
|
||||
sizeof(VIGEM_UNPLUG_TARGET),
|
||||
(PVOID*)&unPlug,
|
||||
&length
|
||||
);
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSENUM, "%!FUNC! Entry");
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"WdfRequestRetrieveInputBuffer failed with status %!STATUS!",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
status = WdfRequestRetrieveInputBuffer(
|
||||
Request,
|
||||
sizeof(VIGEM_UNPLUG_TARGET),
|
||||
(PVOID*)&unPlug,
|
||||
&length
|
||||
);
|
||||
|
||||
if ((sizeof(VIGEM_UNPLUG_TARGET) != unPlug->Size) || (length != unPlug->Size))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"sizeof(VIGEM_UNPLUG_TARGET) buffer size mismatch [%d != %d]",
|
||||
sizeof(VIGEM_UNPLUG_TARGET), unPlug->Size);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"WdfRequestRetrieveInputBuffer failed with status %!STATUS!",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
*Transferred = length;
|
||||
unplugAll = (unPlug->SerialNo == 0);
|
||||
if ((sizeof(VIGEM_UNPLUG_TARGET) != unPlug->Size) || (length != unPlug->Size))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"sizeof(VIGEM_UNPLUG_TARGET) buffer size mismatch [%d != %d]",
|
||||
sizeof(VIGEM_UNPLUG_TARGET), unPlug->Size);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
fileObject = WdfRequestGetFileObject(Request);
|
||||
if (fileObject == NULL)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"WdfRequestGetFileObject failed to fetch WDFFILEOBJECT from request 0x%p",
|
||||
Request);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
*Transferred = length;
|
||||
unplugAll = (unPlug->SerialNo == 0);
|
||||
|
||||
pFileData = FileObjectGetData(fileObject);
|
||||
if (pFileData == NULL)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"FileObjectGetData failed to get context data for 0x%p",
|
||||
fileObject);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
fileObject = WdfRequestGetFileObject(Request);
|
||||
if (fileObject == NULL)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"WdfRequestGetFileObject failed to fetch WDFFILEOBJECT from request 0x%p",
|
||||
Request);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSENUM,
|
||||
"Starting child list traversal");
|
||||
pFileData = FileObjectGetData(fileObject);
|
||||
if (pFileData == NULL)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"FileObjectGetData failed to get context data for 0x%p",
|
||||
fileObject);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
list = WdfFdoGetDefaultChildList(Device);
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSENUM,
|
||||
"Starting child list traversal");
|
||||
|
||||
WDF_CHILD_LIST_ITERATOR_INIT(&iterator, WdfRetrievePresentChildren);
|
||||
list = WdfFdoGetDefaultChildList(Device);
|
||||
|
||||
WdfChildListBeginIteration(list, &iterator);
|
||||
WDF_CHILD_LIST_ITERATOR_INIT(&iterator, WdfRetrievePresentChildren);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
WDF_CHILD_RETRIEVE_INFO_INIT(&childInfo, &description.Header);
|
||||
WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&description.Header, sizeof(description));
|
||||
WdfChildListBeginIteration(list, &iterator);
|
||||
|
||||
status = WdfChildListRetrieveNextDevice(list, &iterator, &hChild, &childInfo);
|
||||
for (;;)
|
||||
{
|
||||
WDF_CHILD_RETRIEVE_INFO_INIT(&childInfo, &description.Header);
|
||||
WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&description.Header, sizeof(description));
|
||||
|
||||
// Error or no more children, end loop
|
||||
if (!NT_SUCCESS(status) || status == STATUS_NO_MORE_ENTRIES)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSENUM,
|
||||
"WdfChildListRetrieveNextDevice returned with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
status = WdfChildListRetrieveNextDevice(list, &iterator, &hChild, &childInfo);
|
||||
|
||||
// If unable to retrieve device
|
||||
if (childInfo.Status != WdfChildListRetrieveDeviceSuccess)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSENUM,
|
||||
"childInfo.Status = %d",
|
||||
childInfo.Status);
|
||||
continue;
|
||||
}
|
||||
// Error or no more children, end loop
|
||||
if (!NT_SUCCESS(status) || status == STATUS_NO_MORE_ENTRIES)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSENUM,
|
||||
"WdfChildListRetrieveNextDevice returned with status %!STATUS!",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
// Child isn't the one we looked for, skip
|
||||
if (!unplugAll && description.SerialNo != unPlug->SerialNo)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSENUM,
|
||||
"Seeking serial mismatch: %d != %d",
|
||||
description.SerialNo,
|
||||
unPlug->SerialNo);
|
||||
continue;
|
||||
}
|
||||
// If unable to retrieve device
|
||||
if (childInfo.Status != WdfChildListRetrieveDeviceSuccess)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSENUM,
|
||||
"childInfo.Status = %d",
|
||||
childInfo.Status);
|
||||
continue;
|
||||
}
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSENUM,
|
||||
"description.SessionId = %d, pFileData->SessionId = %d",
|
||||
description.SessionId,
|
||||
pFileData->SessionId);
|
||||
// Child isn't the one we looked for, skip
|
||||
if (!unplugAll && description.SerialNo != unPlug->SerialNo)
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSENUM,
|
||||
"Seeking serial mismatch: %d != %d",
|
||||
description.SerialNo,
|
||||
unPlug->SerialNo);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only unplug owned children
|
||||
if (IsInternal || description.SessionId == pFileData->SessionId)
|
||||
{
|
||||
// Unplug child
|
||||
status = WdfChildListUpdateChildDescriptionAsMissing(list, &description.Header);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"WdfChildListUpdateChildDescriptionAsMissing failed with status %!STATUS!",
|
||||
status);
|
||||
}
|
||||
}
|
||||
}
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSENUM,
|
||||
"description.SessionId = %d, pFileData->SessionId = %d",
|
||||
description.SessionId,
|
||||
pFileData->SessionId);
|
||||
|
||||
WdfChildListEndIteration(list, &iterator);
|
||||
// Only unplug owned children
|
||||
if (IsInternal || description.SessionId == pFileData->SessionId)
|
||||
{
|
||||
// Unplug child
|
||||
status = WdfChildListUpdateChildDescriptionAsMissing(list, &description.Header);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_BUSENUM,
|
||||
"WdfChildListUpdateChildDescriptionAsMissing failed with status %!STATUS!",
|
||||
status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSENUM,
|
||||
"Finished child list traversal");
|
||||
WdfChildListEndIteration(list, &iterator);
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSENUM, "%!FUNC! Exit with status %!STATUS!", STATUS_SUCCESS);
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_BUSENUM,
|
||||
"Finished child list traversal");
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSENUM, "%!FUNC! Exit with status %!STATUS!", STATUS_SUCCESS);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user