mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-07-04 17:43:05 +02:00
git-subtree-dir: linux_configuration git-subtree-mainline:11427631cdgit-subtree-split:0762e3d07b
197 lines
6.2 KiB
Bash
Executable File
197 lines
6.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Fix/diagnose Xbox One (and 360) controllers on Arch Linux over USB.
|
|
# - Detects the device, relevant kernel modules, and evdev/joystick nodes
|
|
# - Loads safe modules (xpad, joydev) if missing
|
|
# - Shows dmesg hints and permission status
|
|
# - Suggests next steps (packages to test: evtest, joystick; drivers for BT/dongle)
|
|
#
|
|
# Conventions: sudo re-exec, idempotent, log with timestamps.
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_NAME="$(basename "$0")"
|
|
LOG_FILE="/var/log/xbox-controller-fix.log"
|
|
|
|
timestamp() { date '+%Y-%m-%d %H:%M:%S%z'; }
|
|
|
|
log() {
|
|
local msg="$1"
|
|
echo "[$(timestamp)] $msg"
|
|
if [[ -w "$(dirname "$LOG_FILE")" ]] || [[ ! -e $LOG_FILE && -w /var/log ]]; then
|
|
echo "[$(timestamp)] $msg" >> "$LOG_FILE" || true
|
|
fi
|
|
}
|
|
|
|
require_root() {
|
|
if [[ ${EUID:-$(id -u)} -ne 0 ]]; then
|
|
echo "$SCRIPT_NAME needs root to load kernel modules and read some diagnostics. Re-executing with sudo..."
|
|
exec sudo -E bash "$0" "$@"
|
|
fi
|
|
}
|
|
|
|
print_header() {
|
|
echo "=== $1 ==="
|
|
}
|
|
|
|
detect_distro() {
|
|
if command -v pacman > /dev/null 2>&1; then
|
|
echo "arch"
|
|
else
|
|
echo "other"
|
|
fi
|
|
}
|
|
|
|
list_input_nodes() {
|
|
print_header "Input device nodes"
|
|
if [[ -d /dev/input/by-id ]]; then
|
|
# Robust listing with proper handling of special characters
|
|
local count=0
|
|
while IFS= read -r -d '' f; do
|
|
stat -c '%A %a %U:%G %N' "$f" 2> /dev/null || true
|
|
count=$((count + 1))
|
|
[[ $count -ge 120 ]] && break
|
|
done < <(find /dev/input/by-id -maxdepth 1 -mindepth 1 -print0 2> /dev/null)
|
|
else
|
|
echo "/dev/input/by-id not present"
|
|
fi
|
|
echo
|
|
if compgen -G "/dev/input/*js*" > /dev/null; then
|
|
ls -l /dev/input/js* || true
|
|
else
|
|
echo "No legacy /dev/input/js* nodes (joydev) present. That's okay for most apps using evdev."
|
|
fi
|
|
echo
|
|
}
|
|
|
|
show_lsusb() {
|
|
print_header "USB devices (filtered)"
|
|
if command -v lsusb > /dev/null 2>&1; then
|
|
lsusb | grep -Ei 'microsoft|xbox|045e:' || {
|
|
echo "No Microsoft/Xbox device found via lsusb."
|
|
true
|
|
}
|
|
else
|
|
echo "lsusb not found (usbutils). Install usbutils for richer diagnostics."
|
|
fi
|
|
echo
|
|
}
|
|
|
|
show_modules() {
|
|
print_header "Kernel modules state"
|
|
lsmod | grep -E '(^|\s)(xpad|joydev|hid_microsoft|hid_generic|hid_xpadneo|xone)(\s|$)' || echo "No matching modules currently loaded."
|
|
echo
|
|
}
|
|
|
|
modprobe_safe() {
|
|
local mod="$1"
|
|
if ! lsmod | grep -q "^${mod}\b"; then
|
|
if modprobe "$mod" 2> /dev/null; then
|
|
log "Loaded module: $mod"
|
|
else
|
|
log "Module $mod not loaded (may be built-in or unavailable)."
|
|
fi
|
|
fi
|
|
}
|
|
|
|
show_dmesg_hints() {
|
|
print_header "Recent kernel messages (xpad/xbox/hid/input)"
|
|
dmesg --color=never | grep -Ei 'xbox|xpad|045e:|Microsoft|input:.*gamepad|event.*joystick|hid.*(xbox|microsoft)' | tail -n 200 || true
|
|
echo
|
|
}
|
|
|
|
check_permissions() {
|
|
print_header "Permissions on event/joystick nodes"
|
|
local any=0
|
|
for path in /dev/input/by-id/*-event-joystick /dev/input/js*; do
|
|
if [[ -e $path ]]; then
|
|
any=1
|
|
printf '%s -> ' "$path"
|
|
local dev
|
|
dev=$(readlink -f "$path" 2> /dev/null || echo "$path")
|
|
stat -c '%A %a %U:%G %n' "$dev" 2> /dev/null || true
|
|
fi
|
|
done
|
|
if [[ $any -eq 0 ]]; then
|
|
echo "No event-joystick or js nodes found to check permissions."
|
|
fi
|
|
echo
|
|
if [[ $(detect_distro) == "arch" ]]; then
|
|
echo "On Arch, prefer TAG+\"uaccess\"-based access over adding users to the 'input' group."
|
|
echo "If access is denied in apps, install: pacman -S game-devices-udev (provides modern udev rules)."
|
|
fi
|
|
echo
|
|
}
|
|
|
|
suggest_tests() {
|
|
print_header "Next steps / tests"
|
|
echo "- Test evdev: install 'evtest' and run: evtest /dev/input/by-id/*-event-joystick"
|
|
echo "- Test joystick API: install 'joystick' (jstest) and run: jstest /dev/input/js0 (if present)"
|
|
echo "- For force feedback test (rumble): install 'linuxconsole' (fftest): fftest /dev/input/by-id/*-event-joystick"
|
|
echo
|
|
echo "Steam users: Ensure Steam Input settings match your use case. If rumble fails in SDL titles, try: SDL_JOYSTICK_HIDAPI=0"
|
|
echo
|
|
echo "If you are actually using Bluetooth: consider xpadneo (AUR: xpadneo-dkms)."
|
|
echo "If you are using the official wireless USB adapter: consider xone (AUR: xone-dkms and xone-dongle-firmware)."
|
|
echo
|
|
}
|
|
|
|
main() {
|
|
require_root "$@"
|
|
print_header "${SCRIPT_NAME} starting"
|
|
log "Kernel: $(uname -r) | Distro: $(detect_distro)"
|
|
|
|
show_lsusb
|
|
show_modules
|
|
|
|
# Load common modules safely (idempotent)
|
|
modprobe_safe usbhid
|
|
modprobe_safe xpad
|
|
modprobe_safe joydev
|
|
|
|
# If xpad failed to load and kernel says it's a module, but it's not present, hint about out-of-sync modules
|
|
if ! lsmod | grep -q '^xpad\b'; then
|
|
if command -v zcat > /dev/null 2>&1 && [[ -r /proc/config.gz ]] && zcat /proc/config.gz 2> /dev/null | grep -q '^CONFIG_JOYSTICK_XPAD=m'; then
|
|
if ! find "/lib/modules/$(uname -r)" -type f -name 'xpad*.ko*' 2> /dev/null | grep -q .; then
|
|
log "xpad is configured as a module but missing under /lib/modules/$(uname -r). Your kernel modules may be out-of-sync or incomplete."
|
|
if [[ $(detect_distro) == "arch" ]]; then
|
|
echo "Arch hint: reinstall the matching kernel package (e.g. 'sudo pacman -S linux' or your variant like linux-zen) and reboot."
|
|
else
|
|
echo "Hint: reinstall your running kernel's modules then reboot."
|
|
fi
|
|
echo
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
list_input_nodes
|
|
check_permissions
|
|
show_dmesg_hints
|
|
|
|
# Simple heuristic: do we see an Xbox/Microsoft event-joystick?
|
|
if compgen -G "/dev/input/by-id/*-event-joystick" > /dev/null; then
|
|
local found_label=0
|
|
for f in /dev/input/by-id/*-event-joystick; do
|
|
[[ -e $f ]] || continue
|
|
if printf '%s' "$(basename "$f")" | grep -Eqi 'xbox|microsoft|controller|wireless'; then
|
|
found_label=1
|
|
break
|
|
fi
|
|
done
|
|
if ((found_label == 1)); then
|
|
log "Controller event device detected."
|
|
else
|
|
log "Event-joystick device(s) exist but not obviously Xbox-labelled. Still likely usable."
|
|
fi
|
|
else
|
|
log "No -event-joystick device found. If the controller vibrated but no input node exists, check the cable and try another USB port/cable."
|
|
log "Also check dmesg for descriptor errors; for Xbox 360 Play&Charge cable: note it only charges and does not carry input."
|
|
fi
|
|
|
|
suggest_tests
|
|
|
|
print_header "Done"
|
|
}
|
|
|
|
main "$@"
|