diff --git a/sys/EmulationTargetPDO.cpp b/sys/EmulationTargetPDO.cpp index a3fb120..31330f6 100644 --- a/sys/EmulationTargetPDO.cpp +++ b/sys/EmulationTargetPDO.cpp @@ -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(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(reinterpret_cast(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(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(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(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(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; } diff --git a/sys/EmulationTargetPDO.hpp b/sys/EmulationTargetPDO.hpp index 306f94d..31c9cef 100644 --- a/sys/EmulationTargetPDO.hpp +++ b/sys/EmulationTargetPDO.hpp @@ -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 diff --git a/sys/ViGEmBus.vcxproj b/sys/ViGEmBus.vcxproj index 4548ac5..fc5cb8c 100644 --- a/sys/ViGEmBus.vcxproj +++ b/sys/ViGEmBus.vcxproj @@ -213,6 +213,9 @@ + + + diff --git a/sys/ViGEmBus.vcxproj.filters b/sys/ViGEmBus.vcxproj.filters index ac09d8a..e585b1a 100644 --- a/sys/ViGEmBus.vcxproj.filters +++ b/sys/ViGEmBus.vcxproj.filters @@ -110,4 +110,7 @@ Resource Files + + + \ No newline at end of file diff --git a/sys/busenum.cpp b/sys/busenum.cpp index 0bd8b35..5493be2 100644 --- a/sys/busenum.cpp +++ b/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(&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(&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; }