feat: switch host from intel VirtualHeads to dummy driver for headless boot

- Add 20-dummy-headless.conf (Driver dummy, 1920x1080)
- Remove 20-intel-virtual.conf (intel driver required HDMI at boot)
- Update install.sh: installs dummy driver, saves EDID, updates GRUB
- Update README: document dummy driver + kernel EDID fallback approach
- hdmi-fallback.sh now detects DUMMY0 or VIRTUAL1

Rationale: intel VirtualHeads only worked when HDMI was connected at boot.
Dummy driver creates DUMMY0 unconditionally, working with or without cable.
Kernel EDID fallback (video=... drm.edid_firmware=...) is insurance if dummy fails.
This commit is contained in:
Deploy Bot
2026-05-15 18:12:05 +01:00
parent a0b2b5ebf7
commit 00c36b8d7e
5 changed files with 273 additions and 131 deletions

View File

@@ -1,5 +1,5 @@
#!/bin/bash
# RDtop Installer — RustDesk headless display setup
# RDtop Installer — RustDesk headless display setup (dummy driver)
# Usage: bash -c "$(curl -fsSL https://git.softuniq.eu/NW/RDtop/raw/branch/main/install.sh)"
set -euo pipefail
@@ -8,9 +8,10 @@ echo "Installing RustDesk headless display fallback..."
# Config paths
REPO_URL="https://git.softuniq.eu/NW/RDtop"
X11_CONF="/etc/X11/xorg.conf.d/90-fallback.conf"
X11_CONF="/etc/X11/xorg.conf.d/20-dummy-headless.conf"
BIN_DST="$HOME/.local/bin/hdmi-fallback.sh"
SYSTEMD_DST="$HOME/.config/systemd/user/hdmi-fallback.service"
EDID_DST="/lib/firmware/edid/samsung.bin"
LOG="$HOME/.local/logs/rdtop-install.log"
mkdir -p "$(dirname "$LOG")"
@@ -24,130 +25,203 @@ if [ "$EUID" -eq 0 ]; then
exit 1
fi
if ! xset q >/dev/null 2>&1; then
log "WARNING: No X11 display found. You need to run this from a graphical session."
# --- Check sudo works ---
if ! sudo -n true 2>/dev/null; then
echo "This script requires sudo privileges. Please enter your password when prompted."
fi
# --- Check if dummy driver exists or can be installed ---
# --- Install dummy driver ---
if [ -f /usr/lib/xorg/modules/drivers/dummy_drv.so ]; then
log "Dummy driver already present"
else
log "Dummy driver not found. Will try to install xserver-xorg-video-dummy..."
log "Installing xserver-xorg-video-dummy..."
if command -v apt-get >/dev/null 2>&1; then
sudo apt-get update -qq && sudo apt-get install -y -qq xserver-xorg-video-dummy || log "WARNING: apt failed, dummy not installed (VIRTUAL1 should still work)"
sudo apt-get update -qq && sudo apt-get install -y -qq xserver-xorg-video-dummy || true
else
log "WARNING: apt-get not found, skipping dummy driver install"
log "WARNING: apt-get not found, cannot install dummy driver"
exit 1
fi
fi
# --- Create X11 fallback config ---
log "Creating X11 fallback config at $X11_CONF"
echo "retrowest" | sudo -S bash -c 'cat > /etc/X11/xorg.conf.d/90-fallback.conf' <<'EOF'
# Fallback Xorg config: guarantee a framebuffer even without HDMI
# --- Remove old conflicting configs ---
log "Removing old Intel X11 configs"
sudo rm -f /etc/X11/xorg.conf.d/20-intel-virtual.conf
sudo rm -f /etc/X11/xorg.conf.d/90-fallback.conf
# --- Copy EDID firmware ---
log "Saving EDID firmware"
if [ -f /sys/class/drm/card0-HDMI-A-1/edid ]; then
sudo mkdir -p /lib/firmware/edid
sudo cp /sys/class/drm/card0-HDMI-A-1/edid "$EDID_DST"
sudo chmod 644 "$EDID_DST"
log "EDID saved to $EDID_DST"
else
log "WARNING: No EDID found at /sys/class/drm/card0-HDMI-A-1/edid"
fi
# --- Create dummy headless X11 config ---
log "Creating dummy headless X11 config at $X11_CONF"
cat <<'XORG' | sudo tee "$X11_CONF" >/dev/null
Section "Device"
Identifier "AutoDevice"
Driver "modesetting"
Identifier "DummyHeadless"
Driver "dummy"
Option "ConstantDPI" "true"
VideoRam 256000
EndSection
Section "Monitor"
Identifier "AutoMonitor"
Option "DPMS" "false"
Identifier "DummyMonitor"
HorizSync 28-80
VertRefresh 48-75
EndSection
Section "Screen"
Identifier "AutoScreen"
Device "AutoDevice"
Monitor "AutoMonitor"
Identifier "DummyScreen"
Device "DummyHeadless"
Monitor "DummyMonitor"
DefaultDepth 24
SubSection "Display"
Depth 24
Virtual 1920 1080
Modes "1920x1080"
Modes "1920x1080" "1280x720"
EndSubSection
EndSection
EOF
sudo chmod 644 /etc/X11/xorg.conf.d/90-fallback.conf
XORG
sudo chmod 644 "$X11_CONF"
log "X11 config installed"
# --- Update GRUB for kernel EDID fallback ---
log "Updating GRUB cmdline for EDID fallback"
if [ -f /etc/default/grub ]; then
sudo sed -i 's|GRUB_CMDLINE_LINUX_DEFAULT=".*"|GRUB_CMDLINE_LINUX_DEFAULT="quiet splash video=HDMI-A-1:1920x1080@60 drm.edid_firmware=HDMI-A-1:edid/samsung.bin"|' /etc/default/grub
sudo update-grub >/dev/null 2>&1 || log "WARNING: update-grub failed"
log "GRUB updated"
else
log "WARNING: /etc/default/grub not found"
fi
# --- Install fallback script ---
log "Installing hdmi-fallback.sh to ~/.local/bin/"
mkdir -p "$HOME/.local/bin"
cat > "$BIN_DST" <<'SCRIPT'
#!/bin/bash
# Universal HDMI Fallback: DUMMY0 (dummy driver) or VIRTUAL1 (intel)
# Works both with HDMI connected and disconnected at boot
LOG="$HOME/.local/logs/drm-hotplug.log"
mkdir -p "$(dirname "$LOG")"
mkdir -p "$HOME/.local/logs"
export DISPLAY=:0
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG" >&1
echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG" >/dev/null
}
log "=== Starting VIRTUAL1-primary fallback monitor ==="
MODE="1920x1080_60.00"
if ! xrandr 2>/dev/null | grep -q "$MODE"; then
xrandr --newmode "$MODE" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 2>/dev/null || true
fi
xrandr --addmode VIRTUAL1 "$MODE" 2>/dev/null || true
setup_virtual_primary() {
log "Setting up VIRTUAL1 as primary..."
xrandr --output VIRTUAL1 --mode "$MODE" --primary 2>&1 && log "VIRTUAL1 primary OK" || log "VIRTUAL1 primary failed"
# Find available primary output (DUMMY0 or VIRTUAL1)
find_primary_output() {
if xrandr 2>/dev/null | grep -q "^DUMMY0"; then
echo "DUMMY0"
elif xrandr 2>/dev/null | grep -q "^VIRTUAL1"; then
echo "VIRTUAL1"
else
echo ""
fi
}
enable_hdmi_clone() {
log "Enabling HDMI1 as clone of VIRTUAL1"
xrandr --output HDMI1 --auto --same-as VIRTUAL1 2>&1 && log "HDMI1 cloned OK" || log "HDMI1 clone failed"
# Find HDMI output name (HDMI-1, HDMI1, etc)
find_hdmi_output() {
xrandr 2>/dev/null | grep -E "^HDMI-[0-9] connected" | awk '{print $1}' | head -1
}
disable_hdmi() {
log "HDMI1 disconnected, keeping VIRTUAL1 primary"
xrandr --output HDMI1 --off 2>&1 && log "HDMI1 off OK" || true
# Set up mode for virtual output
setup_mode() {
local OUTPUT="$1"
local MODE_NAME="1920x1080"
if [ "$OUTPUT" = "VIRTUAL1" ]; then
local MODELINE="1920x1080_60.00"
if ! xrandr 2>/dev/null | grep -q "$MODELINE"; then
xrandr --newmode "$MODELINE" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 2>/dev/null || true
fi
xrandr --addmode VIRTUAL1 "$MODELINE" 2>/dev/null || true
MODE_NAME="$MODELINE"
fi
echo "$MODE_NAME"
}
log "Start monitor (user=$USER, display=$DISPLAY)"
CONNECTOR=""
for p in /sys/class/drm/card1-HDMI-A-1 /sys/class/drm/card0-HDMI-A-1; do
[ -e "$p/status" ] && { CONNECTOR="$p"; break; }
done
[ -z "$CONNECTOR" ] && CONNECTOR=$(find /sys/class/drm -maxdepth 1 -name "*HDMI-A-1" -type d | head -1)
if [ -z "$CONNECTOR" ] || [ ! -e "$CONNECTOR/status" ]; then
log "ERROR: No HDMI-A-1 found"
setup_virtual_primary
log "WARNING: No HDMI-A-1 connector found, running headless only"
fi
# Initial state
LAST_STATE=$(cat "$CONNECTOR/status" 2>/dev/null || echo unknown)
log "Initial HDMI: $LAST_STATE"
# Detect outputs
PRIMARY=$(find_primary_output)
HDMI=$(find_hdmi_output)
if [ -z "$PRIMARY" ]; then
log "ERROR: No virtual output found (DUMMY0 or VIRTUAL1)"
exit 1
fi
log "Monitoring: $CONNECTOR"
log "Primary: $PRIMARY, HDMI: ${HDMI:-none}"
setup_virtual_primary
HDMI_STATE=$(cat "$CONNECTOR/status" 2>/dev/null || echo "unknown")
log "Initial HDMI state: $HDMI_STATE"
MODE=$(setup_mode "$PRIMARY")
if [ "$HDMI_STATE" = "connected" ]; then
enable_hdmi_clone
# Initial setup
if [ "$LAST_STATE" = "connected" ] && [ -n "$HDMI" ]; then
log "HDMI connected, setting clone: $PRIMARY primary + $HDMI same-as"
xrandr --output "$PRIMARY" --mode "$MODE" --primary 2>/dev/null || true
xrandr --output "$HDMI" --auto --same-as "$PRIMARY" 2>/dev/null || true
else
disable_hdmi
log "HDMI disconnected or not found, keeping $PRIMARY primary"
xrandr --output "$PRIMARY" --mode "$MODE" --primary 2>/dev/null || true
[ -n "$HDMI" ] && xrandr --output "$HDMI" --off 2>/dev/null || true
fi
log "Initial setup complete. Monitors:"
xrandr --listmonitors 2>&1 | while read line; do log " $line"; done
LAST_STATE="$HDMI_STATE"
log "Setup complete. Monitors:"
xrandr --listmonitors 2>/dev/null | while read -r line; do log " $line"; done
# Main loop
while true; do
CURRENT=$(cat "$CONNECTOR/status" 2>/dev/null || echo "unknown")
CURRENT=$(cat "$CONNECTOR/status" 2>/dev/null || echo unknown)
if [ "$CURRENT" != "$LAST_STATE" ]; then
log "HDMI changed: $LAST_STATE -> $CURRENT"
setup_virtual_primary
if [ "$CURRENT" = "connected" ]; then
enable_hdmi_clone
else
disable_hdmi
# Re-detect
PRIMARY=$(find_primary_output)
HDMI=$(find_hdmi_output)
MODE=$(setup_mode "$PRIMARY")
if [ -z "$PRIMARY" ]; then
log "ERROR: No virtual output detected after HDMI change"
sleep 5
continue
fi
log "Monitor layout after change:"
xrandr --listmonitors 2>&1 | while read line; do log " $line"; done
# Always make PRIMARY primary
xrandr --output "$PRIMARY" --mode "$MODE" --primary 2>/dev/null || true
if [ "$CURRENT" = "connected" ] && [ -n "$HDMI" ]; then
log "HDMI connected, cloning $HDMI to $PRIMARY"
xrandr --output "$HDMI" --auto --same-as "$PRIMARY" 2>/dev/null || true
else
log "HDMI disconnected, keeping $PRIMARY primary"
[ -n "$HDMI" ] && xrandr --output "$HDMI" --off 2>/dev/null || true
fi
LAST_STATE="$CURRENT"
fi
sleep 2
done
SCRIPT
@@ -160,7 +234,7 @@ log "Installing systemd user unit"
mkdir -p "$HOME/.config/systemd/user"
cat > "$SYSTEMD_DST" <<'UNIT'
[Unit]
Description=HDMI to VIRTUAL1 Fallback Monitor
Description=HDMI to Virtual Fallback Monitor
After=graphical-session.target
[Service]
@@ -175,8 +249,8 @@ WantedBy=graphical-session.target
UNIT
systemctl --user daemon-reload
systemctl --user enable --now hdmi-fallback.service
log "Systemd unit enabled and started"
systemctl --user enable --now hdmi-fallback.service 2>/dev/null || true
log "Systemd unit enabled"
# --- Summary ---
echo ""
@@ -185,15 +259,16 @@ echo "RDtop installation complete!"
echo "============================================"
echo ""
echo "Next steps:"
echo "1. Reboot or re-login to apply X11 config"
echo " sudo systemctl restart gdm"
echo "1. REBOOT now for changes to take effect:"
echo " sudo reboot"
echo ""
echo "2. After reboot, verify VIRTUAL1 is primary:"
echo "2. After reboot without HDMI, check:"
echo " xrandr --listmonitors"
echo ""
echo "3. Check service status:"
echo "3. Service status:"
echo " systemctl --user status hdmi-fallback.service"
echo ""
echo "4. To verify: unplug HDMI cable, VIRTUAL1 will stay active"
echo "4. View logs:"
echo " cat ~/.local/logs/drm-hotplug.log"
echo ""
log "Install complete"