├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ ├── feature_request.md │ └── use-this-for-problems-with-the-setup.md ├── PULL_REQUEST_TEMPLATE │ └── pull_request_template.md ├── dependabot.yml └── workflows │ ├── support.yml │ └── winget.yml ├── .gitignore ├── .gitmodules ├── .nuke ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── ViGEmBus.sln ├── ViGEmBus.sln.DotSettings ├── ViGEmBus_ARM64.ddf ├── ViGEmBus_x64.ddf ├── ViGEmBus_x86.ddf ├── app ├── app.cpp ├── app.vcxproj └── app.vcxproj.filters ├── appveyor.yml ├── build.cmd ├── build.ps1 ├── build.sh ├── build ├── .editorconfig ├── Build.cs ├── Configuration.cs ├── _build.csproj └── _build.csproj.DotSettings ├── drivers ├── README.md └── devcon-LICENSE ├── patches └── dmf.diff ├── setup ├── LICENSE.rtf ├── ViGEm.ico └── ViGEmBus.aip ├── stage0.ps1 ├── sys ├── CRTCPP.hpp ├── Dmf.props ├── Driver.cpp ├── Driver.h ├── Ds4Pdo.cpp ├── Ds4Pdo.hpp ├── EmulationTargetPDO.cpp ├── EmulationTargetPDO.hpp ├── Queue.cpp ├── Queue.hpp ├── ViGEmBus.inf ├── ViGEmBus.rc ├── ViGEmBus.vcxproj ├── ViGEmBus.vcxproj.filters ├── XusbPdo.cpp ├── XusbPdo.hpp ├── busenum.cpp ├── buspdo.cpp ├── resource.h └── trace.h └── updates.txt /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior (example): 12 | 1. Start program '...' 13 | 2. Click on '....' 14 | 3. Plug in device '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **System details (please complete the following information):** 24 | - OS: [e.g. Windows 10 1803] 25 | - Feeder software: [e.g. VDX, DS4Windows, ...] 26 | - Driver Version: [e.g. 1.14.3.0] 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: 💬 Community support 4 | url: https://docs.nefarius.at/Community-Support/ 5 | about: Use these resources for support. 6 | - name: 📖 Documentation 7 | url: https://docs.nefarius.at/projects/ 8 | about: Extended documentation about the projects. 9 | - name: ❓ Other issue? 10 | url: https://discord.nefarius.at/ 11 | about: See you on Discord. 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/use-this-for-problems-with-the-setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Setup issues 3 | about: Use this if you have problems with the setup 4 | 5 | --- 6 | 7 | ## README first 8 | 9 | Before you report issues with the setup, make sure to check the following things **first**: 10 | 11 | - Are you on anything older than Windows **10**? Windows XP/Vista/7/8/8.1 **are not supported** so don't report this as an issue, it is intentional. 12 | - [Have you chosen the right setup for your CPU architecture?](https://vigem.org/research/How-to-check-architecture/) 13 | - You **can not mix these**, make sure to download and run the correct setup. 14 | - **ARM/ARM64** is **not supported**. See above link to check for yourself. 15 | 16 | ## I verified all that and am still stuck 17 | 18 | Please provide the following **log files** and attach them to the issue. Failing to do so will result in the issue being closed without any further comment. 19 | 20 | ### Setup log 21 | 22 | Run the setup from the command line (either old-school `cmd` or PowerShell) with the following additional arguments: `/L*V .\install.log` 23 | 24 | This will generate the log file `install.log` in the same directory the setup resides in. Attach it once the setup is "done" failing. 25 | 26 | Last but not least look for `C:\Windows\INF\setupapi.dev.log` and attach it as well. 27 | 28 | Optionally compress both files down if it gives you troubles uploading. 29 | 30 | Your compliance is appreciated! 😘 31 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # TBD :smiley: 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | -------------------------------------------------------------------------------- /.github/workflows/support.yml: -------------------------------------------------------------------------------- 1 | name: 'Support Requests' 2 | 3 | on: 4 | issues: 5 | types: [labeled, unlabeled, reopened] 6 | 7 | permissions: 8 | issues: write 9 | 10 | jobs: 11 | action: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: dessant/support-requests@v3 15 | with: 16 | github-token: ${{ github.token }} 17 | support-label: 'support' 18 | issue-comment: > 19 | :wave: @{issue-author}, we use the issue tracker exclusively 20 | for bug reports and feature requests. However, this issue appears 21 | to be a support request. Please use our support channels 22 | to get help with the project. 23 | close-issue: true 24 | lock-issue: true 25 | issue-lock-reason: 'off-topic' 26 | -------------------------------------------------------------------------------- /.github/workflows/winget.yml: -------------------------------------------------------------------------------- 1 | name: Publish to WinGet 2 | on: 3 | release: 4 | types: [released] 5 | 6 | jobs: 7 | publish: 8 | runs-on: windows-latest 9 | steps: 10 | - uses: vedantmgoyal2009/winget-releaser@v2 11 | with: 12 | identifier: ViGEm.ViGEmBus 13 | token: ${{ secrets.WINGET_TOKEN }} 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.vspscc 94 | *.vssscc 95 | .builds 96 | *.pidb 97 | *.svclog 98 | *.scc 99 | 100 | # Chutzpah Test files 101 | _Chutzpah* 102 | 103 | # Visual C++ cache files 104 | ipch/ 105 | *.aps 106 | *.ncb 107 | *.opendb 108 | *.opensdf 109 | *.sdf 110 | *.cachefile 111 | *.VC.db 112 | *.VC.VC.opendb 113 | 114 | # Visual Studio profiler 115 | *.psess 116 | *.vsp 117 | *.vspx 118 | *.sap 119 | 120 | # Visual Studio Trace Files 121 | *.e2e 122 | 123 | # TFS 2012 Local Workspace 124 | $tf/ 125 | 126 | # Guidance Automation Toolkit 127 | *.gpState 128 | 129 | # ReSharper is a .NET coding add-in 130 | _ReSharper*/ 131 | *.[Rr]e[Ss]harper 132 | *.DotSettings.user 133 | 134 | # TeamCity is a build add-in 135 | _TeamCity* 136 | 137 | # DotCover is a Code Coverage Tool 138 | *.dotCover 139 | 140 | # AxoCover is a Code Coverage Tool 141 | .axoCover/* 142 | !.axoCover/settings.json 143 | 144 | # Coverlet is a free, cross platform Code Coverage Tool 145 | coverage*[.json, .xml, .info] 146 | 147 | # Visual Studio code coverage results 148 | *.coverage 149 | *.coveragexml 150 | 151 | # NCrunch 152 | _NCrunch_* 153 | .*crunch*.local.xml 154 | nCrunchTemp_* 155 | 156 | # MightyMoose 157 | *.mm.* 158 | AutoTest.Net/ 159 | 160 | # Web workbench (sass) 161 | .sass-cache/ 162 | 163 | # Installshield output folder 164 | [Ee]xpress/ 165 | 166 | # DocProject is a documentation generator add-in 167 | DocProject/buildhelp/ 168 | DocProject/Help/*.HxT 169 | DocProject/Help/*.HxC 170 | DocProject/Help/*.hhc 171 | DocProject/Help/*.hhk 172 | DocProject/Help/*.hhp 173 | DocProject/Help/Html2 174 | DocProject/Help/html 175 | 176 | # Click-Once directory 177 | publish/ 178 | 179 | # Publish Web Output 180 | *.[Pp]ublish.xml 181 | *.azurePubxml 182 | # Note: Comment the next line if you want to checkin your web deploy settings, 183 | # but database connection strings (with potential passwords) will be unencrypted 184 | *.pubxml 185 | *.publishproj 186 | 187 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 188 | # checkin your Azure Web App publish settings, but sensitive information contained 189 | # in these scripts will be unencrypted 190 | PublishScripts/ 191 | 192 | # NuGet Packages 193 | *.nupkg 194 | # NuGet Symbol Packages 195 | *.snupkg 196 | # The packages folder can be ignored because of Package Restore 197 | **/[Pp]ackages/* 198 | # except build/, which is used as an MSBuild target. 199 | !**/[Pp]ackages/build/ 200 | # Uncomment if necessary however generally it will be regenerated when needed 201 | #!**/[Pp]ackages/repositories.config 202 | # NuGet v3's project.json files produces more ignorable files 203 | *.nuget.props 204 | *.nuget.targets 205 | 206 | # Microsoft Azure Build Output 207 | csx/ 208 | *.build.csdef 209 | 210 | # Microsoft Azure Emulator 211 | ecf/ 212 | rcf/ 213 | 214 | # Windows Store app package directories and files 215 | AppPackages/ 216 | BundleArtifacts/ 217 | Package.StoreAssociation.xml 218 | _pkginfo.txt 219 | *.appx 220 | *.appxbundle 221 | *.appxupload 222 | 223 | # Visual Studio cache files 224 | # files ending in .cache can be ignored 225 | *.[Cc]ache 226 | # but keep track of directories ending in .cache 227 | !?*.[Cc]ache/ 228 | 229 | # Others 230 | ClientBin/ 231 | ~$* 232 | *~ 233 | *.dbmdl 234 | *.dbproj.schemaview 235 | *.jfm 236 | *.pfx 237 | *.publishsettings 238 | orleans.codegen.cs 239 | 240 | # Including strong name files can present a security risk 241 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 242 | #*.snk 243 | 244 | # Since there are multiple workflows, uncomment next line to ignore bower_components 245 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 246 | #bower_components/ 247 | 248 | # RIA/Silverlight projects 249 | Generated_Code/ 250 | 251 | # Backup & report files from converting an old project file 252 | # to a newer Visual Studio version. Backup files are not needed, 253 | # because we have git ;-) 254 | _UpgradeReport_Files/ 255 | Backup*/ 256 | UpgradeLog*.XML 257 | UpgradeLog*.htm 258 | ServiceFabricBackup/ 259 | *.rptproj.bak 260 | 261 | # SQL Server files 262 | *.mdf 263 | *.ldf 264 | *.ndf 265 | 266 | # Business Intelligence projects 267 | *.rdl.data 268 | *.bim.layout 269 | *.bim_*.settings 270 | *.rptproj.rsuser 271 | *- [Bb]ackup.rdl 272 | *- [Bb]ackup ([0-9]).rdl 273 | *- [Bb]ackup ([0-9][0-9]).rdl 274 | 275 | # Microsoft Fakes 276 | FakesAssemblies/ 277 | 278 | # GhostDoc plugin setting file 279 | *.GhostDoc.xml 280 | 281 | # Node.js Tools for Visual Studio 282 | .ntvs_analysis.dat 283 | node_modules/ 284 | 285 | # Visual Studio 6 build log 286 | *.plg 287 | 288 | # Visual Studio 6 workspace options file 289 | *.opt 290 | 291 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 292 | *.vbw 293 | 294 | # Visual Studio LightSwitch build output 295 | **/*.HTMLClient/GeneratedArtifacts 296 | **/*.DesktopClient/GeneratedArtifacts 297 | **/*.DesktopClient/ModelManifest.xml 298 | **/*.Server/GeneratedArtifacts 299 | **/*.Server/ModelManifest.xml 300 | _Pvt_Extensions 301 | 302 | # Paket dependency manager 303 | .paket/paket.exe 304 | paket-files/ 305 | 306 | # FAKE - F# Make 307 | .fake/ 308 | 309 | # CodeRush personal settings 310 | .cr/personal 311 | 312 | # Python Tools for Visual Studio (PTVS) 313 | __pycache__/ 314 | *.pyc 315 | 316 | # Cake - Uncomment if you are using it 317 | # tools/** 318 | # !tools/packages.config 319 | 320 | # Tabs Studio 321 | *.tss 322 | 323 | # Telerik's JustMock configuration file 324 | *.jmconfig 325 | 326 | # BizTalk build output 327 | *.btp.cs 328 | *.btm.cs 329 | *.odx.cs 330 | *.xsd.cs 331 | 332 | # OpenCover UI analysis results 333 | OpenCover/ 334 | 335 | # Azure Stream Analytics local run output 336 | ASALocalRun/ 337 | 338 | # MSBuild Binary and Structured Log 339 | *.binlog 340 | 341 | # NVidia Nsight GPU debugger configuration file 342 | *.nvuser 343 | 344 | # MFractors (Xamarin productivity tool) working folder 345 | .mfractor/ 346 | 347 | # Local History for Visual Studio 348 | .localhistory/ 349 | 350 | # BeatPulse healthcheck temp database 351 | healthchecksdb 352 | 353 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 354 | MigrationBackup/ 355 | 356 | # Ionide (cross platform F# VS Code tools) working folder 357 | .ionide/ 358 | 359 | # Fody - auto-generated XML schema 360 | FodyWeavers.xsd 361 | /disk1/ViGEmBus_x64.cab 362 | /setup.inf 363 | /setup.rpt 364 | /drivers 365 | /_setup 366 | /setup/Setup Files 367 | /setup/ViGEmBus-cache 368 | /setup/ViGEmBus.back.aip 369 | /sdk 370 | *.aip 371 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "sdk"] 2 | path = sdk 3 | url = https://github.com/ViGEm/ViGEmClient.git 4 | -------------------------------------------------------------------------------- /.nuke: -------------------------------------------------------------------------------- 1 | ViGEmBus.sln -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "dotnet.defaultSolution": "disable", 3 | "cSpell.words": [ 4 | "Gamepads", 5 | "helpdesk" 6 | ] 7 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2016-2020, Nefarius Software Solutions e.U. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ViGEm Bus Driver 2 | 3 | Windows kernel-mode driver emulating well-known USB game controllers. 4 | 5 | [![Build status](https://ci.appveyor.com/api/projects/status/rv74ufluwib52dq2?svg=true)](https://ci.appveyor.com/project/nefarius/vigembus) [![GitHub All Releases](https://img.shields.io/github/downloads/ViGEm/ViGEmBus/total)](https://somsubhra.github.io/github-release-stats/?username=nefarius&repository=ViGEmBus) [![Discord](https://img.shields.io/discord/346756263763378176.svg)](https://discord.nefarius.at) [![Website](https://img.shields.io/website-up-down-green-red/https/vigem.org.svg?label=docs.nefarius.at)](https://docs.nefarius.at/) [![GitHub followers](https://img.shields.io/github/followers/nefarius.svg?style=social&label=Follow)](https://github.com/nefarius) [![Mastodon Follow](https://img.shields.io/mastodon/follow/109321120351128938?domain=https%3A%2F%2Ffosstodon.org%2F&style=social)](https://fosstodon.org/@Nefarius) 6 | 7 | --- 8 | 9 | ## 🧟 THIS PROJECT HAS BEEN RETIRED 🧟 10 | 11 | Users of this software are encouraged to [read the end-of-life statement](https://docs.nefarius.at/projects/ViGEm/End-of-Life/). So long, cheers 🖖 12 | 13 | --- 14 | 15 | ## About 16 | 17 | The `ViGEmBus` driver and `ViGEmClient` libraries represent the core of the Virtual Gamepad Emulation Framework (or `ViGEm` , for short). `ViGEm` aims for a 100% accurate [emulation]() of well-known gaming peripherals as pure software-based devices at kernel level. As it mimics "the real thing" games and other processes require no additional modification whatsoever to detect `ViGEm`-based devices (no Proxy-DLLs or API-Hooking) and simply work out of the box. While the (now obsolete) [Scarlett.Crush Productions Virtual Bus Driver]() is the spiritual father of this project, `ViGEm` has been designed and written from the ground up utilizing Microsoft's [Kernel-Mode Driver Framework](https://en.wikipedia.org/wiki/Kernel-Mode_Driver_Framework). 18 | 19 | ### Emulated devices 20 | 21 | Emulation of the following USB Gamepads is supported: 22 | 23 | - [Microsoft Xbox 360 Controller](https://en.wikipedia.org/wiki/Xbox_360_controller) 24 | - [Sony DualShock 4 Controller](https://en.wikipedia.org/wiki/DualShock#DualShock_4) 25 | 26 | ## Use cases 27 | 28 | A few examples of the most common use cases for `ViGEm` are: 29 | 30 | - You have an unsupported input device you'd like to use within games without modifying said game. 31 | - You want the freedom to use a different controller of your choice in [PS4 Remote Play](). 32 | - You encountered a game not compatible with [x360ce]() (prior to version 4.x). 33 | - You want to extend the reach of your input device (like send traffic to a different machine over a network). 34 | - You want to test/benchmark your game and need a replay mechanism for your user inputs. 35 | - You want to work around player slot assignment order issues in `XInput`. 36 | 37 | ## Supported Systems 38 | 39 | 🛑 **Windows Server** might work but is **not supported** 🛑 40 | 41 | Bug reports/support requests regarding running on a Server OS will be discarded. 42 | 43 | ### Version 1.16 and below 44 | 45 | The driver is built for Windows 7/8.1/10 (x86 and amd64). 46 | 47 | ### Version 1.17 and above 48 | 49 | The driver is built for Windows 10/11 only (x86, amd64 and ARM64). 50 | 51 | ## License 52 | 53 | The ViGEm Bus Driver is licensed under the **BSD-3-Clause**, see [LICENSE](./LICENSE.md) for more information. 54 | 55 | ## How to build 56 | 57 | ### Prerequisites 58 | 59 | - [Step 1: Install Visual Studio 2019](https://docs.microsoft.com/en-us/windows-hardware/drivers/other-wdk-downloads#step-1-install-visual-studio) 60 | - [Step 2: Install WDK for Windows 10, version 2004](https://docs.microsoft.com/en-us/windows-hardware/drivers/other-wdk-downloads#step-2-install-the-wdk) 61 | - [Step 3: Clone the Driver Module Framework (DMF)](https://github.com/microsoft/DMF) into the same parent directory. 62 | - Build the `DmfK` project with Release and Debug configurations for all architectures (x64 and Win32). 63 | 64 | You can build directly within Visual Studio. 65 | 66 | Do bear in mind that you'll need to **sign** the driver to use it without [test mode](https://docs.microsoft.com/en-us/windows-hardware/drivers/install/the-testsigning-boot-configuration-option#enable-or-disable-use-of-test-signed-code). 67 | 68 | ## Contribute 69 | 70 | ### Bugs & Features 71 | 72 | Found a bug and want it fixed? Open a detailed issue on the [GitHub issue tracker](../../issues)! 73 | 74 | Have an idea for a new feature? Let's have a chat about your request on [Discord](https://discord.nefarius.at). 75 | 76 | ### Questions & Support 77 | 78 | Please respect that the GitHub issue tracker isn't a helpdesk. We offer a [range of support resources](https://docs.nefarius.at/Community-Support/) you're welcome to check out! 79 | 80 | ## Installation 81 | 82 | Pre-built production-signed binaries **for Windows 10/11** are provided by `Nefarius Software Solutions e.U.` [as an all-in-one setup](../../releases/latest). 83 | 84 | ## Sponsors 85 | 86 | Sponsors listed here have helped the project flourish by either financial support or by gifting licenses: 87 | 88 | - [3dRudder](https://www.3drudder.com/) 89 | - [Parsec](https://parsec.app/) 90 | - [JetBrains](https://www.jetbrains.com/resharper/) 91 | - [Advanced Installer](https://www.advancedinstaller.com/) 92 | - [ICAROS](https://www.icaros.com/) 93 | 94 | ## Known users of ViGEm 95 | 96 | A brief listing of projects/companies/vendors known to build upon the powers of ViGEm. 97 | 98 | This list is non-exhaustive, if you'd like to see your project included, contact us! 99 | 100 | - [3dRudder](https://www.3drudder.com/) 101 | - [Parsec](https://parsec.app/) 102 | - [GloSC](https://github.com/Alia5/GloSC) 103 | - [UCR](https://github.com/Snoothy/UCR) 104 | - [InputMapper](https://inputmapper.com/) 105 | - [Oculus VR, LLC.](https://www.oculus.com/) 106 | - [WiimoteHook](https://forum.cemu.info/showthread.php/140-WiimoteHook-Nintendo-Wii-Remote-with-Motion-Rumble-and-Nunchuk-support) 107 | - [XJoy](https://github.com/sam0x17/XJoy) 108 | - [HP](https://www8.hp.com/us/en/gaming/omen.html) 109 | - [DS4Windows](https://ryochan7.github.io/ds4windows-site/) 110 | - [XOutput](https://github.com/csutorasa/XOutput) 111 | - [RdpGamepad](https://github.com/microsoft/RdpGamepad) 112 | - [Touchmote](https://github.com/Ryochan7/Touchmote/tree/ryochan7) 113 | - [Mi-ViGEm](https://github.com/grayver/mi-vigem) 114 | - [BetterJoy](https://github.com/Davidobot/BetterJoy) 115 | - [Regame](https://github.com/ksyun-kenc/liuguang) 116 | - [NetInput](https://github.com/usertoroot/NetInput) 117 | - [NetJoy](https://github.com/Qcent/NetJoy/) 118 | -------------------------------------------------------------------------------- /ViGEmBus.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29613.14 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ViGEmBus", "sys\ViGEmBus.vcxproj", "{040101B0-EE5C-4EF1-99EE-9F81C795C001}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SDK", "SDK", "{733360FF-9D9F-4C67-86D1-B20881C17000}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{0182EE0E-A2FB-4525-9FEA-1910B12B21C8}" 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ViGEmClient", "sdk\src\ViGEmClient.vcxproj", "{7DB06674-1F4F-464B-8E1C-172E9587F9DC}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build\_build.csproj", "{C2BA387E-D491-4FB7-8BEE-99D77E8949E7}" 15 | EndProject 16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "App", "App", "{14E3C232-1A02-49B0-B9CE-4CA2023B7C3D}" 17 | EndProject 18 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "app", "app\app.vcxproj", "{74584E9B-2D99-439B-AF9A-27FD10154B33}" 19 | EndProject 20 | Global 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug_DLL|ARM64 = Debug_DLL|ARM64 23 | Debug_DLL|x64 = Debug_DLL|x64 24 | Debug_DLL|x86 = Debug_DLL|x86 25 | Debug_LIB|ARM64 = Debug_LIB|ARM64 26 | Debug_LIB|x64 = Debug_LIB|x64 27 | Debug_LIB|x86 = Debug_LIB|x86 28 | Debug|ARM64 = Debug|ARM64 29 | Debug|x64 = Debug|x64 30 | Debug|x86 = Debug|x86 31 | Release_DLL|ARM64 = Release_DLL|ARM64 32 | Release_DLL|x64 = Release_DLL|x64 33 | Release_DLL|x86 = Release_DLL|x86 34 | Release_LIB|ARM64 = Release_LIB|ARM64 35 | Release_LIB|x64 = Release_LIB|x64 36 | Release_LIB|x86 = Release_LIB|x86 37 | Release|ARM64 = Release|ARM64 38 | Release|x64 = Release|x64 39 | Release|x86 = Release|x86 40 | EndGlobalSection 41 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 42 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_DLL|ARM64.ActiveCfg = Debug|ARM64 43 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_DLL|ARM64.Build.0 = Debug|ARM64 44 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_DLL|ARM64.Deploy.0 = Debug|ARM64 45 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_DLL|x64.ActiveCfg = Debug|x64 46 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_DLL|x64.Build.0 = Debug|x64 47 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_DLL|x64.Deploy.0 = Debug|x64 48 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_DLL|x86.ActiveCfg = Debug|Win32 49 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_DLL|x86.Build.0 = Debug|Win32 50 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_DLL|x86.Deploy.0 = Debug|Win32 51 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_LIB|ARM64.ActiveCfg = Debug|ARM64 52 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_LIB|ARM64.Build.0 = Debug|ARM64 53 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_LIB|ARM64.Deploy.0 = Debug|ARM64 54 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_LIB|x64.ActiveCfg = Debug|x64 55 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_LIB|x64.Build.0 = Debug|x64 56 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_LIB|x64.Deploy.0 = Debug|x64 57 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_LIB|x86.ActiveCfg = Debug|Win32 58 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_LIB|x86.Build.0 = Debug|Win32 59 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug_LIB|x86.Deploy.0 = Debug|Win32 60 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug|ARM64.ActiveCfg = Debug|ARM64 61 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug|ARM64.Build.0 = Debug|ARM64 62 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug|ARM64.Deploy.0 = Debug|ARM64 63 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug|x64.ActiveCfg = Debug|x64 64 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug|x64.Build.0 = Debug|x64 65 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug|x64.Deploy.0 = Debug|x64 66 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug|x86.ActiveCfg = Debug|Win32 67 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug|x86.Build.0 = Debug|Win32 68 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Debug|x86.Deploy.0 = Debug|Win32 69 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_DLL|ARM64.ActiveCfg = Release|ARM64 70 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_DLL|ARM64.Build.0 = Release|ARM64 71 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_DLL|ARM64.Deploy.0 = Release|ARM64 72 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_DLL|x64.ActiveCfg = Release|x64 73 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_DLL|x64.Build.0 = Release|x64 74 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_DLL|x64.Deploy.0 = Release|x64 75 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_DLL|x86.ActiveCfg = Release|Win32 76 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_DLL|x86.Build.0 = Release|Win32 77 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_DLL|x86.Deploy.0 = Release|Win32 78 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_LIB|ARM64.ActiveCfg = Release|ARM64 79 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_LIB|ARM64.Build.0 = Release|ARM64 80 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_LIB|ARM64.Deploy.0 = Release|ARM64 81 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_LIB|x64.ActiveCfg = Release|x64 82 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_LIB|x64.Build.0 = Release|x64 83 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_LIB|x64.Deploy.0 = Release|x64 84 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_LIB|x86.ActiveCfg = Release|Win32 85 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_LIB|x86.Build.0 = Release|Win32 86 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release_LIB|x86.Deploy.0 = Release|Win32 87 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release|ARM64.ActiveCfg = Release|ARM64 88 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release|ARM64.Build.0 = Release|ARM64 89 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release|ARM64.Deploy.0 = Release|ARM64 90 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release|x64.ActiveCfg = Release|x64 91 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release|x64.Build.0 = Release|x64 92 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release|x64.Deploy.0 = Release|x64 93 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release|x86.ActiveCfg = Release|Win32 94 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release|x86.Build.0 = Release|Win32 95 | {040101B0-EE5C-4EF1-99EE-9F81C795C001}.Release|x86.Deploy.0 = Release|Win32 96 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_DLL|ARM64.ActiveCfg = Debug_DLL|ARM64 97 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_DLL|ARM64.Build.0 = Debug_DLL|ARM64 98 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_DLL|x64.ActiveCfg = Debug_DLL|x64 99 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_DLL|x64.Build.0 = Debug_DLL|x64 100 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_DLL|x86.ActiveCfg = Debug_DLL|Win32 101 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_DLL|x86.Build.0 = Debug_DLL|Win32 102 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_LIB|ARM64.ActiveCfg = Debug_LIB|Win32 103 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_LIB|ARM64.Build.0 = Debug_LIB|Win32 104 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_LIB|x64.ActiveCfg = Debug_LIB|x64 105 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_LIB|x64.Build.0 = Debug_LIB|x64 106 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_LIB|x86.ActiveCfg = Debug_LIB|Win32 107 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_LIB|x86.Build.0 = Debug_LIB|Win32 108 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug|ARM64.ActiveCfg = Debug_LIB|ARM64 109 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug|ARM64.Build.0 = Debug_LIB|ARM64 110 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug|x64.ActiveCfg = Debug_DLL|x64 111 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug|x64.Build.0 = Debug_DLL|x64 112 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug|x86.ActiveCfg = Debug_LIB|Win32 113 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug|x86.Build.0 = Debug_LIB|Win32 114 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_DLL|ARM64.ActiveCfg = Release_DLL|Win32 115 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_DLL|ARM64.Build.0 = Release_DLL|Win32 116 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_DLL|x64.ActiveCfg = Release_DLL|x64 117 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_DLL|x64.Build.0 = Release_DLL|x64 118 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_DLL|x86.ActiveCfg = Release_DLL|Win32 119 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_DLL|x86.Build.0 = Release_DLL|Win32 120 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_LIB|ARM64.ActiveCfg = Release_LIB|Win32 121 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_LIB|ARM64.Build.0 = Release_LIB|Win32 122 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_LIB|x64.ActiveCfg = Release_LIB|x64 123 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_LIB|x64.Build.0 = Release_LIB|x64 124 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_LIB|x86.ActiveCfg = Release_LIB|Win32 125 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_LIB|x86.Build.0 = Release_LIB|Win32 126 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release|ARM64.ActiveCfg = Release_DLL|Win32 127 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release|ARM64.Build.0 = Release_DLL|Win32 128 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release|x64.ActiveCfg = Release_LIB|x64 129 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release|x64.Build.0 = Release_LIB|x64 130 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release|x86.ActiveCfg = Release_DLL|Win32 131 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release|x86.Build.0 = Release_DLL|Win32 132 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Debug_DLL|ARM64.ActiveCfg = Debug|ARM64 133 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Debug_DLL|x64.ActiveCfg = Debug|Any CPU 134 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Debug_DLL|x86.ActiveCfg = Debug|Any CPU 135 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Debug_LIB|ARM64.ActiveCfg = Debug|ARM64 136 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Debug_LIB|x64.ActiveCfg = Debug|Any CPU 137 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Debug_LIB|x86.ActiveCfg = Debug|Any CPU 138 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Debug|ARM64.ActiveCfg = Debug|ARM64 139 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Debug|x64.ActiveCfg = Debug|Any CPU 140 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Debug|x86.ActiveCfg = Debug|Any CPU 141 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Release_DLL|ARM64.ActiveCfg = Release|ARM64 142 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Release_DLL|x64.ActiveCfg = Release|Any CPU 143 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Release_DLL|x86.ActiveCfg = Release|Any CPU 144 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Release_LIB|ARM64.ActiveCfg = Release|ARM64 145 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Release_LIB|x64.ActiveCfg = Release|Any CPU 146 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Release_LIB|x86.ActiveCfg = Release|Any CPU 147 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Release|ARM64.ActiveCfg = Release|ARM64 148 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Release|x64.ActiveCfg = Release|Any CPU 149 | {C2BA387E-D491-4FB7-8BEE-99D77E8949E7}.Release|x86.ActiveCfg = Release|Any CPU 150 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug_DLL|ARM64.ActiveCfg = Debug|Win32 151 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug_DLL|ARM64.Build.0 = Debug|Win32 152 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug_DLL|x64.ActiveCfg = Debug|x64 153 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug_DLL|x64.Build.0 = Debug|x64 154 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug_DLL|x86.ActiveCfg = Debug|Win32 155 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug_DLL|x86.Build.0 = Debug|Win32 156 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug_LIB|ARM64.ActiveCfg = Debug|Win32 157 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug_LIB|ARM64.Build.0 = Debug|Win32 158 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug_LIB|x64.ActiveCfg = Debug|x64 159 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug_LIB|x64.Build.0 = Debug|x64 160 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug_LIB|x86.ActiveCfg = Debug|Win32 161 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug_LIB|x86.Build.0 = Debug|Win32 162 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug|ARM64.ActiveCfg = Debug|Win32 163 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug|x64.ActiveCfg = Debug|x64 164 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug|x64.Build.0 = Debug|x64 165 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug|x86.ActiveCfg = Debug|Win32 166 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Debug|x86.Build.0 = Debug|Win32 167 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Release_DLL|ARM64.ActiveCfg = Debug|Win32 168 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Release_DLL|x64.ActiveCfg = Release|x64 169 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Release_DLL|x86.ActiveCfg = Release|Win32 170 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Release_LIB|ARM64.ActiveCfg = Debug|Win32 171 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Release_LIB|x64.ActiveCfg = Release|x64 172 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Release_LIB|x86.ActiveCfg = Release|Win32 173 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Release|ARM64.ActiveCfg = Release|Win32 174 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Release|x64.ActiveCfg = Release|x64 175 | {74584E9B-2D99-439B-AF9A-27FD10154B33}.Release|x86.ActiveCfg = Release|Win32 176 | EndGlobalSection 177 | GlobalSection(SolutionProperties) = preSolution 178 | HideSolutionNode = FALSE 179 | EndGlobalSection 180 | GlobalSection(NestedProjects) = preSolution 181 | {040101B0-EE5C-4EF1-99EE-9F81C795C001} = {0182EE0E-A2FB-4525-9FEA-1910B12B21C8} 182 | {7DB06674-1F4F-464B-8E1C-172E9587F9DC} = {733360FF-9D9F-4C67-86D1-B20881C17000} 183 | {74584E9B-2D99-439B-AF9A-27FD10154B33} = {14E3C232-1A02-49B0-B9CE-4CA2023B7C3D} 184 | EndGlobalSection 185 | GlobalSection(ExtensibilityGlobals) = postSolution 186 | SolutionGuid = {D5CD61FD-80BB-4E0E-840C-BAF66ABB1CF0} 187 | EndGlobalSection 188 | EndGlobal 189 | -------------------------------------------------------------------------------- /ViGEmBus.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True 4 | True 5 | True 6 | True 7 | True 8 | True 9 | True 10 | True 11 | True 12 | True 13 | True 14 | True 15 | True 16 | True 17 | True -------------------------------------------------------------------------------- /ViGEmBus_ARM64.ddf: -------------------------------------------------------------------------------- 1 | ; ViGEmBus cab file for attestation submission 2 | .OPTION EXPLICIT 3 | .Set CabinetFileCountThreshold=0 4 | .Set FolderFileCountThreshold=0 5 | .Set FolderSizeThreshold=0 6 | .Set MaxCabinetSize=0 7 | .Set MaxDiskFileCount=0 8 | .Set MaxDiskSize=0 9 | .Set CompressionType=MSZIP 10 | .Set Cabinet=on 11 | .Set Compress=on 12 | ; ARM64 13 | .Set CabinetNameTemplate=ViGEmBus_ARM64.cab 14 | .Set DestinationDir=ViGEmBus_ARM64 15 | LICENSE 16 | bin\ARM64\ViGEmBus.pdb 17 | bin\ARM64\ViGEmBus\ViGEmBus.inf 18 | bin\ARM64\ViGEmBus\ViGEmBus.sys -------------------------------------------------------------------------------- /ViGEmBus_x64.ddf: -------------------------------------------------------------------------------- 1 | ; ViGEmBus cab file for attestation submission 2 | .OPTION EXPLICIT 3 | .Set CabinetFileCountThreshold=0 4 | .Set FolderFileCountThreshold=0 5 | .Set FolderSizeThreshold=0 6 | .Set MaxCabinetSize=0 7 | .Set MaxDiskFileCount=0 8 | .Set MaxDiskSize=0 9 | .Set CompressionType=MSZIP 10 | .Set Cabinet=on 11 | .Set Compress=on 12 | ; x64 13 | .Set CabinetNameTemplate=ViGEmBus_x64.cab 14 | .Set DestinationDir=ViGEmBus_x64 15 | LICENSE 16 | bin\x64\ViGEmBus.pdb 17 | bin\x64\ViGEmBus\ViGEmBus.inf 18 | bin\x64\ViGEmBus\ViGEmBus.sys -------------------------------------------------------------------------------- /ViGEmBus_x86.ddf: -------------------------------------------------------------------------------- 1 | ; ViGEmBus cab file for attestation submission 2 | .OPTION EXPLICIT 3 | .Set CabinetFileCountThreshold=0 4 | .Set FolderFileCountThreshold=0 5 | .Set FolderSizeThreshold=0 6 | .Set MaxCabinetSize=0 7 | .Set MaxDiskFileCount=0 8 | .Set MaxDiskSize=0 9 | .Set CompressionType=MSZIP 10 | .Set Cabinet=on 11 | .Set Compress=on 12 | ; x86 13 | .Set CabinetNameTemplate=ViGEmBus_x86.cab 14 | .Set DestinationDir=ViGEmBus_x86 15 | LICENSE 16 | bin\x86\ViGEmBus.pdb 17 | bin\x86\ViGEmBus\ViGEmBus.inf 18 | bin\x86\ViGEmBus\ViGEmBus.sys -------------------------------------------------------------------------------- /app/app.cpp: -------------------------------------------------------------------------------- 1 | // app.cpp : This file contains the 'main' function. Program execution begins and ends there. 2 | // 3 | 4 | #define WIN32_LEAN_AND_MEAN 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #pragma comment(lib, "setupapi.lib") 15 | 16 | static std::string hexStr(unsigned char* data, int len) 17 | { 18 | std::stringstream ss; 19 | ss << std::hex; 20 | for (int i = 0; i < len; ++i) 21 | ss << std::setw(2) << std::setfill('0') << static_cast(data[i]) << ' '; 22 | return ss.str(); 23 | } 24 | 25 | int main() 26 | { 27 | const auto client = vigem_alloc(); 28 | 29 | auto error = vigem_connect(client); 30 | 31 | const auto ds4 = vigem_target_ds4_alloc(); 32 | 33 | error = vigem_target_add(client, ds4); 34 | 35 | DS4_OUTPUT_BUFFER out; 36 | 37 | while (TRUE) 38 | { 39 | //error = vigem_target_ds4_await_output_report(client, ds4, &out); 40 | error = vigem_target_ds4_await_output_report_timeout(client, ds4, 100, &out); 41 | 42 | if (VIGEM_SUCCESS(error)) 43 | { 44 | std::cout << hexStr(out.Buffer, sizeof(DS4_OUTPUT_BUFFER)) << std::endl; 45 | } 46 | else if (error != VIGEM_ERROR_TIMED_OUT) 47 | { 48 | auto win32 = GetLastError(); 49 | 50 | auto t = 0; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/app.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {74584e9b-2d99-439b-af9a-27fd10154b33} 25 | app 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | true 91 | $(SolutionDir)sdk\include 92 | MultiThreadedDebug 93 | 94 | 95 | Console 96 | true 97 | 98 | 99 | 100 | 101 | Level3 102 | true 103 | true 104 | true 105 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | $(SolutionDir)sdk\include 108 | MultiThreaded 109 | 110 | 111 | Console 112 | true 113 | true 114 | true 115 | 116 | 117 | 118 | 119 | Level3 120 | true 121 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 122 | true 123 | $(SolutionDir)sdk\include 124 | MultiThreadedDebug 125 | 126 | 127 | Console 128 | true 129 | 130 | 131 | 132 | 133 | Level3 134 | true 135 | true 136 | true 137 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 138 | true 139 | $(SolutionDir)sdk\include 140 | MultiThreaded 141 | 142 | 143 | Console 144 | true 145 | true 146 | true 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | {7db06674-1f4f-464b-8e1c-172e9587f9dc} 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /app/app.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.21.{build}.0 2 | image: Visual Studio 2019 3 | skip_commits: 4 | files: 5 | - '**/*.md' 6 | - '**/*.aip' 7 | cache: 8 | - C:\projects\DMF 9 | - C:\projects\ViGEmBus\vpatch.exe 10 | platform: 11 | - x86 12 | - x64 13 | - ARM64 14 | configuration: 15 | - Release 16 | environment: 17 | DmfRootPath: C:\projects\DMF 18 | install: 19 | - cmd: git submodule -q update --init 20 | - cmd: git clone -q https://github.com/microsoft/DMF.git C:\projects\DMF 2> nul || set ERRORLEVEL=0 21 | - cmd: | 22 | cd "C:\projects\DMF" 23 | git pull > NUL 24 | git apply --reject "%APPVEYOR_BUILD_FOLDER%\patches\dmf.diff 25 | cd %appveyor_build_folder% 26 | before_build: 27 | - ps: Invoke-WebRequest "https://github.com/nefarius/vpatch/releases/latest/download/vpatch.exe" -OutFile vpatch.exe 28 | - cmd: vpatch.exe --stamp-version "%APPVEYOR_BUILD_VERSION%" --target-file ".\sys\ViGEmBus.vcxproj" --vcxproj.inf-time-stamp 29 | - cmd: vpatch.exe --stamp-version "%APPVEYOR_BUILD_VERSION%" --target-file ".\sys\ViGEmBus.rc" --resource.file-version --resource.product-version 30 | build_script: 31 | - cmd: .\build.cmd 32 | after_build: 33 | - cmd: makecab.exe /f ViGEmBus_%PLATFORM%.ddf 34 | artifacts: 35 | - path: 'bin**\$(APPVEYOR_PROJECT_NAME)\*.inf' 36 | - path: 'bin**\$(APPVEYOR_PROJECT_NAME)\*.sys' 37 | - path: 'bin**\*.pdb' 38 | - path: 'disk1\*.cab' 39 | deploy: 40 | - provider: Environment 41 | name: BUILDBOT 42 | on: 43 | appveyor_repo_tag: true -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | :; set -eo pipefail 2 | :; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) 3 | :; ${SCRIPT_DIR}/build.sh "$@" 4 | :; exit $? 5 | 6 | @ECHO OFF 7 | powershell -ExecutionPolicy ByPass -NoProfile %0\..\build.ps1 %* 8 | -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | Param( 3 | [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] 4 | [string[]]$BuildArguments 5 | ) 6 | 7 | Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)" 8 | 9 | Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { Write-Error $_ -ErrorAction Continue; exit 1 } 10 | $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent 11 | 12 | ########################################################################### 13 | # CONFIGURATION 14 | ########################################################################### 15 | 16 | $BuildProjectFile = "$PSScriptRoot\build\_build.csproj" 17 | $TempDirectory = "$PSScriptRoot\\.tmp" 18 | 19 | $DotNetGlobalFile = "$PSScriptRoot\\global.json" 20 | $DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1" 21 | $DotNetChannel = "Current" 22 | 23 | $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1 24 | $env:DOTNET_CLI_TELEMETRY_OPTOUT = 1 25 | $env:DOTNET_MULTILEVEL_LOOKUP = 0 26 | 27 | ########################################################################### 28 | # EXECUTION 29 | ########################################################################### 30 | 31 | function ExecSafe([scriptblock] $cmd) { 32 | & $cmd 33 | if ($LASTEXITCODE) { exit $LASTEXITCODE } 34 | } 35 | 36 | # If dotnet CLI is installed globally and it matches requested version, use for execution 37 | if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and ` 38 | $(dotnet --version) -and $LASTEXITCODE -eq 0) { 39 | $env:DOTNET_EXE = (Get-Command "dotnet").Path 40 | } 41 | else { 42 | # Download install script 43 | $DotNetInstallFile = "$TempDirectory\dotnet-install.ps1" 44 | New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null 45 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 46 | (New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile) 47 | 48 | # If global.json exists, load expected version 49 | if (Test-Path $DotNetGlobalFile) { 50 | $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json) 51 | if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) { 52 | $DotNetVersion = $DotNetGlobal.sdk.version 53 | } 54 | } 55 | 56 | # Install by channel or version 57 | $DotNetDirectory = "$TempDirectory\dotnet-win" 58 | if (!(Test-Path variable:DotNetVersion)) { 59 | ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath } 60 | } else { 61 | ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath } 62 | } 63 | $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe" 64 | } 65 | 66 | Write-Output "Microsoft (R) .NET Core SDK version $(& $env:DOTNET_EXE --version)" 67 | 68 | ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet } 69 | ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments } 70 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | bash --version 2>&1 | head -n 1 4 | 5 | set -eo pipefail 6 | SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) 7 | 8 | ########################################################################### 9 | # CONFIGURATION 10 | ########################################################################### 11 | 12 | BUILD_PROJECT_FILE="$SCRIPT_DIR/build/_build.csproj" 13 | TEMP_DIRECTORY="$SCRIPT_DIR//.tmp" 14 | 15 | DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json" 16 | DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh" 17 | DOTNET_CHANNEL="Current" 18 | 19 | export DOTNET_CLI_TELEMETRY_OPTOUT=1 20 | export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 21 | export DOTNET_MULTILEVEL_LOOKUP=0 22 | 23 | ########################################################################### 24 | # EXECUTION 25 | ########################################################################### 26 | 27 | function FirstJsonValue { 28 | perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}" 29 | } 30 | 31 | # If dotnet CLI is installed globally and it matches requested version, use for execution 32 | if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then 33 | export DOTNET_EXE="$(command -v dotnet)" 34 | else 35 | # Download install script 36 | DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh" 37 | mkdir -p "$TEMP_DIRECTORY" 38 | curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL" 39 | chmod +x "$DOTNET_INSTALL_FILE" 40 | 41 | # If global.json exists, load expected version 42 | if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then 43 | DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")") 44 | if [[ "$DOTNET_VERSION" == "" ]]; then 45 | unset DOTNET_VERSION 46 | fi 47 | fi 48 | 49 | # Install by channel or version 50 | DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix" 51 | if [[ -z ${DOTNET_VERSION+x} ]]; then 52 | "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path 53 | else 54 | "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path 55 | fi 56 | export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet" 57 | fi 58 | 59 | echo "Microsoft (R) .NET Core SDK version $("$DOTNET_EXE" --version)" 60 | 61 | "$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet 62 | "$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@" 63 | -------------------------------------------------------------------------------- /build/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | dotnet_style_qualification_for_field = false:warning 3 | dotnet_style_qualification_for_property = false:warning 4 | dotnet_style_qualification_for_method = false:warning 5 | dotnet_style_qualification_for_event = false:warning 6 | dotnet_style_require_accessibility_modifiers = never:warning 7 | 8 | csharp_style_expression_bodied_methods = true:silent 9 | csharp_style_expression_bodied_properties = true:warning 10 | csharp_style_expression_bodied_indexers = true:warning 11 | csharp_style_expression_bodied_accessors = true:warning 12 | -------------------------------------------------------------------------------- /build/Build.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Nuke.Common; 4 | using Nuke.Common.CI; 5 | using Nuke.Common.CI.AppVeyor; 6 | using Nuke.Common.Execution; 7 | using Nuke.Common.Git; 8 | using Nuke.Common.IO; 9 | using Nuke.Common.ProjectModel; 10 | using Nuke.Common.Tooling; 11 | using Nuke.Common.Tools.MSBuild; 12 | using Nuke.Common.Utilities.Collections; 13 | using static Nuke.Common.EnvironmentInfo; 14 | using static Nuke.Common.IO.FileSystemTasks; 15 | using static Nuke.Common.IO.PathConstruction; 16 | using static Nuke.Common.Tools.MSBuild.MSBuildTasks; 17 | 18 | [CheckBuildProjectConfigurations] 19 | class Build : NukeBuild 20 | { 21 | /// Support plugins are available for: 22 | /// - JetBrains ReSharper https://nuke.build/resharper 23 | /// - JetBrains Rider https://nuke.build/rider 24 | /// - Microsoft VisualStudio https://nuke.build/visualstudio 25 | /// - Microsoft VSCode https://nuke.build/vscode 26 | 27 | public static int Main () => Execute(x => x.Compile); 28 | 29 | [Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")] 30 | readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release; 31 | 32 | [Solution] readonly Solution Solution; 33 | [GitRepository] readonly GitRepository GitRepository; 34 | 35 | AbsolutePath DmfSolution => RootDirectory / "../DMF/Dmf.sln"; 36 | 37 | Target Restore => _ => _ 38 | .Executes(() => 39 | { 40 | MSBuild(s => s 41 | .SetTargetPath(Solution) 42 | .SetTargets("Restore")); 43 | }); 44 | 45 | Target BuildDmf => _ => _ 46 | .Executes(() => 47 | { 48 | if (IsLocalBuild) 49 | return; 50 | 51 | Console.WriteLine($"DMF solution path: {DmfSolution}"); 52 | 53 | var platform = MSBuildTargetPlatform.x64; 54 | 55 | if (AppVeyor.Instance.Platform is "x86") 56 | platform = MSBuildTargetPlatform.Win32; 57 | 58 | if (AppVeyor.Instance.Platform is "ARM64") 59 | platform = (MSBuildTargetPlatform) "ARM64"; 60 | 61 | MSBuild(s => s 62 | .SetTargetPath(DmfSolution) 63 | .SetTargets("Build") 64 | .SetConfiguration(Configuration) 65 | .SetTargetPlatform(platform) 66 | .SetMaxCpuCount(Environment.ProcessorCount) 67 | .SetNodeReuse(IsLocalBuild)); 68 | }); 69 | 70 | Target Compile => _ => _ 71 | .DependsOn(BuildDmf) 72 | .Executes(() => 73 | { 74 | MSBuild(s => s 75 | .SetTargetPath(Solution) 76 | .SetTargets("Rebuild") 77 | .SetConfiguration(Configuration) 78 | .SetMaxCpuCount(Environment.ProcessorCount) 79 | .SetNodeReuse(IsLocalBuild)); 80 | }); 81 | 82 | } 83 | -------------------------------------------------------------------------------- /build/Configuration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | using Nuke.Common.Tooling; 5 | 6 | [TypeConverter(typeof(TypeConverter))] 7 | public class Configuration : Enumeration 8 | { 9 | public static Configuration Debug = new Configuration { Value = nameof(Debug) }; 10 | public static Configuration Release = new Configuration { Value = nameof(Release) }; 11 | 12 | public static implicit operator string(Configuration configuration) 13 | { 14 | return configuration.Value; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /build/_build.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | 7 | CS0649;CS0169 8 | .. 9 | .. 10 | AnyCPU;ARM64 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /build/_build.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | DO_NOT_SHOW 3 | DO_NOT_SHOW 4 | DO_NOT_SHOW 5 | DO_NOT_SHOW 6 | Implicit 7 | Implicit 8 | ExpressionBody 9 | 0 10 | NEXT_LINE 11 | True 12 | False 13 | 120 14 | IF_OWNER_IS_SINGLE_LINE 15 | WRAP_IF_LONG 16 | False 17 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 18 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 19 | True 20 | True 21 | True 22 | True 23 | True 24 | True 25 | True 26 | True 27 | True 28 | -------------------------------------------------------------------------------- /drivers/README.md: -------------------------------------------------------------------------------- 1 | # Drivers directory 2 | 3 | Place the attestation signed driver files into the corresponding sub-directories and locally build the setup and sign it afterwards for production release. 4 | -------------------------------------------------------------------------------- /drivers/devcon-LICENSE: -------------------------------------------------------------------------------- 1 | The Microsoft Public License (MS-PL) 2 | Copyright (c) 2015 Microsoft 3 | 4 | This license governs use of the accompanying software. If you use the software, you 5 | accept this license. If you do not accept the license, do not use the software. 6 | 7 | 1. Definitions 8 | The terms "reproduce," "reproduction," "derivative works," and "distribution" have the 9 | same meaning here as under U.S. copyright law. 10 | A "contribution" is the original software, or any additions or changes to the software. 11 | A "contributor" is any person that distributes its contribution under this license. 12 | "Licensed patents" are a contributor's patent claims that read directly on its contribution. 13 | 14 | 2. Grant of Rights 15 | (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. 16 | (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. 17 | 18 | 3. Conditions and Limitations 19 | (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. 20 | (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. 21 | (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. 22 | (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. 23 | (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. 24 | -------------------------------------------------------------------------------- /setup/LICENSE.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}} 2 | {\*\generator Riched20 10.0.18362}\viewkind4\uc1 3 | \pard\sl240\slmult1\f0\fs16\lang9 BSD 3-Clause License\par 4 | \par 5 | Copyright (c) 2016-2020, Nefarius Software Solutions e.U.\par 6 | All rights reserved.\par 7 | \par 8 | Redistribution and use in source and binary forms, with or without\par 9 | modification, are permitted provided that the following conditions are met:\par 10 | \par 11 | 1. Redistributions of source code must retain the above copyright notice, this\par 12 | list of conditions and the following disclaimer.\par 13 | \par 14 | 2. Redistributions in binary form must reproduce the above copyright notice,\par 15 | this list of conditions and the following disclaimer in the documentation\par 16 | and/or other materials provided with the distribution.\par 17 | \par 18 | 3. Neither the name of the copyright holder nor the names of its\par 19 | contributors may be used to endorse or promote products derived from\par 20 | this software without specific prior written permission.\par 21 | \par 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\par 23 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\par 24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\par 25 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\par 26 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\par 27 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\par 28 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\par 29 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\par 30 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\par 31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\par 32 | } 33 | -------------------------------------------------------------------------------- /setup/ViGEm.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nefarius/ViGEmBus/d986e1d93708ec9b11049542fa6027272cce716c/setup/ViGEm.ico -------------------------------------------------------------------------------- /stage0.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [Parameter(Mandatory=$true)] 3 | [string]$BuildVersion, 4 | [Parameter(Mandatory=$true)] 5 | [string]$Token, 6 | [Parameter(Mandatory=$false)] 7 | [string]$Path = "./artifacts", 8 | [Parameter(Mandatory=$false)] 9 | [Switch]$NoSigning 10 | ) #end param 11 | 12 | $signTool = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\signtool.exe" 13 | $timestampUrl = "http://timestamp.digicert.com" 14 | $certName = "Nefarius Software Solutions e.U." 15 | 16 | function Get-AppVeyorArtifacts 17 | { 18 | [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')] 19 | param( 20 | #The name of the account you wish to download artifacts from 21 | [parameter(Mandatory = $true)] 22 | [string]$Account, 23 | #The name of the project you wish to download artifacts from 24 | [parameter(Mandatory = $true)] 25 | [string]$Project, 26 | #Where to save the downloaded artifacts. Defaults to current directory. 27 | [alias("DownloadDirectory")][string]$Path = '.', 28 | [string]$Token, 29 | #Filter to a specific branch or project directory. You can specify Branch as either branch name ("master") or build version ("0.1.29") 30 | [string]$Branch, 31 | #If you have multiple build jobs, specify which job you wish to retrieve the artifacts from 32 | [string]$JobName, 33 | #Download all files into a single directory, do not preserve any hierarchy that might exist in the artifacts 34 | [switch]$Flat, 35 | [string]$Proxy, 36 | [switch]$ProxyUseDefaultCredentials, 37 | #URL of Appveyor API. You normally shouldn't need to change this. 38 | $apiUrl = 'https://ci.appveyor.com/api' 39 | ) 40 | 41 | $headers = @{ 42 | 'Content-type' = 'application/json' 43 | } 44 | 45 | if ($Token) {$headers.'Authorization' = "Bearer $token"} 46 | 47 | # Prepare proxy args to splat to Invoke-RestMethod 48 | $proxyArgs = @{} 49 | if (-not [string]::IsNullOrEmpty($proxy)) { 50 | $proxyArgs.Add('Proxy', $proxy) 51 | } 52 | if ($proxyUseDefaultCredentials.IsPresent) { 53 | $proxyArgs.Add('ProxyUseDefaultCredentials', $proxyUseDefaultCredentials) 54 | } 55 | 56 | $errorActionPreference = 'Stop' 57 | $projectURI = "$apiUrl/projects/$account/$project" 58 | if ($Branch) {$projectURI = $projectURI + "/build/$Branch"} 59 | 60 | $projectObject = Invoke-RestMethod -Method Get -Uri $projectURI ` 61 | -Headers $headers @proxyArgs 62 | 63 | if (-not $projectObject.build.jobs) {throw "No jobs found for this project or the project and/or account name was incorrectly specified"} 64 | 65 | if (($projectObject.build.jobs.count -gt 1) -and -not $jobName) { 66 | throw "Multiple Jobs found for the latest build. Please specify the -JobName paramter to select which job you want the artifacts for" 67 | } 68 | 69 | if ($JobName) { 70 | $jobid = ($projectObject.build.jobs | Where-Object name -eq "$JobName" | Select-Object -first 1).jobid 71 | if (-not $jobId) {throw "Unable to find a job named $JobName within the latest specified build. Did you spell it correctly?"} 72 | } else { 73 | $jobid = $projectObject.build.jobs[0].jobid 74 | } 75 | 76 | $artifacts = Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts" ` 77 | -Headers $headers @proxyArgs 78 | $artifacts ` 79 | | ? { $psCmdlet.ShouldProcess($_.fileName) } ` 80 | | % { 81 | 82 | $type = $_.type 83 | 84 | $localArtifactPath = $_.fileName -split '/' | % { [Uri]::UnescapeDataString($_) } 85 | if ($flat.IsPresent) { 86 | $localArtifactPath = ($localArtifactPath | select -Last 1) 87 | } else { 88 | $localArtifactPath = $localArtifactPath -join [IO.Path]::DirectorySeparatorChar 89 | } 90 | $localArtifactPath = Join-Path $path $localArtifactPath 91 | 92 | $artifactUrl = "$apiUrl/buildjobs/$jobId/artifacts/$($_.fileName)" 93 | Write-Verbose "Downloading $artifactUrl to $localArtifactPath" 94 | 95 | New-Item -ItemType Directory -Force -Path (Split-Path -Path $localArtifactPath) | Out-Null 96 | 97 | Invoke-RestMethod -Method Get -Uri $artifactUrl -OutFile $localArtifactPath -Headers $headers @proxyArgs 98 | 99 | New-Object PSObject -Property @{ 100 | 'Source' = $artifactUrl 101 | 'Type' = $type 102 | 'Target' = $localArtifactPath 103 | } 104 | } 105 | } 106 | 107 | # Download x64 binaries 108 | Get-AppVeyorArtifacts -Account "nefarius" -Project "ViGemBus" -Path $Path -Token $Token -Branch $BuildVersion -JobName "Platform: x64" 109 | 110 | # Download x86 binaries 111 | Get-AppVeyorArtifacts -Account "nefarius" -Project "ViGemBus" -Path $Path -Token $Token -Branch $BuildVersion -JobName "Platform: x86" 112 | 113 | # Download ARM64 binaries 114 | Get-AppVeyorArtifacts -Account "nefarius" -Project "ViGemBus" -Path $Path -Token $Token -Branch $BuildVersion -JobName "Platform: ARM64" 115 | 116 | # List of files to sign 117 | $files = "`".\artifacts\disk1\*.cab`" " 118 | 119 | if ($NoSigning -eq $false) { 120 | # sign with only one certificate 121 | Invoke-Expression "& `"$signTool`" sign /v /as /n `"$certName`" /tr $timestampUrl /fd sha256 /td sha256 $files" 122 | } 123 | 124 | # Print helper job names for sign portal 125 | "ViGemBus x86 v$BuildVersion $(Get-Date -Format "dd.MM.yyyy")" 126 | "ViGemBus x64 v$BuildVersion $(Get-Date -Format "dd.MM.yyyy")" 127 | "ViGemBus ARM64 v$BuildVersion $(Get-Date -Format "dd.MM.yyyy")" 128 | -------------------------------------------------------------------------------- /sys/CRTCPP.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver 3 | * 4 | * BSD 3-Clause License 5 | * 6 | * Copyright (c) 2018-2020, Nefarius Software Solutions e.U. and Contributors 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the copyright holder nor the names of its 20 | * contributors may be used to endorse or promote products derived from 21 | * this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | 36 | #pragma once 37 | 38 | constexpr auto cpp_pool_tag = 'EGiV'; 39 | 40 | #ifdef _AMD64_ 41 | 42 | void* operator new 43 | ( 44 | size_t size 45 | ) 46 | { 47 | return ExAllocatePoolZero(NonPagedPoolNx, size, cpp_pool_tag); 48 | } 49 | 50 | void* operator new[] 51 | ( 52 | size_t size 53 | ) 54 | { 55 | return ExAllocatePoolZero(NonPagedPoolNx, size, cpp_pool_tag); 56 | } 57 | 58 | void operator delete 59 | ( 60 | void* what 61 | ) 62 | { 63 | if (what == nullptr) 64 | { 65 | return; 66 | } 67 | 68 | ExFreePoolWithTag(what, cpp_pool_tag); 69 | } 70 | 71 | void operator delete 72 | ( 73 | void* what, 74 | size_t size 75 | ) 76 | { 77 | UNREFERENCED_PARAMETER(size); 78 | 79 | if (what == nullptr) 80 | { 81 | return; 82 | } 83 | 84 | ExFreePoolWithTag(what, cpp_pool_tag); 85 | } 86 | 87 | void operator delete[] 88 | ( 89 | void* what, 90 | size_t size 91 | ) 92 | { 93 | UNREFERENCED_PARAMETER(size); 94 | 95 | if (what == nullptr) 96 | { 97 | return; 98 | } 99 | 100 | ExFreePoolWithTag(what, cpp_pool_tag); 101 | } 102 | 103 | #else 104 | 105 | void* __CRTDECL operator new 106 | ( 107 | size_t size 108 | ) 109 | { 110 | return ExAllocatePoolZero(NonPagedPoolNx, size, cpp_pool_tag); 111 | } 112 | 113 | void* __CRTDECL operator new[] 114 | ( 115 | size_t size 116 | ) 117 | { 118 | return ExAllocatePoolZero(NonPagedPoolNx, size, cpp_pool_tag); 119 | } 120 | 121 | void __CRTDECL operator delete 122 | ( 123 | void* what 124 | ) 125 | { 126 | if (what == nullptr) 127 | { 128 | return; 129 | } 130 | 131 | ExFreePoolWithTag(what, cpp_pool_tag); 132 | } 133 | 134 | void __CRTDECL operator delete 135 | ( 136 | void* what, 137 | size_t size 138 | ) 139 | { 140 | UNREFERENCED_PARAMETER(size); 141 | 142 | if (what == nullptr) 143 | { 144 | return; 145 | } 146 | 147 | ExFreePoolWithTag(what, cpp_pool_tag); 148 | } 149 | 150 | void __CRTDECL operator delete[] 151 | ( 152 | void* what, 153 | size_t size 154 | ) 155 | { 156 | UNREFERENCED_PARAMETER(size); 157 | 158 | if (what == nullptr) 159 | { 160 | return; 161 | } 162 | 163 | ExFreePoolWithTag(what, cpp_pool_tag); 164 | } 165 | 166 | #endif 167 | -------------------------------------------------------------------------------- /sys/Dmf.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <_PropertySheetDisplayName>Driver Module Framework 7 | 8 | $(SolutionDir)..\ 9 | 10 | 11 | 12 | $(DmfRootPath)\DMF\Modules.Library;$(DmfRootPath)\DMF\Modules.Template;$(DmfRootPath)\DMF\Modules.Library.Tests;$(DmfRootPath)\DMF\Framework;$(IntDir);%(AdditionalIncludeDirectories) 13 | 14 | 15 | $(DmfRootPath)\$(Configuration)\$(PlatformName)\lib\DmfK\DmfK.lib;$(DmfRootPath)\$(Configuration)\$(PlatformName)\individual_libs\DmfKModules.Template\DmfKModules.Template.lib;%(AdditionalDependencies); 16 | $(DmfRootPath)\$(Configuration)\$(PlatformName)\lib\DmfU\DmfU.lib;$(DmfRootPath)\$(Configuration)\$(PlatformName)\individual_libs\DmfUModules.Template\DmfUModules.Template.lib;%(AdditionalDependencies); 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /sys/Driver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver 3 | * 4 | * BSD 3-Clause License 5 | * 6 | * Copyright (c) 2018-2022, Nefarius Software Solutions e.U. and Contributors 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the copyright holder nor the names of its 20 | * contributors may be used to endorse or promote products derived from 21 | * this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | 36 | #include "Driver.h" 37 | #include "trace.h" 38 | #include "Driver.tmh" 39 | #include 40 | 41 | #ifdef ALLOC_PRAGMA 42 | #pragma alloc_text (INIT, DriverEntry) 43 | #pragma alloc_text (PAGE, Bus_EvtDeviceAdd) 44 | #pragma alloc_text (PAGE, Bus_DeviceFileCreate) 45 | #pragma alloc_text (PAGE, Bus_FileClose) 46 | #pragma alloc_text (PAGE, Bus_EvtDriverContextCleanup) 47 | #endif 48 | 49 | #include "Queue.hpp" 50 | #include "EmulationTargetPDO.hpp" 51 | #include "XusbPdo.hpp" 52 | #include "Ds4Pdo.hpp" 53 | 54 | using ViGEm::Bus::Core::PDO_IDENTIFICATION_DESCRIPTION; 55 | using ViGEm::Bus::Core::EmulationTargetPDO; 56 | using ViGEm::Bus::Targets::EmulationTargetXUSB; 57 | using ViGEm::Bus::Targets::EmulationTargetDS4; 58 | 59 | 60 | EXTERN_C_START 61 | 62 | IoctlHandler_IoctlRecord ViGEmBus_IoctlSpecification[] = 63 | { 64 | {IOCTL_VIGEM_CHECK_VERSION, sizeof(VIGEM_CHECK_VERSION), 0, Bus_CheckVersionHandler}, 65 | {IOCTL_VIGEM_WAIT_DEVICE_READY, sizeof(VIGEM_WAIT_DEVICE_READY), 0, Bus_WaitDeviceReadyHandler}, 66 | {IOCTL_VIGEM_PLUGIN_TARGET, sizeof(VIGEM_PLUGIN_TARGET), 0, Bus_PluginTargetHandler}, 67 | {IOCTL_VIGEM_UNPLUG_TARGET, sizeof(VIGEM_UNPLUG_TARGET), 0, Bus_UnplugTargetHandler}, 68 | {IOCTL_XUSB_SUBMIT_REPORT, sizeof(XUSB_SUBMIT_REPORT), 0, Bus_XusbSubmitReportHandler}, 69 | {IOCTL_XUSB_REQUEST_NOTIFICATION, sizeof(XUSB_REQUEST_NOTIFICATION), sizeof(XUSB_REQUEST_NOTIFICATION), Bus_XusbRequestNotificationHandler}, 70 | {IOCTL_DS4_SUBMIT_REPORT, sizeof(DS4_SUBMIT_REPORT), 0, Bus_Ds4SubmitReportHandler}, 71 | {IOCTL_DS4_REQUEST_NOTIFICATION, sizeof(DS4_REQUEST_NOTIFICATION), sizeof(DS4_REQUEST_NOTIFICATION), Bus_Ds4RequestNotificationHandler}, 72 | {IOCTL_XUSB_GET_USER_INDEX, sizeof(XUSB_GET_USER_INDEX), sizeof(XUSB_GET_USER_INDEX), Bus_XusbGetUserIndexHandler}, 73 | {IOCTL_DS4_AWAIT_OUTPUT_AVAILABLE, sizeof(DS4_AWAIT_OUTPUT), sizeof(DS4_AWAIT_OUTPUT), Bus_Ds4AwaitOutputHandler}, 74 | }; 75 | 76 | // 77 | // Driver entry routine. 78 | // 79 | NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) 80 | { 81 | WDF_DRIVER_CONFIG config; 82 | NTSTATUS status; 83 | WDFDRIVER driver; 84 | WDF_OBJECT_ATTRIBUTES attributes; 85 | 86 | KdPrint((DRIVERNAME "Virtual Gamepad Emulation Bus Driver [built: %s %s]\n", __DATE__, __TIME__)); 87 | 88 | // 89 | // Initialize WPP Tracing 90 | // 91 | WPP_INIT_TRACING(DriverObject, RegistryPath); 92 | 93 | TraceEvents(TRACE_LEVEL_INFORMATION, 94 | TRACE_DRIVER, 95 | "Loading Virtual Gamepad Emulation Bus Driver" 96 | ); 97 | 98 | ExInitializeDriverRuntime(DrvRtPoolNxOptIn); 99 | 100 | // 101 | // Register cleanup callback 102 | // 103 | WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 104 | attributes.EvtCleanupCallback = Bus_EvtDriverContextCleanup; 105 | 106 | WDF_DRIVER_CONFIG_INIT(&config, Bus_EvtDeviceAdd); 107 | 108 | status = WdfDriverCreate(DriverObject, RegistryPath, &attributes, &config, &driver); 109 | 110 | if (!NT_SUCCESS(status)) 111 | { 112 | WPP_CLEANUP(DriverObject); 113 | KdPrint((DRIVERNAME "WdfDriverCreate failed with status 0x%x\n", status)); 114 | } 115 | 116 | return status; 117 | } 118 | 119 | // 120 | // Bus-device creation routine. 121 | // 122 | NTSTATUS Bus_EvtDeviceAdd(IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit) 123 | { 124 | WDF_CHILD_LIST_CONFIG config; 125 | NTSTATUS status; 126 | WDFDEVICE device = NULL; 127 | PNP_BUS_INFORMATION busInfo; 128 | WDF_FILEOBJECT_CONFIG foConfig; 129 | WDF_OBJECT_ATTRIBUTES fdoAttributes; 130 | WDF_OBJECT_ATTRIBUTES fileHandleAttributes; 131 | PFDO_DEVICE_DATA pFDOData; 132 | PWSTR pSymbolicNameList; 133 | PDMFDEVICE_INIT dmfDeviceInit = NULL; 134 | 135 | UNREFERENCED_PARAMETER(Driver); 136 | 137 | PAGED_CODE(); 138 | 139 | FuncEntry(TRACE_DRIVER); 140 | 141 | #pragma region Check for duplicated FDO 142 | 143 | // 144 | // Note: this could be avoided if converted to non-PNP driver 145 | // and use of named device object. Food for thought for future. 146 | // 147 | 148 | if (NT_SUCCESS(status = IoGetDeviceInterfaces( 149 | &GUID_DEVINTERFACE_BUSENUM_VIGEM, 150 | NULL, 151 | 0, // Important! 152 | &pSymbolicNameList 153 | ))) 154 | { 155 | const bool deviceAlreadyExists = (0 != *pSymbolicNameList); 156 | ExFreePool(pSymbolicNameList); 157 | 158 | if (deviceAlreadyExists) 159 | { 160 | TraceError( 161 | TRACE_DRIVER, 162 | "Device with interface GUID {%!GUID!} already exists (%ws)", 163 | &GUID_DEVINTERFACE_BUSENUM_VIGEM, 164 | pSymbolicNameList 165 | ); 166 | 167 | return STATUS_RESOURCE_IN_USE; 168 | } 169 | } 170 | else 171 | { 172 | TraceEvents(TRACE_LEVEL_WARNING, 173 | TRACE_DRIVER, 174 | "IoGetDeviceInterfaces failed with status %!STATUS!", 175 | status); 176 | } 177 | 178 | #pragma endregion 179 | 180 | do 181 | { 182 | dmfDeviceInit = DMF_DmfDeviceInitAllocate(DeviceInit); 183 | 184 | if (dmfDeviceInit == NULL) 185 | { 186 | TraceError( 187 | TRACE_DRIVER, 188 | "DMF_DmfDeviceInitAllocate failed" 189 | ); 190 | 191 | status = STATUS_INSUFFICIENT_RESOURCES; 192 | break; 193 | } 194 | 195 | DMF_DmfDeviceInitHookPnpPowerEventCallbacks(dmfDeviceInit, NULL); 196 | DMF_DmfDeviceInitHookPowerPolicyEventCallbacks(dmfDeviceInit, NULL); 197 | 198 | WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER); 199 | 200 | #pragma region Prepare child list 201 | 202 | WDF_CHILD_LIST_CONFIG_INIT(&config, sizeof(PDO_IDENTIFICATION_DESCRIPTION), Bus_EvtDeviceListCreatePdo); 203 | 204 | config.EvtChildListIdentificationDescriptionCompare = EmulationTargetPDO::EvtChildListIdentificationDescriptionCompare; 205 | 206 | WdfFdoInitSetDefaultChildListConfig(DeviceInit, &config, WDF_NO_OBJECT_ATTRIBUTES); 207 | 208 | #pragma endregion 209 | 210 | #pragma region Assign File Object Configuration 211 | 212 | WDF_FILEOBJECT_CONFIG_INIT(&foConfig, Bus_DeviceFileCreate, Bus_FileClose, NULL); 213 | 214 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fileHandleAttributes, FDO_FILE_DATA); 215 | 216 | DMF_DmfDeviceInitHookFileObjectConfig(dmfDeviceInit, &foConfig); 217 | 218 | WdfDeviceInitSetFileObjectConfig(DeviceInit, &foConfig, &fileHandleAttributes); 219 | 220 | #pragma endregion 221 | 222 | #pragma region Create FDO 223 | 224 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FDO_DEVICE_DATA); 225 | 226 | if (!NT_SUCCESS(status = WdfDeviceCreate( 227 | &DeviceInit, 228 | &fdoAttributes, 229 | &device 230 | ))) 231 | { 232 | TraceError( 233 | TRACE_DRIVER, 234 | "WdfDeviceCreate failed with status %!STATUS!", 235 | status); 236 | break; 237 | } 238 | 239 | pFDOData = FdoGetData(device); 240 | 241 | pFDOData->InterfaceReferenceCounter = 0; 242 | pFDOData->NextSessionId = FDO_FIRST_SESSION_ID; 243 | 244 | #pragma endregion 245 | 246 | #pragma region Expose FDO interface 247 | 248 | if (!NT_SUCCESS(status = WdfDeviceCreateDeviceInterface( 249 | device, 250 | &GUID_DEVINTERFACE_BUSENUM_VIGEM, 251 | NULL 252 | ))) 253 | { 254 | TraceError( 255 | TRACE_DRIVER, 256 | "WdfDeviceCreateDeviceInterface failed with status %!STATUS!", 257 | status); 258 | break; 259 | } 260 | 261 | #pragma endregion 262 | 263 | #pragma region Set bus information 264 | 265 | busInfo.BusTypeGuid = GUID_BUS_TYPE_USB; 266 | busInfo.LegacyBusType = PNPBus; 267 | busInfo.BusNumber = 0; 268 | 269 | WdfDeviceSetBusInformationForChildren(device, &busInfo); 270 | 271 | #pragma endregion 272 | 273 | // 274 | // DMF Module initialization 275 | // 276 | DMF_EVENT_CALLBACKS dmfEventCallbacks; 277 | DMF_EVENT_CALLBACKS_INIT(&dmfEventCallbacks); 278 | dmfEventCallbacks.EvtDmfDeviceModulesAdd = DmfDeviceModulesAdd; 279 | DMF_DmfDeviceInitSetEventCallbacks( 280 | dmfDeviceInit, 281 | &dmfEventCallbacks 282 | ); 283 | 284 | status = DMF_ModulesCreate(device, &dmfDeviceInit); 285 | 286 | if (!NT_SUCCESS(status)) 287 | { 288 | TraceEvents( 289 | TRACE_LEVEL_ERROR, 290 | TRACE_DRIVER, 291 | "DMF_ModulesCreate failed with status %!STATUS!", 292 | status 293 | ); 294 | break; 295 | } 296 | 297 | } while (FALSE); 298 | 299 | if (dmfDeviceInit != NULL) 300 | { 301 | DMF_DmfDeviceInitFree(&dmfDeviceInit); 302 | } 303 | 304 | if (!NT_SUCCESS(status) && device != NULL) 305 | { 306 | WdfObjectDelete(device); 307 | } 308 | 309 | FuncExit(TRACE_DRIVER, "status=%!STATUS!", status); 310 | 311 | return status; 312 | } 313 | 314 | #pragma code_seg("PAGED") 315 | _IRQL_requires_max_(PASSIVE_LEVEL) 316 | VOID 317 | DmfDeviceModulesAdd( 318 | _In_ WDFDEVICE Device, 319 | _In_ PDMFMODULE_INIT DmfModuleInit 320 | ) 321 | { 322 | FuncEntry(TRACE_DRIVER); 323 | 324 | PFDO_DEVICE_DATA pDevCtx = FdoGetData(Device); 325 | 326 | DMF_MODULE_ATTRIBUTES moduleAttributes; 327 | DMF_CONFIG_IoctlHandler ioctlHandlerConfig; 328 | DMF_CONFIG_IoctlHandler_AND_ATTRIBUTES_INIT(&ioctlHandlerConfig, &moduleAttributes); 329 | 330 | ioctlHandlerConfig.DeviceInterfaceGuid = GUID_DEVINTERFACE_BUSENUM_VIGEM; 331 | ioctlHandlerConfig.IoctlRecordCount = ARRAYSIZE(ViGEmBus_IoctlSpecification); 332 | ioctlHandlerConfig.IoctlRecords = ViGEmBus_IoctlSpecification; 333 | ioctlHandlerConfig.ForwardUnhandledRequests = FALSE; 334 | 335 | DMF_DmfModuleAdd( 336 | DmfModuleInit, 337 | &moduleAttributes, 338 | WDF_NO_OBJECT_ATTRIBUTES, 339 | NULL 340 | ); 341 | 342 | DMF_CONFIG_NotifyUserWithRequestMultiple notifyConfig; 343 | DMF_CONFIG_NotifyUserWithRequestMultiple_AND_ATTRIBUTES_INIT(¬ifyConfig, &moduleAttributes); 344 | 345 | notifyConfig.MaximumNumberOfPendingRequests = 64 * 2; 346 | notifyConfig.SizeOfDataBuffer = sizeof(DS4_AWAIT_OUTPUT); 347 | notifyConfig.MaximumNumberOfPendingDataBuffers = 64; 348 | notifyConfig.ModeType.Modes.ReplayLastMessageToNewClients = FALSE; 349 | notifyConfig.CompletionCallback = Bus_EvtUserNotifyRequestComplete; 350 | 351 | DMF_DmfModuleAdd( 352 | DmfModuleInit, 353 | &moduleAttributes, 354 | WDF_NO_OBJECT_ATTRIBUTES, 355 | &pDevCtx->UserNotification 356 | ); 357 | 358 | FuncExitNoReturn(TRACE_DRIVER); 359 | } 360 | #pragma code_seg() 361 | 362 | // Gets called when the user-land process (or kernel driver) exits or closes the handle, 363 | // and all IO has completed. 364 | // 365 | _Use_decl_annotations_ 366 | VOID 367 | Bus_DeviceFileCreate( 368 | _In_ WDFDEVICE Device, 369 | _In_ WDFREQUEST Request, 370 | _In_ WDFFILEOBJECT FileObject 371 | ) 372 | { 373 | NTSTATUS status = STATUS_INVALID_PARAMETER; 374 | PFDO_FILE_DATA pFileData = NULL; 375 | PFDO_DEVICE_DATA pFDOData = NULL; 376 | LONG refCount = 0; 377 | LONG sessionId = 0; 378 | 379 | UNREFERENCED_PARAMETER(Request); 380 | 381 | PAGED_CODE(); 382 | 383 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); 384 | 385 | pFileData = FileObjectGetData(FileObject); 386 | 387 | if (pFileData == NULL) 388 | { 389 | TraceError( 390 | TRACE_DRIVER, 391 | "FileObjectGetData failed to return file object from WDFFILEOBJECT 0x%p", 392 | FileObject); 393 | } 394 | else 395 | { 396 | pFDOData = FdoGetData(Device); 397 | if (pFDOData == NULL) 398 | { 399 | TraceError( 400 | TRACE_DRIVER, 401 | "FdoGetData failed"); 402 | status = STATUS_NO_SUCH_DEVICE; 403 | } 404 | else 405 | { 406 | refCount = InterlockedIncrement(&pFDOData->InterfaceReferenceCounter); 407 | sessionId = InterlockedIncrement(&pFDOData->NextSessionId); 408 | 409 | pFileData->SessionId = sessionId; 410 | status = STATUS_SUCCESS; 411 | 412 | TraceEvents(TRACE_LEVEL_INFORMATION, 413 | TRACE_DRIVER, 414 | "File/session id = %d, device ref. count = %d", 415 | (int)sessionId, (int)refCount); 416 | } 417 | } 418 | 419 | WdfRequestComplete(Request, status); 420 | 421 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit with status %!STATUS!", status); 422 | } 423 | 424 | // 425 | // Gets called when the user-land process (or kernel driver) exits or closes the handle. 426 | // 427 | _Use_decl_annotations_ 428 | VOID 429 | Bus_FileClose( 430 | WDFFILEOBJECT FileObject 431 | ) 432 | { 433 | WDFDEVICE device; 434 | WDFDEVICE hChild; 435 | NTSTATUS status; 436 | WDFCHILDLIST list; 437 | WDF_CHILD_LIST_ITERATOR iterator; 438 | WDF_CHILD_RETRIEVE_INFO childInfo; 439 | PDO_IDENTIFICATION_DESCRIPTION description; 440 | PFDO_FILE_DATA pFileData = NULL; 441 | PFDO_DEVICE_DATA pFDOData = NULL; 442 | LONG refCount = 0; 443 | 444 | PAGED_CODE(); 445 | 446 | 447 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); 448 | 449 | // Check common context 450 | pFileData = FileObjectGetData(FileObject); 451 | if (pFileData == NULL) 452 | { 453 | TraceError( 454 | TRACE_DRIVER, 455 | "FileObjectGetData failed to return file object from WDFFILEOBJECT 0x%p", 456 | FileObject); 457 | return; 458 | } 459 | 460 | device = WdfFileObjectGetDevice(FileObject); 461 | 462 | pFDOData = FdoGetData(device); 463 | if (pFDOData == NULL) 464 | { 465 | TraceError( 466 | TRACE_DRIVER, 467 | "FdoGetData failed"); 468 | status = STATUS_NO_SUCH_DEVICE; 469 | } 470 | else 471 | { 472 | refCount = InterlockedDecrement(&pFDOData->InterfaceReferenceCounter); 473 | 474 | TraceEvents(TRACE_LEVEL_INFORMATION, 475 | TRACE_DRIVER, 476 | "Device ref. count = %d", 477 | (int)refCount); 478 | } 479 | 480 | list = WdfFdoGetDefaultChildList(device); 481 | 482 | WDF_CHILD_LIST_ITERATOR_INIT(&iterator, WdfRetrievePresentChildren); 483 | 484 | WdfChildListBeginIteration(list, &iterator); 485 | 486 | for (;;) 487 | { 488 | WDF_CHILD_RETRIEVE_INFO_INIT(&childInfo, &description.Header); 489 | WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&description.Header, sizeof(description)); 490 | 491 | status = WdfChildListRetrieveNextDevice(list, &iterator, &hChild, &childInfo); 492 | if (!NT_SUCCESS(status) || status == STATUS_NO_MORE_ENTRIES) 493 | { 494 | break; 495 | } 496 | 497 | //TraceVerbose( 498 | // TRACE_DRIVER, 499 | // "PDO properties: status = %!STATUS!, pdoPID = %d, curPID = %d, pdoSID = %d, curSID = %d, internal = %d", 500 | // (int)childInfo.Status, 501 | // (int)description.OwnerProcessId, 502 | // (int)CURRENT_PROCESS_ID(), 503 | // (int)description.SessionId, 504 | // (int)pFileData->SessionId, 505 | // (int)description.OwnerIsDriver 506 | //); 507 | 508 | // Only unplug devices with matching session id 509 | if (childInfo.Status == WdfChildListRetrieveDeviceSuccess 510 | && description.SessionId == pFileData->SessionId) 511 | { 512 | TraceEvents(TRACE_LEVEL_INFORMATION, 513 | TRACE_DRIVER, 514 | "Unplugging device with serial %d", 515 | description.SerialNo); 516 | 517 | // "Unplug" child 518 | status = WdfChildListUpdateChildDescriptionAsMissing(list, &description.Header); 519 | if (!NT_SUCCESS(status)) 520 | { 521 | TraceError( 522 | TRACE_DRIVER, 523 | "WdfChildListUpdateChildDescriptionAsMissing failed with status %!STATUS!", 524 | status); 525 | } 526 | } 527 | } 528 | 529 | WdfChildListEndIteration(list, &iterator); 530 | 531 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit with status %!STATUS!", status); 532 | } 533 | 534 | VOID 535 | Bus_EvtDriverContextCleanup( 536 | _In_ WDFOBJECT DriverObject 537 | ) 538 | /*++ 539 | Routine Description: 540 | 541 | Free all the resources allocated in DriverEntry. 542 | 543 | Arguments: 544 | 545 | DriverObject - handle to a WDF Driver object. 546 | 547 | Return Value: 548 | 549 | VOID. 550 | 551 | --*/ 552 | { 553 | UNREFERENCED_PARAMETER(DriverObject); 554 | 555 | PAGED_CODE(); 556 | 557 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); 558 | 559 | // 560 | // Stop WPP Tracing 561 | // 562 | WPP_CLEANUP(WdfDriverWdmGetDriverObject((WDFDRIVER)DriverObject)); 563 | 564 | } 565 | 566 | void Bus_EvtUserNotifyRequestComplete( 567 | _In_ DMFMODULE DmfModule, 568 | _In_ WDFREQUEST Request, 569 | _In_opt_ ULONG_PTR Context, 570 | _In_ NTSTATUS NtStatus 571 | ) 572 | { 573 | FuncEntry(TRACE_DRIVER); 574 | 575 | UNREFERENCED_PARAMETER(DmfModule); 576 | 577 | auto pOutput = reinterpret_cast(Context); 578 | PDS4_AWAIT_OUTPUT pNotify = NULL; 579 | size_t length = 0; 580 | 581 | if (NT_SUCCESS(WdfRequestRetrieveOutputBuffer( 582 | Request, 583 | sizeof(DS4_AWAIT_OUTPUT), 584 | reinterpret_cast(&pNotify), 585 | &length))) 586 | { 587 | RtlCopyMemory(pNotify, pOutput, sizeof(DS4_AWAIT_OUTPUT)); 588 | 589 | Util_DumpAsHex("NOTIFY_COMPLETE", pNotify, sizeof(DS4_AWAIT_OUTPUT)); 590 | 591 | WdfRequestSetInformation(Request, sizeof(DS4_AWAIT_OUTPUT)); 592 | } 593 | 594 | WdfRequestComplete(Request, NtStatus); 595 | 596 | FuncExit(TRACE_DRIVER, "status=%!STATUS!", NtStatus); 597 | } 598 | 599 | void Util_DumpAsHex(PCSTR Prefix, PVOID Buffer, ULONG BufferLength) 600 | { 601 | #ifdef DBG 602 | 603 | size_t dumpBufferLength = ((BufferLength * sizeof(CHAR)) * 2) + 1; 604 | PSTR dumpBuffer = static_cast(ExAllocatePoolZero( 605 | NonPagedPoolNx, 606 | dumpBufferLength, 607 | '1234' 608 | )); 609 | if (dumpBuffer) 610 | { 611 | 612 | RtlZeroMemory(dumpBuffer, dumpBufferLength); 613 | 614 | for (ULONG i = 0; i < BufferLength; i++) 615 | { 616 | sprintf(&dumpBuffer[i * 2], "%02X", static_cast(Buffer)[i]); 617 | } 618 | 619 | TraceVerbose(TRACE_BUSPDO, 620 | "%s - Buffer length: %04d, buffer content: %s\n", 621 | Prefix, 622 | BufferLength, 623 | dumpBuffer 624 | ); 625 | 626 | ExFreePoolWithTag(dumpBuffer, '1234'); 627 | } 628 | #else 629 | UNREFERENCED_PARAMETER(Prefix); 630 | UNREFERENCED_PARAMETER(Buffer); 631 | UNREFERENCED_PARAMETER(BufferLength); 632 | #endif 633 | } 634 | 635 | EXTERN_C_END 636 | -------------------------------------------------------------------------------- /sys/Driver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver 3 | * 4 | * BSD 3-Clause License 5 | * 6 | * Copyright (c) 2018-2022, Nefarius Software Solutions e.U. and Contributors 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the copyright holder nor the names of its 20 | * contributors may be used to endorse or promote products derived from 21 | * this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | 36 | #pragma once 37 | 38 | #pragma warning(disable:5040) 39 | #include 40 | #pragma warning(default:5040) 41 | #include 42 | #include 43 | #define NTSTRSAFE_LIB 44 | #include 45 | 46 | 47 | #pragma region Macros 48 | 49 | #define DRIVERNAME "ViGEm: " 50 | 51 | #pragma endregion 52 | 53 | // 54 | // FDO (bus device) context data 55 | // 56 | typedef struct _FDO_DEVICE_DATA 57 | { 58 | // 59 | // Counter of interface references 60 | // 61 | LONG InterfaceReferenceCounter; 62 | 63 | // 64 | // Next SessionId to assign to a file handle 65 | // 66 | LONG NextSessionId; 67 | 68 | // 69 | // Notification DMF module 70 | // 71 | DMFMODULE UserNotification; 72 | 73 | } FDO_DEVICE_DATA, * PFDO_DEVICE_DATA; 74 | 75 | #define FDO_FIRST_SESSION_ID 100 76 | 77 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DEVICE_DATA, FdoGetData) 78 | 79 | // 80 | // Context data associated with file objects created by user mode applications 81 | // 82 | typedef struct _FDO_FILE_DATA 83 | { 84 | // 85 | // SessionId associated with file handle. 86 | // Used to map file handles to emulated gamepad devices. 87 | // 88 | LONG SessionId; 89 | 90 | } FDO_FILE_DATA, * PFDO_FILE_DATA; 91 | 92 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_FILE_DATA, FileObjectGetData) 93 | 94 | 95 | EXTERN_C_START 96 | 97 | #pragma region WDF callback prototypes 98 | 99 | DRIVER_INITIALIZE DriverEntry; 100 | 101 | EVT_WDF_DRIVER_DEVICE_ADD Bus_EvtDeviceAdd; 102 | 103 | EVT_WDF_DEVICE_FILE_CREATE Bus_DeviceFileCreate; 104 | 105 | EVT_WDF_FILE_CLOSE Bus_FileClose; 106 | 107 | EVT_WDF_CHILD_LIST_CREATE_DEVICE Bus_EvtDeviceListCreatePdo; 108 | 109 | EVT_WDF_OBJECT_CONTEXT_CLEANUP Bus_EvtDriverContextCleanup; 110 | 111 | #pragma endregion 112 | 113 | _IRQL_requires_max_(PASSIVE_LEVEL) 114 | VOID 115 | DmfDeviceModulesAdd( 116 | _In_ WDFDEVICE Device, 117 | _In_ PDMFMODULE_INIT DmfModuleInit 118 | ); 119 | 120 | void Bus_EvtUserNotifyRequestComplete( 121 | _In_ DMFMODULE DmfModule, 122 | _In_ WDFREQUEST Request, 123 | _In_opt_ ULONG_PTR Context, 124 | _In_ NTSTATUS NtStatus 125 | ); 126 | 127 | void Util_DumpAsHex(PCSTR Prefix, PVOID Buffer, ULONG BufferLength); 128 | 129 | #pragma region Bus enumeration-specific functions 130 | 131 | NTSTATUS 132 | Bus_PlugInDevice( 133 | _In_ WDFDEVICE Device, 134 | _In_ WDFREQUEST Request, 135 | _In_ BOOLEAN IsInternal, 136 | _Out_ size_t* Transferred 137 | ); 138 | 139 | NTSTATUS 140 | Bus_UnPlugDevice( 141 | _In_ WDFDEVICE Device, 142 | _In_ WDFREQUEST Request, 143 | _In_ BOOLEAN IsInternal, 144 | _Out_ size_t* Transferred 145 | ); 146 | 147 | #pragma endregion 148 | 149 | EXTERN_C_END 150 | -------------------------------------------------------------------------------- /sys/Ds4Pdo.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver 3 | * 4 | * BSD 3-Clause License 5 | * 6 | * Copyright (c) 2018-2020, Nefarius Software Solutions e.U. and Contributors 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the copyright holder nor the names of its 20 | * contributors may be used to endorse or promote products derived from 21 | * this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | 36 | #pragma once 37 | 38 | #include "EmulationTargetPDO.hpp" 39 | #include 40 | 41 | 42 | namespace ViGEm::Bus::Targets 43 | { 44 | // 45 | // Represents a MAC address. 46 | // 47 | typedef struct _MAC_ADDRESS 48 | { 49 | UCHAR Vendor0; 50 | UCHAR Vendor1; 51 | UCHAR Vendor2; 52 | UCHAR Nic0; 53 | UCHAR Nic1; 54 | UCHAR Nic2; 55 | } MAC_ADDRESS, * PMAC_ADDRESS; 56 | 57 | constexpr unsigned char hid_get_report_id(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST* pReq) 58 | { 59 | return pReq->Value & 0xFF; 60 | } 61 | 62 | constexpr unsigned char hid_get_report_type(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST* pReq) 63 | { 64 | return (pReq->Value >> 8) & 0xFF; 65 | } 66 | 67 | class EmulationTargetDS4 : public Core::EmulationTargetPDO 68 | { 69 | public: 70 | EmulationTargetDS4(ULONG Serial, LONG SessionId, USHORT VendorId = 0x054C, USHORT ProductId = 0x05C4); 71 | 72 | NTSTATUS PdoPrepareDevice(PWDFDEVICE_INIT DeviceInit, 73 | PUNICODE_STRING DeviceId, 74 | PUNICODE_STRING DeviceDescription) override; 75 | 76 | NTSTATUS PdoPrepareHardware() override; 77 | 78 | NTSTATUS PdoInitContext() override; 79 | 80 | VOID GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length) override; 81 | 82 | NTSTATUS UsbGetDeviceDescriptorType(PUSB_DEVICE_DESCRIPTOR pDescriptor) override; 83 | 84 | NTSTATUS SelectConfiguration(PURB Urb) override; 85 | 86 | void AbortPipe() override; 87 | 88 | NTSTATUS UsbClassInterface(PURB Urb) override; 89 | 90 | NTSTATUS UsbGetDescriptorFromInterface(PURB Urb) override; 91 | 92 | NTSTATUS UsbSelectInterface(PURB Urb) override; 93 | 94 | NTSTATUS UsbGetStringDescriptorType(PURB Urb) override; 95 | 96 | NTSTATUS UsbBulkOrInterruptTransfer(_URB_BULK_OR_INTERRUPT_TRANSFER* pTransfer, WDFREQUEST Request) override; 97 | 98 | NTSTATUS UsbControlTransfer(PURB Urb) override; 99 | 100 | NTSTATUS SubmitReportImpl(PVOID NewReport) override; 101 | 102 | VOID SetOutputReportNotifyModule(DMFMODULE Module); 103 | 104 | private: 105 | static EVT_WDF_TIMER PendingUsbRequestsTimerFunc; 106 | 107 | static VOID ReverseByteArray(PUCHAR Array, INT Length); 108 | 109 | static VOID GenerateRandomMacAddress(PMAC_ADDRESS Address); 110 | 111 | protected: 112 | void ProcessPendingNotification(WDFQUEUE Queue) override; 113 | 114 | void DmfDeviceModulesAdd(_In_ PDMFMODULE_INIT DmfModuleInit) override; 115 | private: 116 | static PCWSTR _deviceDescription; 117 | 118 | static const int HID_REQUEST_GET_REPORT = 0x01; 119 | static const int HID_REQUEST_SET_REPORT = 0x09; 120 | static const int HID_REPORT_TYPE_FEATURE = 0x03; 121 | 122 | static const int HID_REPORT_ID_0 = 0xA3; 123 | static const int HID_REPORT_ID_1 = 0x02; 124 | static const int HID_REPORT_MAC_ADDRESSES_ID = 0x12; 125 | static const int HID_REPORT_ID_3 = 0x13; 126 | static const int HID_REPORT_ID_4 = 0x14; 127 | 128 | static const int DS4_DESCRIPTOR_SIZE = 0x0029; 129 | #if defined(_X86_) 130 | static const int DS4_CONFIGURATION_SIZE = 0x0050; 131 | #else 132 | static const int DS4_CONFIGURATION_SIZE = 0x0070; 133 | #endif 134 | 135 | static const int DS4_MANUFACTURER_NAME_LENGTH = 0x38; 136 | static const int DS4_PRODUCT_NAME_LENGTH = 0x28; 137 | static const int DS4_OUTPUT_BUFFER_OFFSET = 0x04; 138 | static const int DS4_OUTPUT_BUFFER_LENGTH = 0x05; 139 | 140 | static const int DS4_REPORT_SIZE = 0x40; 141 | static const int DS4_QUEUE_FLUSH_PERIOD = 0x05; 142 | 143 | // 144 | // HID Input Report buffer 145 | // 146 | UCHAR _Report[DS4_REPORT_SIZE]; 147 | 148 | // 149 | // Output report cache 150 | // 151 | DS4_OUTPUT_REPORT _OutputReport; 152 | 153 | // 154 | // Timer for dispatching interrupt transfer 155 | // 156 | WDFTIMER _PendingUsbInRequestsTimer; 157 | 158 | // 159 | // Auto-generated MAC address of the target device 160 | // 161 | MAC_ADDRESS _TargetMacAddress; 162 | 163 | // 164 | // Default MAC address of the host (not used) 165 | // 166 | MAC_ADDRESS _HostMacAddress; 167 | 168 | // 169 | // User-mode notification on new output report 170 | // 171 | DMFMODULE _OutputReportNotify; 172 | 173 | // 174 | // Memory for full output report request 175 | // 176 | DS4_AWAIT_OUTPUT _AwaitOutputCache; 177 | }; 178 | } 179 | -------------------------------------------------------------------------------- /sys/EmulationTargetPDO.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver 3 | * 4 | * BSD 3-Clause License 5 | * 6 | * Copyright (c) 2018-2020, Nefarius Software Solutions e.U. and Contributors 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the copyright holder nor the names of its 20 | * contributors may be used to endorse or promote products derived from 21 | * this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | 36 | #pragma once 37 | 38 | #pragma warning(disable:5040) 39 | #include 40 | #pragma warning(default:5040) 41 | #include 42 | #include 43 | #include 44 | 45 | #include 46 | #include 47 | 48 | #include 49 | 50 | // 51 | // Some insane macro-magic =3 52 | // 53 | #define P99_PROTECT(...) __VA_ARGS__ 54 | #define COPY_BYTE_ARRAY(_dst_, _bytes_) do {BYTE b[] = _bytes_; \ 55 | RtlCopyMemory(_dst_, b, RTL_NUMBER_OF_V1(b)); } while (0) 56 | 57 | namespace ViGEm::Bus::Core 58 | { 59 | typedef struct _PDO_IDENTIFICATION_DESCRIPTION* PPDO_IDENTIFICATION_DESCRIPTION; 60 | 61 | class EmulationTargetPDO 62 | { 63 | public: 64 | EmulationTargetPDO(ULONG Serial, LONG SessionId, USHORT VendorId, USHORT ProductId); 65 | 66 | virtual ~EmulationTargetPDO() = default; 67 | 68 | static bool GetPdoByTypeAndSerial( 69 | IN WDFDEVICE ParentDevice, 70 | IN VIGEM_TARGET_TYPE Type, 71 | IN ULONG SerialNo, 72 | OUT EmulationTargetPDO** Object 73 | ); 74 | 75 | static NTSTATUS EnqueueWaitDeviceReady( 76 | WDFDEVICE ParentDevice, 77 | ULONG SerialNo, 78 | WDFREQUEST Request); 79 | 80 | static EVT_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; 81 | 82 | virtual NTSTATUS PdoPrepareDevice(PWDFDEVICE_INIT DeviceInit, 83 | PUNICODE_STRING DeviceId, 84 | PUNICODE_STRING DeviceDescription) = 0; 85 | 86 | virtual NTSTATUS PdoPrepareHardware() = 0; 87 | 88 | virtual NTSTATUS PdoInitContext() = 0; 89 | 90 | NTSTATUS PdoCreateDevice(_In_ WDFDEVICE ParentDevice, 91 | _In_ PWDFDEVICE_INIT DeviceInit); 92 | 93 | bool operator==(EmulationTargetPDO& other) const 94 | { 95 | return (other._SerialNo == this->_SerialNo); 96 | } 97 | 98 | virtual NTSTATUS UsbGetDeviceDescriptorType(PUSB_DEVICE_DESCRIPTOR pDescriptor) = 0; 99 | 100 | NTSTATUS UsbSelectConfiguration(PURB Urb); 101 | 102 | void UsbAbortPipe(); 103 | 104 | NTSTATUS UsbGetConfigurationDescriptorType(PURB Urb); 105 | 106 | virtual NTSTATUS UsbClassInterface(PURB Urb) = 0; 107 | 108 | virtual NTSTATUS UsbGetDescriptorFromInterface(PURB Urb) = 0; 109 | 110 | virtual NTSTATUS UsbSelectInterface(PURB Urb) = 0; 111 | 112 | virtual NTSTATUS UsbGetStringDescriptorType(PURB Urb) = 0; 113 | 114 | virtual NTSTATUS UsbBulkOrInterruptTransfer(struct _URB_BULK_OR_INTERRUPT_TRANSFER* pTransfer, 115 | WDFREQUEST Request) = 0; 116 | 117 | virtual NTSTATUS UsbControlTransfer(PURB Urb) = 0; 118 | 119 | NTSTATUS SubmitReport(PVOID NewReport); 120 | 121 | NTSTATUS EnqueueNotification(WDFREQUEST Request) const; 122 | 123 | bool IsOwnerProcess() const; 124 | 125 | VIGEM_TARGET_TYPE GetType() const; 126 | 127 | NTSTATUS PdoPrepare(WDFDEVICE ParentDevice); 128 | 129 | private: 130 | static unsigned long current_process_id(); 131 | 132 | static EVT_WDF_DEVICE_CONTEXT_CLEANUP EvtDeviceContextCleanup; 133 | 134 | static bool GetPdoBySerial( 135 | IN WDFDEVICE ParentDevice, 136 | IN ULONG SerialNo, 137 | OUT EmulationTargetPDO** Object 138 | ); 139 | 140 | NTSTATUS EnqueueWaitDeviceReady(WDFREQUEST Request); 141 | 142 | HANDLE _WaitDeviceReadyCompletionWorkerThreadHandle{}; 143 | 144 | protected: 145 | static const ULONG _maxHardwareIdLength = 0xFF; 146 | 147 | static const int MAX_INSTANCE_ID_LEN = 80; 148 | 149 | static const size_t MAX_OUT_BUFFER_QUEUE_COUNT = 64; 150 | 151 | static const size_t MAX_OUT_BUFFER_QUEUE_SIZE = 128; 152 | 153 | static PCWSTR _deviceLocation; 154 | 155 | static BOOLEAN USB_BUSIFFN UsbInterfaceIsDeviceHighSpeed(IN PVOID BusContext); 156 | 157 | static NTSTATUS USB_BUSIFFN UsbInterfaceQueryBusInformation( 158 | IN PVOID BusContext, 159 | IN ULONG Level, 160 | IN OUT PVOID BusInformationBuffer, 161 | IN OUT PULONG BusInformationBufferLength, 162 | OUT PULONG BusInformationActualLength 163 | ); 164 | 165 | static NTSTATUS USB_BUSIFFN UsbInterfaceSubmitIsoOutUrb(IN PVOID BusContext, IN PURB Urb); 166 | 167 | static NTSTATUS USB_BUSIFFN UsbInterfaceQueryBusTime(IN PVOID BusContext, IN OUT PULONG CurrentUsbFrame); 168 | 169 | static VOID USB_BUSIFFN UsbInterfaceGetUSBDIVersion( 170 | IN PVOID BusContext, 171 | IN OUT PUSBD_VERSION_INFORMATION VersionInformation, 172 | IN OUT PULONG HcdCapabilities 173 | ); 174 | 175 | static EVT_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware; 176 | 177 | static EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl; 178 | 179 | static EVT_WDF_IO_QUEUE_STATE EvtWdfIoPendingNotificationQueueState; 180 | 181 | static VOID WaitDeviceReadyCompletionWorkerRoutine(IN PVOID StartContext); 182 | 183 | static VOID DumpAsHex(PCSTR Prefix, PVOID Buffer, ULONG BufferLength); 184 | 185 | static VOID DmfDeviceModulesAdd(_In_ WDFDEVICE Device, _In_ PDMFMODULE_INIT DmfModuleInit); 186 | 187 | virtual VOID GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length) = 0; 188 | 189 | virtual NTSTATUS SelectConfiguration(PURB Urb) = 0; 190 | 191 | virtual void AbortPipe() = 0; 192 | 193 | virtual NTSTATUS SubmitReportImpl(PVOID NewReport) = 0; 194 | 195 | virtual VOID ProcessPendingNotification(WDFQUEUE Queue) = 0; 196 | 197 | virtual void DmfDeviceModulesAdd(_In_ PDMFMODULE_INIT DmfModuleInit) = 0; 198 | 199 | // 200 | // PNP Capabilities may differ from device to device 201 | // 202 | WDF_DEVICE_PNP_CAPABILITIES _PnpCapabilities; 203 | 204 | // 205 | // Power Capabilities may differ from device to device 206 | // 207 | WDF_DEVICE_POWER_CAPABILITIES _PowerCapabilities; 208 | 209 | // 210 | // Unique serial number of the device on the bus 211 | // 212 | ULONG _SerialNo{}; 213 | 214 | // 215 | // PID of the process creating this PDO 216 | // 217 | DWORD _OwnerProcessId{}; 218 | 219 | // 220 | // File object session ID 221 | // 222 | LONG _SessionId{}; 223 | 224 | // 225 | // Device type this PDO is emulating 226 | // 227 | VIGEM_TARGET_TYPE _TargetType; 228 | 229 | // 230 | // If set, the vendor ID the emulated device is reporting 231 | // 232 | USHORT _VendorId{}; 233 | 234 | // 235 | // If set, the product ID the emulated device is reporting 236 | // 237 | USHORT _ProductId{}; 238 | 239 | // 240 | // Queue for blocking plugin requests 241 | // 242 | WDFQUEUE _WaitDeviceReadyRequests{}; 243 | 244 | // 245 | // Queue for incoming data interrupt transfer 246 | // 247 | WDFQUEUE _PendingUsbInRequests{}; 248 | 249 | // 250 | // Queue for inverted calls 251 | // 252 | WDFQUEUE _PendingNotificationRequests{}; 253 | 254 | // 255 | // This child objects' device object 256 | // 257 | WDFDEVICE _PdoDevice{}; 258 | 259 | // 260 | // Configuration descriptor size (populated by derived class) 261 | // 262 | ULONG _UsbConfigurationDescriptionSize{}; 263 | 264 | // 265 | // Signals the bus that PDO is ready to receive data 266 | // 267 | KEVENT _PdoBootNotificationEvent; 268 | 269 | // 270 | // Queue for interrupt out requests delivered to user-land 271 | // 272 | DMFMODULE _UsbInterruptOutBufferQueue{}; 273 | }; 274 | 275 | typedef struct _PDO_IDENTIFICATION_DESCRIPTION 276 | { 277 | // 278 | // List entity header 279 | // 280 | WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Header; 281 | 282 | // 283 | // Primary key to identify PDO 284 | // 285 | ULONG SerialNo; 286 | 287 | // 288 | // Session ID 289 | // 290 | LONG SessionId; 291 | 292 | // 293 | // Context object of PDO 294 | // 295 | EmulationTargetPDO* Target; 296 | } PDO_IDENTIFICATION_DESCRIPTION, * PPDO_IDENTIFICATION_DESCRIPTION; 297 | 298 | typedef struct _EMULATION_TARGET_PDO_CONTEXT 299 | { 300 | EmulationTargetPDO* Target; 301 | } EMULATION_TARGET_PDO_CONTEXT, * PEMULATION_TARGET_PDO_CONTEXT; 302 | 303 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(EMULATION_TARGET_PDO_CONTEXT, EmulationTargetPdoGetContext) 304 | } 305 | -------------------------------------------------------------------------------- /sys/Queue.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver 3 | * 4 | * BSD 3-Clause License 5 | * 6 | * Copyright (c) 2018-2022, Nefarius Software Solutions e.U. and Contributors 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the copyright holder nor the names of its 20 | * contributors may be used to endorse or promote products derived from 21 | * this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | 36 | #include "Driver.h" 37 | #include "trace.h" 38 | #include "Queue.tmh" 39 | 40 | #include "EmulationTargetPDO.hpp" 41 | #include "XusbPdo.hpp" 42 | #include "Ds4Pdo.hpp" 43 | 44 | using ViGEm::Bus::Core::PDO_IDENTIFICATION_DESCRIPTION; 45 | using ViGEm::Bus::Core::EmulationTargetPDO; 46 | using ViGEm::Bus::Targets::EmulationTargetXUSB; 47 | using ViGEm::Bus::Targets::EmulationTargetDS4; 48 | 49 | 50 | EXTERN_C_START 51 | 52 | NTSTATUS 53 | Bus_CheckVersionHandler( 54 | _In_ DMFMODULE DmfModule, 55 | _In_ WDFQUEUE Queue, 56 | _In_ WDFREQUEST Request, 57 | _In_ ULONG IoctlCode, 58 | _In_reads_(InputBufferSize) VOID* InputBuffer, 59 | _In_ size_t InputBufferSize, 60 | _Out_writes_(OutputBufferSize) VOID* OutputBuffer, 61 | _In_ size_t OutputBufferSize, 62 | _Out_ size_t* BytesReturned 63 | ) 64 | { 65 | UNREFERENCED_PARAMETER(DmfModule); 66 | UNREFERENCED_PARAMETER(Queue); 67 | UNREFERENCED_PARAMETER(Request); 68 | UNREFERENCED_PARAMETER(IoctlCode); 69 | UNREFERENCED_PARAMETER(InputBufferSize); 70 | UNREFERENCED_PARAMETER(OutputBufferSize); 71 | UNREFERENCED_PARAMETER(OutputBuffer); 72 | UNREFERENCED_PARAMETER(BytesReturned); 73 | 74 | FuncEntry(TRACE_QUEUE); 75 | 76 | PVIGEM_CHECK_VERSION pCheckVersion = (PVIGEM_CHECK_VERSION)InputBuffer; 77 | 78 | NTSTATUS status = (pCheckVersion->Version == VIGEM_COMMON_VERSION) ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED; 79 | 80 | TraceVerbose( 81 | TRACE_QUEUE, 82 | "Requested version: 0x%04X, compiled version: 0x%04X", 83 | pCheckVersion->Version, VIGEM_COMMON_VERSION); 84 | 85 | FuncExit(TRACE_QUEUE, "status=%!STATUS!", status); 86 | 87 | return status; 88 | } 89 | 90 | NTSTATUS 91 | Bus_WaitDeviceReadyHandler( 92 | _In_ DMFMODULE DmfModule, 93 | _In_ WDFQUEUE Queue, 94 | _In_ WDFREQUEST Request, 95 | _In_ ULONG IoctlCode, 96 | _In_reads_(InputBufferSize) VOID* InputBuffer, 97 | _In_ size_t InputBufferSize, 98 | _Out_writes_(OutputBufferSize) VOID* OutputBuffer, 99 | _In_ size_t OutputBufferSize, 100 | _Out_ size_t* BytesReturned 101 | ) 102 | { 103 | UNREFERENCED_PARAMETER(DmfModule); 104 | UNREFERENCED_PARAMETER(Request); 105 | UNREFERENCED_PARAMETER(IoctlCode); 106 | UNREFERENCED_PARAMETER(InputBufferSize); 107 | UNREFERENCED_PARAMETER(OutputBufferSize); 108 | UNREFERENCED_PARAMETER(OutputBuffer); 109 | UNREFERENCED_PARAMETER(BytesReturned); 110 | 111 | NTSTATUS status; 112 | 113 | FuncEntry(TRACE_QUEUE); 114 | 115 | PVIGEM_WAIT_DEVICE_READY pWaitDeviceReady = (PVIGEM_WAIT_DEVICE_READY)InputBuffer; 116 | 117 | // This request only supports a single PDO at a time 118 | if (pWaitDeviceReady->SerialNo == 0) 119 | { 120 | TraceError( 121 | TRACE_QUEUE, 122 | "Invalid serial 0 submitted"); 123 | 124 | status = STATUS_INVALID_PARAMETER; 125 | goto exit; 126 | } 127 | 128 | status = EmulationTargetPDO::EnqueueWaitDeviceReady( 129 | WdfIoQueueGetDevice(Queue), 130 | pWaitDeviceReady->SerialNo, 131 | Request 132 | ); 133 | 134 | status = NT_SUCCESS(status) ? STATUS_PENDING : STATUS_DEVICE_DOES_NOT_EXIST; 135 | 136 | exit: 137 | FuncExit(TRACE_QUEUE, "status=%!STATUS!", status); 138 | 139 | return status; 140 | } 141 | 142 | NTSTATUS 143 | Bus_PluginTargetHandler( 144 | _In_ DMFMODULE DmfModule, 145 | _In_ WDFQUEUE Queue, 146 | _In_ WDFREQUEST Request, 147 | _In_ ULONG IoctlCode, 148 | _In_reads_(InputBufferSize) VOID* InputBuffer, 149 | _In_ size_t InputBufferSize, 150 | _Out_writes_(OutputBufferSize) VOID* OutputBuffer, 151 | _In_ size_t OutputBufferSize, 152 | _Out_ size_t* BytesReturned 153 | ) 154 | { 155 | UNREFERENCED_PARAMETER(DmfModule); 156 | UNREFERENCED_PARAMETER(Request); 157 | UNREFERENCED_PARAMETER(IoctlCode); 158 | UNREFERENCED_PARAMETER(InputBufferSize); 159 | UNREFERENCED_PARAMETER(InputBuffer); 160 | UNREFERENCED_PARAMETER(OutputBufferSize); 161 | UNREFERENCED_PARAMETER(OutputBuffer); 162 | UNREFERENCED_PARAMETER(BytesReturned); 163 | 164 | FuncEntry(TRACE_QUEUE); 165 | 166 | NTSTATUS status = Bus_PlugInDevice(WdfIoQueueGetDevice(Queue), Request, FALSE, BytesReturned); 167 | 168 | FuncExit(TRACE_QUEUE, "status=%!STATUS!", status); 169 | 170 | return status; 171 | } 172 | 173 | NTSTATUS 174 | Bus_UnplugTargetHandler( 175 | _In_ DMFMODULE DmfModule, 176 | _In_ WDFQUEUE Queue, 177 | _In_ WDFREQUEST Request, 178 | _In_ ULONG IoctlCode, 179 | _In_reads_(InputBufferSize) VOID* InputBuffer, 180 | _In_ size_t InputBufferSize, 181 | _Out_writes_(OutputBufferSize) VOID* OutputBuffer, 182 | _In_ size_t OutputBufferSize, 183 | _Out_ size_t* BytesReturned 184 | ) 185 | { 186 | UNREFERENCED_PARAMETER(DmfModule); 187 | UNREFERENCED_PARAMETER(Request); 188 | UNREFERENCED_PARAMETER(IoctlCode); 189 | UNREFERENCED_PARAMETER(InputBufferSize); 190 | UNREFERENCED_PARAMETER(InputBuffer); 191 | UNREFERENCED_PARAMETER(OutputBufferSize); 192 | UNREFERENCED_PARAMETER(OutputBuffer); 193 | UNREFERENCED_PARAMETER(BytesReturned); 194 | 195 | FuncEntry(TRACE_QUEUE); 196 | 197 | NTSTATUS status = Bus_UnPlugDevice(WdfIoQueueGetDevice(Queue), Request, FALSE, BytesReturned); 198 | 199 | FuncExit(TRACE_QUEUE, "status=%!STATUS!", status); 200 | 201 | return status; 202 | } 203 | 204 | NTSTATUS 205 | Bus_XusbSubmitReportHandler( 206 | _In_ DMFMODULE DmfModule, 207 | _In_ WDFQUEUE Queue, 208 | _In_ WDFREQUEST Request, 209 | _In_ ULONG IoctlCode, 210 | _In_reads_(InputBufferSize) VOID* InputBuffer, 211 | _In_ size_t InputBufferSize, 212 | _Out_writes_(OutputBufferSize) VOID* OutputBuffer, 213 | _In_ size_t OutputBufferSize, 214 | _Out_ size_t* BytesReturned 215 | ) 216 | { 217 | UNREFERENCED_PARAMETER(DmfModule); 218 | UNREFERENCED_PARAMETER(Request); 219 | UNREFERENCED_PARAMETER(IoctlCode); 220 | UNREFERENCED_PARAMETER(InputBufferSize); 221 | UNREFERENCED_PARAMETER(InputBuffer); 222 | UNREFERENCED_PARAMETER(OutputBufferSize); 223 | UNREFERENCED_PARAMETER(OutputBuffer); 224 | UNREFERENCED_PARAMETER(BytesReturned); 225 | 226 | FuncEntry(TRACE_QUEUE); 227 | 228 | NTSTATUS status; 229 | EmulationTargetPDO* pdo; 230 | PXUSB_SUBMIT_REPORT xusbSubmit = (PXUSB_SUBMIT_REPORT)InputBuffer; 231 | 232 | // This request only supports a single PDO at a time 233 | if (xusbSubmit->SerialNo == 0) 234 | { 235 | TraceError( 236 | TRACE_QUEUE, 237 | "Invalid serial 0 submitted"); 238 | 239 | status = STATUS_INVALID_PARAMETER; 240 | goto exit; 241 | } 242 | 243 | if (!EmulationTargetPDO::GetPdoByTypeAndSerial(WdfIoQueueGetDevice(Queue), Xbox360Wired, xusbSubmit->SerialNo, &pdo)) 244 | status = STATUS_DEVICE_DOES_NOT_EXIST; 245 | else 246 | status = pdo->SubmitReport(xusbSubmit); 247 | 248 | exit: 249 | FuncExit(TRACE_QUEUE, "status=%!STATUS!", status); 250 | 251 | return status; 252 | } 253 | 254 | NTSTATUS 255 | Bus_XusbRequestNotificationHandler( 256 | _In_ DMFMODULE DmfModule, 257 | _In_ WDFQUEUE Queue, 258 | _In_ WDFREQUEST Request, 259 | _In_ ULONG IoctlCode, 260 | _In_reads_(InputBufferSize) VOID* InputBuffer, 261 | _In_ size_t InputBufferSize, 262 | _Out_writes_(OutputBufferSize) VOID* OutputBuffer, 263 | _In_ size_t OutputBufferSize, 264 | _Out_ size_t* BytesReturned 265 | ) 266 | { 267 | UNREFERENCED_PARAMETER(DmfModule); 268 | UNREFERENCED_PARAMETER(Request); 269 | UNREFERENCED_PARAMETER(IoctlCode); 270 | UNREFERENCED_PARAMETER(InputBufferSize); 271 | UNREFERENCED_PARAMETER(InputBuffer); 272 | UNREFERENCED_PARAMETER(OutputBufferSize); 273 | UNREFERENCED_PARAMETER(OutputBuffer); 274 | UNREFERENCED_PARAMETER(BytesReturned); 275 | 276 | FuncEntry(TRACE_QUEUE); 277 | 278 | NTSTATUS status; 279 | EmulationTargetPDO* pdo; 280 | PXUSB_REQUEST_NOTIFICATION xusbNotify = (PXUSB_REQUEST_NOTIFICATION)InputBuffer; 281 | 282 | // This request only supports a single PDO at a time 283 | if (xusbNotify->SerialNo == 0) 284 | { 285 | TraceError( 286 | TRACE_QUEUE, 287 | "Invalid serial 0 submitted"); 288 | 289 | status = STATUS_INVALID_PARAMETER; 290 | goto exit; 291 | } 292 | 293 | if (!EmulationTargetPDO::GetPdoByTypeAndSerial(WdfIoQueueGetDevice(Queue), Xbox360Wired, xusbNotify->SerialNo, &pdo)) 294 | status = STATUS_DEVICE_DOES_NOT_EXIST; 295 | else 296 | { 297 | status = pdo->EnqueueNotification(Request); 298 | 299 | status = (NT_SUCCESS(status)) ? STATUS_PENDING : status; 300 | } 301 | 302 | exit: 303 | FuncExit(TRACE_QUEUE, "status=%!STATUS!", status); 304 | 305 | return status; 306 | } 307 | 308 | NTSTATUS 309 | Bus_Ds4SubmitReportHandler( 310 | _In_ DMFMODULE DmfModule, 311 | _In_ WDFQUEUE Queue, 312 | _In_ WDFREQUEST Request, 313 | _In_ ULONG IoctlCode, 314 | _In_reads_(InputBufferSize) VOID* InputBuffer, 315 | _In_ size_t InputBufferSize, 316 | _Out_writes_(OutputBufferSize) VOID* OutputBuffer, 317 | _In_ size_t OutputBufferSize, 318 | _Out_ size_t* BytesReturned 319 | ) 320 | { 321 | UNREFERENCED_PARAMETER(DmfModule); 322 | UNREFERENCED_PARAMETER(Request); 323 | UNREFERENCED_PARAMETER(IoctlCode); 324 | UNREFERENCED_PARAMETER(OutputBufferSize); 325 | UNREFERENCED_PARAMETER(OutputBuffer); 326 | UNREFERENCED_PARAMETER(BytesReturned); 327 | 328 | FuncEntry(TRACE_QUEUE); 329 | 330 | NTSTATUS status; 331 | EmulationTargetPDO* pdo; 332 | PDS4_SUBMIT_REPORT ds4Submit = (PDS4_SUBMIT_REPORT)InputBuffer; 333 | 334 | // 335 | // Check if buffer is within expected bounds 336 | // 337 | if (InputBufferSize < sizeof(DS4_SUBMIT_REPORT) || InputBufferSize > sizeof(DS4_SUBMIT_REPORT_EX)) 338 | { 339 | TraceVerbose( 340 | TRACE_QUEUE, 341 | "Unexpected buffer size: %d", 342 | static_cast(InputBufferSize) 343 | ); 344 | 345 | status = STATUS_INVALID_BUFFER_SIZE; 346 | goto exit; 347 | } 348 | 349 | // 350 | // Check if this makes sense before passing it on 351 | // 352 | if (InputBufferSize != ds4Submit->Size) 353 | { 354 | TraceVerbose( 355 | TRACE_QUEUE, 356 | "Invalid buffer size: %d", 357 | ds4Submit->Size 358 | ); 359 | 360 | status = STATUS_INVALID_BUFFER_SIZE; 361 | goto exit; 362 | } 363 | 364 | // 365 | // This request only supports a single PDO at a time 366 | // 367 | if (ds4Submit->SerialNo == 0) 368 | { 369 | TraceError( 370 | TRACE_QUEUE, 371 | "Invalid serial 0 submitted"); 372 | 373 | status = STATUS_INVALID_PARAMETER; 374 | goto exit; 375 | } 376 | 377 | if (!EmulationTargetPDO::GetPdoByTypeAndSerial(WdfIoQueueGetDevice(Queue), DualShock4Wired, ds4Submit->SerialNo, &pdo)) 378 | status = STATUS_DEVICE_DOES_NOT_EXIST; 379 | else 380 | status = pdo->SubmitReport(ds4Submit); 381 | 382 | exit: 383 | FuncExit(TRACE_QUEUE, "status=%!STATUS!", status); 384 | 385 | return status; 386 | } 387 | 388 | NTSTATUS 389 | Bus_Ds4RequestNotificationHandler( 390 | _In_ DMFMODULE DmfModule, 391 | _In_ WDFQUEUE Queue, 392 | _In_ WDFREQUEST Request, 393 | _In_ ULONG IoctlCode, 394 | _In_reads_(InputBufferSize) VOID* InputBuffer, 395 | _In_ size_t InputBufferSize, 396 | _Out_writes_(OutputBufferSize) VOID* OutputBuffer, 397 | _In_ size_t OutputBufferSize, 398 | _Out_ size_t* BytesReturned 399 | ) 400 | { 401 | UNREFERENCED_PARAMETER(DmfModule); 402 | UNREFERENCED_PARAMETER(Request); 403 | UNREFERENCED_PARAMETER(IoctlCode); 404 | UNREFERENCED_PARAMETER(OutputBufferSize); 405 | UNREFERENCED_PARAMETER(InputBufferSize); 406 | UNREFERENCED_PARAMETER(OutputBuffer); 407 | UNREFERENCED_PARAMETER(BytesReturned); 408 | 409 | FuncEntry(TRACE_QUEUE); 410 | 411 | NTSTATUS status; 412 | EmulationTargetPDO* pdo; 413 | PDS4_REQUEST_NOTIFICATION ds4Notify = (PDS4_REQUEST_NOTIFICATION)InputBuffer; 414 | 415 | // This request only supports a single PDO at a time 416 | if (ds4Notify->SerialNo == 0) 417 | { 418 | TraceError( 419 | TRACE_QUEUE, 420 | "Invalid serial 0 submitted"); 421 | 422 | status = STATUS_INVALID_PARAMETER; 423 | goto exit; 424 | } 425 | 426 | if (!EmulationTargetPDO::GetPdoByTypeAndSerial(WdfIoQueueGetDevice(Queue), DualShock4Wired, ds4Notify->SerialNo, &pdo)) 427 | status = STATUS_DEVICE_DOES_NOT_EXIST; 428 | else 429 | { 430 | status = pdo->EnqueueNotification(Request); 431 | 432 | status = (NT_SUCCESS(status)) ? STATUS_PENDING : status; 433 | } 434 | 435 | exit: 436 | FuncExit(TRACE_QUEUE, "status=%!STATUS!", status); 437 | 438 | return status; 439 | } 440 | 441 | NTSTATUS 442 | Bus_XusbGetUserIndexHandler( 443 | _In_ DMFMODULE DmfModule, 444 | _In_ WDFQUEUE Queue, 445 | _In_ WDFREQUEST Request, 446 | _In_ ULONG IoctlCode, 447 | _In_reads_(InputBufferSize) VOID* InputBuffer, 448 | _In_ size_t InputBufferSize, 449 | _Out_writes_(OutputBufferSize) VOID* OutputBuffer, 450 | _In_ size_t OutputBufferSize, 451 | _Out_ size_t* BytesReturned 452 | ) 453 | { 454 | UNREFERENCED_PARAMETER(DmfModule); 455 | UNREFERENCED_PARAMETER(Request); 456 | UNREFERENCED_PARAMETER(IoctlCode); 457 | UNREFERENCED_PARAMETER(OutputBufferSize); 458 | UNREFERENCED_PARAMETER(InputBufferSize); 459 | UNREFERENCED_PARAMETER(OutputBuffer); 460 | UNREFERENCED_PARAMETER(BytesReturned); 461 | 462 | FuncEntry(TRACE_QUEUE); 463 | 464 | NTSTATUS status; 465 | EmulationTargetPDO* pdo; 466 | PXUSB_GET_USER_INDEX pXusbGetUserIndex = (PXUSB_GET_USER_INDEX)InputBuffer; 467 | 468 | // This request only supports a single PDO at a time 469 | if (pXusbGetUserIndex->SerialNo == 0) 470 | { 471 | status = STATUS_INVALID_PARAMETER; 472 | goto exit; 473 | } 474 | 475 | if (!EmulationTargetPDO::GetPdoByTypeAndSerial(WdfIoQueueGetDevice(Queue), Xbox360Wired, pXusbGetUserIndex->SerialNo, &pdo)) 476 | { 477 | status = STATUS_DEVICE_DOES_NOT_EXIST; 478 | goto exit; 479 | } 480 | 481 | status = static_cast(pdo)->GetUserIndex(&pXusbGetUserIndex->UserIndex); 482 | 483 | exit: 484 | FuncExit(TRACE_QUEUE, "status=%!STATUS!", status); 485 | 486 | return status; 487 | } 488 | 489 | NTSTATUS 490 | Bus_Ds4AwaitOutputHandler( 491 | _In_ DMFMODULE DmfModule, 492 | _In_ WDFQUEUE Queue, 493 | _In_ WDFREQUEST Request, 494 | _In_ ULONG IoctlCode, 495 | _In_reads_(InputBufferSize) VOID* InputBuffer, 496 | _In_ size_t InputBufferSize, 497 | _Out_writes_(OutputBufferSize) VOID* OutputBuffer, 498 | _In_ size_t OutputBufferSize, 499 | _Out_ size_t* BytesReturned 500 | ) 501 | { 502 | UNREFERENCED_PARAMETER(Queue); 503 | UNREFERENCED_PARAMETER(IoctlCode); 504 | UNREFERENCED_PARAMETER(OutputBufferSize); 505 | UNREFERENCED_PARAMETER(InputBufferSize); 506 | UNREFERENCED_PARAMETER(InputBuffer); 507 | UNREFERENCED_PARAMETER(OutputBuffer); 508 | UNREFERENCED_PARAMETER(BytesReturned); 509 | 510 | FuncEntry(TRACE_QUEUE); 511 | 512 | NTSTATUS status; 513 | PFDO_DEVICE_DATA pDevCtx = FdoGetData(DMF_ParentDeviceGet(DmfModule)); 514 | 515 | if (!NT_SUCCESS(status = DMF_NotifyUserWithRequestMultiple_RequestProcess( 516 | pDevCtx->UserNotification, 517 | Request 518 | ))) 519 | { 520 | goto exit; 521 | } 522 | 523 | status = NT_SUCCESS(status) ? STATUS_PENDING : status; 524 | 525 | exit: 526 | FuncExit(TRACE_QUEUE, "status=%!STATUS!", status); 527 | 528 | return status; 529 | } 530 | 531 | EXTERN_C_END 532 | -------------------------------------------------------------------------------- /sys/Queue.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver 3 | * 4 | * BSD 3-Clause License 5 | * 6 | * Copyright (c) 2018-2020, Nefarius Software Solutions e.U. and Contributors 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the copyright holder nor the names of its 20 | * contributors may be used to endorse or promote products derived from 21 | * this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | 36 | #pragma once 37 | 38 | EXTERN_C_START 39 | 40 | EVT_DMF_IoctlHandler_Callback Bus_CheckVersionHandler; 41 | EVT_DMF_IoctlHandler_Callback Bus_WaitDeviceReadyHandler; 42 | EVT_DMF_IoctlHandler_Callback Bus_PluginTargetHandler; 43 | EVT_DMF_IoctlHandler_Callback Bus_UnplugTargetHandler; 44 | EVT_DMF_IoctlHandler_Callback Bus_XusbSubmitReportHandler; 45 | EVT_DMF_IoctlHandler_Callback Bus_XusbRequestNotificationHandler; 46 | EVT_DMF_IoctlHandler_Callback Bus_Ds4SubmitReportHandler; 47 | EVT_DMF_IoctlHandler_Callback Bus_Ds4RequestNotificationHandler; 48 | EVT_DMF_IoctlHandler_Callback Bus_XusbGetUserIndexHandler; 49 | EVT_DMF_IoctlHandler_Callback Bus_Ds4AwaitOutputHandler; 50 | 51 | EXTERN_C_END 52 | -------------------------------------------------------------------------------- /sys/ViGEmBus.inf: -------------------------------------------------------------------------------- 1 | ; Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver 2 | ; 3 | ; BSD 3-Clause License 4 | ; 5 | ; Copyright (c) 2018-2022, Nefarius Software Solutions e.U. and Contributors 6 | ; All rights reserved. 7 | ; 8 | ; Redistribution and use in source and binary forms, with or without 9 | ; modification, are permitted provided that the following conditions are met: 10 | ; 11 | ; 1. Redistributions of source code must retain the above copyright notice, this 12 | ; list of conditions and the following disclaimer. 13 | ; 14 | ; 2. Redistributions in binary form must reproduce the above copyright notice, 15 | ; this list of conditions and the following disclaimer in the documentation 16 | ; and/or other materials provided with the distribution. 17 | ; 18 | ; 3. Neither the name of the copyright holder nor the names of its 19 | ; contributors may be used to endorse or promote products derived from 20 | ; this software without specific prior written permission. 21 | ; 22 | ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | ; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | ; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | ; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 26 | ; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | ; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | ; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | ; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | ; OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | ; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | 34 | [Version] 35 | Signature="$WINDOWS NT$" 36 | Class=System 37 | ClassGuid={4D36E97D-E325-11CE-BFC1-08002BE10318} 38 | Provider=%ManufacturerName% 39 | CatalogFile=ViGEmBus.cat 40 | DriverVer= ; 41 | PnpLockdown=1 42 | 43 | [DestinationDirs] 44 | DefaultDestDir = 12 45 | ViGEmBus_Device_CoInstaller_CopyFiles = 11 46 | 47 | [SourceDisksNames] 48 | 1 = %DiskName%,,, 49 | 50 | [SourceDisksFiles] 51 | ViGEmBus.sys = 1,, 52 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll = 1 53 | 54 | ;***************************************** 55 | ; Install Section 56 | ;***************************************** 57 | 58 | [Manufacturer] 59 | %ManufacturerName%=Standard,NTamd64,NTx86,NTARM64 60 | 61 | [Standard.NTamd64] 62 | %ViGEmBus.DeviceDesc%=ViGEmBus_Device, Nefarius\ViGEmBus\Gen1 63 | 64 | [Standard.NTx86] 65 | %ViGEmBus.DeviceDesc%=ViGEmBus_Device, Nefarius\ViGEmBus\Gen1 66 | 67 | [Standard.NTARM64] 68 | %ViGEmBus.DeviceDesc%=ViGEmBus_Device, Nefarius\ViGEmBus\Gen1 69 | 70 | [ViGEmBus_Device.NT] 71 | CopyFiles=Drivers_Dir 72 | 73 | [Drivers_Dir] 74 | ViGEmBus.sys 75 | 76 | ;-------------- Service installation 77 | [ViGEmBus_Device.NT.Services] 78 | AddService = ViGEmBus,%SPSVCINST_ASSOCSERVICE%, ViGEmBus_Service_Inst 79 | 80 | ; -------------- ViGEmBus driver install sections 81 | [ViGEmBus_Service_Inst] 82 | DisplayName = %ViGEmBus.SVCDESC% 83 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 84 | StartType = 1 ; SERVICE_SYSTEM_START 85 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 86 | ServiceBinary = %12%\ViGEmBus.sys 87 | 88 | ; 89 | ;--- ViGEmBus_Device Coinstaller installation ------ 90 | ; 91 | 92 | [ViGEmBus_Device.NT.CoInstallers] 93 | AddReg=ViGEmBus_Device_CoInstaller_AddReg 94 | CopyFiles=ViGEmBus_Device_CoInstaller_CopyFiles 95 | 96 | [ViGEmBus_Device_CoInstaller_AddReg] 97 | HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" 98 | 99 | [ViGEmBus_Device_CoInstaller_CopyFiles] 100 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll 101 | 102 | [ViGEmBus_Device.NT.Wdf] 103 | KmdfService = ViGEmBus, ViGEmBus_wdfsect 104 | [ViGEmBus_wdfsect] 105 | KmdfLibraryVersion = $KMDFVERSION$ 106 | 107 | [Strings] 108 | SPSVCINST_ASSOCSERVICE= 0x00000002 109 | ManufacturerName="Nefarius Software Solutions e.U." 110 | DiskName = "Nefarius ViGEmBus Installation Disk" 111 | ViGEmBus.DeviceDesc = "Nefarius Virtual Gamepad Emulation Bus" 112 | ViGEmBus.SVCDESC = "Nefarius Virtual Gamepad Emulation Service" 113 | -------------------------------------------------------------------------------- /sys/ViGEmBus.rc: -------------------------------------------------------------------------------- 1 | // 2 | // Include the necessary resources 3 | // 4 | #include 5 | #include 6 | 7 | #ifdef RC_INVOKED 8 | 9 | // 10 | // Set up debug information 11 | // 12 | #if DBG 13 | #define VER_DBG VS_FF_DEBUG 14 | #else 15 | #define VER_DBG 0 16 | #endif 17 | 18 | // ------- version info ------------------------------------------------------- 19 | 20 | VS_VERSION_INFO VERSIONINFO 21 | FILEVERSION 1,16,200,0 22 | PRODUCTVERSION 1,16,200,0 23 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 24 | FILEFLAGS VER_DBG 25 | FILEOS VOS_NT 26 | FILETYPE VFT_DRV 27 | FILESUBTYPE VFT2_DRV_SYSTEM 28 | BEGIN 29 | BLOCK "StringFileInfo" 30 | BEGIN 31 | BLOCK "040904b0" 32 | BEGIN 33 | VALUE "Comments", "Virtual Gamepad Emulation Framework Bus Driver" 34 | VALUE "CompanyName", "Nefarius Software Solutions e.U." 35 | VALUE "FileDescription", "Virtual Gamepad Emulation Framework Bus Driver" 36 | VALUE "FileVersion", "1.16.200.0" 37 | VALUE "InternalName", "Virtual Gamepad Emulation Framework Bus Driver" 38 | VALUE "LegalCopyright", "(C) 2016-2022 Nefarius Software Solutions e.U." 39 | VALUE "OriginalFilename", "ViGEmBus.sys" 40 | VALUE "ProductName", "Virtual Gamepad Emulation Framework Bus Driver" 41 | VALUE "ProductVersion", "1.16.200.0" 42 | END 43 | END 44 | BLOCK "VarFileInfo" 45 | BEGIN 46 | VALUE "Translation", 0x0409,1200 47 | END 48 | END 49 | #endif -------------------------------------------------------------------------------- /sys/ViGEmBus.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | Debug 22 | ARM 23 | 24 | 25 | Release 26 | ARM 27 | 28 | 29 | Debug 30 | ARM64 31 | 32 | 33 | Release 34 | ARM64 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | {040101B0-EE5C-4EF1-99EE-9F81C795C001} 65 | {8c0e3d8b-df43-455b-815a-4a0e72973bc6} 66 | v4.5 67 | 12.0 68 | Debug 69 | Win32 70 | ViGEmBus 71 | 10.0.19041.0 72 | * 73 | $(APPVEYOR_BUILD_VERSION) 74 | 75 | 76 | WindowsKernelModeDriver10.0 77 | Driver 78 | KMDF 79 | Universal 80 | true 81 | 82 | 83 | WindowsKernelModeDriver10.0 84 | Driver 85 | KMDF 86 | Universal 87 | true 88 | Off 89 | 90 | 91 | WindowsKernelModeDriver10.0 92 | Driver 93 | KMDF 94 | Universal 95 | true 96 | 97 | 98 | WindowsKernelModeDriver10.0 99 | Driver 100 | KMDF 101 | Universal 102 | true 103 | Off 104 | 105 | 106 | WindowsKernelModeDriver10.0 107 | Driver 108 | KMDF 109 | Universal 110 | true 111 | 112 | 113 | WindowsKernelModeDriver10.0 114 | Driver 115 | KMDF 116 | Universal 117 | true 118 | 119 | 120 | WindowsKernelModeDriver10.0 121 | Driver 122 | KMDF 123 | Universal 124 | true 125 | 126 | 127 | WindowsKernelModeDriver10.0 128 | Driver 129 | KMDF 130 | Universal 131 | true 132 | Off 133 | 134 | 135 | 136 | Windows10 137 | true 138 | 139 | 140 | Windows10 141 | false 142 | 143 | 144 | Windows10 145 | true 146 | 147 | 148 | Windows10 149 | false 150 | 151 | 152 | Windows10 153 | true 154 | 155 | 156 | Windows10 157 | false 158 | 159 | 160 | Windows10 161 | true 162 | Spectre 163 | 164 | 165 | Windows10 166 | false 167 | Spectre 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | DbgengKernelDebugger 180 | $(SolutionDir)include;$(IncludePath);$(KMDF_INC_PATH)$(KMDF_VER_PATH) 181 | 182 | 183 | DbgengKernelDebugger 184 | $(SolutionDir)include;$(IncludePath);$(KMDF_INC_PATH)$(KMDF_VER_PATH) 185 | $(SolutionDir)bin\$(DDKPlatform)\ 186 | 187 | 188 | DbgengKernelDebugger 189 | $(SolutionDir)include;$(IncludePath);$(KMDF_INC_PATH)$(KMDF_VER_PATH) 190 | 191 | 192 | DbgengKernelDebugger 193 | $(SolutionDir)include;$(IncludePath);$(KMDF_INC_PATH)$(KMDF_VER_PATH) 194 | $(SolutionDir)bin\$(DDKPlatform)\ 195 | 196 | 197 | DbgengKernelDebugger 198 | 199 | 200 | DbgengKernelDebugger 201 | $(SolutionDir)bin\$(DDKPlatform)\ 202 | 203 | 204 | DbgengKernelDebugger 205 | 206 | 207 | DbgengKernelDebugger 208 | $(SolutionDir)bin\$(DDKPlatform)\ 209 | 210 | 211 | 212 | true 213 | true 214 | trace.h 215 | true 216 | POOL_NX_OPTIN=1;POOL_ZERO_DOWN_LEVEL_SUPPORT;_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions) 217 | stdcpp17 218 | $(SolutionDir)include;$(SolutionDir)sdk\include;$(IntDir);%(AdditionalIncludeDirectories) 219 | 220 | 221 | $(DDK_LIB_PATH)wdmsec.lib;%(AdditionalDependencies);ntstrsafe.lib;usbdex.lib 222 | 223 | 224 | 225 | 226 | true 227 | true 228 | trace.h 229 | true 230 | POOL_NX_OPTIN=1;POOL_ZERO_DOWN_LEVEL_SUPPORT;_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions) 231 | stdcpp17 232 | $(SolutionDir)include;$(SolutionDir)sdk\include;$(IntDir);%(AdditionalIncludeDirectories) 233 | MaxSpeed 234 | Speed 235 | true 236 | 237 | 238 | $(DDK_LIB_PATH)wdmsec.lib;%(AdditionalDependencies);ntstrsafe.lib;usbdex.lib 239 | 240 | 241 | 1.0.0.0 242 | 243 | 244 | 245 | 246 | true 247 | true 248 | trace.h 249 | true 250 | POOL_NX_OPTIN=1;POOL_ZERO_DOWN_LEVEL_SUPPORT;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions) 251 | stdcpp17 252 | $(SolutionDir)include;$(SolutionDir)sdk\include;$(IntDir);%(AdditionalIncludeDirectories) 253 | 254 | 255 | $(DDK_LIB_PATH)wdmsec.lib;%(AdditionalDependencies);ntstrsafe.lib;usbdex.lib 256 | 257 | 258 | 259 | 260 | true 261 | true 262 | trace.h 263 | true 264 | POOL_NX_OPTIN=1;POOL_ZERO_DOWN_LEVEL_SUPPORT;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions) 265 | stdcpp17 266 | $(SolutionDir)include;$(SolutionDir)sdk\include;$(IntDir);%(AdditionalIncludeDirectories) 267 | MaxSpeed 268 | Speed 269 | true 270 | 271 | 272 | $(DDK_LIB_PATH)wdmsec.lib;%(AdditionalDependencies);ntstrsafe.lib;usbdex.lib 273 | 274 | 275 | 1.0.0.0 276 | 277 | 278 | 279 | 280 | true 281 | true 282 | trace.h 283 | true 284 | $(SolutionDir)include;$(SolutionDir)sdk\include;$(IntDir);%(AdditionalIncludeDirectories) 285 | POOL_NX_OPTIN=1;POOL_ZERO_DOWN_LEVEL_SUPPORT;_ARM_;ARM;_USE_DECLSPECS_FOR_SAL=1;STD_CALL;%(PreprocessorDefinitions) 286 | 287 | 288 | %(AdditionalDependencies);ntstrsafe.lib 289 | 290 | 291 | 292 | 293 | true 294 | true 295 | trace.h 296 | true 297 | $(SolutionDir)include;$(SolutionDir)sdk\include;$(IntDir);%(AdditionalIncludeDirectories) 298 | POOL_NX_OPTIN=1;POOL_ZERO_DOWN_LEVEL_SUPPORT;_ARM_;ARM;_USE_DECLSPECS_FOR_SAL=1;STD_CALL;%(PreprocessorDefinitions) 299 | MaxSpeed 300 | Speed 301 | 302 | 303 | %(AdditionalDependencies);ntstrsafe.lib 304 | 305 | 306 | 307 | 308 | true 309 | true 310 | trace.h 311 | true 312 | $(SolutionDir)include;$(SolutionDir)sdk\include;$(IntDir);%(AdditionalIncludeDirectories) 313 | stdcpp17 314 | 5040;4064;4627;4627;4366;%(DisableSpecificWarnings) 315 | POOL_NX_OPTIN=1;POOL_ZERO_DOWN_LEVEL_SUPPORT;_ARM64_;ARM64;_USE_DECLSPECS_FOR_SAL=1;STD_CALL;%(PreprocessorDefinitions) 316 | 317 | 318 | %(AdditionalDependencies);ntstrsafe.lib;usbdex.lib 319 | 320 | 321 | 322 | 323 | true 324 | true 325 | trace.h 326 | true 327 | $(SolutionDir)include;$(SolutionDir)sdk\include;$(IntDir);%(AdditionalIncludeDirectories) 328 | stdcpp17 329 | 5040;4064;4627;4627;4366;%(DisableSpecificWarnings) 330 | POOL_NX_OPTIN=1;POOL_ZERO_DOWN_LEVEL_SUPPORT;_ARM64_;ARM64;_USE_DECLSPECS_FOR_SAL=1;STD_CALL;%(PreprocessorDefinitions) 331 | MaxSpeed 332 | Speed 333 | 334 | 335 | %(AdditionalDependencies);ntstrsafe.lib;usbdex.lib 336 | 337 | 338 | 1.0.0.0 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | -------------------------------------------------------------------------------- /sys/ViGEmBus.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | {b00da32a-ce46-490d-9e77-95bb90925995} 22 | 23 | 24 | {3a87fd70-9882-47c4-a23b-50dd0b42b0f8} 25 | 26 | 27 | 28 | 29 | Driver Files 30 | 31 | 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files\Targets 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | Header Files\Targets 50 | 51 | 52 | Header Files 53 | 54 | 55 | Header Files 56 | 57 | 58 | Header Files 59 | 60 | 61 | 62 | 63 | Source Files\Targets 64 | 65 | 66 | Source Files 67 | 68 | 69 | Source Files\Targets 70 | 71 | 72 | Source Files 73 | 74 | 75 | Source Files 76 | 77 | 78 | Source Files 79 | 80 | 81 | Source Files 82 | 83 | 84 | 85 | 86 | Resource Files 87 | 88 | 89 | -------------------------------------------------------------------------------- /sys/XusbPdo.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver 3 | * 4 | * BSD 3-Clause License 5 | * 6 | * Copyright (c) 2018-2020, Nefarius Software Solutions e.U. and Contributors 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the copyright holder nor the names of its 20 | * contributors may be used to endorse or promote products derived from 21 | * this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | 36 | #pragma once 37 | 38 | #include "EmulationTargetPDO.hpp" 39 | 40 | namespace ViGEm::Bus::Targets 41 | { 42 | constexpr auto XUSB_POOL_TAG = 'XUiV'; 43 | 44 | typedef struct _XUSB_INTERRUPT_IN_PACKET 45 | { 46 | UCHAR Id; 47 | 48 | UCHAR Size; 49 | 50 | XUSB_REPORT Report; 51 | } XUSB_INTERRUPT_IN_PACKET, *PXUSB_INTERRUPT_IN_PACKET; 52 | 53 | constexpr bool xusb_is_data_pipe(_URB_BULK_OR_INTERRUPT_TRANSFER* pTransfer) 54 | { 55 | return (pTransfer->PipeHandle == reinterpret_cast(0xFFFF0081)); 56 | } 57 | 58 | constexpr bool xusb_is_control_pipe(_URB_BULK_OR_INTERRUPT_TRANSFER* pTransfer) 59 | { 60 | return (pTransfer->PipeHandle == reinterpret_cast(0xFFFF0083)); 61 | } 62 | 63 | class EmulationTargetXUSB : public Core::EmulationTargetPDO 64 | { 65 | public: 66 | EmulationTargetXUSB(ULONG Serial, LONG SessionId, USHORT VendorId = 0x045E, USHORT ProductId = 0x028E); 67 | 68 | NTSTATUS PdoPrepareDevice(PWDFDEVICE_INIT DeviceInit, 69 | PUNICODE_STRING DeviceId, 70 | PUNICODE_STRING DeviceDescription) override; 71 | 72 | NTSTATUS PdoPrepareHardware() override; 73 | 74 | NTSTATUS PdoInitContext() override; 75 | 76 | VOID GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length) override; 77 | 78 | NTSTATUS UsbGetDeviceDescriptorType(PUSB_DEVICE_DESCRIPTOR pDescriptor) override; 79 | 80 | NTSTATUS SelectConfiguration(PURB Urb) override; 81 | 82 | void AbortPipe() override; 83 | 84 | NTSTATUS UsbClassInterface(PURB Urb) override; 85 | 86 | NTSTATUS UsbGetDescriptorFromInterface(PURB Urb) override; 87 | 88 | NTSTATUS UsbSelectInterface(PURB Urb) override; 89 | 90 | NTSTATUS UsbGetStringDescriptorType(PURB Urb) override; 91 | 92 | NTSTATUS UsbBulkOrInterruptTransfer(_URB_BULK_OR_INTERRUPT_TRANSFER* pTransfer, WDFREQUEST Request) override; 93 | 94 | NTSTATUS UsbControlTransfer(PURB Urb) override; 95 | 96 | NTSTATUS SubmitReportImpl(PVOID NewReport) override; 97 | 98 | NTSTATUS GetUserIndex(PULONG UserIndex) const; 99 | 100 | protected: 101 | void ProcessPendingNotification(WDFQUEUE Queue) override; 102 | void DmfDeviceModulesAdd(_In_ PDMFMODULE_INIT DmfModuleInit) override; 103 | private: 104 | static PCWSTR _deviceDescription; 105 | 106 | #if defined(_X86_) 107 | static const int XUSB_CONFIGURATION_SIZE = 0x00E4; 108 | #else 109 | static const int XUSB_CONFIGURATION_SIZE = 0x0130; 110 | #endif 111 | static const int XUSB_DESCRIPTOR_SIZE = 0x0099; 112 | static const int XUSB_RUMBLE_SIZE = 0x08; 113 | static const int XUSB_LEDSET_SIZE = 0x03; 114 | static const int XUSB_LEDNUM_SIZE = 0x01; 115 | static const int XUSB_INIT_STAGE_SIZE = 0x03; 116 | static const int XUSB_BLOB_STORAGE_SIZE = 0x2A; 117 | 118 | static const int XUSB_BLOB_00_OFFSET = 0x00; 119 | static const int XUSB_BLOB_01_OFFSET = 0x03; 120 | static const int XUSB_BLOB_02_OFFSET = 0x06; 121 | static const int XUSB_BLOB_03_OFFSET = 0x09; 122 | static const int XUSB_BLOB_04_OFFSET = 0x0C; 123 | static const int XUSB_BLOB_05_OFFSET = 0x20; 124 | static const int XUSB_BLOB_06_OFFSET = 0x23; 125 | static const int XUSB_BLOB_07_OFFSET = 0x26; 126 | 127 | // 128 | // Rumble buffer 129 | // 130 | UCHAR _Rumble[XUSB_RUMBLE_SIZE]; 131 | 132 | // 133 | // LED number (represents XInput slot index) 134 | // 135 | CHAR _LedNumber; 136 | 137 | // 138 | // Report packet 139 | // 140 | XUSB_INTERRUPT_IN_PACKET _Packet; 141 | 142 | // 143 | // Queue for incoming control interrupt transfer 144 | // 145 | WDFQUEUE _HoldingUsbInRequests; 146 | 147 | // 148 | // Required for XInputGetCapabilities to work 149 | // 150 | BOOLEAN _ReportedCapabilities; 151 | 152 | // 153 | // Required for XInputGetCapabilities to work 154 | // 155 | ULONG _InterruptInitStage; 156 | 157 | // 158 | // Storage of binary blobs (packets) for PDO initialization 159 | // 160 | WDFMEMORY _InterruptBlobStorage; 161 | }; 162 | } 163 | -------------------------------------------------------------------------------- /sys/busenum.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver 3 | * 4 | * BSD 3-Clause License 5 | * 6 | * Copyright (c) 2018-2022, Nefarius Software Solutions e.U. and Contributors 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the copyright holder nor the names of its 20 | * contributors may be used to endorse or promote products derived from 21 | * this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | 36 | #include "Driver.h" 37 | #include "trace.h" 38 | #include "busenum.tmh" 39 | 40 | #include "EmulationTargetPDO.hpp" 41 | #include "XusbPdo.hpp" 42 | #include "Ds4Pdo.hpp" 43 | 44 | #ifdef ALLOC_PRAGMA 45 | #pragma alloc_text (PAGE, Bus_PlugInDevice) 46 | #pragma alloc_text (PAGE, Bus_UnPlugDevice) 47 | #endif 48 | 49 | using ViGEm::Bus::Core::PDO_IDENTIFICATION_DESCRIPTION; 50 | using ViGEm::Bus::Core::EmulationTargetPDO; 51 | using ViGEm::Bus::Targets::EmulationTargetXUSB; 52 | using ViGEm::Bus::Targets::EmulationTargetDS4; 53 | 54 | // 55 | // Simulates a device plug-in event. 56 | // 57 | EXTERN_C NTSTATUS Bus_PlugInDevice( 58 | _In_ WDFDEVICE Device, 59 | _In_ WDFREQUEST Request, 60 | _In_ BOOLEAN IsInternal, 61 | _Out_ size_t* Transferred) 62 | { 63 | PDO_IDENTIFICATION_DESCRIPTION description; 64 | NTSTATUS status; 65 | PVIGEM_PLUGIN_TARGET plugIn; 66 | WDFFILEOBJECT fileObject; 67 | PFDO_FILE_DATA pFileData; 68 | size_t length = 0; 69 | 70 | UNREFERENCED_PARAMETER(IsInternal); 71 | 72 | PAGED_CODE(); 73 | 74 | 75 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSENUM, "%!FUNC! Entry"); 76 | 77 | status = WdfRequestRetrieveInputBuffer( 78 | Request, 79 | sizeof(VIGEM_PLUGIN_TARGET), 80 | reinterpret_cast(&plugIn), 81 | &length 82 | ); 83 | if (!NT_SUCCESS(status)) 84 | { 85 | TraceError( 86 | TRACE_BUSENUM, 87 | "WdfRequestRetrieveInputBuffer failed with status %!STATUS!", status); 88 | return status; 89 | } 90 | 91 | if ((sizeof(VIGEM_PLUGIN_TARGET) != plugIn->Size) || (length != plugIn->Size)) 92 | { 93 | TraceError( 94 | TRACE_BUSENUM, 95 | "sizeof(VIGEM_PLUGIN_TARGET) buffer size mismatch [%d != %d]", 96 | sizeof(VIGEM_PLUGIN_TARGET), plugIn->Size); 97 | return STATUS_INVALID_PARAMETER; 98 | } 99 | 100 | if (plugIn->SerialNo == 0) 101 | { 102 | TraceError( 103 | TRACE_BUSENUM, 104 | "Serial no. 0 not allowed"); 105 | return STATUS_INVALID_PARAMETER; 106 | } 107 | 108 | *Transferred = length; 109 | 110 | fileObject = WdfRequestGetFileObject(Request); 111 | if (fileObject == NULL) 112 | { 113 | TraceError( 114 | TRACE_BUSENUM, 115 | "WdfRequestGetFileObject failed to fetch WDFFILEOBJECT from request 0x%p", 116 | Request); 117 | return STATUS_INVALID_PARAMETER; 118 | } 119 | 120 | pFileData = FileObjectGetData(fileObject); 121 | if (pFileData == NULL) 122 | { 123 | TraceError( 124 | TRACE_BUSENUM, 125 | "FileObjectGetData failed to get context data for 0x%p", 126 | fileObject); 127 | return STATUS_INVALID_PARAMETER; 128 | } 129 | 130 | // 131 | // Initialize the description with the information about the newly 132 | // plugged in device. 133 | // 134 | WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&description.Header, sizeof(description)); 135 | 136 | description.SerialNo = plugIn->SerialNo; 137 | description.SessionId = pFileData->SessionId; 138 | 139 | // Set default IDs if supplied values are invalid 140 | if (plugIn->VendorId == 0 || plugIn->ProductId == 0) 141 | { 142 | switch (plugIn->TargetType) 143 | { 144 | case Xbox360Wired: 145 | 146 | description.Target = new EmulationTargetXUSB(plugIn->SerialNo, pFileData->SessionId); 147 | 148 | break; 149 | case DualShock4Wired: 150 | 151 | description.Target = new EmulationTargetDS4(plugIn->SerialNo, pFileData->SessionId); 152 | 153 | break; 154 | default: 155 | return STATUS_NOT_SUPPORTED; 156 | } 157 | } 158 | else 159 | { 160 | switch (plugIn->TargetType) 161 | { 162 | case Xbox360Wired: 163 | 164 | description.Target = new EmulationTargetXUSB( 165 | plugIn->SerialNo, 166 | pFileData->SessionId, 167 | plugIn->VendorId, 168 | plugIn->ProductId 169 | ); 170 | 171 | break; 172 | case DualShock4Wired: 173 | 174 | description.Target = new EmulationTargetDS4( 175 | plugIn->SerialNo, 176 | pFileData->SessionId, 177 | plugIn->VendorId, 178 | plugIn->ProductId 179 | ); 180 | 181 | break; 182 | default: 183 | return STATUS_NOT_SUPPORTED; 184 | } 185 | } 186 | 187 | if (!NT_SUCCESS(description.Target->PdoPrepare(Device))) 188 | { 189 | goto pluginEnd; 190 | } 191 | 192 | if (plugIn->TargetType == DualShock4Wired) 193 | { 194 | static_cast(description.Target)->SetOutputReportNotifyModule(FdoGetData(Device)->UserNotification); 195 | } 196 | 197 | status = WdfChildListAddOrUpdateChildDescriptionAsPresent( 198 | WdfFdoGetDefaultChildList(Device), 199 | &description.Header, 200 | NULL 201 | ); 202 | 203 | if (!NT_SUCCESS(status)) 204 | { 205 | TraceError( 206 | TRACE_BUSENUM, 207 | "WdfChildListAddOrUpdateChildDescriptionAsPresent failed with status %!STATUS!", 208 | status); 209 | 210 | goto pluginEnd; 211 | } 212 | 213 | // 214 | // The requested serial number is already in use 215 | // 216 | if (status == STATUS_OBJECT_NAME_EXISTS) 217 | { 218 | status = STATUS_INVALID_PARAMETER; 219 | 220 | TraceError( 221 | TRACE_BUSENUM, 222 | "The described PDO already exists (%!STATUS!)", 223 | status); 224 | 225 | goto pluginEnd; 226 | } 227 | 228 | pluginEnd: 229 | 230 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSENUM, "%!FUNC! Exit with status %!STATUS!", status); 231 | 232 | return status; 233 | } 234 | 235 | // 236 | // Simulates a device unplug event. 237 | // 238 | EXTERN_C NTSTATUS Bus_UnPlugDevice( 239 | _In_ WDFDEVICE Device, 240 | _In_ WDFREQUEST Request, 241 | _In_ BOOLEAN IsInternal, 242 | _Out_ size_t* Transferred) 243 | { 244 | NTSTATUS status; 245 | WDFDEVICE hChild; 246 | WDFCHILDLIST list; 247 | WDF_CHILD_LIST_ITERATOR iterator; 248 | WDF_CHILD_RETRIEVE_INFO childInfo; 249 | PDO_IDENTIFICATION_DESCRIPTION description; 250 | BOOLEAN unplugAll; 251 | PVIGEM_UNPLUG_TARGET unPlug; 252 | WDFFILEOBJECT fileObject; 253 | PFDO_FILE_DATA pFileData = NULL; 254 | size_t length = 0; 255 | 256 | PAGED_CODE(); 257 | 258 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSENUM, "%!FUNC! Entry"); 259 | 260 | status = WdfRequestRetrieveInputBuffer( 261 | Request, 262 | sizeof(VIGEM_UNPLUG_TARGET), 263 | (PVOID*)&unPlug, 264 | &length 265 | ); 266 | 267 | if (!NT_SUCCESS(status)) 268 | { 269 | TraceError( 270 | TRACE_BUSENUM, 271 | "WdfRequestRetrieveInputBuffer failed with status %!STATUS!", 272 | status); 273 | return status; 274 | } 275 | 276 | if ((sizeof(VIGEM_UNPLUG_TARGET) != unPlug->Size) || (length != unPlug->Size)) 277 | { 278 | TraceError( 279 | TRACE_BUSENUM, 280 | "sizeof(VIGEM_UNPLUG_TARGET) buffer size mismatch [%d != %d]", 281 | sizeof(VIGEM_UNPLUG_TARGET), unPlug->Size); 282 | return STATUS_INVALID_PARAMETER; 283 | } 284 | 285 | *Transferred = length; 286 | unplugAll = (unPlug->SerialNo == 0); 287 | 288 | fileObject = WdfRequestGetFileObject(Request); 289 | if (fileObject == NULL) 290 | { 291 | TraceError( 292 | TRACE_BUSENUM, 293 | "WdfRequestGetFileObject failed to fetch WDFFILEOBJECT from request 0x%p", 294 | Request); 295 | return STATUS_INVALID_PARAMETER; 296 | } 297 | 298 | pFileData = FileObjectGetData(fileObject); 299 | if (pFileData == NULL) 300 | { 301 | TraceError( 302 | TRACE_BUSENUM, 303 | "FileObjectGetData failed to get context data for 0x%p", 304 | fileObject); 305 | return STATUS_INVALID_PARAMETER; 306 | } 307 | 308 | TraceVerbose( 309 | TRACE_BUSENUM, 310 | "Starting child list traversal"); 311 | 312 | list = WdfFdoGetDefaultChildList(Device); 313 | 314 | WDF_CHILD_LIST_ITERATOR_INIT(&iterator, WdfRetrievePresentChildren); 315 | 316 | WdfChildListBeginIteration(list, &iterator); 317 | 318 | for (;;) 319 | { 320 | WDF_CHILD_RETRIEVE_INFO_INIT(&childInfo, &description.Header); 321 | WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&description.Header, sizeof(description)); 322 | 323 | status = WdfChildListRetrieveNextDevice(list, &iterator, &hChild, &childInfo); 324 | 325 | // Error or no more children, end loop 326 | if (!NT_SUCCESS(status) || status == STATUS_NO_MORE_ENTRIES) 327 | { 328 | TraceVerbose( 329 | TRACE_BUSENUM, 330 | "WdfChildListRetrieveNextDevice returned with status %!STATUS!", 331 | status); 332 | break; 333 | } 334 | 335 | // If unable to retrieve device 336 | if (childInfo.Status != WdfChildListRetrieveDeviceSuccess) 337 | { 338 | TraceVerbose( 339 | TRACE_BUSENUM, 340 | "childInfo.Status = %d", 341 | childInfo.Status); 342 | continue; 343 | } 344 | 345 | // Child isn't the one we looked for, skip 346 | if (!unplugAll && description.SerialNo != unPlug->SerialNo) 347 | { 348 | TraceVerbose( 349 | TRACE_BUSENUM, 350 | "Seeking serial mismatch: %d != %d", 351 | description.SerialNo, 352 | unPlug->SerialNo); 353 | continue; 354 | } 355 | 356 | TraceVerbose( 357 | TRACE_BUSENUM, 358 | "description.SessionId = %d, pFileData->SessionId = %d", 359 | description.SessionId, 360 | pFileData->SessionId); 361 | 362 | // Only unplug owned children 363 | if (IsInternal || description.SessionId == pFileData->SessionId) 364 | { 365 | // Unplug child 366 | status = WdfChildListUpdateChildDescriptionAsMissing(list, &description.Header); 367 | if (!NT_SUCCESS(status)) 368 | { 369 | TraceError( 370 | TRACE_BUSENUM, 371 | "WdfChildListUpdateChildDescriptionAsMissing failed with status %!STATUS!", 372 | status); 373 | } 374 | } 375 | } 376 | 377 | WdfChildListEndIteration(list, &iterator); 378 | 379 | TraceVerbose( 380 | TRACE_BUSENUM, 381 | "Finished child list traversal"); 382 | 383 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSENUM, "%!FUNC! Exit with status %!STATUS!", STATUS_SUCCESS); 384 | 385 | return STATUS_SUCCESS; 386 | } 387 | -------------------------------------------------------------------------------- /sys/buspdo.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver 3 | * 4 | * BSD 3-Clause License 5 | * 6 | * Copyright (c) 2018-2022, Nefarius Software Solutions e.U. and Contributors 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the copyright holder nor the names of its 20 | * contributors may be used to endorse or promote products derived from 21 | * this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | 36 | #include "Driver.h" 37 | #include "EmulationTargetPDO.hpp" 38 | 39 | #ifdef ALLOC_PRAGMA 40 | #pragma alloc_text(PAGE, Bus_EvtDeviceListCreatePdo) 41 | #endif 42 | 43 | EXTERN_C NTSTATUS Bus_EvtDeviceListCreatePdo( 44 | WDFCHILDLIST DeviceList, 45 | PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, 46 | PWDFDEVICE_INIT ChildInit) 47 | { 48 | ViGEm::Bus::Core::PPDO_IDENTIFICATION_DESCRIPTION pDesc; 49 | 50 | PAGED_CODE(); 51 | 52 | pDesc = CONTAINING_RECORD(IdentificationDescription, ViGEm::Bus::Core::PDO_IDENTIFICATION_DESCRIPTION, Header); 53 | 54 | return pDesc->Target->PdoCreateDevice(WdfChildListGetDevice(DeviceList), ChildInit); 55 | } 56 | -------------------------------------------------------------------------------- /sys/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by ViGEmBus.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /sys/trace.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver 3 | * 4 | * BSD 3-Clause License 5 | * 6 | * Copyright (c) 2018-2022, Nefarius Software Solutions e.U. and Contributors 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the copyright holder nor the names of its 20 | * contributors may be used to endorse or promote products derived from 21 | * this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | 36 | // 37 | // Define the tracing flags. 38 | // 39 | // Tracing GUID - c5ce18fe-27bd-4049-b0b4-8a47cab1dcd9 40 | // 41 | 42 | #define WPP_CONTROL_GUIDS \ 43 | WPP_DEFINE_CONTROL_GUID( \ 44 | ViGEmBusTraceGuid, (c5ce18fe,27bd,4049,b0b4,8a47cab1dcd9), \ 45 | \ 46 | WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ 47 | WPP_DEFINE_BIT(DMF_TRACE) \ 48 | WPP_DEFINE_BIT(TRACE_BUSENUM) \ 49 | WPP_DEFINE_BIT(TRACE_BUSPDO) \ 50 | WPP_DEFINE_BIT(TRACE_BYTEARRAY) \ 51 | WPP_DEFINE_BIT(TRACE_DRIVER) \ 52 | WPP_DEFINE_BIT(TRACE_DS4) \ 53 | WPP_DEFINE_BIT(TRACE_QUEUE) \ 54 | WPP_DEFINE_BIT(TRACE_USBPDO) \ 55 | WPP_DEFINE_BIT(TRACE_UTIL) \ 56 | WPP_DEFINE_BIT(TRACE_XGIP) \ 57 | WPP_DEFINE_BIT(TRACE_XUSB) \ 58 | ) 59 | 60 | #define WPP_FLAG_LEVEL_LOGGER(flag, level) \ 61 | WPP_LEVEL_LOGGER(flag) 62 | 63 | #define WPP_FLAG_LEVEL_ENABLED(flag, level) \ 64 | (WPP_LEVEL_ENABLED(flag) && \ 65 | WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) 66 | 67 | #define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \ 68 | WPP_LEVEL_LOGGER(flags) 69 | 70 | #define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \ 71 | (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) 72 | 73 | // 74 | // This comment block is scanned by the trace preprocessor to define our 75 | // Trace function. 76 | // 77 | // USEPREFIX and USESUFFIX strip all trailing whitespace, so we need to surround 78 | // FuncExit messages with brackets 79 | // 80 | // begin_wpp config 81 | // FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); 82 | // FUNC TraceEvents(LEVEL, FLAGS, MSG, ...); 83 | // FUNC FuncEntry{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS); 84 | // FUNC FuncEntryArguments{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS, MSG, ...); 85 | // FUNC FuncExit{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS, MSG, ...); 86 | // FUNC FuncExitVoid{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS); 87 | // FUNC TraceError{LEVEL=TRACE_LEVEL_ERROR}(FLAGS, MSG, ...); 88 | // FUNC TraceInformation{LEVEL=TRACE_LEVEL_INFORMATION}(FLAGS, MSG, ...); 89 | // FUNC TraceVerbose{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS, MSG, ...); 90 | // FUNC FuncExitNoReturn{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS); 91 | // USEPREFIX(FuncEntry, "%!STDPREFIX! [%!FUNC!] --> Entry"); 92 | // USEPREFIX(FuncEntryArguments, "%!STDPREFIX! [%!FUNC!] --> Entry <"); 93 | // USEPREFIX(FuncExit, "%!STDPREFIX! [%!FUNC!] <-- Exit <"); 94 | // USESUFFIX(FuncExit, ">"); 95 | // USEPREFIX(FuncExitVoid, "%!STDPREFIX! [%!FUNC!] <-- Exit"); 96 | // USEPREFIX(TraceError, "%!STDPREFIX! [%!FUNC!] ERROR:"); 97 | // USEPREFIX(TraceEvents, "%!STDPREFIX! [%!FUNC!] "); 98 | // USEPREFIX(TraceInformation, "%!STDPREFIX! [%!FUNC!] "); 99 | // USEPREFIX(TraceVerbose, "%!STDPREFIX! [%!FUNC!] "); 100 | // USEPREFIX(FuncExitNoReturn, "%!STDPREFIX! [%!FUNC!] <--"); 101 | // end_wpp 102 | -------------------------------------------------------------------------------- /updates.txt: -------------------------------------------------------------------------------- 1 | ;aiu; 2 | 3 | [ViGEmBus_1.16.115] 4 | Name = ViGEm Bus Driver 1.16.115 5 | URL = https://github.com/ViGEm/ViGEmBus/releases/download/v1.16.112/ViGEmBus_Setup_1.16.115.exe 6 | Size = 14310704 7 | Description = This release fixes a few issues with the setup itself. It contains no newer driver than the previous version. 8 | BugFix = Setup can fail on Windows 7 due to unhandled exception in removal action 9 | Enhancement = Disabled the Modify option in the setup as it serves no purpose 10 | RegistryKey = HKLM\Software\Nefarius Software Solutions e.U.\ViGEm Bus Driver\Version 11 | Version = 1.16.115 12 | 13 | [ViGEmBus_1.16.112] 14 | Name = ViGEm Bus Driver 1.16.112 15 | URL = https://github.com/ViGEm/ViGEmBus/releases/download/v1.16.112/ViGEmBus_Setup_1.16.112.exe 16 | Size = 14308440 17 | RegistryKey = HKLM\Software\Nefarius Software Solutions e.U.\ViGEm Bus Driver\Version 18 | Version = 1.16.112 19 | --------------------------------------------------------------------------------