Fix RioGamepad Code 31: add VHF lower filter + joy.cpl friendly name
The driver installed but the device failed with Code 31 (CM_PROB_FAILED_ADD): VhfCreate returned STATUS_INVALID_DEVICE_REQUEST (0xC0000010) because vhf.sys was never attached beneath the FDO. Add the required LowerFilters=vhf AddReg to the INF so VHF loads as a lower filter; the device now starts clean and enumerates in joy.cpl. A VHF virtual HID device cannot supply a HID product string (VHF_CONFIG has no string field and VHF owns IOCTL_HID_GET_STRING), so register the DirectInput OEMName (VID_1209&PID_5249 -> RIOJoy Virtual Gamepad) in install.ps1 -CreateDevice and remove it in uninstall.ps1, giving the controller a proper name instead of the generic VHF default. Also fix a non-ASCII em-dash in sign.ps1 that broke parsing under Windows PowerShell 5.1 (UTF-8 without BOM), and document the Code 52 / Code 31 / friendly-name troubleshooting in driver/README.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+59
-6
@@ -17,7 +17,7 @@ to Windows via `VhfReadReportSubmit`.
|
|||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
**Phase 1 — implemented and compiling.** The driver source under
|
**Phase 1 — implemented, installed, and enumerating.** The driver source under
|
||||||
[`RioGamepad/`](RioGamepad/) builds cleanly to `RioGamepad.sys` against the EWDK
|
[`RioGamepad/`](RioGamepad/) builds cleanly to `RioGamepad.sys` against the EWDK
|
||||||
(KMDF 1.15 + VHF, x64). It is a thin VHF relay: it creates the virtual HID device
|
(KMDF 1.15 + VHF, x64). It is a thin VHF relay: it creates the virtual HID device
|
||||||
from the report descriptor and, on each `IOCTL_RIO_SUBMIT_REPORT`, forwards the
|
from the report descriptor and, on each `IOCTL_RIO_SUBMIT_REPORT`, forwards the
|
||||||
@@ -25,9 +25,12 @@ caller's 25-byte report to `VhfReadReportSubmit`. All report packing lives in th
|
|||||||
C# client (`RioJoy.Core.Hid.RioHidReport`, unit-tested) so the wire format is
|
C# client (`RioJoy.Core.Hid.RioHidReport`, unit-tested) so the wire format is
|
||||||
pinned on both sides ([`RioGamepad/Public.h`](RioGamepad/Public.h)).
|
pinned on both sides ([`RioGamepad/Public.h`](RioGamepad/Public.h)).
|
||||||
|
|
||||||
Not yet done: **test-signing + install + verify in `joy.cpl`** (the on-cabinet
|
Test-signed, installed, and verified on the cabinet: the devnode starts clean
|
||||||
step), and wiring the real `DeviceIoControl` feeder sink (replacing the C# side's
|
(`CM_PROB_NONE`), `vhf` attaches as a lower filter, the VHF HID child enumerates,
|
||||||
`NullJoystickSink`).
|
and the controller registers under `VID_1209&PID_5249` in `joy.cpl`.
|
||||||
|
|
||||||
|
Not yet done: wiring the real `DeviceIoControl` feeder sink (replacing the C#
|
||||||
|
side's `NullJoystickSink`).
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
@@ -63,15 +66,65 @@ powershell -ExecutionPolicy Bypass -File sign.ps1 -Ewdk E:
|
|||||||
:: 3. (admin) Trust the cert, stage the driver, enable test signing
|
:: 3. (admin) Trust the cert, stage the driver, enable test signing
|
||||||
powershell -ExecutionPolicy Bypass -File install.ps1 -Ewdk E:
|
powershell -ExecutionPolicy Bypass -File install.ps1 -Ewdk E:
|
||||||
|
|
||||||
:: 4. REBOOT (test signing only takes effect after a restart)
|
:: 4. Verify test signing is actually set before rebooting:
|
||||||
|
:: bcdedit /enum "{current}" -> must list testsigning Yes
|
||||||
|
:: (if missing, Code 52 will persist; enable with: bcdedit /set testsigning on)
|
||||||
|
|
||||||
:: 5. (admin) Create the device; PnP then installs the staged driver
|
:: 5. REBOOT (test signing only takes effect after a restart)
|
||||||
|
|
||||||
|
:: 6. (admin) Create the device; PnP then installs the staged driver
|
||||||
powershell -ExecutionPolicy Bypass -File install.ps1 -Ewdk E: -CreateDevice
|
powershell -ExecutionPolicy Bypass -File install.ps1 -Ewdk E: -CreateDevice
|
||||||
```
|
```
|
||||||
|
|
||||||
Then open **`joy.cpl`** and confirm **"RIOJoy Virtual Gamepad"** appears with 6
|
Then open **`joy.cpl`** and confirm **"RIOJoy Virtual Gamepad"** appears with 6
|
||||||
axes / POV / 96 buttons. To roll back: `uninstall.ps1 [-DisableTestSigning] [-RemoveCert]`.
|
axes / POV / 96 buttons. To roll back: `uninstall.ps1 [-DisableTestSigning] [-RemoveCert]`.
|
||||||
|
|
||||||
|
> **Friendly name in `joy.cpl`.** A VHF virtual HID device cannot supply a HID
|
||||||
|
> product string: `VHF_CONFIG` has no string field and VHF handles
|
||||||
|
> `IOCTL_HID_GET_STRING` itself rather than forwarding it to the source driver.
|
||||||
|
> Left alone, the controller shows as the generic *"Virtual HID Framework (VHF)
|
||||||
|
> HID device"*. DirectInput instead reads the display name from a registry
|
||||||
|
> `OEMName` value keyed by VID/PID, so `install.ps1 -CreateDevice` writes
|
||||||
|
> `RIOJoy Virtual Gamepad` to
|
||||||
|
> `…\MediaProperties\PrivateProperties\Joystick\OEM\VID_1209&PID_5249\OEMName`
|
||||||
|
> (under both HKLM and HKCU); `uninstall.ps1` removes it. `joy.cpl` must be
|
||||||
|
> reopened to pick up the change.
|
||||||
|
|
||||||
|
> **Secure Boot, drive encryption, and Code 52.** Test signing does not take
|
||||||
|
> effect while **Secure Boot is enabled**, and a test-signed driver shows up in
|
||||||
|
> Device Manager as **Code 52** ("Windows cannot verify the digital signature")
|
||||||
|
> until Secure Boot is turned off in the BIOS/UEFI. **Turn off drive encryption
|
||||||
|
> (BitLocker / device encryption) *before* you disable Secure Boot.** Changing
|
||||||
|
> Secure Boot alters the platform measurements BitLocker is sealed to, so if the
|
||||||
|
> drive is still encrypted the machine boots into BitLocker recovery and demands
|
||||||
|
> the recovery key. Decrypt the system drive (or at minimum suspend BitLocker)
|
||||||
|
> first, then disable Secure Boot, then reboot.
|
||||||
|
>
|
||||||
|
> If Code 52 persists *after* Secure Boot is already disabled: confirm test
|
||||||
|
> signing is actually on (`bcdedit /enum` should list `testsigning Yes`),
|
||||||
|
> re-trust the cert and re-stage with `install.ps1`, and reboot once more — the
|
||||||
|
> `testsigning` flag only takes effect after a restart.
|
||||||
|
|
||||||
|
> **Code 31 (`CM_PROB_FAILED_ADD`) — VHF lower filter.** A different failure
|
||||||
|
> from Code 52: here the image *loads* (signing is fine) but `AddDevice` fails.
|
||||||
|
> For a VHF driver this is almost always `VhfCreate` returning
|
||||||
|
> `STATUS_INVALID_DEVICE_REQUEST` (`0xC0000010`) because **`vhf.sys` is not
|
||||||
|
> attached beneath the device as a lower filter**. The INF must add it:
|
||||||
|
>
|
||||||
|
> ```ini
|
||||||
|
> [RioGamepad_Device.NT.HW]
|
||||||
|
> AddReg = RioGamepad_Device.NT.AddReg
|
||||||
|
>
|
||||||
|
> [RioGamepad_Device.NT.AddReg]
|
||||||
|
> HKR,, "LowerFilters", 0x00010000, "vhf"
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> Confirm with `Get-PnpDeviceProperty -InstanceId <id> -KeyName DEVPKEY_Device_LowerFilters`
|
||||||
|
> (should return `vhf`). The exact failing NTSTATUS for any Code 31/52 is in the
|
||||||
|
> devnode's `DEVPKEY_Device_ProblemStatus`, and image-load rejections are logged
|
||||||
|
> under **Event Viewer → Microsoft-Windows-CodeIntegrity/Operational** and System
|
||||||
|
> event 219.
|
||||||
|
|
||||||
The signed package (`package/`) and the exported cert are local artifacts and are
|
The signed package (`package/`) and the exported cert are local artifacts and are
|
||||||
git-ignored. Redistribution beyond owned hardware would instead use Microsoft
|
git-ignored. Redistribution beyond owned hardware would instead use Microsoft
|
||||||
**attestation signing** via Partner Center (see [../docs/PLAN.md](../docs/PLAN.md),
|
**attestation signing** via Partner Center (see [../docs/PLAN.md](../docs/PLAN.md),
|
||||||
|
|||||||
@@ -32,6 +32,15 @@ CopyFiles = RioGamepad_CopyFiles
|
|||||||
[RioGamepad_CopyFiles]
|
[RioGamepad_CopyFiles]
|
||||||
RioGamepad.sys
|
RioGamepad.sys
|
||||||
|
|
||||||
|
; VHF (vhf.sys) must sit beneath this FDO as a lower filter, otherwise
|
||||||
|
; VhfCreate fails in EvtDeviceAdd with STATUS_INVALID_DEVICE_REQUEST
|
||||||
|
; (0xC0000010) and the device shows Code 31 (CM_PROB_FAILED_ADD).
|
||||||
|
[RioGamepad_Device.NT.HW]
|
||||||
|
AddReg = RioGamepad_Device.NT.AddReg
|
||||||
|
|
||||||
|
[RioGamepad_Device.NT.AddReg]
|
||||||
|
HKR,, "LowerFilters", 0x00010000, "vhf"
|
||||||
|
|
||||||
[RioGamepad_Device.NT.Services]
|
[RioGamepad_Device.NT.Services]
|
||||||
AddService = RioGamepad, 0x00000002, RioGamepad_Service
|
AddService = RioGamepad, 0x00000002, RioGamepad_Service
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,27 @@ $cer = Join-Path $scriptDir "RIOJoyTest.cer"
|
|||||||
$devgen = Join-Path $Ewdk "Program Files\Windows Kits\10\Tools\10.0.28000.0\x64\devgen.exe"
|
$devgen = Join-Path $Ewdk "Program Files\Windows Kits\10\Tools\10.0.28000.0\x64\devgen.exe"
|
||||||
$hardwareId = "root\RioGamepad"
|
$hardwareId = "root\RioGamepad"
|
||||||
|
|
||||||
|
# DirectInput / joy.cpl friendly name. A VHF virtual HID device cannot supply a
|
||||||
|
# HID product string (VHF_CONFIG has no string field and VHF owns
|
||||||
|
# IOCTL_HID_GET_STRING), so without this the controller shows as the generic
|
||||||
|
# "Virtual HID Framework (VHF) HID device". DirectInput reads the display name
|
||||||
|
# from this OEMName value, keyed by VID/PID (see RioGamepad\Public.h:
|
||||||
|
# RIO_VENDOR_ID 0x1209 / RIO_PRODUCT_ID 0x5249).
|
||||||
|
$oemVidPid = "VID_1209&PID_5249"
|
||||||
|
$friendlyName = "RIOJoy Virtual Gamepad"
|
||||||
|
|
||||||
|
function Set-RioJoyFriendlyName {
|
||||||
|
# Write the OEMName under both HKLM (machine-wide, authoritative) and HKCU
|
||||||
|
# (immediate effect for the current user) so joy.cpl shows $friendlyName.
|
||||||
|
$rel = "SYSTEM\CurrentControlSet\Control\MediaProperties\PrivateProperties\Joystick\OEM\$oemVidPid"
|
||||||
|
foreach ($hive in @("HKLM:", "HKCU:")) {
|
||||||
|
$key = "$hive\$rel"
|
||||||
|
New-Item -Path $key -Force | Out-Null
|
||||||
|
New-ItemProperty -Path $key -Name "OEMName" -Value $friendlyName -PropertyType String -Force | Out-Null
|
||||||
|
}
|
||||||
|
Write-Host "Set joy.cpl friendly name for $oemVidPid -> '$friendlyName'."
|
||||||
|
}
|
||||||
|
|
||||||
if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
|
if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
|
||||||
[Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
[Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||||
throw "This script must be run from an elevated (Administrator) shell."
|
throw "This script must be run from an elevated (Administrator) shell."
|
||||||
@@ -45,6 +66,7 @@ if ($CreateDevice) {
|
|||||||
if (-not (Test-Path $devgen)) { throw "devgen not found: $devgen" }
|
if (-not (Test-Path $devgen)) { throw "devgen not found: $devgen" }
|
||||||
Write-Host "Creating device node ($hardwareId)..."
|
Write-Host "Creating device node ($hardwareId)..."
|
||||||
& $devgen /add /instanceid "RIOJOY01" /hardwareid $hardwareId
|
& $devgen /add /instanceid "RIOJOY01" /hardwareid $hardwareId
|
||||||
|
Set-RioJoyFriendlyName
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "Done. Open 'joy.cpl' and look for 'RIOJoy Virtual Gamepad'." -ForegroundColor Green
|
Write-Host "Done. Open 'joy.cpl' and look for 'RIOJoy Virtual Gamepad'." -ForegroundColor Green
|
||||||
Write-Host "If it shows a problem, check Device Manager and 'pnputil /enum-drivers'."
|
Write-Host "If it shows a problem, check Device Manager and 'pnputil /enum-drivers'."
|
||||||
|
|||||||
+1
-1
@@ -71,5 +71,5 @@ Write-Host "Signed package ready in: $pkg" -ForegroundColor Green
|
|||||||
Write-Host "Next: run driver\install.ps1 from an elevated shell to trust the cert," -ForegroundColor Yellow
|
Write-Host "Next: run driver\install.ps1 from an elevated shell to trust the cert," -ForegroundColor Yellow
|
||||||
Write-Host "enable test signing, and install the device." -ForegroundColor Yellow
|
Write-Host "enable test signing, and install the device." -ForegroundColor Yellow
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "(Note: 'signtool verify /pa' will fail until the cert is trusted by install.ps1 —" -ForegroundColor DarkGray
|
Write-Host "(Note: 'signtool verify /pa' will fail until the cert is trusted by install.ps1 -" -ForegroundColor DarkGray
|
||||||
Write-Host " that is expected for a self-signed test driver.)" -ForegroundColor DarkGray
|
Write-Host " that is expected for a self-signed test driver.)" -ForegroundColor DarkGray
|
||||||
|
|||||||
@@ -46,6 +46,16 @@ if ($published) {
|
|||||||
Write-Host "No staged RioGamepad driver package found."
|
Write-Host "No staged RioGamepad driver package found."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 3. Remove the DirectInput / joy.cpl friendly-name registration.
|
||||||
|
$joyOemRel = "SYSTEM\CurrentControlSet\Control\MediaProperties\PrivateProperties\Joystick\OEM\VID_1209&PID_5249"
|
||||||
|
foreach ($hive in @("HKLM:", "HKCU:")) {
|
||||||
|
$key = "$hive\$joyOemRel"
|
||||||
|
if (Test-Path $key) {
|
||||||
|
Write-Host "Removing joy.cpl friendly-name key: $key"
|
||||||
|
Remove-Item -Path $key -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($RemoveCert) {
|
if ($RemoveCert) {
|
||||||
Write-Host "Removing test certificate from trust stores..."
|
Write-Host "Removing test certificate from trust stores..."
|
||||||
Get-ChildItem Cert:\LocalMachine\Root, Cert:\LocalMachine\TrustedPublisher |
|
Get-ChildItem Cert:\LocalMachine\Root, Cert:\LocalMachine\TrustedPublisher |
|
||||||
|
|||||||
Reference in New Issue
Block a user