16 Commits

Author SHA1 Message Date
Benjamin Höglinger-Stelzer
64ca258915 Fixed PNP & Power Capabilities to reflect the actual caps of the physical devices closer
Removed default derived destructors
2020-05-18 19:58:05 +02:00
Benjamin Höglinger-Stelzer
2fe83018c0 Removed RAW device exposure as the real devices don't do that 2020-05-18 18:57:08 +02:00
Benjamin Höglinger-Stelzer
05b3b74db5 Removed RAW device exposure as the real devices don't do that 2020-05-18 18:56:54 +02:00
Benjamin Höglinger-Stelzer
5bea1d5b0f Changed XUSB pool tag 2020-05-15 22:15:52 +02:00
Benjamin Höglinger-Stelzer
f9eaad93f2 Added diagnostic function DumpAsHex 2020-05-15 17:00:06 +02:00
Benjamin Höglinger-Stelzer
81b6fb3926 Added https://github.com/Ryochan7/Touchmote/tree/ryochan7 & https://github.com/grayver/mi-vigem to known users 2020-05-14 19:30:25 +02:00
Benjamin Höglinger-Stelzer
9f4e557d94 Updated cabinet creation
Removed unused files
2020-05-14 19:18:15 +02:00
Benjamin Höglinger-Stelzer
80330f6716 Refining DDF files 2020-05-14 17:08:03 +02:00
Benjamin Höglinger-Stelzer
af18a07443 Code clean-up 2020-05-14 16:44:37 +02:00
Benjamin Höglinger-Stelzer
250d6f7937 Removed redundant headers
Removed obsolete types
2020-05-14 16:43:41 +02:00
Benjamin Höglinger-Stelzer
68ab55d56a Removed unused code 2020-05-14 16:41:08 +02:00
Benjamin Höglinger-Stelzer
dc39ba970d Fixed handle leak 2020-05-14 15:03:59 +02:00
Benjamin Höglinger-Stelzer
2f636a5da6 Minor clean-up 2020-05-14 14:09:46 +02:00
Benjamin Höglinger-Stelzer
15a9b2c896 Minor clean-up 2020-05-13 21:58:37 +02:00
Benjamin Höglinger-Stelzer
5d2dd2a122 Removed unused code 2020-05-13 21:46:14 +02:00
Benjamin Höglinger-Stelzer
225c536205 Removed unused code 2020-05-13 21:37:57 +02:00
25 changed files with 402 additions and 925 deletions

5
.gitignore vendored
View File

@@ -357,4 +357,7 @@ MigrationBackup/
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
FodyWeavers.xsd
/disk1/ViGEmBus_x64.cab
/setup.inf
/setup.rpt

View File

@@ -93,6 +93,8 @@ This list is non-exhaustive, if you'd like to see your project included, contact
- [DS4Windows](https://ryochan7.github.io/ds4windows-site/)
- [XOutput](https://github.com/csutorasa/XOutput)
- [RdpGamepad](https://github.com/microsoft/RdpGamepad)
- [Touchmote](https://github.com/Ryochan7/Touchmote/tree/ryochan7)
- [Mi-ViGEm](https://github.com/grayver/mi-vigem)
## License

View File

@@ -1,21 +0,0 @@
.OPTION EXPLICIT
.Set CabinetFileCountThreshold=0
.Set FolderFileCountThreshold=0
.Set FolderSizeThreshold=0
.Set MaxCabinetSize=0
.Set MaxDiskFileCount=0
.Set MaxDiskSize=0
.Set CompressionType=MSZIP
.Set Cabinet=on
.Set Compress=on
.Set CabinetNameTemplate=ViGEmBus.cab
.Set DestinationDir=ViGEmBus
.\artifacts\ViGEmBus.inf
.Set DestinationDir=ViGEmBus\x64
.\artifacts\x64\ViGEmBus.sys
.\artifacts\x64\ViGEmBus.pdb
.\artifacts\x64\WdfCoinstaller01009.dll
.Set DestinationDir=ViGEmBus\x86
.\artifacts\x86\ViGEmBus.sys
.\artifacts\x86\ViGEmBus.pdb
.\artifacts\x86\WdfCoinstaller01009.dll

19
ViGEmBus_x64.ddf Normal file
View File

@@ -0,0 +1,19 @@
; ViGEmBus cab file for attestation submission
.OPTION EXPLICIT
.Set CabinetFileCountThreshold=0
.Set FolderFileCountThreshold=0
.Set FolderSizeThreshold=0
.Set MaxCabinetSize=0
.Set MaxDiskFileCount=0
.Set MaxDiskSize=0
.Set CompressionType=MSZIP
.Set Cabinet=on
.Set Compress=on
; x64
.Set CabinetNameTemplate=ViGEmBus_x64.cab
.Set DestinationDir=ViGEmBus_x64
LICENSE
bin\x64\ViGEmBus.pdb
bin\x64\ViGEmBus\ViGEmBus.inf
bin\x64\ViGEmBus\ViGEmBus.sys
bin\x64\ViGEmBus\WdfCoinstaller01009.dll

19
ViGEmBus_x86.ddf Normal file
View File

@@ -0,0 +1,19 @@
; ViGEmBus cab file for attestation submission
.OPTION EXPLICIT
.Set CabinetFileCountThreshold=0
.Set FolderFileCountThreshold=0
.Set FolderSizeThreshold=0
.Set MaxCabinetSize=0
.Set MaxDiskFileCount=0
.Set MaxDiskSize=0
.Set CompressionType=MSZIP
.Set Cabinet=on
.Set Compress=on
; x86
.Set CabinetNameTemplate=ViGEmBus_x86.cab
.Set DestinationDir=ViGEmBus_x86
LICENSE
bin\x86\ViGEmBus.pdb
bin\x86\ViGEmBus\ViGEmBus.inf
bin\x86\ViGEmBus\ViGEmBus.sys
bin\x86\ViGEmBus\WdfCoinstaller01009.dll

View File

@@ -14,12 +14,13 @@ before_build:
build:
project: $(APPVEYOR_BUILD_FOLDER)\$(APPVEYOR_PROJECT_NAME).sln
after_build:
#- cmd: makecab.exe /f ViGEmBus.ddf
- cmd: makecab.exe /f ViGEmBus_%PLATFORM%.ddf
artifacts:
- path: 'bin**\$(APPVEYOR_PROJECT_NAME)\*.inf'
- path: 'bin**\$(APPVEYOR_PROJECT_NAME)\*.sys'
- path: 'bin**\$(APPVEYOR_PROJECT_NAME)\*.dll'
- path: 'bin**\*.pdb'
- path: 'disk1\*.cab'
deploy:
- provider: Environment
name: BUILDBOT

View File

@@ -1,89 +0,0 @@
/*
* Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver
*
* MIT License
*
* Copyright (c) 2016-2020 Nefarius Software Solutions e.U. and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// {A77BC4D5-6AF7-4E69-8DC4-6B88A6028CE6}
// ReSharper disable once CppMissingIncludeGuard
DEFINE_GUID(GUID_VIGEM_INTERFACE_PDO,
0xA77BC4D5, 0x6AF7, 0x4E69, 0x8D, 0xC4, 0x6B, 0x88, 0xA6, 0x02, 0x8C, 0xE6);
// {A8BA2D1F-894F-464A-B0CE-7A0C8FD65DF1}
DEFINE_GUID(GUID_DEVCLASS_VIGEM_RAWPDO,
0xA8BA2D1F, 0x894F, 0x464A, 0xB0, 0xCE, 0x7A, 0x0C, 0x8F, 0xD6, 0x5D, 0xF1);
#pragma once
EXTERN_C_START
//
// Describes the current stage a PDO completed
//
typedef enum _VIGEM_PDO_STAGE
{
ViGEmPdoCreate,
ViGEmPdoPrepareHardware,
ViGEmPdoInitFinished
} VIGEM_PDO_STAGE, *PVIGEM_PDO_STAGE;
//
// PDO stage result callback definition
//
typedef
VOID
(*PVIGEM_BUS_PDO_STAGE_RESULT)(
_In_ PINTERFACE InterfaceHeader,
_In_ VIGEM_PDO_STAGE Stage,
_In_ ULONG Serial,
_In_ NTSTATUS Status
);
typedef struct _VIGEM_BUS_INTERFACE {
//
// Standard interface header, must be present
//
INTERFACE InterfaceHeader;
//
// PDO stage result callback
//
PVIGEM_BUS_PDO_STAGE_RESULT BusPdoStageResult;
} VIGEM_BUS_INTERFACE, *PVIGEM_BUS_INTERFACE;
#define VIGEM_BUS_INTERFACE_VERSION 1
VOID FORCEINLINE BUS_PDO_REPORT_STAGE_RESULT(
VIGEM_BUS_INTERFACE Interface,
VIGEM_PDO_STAGE Stage,
ULONG Serial,
NTSTATUS Status
)
{
(*Interface.BusPdoStageResult)(&Interface.InterfaceHeader, Stage, Serial, Status);
}
EXTERN_C_END

View File

@@ -1,216 +0,0 @@
/*
* Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver
*
* MIT License
*
* Copyright (c) 2016-2020 Nefarius Software Solutions e.U. and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "ByteArray.h"
//
// Helpers
//
ULONG_PTR align_to_page_size(ULONG_PTR val)
{
return (val + (PAGE_SIZE - 1)) & -PAGE_SIZE;
}
//
// Forward declarations
//
NTSTATUS IncreaseCapacityByteArray(IN PBYTE_ARRAY Array, IN ULONG NumElements);
//
// Implementation
//
NTSTATUS InitByteArray(IN OUT PBYTE_ARRAY Array)
{
//
// Initialize size and default capacity
Array->Size = 0;
Array->Capacity = INITIAL_ARRAY_CAPACITY;
//
// Allocate memory
Array->Data = (UCHAR*)ExAllocatePoolWithTag(PagedPool, Array->Capacity, ARRAY_POOL_TAG);
if (Array->Data == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
return STATUS_SUCCESS;
}
NTSTATUS AppendElementByteArray(IN PBYTE_ARRAY Array, IN PVOID Element)
{
//
// Make sure there is room to expand into
if (((Array->Size + 1) * sizeof(UCHAR)) > Array->Capacity)
{
//
// Increase capacity
NTSTATUS status = IncreaseCapacityByteArray(Array, sizeof(UCHAR));
if (!NT_SUCCESS(status))
return status;
}
//
// Append the element and increment the size
RtlCopyMemory(Array->Data + (Array->Size * sizeof(UCHAR)), Element, sizeof(UCHAR));
//
// Increment size
Array->Size += 1;
return STATUS_SUCCESS;
}
NTSTATUS AppendElementsByteArray(IN PBYTE_ARRAY Array, IN PVOID Elements, IN ULONG NumElements)
{
//
// Make sure there is room to expand into
if ((Array->Size + NumElements) * sizeof(UCHAR) > Array->Capacity)
{
//
// Increase capacity
NTSTATUS status = IncreaseCapacityByteArray(Array, NumElements);
if (!NT_SUCCESS(status))
return status;
}
//
// Append the elements and increase the size
RtlCopyMemory(Array->Data + (Array->Size * sizeof(UCHAR)), Elements, NumElements * sizeof(UCHAR));
//
// Increase size
Array->Size += NumElements;
return STATUS_SUCCESS;
}
NTSTATUS IncreaseCapacityByteArray(IN PBYTE_ARRAY Array, IN ULONG NumElements)
{
UCHAR* NewData = NULL;
//
// Align new size to the immediate next page boundary
Array->Capacity = align_to_page_size((Array->Size + NumElements) * sizeof(UCHAR));
//
// Allocate new data with new capacity
NewData = (UCHAR*)ExAllocatePoolWithTag(PagedPool, Array->Capacity, ARRAY_POOL_TAG);
if (NewData == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
//
// Copy old data over
RtlCopyMemory(NewData, Array->Data, Array->Size * sizeof(UCHAR));
//
// Free old data
ExFreePoolWithTag(Array->Data, ARRAY_POOL_TAG);
//
// Set data pointer to new allocation
Array->Data = NewData;
return STATUS_SUCCESS;
}
NTSTATUS GetElementByteArray(IN PBYTE_ARRAY Array, IN ULONG Index, OUT PVOID Element)
{
//
// Check array bounds
if (Index >= Array->Size || (LONG)Index < 0)
return STATUS_ARRAY_BOUNDS_EXCEEDED;
//
// Copy data over
RtlCopyMemory(Element, Array->Data + (Index * sizeof(UCHAR)), sizeof(UCHAR));
return STATUS_SUCCESS;
}
NTSTATUS GetElementsByteArray(IN PBYTE_ARRAY Array, IN ULONG Index, OUT PVOID Elements, IN ULONG NumElements)
{
//
// Check array bounds
if (Index >= Array->Size || (LONG)Index < 0)
return STATUS_ARRAY_BOUNDS_EXCEEDED;
//
// Copy data over
RtlCopyMemory(Elements, Array->Data + (Index * sizeof(UCHAR)), NumElements * sizeof(UCHAR));
return STATUS_SUCCESS;
}
NTSTATUS SetElementByteArray(IN PBYTE_ARRAY Array, IN ULONG Index, IN PVOID Element)
{
//
// Check array bounds
if (Index >= Array->Size || (LONG)Index < 0)
return STATUS_ARRAY_BOUNDS_EXCEEDED;
//
// Copy data over
RtlCopyMemory(Array->Data + (Index * sizeof(UCHAR)), Element, sizeof(UCHAR));
return STATUS_SUCCESS;
}
NTSTATUS SetElementsByteArray(IN PBYTE_ARRAY Array, IN ULONG Index, IN PVOID Elements, IN ULONG NumElements)
{
//
// Check array bounds
if (Index >= Array->Size || (LONG)Index < 0)
return STATUS_ARRAY_BOUNDS_EXCEEDED;
//
// Copy data over
RtlCopyMemory(Array->Data + (Index * sizeof(UCHAR)), Elements, NumElements * sizeof(UCHAR));
return STATUS_SUCCESS;
}
NTSTATUS FreeByteArray(IN PBYTE_ARRAY Array)
{
if (Array->Data == NULL)
return STATUS_MEMORY_NOT_ALLOCATED;
//
// Free data
ExFreePoolWithTag(Array->Data, ARRAY_POOL_TAG);
//
// Null out everything
Array->Data = NULL;
Array->Size = 0;
Array->Capacity = 0;
return STATUS_SUCCESS;
}

View File

@@ -1,60 +0,0 @@
/*
* Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver
*
* MIT License
*
* Copyright (c) 2016-2020 Nefarius Software Solutions e.U. and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include <ntifs.h>
EXTERN_C_START
#define INITIAL_ARRAY_CAPACITY PAGE_SIZE
#define ARRAY_POOL_TAG 'arrA'
typedef struct _BYTE_ARRAY
{
UCHAR* Data; //> array of data we're storing
ULONG_PTR Size; //> slots used so far
ULONG_PTR Capacity; //> total available memory
} BYTE_ARRAY, *PBYTE_ARRAY;
NTSTATUS InitByteArray(IN OUT PBYTE_ARRAY Array);
NTSTATUS AppendElementByteArray(IN PBYTE_ARRAY Array, IN PVOID Element);
NTSTATUS AppendElementsByteArray(IN PBYTE_ARRAY Array, IN PVOID Elements, IN ULONG NumElements);
NTSTATUS GetElementByteArray(IN PBYTE_ARRAY Array, IN ULONG Index, OUT PVOID Element);
NTSTATUS GetElementsByteArray(IN PBYTE_ARRAY Array, IN ULONG Index, OUT PVOID Elements, IN ULONG NumElements);
NTSTATUS SetElementByteArray(IN PBYTE_ARRAY Array, IN ULONG Index, IN PVOID Element);
NTSTATUS SetElementsByteArray(IN PBYTE_ARRAY Array, IN ULONG Index, IN PVOID Elements, IN ULONG NumElements);
NTSTATUS FreeByteArray(IN PBYTE_ARRAY Array);
EXTERN_C_END

View File

@@ -1,95 +0,0 @@
/*
* Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver
*
* MIT License
*
* Copyright (c) 2016-2020 Nefarius Software Solutions e.U. and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
//
// FDO (bus device) context data
//
typedef struct _FDO_DEVICE_DATA
{
//
// Counter of interface references
//
LONG InterfaceReferenceCounter;
//
// Next SessionId to assign to a file handle
//
LONG NextSessionId;
//
// Periodic timer sweeping up orphaned requests
//
WDFTIMER PendingPluginRequestsCleanupTimer;
} FDO_DEVICE_DATA, *PFDO_DEVICE_DATA;
#define FDO_FIRST_SESSION_ID 100
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DEVICE_DATA, FdoGetData)
//
// Context data associated with file objects created by user mode applications
//
typedef struct _FDO_FILE_DATA
{
//
// SessionId associated with file handle. Used to map file handles to emulated gamepad devices
//
LONG SessionId;
} FDO_FILE_DATA, *PFDO_FILE_DATA;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_FILE_DATA, FileObjectGetData)
//
// Context data for plugin requests
//
typedef struct _FDO_PLUGIN_REQUEST_DATA
{
//
// Unique serial number of the device on the bus
//
ULONG Serial;
//
// High resolution timestamp taken when this request got moved to pending state
//
LARGE_INTEGER Timestamp;
//
// Performance counter system frequency taken upon fetching timestamp
//
LARGE_INTEGER Frequency;
} FDO_PLUGIN_REQUEST_DATA, *PFDO_PLUGIN_REQUEST_DATA;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_PLUGIN_REQUEST_DATA, PluginRequestGetData)

View File

@@ -24,6 +24,7 @@
* SOFTWARE.
*/
#include <ntifs.h>
#include "Ds4Pdo.hpp"
#include "trace.h"
#include "Ds4Pdo.tmh"
@@ -32,15 +33,25 @@
#include <hidclass.h>
PCWSTR ViGEm::Bus::Targets::EmulationTargetDS4::_deviceDescription = L"Virtual DualShock 4 Controller";
ViGEm::Bus::Targets::EmulationTargetDS4::EmulationTargetDS4(ULONG Serial, LONG SessionId, USHORT VendorId,
USHORT ProductId) : EmulationTargetPDO(
Serial, SessionId, VendorId, ProductId)
{
_TargetType = DualShock4Wired;
_UsbConfigurationDescriptionSize = DS4_DESCRIPTOR_SIZE;
this->_TargetType = DualShock4Wired;
this->_UsbConfigurationDescriptionSize = DS4_DESCRIPTOR_SIZE;
//
// Set PNP Capabilities
//
this->_PnpCapabilities.SurpriseRemovalOK = WdfTrue;
//
// Set Power Capabilities
//
this->_PowerCapabilities.DeviceState[PowerSystemWorking] = PowerDeviceD0;
this->_PowerCapabilities.WakeFromD0 = WdfTrue;
}
NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::PdoPrepareDevice(PWDFDEVICE_INIT DeviceInit,
@@ -1127,6 +1138,41 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::SubmitReportImpl(PVOID NewRepo
return status;
}
VOID ViGEm::Bus::Targets::EmulationTargetDS4::ReverseByteArray(PUCHAR Array, INT Length)
{
const auto s = static_cast<PUCHAR>(ExAllocatePoolWithTag(
NonPagedPool,
sizeof(UCHAR) * Length,
'U4SD'
));
INT c, d;
if (s == nullptr)
return;
for (c = Length - 1, d = 0; c >= 0; c--, d++)
*(s + d) = *(Array + c);
for (c = 0; c < Length; c++)
*(Array + c) = *(s + c);
ExFreePoolWithTag(s, 'U4SD');
}
VOID ViGEm::Bus::Targets::EmulationTargetDS4::GenerateRandomMacAddress(PMAC_ADDRESS Address)
{
// Vendor "C0:13:37"
Address->Vendor0 = 0xC0;
Address->Vendor1 = 0x13;
Address->Vendor2 = 0x37;
ULONG seed = KeQueryPerformanceCounter(NULL).LowPart;
Address->Nic0 = RtlRandomEx(&seed) % 0xFF;
Address->Nic1 = RtlRandomEx(&seed) % 0xFF;
Address->Nic2 = RtlRandomEx(&seed) % 0xFF;
}
VOID ViGEm::Bus::Targets::EmulationTargetDS4::PendingUsbRequestsTimerFunc(
_In_ WDFTIMER Timer
)

View File

@@ -29,11 +29,22 @@
#include "EmulationTargetPDO.hpp"
#include <ViGEm/km/BusShared.h>
#include "Util.h"
namespace ViGEm::Bus::Targets
{
//
// Represents a MAC address.
//
typedef struct _MAC_ADDRESS
{
UCHAR Vendor0;
UCHAR Vendor1;
UCHAR Vendor2;
UCHAR Nic0;
UCHAR Nic1;
UCHAR Nic2;
} MAC_ADDRESS, * PMAC_ADDRESS;
constexpr unsigned char hid_get_report_id(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST* pReq)
{
return pReq->Value & 0xFF;
@@ -48,7 +59,6 @@ namespace ViGEm::Bus::Targets
{
public:
EmulationTargetDS4(ULONG Serial, LONG SessionId, USHORT VendorId = 0x054C, USHORT ProductId = 0x05C4);
~EmulationTargetDS4() = default;
NTSTATUS PdoPrepareDevice(PWDFDEVICE_INIT DeviceInit,
PUNICODE_STRING DeviceId,
@@ -65,14 +75,28 @@ namespace ViGEm::Bus::Targets
NTSTATUS SelectConfiguration(PURB Urb) override;
void AbortPipe() override;
NTSTATUS UsbClassInterface(PURB Urb) override;
NTSTATUS UsbGetDescriptorFromInterface(PURB Urb) override;
NTSTATUS UsbSelectInterface(PURB Urb) override;
NTSTATUS UsbGetStringDescriptorType(PURB Urb) override;
NTSTATUS UsbBulkOrInterruptTransfer(_URB_BULK_OR_INTERRUPT_TRANSFER* pTransfer, WDFREQUEST Request) override;
NTSTATUS UsbControlTransfer(PURB Urb) override;
NTSTATUS SubmitReportImpl(PVOID NewReport) override;
private:
static EVT_WDF_TIMER PendingUsbRequestsTimerFunc;
static VOID ReverseByteArray(PUCHAR Array, INT Length);
static VOID GenerateRandomMacAddress(PMAC_ADDRESS Address);
static PCWSTR _deviceDescription;
static const int HID_REQUEST_GET_REPORT = 0x01;
@@ -123,8 +147,6 @@ namespace ViGEm::Bus::Targets
//
// Default MAC address of the host (not used)
//
MAC_ADDRESS _HostMacAddress;
static EVT_WDF_TIMER PendingUsbRequestsTimerFunc;
MAC_ADDRESS _HostMacAddress;
};
}

View File

@@ -32,7 +32,6 @@
#include <ntstrsafe.h>
#include <usbioctl.h>
#include <usbiodef.h>
#include <ViGEmBusDriver.h>
PCWSTR ViGEm::Bus::Core::EmulationTargetPDO::_deviceLocation = L"Virtual Gamepad Emulation Bus";
@@ -40,8 +39,6 @@ PCWSTR ViGEm::Bus::Core::EmulationTargetPDO::_deviceLocation = L"Virtual Gamepad
NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentDevice, PWDFDEVICE_INIT DeviceInit)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
WDF_DEVICE_PNP_CAPABILITIES pnpCaps;
WDF_DEVICE_POWER_CAPABILITIES powerCaps;
WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
WDF_OBJECT_ATTRIBUTES pdoAttributes;
WDF_IO_QUEUE_CONFIG defaultPdoQueueConfig;
@@ -70,32 +67,6 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
do
{
#pragma region Enter RAW device mode
status = WdfPdoInitAssignRawDevice(DeviceInit, &GUID_DEVCLASS_VIGEM_RAWPDO);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"WdfPdoInitAssignRawDevice failed with status %!STATUS!",
status);
break;
}
WdfDeviceInitSetCharacteristics(DeviceInit, FILE_AUTOGENERATED_DEVICE_NAME, TRUE);
status = WdfDeviceInitAssignSDDLString(DeviceInit, &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"WdfDeviceInitAssignSDDLString failed with status %!STATUS!",
status);
break;
}
#pragma endregion
#pragma region Prepare PDO
status = this->PdoPrepareDevice(DeviceInit, &deviceId, &deviceDescription);
@@ -303,35 +274,24 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::PdoCreateDevice(WDFDEVICE ParentD
#pragma region PNP capabilities
WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps);
//
// Other capabilities initialized in derived class
//
pnpCaps.Removable = WdfTrue;
pnpCaps.EjectSupported = WdfTrue;
pnpCaps.SurpriseRemovalOK = WdfTrue;
this->_PnpCapabilities.Address = this->_SerialNo;
this->_PnpCapabilities.UINumber = this->_SerialNo;
pnpCaps.Address = this->_SerialNo;
pnpCaps.UINumber = this->_SerialNo;
WdfDeviceSetPnpCapabilities(this->_PdoDevice, &pnpCaps);
WdfDeviceSetPnpCapabilities(this->_PdoDevice, &this->_PnpCapabilities);
#pragma endregion
#pragma region Power capabilities
WDF_DEVICE_POWER_CAPABILITIES_INIT(&powerCaps);
//
// Capabilities initialized in derived class
//
powerCaps.DeviceD1 = WdfTrue;
powerCaps.WakeFromD1 = WdfTrue;
powerCaps.DeviceWake = PowerDeviceD1;
powerCaps.DeviceState[PowerSystemWorking] = PowerDeviceD0;
powerCaps.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
powerCaps.DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
powerCaps.DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
powerCaps.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
powerCaps.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
WdfDeviceSetPowerCapabilities(this->_PdoDevice, &powerCaps);
WdfDeviceSetPowerCapabilities(this->_PdoDevice, &this->_PowerCapabilities);
#pragma endregion
} while (FALSE);
@@ -354,6 +314,34 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::EvtDeviceContextCleanup(
//
WdfIoQueuePurgeSynchronously(ctx->Target->_PendingPlugInRequests);
WdfObjectDelete(ctx->Target->_PendingPlugInRequests);
//
// Wait for thread to finish, if active
//
if (ctx->Target->_PluginRequestCompletionWorkerThreadHandle)
{
NTSTATUS status = KeWaitForSingleObject(
&ctx->Target->_PluginRequestCompletionWorkerThreadHandle,
Executive,
KernelMode,
FALSE,
nullptr
);
if (NT_SUCCESS(status))
{
ZwClose(ctx->Target->_PluginRequestCompletionWorkerThreadHandle);
ctx->Target->_PluginRequestCompletionWorkerThreadHandle = nullptr;
}
else
{
TraceEvents(TRACE_LEVEL_WARNING,
TRACE_BUSPDO,
"KeWaitForSingleObject failed with status %!STATUS!",
status
);
}
}
//
// PDO device object getting disposed, free context object
@@ -392,13 +380,34 @@ 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;
if (this->_PluginRequestCompletionWorkerThreadHandle)
{
status = KeWaitForSingleObject(
&this->_PluginRequestCompletionWorkerThreadHandle,
Executive,
KernelMode,
FALSE,
nullptr
);
if (NT_SUCCESS(status))
{
ZwClose(this->_PluginRequestCompletionWorkerThreadHandle);
this->_PluginRequestCompletionWorkerThreadHandle = nullptr;
}
else
{
TraceEvents(TRACE_LEVEL_WARNING,
TRACE_BUSPDO,
"KeWaitForSingleObject failed with status %!STATUS!",
status
);
}
}
status = WdfRequestForwardToIoQueue(Request, this->_PendingPlugInRequests);
@@ -419,7 +428,7 @@ NTSTATUS ViGEm::Bus::Core::EmulationTargetPDO::EnqueuePlugin(WDFREQUEST Request)
InitializeObjectAttributes(&threadOb, NULL,
OBJ_KERNEL_HANDLE, NULL, NULL);
status = PsCreateSystemThread(&_PluginRequestCompletionWorkerThreadHandle,
status = PsCreateSystemThread(&this->_PluginRequestCompletionWorkerThreadHandle,
static_cast<ACCESS_MASK>(0L),
&threadOb,
nullptr,
@@ -543,11 +552,11 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::PluginRequestCompletionWorkerRoutine(
WDFREQUEST pluginRequest;
LARGE_INTEGER timeout;
timeout.QuadPart = WDF_REL_TIMEOUT_IN_SEC(1);;
timeout.QuadPart = WDF_REL_TIMEOUT_IN_SEC(1);
TraceEvents(TRACE_LEVEL_INFORMATION,
TRACE_BUSPDO,
"Waiting for 1 second to complete PDO boot..."
TRACE_BUSPDO,
"Waiting for 1 second to complete PDO boot..."
);
NTSTATUS status = KeWaitForSingleObject(
@@ -566,8 +575,8 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::PluginRequestCompletionWorkerRoutine(
if (!NT_SUCCESS(WdfIoQueueRetrieveNextRequest(ctx->_PendingPlugInRequests, &pluginRequest)))
{
TraceEvents(TRACE_LEVEL_WARNING,
TRACE_BUSPDO,
"No pending plugin request available"
TRACE_BUSPDO,
"No pending plugin request available"
);
break;
}
@@ -575,10 +584,10 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::PluginRequestCompletionWorkerRoutine(
if (status == STATUS_TIMEOUT)
{
TraceEvents(TRACE_LEVEL_WARNING,
TRACE_BUSPDO,
"Plugin request timed out, completing with error"
TRACE_BUSPDO,
"Plugin request timed out, completing with error"
);
//
// We haven't hit a path where the event gets signaled, report error
//
@@ -589,19 +598,59 @@ VOID ViGEm::Bus::Core::EmulationTargetPDO::PluginRequestCompletionWorkerRoutine(
if (NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_INFORMATION,
TRACE_BUSPDO,
"Plugin request completed successfully"
TRACE_BUSPDO,
"Plugin request completed successfully"
);
//
// Event triggered in time, complete with success
//
WdfRequestComplete(pluginRequest, STATUS_SUCCESS);
break;
}
} while (FALSE);
}
while (FALSE);
ZwClose(ctx->_PluginRequestCompletionWorkerThreadHandle);
ctx->_PluginRequestCompletionWorkerThreadHandle = nullptr;
KeClearEvent(&ctx->_PdoBootNotificationEvent);
(void)PsTerminateSystemThread(0);
}
VOID ViGEm::Bus::Core::EmulationTargetPDO::DumpAsHex(PCSTR Prefix, PVOID Buffer, ULONG BufferLength)
{
#ifdef DBG
size_t dumpBufferLength = ((BufferLength * sizeof(CHAR)) * 2) + 1;
PSTR dumpBuffer = static_cast<PSTR>(ExAllocatePoolWithTag(
NonPagedPoolNx,
dumpBufferLength,
'1234'
));
if (dumpBuffer)
{
RtlZeroMemory(dumpBuffer, dumpBufferLength);
for (ULONG i = 0; i < BufferLength; i++)
{
sprintf(&dumpBuffer[i * 2], "%02X", static_cast<PUCHAR>(Buffer)[i]);
}
TraceDbg(TRACE_BUSPDO,
"%s - Buffer length: %04d, buffer content: %s\n",
Prefix,
BufferLength,
dumpBuffer
);
ExFreePoolWithTag(dumpBuffer, '1234');
}
#else
UNREFERENCED_PARAMETER(Prefix);
UNREFERENCED_PARAMETER(Buffer);
UNREFERENCED_PARAMETER(BufferLength);
#endif
}
void ViGEm::Bus::Core::EmulationTargetPDO::UsbAbortPipe()
@@ -664,6 +713,9 @@ _ProductId(ProductId)
{
this->_OwnerProcessId = current_process_id();
KeInitializeEvent(&this->_PdoBootNotificationEvent, NotificationEvent, FALSE);
WDF_DEVICE_PNP_CAPABILITIES_INIT(&this->_PnpCapabilities);
WDF_DEVICE_POWER_CAPABILITIES_INIT(&this->_PowerCapabilities);
}
bool ViGEm::Bus::Core::EmulationTargetPDO::GetPdoBySerial(

View File

@@ -126,6 +126,8 @@ namespace ViGEm::Bus::Core
protected:
static const ULONG _maxHardwareIdLength = 0xFF;
static const int MAX_INSTANCE_ID_LEN = 80;
static PCWSTR _deviceLocation;
static BOOLEAN USB_BUSIFFN UsbInterfaceIsDeviceHighSpeed(IN PVOID BusContext);
@@ -153,9 +155,7 @@ 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;
virtual NTSTATUS SelectConfiguration(PURB Urb) = 0;
@@ -163,6 +163,18 @@ namespace ViGEm::Bus::Core
virtual void AbortPipe() = 0;
virtual NTSTATUS SubmitReportImpl(PVOID NewReport) = 0;
static VOID DumpAsHex(PCSTR Prefix, PVOID Buffer, ULONG BufferLength);
//
// PNP Capabilities may differ from device to device
//
WDF_DEVICE_PNP_CAPABILITIES _PnpCapabilities;
//
// Power Capabilities may differ from device to device
//
WDF_DEVICE_POWER_CAPABILITIES _PowerCapabilities;
//
// Unique serial number of the device on the bus
@@ -215,7 +227,7 @@ namespace ViGEm::Bus::Core
WDFDEVICE _PdoDevice{};
//
// Configuration descriptor size
// Configuration descriptor size (populated by derived class)
//
ULONG _UsbConfigurationDescriptionSize{};

View File

@@ -56,15 +56,15 @@ VOID Bus_EvtIoDeviceControl(
IN ULONG IoControlCode
)
{
NTSTATUS status = STATUS_INVALID_PARAMETER;
WDFDEVICE Device;
size_t length = 0;
PXUSB_SUBMIT_REPORT xusbSubmit = NULL;
PXUSB_REQUEST_NOTIFICATION xusbNotify = NULL;
PDS4_SUBMIT_REPORT ds4Submit = NULL;
PDS4_REQUEST_NOTIFICATION ds4Notify = NULL;
PVIGEM_CHECK_VERSION pCheckVersion = NULL;
PXUSB_GET_USER_INDEX pXusbGetUserIndex = NULL;
NTSTATUS status = STATUS_INVALID_PARAMETER;
WDFDEVICE Device;
size_t length = 0;
PXUSB_SUBMIT_REPORT xusbSubmit = nullptr;
PXUSB_REQUEST_NOTIFICATION xusbNotify = nullptr;
PDS4_SUBMIT_REPORT ds4Submit = nullptr;
PDS4_REQUEST_NOTIFICATION ds4Notify = nullptr;
PVIGEM_CHECK_VERSION pCheckVersion = nullptr;
PXUSB_GET_USER_INDEX pXusbGetUserIndex = nullptr;
EmulationTargetPDO* pdo;
Device = WdfIoQueueGetDevice(Queue);
@@ -74,7 +74,7 @@ VOID Bus_EvtIoDeviceControl(
switch (IoControlCode)
{
#pragma region IOCTL_VIGEM_CHECK_VERSION
case IOCTL_VIGEM_CHECK_VERSION:
TraceDbg(TRACE_QUEUE, "IOCTL_VIGEM_CHECK_VERSION");
@@ -82,7 +82,7 @@ VOID Bus_EvtIoDeviceControl(
status = WdfRequestRetrieveInputBuffer(
Request,
sizeof(VIGEM_CHECK_VERSION),
(PVOID*)&pCheckVersion,
reinterpret_cast<PVOID*>(&pCheckVersion),
&length
);
@@ -95,16 +95,16 @@ VOID Bus_EvtIoDeviceControl(
status = (pCheckVersion->Version == VIGEM_COMMON_VERSION) ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED;
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_QUEUE,
"Requested version: 0x%04X, compiled version: 0x%04X",
pCheckVersion->Version, VIGEM_COMMON_VERSION);
TRACE_QUEUE,
"Requested version: 0x%04X, compiled version: 0x%04X",
pCheckVersion->Version, VIGEM_COMMON_VERSION);
break;
#pragma endregion
#pragma endregion
#pragma region IOCTL_VIGEM_PLUGIN_TARGET
case IOCTL_VIGEM_PLUGIN_TARGET:
TraceDbg(TRACE_QUEUE, "IOCTL_VIGEM_PLUGIN_TARGET");
@@ -112,40 +112,40 @@ VOID Bus_EvtIoDeviceControl(
status = Bus_PlugInDevice(Device, Request, FALSE, &length);
break;
#pragma endregion
#pragma endregion
#pragma region IOCTL_VIGEM_UNPLUG_TARGET
case IOCTL_VIGEM_UNPLUG_TARGET:
TraceDbg(TRACE_QUEUE, "IOCTL_VIGEM_UNPLUG_TARGET");
status = Bus_UnPlugDevice(Device, Request, FALSE, &length);
break;
#pragma endregion
#pragma endregion
#pragma region IOCTL_XUSB_SUBMIT_REPORT
case IOCTL_XUSB_SUBMIT_REPORT:
TraceDbg(TRACE_QUEUE, "IOCTL_XUSB_SUBMIT_REPORT");
status = WdfRequestRetrieveInputBuffer(
Request,
sizeof(XUSB_SUBMIT_REPORT),
(PVOID*)&xusbSubmit,
reinterpret_cast<PVOID*>(&xusbSubmit),
&length
);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_QUEUE,
"WdfRequestRetrieveInputBuffer failed with status %!STATUS!",
status);
TRACE_QUEUE,
"WdfRequestRetrieveInputBuffer failed with status %!STATUS!",
status);
break;
}
@@ -155,8 +155,8 @@ VOID Bus_EvtIoDeviceControl(
if (xusbSubmit->SerialNo == 0)
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_QUEUE,
"Invalid serial 0 submitted");
TRACE_QUEUE,
"Invalid serial 0 submitted");
status = STATUS_INVALID_PARAMETER;
break;
@@ -169,38 +169,38 @@ VOID Bus_EvtIoDeviceControl(
}
break;
#pragma endregion
#pragma endregion
#pragma region IOCTL_XUSB_REQUEST_NOTIFICATION
case IOCTL_XUSB_REQUEST_NOTIFICATION:
TraceDbg(TRACE_QUEUE, "IOCTL_XUSB_REQUEST_NOTIFICATION");
// Don't accept the request if the output buffer can't hold the results
if (OutputBufferLength < sizeof(XUSB_REQUEST_NOTIFICATION))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_QUEUE,
"Output buffer %d too small, require at least %d",
(int)OutputBufferLength, (int)sizeof(XUSB_REQUEST_NOTIFICATION));
TRACE_QUEUE,
"Output buffer %d too small, require at least %d",
static_cast<int>(OutputBufferLength), static_cast<int>(sizeof(XUSB_REQUEST_NOTIFICATION)));
break;
}
status = WdfRequestRetrieveInputBuffer(
Request,
sizeof(XUSB_REQUEST_NOTIFICATION),
(PVOID*)&xusbNotify,
reinterpret_cast<PVOID*>(&xusbNotify),
&length
);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_QUEUE,
"WdfRequestRetrieveInputBuffer failed with status %!STATUS!",
status);
TRACE_QUEUE,
"WdfRequestRetrieveInputBuffer failed with status %!STATUS!",
status);
break;
}
@@ -210,8 +210,8 @@ VOID Bus_EvtIoDeviceControl(
if (xusbNotify->SerialNo == 0)
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_QUEUE,
"Invalid serial 0 submitted");
TRACE_QUEUE,
"Invalid serial 0 submitted");
status = STATUS_INVALID_PARAMETER;
break;
@@ -228,28 +228,28 @@ VOID Bus_EvtIoDeviceControl(
}
break;
#pragma endregion
#pragma endregion
#pragma region IOCTL_DS4_SUBMIT_REPORT
case IOCTL_DS4_SUBMIT_REPORT:
TraceDbg(TRACE_QUEUE, "IOCTL_DS4_SUBMIT_REPORT");
status = WdfRequestRetrieveInputBuffer(
Request,
sizeof(DS4_SUBMIT_REPORT),
(PVOID*)&ds4Submit,
reinterpret_cast<PVOID*>(&ds4Submit),
&length
);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_QUEUE,
"WdfRequestRetrieveInputBuffer failed with status %!STATUS!",
status);
TRACE_QUEUE,
"WdfRequestRetrieveInputBuffer failed with status %!STATUS!",
status);
break;
}
@@ -259,8 +259,8 @@ VOID Bus_EvtIoDeviceControl(
if (ds4Submit->SerialNo == 0)
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_QUEUE,
"Invalid serial 0 submitted");
TRACE_QUEUE,
"Invalid serial 0 submitted");
status = STATUS_INVALID_PARAMETER;
break;
@@ -273,8 +273,8 @@ VOID Bus_EvtIoDeviceControl(
}
break;
#pragma endregion
#pragma endregion
#pragma region IOCTL_DS4_REQUEST_NOTIFICATION
@@ -286,25 +286,25 @@ VOID Bus_EvtIoDeviceControl(
if (OutputBufferLength < sizeof(DS4_REQUEST_NOTIFICATION))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_QUEUE,
"Output buffer %d too small, require at least %d",
(int)OutputBufferLength, (int)sizeof(DS4_REQUEST_NOTIFICATION));
TRACE_QUEUE,
"Output buffer %d too small, require at least %d",
static_cast<int>(OutputBufferLength), static_cast<int>(sizeof(DS4_REQUEST_NOTIFICATION)));
break;
}
status = WdfRequestRetrieveInputBuffer(
Request,
sizeof(DS4_REQUEST_NOTIFICATION),
(PVOID*)&ds4Notify,
reinterpret_cast<PVOID*>(&ds4Notify),
&length
);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_QUEUE,
"WdfRequestRetrieveInputBuffer failed with status %!STATUS!",
status);
TRACE_QUEUE,
"WdfRequestRetrieveInputBuffer failed with status %!STATUS!",
status);
break;
}
@@ -314,8 +314,8 @@ VOID Bus_EvtIoDeviceControl(
if (ds4Notify->SerialNo == 0)
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_QUEUE,
"Invalid serial 0 submitted");
TRACE_QUEUE,
"Invalid serial 0 submitted");
status = STATUS_INVALID_PARAMETER;
break;
@@ -332,15 +332,15 @@ VOID Bus_EvtIoDeviceControl(
}
break;
#pragma endregion
#pragma endregion
#pragma region IOCTL_XUSB_GET_USER_INDEX
case IOCTL_XUSB_GET_USER_INDEX:
TraceDbg(TRACE_QUEUE, "IOCTL_XUSB_GET_USER_INDEX");
// Don't accept the request if the output buffer can't hold the results
if (OutputBufferLength < sizeof(XUSB_GET_USER_INDEX))
{
@@ -351,7 +351,7 @@ VOID Bus_EvtIoDeviceControl(
status = WdfRequestRetrieveInputBuffer(
Request,
sizeof(XUSB_GET_USER_INDEX),
(PVOID*)&pXusbGetUserIndex,
reinterpret_cast<PVOID*>(&pXusbGetUserIndex),
&length);
if (!NT_SUCCESS(status))
@@ -379,14 +379,14 @@ VOID Bus_EvtIoDeviceControl(
}
break;
#pragma endregion
default:
TraceEvents(TRACE_LEVEL_WARNING,
TRACE_QUEUE,
"Unknown I/O control code 0x%X", IoControlCode);
TRACE_QUEUE,
"Unknown I/O control code 0x%X", IoControlCode);
break; // default status is STATUS_INVALID_PARAMETER
}

Binary file not shown.

View File

@@ -1,56 +0,0 @@
/*
* Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver
*
* MIT License
*
* Copyright (c) 2016-2020 Nefarius Software Solutions e.U. and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
//
// Returns the current caller process id.
//
#define CURRENT_PROCESS_ID() ((DWORD)((DWORD_PTR)PsGetCurrentProcessId() & 0xFFFFFFFF))
#define IS_OWNER(_pdo_) (_pdo_->OwnerProcessId == CURRENT_PROCESS_ID())
//
// Represents a MAC address.
//
typedef struct _MAC_ADDRESS
{
UCHAR Vendor0;
UCHAR Vendor1;
UCHAR Vendor2;
UCHAR Nic0;
UCHAR Nic1;
UCHAR Nic2;
} MAC_ADDRESS, *PMAC_ADDRESS;
EXTERN_C_START
VOID ReverseByteArray(PUCHAR Array, INT Length);
VOID GenerateRandomMacAddress(PMAC_ADDRESS Address);
EXTERN_C_END

View File

@@ -35,13 +35,8 @@ DriverVer= ;
DefaultDestDir = 12
ViGEmBus_Device_CoInstaller_CopyFiles = 11
; ================= Class section =====================
[SourceDisksNames.amd64]
1 = %DiskName%,,,"\x64"
[SourceDisksNames.x86]
1 = %DiskName%,,,"\x86"
[SourceDisksNames]
1 = %DiskName%,,,
[SourceDisksFiles]
ViGEmBus.sys = 1,,

View File

@@ -89,27 +89,27 @@
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
<IncludePath>$(SolutionDir)include;$(SolutionDir)client\include;$(IncludePath)</IncludePath>
<Inf2CatUseLocalTime>true</Inf2CatUseLocalTime>
<EnableInf2cat>false</EnableInf2cat>
<EnableInf2cat>true</EnableInf2cat>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
<IncludePath>$(SolutionDir)include;$(SolutionDir)client\include;$(IncludePath)</IncludePath>
<Inf2CatUseLocalTime>true</Inf2CatUseLocalTime>
<OutDir>$(SolutionDir)bin\$(DDKPlatform)\</OutDir>
<EnableInf2cat>false</EnableInf2cat>
<EnableInf2cat>true</EnableInf2cat>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
<IncludePath>$(SolutionDir)include;$(SolutionDir)client\include;$(IncludePath)</IncludePath>
<Inf2CatUseLocalTime>true</Inf2CatUseLocalTime>
<EnableInf2cat>false</EnableInf2cat>
<EnableInf2cat>true</EnableInf2cat>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
<IncludePath>$(SolutionDir)include;$(SolutionDir)client\include;$(IncludePath)</IncludePath>
<Inf2CatUseLocalTime>true</Inf2CatUseLocalTime>
<OutDir>$(SolutionDir)bin\$(DDKPlatform)\</OutDir>
<EnableInf2cat>false</EnableInf2cat>
<EnableInf2cat>true</EnableInf2cat>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Inf>
@@ -179,24 +179,19 @@
</ItemDefinitionGroup>
<ItemGroup>
<Inf Include="ViGEmBus.inf" />
<Inf Include="ViGEmBus_SingleArch.inf" />
</ItemGroup>
<ItemGroup>
<FilesToPackage Include="$(TargetPath)" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(SolutionDir)\Include\ViGEmBusDriver.h" />
<ClInclude Include="..\client\include\ViGEm\km\BusShared.h" />
<ClInclude Include="busenum.h" />
<ClInclude Include="ByteArray.h" />
<ClInclude Include="Context.h" />
<ClInclude Include="CRTCPP.hpp" />
<ClInclude Include="Ds4Pdo.hpp" />
<ClInclude Include="EmulationTargetPDO.hpp" />
<ClInclude Include="Queue.hpp" />
<ClInclude Include="resource.h" />
<ClInclude Include="trace.h" />
<ClInclude Include="Util.h" />
<ClInclude Include="XusbPdo.hpp" />
</ItemGroup>
<ItemGroup>
@@ -205,17 +200,12 @@
<ItemGroup>
<ClCompile Include="busenum.cpp" />
<ClCompile Include="buspdo.cpp" />
<ClCompile Include="ByteArray.c" />
<ClCompile Include="Driver.cpp" />
<ClCompile Include="Ds4Pdo.cpp" />
<ClCompile Include="EmulationTargetPDO.cpp" />
<ClCompile Include="Queue.cpp" />
<ClCompile Include="Util.c" />
<ClCompile Include="XusbPdo.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@@ -17,9 +17,6 @@
<UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>
<Extensions>inf;inv;inx;mof;mc;</Extensions>
</Filter>
<Filter Include="Header Files\Common">
<UniqueIdentifier>{bbf85b1d-5a75-4302-af4e-46627fcf0d78}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Targets">
<UniqueIdentifier>{b00da32a-ce46-490d-9e77-95bb90925995}</UniqueIdentifier>
</Filter>
@@ -31,26 +28,11 @@
<Inf Include="ViGEmBus.inf">
<Filter>Driver Files</Filter>
</Inf>
<Inf Include="ViGEmBus_SingleArch.inf">
<Filter>Driver Files</Filter>
</Inf>
</ItemGroup>
<ItemGroup>
<ClInclude Include="busenum.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Context.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Util.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ByteArray.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(SolutionDir)\Include\ViGEmBusDriver.h">
<Filter>Header Files\Common</Filter>
</ClInclude>
<ClInclude Include="trace.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -77,12 +59,6 @@
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Util.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ByteArray.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="XusbPdo.cpp">
<Filter>Source Files\Targets</Filter>
</ClCompile>
@@ -110,7 +86,4 @@
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />
</ItemGroup>
</Project>

View File

@@ -1,100 +0,0 @@
; Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver
;
; MIT License
;
; Copyright (c) 2016-2020 Nefarius Software Solutions e.U. and Contributors
;
; Permission is hereby granted, free of charge, to any person obtaining a copy
; of this software and associated documentation files (the "Software"), to deal
; in the Software without restriction, including without limitation the rights
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
; copies of the Software, and to permit persons to whom the Software is
; furnished to do so, subject to the following conditions:
;
; The above copyright notice and this permission notice shall be included in all
; copies or substantial portions of the Software.
;
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
; SOFTWARE.
[Version]
Signature="$WINDOWS NT$"
Class=System
ClassGuid={4D36E97D-E325-11CE-BFC1-08002BE10318}
Provider=%ManufacturerName%
CatalogFile=ViGEmBus.cat
DriverVer= ;
[DestinationDirs]
DefaultDestDir = 12
ViGEmBus_Device_CoInstaller_CopyFiles = 11
[SourceDisksNames]
1 = %DiskName%,,,
[SourceDisksFiles]
ViGEmBus.sys = 1,,
WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll = 1
;*****************************************
; Install Section
;*****************************************
[Manufacturer]
%ManufacturerName%=Standard,NTamd64,NTx86
[Standard.NTamd64]
%ViGEmBus.DeviceDesc%=ViGEmBus_Device, Nefarius\ViGEmBus\Gen1
[Standard.NTx86]
%ViGEmBus.DeviceDesc%=ViGEmBus_Device, Nefarius\ViGEmBus\Gen1
[ViGEmBus_Device.NT]
CopyFiles=Drivers_Dir
[Drivers_Dir]
ViGEmBus.sys
;-------------- Service installation
[ViGEmBus_Device.NT.Services]
AddService = ViGEmBus,%SPSVCINST_ASSOCSERVICE%, ViGEmBus_Service_Inst
; -------------- ViGEmBus driver install sections
[ViGEmBus_Service_Inst]
DisplayName = %ViGEmBus.SVCDESC%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %12%\ViGEmBus.sys
;
;--- ViGEmBus_Device Coinstaller installation ------
;
[ViGEmBus_Device.NT.CoInstallers]
AddReg=ViGEmBus_Device_CoInstaller_AddReg
CopyFiles=ViGEmBus_Device_CoInstaller_CopyFiles
[ViGEmBus_Device_CoInstaller_AddReg]
HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"
[ViGEmBus_Device_CoInstaller_CopyFiles]
WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll
[ViGEmBus_Device.NT.Wdf]
KmdfService = ViGEmBus, ViGEmBus_wdfsect
[ViGEmBus_wdfsect]
KmdfLibraryVersion = $KMDFVERSION$
[Strings]
SPSVCINST_ASSOCSERVICE= 0x00000002
ManufacturerName="Nefarius Software Solutions e.U."
DiskName = "ViGEmBus Installation Disk"
ViGEmBus.DeviceDesc = "Virtual Gamepad Emulation Bus"
ViGEmBus.SVCDESC = "Virtual Gamepad Emulation Service"

View File

@@ -41,8 +41,30 @@ ViGEm::Bus::Targets::EmulationTargetXUSB::EmulationTargetXUSB(ULONG Serial, LONG
USHORT ProductId) : EmulationTargetPDO(
Serial, SessionId, VendorId, ProductId)
{
_TargetType = Xbox360Wired;
_UsbConfigurationDescriptionSize = XUSB_DESCRIPTOR_SIZE;
this->_TargetType = Xbox360Wired;
this->_UsbConfigurationDescriptionSize = XUSB_DESCRIPTOR_SIZE;
//
// Set PNP Capabilities
//
this->_PnpCapabilities.Removable = WdfTrue;
this->_PnpCapabilities.SurpriseRemovalOK = WdfTrue;
this->_PnpCapabilities.UniqueID = WdfTrue;
//
// Set Power Capabilities
//
this->_PowerCapabilities.DeviceState[PowerSystemWorking] = PowerDeviceD0;
this->_PowerCapabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD2;
this->_PowerCapabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
this->_PowerCapabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;
this->_PowerCapabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD2;
this->_PowerCapabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
this->_PowerCapabilities.DeviceD1 = WdfTrue;
this->_PowerCapabilities.DeviceD2 = WdfTrue;
this->_PowerCapabilities.WakeFromD0 = WdfTrue;
this->_PowerCapabilities.WakeFromD1 = WdfTrue;
this->_PowerCapabilities.WakeFromD2 = WdfTrue;
}
NTSTATUS ViGEm::Bus::Targets::EmulationTargetXUSB::PdoPrepareDevice(PWDFDEVICE_INIT DeviceInit, PUNICODE_STRING DeviceId,

View File

@@ -30,7 +30,7 @@
namespace ViGEm::Bus::Targets
{
constexpr auto XUSB_POOL_TAG = 'EGiV';
constexpr auto XUSB_POOL_TAG = 'XUiV';
typedef struct _XUSB_INTERRUPT_IN_PACKET
{
@@ -55,7 +55,6 @@ namespace ViGEm::Bus::Targets
{
public:
EmulationTargetXUSB(ULONG Serial, LONG SessionId, USHORT VendorId = 0x045E, USHORT ProductId = 0x028E);
~EmulationTargetXUSB() = default;
NTSTATUS PdoPrepareDevice(PWDFDEVICE_INIT DeviceInit,
PUNICODE_STRING DeviceId,
@@ -74,14 +73,21 @@ namespace ViGEm::Bus::Targets
void AbortPipe() override;
NTSTATUS UsbClassInterface(PURB Urb) override;
NTSTATUS UsbGetDescriptorFromInterface(PURB Urb) override;
NTSTATUS UsbSelectInterface(PURB Urb) override;
NTSTATUS UsbGetStringDescriptorType(PURB Urb) override;
NTSTATUS UsbBulkOrInterruptTransfer(_URB_BULK_OR_INTERRUPT_TRANSFER* pTransfer, WDFREQUEST Request) override;
NTSTATUS UsbControlTransfer(PURB Urb) override;
NTSTATUS SubmitReportImpl(PVOID NewReport) override;
NTSTATUS GetUserIndex(PULONG UserIndex) const;
private:
static PCWSTR _deviceDescription;

View File

@@ -32,34 +32,52 @@
#include <wdf.h>
#define NTSTRSAFE_LIB
#include <ntstrsafe.h>
#include <ntintsafe.h>
#include <initguid.h>
#include "ViGEmBusDriver.h"
#include <ViGEm/km/BusShared.h>
#include "Queue.hpp"
#include <usb.h>
#include <usbbusif.h>
#include "Context.h"
#include "Util.h"
#pragma region Macros
#define HID_LANGUAGE_ID_LENGTH 0x04
#define VIGEM_POOL_TAG 0x45476956 // "EGiV"
#define DRIVERNAME "ViGEm: "
#define ORC_PC_FREQUENCY_DIVIDER 1000
#define ORC_TIMER_START_DELAY 500 // ms
#define ORC_TIMER_PERIODIC_DUE_TIME 500 // ms
#define ORC_REQUEST_MAX_AGE 500 // ms
#pragma endregion
//
// FDO (bus device) context data
//
typedef struct _FDO_DEVICE_DATA
{
//
// Counter of interface references
//
LONG InterfaceReferenceCounter;
//
// Next SessionId to assign to a file handle
//
LONG NextSessionId;
} FDO_DEVICE_DATA, * PFDO_DEVICE_DATA;
#define FDO_FIRST_SESSION_ID 100
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DEVICE_DATA, FdoGetData)
//
// Context data associated with file objects created by user mode applications
//
typedef struct _FDO_FILE_DATA
{
//
// SessionId associated with file handle. Used to map file handles to emulated gamepad devices
//
LONG SessionId;
} FDO_FILE_DATA, * PFDO_FILE_DATA;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_FILE_DATA, FileObjectGetData)
EXTERN_C_START
@@ -78,10 +96,6 @@ EVT_WDF_CHILD_LIST_CREATE_DEVICE Bus_EvtDeviceListCreatePdo;
EVT_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE Bus_EvtChildListIdentificationDescriptionCompare;
EVT_WDF_DEVICE_PREPARE_HARDWARE Pdo_EvtDevicePrepareHardware;
EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL Pdo_EvtIoInternalDeviceControl;
EVT_WDF_OBJECT_CONTEXT_CLEANUP Bus_EvtDriverContextCleanup;
#pragma endregion

View File

@@ -1,62 +0,0 @@
/*
* Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver
*
* MIT License
*
* Copyright (c) 2016-2020 Nefarius Software Solutions e.U. and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <ntifs.h>
#include "busenum.h"
#include "util.tmh"
VOID ReverseByteArray(PUCHAR Array, INT Length)
{
PUCHAR s = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, sizeof(UCHAR) * Length, VIGEM_POOL_TAG);
INT c, d;
if (s == NULL)
return;
for (c = Length - 1, d = 0; c >= 0; c--, d++)
*(s + d) = *(Array + c);
for (c = 0; c < Length; c++)
*(Array + c) = *(s + c);
ExFreePoolWithTag(s, VIGEM_POOL_TAG);
}
VOID GenerateRandomMacAddress(PMAC_ADDRESS Address)
{
// Vendor "C0:13:37"
Address->Vendor0 = 0xC0;
Address->Vendor1 = 0x13;
Address->Vendor2 = 0x37;
ULONG seed = KeQueryPerformanceCounter(NULL).LowPart;
Address->Nic0 = RtlRandomEx(&seed) % 0xFF;
Address->Nic1 = RtlRandomEx(&seed) % 0xFF;
Address->Nic2 = RtlRandomEx(&seed) % 0xFF;
}