Moved common WDF objects to PDO context

Fixed queue locking
This commit is contained in:
Benjamin Höglinger
2017-10-26 22:45:12 +02:00
parent 4421b89587
commit 5771c48515
8 changed files with 111 additions and 131 deletions

View File

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

49
Ds4.c
View File

@@ -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(&notificationsQueueConfig, WdfIoQueueDispatchManual);
status = WdfIoQueueCreate(Device, &notificationsQueueConfig, 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);
}

11
Ds4.h
View File

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

20
Xusb.h
View File

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

View File

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

View File

@@ -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(&notificationsQueueConfig, WdfIoQueueDispatchManual);
status = WdfIoQueueCreate(Device, &notificationsQueueConfig, 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);

View File

@@ -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, &notifyRequest);
WdfSpinLockRelease(xusb->PendingNotificationRequestsLock);
WdfSpinLockAcquire(pdoData->PendingNotificationRequestsLock);
status = WdfIoQueueRetrieveNextRequest(pdoData->PendingNotificationRequests, &notifyRequest);
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, &notifyRequest);
status = WdfIoQueueRetrieveNextRequest(pdoData->PendingNotificationRequests, &notifyRequest);
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;
}

38
xusb.c
View File

@@ -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(&notificationsQueueConfig, WdfIoQueueDispatchManual);
status = WdfIoQueueCreate(Device, &notificationsQueueConfig, 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);