diff --git a/bin/xconfig b/bin/xconfig index bd41da6..d1d61e5 100755 --- a/bin/xconfig +++ b/bin/xconfig @@ -1,29 +1,21 @@ #!/bin/sh -# -# xconfig - Intelligent X11 configuration tool for GhostBSD / FreeBSD -# -# - Detects GPUs and common hypervisors -# - Installs appropriate drivers (optionally from /xdrivers) -# - Applies tuned Xorg configuration templates -# - Supports Xorg and XLibre X servers -# -# This version includes explicit bhyve detection which maps to the scfb template. -# set -eu SCRIPT_NAME=$(basename "$0") -SCRIPT_DIR=$(dirname "$(readlink -f "$0" 2>/dev/null || echo "$0")") +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) LOG_FILE="/var/log/xconfig.log" XORG_CONF="/etc/X11/xorg.conf" BACKUP_DIR="/etc/X11/backup" +BACKUP_KEEP=10 -# Where to look for cardDetect templates LOCAL_CONFIG_DIR="$SCRIPT_DIR/cardDetect" SYSTEM_CONFIG_DIR="/usr/local/etc/X11/cardDetect" -# Default to POSIX locale for predictable dialog output +# Allow override via environment +NVIDIA_DRIVER_VERSION="${NVIDIA_DRIVER_VERSION:-580}" + export LC_ALL=C ############################################################################### @@ -31,260 +23,613 @@ export LC_ALL=C ############################################################################### log() { - level=$1 - shift || true ts=$(date '+%Y-%m-%d %H:%M:%S') - msg=$* - printf '[%s] [%s] %s\n' "$ts" "$level" "$msg" | tee -a "$LOG_FILE" >&2 + lvl=$1 + shift + printf "[%s] [%s] %s\n" "$ts" "$lvl" "$*" | tee -a "$LOG_FILE" >&2 } ############################################################################### -# Helpers: config directory, backup, application +# rc.conf management helpers +############################################################################### + +rc_conf_get() { + key=$1 + sysrc -n "$key" 2>/dev/null || echo "" +} + +rc_conf_has() { + key=$1 + + if grep "^$key=" /etc/rc.conf >/dev/null 2>&1 ; then + return 0 + fi + + if [ -f /etc/rc.conf.local ] && grep "^$key=" /etc/rc.conf.local >/dev/null 2>&1 ; then + return 0 + fi + + return 1 +} + +enable_rc_conf() { + key=$1 + val=$2 + current=$(rc_conf_get "$key") + + if [ "$current" = "$val" ]; then + log INFO "$key already set to $val" + elif rc_conf_has "$key"; then + log INFO "Updating $key from '$current' to '$val'" + sysrc "${key}=${val}" + else + log INFO "Enabling $key=$val" + sysrc "${key}=${val}" + fi +} + +start_service_safe() { + svc=$1 + + if service "$svc" onestatus >/dev/null 2>&1 ; then + log INFO "$svc already running" + return 0 + fi + + log INFO "Starting $svc" + if service "$svc" start >/dev/null 2>&1 ; then + log INFO "$svc started" + else + log WARN "$svc failed to start" + fi +} + +############################################################################### +# Template + backup management ############################################################################### find_config_dir() { if [ -d "$LOCAL_CONFIG_DIR" ]; then echo "$LOCAL_CONFIG_DIR" - return 0 + return fi + if [ -d "$SYSTEM_CONFIG_DIR" ]; then echo "$SYSTEM_CONFIG_DIR" - return 0 + return fi + echo "" - return 1 } backup_xorg_conf() { if [ -f "$XORG_CONF" ]; then mkdir -p "$BACKUP_DIR" ts=$(date '+%Y%m%d_%H%M%S') - backup="$BACKUP_DIR/xorg.conf.$ts" - cp "$XORG_CONF" "$backup" - log INFO "Backed up existing $XORG_CONF to $backup" + cp "$XORG_CONF" "$BACKUP_DIR/xorg.conf.$ts" + log INFO "Backed up existing xorg.conf" + + # Prune old backups, keep only BACKUP_KEEP most recent + # shellcheck disable=SC2012 + ls -t "$BACKUP_DIR"/xorg.conf.* 2>/dev/null | tail -n +"$((BACKUP_KEEP + 1))" | xargs rm -f 2>/dev/null || true fi } apply_config_template() { - template_name=$1 + template=$1 + dir=$(find_config_dir) - CONFIG_DIR=$(find_config_dir || true) - if [ -z "$CONFIG_DIR" ]; then - log ERROR "No cardDetect directory found. Tried: $LOCAL_CONFIG_DIR and $SYSTEM_CONFIG_DIR" - log ERROR "Cannot apply template $template_name" + if [ -z "$dir" ]; then + log ERROR "No cardDetect directory found" return 1 fi - template_path="$CONFIG_DIR/$template_name" - if [ ! -f "$template_path" ]; then - log ERROR "Template $template_name not found in $CONFIG_DIR" + path="$dir/$template" + + if [ ! -f "$path" ]; then + log ERROR "Template $template not found" return 1 fi mkdir -p "$(dirname "$XORG_CONF")" backup_xorg_conf - cp "$template_path" "$XORG_CONF" - log INFO "Applied template $template_name to $XORG_CONF" - return 0 + cp "$path" "$XORG_CONF" + log INFO "Applied template $template" } ############################################################################### -# Helpers: /xdrivers offline installs and pkg +# Offline driver install (/xdrivers) ############################################################################### install_from_xdrivers() { pkgname=$1 - if [ ! -d /xdrivers ]; then - return 1 - fi - if [ ! -f /xdrivers/drivers-list ]; then - return 1 - fi + [ -d /xdrivers ] || return 1 + [ -f /xdrivers/drivers-list ] || return 1 - # Format: " " - filename=$(awk -v p="$pkgname" '$1 == p {print $2}' /xdrivers/drivers-list | head -n 1) - if [ -z "$filename" ]; then - return 1 - fi + file=$(awk -v p="$pkgname" '$1 == p { print $2 }' /xdrivers/drivers-list | head -n 1) - pkgpath="/xdrivers/$filename" - if [ ! -f "$pkgpath" ]; then - log WARN "Entry for $pkgname found in /xdrivers/drivers-list but $pkgpath is missing" - return 1 - fi + [ -n "$file" ] || return 1 + [ -f "/xdrivers/$file" ] || return 1 - log INFO "Installing $pkgname from offline package $pkgpath" - if pkg add "$pkgpath"; then + log INFO "Installing $pkgname from offline package" + # Note: offline packages must include all dependencies in /xdrivers + if pkg add "/xdrivers/$file"; then return 0 fi - log WARN "Offline install from $pkgpath failed for $pkgname" + log WARN "Offline install failed for $pkgname (missing dependencies?)" return 1 } pkg_install_wrapper() { pkgname=$1 - if install_from_xdrivers "$pkgname"; then - return 0 - fi + install_from_xdrivers "$pkgname" && return 0 - log INFO "Installing $pkgname from pkg repositories" - if pkg install -y "$pkgname"; then - return 0 - fi + log INFO "Installing $pkgname from pkg" + pkg install -y "$pkgname" && return 0 - log ERROR "Failed to install package $pkgname" + log ERROR "Failed to install $pkgname" return 1 } ############################################################################### -# X server detection: Xorg vs XLibre +# Dialog detection and wrappers ############################################################################### -detect_x_server() { - # Returns: "xorg" or "xlibre" - if command -v xlibre >/dev/null 2>&1; then - echo "xlibre" - return 0 +# Detect available dialog tool (prefer bsddialog) +detect_dialog_tool() { + if command -v bsddialog >/dev/null 2>&1; then + echo "bsddialog" + elif command -v dialog >/dev/null 2>&1; then + echo "dialog" + else + echo "" fi +} - if [ -x /usr/local/bin/xlibre ]; then - echo "xlibre" - return 0 +# Run a menu dialog, returns selected tag via stdout +# Usage: run_menu_dialog "title" "prompt" tag1 label1 tag2 label2 ... +run_menu_dialog() { + title=$1 + prompt=$2 + shift 2 + + tool=$(detect_dialog_tool) + if [ -z "$tool" ]; then + log ERROR "No dialog tool found. Install bsddialog or dialog." + return 1 + fi + + # Build menu items safely using set -- + set -- + while [ $# -ge 2 ]; do + set -- "$@" "$1" "$2" + shift 2 + done + + # Create temp file for result + tmpfile=$(mktemp) + trap "rm -f '$tmpfile'" EXIT + + if [ "$tool" = "bsddialog" ]; then + bsddialog --title "$title" --menu "$prompt" 0 0 0 "$@" 2>"$tmpfile" + ret=$? + else + dialog --title "$title" --menu "$prompt" 0 0 0 "$@" 2>"$tmpfile" + ret=$? fi - # Default to Xorg - echo "xorg" - return 0 + if [ $ret -eq 0 ]; then + cat "$tmpfile" + fi + rm -f "$tmpfile" + trap - EXIT + return $ret +} + +# Display an info message box +# Usage: run_msgbox "title" "message" +run_msgbox() { + title=$1 + message=$2 + + tool=$(detect_dialog_tool) + if [ -z "$tool" ]; then + echo "$message" + return + fi + + if [ "$tool" = "bsddialog" ]; then + bsddialog --title "$title" --msgbox "$message" 0 0 + else + dialog --title "$title" --msgbox "$message" 0 0 + fi } ############################################################################### -# Hardware detection helpers +# X server detection ############################################################################### +detect_x_server() { + if command -v xlibre >/dev/null 2>&1 ; then + echo xlibre + return + fi + echo xorg +} + +############################################################################### +# VM + GPU detection +############################################################################### + +# Cache vm_guest detection result +_VM_GUEST_CACHE="" + detect_vm_guest() { - # Print kern.vm_guest if available - if sysctl -n kern.vm_guest >/dev/null 2>&1; then - sysctl -n kern.vm_guest - return 0 + if [ -n "$_VM_GUEST_CACHE" ]; then + echo "$_VM_GUEST_CACHE" + return + fi + + if sysctl -n kern.vm_guest >/dev/null 2>&1 ; then + _VM_GUEST_CACHE=$(sysctl -n kern.vm_guest) + else + _VM_GUEST_CACHE="none" fi - echo "none" - return 0 + echo "$_VM_GUEST_CACHE" } detect_virtualbox() { guest=$(detect_vm_guest) - if echo "$guest" | grep -qi "vbox"; then - return 0 - fi - if dmesg 2>/dev/null | grep -qi "VirtualBox"; then - return 0 - fi + echo "$guest" | grep -qi vbox && return 0 + dmesg 2>/dev/null | grep -qi VirtualBox && return 0 return 1 } detect_vmware() { guest=$(detect_vm_guest) - if echo "$guest" | grep -qi "vmware"; then - return 0 - fi - if dmesg 2>/dev/null | grep -qi "VMware"; then - return 0 - fi + echo "$guest" | grep -qi vmware && return 0 + dmesg 2>/dev/null | grep -qi VMware && return 0 return 1 } detect_qemu() { guest=$(detect_vm_guest) - if echo "$guest" | grep -qi "kvm"; then - return 0 - fi - if echo "$guest" | grep -qi "qemu"; then - return 0 - fi - if dmesg 2>/dev/null | grep -qi "QEMU"; then - return 0 - fi + echo "$guest" | grep -qi kvm && return 0 + echo "$guest" | grep -qi qemu && return 0 + dmesg 2>/dev/null | grep -qi QEMU && return 0 return 1 } detect_hyperv() { guest=$(detect_vm_guest) - if echo "$guest" | grep -qi "hyperv"; then - return 0 - fi - if dmesg 2>/dev/null | grep -qi "Hyper-V"; then - return 0 - fi + echo "$guest" | grep -qi hyperv && return 0 + dmesg 2>/dev/null | grep -qi Hyper-V && return 0 return 1 } detect_bhyve() { guest=$(detect_vm_guest) - if echo "$guest" | grep -qi "bhyve"; then - return 0 - fi - # Secondary heuristic if needed - if dmesg 2>/dev/null | grep -qi "bhyve"; then - return 0 - fi + echo "$guest" | grep -qi bhyve && return 0 + dmesg 2>/dev/null | grep -qi bhyve && return 0 return 1 } detect_intel_gpu() { - if pciconf -lv 2>/dev/null | grep -A4 -Ei "vga|display" | grep -qi "Intel"; then - return 0 - fi - return 1 + pciconf -lv 2>/dev/null | grep -A4 -Ei "vga|display" | grep -qi Intel } detect_amd_gpu() { - if pciconf -lv 2>/dev/null | grep -A4 -Ei "vga|display" | grep -Eiq "AMD|ATI"; then - return 0 - fi - return 1 + pciconf -lv 2>/dev/null | grep -A4 -Ei "vga|display" | grep -Eiq "AMD|ATI" } detect_nvidia_gpu() { - if pciconf -lv 2>/dev/null | grep -A4 -Ei "vga|display" | grep -qi "NVIDIA"; then - return 0 + # Check VGA, display, AND 3D controller classes + # Many NVIDIA dGPUs (especially in laptops/servers) register as 3D controller + pciconf -lv 2>/dev/null | grep -A4 -Ei "vga|display|3d" | grep -qi NVIDIA +} + +# Get NVIDIA GPU PCI device IDs (returns space-separated list) +# Includes VGA, display, and 3D controller class devices +get_nvidia_device_ids() { + pciconf -l 2>/dev/null | grep -i "chip=.*10de" | \ + sed -E 's/.*chip=0x([0-9a-fA-F]{4}).*/\1/' | tr 'A-F' 'a-f' | sort -u +} + +# Map NVIDIA device ID to required driver series +# Based on NVIDIA's legacy driver support matrix +# Returns: 580 (current), 470, 390, 340, or 304 +nvidia_device_to_driver() { + devid=$1 + + # Convert to lowercase for comparison + devid=$(echo "$devid" | tr 'A-F' 'a-f') + + # First, check explicit device ID table for known edge cases + # This catches GPUs that don't fit neat prefix patterns + case "$devid" in + # ===== 304.xx legacy (NV4x/G7x: GeForce 6xxx, 7xxx) ===== + # These are GeForce 6/7 series from ~2004-2006 + 0040|0041|0042|0043|0044|0045|0046|0047|0048|004e) echo "304"; return ;; + 0090|0091|0092|0093|0095|0098|0099|009d) echo "304"; return ;; + 00c0|00c1|00c2|00c3|00c8|00c9|00cc|00cd|00ce) echo "304"; return ;; + 00f1|00f2|00f3|00f4|00f5|00f6|00f8|00f9) echo "304"; return ;; + 0140|0141|0142|0143|0144|0145|0146|0147|0148|0149|014a|014c|014d|014e|014f) echo "304"; return ;; + 0160|0161|0162|0163|0164|0165|0166|0167|0168|0169|016a) echo "304"; return ;; + 0191|0193|0194|0197) echo "304"; return ;; + 01d0|01d1|01d2|01d3|01d6|01d7|01d8|01da|01db|01dc|01dd|01de|01df) echo "304"; return ;; + 0211|0212|0215|0218|021a|021b) echo "304"; return ;; + 0221|0222|0240|0241|0242|0244|0245|0247|0248) echo "304"; return ;; + 0290|0291|0292|0293|0294|0295|0297|0298|0299) echo "304"; return ;; + 029a|029b|029c|029d|029e|029f) echo "304"; return ;; + 02e0|02e1|02e2|02e3|02e4) echo "304"; return ;; + 0390|0391|0392|0393|0394|0395|0397|0398|0399|039c|039e) echo "304"; return ;; + 03d0|03d1|03d2|03d5|03d6) echo "304"; return ;; + + # ===== 340.xx legacy (Tesla: GeForce 8xxx, 9xxx, 1xx, 2xx, 3xx) ===== + # Tesla architecture ~2006-2010 + 0400|0401|0402|0403|0404|0405|0406|0407|0408|0409|0410) echo "340"; return ;; + 0420|0421|0422|0423|0424|0425|0426|0427|0428|0429|042a|042b|042c|042d|042e|042f) echo "340"; return ;; + 05e0|05e1|05e2|05e3|05e6|05e7|05ea|05eb|05ed|05f8|05f9|05fd|05fe|05ff) echo "340"; return ;; + 0600|0601|0602|0603|0604|0605|0606|0607|0608|0609|060a|060b|060c|060d|060f) echo "340"; return ;; + 0610|0611|0612|0613|0614|0615|0617|0618|0619|061a|061b|061c|061d|061e|061f) echo "340"; return ;; + 0620|0621|0622|0623|0625|0626|0627|0628|062a|062b|062c|062d|062e) echo "340"; return ;; + 0630|0631|0632|0635|0637|0638|063a) echo "340"; return ;; + 0640|0641|0643|0644|0645|0646|0647|0648|0649|064a|064b|064c) echo "340"; return ;; + 0651|0652|0653|0654|0655|0656|0658|0659|065a|065b|065c|065f) echo "340"; return ;; + 06c0|06c4|06ca|06cb|06cd|06d1|06d2|06d8|06d9|06da|06dc|06dd|06de|06df) echo "340"; return ;; + 06e0|06e1|06e2|06e3|06e4|06e5|06e6|06e7|06e8|06e9|06ea|06eb|06ec|06ef) echo "340"; return ;; + 06f1|06f8|06f9|06fa|06fb|06fd|06ff) echo "340"; return ;; + 0840|0844|0845|0846|0847|0848|0849|084a|084b|084c|084d|084f) echo "340"; return ;; + 0860|0861|0862|0863|0864|0865|0866|0867|0868|0869|086a|086c|086d|086e|086f) echo "340"; return ;; + 0870|0871|0872|0873|0874|0876) echo "340"; return ;; + 087d|087e|087f) echo "340"; return ;; + 0a20|0a22|0a23|0a26|0a27|0a28|0a29|0a2a|0a2b|0a2c|0a2d) echo "340"; return ;; + 0a30|0a32|0a34|0a35|0a38|0a3c) echo "340"; return ;; + 0a60|0a62|0a63|0a64|0a65|0a66|0a67|0a68|0a69|0a6a|0a6c|0a6e|0a6f) echo "340"; return ;; + 0a70|0a71|0a72|0a73|0a74|0a75|0a76|0a78|0a7a|0a7c) echo "340"; return ;; + 0ca0|0ca2|0ca3|0ca4|0ca5|0ca7|0ca8|0ca9|0cac|0caf) echo "340"; return ;; + 0cb0|0cb1) echo "340"; return ;; + + # ===== 390.xx legacy (Fermi: GeForce 4xx, 5xx, 6xx low-end) ===== + # Fermi architecture ~2010-2012 + 06c0|06c4|06ca|06cb|06cd|06d1|06d2|06d8|06d9|06da|06dc|06dd|06de|06df) echo "390"; return ;; + 0dc0|0dc4|0dc5|0dc6|0dcd|0dce) echo "390"; return ;; + 0dd1|0dd2|0dd3|0dd6|0dd8|0dda) echo "390"; return ;; + 0de0|0de1|0de2|0de3|0de4|0de5|0de7|0de8|0de9|0dea|0deb|0dec|0ded|0dee|0def) echo "390"; return ;; + 0df0|0df1|0df2|0df3|0df4|0df5|0df6|0df7|0df8|0df9|0dfa|0dfc) echo "390"; return ;; + 0e22|0e23|0e24|0e30|0e31|0e3a|0e3b) echo "390"; return ;; + 1040|1042|1048|1049|104a|104b|104c) echo "390"; return ;; + 1050|1051|1052|1054|1055|1056|1057|1058|1059|105a|105b) echo "390"; return ;; + 107c|107d) echo "390"; return ;; + 1080|1081|1082|1084|1086|1087|1088|1089|108b|108e) echo "390"; return ;; + 1091|1094|1096|109a|109b) echo "390"; return ;; + 10c0|10c3|10c5|10d8) echo "390"; return ;; + 1180|1183|1184|1185|1187|1188|1189|118a|118e|118f) echo "390"; return ;; + 1193|1194|1195|1198|1199|119a|119d|119e|119f) echo "390"; return ;; + 11a0|11a1|11a2|11a3|11a7) echo "390"; return ;; + 11b4|11b6|11b7|11b8|11ba|11bc|11bd|11be|11bf) echo "390"; return ;; + 11c0|11c2|11c3|11c4|11c5|11c6|11c8) echo "390"; return ;; + + # ===== 470.xx legacy (Kepler: early GK1xx) ===== + # Some Kepler devices dropped from 535+ driver + 0fc0|0fc1|0fc2|0fc5|0fc6|0fc8|0fc9|0fcd|0fce|0fd1|0fd2) echo "470"; return ;; + 0fd3|0fd4|0fd5|0fd8|0fd9|0fdf) echo "470"; return ;; + 0fe0|0fe1|0fe2|0fe3|0fe4|0fe9|0fea|0fec|0fed|0fee|0fef|0ff2) echo "470"; return ;; + 0ff3|0ff6|0ff8|0ff9|0ffa|0ffb|0ffc|0ffd|0ffe|0fff) echo "470"; return ;; + 1001|1004|1005|1007|1008|100a|100c|101e|101f) echo "470"; return ;; + 1021|1022|1023|1024|1026|1027|1028|102a|102d|103a|103c) echo "470"; return ;; + 1200|1201|1203|1205|1206|1207|1208|1210|1211|1212|1213) echo "470"; return ;; + esac + + # If not in explicit table, fall back to prefix-based matching + # Extract first two hex digits (device class within NVIDIA) + prefix=$(echo "$devid" | cut -c1-2) + + case "$prefix" in + # ===== Current driver (580) ===== + # Blackwell (RTX 50xx) - 2bxx, 2cxx + 2b|2c) + echo "580" + ;; + # Ada Lovelace (RTX 40xx) - 26xx, 27xx, 28xx + 26|27|28) + echo "580" + ;; + # Hopper (H100, etc) - 23xx (data center) + 23) + echo "580" + ;; + # Ampere (RTX 30xx, A-series) - 20xx, 22xx, 24xx, 25xx + 20|22|24|25) + echo "580" + ;; + # Turing (RTX 20xx, GTX 16xx) - 1exx, 1fxx, 21xx + 1e|1f|21) + echo "580" + ;; + # Volta (Titan V, Quadro GV100) - 1dxx + 1d) + echo "580" + ;; + # Pascal (GTX 10xx) - 15xx, 17xx, 1bxx, 1cxx + 15|17|1b|1c) + echo "580" + ;; + # Maxwell (GTX 9xx, GTX 750 Ti) - 13xx, 14xx, 17xx (some) + 13|14) + echo "580" + ;; + # Kepler (GTX 6xx, 7xx) - remaining devices not in 470 list + # GK104, GK106, GK107, GK110, GK208 - 0fxx, 10xx, 11xx, 12xx + 0f|10|11|12) + # Most Kepler works with current driver + # Edge cases handled in explicit table above + echo "580" + ;; + + # ===== Legacy drivers ===== + # Fermi (GTX 4xx, 5xx) - need 390 legacy driver + # Remaining 0cxx, 0dxx, 0exx not caught by explicit table + 0c|0d|0e) + echo "390" + ;; + # Tesla (GeForce 8xxx, 9xxx, 2xx, 3xx) - need 340 legacy + # Remaining 04xx, 05xx, 06xx, 08xx, 0axx not caught above + 04|05|06|08|0a) + echo "340" + ;; + # Very old GPUs - 304 legacy + 00|01|02|03) + echo "304" + ;; + *) + # Unknown prefix - default to current driver + # Let it fail gracefully with a descriptive error + log WARN "Unknown NVIDIA device ID: $devid (prefix: $prefix)" + echo "580" + ;; + esac +} + +# Auto-detect best driver for installed NVIDIA GPU +auto_detect_nvidia_driver() { + device_ids=$(get_nvidia_device_ids) + + if [ -z "$device_ids" ]; then + echo "580" + return fi - return 1 + + # If multiple GPUs, find the lowest common driver version + min_driver="580" + + for devid in $device_ids; do + driver=$(nvidia_device_to_driver "$devid") + + # Lower version = older GPU = more restrictive + case "$driver" in + 304) + min_driver="304" + ;; + 340) + [ "$min_driver" != "304" ] && min_driver="340" + ;; + 390) + case "$min_driver" in + 304|340) ;; + *) min_driver="390" ;; + esac + ;; + 470) + case "$min_driver" in + 304|340|390) ;; + *) min_driver="470" ;; + esac + ;; + esac + done + + echo "$min_driver" +} + + + +count_gpu_devices() { + # Count actual VGA/display/3D controller class devices + # Include 3D controller for NVIDIA dGPUs that register that way + pciconf -lv 2>/dev/null | grep -Ei "^[a-z].*class.*=.*(vga|display|3d)" | wc -l | tr -d ' ' +} + +detect_hybrid_gpu() { + # True hybrid = multiple GPU devices from different vendors + gpu_count=$(count_gpu_devices) + [ "$gpu_count" -gt 1 ] || return 1 + + # Check which vendors are present (include 3D controller class) + has_intel=0 + has_amd=0 + has_nvidia=0 + + pciconf -lv 2>/dev/null | grep -B1 -A3 -Ei "class.*=.*(vga|display|3d)" | grep -qi Intel && has_intel=1 + pciconf -lv 2>/dev/null | grep -B1 -A3 -Ei "class.*=.*(vga|display|3d)" | grep -Eiq "AMD|ATI" && has_amd=1 + pciconf -lv 2>/dev/null | grep -B1 -A3 -Ei "class.*=.*(vga|display|3d)" | grep -qi NVIDIA && has_nvidia=1 + + # Hybrid = Intel+NVIDIA, Intel+AMD, or AMD integrated+discrete + vendor_count=$((has_intel + has_amd + has_nvidia)) + [ "$vendor_count" -gt 1 ] } ############################################################################### -# NVIDIA branch selection (heuristic, simplified) +# NVIDIA driver selection ############################################################################### select_nvidia_pkg() { - # This is a simplified heuristic. You may refine with pciconf parsing. - # Default to the newest branch and fall back if not available. server=$(detect_x_server) - base_pkg="nvidia-driver-580" + prefix="nvidia-driver" if [ "$server" = "xlibre" ]; then - base_pkg="xlibre-nvidia-driver-580" + prefix="xlibre-nvidia-driver" fi - # Try a sequence until one is installable - candidates="580 470 390 340 304" - for v in $candidates; do - pkgname="nvidia-driver-$v" - if [ "$server" = "xlibre" ]; then - pkgname="xlibre-$pkgname" + # Determine driver version to use + driver_version="$NVIDIA_DRIVER_VERSION" + + # If not explicitly set (still default), auto-detect based on GPU + if [ "$driver_version" = "580" ] && [ -z "${NVIDIA_DRIVER_VERSION_SET:-}" ]; then + detected=$(auto_detect_nvidia_driver) + if [ "$detected" != "580" ]; then + log INFO "Auto-detected legacy GPU, using driver series: $detected" + driver_version="$detected" fi - echo "$pkgname" - return 0 - done + fi - # Fallback to generic name - if [ "$server" = "xlibre" ]; then - echo "xlibre-nvidia-driver" - else - echo "nvidia-driver" + # If user specified a full version (contains '.'), use it directly + case "$driver_version" in + *.*) + echo "${prefix}-${driver_version}" + return + ;; + esac + + # Search for matching package by major version + # For legacy drivers (304, 340, 390, 470), include them in search + match=$(pkg search -q "^${prefix}-${driver_version}" 2>/dev/null | \ + grep -v -- "-devel" | \ + head -n 1) + + if [ -n "$match" ]; then + echo "$match" + return + fi + + # Fallback: if requested version not found, try to find ANY matching driver + # For legacy drivers, this is critical - don't exclude them + case "$driver_version" in + 304|340|390|470) + # Legacy driver not found - this is an error + log ERROR "Legacy driver ${driver_version} not found in packages" + echo "${prefix}-${driver_version}" + return + ;; + esac + + # For current drivers, try the latest non-legacy driver + match=$(pkg search -q "^${prefix}-[0-9]" 2>/dev/null | \ + grep -Ev -- "-(304|340|390|470|devel)" | \ + sort -t- -k3 -V | \ + tail -n 1) + + if [ -n "$match" ]; then + log WARN "Requested driver ${driver_version} not found, using $match" + echo "$match" + return fi + + # Last resort: return what was requested, let pkg fail with clear error + echo "${prefix}-${driver_version}" } ############################################################################### @@ -292,251 +637,377 @@ select_nvidia_pkg() { ############################################################################### setup_intel_config() { - log INFO "Setting up Intel GPU (external XF86Config.intel)" - apply_config_template "XF86Config.intel" - log INFO "Intel configuration applied" + log INFO "Configuring Intel GPU (template)" + apply_config_template "XF86Config.intel" || return 1 } setup_intel_auto() { - log INFO "Setting up Intel GPU (auto, no config file)" - # In auto mode we rely on Xorg autodetection. No xorg.conf required. + log INFO "Intel auto mode — no xorg.conf" backup_xorg_conf rm -f "$XORG_CONF" - log INFO "Removed $XORG_CONF so Intel can auto configure" } setup_amd_auto() { - log INFO "Auto selecting AMD driver (amdgpu or radeonkms)" - # Very simple heuristic: prefer amdgpu, fall back to radeonkms - if apply_config_template "XF86Config.amdgpu"; then - log INFO "Applied amdgpu template" - return 0 - fi - if apply_config_template "XF86Config.radeonkms"; then - log INFO "Applied radeonkms template" - return 0 - fi - log ERROR "No suitable AMD template found" + log INFO "Auto-selecting AMD driver" + apply_config_template "XF86Config.amdgpu" && return 0 + apply_config_template "XF86Config.radeonkms" && return 0 + log ERROR "No AMD templates available" return 1 } setup_amdgpu() { - log INFO "Forcing AMDGPU template" - apply_config_template "XF86Config.amdgpu" + apply_config_template "XF86Config.amdgpu" || return 1 } setup_radeonkms() { - log INFO "Forcing radeonkms template" - apply_config_template "XF86Config.radeonkms" + apply_config_template "XF86Config.radeonkms" || return 1 } setup_nvidia() { - log INFO "Setting up NVIDIA GPU" - pkgname=$(select_nvidia_pkg) - log INFO "Selected NVIDIA package: $pkgname" - pkg_install_wrapper "$pkgname" || log WARN "NVIDIA driver installation failed" + pkg=$(select_nvidia_pkg) + log INFO "Installing NVIDIA driver: $pkg" + pkg_install_wrapper "$pkg" || log WARN "NVIDIA installation failed" - # NVIDIA usually autoconfigures; leave xorg.conf minimal or absent. backup_xorg_conf rm -f "$XORG_CONF" - log INFO "Removed $XORG_CONF so NVIDIA Xorg can auto configure" + log INFO "NVIDIA autoconfiguration enabled" } +############################################################################### +# Enhanced VirtualBox Support +############################################################################### + setup_virtualbox() { - log INFO "Setting up VirtualBox guest" - apply_config_template "XF86Config.virtualbox" || log WARN "Failed to apply VirtualBox template" + log INFO "Setting up VirtualBox environment" + + apply_config_template "XF86Config.virtualbox" || \ + log WARN "VirtualBox template missing" + + # Enable required rc.conf settings + enable_rc_conf "vboxguest_enable" "YES" + enable_rc_conf "vboxservice_enable" "YES" + + # Start services + start_service_safe "vboxguest" + start_service_safe "vboxservice" } setup_vmware() { - log INFO "Setting up VMware guest" - apply_config_template "XF86Config.vmware" || log WARN "Failed to apply VMware template" + log INFO "VMware configuration" + apply_config_template "XF86Config.vmware" || return 1 } setup_qemu() { - log INFO "Setting up QEMU/KVM guest" - apply_config_template "XF86Config.qemu" || log WARN "Failed to apply QEMU template" + log INFO "QEMU/KVM configuration" + apply_config_template "XF86Config.qemu" || return 1 } setup_hyperv() { - log INFO "Setting up Hyper-V guest" - apply_config_template "XF86Config.hyperv" || log WARN "Failed to apply Hyper-V template" + log INFO "Hyper-V configuration" + apply_config_template "XF86Config.hyperv" || return 1 } setup_bhyve() { - log INFO "Setting up bhyve guest using scfb" - # You can either reuse scfb or create a dedicated XF86Config.bhyve - if apply_config_template "XF86Config.bhyve"; then - log INFO "Applied XF86Config.bhyve" - return 0 - fi - log INFO "XF86Config.bhyve not found. Falling back to XF86Config.scfb" - apply_config_template "XF86Config.scfb" + log INFO "bhyve guest detected" + apply_config_template "XF86Config.bhyve" && return 0 + apply_config_template "XF86Config.scfb" || return 1 } setup_scfb() { - log INFO "Setting up scfb (framebuffer) configuration" - apply_config_template "XF86Config.scfb" + apply_config_template "XF86Config.scfb" || return 1 } setup_vesa() { - log INFO "Setting up VESA configuration" - apply_config_template "XF86Config.vesa" + apply_config_template "XF86Config.vesa" || return 1 } setup_safe() { - log INFO "Setting up safe minimal configuration" - apply_config_template "XF86Config.safe" + apply_config_template "XF86Config.safe" || return 1 } setup_dual() { - log INFO "Setting up dual monitor configuration" - apply_config_template "XF86Config.dual" + apply_config_template "XF86Config.dual" || return 1 } ############################################################################### -# Dialog helpers (bsddialog preferred) +# Interactive menus ############################################################################### -have_bsddialog() { - command -v bsddialog >/dev/null 2>&1 -} +# NVIDIA driver version selection submenu +menu_nvidia_driver() { + detected=$(auto_detect_nvidia_driver) + device_ids=$(get_nvidia_device_ids) + + # Build info string about detected GPU + gpu_info="" + if [ -n "$device_ids" ]; then + gpu_info="Detected GPU(s): " + for devid in $device_ids; do + driver=$(nvidia_device_to_driver "$devid") + gpu_info="${gpu_info}0x${devid}(${driver}) " + done + gpu_info="${gpu_info}\nRecommended: ${detected}" + else + gpu_info="No NVIDIA GPU detected" + fi -have_dialog() { - command -v dialog >/dev/null 2>&1 + choice=$(run_menu_dialog "NVIDIA Driver Selection" \ + "Select NVIDIA driver version.\n${gpu_info}" \ + "auto" "Auto-detect (recommended: ${detected})" \ + "580" "580.x (Current - Blackwell/Ada/Ampere/Turing/Pascal/Maxwell)" \ + "470" "470.x (Legacy - Early Kepler)" \ + "390" "390.x (Legacy - Fermi GTX 4xx/5xx)" \ + "340" "340.x (Legacy - Tesla GeForce 8/9/2xx/3xx)" \ + "304" "304.x (Legacy - NV4x/G7x GeForce 6/7xxx)" \ + "cancel" "Cancel") + + case "$choice" in + auto) + setup_nvidia + run_msgbox "NVIDIA Setup" "NVIDIA driver installed (auto-detected: ${detected})" + ;; + 580|470|390|340|304) + export NVIDIA_DRIVER_VERSION="$choice" + export NVIDIA_DRIVER_VERSION_SET=1 + setup_nvidia + run_msgbox "NVIDIA Setup" "NVIDIA driver ${choice}.x installed" + ;; + cancel|"") + return 1 + ;; + esac } -interactive_menu() { - title=$1 - shift +# AMD driver selection submenu +menu_amd_driver() { + choice=$(run_menu_dialog "AMD Driver Selection" \ + "Select AMD driver configuration." \ + "auto" "Auto-detect (recommended)" \ + "amdgpu" "AMDGPU (modern AMD GPUs)" \ + "radeonkms" "RadeonKMS (legacy AMD GPUs)" \ + "cancel" "Cancel") - if have_bsddialog; then - bsddialog --title "$title" --menu "Select an option:" 0 0 0 "$@" 2>&1 1>/dev/tty - return $? - fi + case "$choice" in + auto) + setup_amd_auto + run_msgbox "AMD Setup" "AMD driver configured (auto-detected)" + ;; + amdgpu) + setup_amdgpu + run_msgbox "AMD Setup" "AMDGPU driver configured" + ;; + radeonkms) + setup_radeonkms + run_msgbox "AMD Setup" "RadeonKMS driver configured" + ;; + cancel|"") + return 1 + ;; + esac +} - if have_dialog; then - dialog --title "$title" --menu "Select an option:" 0 0 0 "$@" 2> /tmp/xconfig-menu.$$ 1>/dev/tty - rc=$? - choice=$(cat /tmp/xconfig-menu.$$ 2>/dev/null || true) - rm -f /tmp/xconfig-menu.$$ || true - if [ $rc -ne 0 ]; then - return $rc - fi - printf '%s\n' "$choice" - return 0 - fi +# Intel driver selection submenu +menu_intel_driver() { + choice=$(run_menu_dialog "Intel Driver Selection" \ + "Select Intel driver configuration." \ + "template" "Intel (with xorg.conf template)" \ + "auto" "Intel Auto (no xorg.conf, let X auto-configure)" \ + "cancel" "Cancel") - log ERROR "Neither bsddialog nor dialog is available for interactive mode" - return 1 + case "$choice" in + template) + setup_intel_config + run_msgbox "Intel Setup" "Intel GPU configured with template" + ;; + auto) + setup_intel_auto + run_msgbox "Intel Setup" "Intel GPU configured (auto mode)" + ;; + cancel|"") + return 1 + ;; + esac } -run_interactive() { - # Build menu entries - set -- \ - "auto" "Automatic detection and configuration" \ - "intel" "Intel GPU with external config" \ - "intel-auto" "Intel GPU (auto, no config file)" \ - "amd" "AMD auto (amdgpu or radeonkms)" \ - "amdgpu" "Force amdgpu" \ - "radeonkms" "Force radeonkms" \ - "nvidia" "NVIDIA (auto branch selection)" \ - "virtualbox" "VirtualBox guest" \ - "vmware" "VMware guest" \ - "qemu" "QEMU/KVM guest" \ - "hyperv" "Microsoft Hyper-V guest" \ - "bhyve" "bhyve guest (scfb)" \ - "vesa" "Generic VESA" \ - "scfb" "Framebuffer (scfb)" \ - "safe" "Safe minimal configuration" \ - "dual" "Dual monitor template" \ - "quit" "Exit without changes" - - choice=$(interactive_menu "xconfig" "$@") || return 1 - - case $choice in - auto) cmd_auto ;; - intel) setup_intel_config ;; - intel-auto) setup_intel_auto ;; - amd) setup_amd_auto ;; - amdgpu) setup_amdgpu ;; - radeonkms) setup_radeonkms ;; - nvidia) setup_nvidia ;; - virtualbox) setup_virtualbox ;; - vmware) setup_vmware ;; - qemu) setup_qemu ;; - hyperv) setup_hyperv ;; - bhyve) setup_bhyve ;; - vesa) setup_vesa ;; - scfb) setup_scfb ;; - safe) setup_safe ;; - dual) setup_dual ;; - quit) log INFO "User requested quit. No changes made." ;; - *) log ERROR "Unknown selection $choice" ;; +# Virtualization selection submenu +menu_virtualization() { + detected_vm=$(detect_vm_guest) + + choice=$(run_menu_dialog "Virtualization Setup" \ + "Select hypervisor configuration.\nDetected: ${detected_vm}" \ + "virtualbox" "VirtualBox Guest" \ + "vmware" "VMware Guest" \ + "qemu" "QEMU/KVM Guest" \ + "hyperv" "Hyper-V Guest" \ + "bhyve" "bhyve Guest" \ + "cancel" "Cancel") + + case "$choice" in + virtualbox) + setup_virtualbox + run_msgbox "VirtualBox Setup" "VirtualBox guest configured" + ;; + vmware) + setup_vmware + run_msgbox "VMware Setup" "VMware guest configured" + ;; + qemu) + setup_qemu + run_msgbox "QEMU Setup" "QEMU/KVM guest configured" + ;; + hyperv) + setup_hyperv + run_msgbox "Hyper-V Setup" "Hyper-V guest configured" + ;; + bhyve) + setup_bhyve + run_msgbox "bhyve Setup" "bhyve guest configured" + ;; + cancel|"") + return 1 + ;; esac } +# Main interactive setup menu +cmd_setup() { + tool=$(detect_dialog_tool) + if [ -z "$tool" ]; then + log ERROR "No dialog tool available. Install bsddialog or dialog." + log INFO "Alternatively, use direct commands: xconfig nvidia, xconfig intel, etc." + return 1 + fi + + log INFO "Starting interactive setup (using $tool)" + + while true; do + choice=$(run_menu_dialog "xconfig - X11 Configuration" \ + "Select configuration type:" \ + "auto" "Automatic Detection (recommended)" \ + "nvidia" "NVIDIA GPU (select driver version)" \ + "amd" "AMD GPU (amdgpu/radeonkms)" \ + "intel" "Intel GPU" \ + "vm" "Virtualization (VirtualBox/VMware/etc.)" \ + "dual" "Dual GPU / Multi-monitor" \ + "vesa" "VESA (generic fallback)" \ + "scfb" "Framebuffer (syscons)" \ + "safe" "Safe Mode (minimal config)" \ + "debug" "Show Debug Info" \ + "exit" "Exit") + + case "$choice" in + auto) + cmd_auto + run_msgbox "Auto Setup" "Automatic configuration complete" + ;; + nvidia) + menu_nvidia_driver + ;; + amd) + menu_amd_driver + ;; + intel) + menu_intel_driver + ;; + vm) + menu_virtualization + ;; + dual) + setup_dual + run_msgbox "Dual GPU Setup" "Dual GPU configuration applied" + ;; + vesa) + setup_vesa + run_msgbox "VESA Setup" "VESA fallback configuration applied" + ;; + scfb) + setup_scfb + run_msgbox "SCFB Setup" "Framebuffer configuration applied" + ;; + safe) + setup_safe + run_msgbox "Safe Mode" "Minimal safe configuration applied" + ;; + debug) + # Clear screen and show debug output + clear + cmd_debug + echo "" + echo "Press Enter to continue..." + read dummy + ;; + exit|"") + log INFO "Exiting interactive setup" + break + ;; + esac + done +} + ############################################################################### -# Auto mode logic +# Auto mode ############################################################################### cmd_auto() { log INFO "Running automatic detection" - xserver=$(detect_x_server) - log INFO "Detected X server: $xserver" - - # Hypervisors first - if detect_virtualbox; then - log INFO "Detected VirtualBox guest" + if detect_virtualbox ; then + log INFO "Detected VirtualBox" setup_virtualbox return 0 fi - if detect_vmware; then - log INFO "Detected VMware guest" + if detect_vmware ; then + log INFO "Detected VMware" setup_vmware - return 0 + return $? fi - if detect_qemu; then - log INFO "Detected QEMU/KVM guest" + if detect_qemu ; then + log INFO "Detected QEMU/KVM" setup_qemu - return 0 + return $? fi - if detect_hyperv; then - log INFO "Detected Hyper-V guest" + if detect_hyperv ; then + log INFO "Detected Hyper-V" setup_hyperv - return 0 + return $? fi - if detect_bhyve; then - log INFO "Detected bhyve guest" + if detect_bhyve ; then + log INFO "Detected bhyve" setup_bhyve - return 0 + return $? fi - # Physical GPUs - if detect_intel_gpu; then - log INFO "Detected Intel GPU" - setup_intel_config + # For hybrid graphics, prefer discrete GPU over integrated + # User can manually select 'dual' if multi-monitor across GPUs is needed + if detect_hybrid_gpu ; then + log INFO "Detected hybrid graphics (multiple GPUs from different vendors)" + log INFO "Selecting discrete GPU; use 'dual' command for multi-GPU output" + fi + + # Priority: NVIDIA > AMD > Intel (discrete over integrated) + if detect_nvidia_gpu ; then + log INFO "Detected NVIDIA GPU" + setup_nvidia return 0 fi - if detect_amd_gpu; then + if detect_amd_gpu ; then log INFO "Detected AMD GPU" setup_amd_auto - return 0 + return $? fi - if detect_nvidia_gpu; then - log INFO "Detected NVIDIA GPU" - setup_nvidia - return 0 + if detect_intel_gpu ; then + log INFO "Detected Intel GPU" + setup_intel_config + return $? fi - # Fallback - log WARN "Could not identify a supported GPU or hypervisor. Falling back to scfb" + log WARN "No supported GPU found — using scfb" setup_scfb } @@ -546,50 +1017,48 @@ cmd_auto() { cmd_debug() { echo "===== xconfig debug =====" - echo "Script: $SCRIPT_NAME" - echo "Script dir: $SCRIPT_DIR" - echo "Config dirs: $LOCAL_CONFIG_DIR, $SYSTEM_CONFIG_DIR" - echo "Xorg conf: $XORG_CONF" - echo "Backup dir: $BACKUP_DIR" + echo "kern.vm_guest: $(detect_vm_guest)" + echo "Detected X server: $(detect_x_server)" + echo "NVIDIA driver version setting: $NVIDIA_DRIVER_VERSION" + echo "NVIDIA auto-detected driver: $(auto_detect_nvidia_driver)" + echo "NVIDIA device IDs: $(get_nvidia_device_ids)" + echo "NVIDIA package selected: $(select_nvidia_pkg)" echo - echo "FreeBSD version:" - freebsd-version -kru 2>/dev/null || uname -a - echo - - echo "kern.vm_guest:" - detect_vm_guest - echo + # Show per-device driver mapping + device_ids=$(get_nvidia_device_ids) + if [ -n "$device_ids" ]; then + echo "NVIDIA per-device driver mapping:" + for devid in $device_ids; do + driver=$(nvidia_device_to_driver "$devid") + echo " Device 0x$devid -> driver series $driver" + done + echo + fi - echo "Detected GPUs (pciconf):" - pciconf -lv 2>/dev/null | grep -A4 -Ei "vga|display" || echo "No VGA/display controllers found" + echo "GPU devices found: $(count_gpu_devices)" + echo "GPU detection output (VGA/display/3D controller classes):" + pciconf -lv | grep -B1 -A3 -Ei "class.*=.*(vga|display|3d)" || echo "No GPU found" echo - echo "X server detection:" - detect_x_server + echo "GPU vendor detection:" + echo " Intel: $(detect_intel_gpu && echo "yes" || echo "no")" + echo " AMD: $(detect_amd_gpu && echo "yes" || echo "no")" + echo " NVIDIA: $(detect_nvidia_gpu && echo "yes" || echo "no")" + echo " Hybrid: $(detect_hybrid_gpu && echo "yes" || echo "no")" echo echo "Available templates:" - CONFIG_DIR=$(find_config_dir || true) - if [ -n "$CONFIG_DIR" ]; then - ls -1 "$CONFIG_DIR" - else - echo "No cardDetect directory found" - fi + dir=$(find_config_dir) + if [ -n "$dir" ]; then ls -1 "$dir"; else echo "None"; fi echo - if [ -d /xdrivers ]; then - echo "/xdrivers exists" - if [ -f /xdrivers/drivers-list ]; then - echo "drivers-list:" - cat /xdrivers/drivers-list - else - echo "drivers-list not present" - fi + echo "Backup directory ($BACKUP_DIR):" + if [ -d "$BACKUP_DIR" ]; then + ls -lt "$BACKUP_DIR" | head -n "$((BACKUP_KEEP + 1))" else - echo "/xdrivers does not exist" + echo " (not created yet)" fi - echo "===== end of debug =====" } @@ -598,35 +1067,48 @@ cmd_debug() { ############################################################################### usage() { - cat < Commands: - auto Automatic detection and configuration - setup Interactive setup (same as manual) - manual Interactive setup using bsddialog or dialog - intel Intel GPU with external config (XF86Config.intel) - intel-auto Intel GPU auto. No xorg.conf file - amd AMD auto (amdgpu or radeonkms) - amdgpu Force amdgpu template - radeonkms Force radeonkms template - nvidia NVIDIA configuration with driver install - virtualbox VirtualBox guest configuration - vmware VMware guest configuration - qemu QEMU/KVM guest configuration - hyperv Hyper-V guest configuration - bhyve bhyve guest. Uses XF86Config.bhyve if present, otherwise scfb - vesa Generic VESA configuration - scfb Generic framebuffer configuration - safe Safe minimal configuration - dual Dual monitor template - debug Print diagnostic information - help Show this help message - -Examples: - sudo $SCRIPT_NAME auto - sudo $SCRIPT_NAME intel - sudo $SCRIPT_NAME bhyve + auto Detect and configure automatically + setup Interactive menu (bsddialog/dialog) + manual Alias for 'setup' + intel Intel GPU (template) + intel-auto Intel GPU (no xorg.conf) + amd Auto-select AMD (amdgpu/radeonkms) + amdgpu Force AMDGPU + radeonkms Force radeonkms + nvidia NVIDIA (auto-detects driver version) + virtualbox VirtualBox guest + vmware VMware guest + qemu QEMU/KVM guest + hyperv Hyper-V guest + bhyve bhyve (scfb fallback) + vesa VESA + scfb Framebuffer + safe Minimal + dual Multi-GPU output (for displays on separate GPUs) + debug Diagnostic dump (shows per-device driver mapping) + help Show this help + +NVIDIA Driver Support: + Auto-detection maps GPU device IDs to appropriate driver series: + 580 (current) - Blackwell, Ada, Ampere, Turing, Pascal, Maxwell, most Kepler + 470 (legacy) - Some early Kepler (GK1xx) + 390 (legacy) - Fermi (GTX 4xx/5xx) + 340 (legacy) - Tesla (GeForce 8xxx/9xxx/2xx/3xx) + 304 (legacy) - NV4x/G7x (GeForce 6xxx/7xxx) + + For unsupported legacy GPUs, use scfb or vesa as fallback. + Detection includes 3D controller class for laptop/server dGPUs. + +Environment: + NVIDIA_DRIVER_VERSION NVIDIA driver major (580, 470, 390, 340, 304) + or full version (580.105.08). Auto-detected + from GPU hardware if not set. + Set NVIDIA_DRIVER_VERSION_SET=1 to force + your chosen version over auto-detection. EOF } @@ -638,64 +1120,26 @@ EOF main() { cmd=${1:-auto} - case $cmd in - auto) - cmd_auto - ;; - setup|manual) - run_interactive - ;; - intel) - setup_intel_config - ;; - intel-auto) - setup_intel_auto - ;; - amd) - setup_amd_auto - ;; - amdgpu) - setup_amdgpu - ;; - radeonkms) - setup_radeonkms - ;; - nvidia) - setup_nvidia - ;; - virtualbox) - setup_virtualbox - ;; - vmware) - setup_vmware - ;; - qemu) - setup_qemu - ;; - hyperv) - setup_hyperv - ;; - bhyve) - setup_bhyve - ;; - vesa) - setup_vesa - ;; - scfb) - setup_scfb - ;; - safe) - setup_safe - ;; - dual) - setup_dual - ;; - debug) - cmd_debug - ;; - help|-h|--help) - usage - ;; + case "$cmd" in + auto) cmd_auto ;; + setup|manual) cmd_setup ;; + intel) setup_intel_config ;; + intel-auto) setup_intel_auto ;; + amd) setup_amd_auto ;; + amdgpu) setup_amdgpu ;; + radeonkms) setup_radeonkms ;; + nvidia) setup_nvidia ;; + virtualbox) setup_virtualbox ;; + vmware) setup_vmware ;; + qemu) setup_qemu ;; + hyperv) setup_hyperv ;; + bhyve) setup_bhyve ;; + vesa) setup_vesa ;; + scfb) setup_scfb ;; + safe) setup_safe ;; + dual) setup_dual ;; + debug) cmd_debug ;; + help|-h|--help) usage ;; *) log ERROR "Unknown command: $cmd" usage