diff --git a/Context.h b/Context.h index def05b1..c98d6f9 100644 --- a/Context.h +++ b/Context.h @@ -98,6 +98,26 @@ typedef struct _PDO_DEVICE_DATA VIGEM_BUS_INTERFACE BusInterface; + // + // Queue for incoming data interrupt transfer + // + WDFQUEUE PendingUsbInRequests; + + // + // Lock for queue for incoming data interrupt transfer + // + WDFSPINLOCK PendingUsbInRequestsLock; + + // + // Queue for inverted calls + // + WDFQUEUE PendingNotificationRequests; + + // + // Lock for queue for inverted calls + // + WDFSPINLOCK PendingNotificationRequestsLock; + } PDO_DEVICE_DATA, *PPDO_DEVICE_DATA; WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(PDO_DEVICE_DATA, PdoGetData) diff --git a/Ds4.c b/Ds4.c index 338ff47..256a9c8 100644 --- a/Ds4.c +++ b/Ds4.c @@ -123,25 +123,11 @@ NTSTATUS Ds4_PrepareHardware(WDFDEVICE Device) NTSTATUS Ds4_AssignPdoContext(WDFDEVICE Device, PPDO_IDENTIFICATION_DESCRIPTION Description) { - NTSTATUS status; - - PDS4_DEVICE_DATA ds4 = Ds4GetData(Device); + NTSTATUS status; + PDS4_DEVICE_DATA ds4 = Ds4GetData(Device); KdPrint((DRIVERNAME "Initializing DS4 context...\n")); - // I/O Queue for pending IRPs - WDF_IO_QUEUE_CONFIG pendingUsbQueueConfig, notificationsQueueConfig; - - // Create and assign queue for incoming interrupt transfer - WDF_IO_QUEUE_CONFIG_INIT(&pendingUsbQueueConfig, WdfIoQueueDispatchManual); - - status = WdfIoQueueCreate(Device, &pendingUsbQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &ds4->PendingUsbInRequests); - if (!NT_SUCCESS(status)) - { - KdPrint((DRIVERNAME "WdfIoQueueCreate failed 0x%x\n", status)); - return status; - } - // Initialize periodic timer WDF_TIMER_CONFIG timerConfig; WDF_TIMER_CONFIG_INIT_PERIODIC(&timerConfig, Ds4_PendingUsbRequestsTimerFunc, DS4_QUEUE_FLUSH_PERIOD); @@ -161,16 +147,6 @@ NTSTATUS Ds4_AssignPdoContext(WDFDEVICE Device, PPDO_IDENTIFICATION_DESCRIPTION return status; } - // Create and assign queue for user-land notification requests - WDF_IO_QUEUE_CONFIG_INIT(¬ificationsQueueConfig, WdfIoQueueDispatchManual); - - status = WdfIoQueueCreate(Device, ¬ificationsQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &ds4->PendingNotificationRequests); - if (!NT_SUCCESS(status)) - { - KdPrint((DRIVERNAME "WdfIoQueueCreate failed 0x%x\n", status)); - return status; - } - // Load/generate MAC address // TODO: tidy up this region @@ -362,20 +338,21 @@ VOID Ds4_PendingUsbRequestsTimerFunc( _In_ WDFTIMER Timer ) { - NTSTATUS status; - WDFREQUEST usbRequest; - WDFDEVICE hChild; - PDS4_DEVICE_DATA ds4Data; - PIRP pendingIrp; - PIO_STACK_LOCATION irpStack; - - // KdPrint((DRIVERNAME "Ds4_PendingUsbRequestsTimerFunc: Timer elapsed\n")); + NTSTATUS status; + WDFREQUEST usbRequest; + WDFDEVICE hChild; + PDS4_DEVICE_DATA ds4Data; + PIRP pendingIrp; + PIO_STACK_LOCATION irpStack; + PPDO_DEVICE_DATA pdoData; hChild = WdfTimerGetParentObject(Timer); + pdoData = PdoGetData(hChild); ds4Data = Ds4GetData(hChild); // Get pending USB request - status = WdfIoQueueRetrieveNextRequest(ds4Data->PendingUsbInRequests, &usbRequest); + WdfSpinLockAcquire(pdoData->PendingUsbInRequestsLock); + status = WdfIoQueueRetrieveNextRequest(pdoData->PendingUsbInRequests, &usbRequest); if (NT_SUCCESS(status)) { @@ -399,5 +376,7 @@ VOID Ds4_PendingUsbRequestsTimerFunc( // Complete pending request WdfRequestComplete(usbRequest, status); } + + WdfSpinLockRelease(pdoData->PendingUsbInRequestsLock); } diff --git a/Ds4.h b/Ds4.h index b5409bd..7c9faa0 100644 --- a/Ds4.h +++ b/Ds4.h @@ -66,21 +66,11 @@ typedef struct _DS4_DEVICE_DATA // DS4_OUTPUT_REPORT OutputReport; - // - // Queue for incoming interrupt transfer - // - WDFQUEUE PendingUsbInRequests; - // // Timer for dispatching interrupt transfer // WDFTIMER PendingUsbInRequestsTimer; - // - // Queue for inverted calls - // - WDFQUEUE PendingNotificationRequests; - // // Auto-generated MAC address of the target device // @@ -90,6 +80,7 @@ typedef struct _DS4_DEVICE_DATA // Default MAC address of the host (not used) // MAC_ADDRESS HostMacAddress; + } DS4_DEVICE_DATA, *PDS4_DEVICE_DATA; WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DS4_DEVICE_DATA, Ds4GetData) diff --git a/Xusb.h b/Xusb.h index fdd5223..459ad3f 100644 --- a/Xusb.h +++ b/Xusb.h @@ -86,16 +86,6 @@ typedef struct _XUSB_DEVICE_DATA // XUSB_INTERRUPT_IN_PACKET Packet; - // - // Queue for incoming data interrupt transfer - // - WDFQUEUE PendingUsbInRequests; - - // - // Lock for queue for incoming data interrupt transfer - // - WDFSPINLOCK PendingUsbInRequestsLock; - // // Queue for incoming control interrupt transfer // @@ -106,16 +96,6 @@ typedef struct _XUSB_DEVICE_DATA // WDFSPINLOCK HoldingUsbInRequestsLock; - // - // Queue for inverted calls - // - WDFQUEUE PendingNotificationRequests; - - // - // Lock for queue for inverted calls - // - WDFSPINLOCK PendingNotificationRequestsLock; - } XUSB_DEVICE_DATA, *PXUSB_DEVICE_DATA; WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(XUSB_DEVICE_DATA, XusbGetData) diff --git a/busenum.c b/busenum.c index f37babf..2d6b685 100644 --- a/busenum.c +++ b/busenum.c @@ -361,9 +361,9 @@ NTSTATUS Bus_QueueNotification(WDFDEVICE Device, ULONG SerialNo, WDFREQUEST Requ if (xusbData == NULL) break; - WdfSpinLockAcquire(xusbData->PendingNotificationRequestsLock); - status = WdfRequestForwardToIoQueue(Request, xusbData->PendingNotificationRequests); - WdfSpinLockRelease(xusbData->PendingNotificationRequestsLock); + WdfSpinLockAcquire(pdoData->PendingNotificationRequestsLock); + status = WdfRequestForwardToIoQueue(Request, pdoData->PendingNotificationRequests); + WdfSpinLockRelease(pdoData->PendingNotificationRequestsLock); break; case DualShock4Wired: @@ -372,7 +372,7 @@ NTSTATUS Bus_QueueNotification(WDFDEVICE Device, ULONG SerialNo, WDFREQUEST Requ if (ds4Data == NULL) break; - status = WdfRequestForwardToIoQueue(Request, ds4Data->PendingNotificationRequests); + status = WdfRequestForwardToIoQueue(Request, pdoData->PendingNotificationRequests); break; } @@ -491,19 +491,19 @@ NTSTATUS Bus_SubmitReport(WDFDEVICE Device, ULONG SerialNo, PVOID Report, BOOLEA KdPrint((DRIVERNAME "Bus_SubmitReport: received new report\n")); + WdfSpinLockAcquire(pdoData->PendingUsbInRequestsLock); + // Get pending USB request switch (pdoData->TargetType) { case Xbox360Wired: - - WdfSpinLockAcquire(XusbGetData(hChild)->PendingUsbInRequestsLock); - status = WdfIoQueueRetrieveNextRequest(XusbGetData(hChild)->PendingUsbInRequests, &usbRequest); - WdfSpinLockRelease(XusbGetData(hChild)->PendingUsbInRequestsLock); + + status = WdfIoQueueRetrieveNextRequest(pdoData->PendingUsbInRequests, &usbRequest); break; case DualShock4Wired: - status = WdfIoQueueRetrieveNextRequest(Ds4GetData(hChild)->PendingUsbInRequests, &usbRequest); + status = WdfIoQueueRetrieveNextRequest(pdoData->PendingUsbInRequests, &usbRequest); break; case XboxOneWired: @@ -525,7 +525,7 @@ NTSTATUS Bus_SubmitReport(WDFDEVICE Device, ULONG SerialNo, PVOID Report, BOOLEA if (!NT_SUCCESS(status)) { KdPrint((DRIVERNAME "WdfMemoryCreate failed with status 0x%X\n", status)); - return status; + goto releaseAndExit; } // Copy interrupt buffer to memory object @@ -533,7 +533,7 @@ NTSTATUS Bus_SubmitReport(WDFDEVICE Device, ULONG SerialNo, PVOID Report, BOOLEA if (!NT_SUCCESS(status)) { KdPrint((DRIVERNAME "WdfMemoryCopyFromBuffer failed with status 0x%X\n", status)); - return status; + goto releaseAndExit; } // Add memory object to collection @@ -541,7 +541,7 @@ NTSTATUS Bus_SubmitReport(WDFDEVICE Device, ULONG SerialNo, PVOID Report, BOOLEA if (!NT_SUCCESS(status)) { KdPrint((DRIVERNAME "WdfCollectionAdd failed with status 0x%X\n", status)); - return status; + goto releaseAndExit; } // Check if all packets have been received @@ -554,7 +554,7 @@ NTSTATUS Bus_SubmitReport(WDFDEVICE Device, ULONG SerialNo, PVOID Report, BOOLEA WdfTimerStart(xgip->XboxgipSysInitTimer, XGIP_SYS_INIT_PERIOD); } - return status; + goto releaseAndExit; } status = WdfIoQueueRetrieveNextRequest(XgipGetData(hChild)->PendingUsbInRequests, &usbRequest); @@ -562,11 +562,12 @@ NTSTATUS Bus_SubmitReport(WDFDEVICE Device, ULONG SerialNo, PVOID Report, BOOLEA break; default: - return STATUS_NOT_SUPPORTED; + status = STATUS_NOT_SUPPORTED; + goto releaseAndExit; } if (!NT_SUCCESS(status)) - return status; + goto releaseAndExit; KdPrint((DRIVERNAME "Bus_SubmitReport: pending IRP found\n")); @@ -628,6 +629,8 @@ NTSTATUS Bus_SubmitReport(WDFDEVICE Device, ULONG SerialNo, PVOID Report, BOOLEA // Complete pending request WdfRequestComplete(usbRequest, status); +releaseAndExit: + WdfSpinLockRelease(pdoData->PendingUsbInRequestsLock); return status; } diff --git a/buspdo.c b/buspdo.c index 4987127..6347409 100644 --- a/buspdo.c +++ b/buspdo.c @@ -88,8 +88,10 @@ NTSTATUS Bus_CreatePdo( WDFQUEUE defaultPdoQueue; UNICODE_STRING deviceDescription; VIGEM_BUS_INTERFACE busInterface; - - + WDF_OBJECT_ATTRIBUTES attributes; + WDF_IO_QUEUE_CONFIG usbInQueueConfig; + WDF_IO_QUEUE_CONFIG notificationsQueueConfig; + DECLARE_CONST_UNICODE_STRING(deviceLocation, L"Virtual Gamepad Emulation Bus"); DECLARE_UNICODE_STRING_SIZE(buffer, MAX_INSTANCE_ID_LEN); // reserve space for device id @@ -351,6 +353,46 @@ NTSTATUS Bus_CreatePdo( #pragma endregion +#pragma region Create Queues & Locks + + // Create and assign queue for incoming interrupt transfer + WDF_IO_QUEUE_CONFIG_INIT(&usbInQueueConfig, WdfIoQueueDispatchManual); + + status = WdfIoQueueCreate(Device, &usbInQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pdoData->PendingUsbInRequests); + if (!NT_SUCCESS(status)) + { + KdPrint((DRIVERNAME "WdfIoQueueCreate failed 0x%x\n", status)); + return status; + } + + // Create lock for queue + status = WdfSpinLockCreate(&attributes, &pdoData->PendingUsbInRequestsLock); + if (!NT_SUCCESS(status)) + { + KdPrint((DRIVERNAME "WdfSpinLockCreate failed 0x%x\n", status)); + return status; + } + + // Create and assign queue for user-land notification requests + WDF_IO_QUEUE_CONFIG_INIT(¬ificationsQueueConfig, WdfIoQueueDispatchManual); + + status = WdfIoQueueCreate(Device, ¬ificationsQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pdoData->PendingNotificationRequests); + if (!NT_SUCCESS(status)) + { + KdPrint((DRIVERNAME "WdfIoQueueCreate failed 0x%x\n", status)); + return status; + } + + // Create lock for queue + status = WdfSpinLockCreate(&attributes, &pdoData->PendingNotificationRequestsLock); + if (!NT_SUCCESS(status)) + { + KdPrint((DRIVERNAME "WdfSpinLockCreate failed 0x%x\n", status)); + return status; + } + +#pragma endregion + #pragma region Default I/O queue setup WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&defaultPdoQueueConfig, WdfIoQueueDispatchParallel); diff --git a/usbpdo.c b/usbpdo.c index d5a79cc..f8a2d56 100644 --- a/usbpdo.c +++ b/usbpdo.c @@ -507,9 +507,9 @@ NTSTATUS UsbPdo_BulkOrInterruptTransfer(PURB urb, WDFDEVICE Device, WDFREQUEST R /* This request is sent periodically and relies on data the "feeder" * has to supply, so we queue this request and return with STATUS_PENDING. * The request gets completed as soon as the "feeder" sent an update. */ - WdfSpinLockAcquire(xusb->PendingUsbInRequestsLock); - status = WdfRequestForwardToIoQueue(Request, xusb->PendingUsbInRequests); - WdfSpinLockRelease(xusb->PendingUsbInRequestsLock); + WdfSpinLockAcquire(pdoData->PendingUsbInRequestsLock); + status = WdfRequestForwardToIoQueue(Request, pdoData->PendingUsbInRequests); + WdfSpinLockRelease(pdoData->PendingUsbInRequestsLock); return (NT_SUCCESS(status)) ? STATUS_PENDING : status; } @@ -567,10 +567,9 @@ NTSTATUS UsbPdo_BulkOrInterruptTransfer(PURB urb, WDFDEVICE Device, WDFREQUEST R } // Notify user-mode process that new data is available - WdfSpinLockAcquire(xusb->PendingNotificationRequestsLock); - status = WdfIoQueueRetrieveNextRequest(xusb->PendingNotificationRequests, ¬ifyRequest); - WdfSpinLockRelease(xusb->PendingNotificationRequestsLock); - + WdfSpinLockAcquire(pdoData->PendingNotificationRequestsLock); + status = WdfIoQueueRetrieveNextRequest(pdoData->PendingNotificationRequests, ¬ifyRequest); + if (NT_SUCCESS(status)) { PXUSB_REQUEST_NOTIFICATION notify = NULL; @@ -594,6 +593,8 @@ NTSTATUS UsbPdo_BulkOrInterruptTransfer(PURB urb, WDFDEVICE Device, WDFREQUEST R } } + WdfSpinLockRelease(pdoData->PendingNotificationRequestsLock); + break; } case DualShock4Wired: @@ -609,7 +610,7 @@ NTSTATUS UsbPdo_BulkOrInterruptTransfer(PURB urb, WDFDEVICE Device, WDFREQUEST R /* This request is sent periodically and relies on data the "feeder" has to supply, so we queue this request and return with STATUS_PENDING. The request gets completed as soon as the "feeder" sent an update. */ - status = WdfRequestForwardToIoQueue(Request, ds4Data->PendingUsbInRequests); + status = WdfRequestForwardToIoQueue(Request, pdoData->PendingUsbInRequests); return (NT_SUCCESS(status)) ? STATUS_PENDING : status; } @@ -620,7 +621,7 @@ NTSTATUS UsbPdo_BulkOrInterruptTransfer(PURB urb, WDFDEVICE Device, WDFREQUEST R DS4_OUTPUT_BUFFER_LENGTH); // Notify user-mode process that new data is available - status = WdfIoQueueRetrieveNextRequest(ds4Data->PendingNotificationRequests, ¬ifyRequest); + status = WdfIoQueueRetrieveNextRequest(pdoData->PendingNotificationRequests, ¬ifyRequest); if (NT_SUCCESS(status)) { @@ -699,8 +700,8 @@ NTSTATUS UsbPdo_AbortPipe(WDFDEVICE Device) } // Higher driver shutting down, emptying PDOs queues - WdfIoQueuePurge(xusb->PendingUsbInRequests, NULL, NULL); - WdfIoQueuePurge(xusb->PendingNotificationRequests, NULL, NULL); + WdfIoQueuePurge(pdoData->PendingUsbInRequests, NULL, NULL); + WdfIoQueuePurge(pdoData->PendingNotificationRequests, NULL, NULL); break; } @@ -718,7 +719,7 @@ NTSTATUS UsbPdo_AbortPipe(WDFDEVICE Device) // Higher driver shutting down, emptying PDOs queues WdfTimerStop(ds4->PendingUsbInRequestsTimer, TRUE); - WdfIoQueuePurge(ds4->PendingUsbInRequests, NULL, NULL); + WdfIoQueuePurge(pdoData->PendingUsbInRequests, NULL, NULL); break; } diff --git a/xusb.c b/xusb.c index 0d196ec..13ba725 100644 --- a/xusb.c +++ b/xusb.c @@ -216,43 +216,7 @@ NTSTATUS Xusb_AssignPdoContext(WDFDEVICE Device, PPDO_IDENTIFICATION_DESCRIPTION xusb->Packet.Size = 0x14; // I/O Queue for pending IRPs - WDF_IO_QUEUE_CONFIG usbInQueueConfig, notificationsQueueConfig, holdingInQueueConfig; - - // Create and assign queue for incoming interrupt transfer - WDF_IO_QUEUE_CONFIG_INIT(&usbInQueueConfig, WdfIoQueueDispatchManual); - - status = WdfIoQueueCreate(Device, &usbInQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &xusb->PendingUsbInRequests); - if (!NT_SUCCESS(status)) - { - KdPrint((DRIVERNAME "WdfIoQueueCreate failed 0x%x\n", status)); - return status; - } - - // Create lock for queue - status = WdfSpinLockCreate(&attributes, &xusb->PendingUsbInRequestsLock); - if (!NT_SUCCESS(status)) - { - KdPrint((DRIVERNAME "WdfSpinLockCreate failed 0x%x\n", status)); - return status; - } - - // Create and assign queue for user-land notification requests - WDF_IO_QUEUE_CONFIG_INIT(¬ificationsQueueConfig, WdfIoQueueDispatchManual); - - status = WdfIoQueueCreate(Device, ¬ificationsQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &xusb->PendingNotificationRequests); - if (!NT_SUCCESS(status)) - { - KdPrint((DRIVERNAME "WdfIoQueueCreate failed 0x%x\n", status)); - return status; - } - - // Create lock for queue - status = WdfSpinLockCreate(&attributes, &xusb->PendingNotificationRequestsLock); - if (!NT_SUCCESS(status)) - { - KdPrint((DRIVERNAME "WdfSpinLockCreate failed 0x%x\n", status)); - return status; - } + WDF_IO_QUEUE_CONFIG holdingInQueueConfig; // Create and assign queue for unhandled interrupt requests WDF_IO_QUEUE_CONFIG_INIT(&holdingInQueueConfig, WdfIoQueueDispatchManual);