From a1c89d59a17ed5d7c8da69c3284926b75902a38e Mon Sep 17 00:00:00 2001 From: Benedek Kupper Date: Sat, 11 Oct 2025 23:35:46 +0200 Subject: [PATCH 1/2] add Debian package sources for resetting USB after resume --- uhk-usb-service/DEBIAN/control | 11 +++++++ uhk-usb-service/DEBIAN/postinst | 12 +++++++ uhk-usb-service/DEBIAN/prerm | 14 ++++++++ .../lib/systemd/system/uhk-usb-rebind.service | 10 ++++++ .../usr/local/bin/uhk-usb-rebind.sh | 32 +++++++++++++++++++ 5 files changed, 79 insertions(+) create mode 100644 uhk-usb-service/DEBIAN/control create mode 100755 uhk-usb-service/DEBIAN/postinst create mode 100755 uhk-usb-service/DEBIAN/prerm create mode 100644 uhk-usb-service/usr/lib/systemd/system/uhk-usb-rebind.service create mode 100755 uhk-usb-service/usr/local/bin/uhk-usb-rebind.sh diff --git a/uhk-usb-service/DEBIAN/control b/uhk-usb-service/DEBIAN/control new file mode 100644 index 00000000000..9751f09caf0 --- /dev/null +++ b/uhk-usb-service/DEBIAN/control @@ -0,0 +1,11 @@ +Package: uhk-usb-rebind +Version: 1.0 +Section: utils +Priority: optional +Architecture: all +Maintainer: Benedek Kupper +Description: Rebinds UHK USB devices on resume to fix scrolling issues + This package provides a script and a systemd service that put both the host and the device + into a known good state after resuming from suspend. This is a temporary workaround, + until this patch is merged into the Linux kernel: + https://lore.kernel.org/linux-input/20251007203544.9963-1-kupper.benedek@gmail.com/T/#u diff --git a/uhk-usb-service/DEBIAN/postinst b/uhk-usb-service/DEBIAN/postinst new file mode 100755 index 00000000000..15068b4b401 --- /dev/null +++ b/uhk-usb-service/DEBIAN/postinst @@ -0,0 +1,12 @@ +#!/bin/bash +set -e + +# If systemctl is available, reload units and enable the service now. +if command -v systemctl >/dev/null 2>&1; then + # Reload systemd units to pick up the newly installed unit file + systemctl daemon-reload || true + # Enable and start the service for the current system + systemctl enable --now uhk-usb-rebind.service || true +fi + +exit 0 diff --git a/uhk-usb-service/DEBIAN/prerm b/uhk-usb-service/DEBIAN/prerm new file mode 100755 index 00000000000..190917f501c --- /dev/null +++ b/uhk-usb-service/DEBIAN/prerm @@ -0,0 +1,14 @@ +#!/bin/bash +set -e + +# If systemctl is available, try to disable the unit so packager removal cleans up symlinks +if command -v systemctl >/dev/null 2>&1; then + # Try to stop the service (ignore failures) + systemctl stop uhk-usb-rebind.service || true + # Disable the unit (remove symlink) + systemctl disable uhk-usb-rebind.service || true + # Reload daemon so the removal is recognized + systemctl daemon-reload || true +fi + +exit 0 diff --git a/uhk-usb-service/usr/lib/systemd/system/uhk-usb-rebind.service b/uhk-usb-service/usr/lib/systemd/system/uhk-usb-rebind.service new file mode 100644 index 00000000000..8b8cb1de51c --- /dev/null +++ b/uhk-usb-service/usr/lib/systemd/system/uhk-usb-rebind.service @@ -0,0 +1,10 @@ +[Unit] +Description=UHK USB reset after resume +After=suspend.target + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/uhk-usb-rebind.sh + +[Install] +WantedBy=suspend.target diff --git a/uhk-usb-service/usr/local/bin/uhk-usb-rebind.sh b/uhk-usb-service/usr/local/bin/uhk-usb-rebind.sh new file mode 100755 index 00000000000..951b22cd9fb --- /dev/null +++ b/uhk-usb-service/usr/local/bin/uhk-usb-rebind.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +declare -a uhk_devices=( + "37a8:0001" + "37a8:0003" + "37a8:0005" + "37a8:0007" + "37a8:0009" +) + +USB_DRIVER_PATH="/sys/bus/usb/drivers/usb" + +for dev in /sys/bus/usb/devices/*; do + if [[ -f "$dev/idVendor" && -f "$dev/idProduct" ]]; then + VID=$(cat "$dev/idVendor") + PID=$(cat "$dev/idProduct") + MATCH="${VID}:${PID}" + + for target in "${uhk_devices[@]}"; do + if [[ "$MATCH" == "$target" ]]; then + DEVNAME=$(basename "$dev") + + if [[ -e "$USB_DRIVER_PATH/unbind" ]]; then + echo "$DEVNAME" | sudo tee "$USB_DRIVER_PATH/unbind" + sleep 1.5 + echo "$DEVNAME" | sudo tee "$USB_DRIVER_PATH/bind" + echo "Rebound device: $dev" + fi + fi + done + fi +done From adfa3ed7b3016afd9f04decefc0b955aefcc8a7c Mon Sep 17 00:00:00 2001 From: Benedek Kupper Date: Sat, 15 Nov 2025 21:27:33 +0100 Subject: [PATCH 2/2] ship the service with agent for manual installation --- scripts/copy-to-tmp-folder.js | 6 +++ scripts/release.mjs | 3 ++ uhk-usb-service/DEBIAN/control | 11 ------ uhk-usb-service/DEBIAN/postinst | 12 ------ uhk-usb-service/DEBIAN/prerm | 14 ------- uhk-usb-service/manual-install.sh | 62 +++++++++++++++++++++++++++++++ 6 files changed, 71 insertions(+), 37 deletions(-) delete mode 100644 uhk-usb-service/DEBIAN/control delete mode 100755 uhk-usb-service/DEBIAN/postinst delete mode 100755 uhk-usb-service/DEBIAN/prerm create mode 100755 uhk-usb-service/manual-install.sh diff --git a/scripts/copy-to-tmp-folder.js b/scripts/copy-to-tmp-folder.js index d79c3ed49d3..3ec264bf4a8 100644 --- a/scripts/copy-to-tmp-folder.js +++ b/scripts/copy-to-tmp-folder.js @@ -20,6 +20,12 @@ promises.push( path.join(__dirname, '../tmp/smart-macro-docs'), copyOptions) ); +promises.push( + fse.copy( + path.join(__dirname, '../uhk-usb-service'), + path.join(__dirname, '../tmp/uhk-usb-service'), + copyOptions) +); Promise .all(promises) diff --git a/scripts/release.mjs b/scripts/release.mjs index 7fccc45b394..537c3913d04 100644 --- a/scripts/release.mjs +++ b/scripts/release.mjs @@ -54,6 +54,9 @@ if (process.platform === 'darwin') { artifactName += '-${arch}.${ext}'; extraResources.push('rules/setup-rules.sh'); extraResources.push('rules/50-uhk60.rules'); + extraResources.push('uhk-usb-service/manual-install.sh'); + extraResources.push('uhk-usb-service/usr/lib/systemd/system/uhk-usb-rebind.service'); + extraResources.push('uhk-usb-service/usr/local/bin/uhk-usb-rebind.sh'); } else { console.error(`I dunno how to publish a release for ${process.platform} :(`); process.exit(1); diff --git a/uhk-usb-service/DEBIAN/control b/uhk-usb-service/DEBIAN/control deleted file mode 100644 index 9751f09caf0..00000000000 --- a/uhk-usb-service/DEBIAN/control +++ /dev/null @@ -1,11 +0,0 @@ -Package: uhk-usb-rebind -Version: 1.0 -Section: utils -Priority: optional -Architecture: all -Maintainer: Benedek Kupper -Description: Rebinds UHK USB devices on resume to fix scrolling issues - This package provides a script and a systemd service that put both the host and the device - into a known good state after resuming from suspend. This is a temporary workaround, - until this patch is merged into the Linux kernel: - https://lore.kernel.org/linux-input/20251007203544.9963-1-kupper.benedek@gmail.com/T/#u diff --git a/uhk-usb-service/DEBIAN/postinst b/uhk-usb-service/DEBIAN/postinst deleted file mode 100755 index 15068b4b401..00000000000 --- a/uhk-usb-service/DEBIAN/postinst +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -set -e - -# If systemctl is available, reload units and enable the service now. -if command -v systemctl >/dev/null 2>&1; then - # Reload systemd units to pick up the newly installed unit file - systemctl daemon-reload || true - # Enable and start the service for the current system - systemctl enable --now uhk-usb-rebind.service || true -fi - -exit 0 diff --git a/uhk-usb-service/DEBIAN/prerm b/uhk-usb-service/DEBIAN/prerm deleted file mode 100755 index 190917f501c..00000000000 --- a/uhk-usb-service/DEBIAN/prerm +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -set -e - -# If systemctl is available, try to disable the unit so packager removal cleans up symlinks -if command -v systemctl >/dev/null 2>&1; then - # Try to stop the service (ignore failures) - systemctl stop uhk-usb-rebind.service || true - # Disable the unit (remove symlink) - systemctl disable uhk-usb-rebind.service || true - # Reload daemon so the removal is recognized - systemctl daemon-reload || true -fi - -exit 0 diff --git a/uhk-usb-service/manual-install.sh b/uhk-usb-service/manual-install.sh new file mode 100755 index 00000000000..6d8f731839b --- /dev/null +++ b/uhk-usb-service/manual-install.sh @@ -0,0 +1,62 @@ +#!/bin/bash +# Manual installer for systems without package manager support +# Usage: sudo ./manual-install.sh install|uninstall + +set -euo pipefail + +SCRIPT_SRC="usr/local/bin/uhk-usb-rebind.sh" +UNIT_SRC="usr/lib/systemd/system/uhk-usb-rebind.service" + +SCRIPT_DST="/usr/local/bin/uhk-usb-rebind.sh" +UNIT_DST="/usr/local/lib/systemd/system/uhk-usb-rebind.service" + +usage() { + echo "Usage: $0 install|uninstall" + exit 2 +} + +if [[ $(id -u) -ne 0 ]]; then + echo "This script must be run as root (sudo)" + exit 1 +fi + +if [[ $# -ne 1 ]]; then + usage +fi + +action="$1" + +case "$action" in + install) + echo "Installing UHK USB rebind script and systemd unit to /usr/local..." + mkdir -p "$(dirname "$SCRIPT_DST")" "$(dirname "$UNIT_DST")" + cp -a "$SCRIPT_SRC" "$SCRIPT_DST" + chmod 755 "$SCRIPT_DST" + cp -a "$UNIT_SRC" "$UNIT_DST" + chmod 644 "$UNIT_DST" + if command -v systemctl >/dev/null 2>&1; then + systemctl daemon-reload || true + systemctl enable --now uhk-usb-rebind.service || true + echo "Service enabled and started (if systemd present)." + else + echo "systemctl not found; unit installed at $UNIT_DST. Enable it manually if desired." + fi + echo "Install complete." + ;; + uninstall) + echo "Uninstalling UHK USB rebind script and systemd unit from /usr/local..." + if command -v systemctl >/dev/null 2>&1; then + systemctl stop uhk-usb-rebind.service || true + systemctl disable uhk-usb-rebind.service || true + systemctl daemon-reload || true + fi + rm -f "$SCRIPT_DST" || true + rm -f "$UNIT_DST" || true + echo "Uninstall complete." + ;; + *) + usage + ;; +esac + +exit 0