fix(windows-installer): build the gamepad drivers from source in CI too
Fold the pf-dualsense (DualSense / DualShock 4) and pf-xusb (Xbox 360 / XInput)
UMDF drivers into the in-tree drivers workspace (their source had stale
../../crates/wdk-* path-deps from before the wdk vendoring reorg and could no
longer build at all) and build them from source per release, exactly like
pf-vdisplay - same anti-stale reasoning. One `cargo build --release` now builds
all three drivers against the vendored wdk-sys (incl. the bindgen 0.72 pin), and
build-gamepad-drivers.ps1 signs pf_dualsense + pf_xusb (clear FORCE_INTEGRITY ->
sign dll -> stampinf -> Inf2Cat -> sign cat) with one shared cert + .cer,
matching the layout install-gamepad-drivers.ps1 expects. pack-host-installer.ps1
builds + stages them instead of the retired checked-in binaries.
Validated on the runner: the whole workspace (pf-vdisplay + pf-dualsense +
pf-xusb) builds with CARGO_TARGET_DIR=C:\t set, and build-gamepad-drivers.ps1
produces signed pf_dualsense.{dll,inf,cat} + pf_xusb.{dll,inf,cat} + the .cer.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Build + sign the punktfunk virtual-gamepad UMDF drivers (pf-dualsense = DualSense/DualShock 4, pf-xusb =
|
||||
Xbox 360 / XInput) FROM SOURCE, in CI, and stage them for the host installer. The gamepad analogue of
|
||||
build-pf-vdisplay.ps1 - replaces the checked-in prebuilt binaries (packaging/windows/gamepad-drivers/)
|
||||
so the .dll/.inf/.cat stay in lockstep with the source and never go stale.
|
||||
|
||||
.DESCRIPTION
|
||||
Both drivers are members of the in-tree drivers workspace (packaging/windows/drivers/), so one
|
||||
`cargo build --release` builds the whole workspace (this shares wdk-sys/wdk-build + the bindgen pin with
|
||||
pf-vdisplay). Then, per driver: CLEAR the FORCE_INTEGRITY PE bit, sign the .dll, stampinf a DriverVer
|
||||
into the INF; then Inf2Cat both catalogs and sign them. Both drivers share ONE self-signed cert (or a
|
||||
supplied DRIVER_CERT secret) + ONE exported .cer, matching the vendored gamepad-drivers/ layout that
|
||||
install-gamepad-drivers.ps1 expects.
|
||||
|
||||
Output (-Out): pf_dualsense.{dll,inf,cat} + pf_xusb.{dll,inf,cat} + punktfunk-driver.cer.
|
||||
|
||||
.EXAMPLE
|
||||
pwsh -File build-gamepad-drivers.ps1 -Out C:\t\gamepad
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$DriversDir = (Join-Path $PSScriptRoot 'drivers'),
|
||||
[Parameter(Mandatory = $true)][string]$Out,
|
||||
[string]$DriverVer,
|
||||
[string]$CertPfxB64 = $env:DRIVER_CERT_PFX_B64,
|
||||
[string]$CertPassword = $env:DRIVER_CERT_PASSWORD,
|
||||
[switch]$SkipBuild
|
||||
)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
$PSNativeCommandUseErrorActionPreference = $false
|
||||
|
||||
$DriversDir = (Resolve-Path $DriversDir).Path
|
||||
$clear = Join-Path $PSScriptRoot 'clear-force-integrity.ps1'
|
||||
|
||||
$drivers = @(
|
||||
@{ crate = 'pf-dualsense'; dll = 'pf_dualsense.dll'; inx = 'pf-dualsense\pf_dualsense.inx'; inf = 'pf_dualsense.inf'; cat = 'pf_dualsense.cat' }
|
||||
@{ crate = 'pf-xusb'; dll = 'pf_xusb.dll'; inx = 'pf-xusb\pf_xusb.inx'; inf = 'pf_xusb.inf'; cat = 'pf_xusb.cat' }
|
||||
)
|
||||
foreach ($d in $drivers) {
|
||||
if (-not (Test-Path (Join-Path $DriversDir $d.inx))) { throw "no $($d.inx) under $DriversDir" }
|
||||
}
|
||||
|
||||
# --- WDK build env ----------------------------------------------------------------------------
|
||||
if (-not $env:Version_Number) { $env:Version_Number = '10.0.26100.0' }
|
||||
if (-not $env:LIBCLANG_PATH -and (Test-Path 'C:\Program Files\LLVM\bin\libclang.dll')) {
|
||||
$env:LIBCLANG_PATH = 'C:\Program Files\LLVM\bin'
|
||||
}
|
||||
# Build into the DEFAULT workspace target dir (not an external CARGO_TARGET_DIR) - wdk-build walks up
|
||||
# from OUT_DIR for a Cargo.lock and doesn't support out-of-tree target dirs. See build-pf-vdisplay.ps1.
|
||||
$rel = Join-Path $DriversDir 'target\x86_64-pc-windows-msvc\release'
|
||||
|
||||
# --- 1. build (release) - one build covers the whole workspace --------------------------------
|
||||
if (-not $SkipBuild) {
|
||||
Write-Host "==> cargo build --release (drivers workspace) in $DriversDir"
|
||||
$prevTarget = $env:CARGO_TARGET_DIR
|
||||
Remove-Item Env:\CARGO_TARGET_DIR -ErrorAction SilentlyContinue
|
||||
Push-Location $DriversDir
|
||||
& cargo build --release
|
||||
$rc = $LASTEXITCODE
|
||||
Pop-Location
|
||||
if ($prevTarget) { $env:CARGO_TARGET_DIR = $prevTarget } else { Remove-Item Env:\CARGO_TARGET_DIR -ErrorAction SilentlyContinue }
|
||||
if ($rc -ne 0) { throw "gamepad drivers cargo build failed ($rc)" }
|
||||
}
|
||||
foreach ($d in $drivers) {
|
||||
if (-not (Test-Path (Join-Path $rel $d.dll))) { throw "driver not built: $(Join-Path $rel $d.dll)" }
|
||||
}
|
||||
|
||||
# --- 2. WDK sign tools ------------------------------------------------------------------------
|
||||
$kits = 'C:\Program Files (x86)\Windows Kits\10\bin'
|
||||
function Find-Tool([string]$name, [string]$arch) {
|
||||
(Get-ChildItem "$kits\*\$arch\$name" -ErrorAction SilentlyContinue | Sort-Object FullName | Select-Object -Last 1).FullName
|
||||
}
|
||||
$signtool = Find-Tool 'signtool.exe' 'x64'
|
||||
$stampinf = Find-Tool 'stampinf.exe' 'x64'
|
||||
$inf2cat = Find-Tool 'Inf2Cat.exe' 'x86'
|
||||
foreach ($t in @($signtool, $stampinf, $inf2cat)) {
|
||||
if (-not $t) { throw 'a WDK tool (signtool/stampinf/Inf2Cat) was not found - install the Windows 10/11 WDK.' }
|
||||
}
|
||||
|
||||
# --- 3. signing cert (supplied stable pfx OR fresh self-signed; shared by both drivers) -------
|
||||
$cleanupCert = $null
|
||||
if ($CertPfxB64) {
|
||||
Write-Host '==> signing with supplied driver cert (DRIVER_CERT_PFX_B64)'
|
||||
$pfx = Join-Path (Split-Path -Parent $Out) 'driver-signing.pfx'
|
||||
[IO.File]::WriteAllBytes($pfx, [Convert]::FromBase64String($CertPfxB64))
|
||||
$sec = if ($CertPassword) { ConvertTo-SecureString $CertPassword -AsPlainText -Force } else { $null }
|
||||
$signArgs = @('/f', $pfx); if ($CertPassword) { $signArgs += @('/p', $CertPassword) }
|
||||
$pubForCer = if ($sec) { Get-PfxCertificate -FilePath $pfx -Password $sec } else { Get-PfxCertificate -FilePath $pfx }
|
||||
}
|
||||
else {
|
||||
Write-Host '==> no DRIVER_CERT_PFX_B64 -> generating a fresh self-signed driver cert (the installer trusts the bundled .cer at install time)'
|
||||
$cleanupCert = New-SelfSignedCertificate -Type CodeSigningCert -Subject 'CN=punktfunk-driver' `
|
||||
-CertStoreLocation Cert:\CurrentUser\My -KeyExportPolicy Exportable -NotAfter (Get-Date).AddYears(10)
|
||||
$signArgs = @('/sha1', $cleanupCert.Thumbprint)
|
||||
$pubForCer = $cleanupCert
|
||||
}
|
||||
|
||||
# --- 4. stage + clear FORCE_INTEGRITY + sign dlls + stampinf infs ------------------------------
|
||||
if (Test-Path $Out) { Remove-Item $Out -Recurse -Force }
|
||||
New-Item -ItemType Directory -Force -Path $Out | Out-Null
|
||||
if (-not $DriverVer) { $now = Get-Date; $DriverVer = '9.9.{0}.{1}' -f $now.ToString('MMdd'), $now.ToString('HHmm') }
|
||||
|
||||
foreach ($d in $drivers) {
|
||||
$sDll = Join-Path $Out $d.dll
|
||||
$sInf = Join-Path $Out $d.inf
|
||||
Copy-Item (Join-Path $rel $d.dll) $sDll -Force
|
||||
Copy-Item (Join-Path $DriversDir $d.inx) $sInf -Force # stampinf rewrites this copy in place
|
||||
& powershell -NoProfile -ExecutionPolicy Bypass -File $clear -Path $sDll | Out-Null
|
||||
& $signtool sign /fd SHA256 @signArgs $sDll | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) { throw "signtool sign ($($d.dll)) failed ($LASTEXITCODE)" }
|
||||
& $stampinf -f $sInf -d '*' -a 'amd64' -u '2.15.0' -v $DriverVer | Out-Null
|
||||
}
|
||||
|
||||
# --- 5. Inf2Cat both catalogs (one pass over -Out), then sign each -----------------------------
|
||||
& $inf2cat /driver:$Out /os:10_X64 /uselocaltime | Out-Null
|
||||
foreach ($d in $drivers) {
|
||||
$sCat = Join-Path $Out $d.cat
|
||||
if (-not (Test-Path $sCat)) { throw "Inf2Cat did not produce $sCat" }
|
||||
& $signtool sign /fd SHA256 @signArgs $sCat | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) { throw "signtool sign ($($d.cat)) failed ($LASTEXITCODE)" }
|
||||
}
|
||||
|
||||
# --- 6. one shared public .cer ----------------------------------------------------------------
|
||||
Export-Certificate -Cert $pubForCer -FilePath (Join-Path $Out 'punktfunk-driver.cer') | Out-Null
|
||||
if ($cleanupCert) { Remove-Item "Cert:\CurrentUser\My\$($cleanupCert.Thumbprint)" -Force -ErrorAction SilentlyContinue }
|
||||
|
||||
Write-Host "==> built + signed gamepad drivers DriverVer=$DriverVer -> $Out"
|
||||
Get-ChildItem $Out -File | ForEach-Object { " $($_.Name) ($($_.Length) bytes)" }
|
||||
Generated
+20
-2
@@ -63,9 +63,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.102"
|
||||
version = "1.0.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||
checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
@@ -401,6 +401,15 @@ dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pf-dualsense"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"wdk",
|
||||
"wdk-build",
|
||||
"wdk-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pf-vdisplay"
|
||||
version = "0.0.1"
|
||||
@@ -414,6 +423,15 @@ dependencies = [
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pf-xusb"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"wdk",
|
||||
"wdk-build",
|
||||
"wdk-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.17"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# crates/pf-driver-proto from the main tree.
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["wdk-probe", "wdk-iddcx", "pf-vdisplay"]
|
||||
members = ["wdk-probe", "wdk-iddcx", "pf-vdisplay", "pf-dualsense", "pf-xusb"]
|
||||
|
||||
[workspace.package]
|
||||
edition = "2024"
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# pf-dualsense - punktfunk virtual DualSense (DS5) / DualShock 4 (DS4) UMDF2 HID minidriver.
|
||||
# A member of the in-tree drivers workspace (shares the vendored wdk-sys/wdk-build with the bindgen pin
|
||||
# + the crt-static .cargo/config), built from source per release like pf-vdisplay.
|
||||
[package]
|
||||
name = "pf-dualsense"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
publish = false
|
||||
description = "punktfunk virtual DualSense / DualShock 4 UMDF2 HID minidriver"
|
||||
|
||||
[package.metadata.wdk.driver-model]
|
||||
driver-type = "UMDF"
|
||||
umdf-version-major = 2
|
||||
target-umdf-version-minor = 31
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[build-dependencies]
|
||||
wdk-build.workspace = true
|
||||
|
||||
[dependencies]
|
||||
wdk.workspace = true
|
||||
wdk-sys.workspace = true
|
||||
|
||||
[features]
|
||||
default = ["hid"]
|
||||
hid = ["wdk-sys/hid"]
|
||||
nightly = ["wdk-sys/nightly", "wdk/nightly"]
|
||||
@@ -0,0 +1,29 @@
|
||||
# pf-xusb - punktfunk virtual Xbox 360 XUSB companion (UMDF2, classic XInput).
|
||||
# A member of the in-tree drivers workspace (shares the vendored wdk-sys/wdk-build with the bindgen pin
|
||||
# + the crt-static .cargo/config), built from source per release like pf-vdisplay.
|
||||
[package]
|
||||
name = "pf-xusb"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
publish = false
|
||||
description = "punktfunk virtual Xbox 360 XUSB companion (UMDF2 - classic XInput)"
|
||||
|
||||
[package.metadata.wdk.driver-model]
|
||||
driver-type = "UMDF"
|
||||
umdf-version-major = 2
|
||||
target-umdf-version-minor = 31
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[build-dependencies]
|
||||
wdk-build.workspace = true
|
||||
|
||||
[dependencies]
|
||||
wdk.workspace = true
|
||||
wdk-sys.workspace = true
|
||||
|
||||
[features]
|
||||
default = []
|
||||
nightly = ["wdk-sys/nightly", "wdk/nightly"]
|
||||
@@ -1,36 +0,0 @@
|
||||
[package]
|
||||
edition = "2024"
|
||||
name = "pf-dualsense"
|
||||
version = "0.1.0"
|
||||
publish = false
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "punktfunk virtual DualSense UMDF2 HID minidriver (M0 spike)"
|
||||
|
||||
[package.metadata.wdk.driver-model]
|
||||
driver-type = "UMDF"
|
||||
target-umdf-version-minor = 31
|
||||
umdf-version-major = 2
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[build-dependencies]
|
||||
wdk-build.path = "../../crates/wdk-build"
|
||||
|
||||
[dependencies]
|
||||
wdk.path = "../../crates/wdk"
|
||||
wdk-sys.path = "../../crates/wdk-sys"
|
||||
|
||||
[features]
|
||||
default = ["hid"]
|
||||
hid = ["wdk-sys/hid"]
|
||||
nightly = ["wdk-sys/nightly", "wdk/nightly"]
|
||||
|
||||
[profile.dev]
|
||||
lto = true
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
||||
# Standalone package (not part of the windows-drivers-rs root workspace).
|
||||
[workspace]
|
||||
@@ -1,4 +0,0 @@
|
||||
extend = [
|
||||
{ path = "../../crates/wdk-build/rust-driver-makefile.toml" },
|
||||
{ path = "../../crates/wdk-build/rust-driver-sample-makefile.toml" },
|
||||
]
|
||||
@@ -157,21 +157,21 @@ if (-not $NoDriver) {
|
||||
}
|
||||
else { Write-Host "-NoDriver: building installer WITHOUT the bundled pf-vdisplay driver" }
|
||||
|
||||
# --- stage the punktfunk virtual-gamepad UMDF drivers (DualSense/DS4 + Xbox 360 XUSB) ----------
|
||||
# Vendored, pre-signed under packaging/windows/gamepad-drivers/ (like pf-vdisplay). Rebuild + re-vendor
|
||||
# from packaging/windows/{dualsense,xusb}-driver/ when the driver source changes (see their READMEs).
|
||||
# --- build (from source) + stage the punktfunk virtual-gamepad UMDF drivers --------------------
|
||||
# pf-dualsense (DualSense / DualShock 4) + pf-xusb (Xbox 360 / XInput) are members of the same drivers
|
||||
# workspace as pf-vdisplay, built from source per release (build-gamepad-drivers.ps1) - same anti-stale
|
||||
# reasoning as pf-vdisplay; the prior checked-in binaries under gamepad-drivers/ are retired. install-
|
||||
# gamepad-drivers.ps1 adds each to the store (the host SwDeviceCreate's the per-session devnodes).
|
||||
if (-not $NoDriver) {
|
||||
$gpVendor = Join-Path $here 'gamepad-drivers'
|
||||
if (Test-Path (Join-Path $gpVendor 'pf_dualsense.inf')) {
|
||||
$gpStage = Join-Path $OutDir 'gamepad'
|
||||
if (Test-Path $gpStage) { Remove-Item -Recurse -Force $gpStage }
|
||||
New-Item -ItemType Directory -Force -Path $gpStage | Out-Null
|
||||
Copy-Item (Join-Path $gpVendor '*') $gpStage -Force
|
||||
Copy-Item (Join-Path $here 'install-gamepad-drivers.ps1') (Join-Path $gpStage 'install-gamepad-drivers.ps1') -Force
|
||||
$defines += "/DGamepadStageDir=$gpStage"
|
||||
Write-Host "==> staged vendored gamepad UMDF drivers from $gpVendor"
|
||||
}
|
||||
else { Write-Warning "no vendored gamepad drivers under $gpVendor - installer built WITHOUT them" }
|
||||
$gpBuilt = Join-Path $OutDir 'gamepad-built'
|
||||
& (Join-Path $here 'build-gamepad-drivers.ps1') -Out $gpBuilt
|
||||
$gpStage = Join-Path $OutDir 'gamepad'
|
||||
if (Test-Path $gpStage) { Remove-Item -Recurse -Force $gpStage }
|
||||
New-Item -ItemType Directory -Force -Path $gpStage | Out-Null
|
||||
Copy-Item (Join-Path $gpBuilt '*') $gpStage -Force
|
||||
Copy-Item (Join-Path $here 'install-gamepad-drivers.ps1') (Join-Path $gpStage 'install-gamepad-drivers.ps1') -Force
|
||||
$defines += "/DGamepadStageDir=$gpStage"
|
||||
Write-Host "==> built + staged gamepad UMDF drivers -> $gpStage"
|
||||
}
|
||||
|
||||
# --- stage the FFmpeg shared DLLs (AMD/Intel AMF/QSV build) ------------------------------------
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
[package]
|
||||
edition = "2024"
|
||||
name = "pf-xusb"
|
||||
version = "0.1.0"
|
||||
publish = false
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "punktfunk virtual Xbox 360 XUSB companion (UMDF2 — classic XInput)"
|
||||
|
||||
[package.metadata.wdk.driver-model]
|
||||
driver-type = "UMDF"
|
||||
target-umdf-version-minor = 31
|
||||
umdf-version-major = 2
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[build-dependencies]
|
||||
wdk-build.path = "../../crates/wdk-build"
|
||||
|
||||
[dependencies]
|
||||
wdk.path = "../../crates/wdk"
|
||||
wdk-sys.path = "../../crates/wdk-sys"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
nightly = ["wdk-sys/nightly", "wdk/nightly"]
|
||||
|
||||
[profile.dev]
|
||||
lto = true
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
||||
# Standalone package (not part of the windows-drivers-rs root workspace).
|
||||
[workspace]
|
||||
@@ -1,4 +0,0 @@
|
||||
extend = [
|
||||
{ path = "../../crates/wdk-build/rust-driver-makefile.toml" },
|
||||
{ path = "../../crates/wdk-build/rust-driver-sample-makefile.toml" },
|
||||
]
|
||||
Reference in New Issue
Block a user