Merge branch 'master' into feature/api/vigem_target_x360_get_user_index

This commit is contained in:
Benjamin Höglinger
2018-05-13 22:45:21 +02:00
16 changed files with 1182 additions and 220 deletions

View File

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