Last active
April 30, 2026 05:03
-
-
Save timsonner/1d81c099181457a611c17cb7d0be63e0 to your computer and use it in GitHub Desktop.
Fixes third monitor not showing with DisplayLink on Proxmox VE / Debian trixie with kernel 7.0+ and GNOME Wayland. Re-connect dock after run.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # fix-displaylink.sh | |
| # | |
| # Fixes DisplayLink on Proxmox VE / Debian trixie with kernel 7.0+ and GNOME Wayland. | |
| # | |
| # Root cause: DisplayLinkManager uses dlopen("libevdi.so") at runtime, but the | |
| # Debian package install does NOT build/install libevdi.so into /usr/lib/displaylink/. | |
| # Without it, DLM silently fails to open any evdi virtual displays. | |
| # | |
| # Additionally, the Debian evdi package (1.14.8) does not build against kernel 7.0+ | |
| # due to DRM API changes, so evdi 1.14.15 must be built from source via DKMS. | |
| # | |
| # Requirements before running this script: | |
| # - Kernel 7.0.0-3-pve (or later) running: uname -r | |
| # - displaylink-driver package installed (provides /usr/lib/displaylink/) | |
| # - DisplayLink dock plugged in | |
| # | |
| # What this script does: | |
| # 1. Builds evdi 1.14.15 kernel module via DKMS (if not already installed) | |
| # 2. Builds libevdi.so from DisplayLink's bundled evdi.tar.gz | |
| # 3. Installs libevdi.so into /usr/lib/displaylink/ | |
| # 4. Restarts the displaylink-driver service | |
| set -e | |
| KERNEL=$(uname -r) | |
| DL_DIR="/usr/lib/displaylink" | |
| EVDI_TAR="$DL_DIR/evdi.tar.gz" | |
| BUILD_DIR="/tmp/evdi-dl-build" | |
| EVDI_DKMS_VER="1.14.15" | |
| EVDI_DKMS_SRC="/usr/src/evdi-${EVDI_DKMS_VER}" | |
| # Must run as root | |
| if [ "$(id -u)" -ne 0 ]; then | |
| echo "Error: run this script as root (sudo $0)" >&2 | |
| exit 1 | |
| fi | |
| # Check DisplayLink is installed | |
| if [ ! -f "$DL_DIR/DisplayLinkManager" ]; then | |
| echo "Error: $DL_DIR/DisplayLinkManager not found." >&2 | |
| echo "Install the displaylink-driver Debian package first." >&2 | |
| exit 1 | |
| fi | |
| echo "=== Step 1: Install build dependencies ===" | |
| apt-get install -y --no-install-recommends dkms libdrm-dev build-essential git | |
| echo "" | |
| echo "=== Step 2: Build evdi $EVDI_DKMS_VER kernel module via DKMS ===" | |
| if dkms status evdi/$EVDI_DKMS_VER | grep -q "installed.*$KERNEL"; then | |
| echo "evdi $EVDI_DKMS_VER already installed for $KERNEL, skipping." | |
| else | |
| if [ ! -d "$EVDI_DKMS_SRC" ]; then | |
| echo "Cloning evdi $EVDI_DKMS_VER from GitHub..." | |
| REPO_DIR=$(mktemp -d) | |
| git clone --branch "v${EVDI_DKMS_VER}" --depth 1 \ | |
| https://github.com/DisplayLink/evdi.git "$REPO_DIR" | |
| cp -r "$REPO_DIR/module" "$EVDI_DKMS_SRC" | |
| rm -rf "$REPO_DIR" | |
| fi | |
| # Unregister any conflicting evdi versions from DKMS | |
| for old_ver in $(dkms status evdi | awk -F'[,/]' '{print $2}' | tr -d ' ' | sort -u); do | |
| if [ "$old_ver" != "$EVDI_DKMS_VER" ]; then | |
| echo "Removing conflicting evdi DKMS version: $old_ver" | |
| dkms remove evdi/"$old_ver" --all 2>/dev/null || true | |
| fi | |
| done | |
| dkms add -m evdi -v "$EVDI_DKMS_VER" | |
| dkms build evdi/"$EVDI_DKMS_VER" -k "$KERNEL" | |
| dkms install evdi/"$EVDI_DKMS_VER" -k "$KERNEL" | |
| echo "evdi $EVDI_DKMS_VER installed for $KERNEL." | |
| fi | |
| echo "" | |
| echo "=== Step 3: Build libevdi.so from DisplayLink's bundled evdi source ===" | |
| if [ ! -f "$EVDI_TAR" ]; then | |
| echo "Error: $EVDI_TAR not found." >&2 | |
| echo "Is the displaylink-driver package properly installed?" >&2 | |
| exit 1 | |
| fi | |
| rm -rf "$BUILD_DIR" | |
| mkdir -p "$BUILD_DIR" | |
| tar -xzf "$EVDI_TAR" -C "$BUILD_DIR" | |
| make -C "$BUILD_DIR/library" | |
| LIBEVDI_VER=$(grep 'LIBVER' "$BUILD_DIR/library/Makefile" | head -1 | awk -F':=' '{print $2}' | tr -d ' ') | |
| echo "Built libevdi.so.$LIBEVDI_VER" | |
| echo "" | |
| echo "=== Step 4: Install libevdi.so into $DL_DIR ===" | |
| install -m 0755 "$BUILD_DIR/library/libevdi.so.$LIBEVDI_VER" "$DL_DIR/libevdi.so" | |
| echo "Installed $DL_DIR/libevdi.so" | |
| rm -rf "$BUILD_DIR" | |
| echo "" | |
| echo "=== Step 5: Load evdi module and restart DisplayLink service ===" | |
| modprobe evdi 2>/dev/null || true | |
| systemctl restart displaylink-driver | |
| echo "" | |
| echo "=== Done ===" | |
| echo "Waiting 3 seconds for DLM to initialize..." | |
| sleep 3 | |
| REFCNT=$(cat /sys/module/evdi/refcnt 2>/dev/null || echo "unknown") | |
| echo "evdi refcount: $REFCNT (should be >= 1 if DLM opened it)" | |
| CONNECTORS=$(ls /sys/class/drm/ | grep -v 'card1\|card0\|render\|version' || echo "none") | |
| echo "DisplayLink DRM connectors: $CONNECTORS" | |
| for connector in $(ls /sys/class/drm/ | grep -E '^card[2-9]'); do | |
| status=$(cat /sys/class/drm/${connector}-*/status 2>/dev/null | head -1) | |
| echo " $connector: $status" | |
| done | |
| if [ "$REFCNT" -ge 1 ] 2>/dev/null; then | |
| echo "" | |
| echo "Success! Open GNOME Settings -> Displays to configure your DisplayLink monitor." | |
| else | |
| echo "" | |
| echo "Warning: evdi refcount is $REFCNT — DLM may not have loaded libevdi.so correctly." | |
| echo "Check: strings $DL_DIR/DisplayLinkManager | grep 'libevdi'" | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment