#!/bin/sh # Clawdie Shell — GPU Detection Module # Purpose: Detect GPU and configure appropriate kernel modules # POSIX-compliant (no bash-isms) set -eu # Configuration (can be overridden for testing) RC_CONF="${RC_CONF:-/etc/rc.conf}" LOG_FILE="${LOG_FILE:-/var/log/clawdie-firstboot.log}" PROGRESS_FILE="${PROGRESS_FILE:-/var/log/clawdie-firstboot.progress}" # ============================================================================ # MAIN ENTRY POINT # ============================================================================ clawdie_shell_gpu_detect() { # Main orchestrator: detect GPU and write rc.conf # Sets DETECTED_GPU for use by other modules log_msg "[gpu] Starting GPU detection" # Query pciconf for GPU vendor gpu_vendor=$(clawdie_shell_gpu_detect_pci) if [ -z "$gpu_vendor" ]; then log_msg "[gpu] No GPU detected — using VESA fallback" DETECTED_GPU="vesa" echo "[GPU] VESA" >> "$PROGRESS_FILE" return 0 fi log_msg "[gpu] Detected GPU vendor: $gpu_vendor" # Convert vendor to driver module list kld_list=$(clawdie_shell_gpu_match_driver "$gpu_vendor") DETECTED_GPU="$gpu_vendor" if [ -z "$kld_list" ]; then log_msg "[gpu] Vendor '$gpu_vendor' has no driver — using VESA fallback" DETECTED_GPU="vesa" echo "[GPU] VESA (unknown vendor)" >> "$PROGRESS_FILE" return 0 fi log_msg "[gpu] Matched driver: $kld_list" # Write to rc.conf clawdie_shell_gpu_write_rcconf "$kld_list" log_msg "[gpu] Updated rc.conf with kld_list" echo "[GPU] $DETECTED_GPU ($kld_list)" >> "$PROGRESS_FILE" log_msg "[gpu] GPU detection complete" } # ============================================================================ # GPU DETECTION VIA PCICONF # ============================================================================ clawdie_shell_gpu_detect_pci() { # Query pciconf for GPU vendor # Returns: intel, amd, nvidia, vmware, or empty string local pciconf_out # Get pciconf output (filter to VGA device) pciconf_out=$(pciconf -lv 2>/dev/null | grep -i "class=0x030000" | head -1 || true) if [ -z "$pciconf_out" ]; then return fi # Extract vendor string if echo "$pciconf_out" | grep -iq "Intel"; then echo "intel" elif echo "$pciconf_out" | grep -iq "AMD\|ATI"; then echo "amd" elif echo "$pciconf_out" | grep -iq "NVIDIA"; then echo "nvidia" elif echo "$pciconf_out" | grep -iq "VMware"; then echo "vmware" fi } # ============================================================================ # DRIVER LOOKUP TABLE # ============================================================================ clawdie_shell_gpu_match_driver() { # Convert vendor to kernel module list # Input: intel, amd, nvidia, vmware, or vendor string # Output: space-separated kld module names (e.g., "i915kms" or "nvidia-modeset nvidia") local vendor="$1" case "$vendor" in intel) echo "i915kms" ;; amd) echo "amdgpu" ;; nvidia) # NVIDIA driver is set separately by clawdie_shell_nvidia_detect() # This module just returns the base driver name echo "nvidia-modeset nvidia" ;; vmware) echo "vmwgfx" ;; *) # Unknown vendor — no driver return ;; esac } # ============================================================================ # RC.CONF WRITING # ============================================================================ clawdie_shell_gpu_write_rcconf() { # Write kld_list to rc.conf # Input: space-separated module list (e.g., "i915kms" or "nvidia-modeset nvidia") local kld_list="$1" if [ ! -f "$RC_CONF" ]; then log_msg "[gpu] Creating $RC_CONF" touch "$RC_CONF" fi # If kld_list is empty (VESA), skip writing anything if [ -z "$kld_list" ]; then log_msg "[gpu] No driver — skipping kld_list (VESA fallback)" return 0 fi # Remove existing kld_list if present if grep -q "^kld_list=" "$RC_CONF" 2>/dev/null; then sed -i.bak '/^kld_list=/d' "$RC_CONF" rm -f "$RC_CONF.bak" fi # Append new kld_list echo "kld_list=\"$kld_list\"" >> "$RC_CONF" log_msg "[gpu] Wrote kld_list=$kld_list to $RC_CONF" } # ============================================================================ # VALIDATION # ============================================================================ clawdie_shell_gpu_validate() { # Verify rc.conf has valid kld_list (if GPU detected) if [ ! -f "$RC_CONF" ]; then log_msg "[gpu] ERROR: $RC_CONF not found" return 1 fi if grep -q "^kld_list=" "$RC_CONF" 2>/dev/null; then local kld=$(grep "^kld_list=" "$RC_CONF" | cut -d= -f2 | tr -d '"' | head -1) if [ -z "$kld" ]; then log_msg "[gpu] ERROR: kld_list is empty" return 1 fi fi return 0 } # ============================================================================ # LOGGING HELPER # ============================================================================ log_msg() { echo "$(date '+%H:%M:%S') $1" | tee -a "$LOG_FILE" 2>/dev/null || true } # Only run if sourced directly (not during test) if [ "${SHELL_GPU_TEST:-0}" -eq 0 ]; then clawdie_shell_gpu_detect fi