Skip to content

feat(usb): enable remote wakeup for HID devices#1235

Merged
adamshiervani merged 2 commits intojetkvm:devfrom
jlian:feat/usb-remote-wakeup-backend
Mar 28, 2026
Merged

feat(usb): enable remote wakeup for HID devices#1235
adamshiervani merged 2 commits intojetkvm:devfrom
jlian:feat/usb-remote-wakeup-backend

Conversation

@jlian
Copy link
Copy Markdown
Contributor

@jlian jlian commented Mar 2, 2026

Fixes #120 and #674.

Summary

Enable USB remote wakeup so JetKVM can wake a sleeping host via keyboard or mouse input.

Requires the kernel-side wakeup_on_write configfs attribute from jetkvm/rv1106-system#57 to work end to end.

Two changes:

  1. Set bmAttributes = 0xa0 (bus-powered + remote wakeup) in the USB configuration descriptor, advertising remote wakeup capability to the host during enumeration
  2. Set wakeup_on_write = 1 on all three HID functions (keyboard, absolute mouse, relative mouse), so the kernel calls usb_gadget_wakeup() before each HID report write

Changes

  • config.go: Add bmAttributes: "0xa0" to gadget config attributes
  • hid_keyboard.go: Add wakeup_on_write: "1"
  • hid_mouse_absolute.go: Add wakeup_on_write: "1"
  • hid_mouse_relative.go: Add wakeup_on_write: "1"

Testing

Tested on JetKVM v2 with patched kernel (rv1106-system#57). Host: Windows 11 (S3 sleep), Intel Z390 chipset, xHCI controller.

Test setup

  • Host: Windows 11, Intel Z390, S3 (legacy suspend-to-RAM, not Modern Standby)
  • "Allow this device to wake the computer" enabled on the USB hub in Device Manager (Windows default)
  • JetKVM connected via HDMI (DP-to-HDMI adapter) + USB-C
  • After deploying patched kernel + app, USB re-enumeration required (reconnect cable or reboot JetKVM)
  • Each test started from confirmed cold sleep (100% ping packet loss verified before sending wake signal)

Descriptor verification

lsusb -v on host confirms the configuration descriptor advertises remote wakeup:

  Configuration Descriptor:
    bmAttributes         0xa0
      (Bus Powered)
      Remote Wakeup

Test 1: Direct HID write via SSH (measures raw PC wake time)

SSH into JetKVM and write a raw keyboard HID report to the gadget device:

# Press spacebar (usage 0x2c)
echo -ne '\x00\x00\x2c\x00\x00\x00\x00\x00' > /dev/hidg0
# Release
echo -ne '\x00\x00\x00\x00\x00\x00\x00\x00' > /dev/hidg0

Measurement: timed from HID write completion to first successful ping response from the host.

Run Wake time (HID write to first ping)
1 4,016ms
2 4,015ms
3 4,013ms
Avg 4,015ms

powercfg /lastwake confirms wake source on every test:

Wake Source [0]:
  Type: Device
  Friendly Name: Intel(R) USB 3.1 eXtensible Host Controller
  Description: USB xHCI Compliant Host Controller

Note: the total SSH command time is dominated by SSH overhead to JetKVM's BusyBox shell on the RV1106. The actual HID write and USB wakeup are near-instant.

Test 2: Wake via JetKVM web UI (measures end-to-end user experience)

With the host asleep, pressed spacebar through the KVM web interface.

Measurement: JS polling video.currentTime every 50ms in headful Chromium, detecting when the video stream advances >0.05s from the frozen baseline. This measures the full pipeline: HID write, PC wake, GPU resume, HDMI signal, JetKVM capture, WebRTC stream.

Run Button click to first video frame
1 26,271ms
2 26,200ms
3 26,450ms
Avg 26,307ms (~26s)

The ~22s overhead beyond the raw 4s wake time is almost entirely Windows GPU resume (powering from D3, reinitializing display driver, outputting HDMI signal). This is outside JetKVM's control and will vary by GPU, driver version, and display configuration.

Test 3: Mouse input

Tested with both absolute and relative mouse movement through the web UI. Both wake the host successfully with the same timing.

Notes

  • Wake works from all three HID functions: keyboard, absolute mouse, relative mouse
  • The PC must have enumerated JetKVM's USB device before entering sleep. If JetKVM reboots while the host is asleep, wake won't work until the host is woken by other means (e.g. WoL) and re-enumerates the device.
  • Modern Standby (S0ix) hosts may behave differently; only S3 was tested.
  • Multiple sleep/wake cycles tested (3+) with consistent results.

Checklist

  • Ran make test_e2e locally and passed
  • Linked to issue(s) above by issue number
  • One problem per PR (no unrelated changes)
  • Lints pass; CI green

Note

Medium Risk
Touches USB gadget descriptor/configfs attributes used during enumeration and runtime HID writes; behavior depends on kernel support for wakeup_on_write and could affect host compatibility if misconfigured.

Overview
Advertises USB remote wakeup support by setting bmAttributes = 0xa0 on the base gadget configuration.

Enables kernel-triggered wakeups on input by writing wakeup_on_write = 1 for keyboard and both mouse HID functions, and updates the configfs transaction writer to ignore errors when wakeup_on_write is unsupported (optional kernel feature).

Written by Cursor Bugbot for commit 41c50f0. This will update automatically on new commits. Configure here.

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Mar 2, 2026

CLA assistant check
All committers have signed the CLA.

@jlian jlian force-pushed the feat/usb-remote-wakeup-backend branch from bcc0cd5 to ccde02b Compare March 2, 2026 05:20
@jlian jlian changed the title usb: enable remote wakeup for HID devices feat(usb): enable remote wakeup for HID devices Mar 2, 2026
@mithun3 mithun3 mentioned this pull request Mar 12, 2026
1 task
Copy link
Copy Markdown
Contributor

@adamshiervani adamshiervani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the thorough PR description and testing — the benchmarks and powercfg /lastwake verification are excellent.

I reviewed both this PR and the companion kernel patch (rv1106-system#57). Two issues:


1. Backward compatibility: wakeup_on_write will break USB init on unpatched kernels

The wakeup_on_write attribute is added unconditionally to all three HID function configs. On devices running a kernel without rv1106-system#57, this configfs attribute won't exist. Walking through the changeset resolver:

  1. getActualState() → file doesn't exist → ActualState = FileStateAbsent
  2. getFileChangeResolvedAction() for FileStateFileContentMatch with ActualState != FileStateFile → returns FileChangeResolvedActionCreateFile
  3. applyChange()os.WriteFile() on a non-existent configfs path → fails (configfs doesn't allow creating arbitrary files)
  4. IgnoreErrors is not set → error propagates → entire USB gadget initialization fails

This means deploying this Go binary on a device without the patched kernel will break USB entirely — no keyboard, no mouse, no mass storage.

Options:

  • Set IgnoreErrors: true on the wakeup_on_write attribute writes
  • Detect kernel support (e.g. check if the attribute file exists before writing)
  • Coordinate the rollout so the kernel patch always lands first (fragile)

The bmAttributes = 0xa0 change is also unconditional — advertising remote wakeup on a kernel that can't deliver it is misleading but not harmful.


2. Kernel patch (rv1106-system#57): potential NULL dereference in f_hidg_write

struct usb_composite_dev *cdev = hidg->func.config->cdev;

This unconditionally dereferences hidg->func.config at the variable declaration, before the null checks on cdev and cdev->gadget. If config is NULL (e.g. during unbind racing with a write), this is a kernel NULL pointer dereference → oops/panic.

Yes, the existing code already accesses hidg->in_ep later with the same assumption, but this new dereference happens earlier (before the spinlock), widening the race window.

Suggested fix — move the dereference inside the guard:

if (hidg->wakeup_on_write && hidg->func.config) {
    struct usb_composite_dev *cdev = hidg->func.config->cdev;
    if (cdev && cdev->gadget)
        usb_gadget_wakeup(cdev->gadget);
}

Or at minimum, guard config:

struct usb_composite_dev *cdev = hidg->func.config ?
                                  hidg->func.config->cdev : NULL;

Everything else looks clean: the configfs registration follows the no_out_endpoint pattern, the hidg_alloc copy is consistent, and the Go-side config changes are minimal.

@jlian jlian force-pushed the feat/usb-remote-wakeup-backend branch 2 times, most recently from d26a3d7 to b7a697a Compare March 18, 2026 19:39
@jlian
Copy link
Copy Markdown
Contributor Author

jlian commented Mar 18, 2026

@adamshiervani thanks for taking a look. Both PRs updated following review suggestions.

@adamshiervani adamshiervani mentioned this pull request Mar 25, 2026
@jlian jlian requested a review from adamshiervani March 26, 2026 17:17
jlian and others added 2 commits March 29, 2026 00:18
Set bmAttributes to 0xa0 (bus-powered + remote wakeup) in the USB
configuration descriptor, and enable wakeup_on_write on all HID
functions (keyboard, absolute mouse, relative mouse).

Together with the corresponding kernel f_hid patch in rv1106-system,
this allows the JetKVM to wake a sleeping host by sending keyboard or
mouse input through the web UI or API.

Tested on JetKVM v2 waking a Windows 11 host from S3 sleep.

Requires: jetkvm/rv1106-system kernel patch (f_hid wakeup_on_write)
Closes: jetkvm#120
Closes: jetkvm#674
The wakeup_on_write configfs attribute only exists on kernels with
the rv1106-system#57 patch. On unpatched kernels the attribute is
absent, and writing to it fails, which would break the entire USB
gadget initialization.

Set IgnoreErrors for wakeup_on_write so it is silently skipped on
kernels that lack the attribute.
@adamshiervani adamshiervani force-pushed the feat/usb-remote-wakeup-backend branch from b7a697a to 41c50f0 Compare March 28, 2026 23:20
@adamshiervani adamshiervani merged commit 009a22e into jetkvm:dev Mar 28, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JetKVM doesn't wake PC from sleep

3 participants