Implemented new plugin request tracking

This commit is contained in:
Benjamin Höglinger-Stelzer
2020-05-13 17:59:18 +02:00
parent 2457076e20
commit 9a2f66048d
5 changed files with 548 additions and 407 deletions

View File

@@ -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(&notificationsQueueConfig, 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;
}

View File

@@ -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

View File

@@ -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>

View File

@@ -110,4 +110,7 @@
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />
</ItemGroup>
</Project>

View File

@@ -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;
}