mirror of
https://github.com/nefarius/ViGEmBus.git
synced 2025-08-10 00:52:17 +00:00
Merge branch 'master' into feature/api/vigem_target_x360_get_user_index
This commit is contained in:
282
sys/Driver.c
282
sys/Driver.c
@@ -25,12 +25,14 @@ SOFTWARE.
|
||||
|
||||
#include "busenum.h"
|
||||
#include <wdmguid.h>
|
||||
#include "driver.tmh"
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text (INIT, DriverEntry)
|
||||
#pragma alloc_text (PAGE, Bus_EvtDeviceAdd)
|
||||
#pragma alloc_text (PAGE, Bus_DeviceFileCreate)
|
||||
#pragma alloc_text (PAGE, Bus_FileClose)
|
||||
#pragma alloc_text (PAGE, Bus_EvtDriverContextCleanup)
|
||||
#pragma alloc_text (PAGE, Bus_PdoStageResult)
|
||||
#endif
|
||||
|
||||
@@ -40,18 +42,36 @@ SOFTWARE.
|
||||
//
|
||||
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
|
||||
{
|
||||
WDF_DRIVER_CONFIG config;
|
||||
NTSTATUS status;
|
||||
WDFDRIVER driver;
|
||||
WDF_DRIVER_CONFIG config;
|
||||
NTSTATUS status;
|
||||
WDFDRIVER driver;
|
||||
WDF_OBJECT_ATTRIBUTES attributes;
|
||||
|
||||
KdPrint((DRIVERNAME "Virtual Gamepad Emulation Bus Driver [built: %s %s]\n", __DATE__, __TIME__));
|
||||
|
||||
//
|
||||
// Initialize WPP Tracing
|
||||
//
|
||||
WPP_INIT_TRACING(DriverObject, RegistryPath);
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION,
|
||||
TRACE_DRIVER,
|
||||
"Loading Virtual Gamepad Emulation Bus Driver [built: %s %s]",
|
||||
__DATE__, __TIME__);
|
||||
|
||||
//
|
||||
// Register cleanup callback
|
||||
//
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
|
||||
attributes.EvtCleanupCallback = Bus_EvtDriverContextCleanup;
|
||||
|
||||
WDF_DRIVER_CONFIG_INIT(&config, Bus_EvtDeviceAdd);
|
||||
|
||||
status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, &driver);
|
||||
status = WdfDriverCreate(DriverObject, RegistryPath, &attributes, &config, &driver);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
WPP_CLEANUP(DriverObject);
|
||||
KdPrint((DRIVERNAME "WdfDriverCreate failed with status 0x%x\n", status));
|
||||
}
|
||||
|
||||
@@ -73,15 +93,17 @@ NTSTATUS Bus_EvtDeviceAdd(IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit)
|
||||
WDF_OBJECT_ATTRIBUTES fdoAttributes;
|
||||
WDF_OBJECT_ATTRIBUTES fileHandleAttributes;
|
||||
WDF_OBJECT_ATTRIBUTES collectionAttributes;
|
||||
WDF_OBJECT_ATTRIBUTES timerAttributes;
|
||||
PFDO_DEVICE_DATA pFDOData;
|
||||
VIGEM_BUS_INTERFACE busInterface;
|
||||
PINTERFACE interfaceHeader;
|
||||
WDF_TIMER_CONFIG reqTimerCfg;
|
||||
|
||||
UNREFERENCED_PARAMETER(Driver);
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
KdPrint((DRIVERNAME "Bus_EvtDeviceAdd: 0x%p\n", Driver));
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
|
||||
|
||||
WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER);
|
||||
// More than one process may talk to the bus at the same time
|
||||
@@ -117,16 +139,19 @@ NTSTATUS Bus_EvtDeviceAdd(IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit)
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
KdPrint((DRIVERNAME "Error creating device 0x%x\n", status));
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_DRIVER,
|
||||
"WdfDeviceCreate failed with status %!STATUS!",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
KdPrint((DRIVERNAME "Created FDO: 0x%X\n", device));
|
||||
|
||||
pFDOData = FdoGetData(device);
|
||||
if (pFDOData == NULL)
|
||||
{
|
||||
KdPrint((DRIVERNAME "Error creating device context\n"));
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_DRIVER,
|
||||
"FdoGetData failed");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
@@ -143,7 +168,10 @@ NTSTATUS Bus_EvtDeviceAdd(IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit)
|
||||
status = WdfCollectionCreate(&collectionAttributes, &pFDOData->PendingPluginRequests);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
KdPrint((DRIVERNAME "WdfCollectionCreate failed with status 0x%X\n", status));
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_DRIVER,
|
||||
"WdfCollectionCreate failed with status %!STATUS!",
|
||||
status);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
@@ -153,12 +181,41 @@ NTSTATUS Bus_EvtDeviceAdd(IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit)
|
||||
status = WdfSpinLockCreate(&collectionAttributes, &pFDOData->PendingPluginRequestsLock);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
KdPrint((DRIVERNAME "WdfSpinLockCreate failed with status 0x%X\n", status));
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_DRIVER,
|
||||
"WdfSpinLockCreate failed with status %!STATUS!",
|
||||
status);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Create timer for sweeping up orphaned requests
|
||||
|
||||
WDF_TIMER_CONFIG_INIT_PERIODIC(
|
||||
&reqTimerCfg,
|
||||
Bus_PlugInRequestCleanUpEvtTimerFunc,
|
||||
ORC_TIMER_START_DELAY
|
||||
);
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);
|
||||
timerAttributes.ParentObject = device;
|
||||
|
||||
status = WdfTimerCreate(&reqTimerCfg, &timerAttributes, &pFDOData->PendingPluginRequestsCleanupTimer);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_DRIVER,
|
||||
"WdfTimerCreate failed with status %!STATUS!",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
WdfTimerStart(
|
||||
pFDOData->PendingPluginRequestsCleanupTimer,
|
||||
WDF_REL_TIMEOUT_IN_MS(ORC_TIMER_PERIODIC_DUE_TIME)
|
||||
);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Add query interface
|
||||
|
||||
//
|
||||
@@ -191,7 +248,10 @@ NTSTATUS Bus_EvtDeviceAdd(IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit)
|
||||
&queryInterfaceConfig);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
KdPrint((DRIVERNAME "WdfDeviceAddQueryInterface failed 0x%0x\n", status));
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_DRIVER,
|
||||
"WdfDeviceAddQueryInterface failed with status %!STATUS!",
|
||||
status);
|
||||
return(status);
|
||||
}
|
||||
|
||||
@@ -211,7 +271,10 @@ NTSTATUS Bus_EvtDeviceAdd(IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit)
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
KdPrint((DRIVERNAME "WdfIoQueueCreate failed status 0x%x\n", status));
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_DRIVER,
|
||||
"WdfIoQueueCreate failed with status %!STATUS!",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -223,7 +286,10 @@ NTSTATUS Bus_EvtDeviceAdd(IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit)
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
KdPrint((DRIVERNAME "WdfDeviceCreateDeviceInterface failed status 0x%x\n", status));
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_DRIVER,
|
||||
"WdfDeviceCreateDeviceInterface failed with status %!STATUS!",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -239,6 +305,8 @@ NTSTATUS Bus_EvtDeviceAdd(IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit)
|
||||
|
||||
#pragma endregion
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit with status %!STATUS!", status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -263,17 +331,25 @@ Bus_DeviceFileCreate(
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
|
||||
|
||||
pFileData = FileObjectGetData(FileObject);
|
||||
|
||||
if (pFileData == NULL)
|
||||
{
|
||||
KdPrint((DRIVERNAME "Bus_DeviceFileCreate: ERROR! File handle context not found\n"));
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_DRIVER,
|
||||
"FileObjectGetData failed to return file object from WDFFILEOBJECT 0x%p",
|
||||
FileObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
pFDOData = FdoGetData(Device);
|
||||
if (pFDOData == NULL)
|
||||
{
|
||||
KdPrint((DRIVERNAME "Bus_DeviceFileCreate: ERROR! FDO context not found\n"));
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_DRIVER,
|
||||
"FdoGetData failed");
|
||||
status = STATUS_NO_SUCH_DEVICE;
|
||||
}
|
||||
else
|
||||
@@ -284,11 +360,16 @@ Bus_DeviceFileCreate(
|
||||
pFileData->SessionId = sessionId;
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
KdPrint((DRIVERNAME "Bus_DeviceFileCreate: File id=%d. Device refcount=%d\n", (int)sessionId, (int)refCount));
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION,
|
||||
TRACE_DRIVER,
|
||||
"File/session id = %d, device ref. count = %d",
|
||||
(int)sessionId, (int)refCount);
|
||||
}
|
||||
}
|
||||
|
||||
WdfRequestComplete(Request, status);
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit with status %!STATUS!", status);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -313,13 +394,17 @@ Bus_FileClose(
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
KdPrint((DRIVERNAME "Bus_FileClose called\n"));
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
|
||||
|
||||
// Check common context
|
||||
pFileData = FileObjectGetData(FileObject);
|
||||
if (pFileData == NULL)
|
||||
{
|
||||
KdPrint((DRIVERNAME "Bus_FileClose: ERROR! File handle context not found\n"));
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_DRIVER,
|
||||
"FileObjectGetData failed to return file object from WDFFILEOBJECT 0x%p",
|
||||
FileObject);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -328,14 +413,19 @@ Bus_FileClose(
|
||||
pFDOData = FdoGetData(device);
|
||||
if (pFDOData == NULL)
|
||||
{
|
||||
KdPrint((DRIVERNAME "Bus_FileClose: ERROR! FDO context not found\n"));
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_DRIVER,
|
||||
"FdoGetData failed");
|
||||
status = STATUS_NO_SUCH_DEVICE;
|
||||
}
|
||||
else
|
||||
{
|
||||
refCount = InterlockedDecrement(&pFDOData->InterfaceReferenceCounter);
|
||||
|
||||
KdPrint((DRIVERNAME "Bus_FileClose: Device refcount=%d\n", (int)refCount));
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION,
|
||||
TRACE_DRIVER,
|
||||
"Device ref. count = %d",
|
||||
(int)refCount);
|
||||
}
|
||||
|
||||
list = WdfFdoGetDefaultChildList(device);
|
||||
@@ -355,31 +445,74 @@ Bus_FileClose(
|
||||
break;
|
||||
}
|
||||
|
||||
KdPrint((DRIVERNAME "Bus_FileClose enumerate: status=%d devicePID=%d currentPID=%d fileSessionId=%d deviceSessionId=%d ownerIsDriver=%d\n",
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_DRIVER,
|
||||
"PDO properties: status = %!STATUS!, pdoPID = %d, curPID = %d, pdoSID = %d, curSID = %d, internal = %d",
|
||||
(int)childInfo.Status,
|
||||
(int)description.OwnerProcessId,
|
||||
(int)CURRENT_PROCESS_ID(),
|
||||
(int)pFileData->SessionId,
|
||||
(int)description.SessionId,
|
||||
(int)description.OwnerIsDriver));
|
||||
(int)pFileData->SessionId,
|
||||
(int)description.OwnerIsDriver
|
||||
);
|
||||
|
||||
// Only unplug devices with matching session id
|
||||
if (childInfo.Status == WdfChildListRetrieveDeviceSuccess
|
||||
&& description.SessionId == pFileData->SessionId
|
||||
&& !description.OwnerIsDriver)
|
||||
{
|
||||
KdPrint((DRIVERNAME "Bus_FileClose unplugging\n"));
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION,
|
||||
TRACE_DRIVER,
|
||||
"Unplugging device with serial %d",
|
||||
description.SerialNo);
|
||||
|
||||
// "Unplug" child
|
||||
status = WdfChildListUpdateChildDescriptionAsMissing(list, &description.Header);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
KdPrint((DRIVERNAME "WdfChildListUpdateChildDescriptionAsMissing failed with status 0x%X\n", status));
|
||||
TraceEvents(TRACE_LEVEL_ERROR,
|
||||
TRACE_DRIVER,
|
||||
"WdfChildListUpdateChildDescriptionAsMissing failed with status %!STATUS!",
|
||||
status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WdfChildListEndIteration(list, &iterator);
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit with status %!STATUS!", status);
|
||||
}
|
||||
|
||||
VOID
|
||||
Bus_EvtDriverContextCleanup(
|
||||
_In_ WDFOBJECT DriverObject
|
||||
)
|
||||
/*++
|
||||
Routine Description:
|
||||
|
||||
Free all the resources allocated in DriverEntry.
|
||||
|
||||
Arguments:
|
||||
|
||||
DriverObject - handle to a WDF Driver object.
|
||||
|
||||
Return Value:
|
||||
|
||||
VOID.
|
||||
|
||||
--*/
|
||||
{
|
||||
UNREFERENCED_PARAMETER(DriverObject);
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
|
||||
|
||||
//
|
||||
// Stop WPP Tracing
|
||||
//
|
||||
WPP_CLEANUP(WdfDriverWdmGetDriverObject((WDFDRIVER)DriverObject));
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
@@ -394,17 +527,20 @@ Bus_PdoStageResult(
|
||||
_In_ NTSTATUS Status
|
||||
)
|
||||
{
|
||||
ULONG i;
|
||||
PFDO_DEVICE_DATA pFdoData;
|
||||
WDFREQUEST curRequest;
|
||||
ULONG curSerial;
|
||||
ULONG items;
|
||||
ULONG i;
|
||||
PFDO_DEVICE_DATA pFdoData;
|
||||
WDFREQUEST curRequest;
|
||||
ULONG curSerial;
|
||||
ULONG items;
|
||||
|
||||
UNREFERENCED_PARAMETER(InterfaceHeader);
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
KdPrint((DRIVERNAME "Bus_PdoStageResult: Stage: %d, Serial: %d, status: 0x%X\n", Stage, Serial, Status));
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION,
|
||||
TRACE_DRIVER,
|
||||
"%!FUNC! Entry (stage = %d, serial = %d, status = %!STATUS!)",
|
||||
Stage, Serial, Status);
|
||||
|
||||
pFdoData = FdoGetData(InterfaceHeader->Context);
|
||||
|
||||
@@ -417,14 +553,20 @@ Bus_PdoStageResult(
|
||||
|
||||
items = WdfCollectionGetCount(pFdoData->PendingPluginRequests);
|
||||
|
||||
KdPrint((DRIVERNAME "Items count: %d\n", items));
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION,
|
||||
TRACE_DRIVER,
|
||||
"Items count: %d",
|
||||
items);
|
||||
|
||||
for (i = 0; i < items; i++)
|
||||
{
|
||||
curRequest = WdfCollectionGetItem(pFdoData->PendingPluginRequests, i);
|
||||
curSerial = PluginRequestGetData(curRequest)->Serial;
|
||||
|
||||
KdPrint((DRIVERNAME "Serial: %d, curSerial: %d\n", Serial, curSerial));
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION,
|
||||
TRACE_DRIVER,
|
||||
"Serial: %d, curSerial: %d",
|
||||
Serial, curSerial);
|
||||
|
||||
if (Serial == curSerial)
|
||||
{
|
||||
@@ -432,11 +574,81 @@ Bus_PdoStageResult(
|
||||
|
||||
WdfCollectionRemove(pFdoData->PendingPluginRequests, curRequest);
|
||||
|
||||
KdPrint((DRIVERNAME "Removed item with serial: %d\n", curSerial));
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION,
|
||||
TRACE_DRIVER,
|
||||
"Removed item with serial: %d",
|
||||
curSerial);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
WdfSpinLockRelease(pFdoData->PendingPluginRequestsLock);
|
||||
}
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
VOID
|
||||
Bus_PlugInRequestCleanUpEvtTimerFunc(
|
||||
WDFTIMER Timer
|
||||
)
|
||||
{
|
||||
ULONG i;
|
||||
PFDO_DEVICE_DATA pFdoData;
|
||||
WDFREQUEST curRequest;
|
||||
ULONG items;
|
||||
WDFDEVICE device;
|
||||
PFDO_PLUGIN_REQUEST_DATA pPluginData;
|
||||
LONGLONG freq;
|
||||
LARGE_INTEGER pcNow;
|
||||
LONGLONG ellapsed;
|
||||
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
|
||||
|
||||
device = WdfTimerGetParentObject(Timer);
|
||||
pFdoData = FdoGetData(device);
|
||||
|
||||
WdfSpinLockAcquire(pFdoData->PendingPluginRequestsLock);
|
||||
|
||||
items = WdfCollectionGetCount(pFdoData->PendingPluginRequests);
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION,
|
||||
TRACE_DRIVER,
|
||||
"Items count: %d",
|
||||
items);
|
||||
|
||||
for (i = 0; i < items; i++)
|
||||
{
|
||||
curRequest = WdfCollectionGetItem(pFdoData->PendingPluginRequests, i);
|
||||
pPluginData = PluginRequestGetData(curRequest);
|
||||
|
||||
freq = pPluginData->Frequency.QuadPart / ORC_PC_FREQUENCY_DIVIDER;
|
||||
pcNow = KeQueryPerformanceCounter(NULL);
|
||||
ellapsed = (pcNow.QuadPart - pPluginData->Timestamp.QuadPart) / freq;
|
||||
|
||||
TraceEvents(TRACE_LEVEL_VERBOSE,
|
||||
TRACE_DRIVER,
|
||||
"PDO (serial = %d) age: %llu",
|
||||
pPluginData->Serial, ellapsed);
|
||||
|
||||
if (ellapsed >= ORC_REQUEST_MAX_AGE)
|
||||
{
|
||||
WdfRequestComplete(curRequest, STATUS_SUCCESS);
|
||||
|
||||
WdfCollectionRemove(pFdoData->PendingPluginRequests, curRequest);
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION,
|
||||
TRACE_DRIVER,
|
||||
"Removed item with serial: %d",
|
||||
pPluginData->Serial);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
WdfSpinLockRelease(pFdoData->PendingPluginRequestsLock);
|
||||
|
||||
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user