#!/bin/sh
# nvidia-drivers - scraps hook script.
#
# The proprietary driver needs a handful of decisions made about it: kernel
# modesetting for Wayland, preserving video memory across suspend, blacklisting
# nouveau so the two do not fight over the card, and an initramfs rebuild.
#
# ScrapLinux asks rather than assuming, because plenty of people have a working
# hand-rolled setup they do not want touched.
# Every path below is written under $SCRAPS_ROOT, not to a bare /etc.
# scraps sets SCRAPS_ROOT for the root it is operating on, and it is "/" for an
# ordinary install - so this is a no-op in the normal case and the difference
# only shows up under `scraps --root=/mnt`, where the unprefixed version wrote
# the driver's modprobe config, its modules-load list and a regenerated
# initramfs onto the *build host* while claiming to have configured the target.
# The target got the modules and none of the configuration; the host got
# configuration for a driver it does not have.
# shellcheck shell=sh
R=${SCRAPS_ROOT:-/}; R=${R%/}

post_install() {
	printf '\n'
	printf '  The NVIDIA driver is installed but not configured yet.\n\n'
	printf '  Automatic configuration would:\n'
	printf '    - enable kernel modesetting (nvidia_drm modeset=1), which Wayland needs\n'
	printf '    - preserve video memory across suspend\n'
	printf '    - blacklist nouveau so it does not claim the card first\n'
	printf '    - load nvidia, nvidia_modeset and nvidia_drm at boot\n'
	printf '    - rebuild the initramfs\n\n'

	printf 'Let scraps auto configure this driver or leave it be? N/y '
	read -r answer </dev/tty 2>/dev/null || answer=n

	case "$answer" in
	y|Y|yes|YES|Yes) ;;
	*)
		printf '\n  Left alone. Nothing was written.\n'
		printf '  To configure it later:  scraps-nvidia-configure\n\n'
		return 0 ;;
	esac

	nvidia_configure
	printf '\n  Configured. Reboot for the module to take over the console.\n\n'
}

post_upgrade() {
	# On an upgrade, only rebuild what already exists - never re-ask.
	if [ -f "$R/etc/modprobe.d/nvidia.conf" ]; then
		printf '  nvidia: rebuilding the kernel module for the running kernels\n'
		for kdir in /usr/lib/modules/*/build; do
			[ -d "$kdir" ] || continue
			gmake -C "$kdir" M=/usr/src/nvidia modules >/dev/null 2>&1 || :
		done
		have_initramfs && scraplinux-mkinitramfs >/dev/null 2>&1 || :
	fi
}

pre_remove() {
	rm -f "$R/etc/modprobe.d/nvidia.conf" "$R/etc/modules-load.d/nvidia.conf"
	rm -f "$R/etc/modprobe.d/nouveau-blacklist.conf"
}

# Only meaningful for the running system. Under `scraps --root=/mnt` the
# host's scraplinux-mkinitramfs would regenerate the *host's* initramfs from
# the host's own modules, which is both wrong and destructive - the target's
# initramfs is rebuilt when it next boots and installs its own kernel, or by
# running scraplinux-mkinitramfs inside a chroot of it.
have_initramfs() {
	[ "$R" = "" ] || return 1
	command -v scraplinux-mkinitramfs >/dev/null 2>&1
}

nvidia_configure() {
	mkdir -p "$R/etc/modprobe.d" "$R/etc/modules-load.d"

	cat >"$R/etc/modprobe.d/nvidia.conf" <<-'CONF'
		# Written by scraps when the NVIDIA driver was installed.
		# Remove this file to hand configuration back to yourself.

		# Keeps the framebuffer intact across suspend/resume.
		options nvidia NVreg_PreserveVideoMemoryAllocations=1

		# Kernel modesetting. Wayland compositors need this; without it you get
		# a black screen on anything that is not Xorg.
		options nvidia_drm modeset=1 fbdev=1
	CONF

	cat >"$R/etc/modprobe.d/nouveau-blacklist.conf" <<-'CONF'
		# nouveau and the proprietary driver cannot both drive the card.
		blacklist nouveau
		options nouveau modeset=0
	CONF

	cat >"$R/etc/modules-load.d/nvidia.conf" <<-'CONF'
		nvidia
		nvidia_modeset
		nvidia_drm
	CONF

	have_initramfs && scraplinux-mkinitramfs >/dev/null 2>&1 || :
}
