#!/bin/sh -e

##########################################################################
#   Title:
#       Optional, defaults to the name of the script sans extention
#
#   Section:
#       8
#
#   Synopsis:
#       
#   Description:
#       FreeBSD requires a kernel module to support modern Intel
#       GPUs.  This script automatically detects the presence of an
#       Intel GPU and performs the necessary system configuration to
#       enable it in Xorg.
#       
#   Arguments:
#       
#   Returns:
#
#   Examples:
#
#   Files:
#
#   Environment:
#
#   See also:
#       
#   History:
#   Date        Name        Modification
#   2017-02-14  J Bacon     Begin
#   2024-11-12  Jason Bacon Add man page template and usage
##########################################################################

##########################################################################
#   Function description:
#       Pause until user presses return
##########################################################################

pause()
{
    local junk
    
    printf "Press return to continue..."
    read junk
}


##########################################################################
#   Function description:
#       Remove old DRM modules from config
#       
#   History:
#   Date        Name        Modification
#   2020-06-11  Jason Bacon Begin
##########################################################################

scrub_drm()
{
    # Remove old modules
    sysrc -q "kld_list-=/boot/kernel/i915kms.ko" > /dev/null
    sysrc -q "kld_list-=/boot/kernel/radeonkms.ko" > /dev/null
    sysrc -q "kld_list-=/boot/modules/i915kms.ko" > /dev/null
    sysrc -q "kld_list-=/boot/modules/radeonkms.ko" > /dev/null
    sysrc -q "kld_list-=radeonkms" > /dev/null
    sysrc -q "kld_list-=i915kms" > /dev/null
    sysrc -q "kld_list-=amdgpu" > /dev/null
    sysrc -q "kld_list-=nvidia" > /dev/null
    sysrc -q "kld_list-=nvidia-modeset" > /dev/null
}


##########################################################################
#   Function description:
#       Remove DRM and video driver packages
#       
#   History:
#   Date        Name        Modification
#   2020-06-11  Jason Bacon Begin
##########################################################################

scrub_packages()
{
    pkg remove -y 'drm*kmod' \
	xf86-video-amdgpu 'xf86-video-ati*' \
	xf86-video-intel \
	xf86-video-nv 'nvidia-driver*' || true
}


##########################################################################
#   Function description:
#       Mark all DRM kmod packages for building from source in
#       auto-update-system
#       
#   History:
#   Date        Name        Modification
#   2021-01-30  J Bacon     Begin
##########################################################################

drm_from_source()
{
    cd /usr/ports
    for port in graphics/drm-*; do
	auto-mark-install-from-source $port KBI
    done
}


##########################################################################
#   Main
##########################################################################

# This strategy doesn't really help.  Build failures in drm-kmod are about
# as common as KBI compatibility issues
# if [ -e /usr/src/Makefile ]; then
#     drm_from_source
#     src_flags="-s"
# else
#     cat << EOM
# 
# No /usr/src tree found.  Installing DRM from binary packages.  This could
# result in KBI compatibility issues.  Please consider installing the source
# tree and rerunning $0.
# 
# EOM
# fi

usage()
{
    printf "Usage: $0\n"
    exit 1
}


##########################################################################
#   Main
##########################################################################

if [ $# != 0 ]; then
    usage
fi

case $(auto-ostype) in
FreeBSD)
    more << EOM

We will now attempt to detect your GPU and provide some guidance.  This
will automatically install the stable version of the drm-kmod (Direct
Rendering Kernel Module).

===

Given the wide variety of graphics chipsets available, it is virtually
impossible to configure the graphics environment automatically.

If your screen goes blank during the next boot, you probably have a chipset
not supported by the drm module.  In that case, tap the power button and wait
a minute for a graceful shutdown.  You can also try to ssh in from another
host.  Hold the power button to force power off only if absolutely necessary,
as this may cause file system damage on any system.

Then boot into single-user mode and do the following:

mount -u -o rw /
vi /etc/rc.conf

Remove the "kms" module (e.g. i915kms, radeonkms) from the "kld_list" setting.
Save and reboot.

Then run auto-gpu-setup again and try different options.

===

There may also occasionally be bad interactions between the DRI/DRM, Xorg,
and specific software such as GTK, QT, Gnome, etc.  Using a different driver
such as vesa or scfb is often a good temporary workaround.

EOM
    pause
    if [ -z "$(pciconf -lv)" ]; then
	printf "No PCI hardware detected.\n"
	exit 0
    fi
    
    if sysctl -n kern.vm_guest | fgrep -iq parallels; then
	printf "Parallels VM detected.  Forcing SCBF...\n"
	mkdir -p /etc/X11/xorg.conf.d
	cat << EOM > /etc/X11/xorg.conf.d/10-parallels-scfb.conf
Section "Device"
	### Force SCFB driver for Parallels 15+
	Identifier  "Card0"
	Driver      "scfb"
	# Default BusID detected by Xorg -configure
	# BusID       "PCI:1:0:0"
EndSection
EOM
	pause
	exit 0
    fi
    
    if sysctl -n kern.vm_guest | fgrep -iq vmware; then
	printf "VMWare VM detected.  Installing XF86-video-vmware...\n"
	mkdir -p /etc/X11/xorg.conf.d
	pkg install -y xf86-video-vmware
	pause
	exit 0
    fi
    
    if sysctl dev.acpi.0.%desc 2> /dev/null | fgrep -iq VBOX; then
	printf "VirtualBox VM detected.  No driver setup needed.\n"
	pause
	exit 0
    fi
    
    if pciconf -lv | grep -B 2 display | grep vendor | grep -iq intel; then
	printf "Intel GPU detected.\n"
	pciconf -lv | grep -B 2 display
	pause
	cat << EOM

1.. For most modern Intel GPUs, use the modesetting driver which is part of
    the FreeBSD base.

    auto-install-packages -n $src_flags graphics/drm-kmod
    Add kld_list="/boot/modules/i915kms.ko" to /etc/rc.conf

2.. For older Intel GPUs, or if you encounter other issues with the built-in
    DRM or Intel modesetting driver, try the Intel xorg driver with no DRM:

    pkg install -y xf86-video-intel

3.. No drivers or DRM, I'll use SCFB or VESA or manually configure a driver
    later.

4.. Leave my current configuration alone.

EOM
	selection=0
	while [ $selection -lt 1 ] || [ $selection -gt 4 ]; do
	    printf "Selection? [1] "
	    read selection
	    if [ 0$selection = 0 ]; then
		selection=1
	    fi
	    case $selection in
	    1)
		scrub_packages
		scrub_drm
		auto-install-packages -n $src_flags graphics/drm-kmod
		sysrc "kld_list+=/boot/modules/i915kms.ko"
		;;
	    2)
		scrub_packages
		scrub_drm
		pkg install -y xf86-video-intel
		;;
	    3)
		scrub_packages
		scrub_drm
		;;
	    4)
		;;
	    *)
		printf "Invalid selection: $selection\n"
		;;
	    esac
	done
    fi
    
    if pciconf -lv | grep -B 2 display | grep vendor | grep -iq amd; then
	printf "AMD GPU detected.\n"
	pciconf -lv | grep -B 2 display
	pause
	cat << EOM

1.. For recent AMD GPUs, you can try

    auto-install-packages -n $src_flags graphics/drm-kmod
    pkg install -y xf86-video-amdgpu
    Add "kld_list=amdgpu" to /etc/rc.conf

2.. For older AMD GPUs, you can try

    auto-install-packages -n $src_flags graphics/drm-kmod
    pkg install -y xf86-video-ati
    Add "kld_list=/boot/modules/radeonkms.ko" to /etc/rc.conf

3.. For even older AMD GPUs or systems lacking DRM support, try the ATI
    driver with no DRM:

    pkg install -y xf86-video-ati

4.. No drivers or DRM, I'll use SCFB or VESA or manually configure a driver
    later.

5.. Leave my current configuration alone.

EOM
	selection=0
	while [ $selection -lt 1 ] || [ $selection -gt 5 ]; do
	    printf "Selection? [1] "
	    read selection
	    if [ 0$selection = 0 ]; then
		selection=1
	    fi
	    case $selection in
	    1)
		scrub_packages
		scrub_drm
		auto-install-packages -n $src_flags graphics/drm-kmod
		pkg install -y xf86-video-amdgpu
		sysrc "kld_list+=amdgpu"
		;;
	    2)
		scrub_packages
		scrub_drm
		auto-install-packages -n $src_flags graphics/drm-kmod
		pkg install -y xf86-video-ati
		sysrc "kld_list+=/boot/modules/radeonkms.ko"
		;;
	    3)
		scrub_packages
		scrub_drm
		pkg install -y xf86-video-ati
		;;
	    4)
		scrub_packages
		scrub_drm
		;;
	    5)
		;;
	    *)
		printf "Invalid selection: $selection\n"
		;;
	    esac
	done
    fi
    
    ##########################################################################
    #       FreeBSD requires a kernel module and driver to support nVidia
    #       GPUs.  This script automatically detects the presence of an
    #       nVidia GPU and performs the necessary system configuration to
    #       enable it in Xorg.
    ##########################################################################
    
    # https://forums.freebsd.org/threads/howto-setup-xorg-with-nvidias-driver.52311/
    
    if pciconf -lv | grep -B 2 display | grep vendor | grep -iq nvidia; then
	cat << EOM

nVidia GPU detected.

1.. For recent nVidia GPUs, you can try a closed-source nVidia driver

2.. For very old nvidia GPUs, you can try the open-source nv driver

3.. No drivers or DRM, I'll use SCFB or VESA or manually configure a driver
    later.

4.. Leave my current configuration alone.

EOM
	selection=0
	while [ $selection -lt 1 ] || [ $selection -gt 4 ]; do
	    printf "Selection? [1] "
	    read selection
	    if [ 0$selection = 0 ]; then
		selection=1
	    fi
	    case $selection in
	    1)
		scrub_packages
		scrub_drm
		
		pciconf -lv | grep -B 2 display
		ls -d /usr/ports/x11/nvidia-driver*
		pause
		cat << EOM

Check the nVidia docs to determine which driver version[s] support[s] the
device shown above.  Then choose a compatible driver version from the
list of ports below.  The device may be supported by more than one
driver version.  We recommend using the latest driver possible.

Just press enter to use the latest driver or enter just the version number
(the number after the final '-') from the list above.

EOM
		printf "Driver version? "
		read driver
    
		cat << EOM

The nVidia driver binary packages include Linux support.  We will now
install the Linux compatibility system of your choice.  Enter '6'
for RHEL 6 compatibility or '7' for RHEL 7.  Some packages such
as Linux Flash plugin may require RHEL 6.

EOM
		auto-install-linux_base
		if [ 0$driver = 0 ]; then
		    pkg install -y nvidia-driver
		    kld=nvidia-modeset
		else
		    pkg install -y nvidia-driver-$driver
		    if [ $driver -le 340 ]; then
			kld=nvidia
		    else
			kld=nvidia-modeset
		    fi
		fi
		
		sysrc "kld_list+=$kld"
		kldload $kld || true
		
		dir=/usr/local/etc/X11/xorg.conf.d
		fragment=$dir/nvidia.conf
		if [ ! -e $fragment ]; then
		    mkdir -p $dir
		    cat << EOM > $fragment
Section "Device"
Identifier "NVIDIA Card"
VendorName "NVIDIA Corporation"
Driver "nvidia"
EndSection
EOM
		fi
		;;
	    2)
		scrub_packages
		scrub_drm
		pkg install -y xf86-video-nv
		;;
	    3)
		scrub_packages
		scrub_drm
		;;
	    4)
		;;
	    *)
		printf "Invalid selection: $selection\n"
		;;
	    esac
	done
    fi
    ;;
    
*)
    auto-unsupported-os $0
    exit 1
    ;;

esac

cat << EOM

If you have changed kld_list in /etc/rc.conf, you should reboot now to test
the new module.

EOM
printf "Reboot now? (y/n) [y] "
read reboot
if [ "0$reboot" != 0n ]; then
    shutdown -r now
fi
