#!/bin/sh
#-
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2024 The FreeBSD Foundation
#
# This software was developed by Björn Zeeb
# under sponsorship from the FreeBSD Foundation.
#
# This is neither efficient nor elegant but we need it few times
# a year and it does the job.
#
#
# USAGE: please check out the correct tag/hash for ports in the
# linux-firmware.git repository you point this script to.
#

set -e

DRIVER=ath12k
CHECKFILE=dp_mon.c

################################################################################
#
# Check pre-reqs
#
if [ $# -ne 1 ]; then
	printf "USAGE: %s /path/to/linux-firmware.git\n" $0 >&2
	exit 1
fi

if [ ! -e ${CHECKFILE} ]; then
	printf "ERROR: run from %s driver directory; no %s.c here\n" ${DRIVER} ${CHECKFILE} >&2
	exit 1
fi

LFWDIR=${1}
if test ! -d ${LFWDIR} -o ! -e ${LFWDIR}/WHENCE; then
	printf "ERROR: cannot find linux-firmware.git at '%s'\n" ${LFWDIR} >&2
	exit 1
fi
LFWDIR=${LFWDIR}/${DRIVER}

################################################################################
#
# Helper functions.
#
# This uses a hack (cpp) to expand some macros for us and parses out the result
# which is the PCI device ID or the firmware directory for that.
#
list_fw()
{
	# List of already seen flavor (firmware directory).
	sfwl=""

	# List of "supported" device IDs.
	devidl=$(cpp pci.c 2> /dev/null | awk '/PCI_VDEVICE\(QCOM,/ { gsub("^.*, ", ""); gsub("\\) },$", ""); print tolower($0); }')
	# Turn them into a regex.
	didreg=$(echo "${devidl}" | xargs -J % echo -n % | sed -e 's, ,|,g')
	# List the device ID cases along with their hw_rev which we can go and take to lookup fw.
	hwrevs=$(cpp pci.c 2> /dev/null | egrep -E "(case (${didreg})|ab->hw_rev = )" | awk '{
		if (FNR > 1 && /case/) {
			printf "\n";
		}
		gsub("^.*case[[:space:]]*", "");
		gsub("[[:space:]]*ab->hw_rev = ", " ");
		gsub("[:;]", "");
		printf "%s", $0;
	}')

	# hwrevs is a list of (device IDs) -> (1..n hardware revisions) mappings.
	#echo "==> ${devidl} :: ${didreg} :: ${hwrevs}" >&2

	# List of (hardware revision) -> (firware directory) mappings.
	l=$(cpp hw.c 2> /dev/null | egrep -E '\.(hw_rev|dir) = ' | awk '{ if (/hw_rev/) { printf "%s", $0; } else { print; } }' | sort | uniq | \
	awk '{
		gsub("^.*hw_rev = ", "");
		gsub(",.* = ", "\t");
		gsub(",$", "");
		gsub(/"/, "");
		gsub(" ", "");
		gsub("\t", " ");
		print;
	}')
	#echo "===> ${l}" >&2

	ll=$(echo "${l}" | wc -w | awk '{ print $1 }')
	while test "${ll}" -gt 1; do
		hwr=${l%%[[:space:]]*}
		l=${l#*[[:space:]]}
		fwd=${l%%[[:space:]]*}
		l=${l#*[[:space:]]}

		#echo "=+=> ${hwr} -> ${fwd}" >&2
		eval fwd_${hwr}=${fwd}
		ll=$(echo "${l}" | wc -w | awk '{ print $1 }')
	done

	echo "${hwrevs}" | \
	while read did hwrl; do
		hwrn=$(echo "${hwrl}" | wc -w | awk '{ print $1 }')
		if test ${hwrn} -lt 1; then
			printf "Device ID %s has no hardware revisions (%s); skipping\n" "${did}" ${hwrn} >&2
			continue
		fi

		for hwrx in ${hwrl}; do

			eval fwd=\${fwd_${hwrx}}
			#echo "===> ${did} -> ${hwrx} -> ${fwd}" >&2

			if test ! -d ${LFWDIR}/${fwd}; then
				#printf "Firmware dir %s (for %s) does not exist; skipping\n" ${fwd} ${did} >&2
				continue
			fi

			flav=$(echo "${fwd}" | awk -v drv=${DRIVER} '{
				# Ports FLAVOR names are [a-z0-9_].  If needed add more mangling magic here.
				gsub("^" drv "/", "");
				gsub("/", "_");
				gsub("\\.", "");
				print tolower($0);
			}')

			# Print this first or otherwise if two device IDs have the same firmware
			# we may not see that.
			echo "FWGET ${did} ${flav}"

			x=""
			for zf in ${sfwl}; do
				if test "${zf}" == "${flav}"; then
					x="${zf}"
					break
				fi
			done
			if test "${x}" != ""; then
				#printf "Flavor %s (firmware directory %s) already seen; skipping\n" ${flav} ${fwd} >&2
				continue
			fi
			sfwl="${sfwl} ${flav}"

			#echo "==> ${did} -> ${fwd} -> ${flav}"

			lx=$(cd ${LFWDIR} && find ${fwd} -type f \! -name "*sdio*" -a \! -name "*.txt" -print)

			# Get a count so we can automatically add \\ apart from the last line.
			fn=$(echo "${lx}" | wc -w | awk '{ print $1 }')

			#echo "==> ${flav} :: ${fn} :: ${lx}" >&2

			if test ${fn} -gt 0; then

				echo "FWS ${flav}"
				echo "DISTFILES_${flav}= \\"
				for fz in ${lx}; do echo "${fz}"; done | \
				awk -v fn=$fn -v fwg=${flav} -v drv=${DRIVER} '{
					if (FNR == fn) { x="" } else { x=" \\" };
					#gsub("^" drv "/", "${FWSUBDIR}/");
					gsub("^", "${FWSUBDIR}/");
					printf "\t%s${DISTURL_SUFFIX}%s\n", $0, x;
				}'

				# Check for "lic" files.
				lx=$(cd ${LFWDIR} && find ${fwd} -type f \! -name "*sdio*" -a -name "*.txt" -print)

				# Get a count so we can automatically add \\ apart from the last line.
				fn=$(echo "${lx}" | wc -w | awk '{ print $1 }')

				if test ${fn} -gt 0; then
					echo "FWL ${flav}"
					echo "DISTFILES_${flav}_lic= \\"
					for fz in ${lx}; do echo "${fz}"; done | \
					awk -v fn=$fn -v fwg=${flav} -v drv=${DRIVER} '{
						if (FNR == fn) { x="" } else { x=" \\" };
						#gsub("^" drv "/", "${FWSUBDIR}/");
						gsub("^", "${FWSUBDIR}/");
						printf "\t%s${DISTURL_SUFFIX}%s\n", $0, x;
					}'
				fi
			fi
		done

	done
}

################################################################################
#
# Generate the PORTS file template.
#

fwsl=$(list_fw | grep ^FWS | awk '{ print $2 }')
# Get a count so we can automatically add \\ apart from the last line.
fn=$(echo "${fwsl}" | wc -w | awk '{ print $1 }')

if test ${fn} -gt 0; then

	portsfile=$(mktemp -p /tmp ${DRIVER}-fwport.XXXXXX)

	:> ${portsfile}
	(
	echo "FWSUBS= \\"
	for sz in ${fwsl}; do echo "${sz}"; done | \
	awk -v fn=$fn '{
		if (FNR == fn) { x="" } else { x=" \\" };
		printf "\t%s%s\n", $0, x;
	}'

	echo
	list_fw | grep -v ^FWS | grep -v ^FWL | grep -v ^FWGET

	echo
	echo "DISTFILES_\${FWDRV}= \\"
	for sz in ${fwsl}; do echo "${sz}"; done | \
	awk -v fn=$fn '{
		if (FNR == fn) { x="" } else { x=" \\" };
		printf "\t${DISTFILES_%s}%s\n", $0, x;
	}'

	fwsl=$(list_fw | grep ^FWL | awk '{ print $2 }')
	# Get a count so we can automatically add \\ apart from the last line.
	fn=$(echo "${fwsl}" | wc -w | awk '{ print $1 }')
	if test ${fn} -gt 0; then
		echo "DISTFILES_\${FWDRV}_lic= \\"
		for sz in ${fwsl}; do echo "${sz}"; done | \
		awk -v fn=$fn '{
			if (FNR == fn) { x="" } else { x=" \\" };
			printf "\t${DISTFILES_%s_lic}%s\n", $0, x;
		}'
	else
		echo "DISTFILES_\${FWDRV}_lic="
	fi

	) >> ${portsfile}

	printf "INFO: wifi-firmware-%s-kmod template at %s\n" ${DRIVER} ${portsfile} >&2
fi

################################################################################
#
# Generate the fwget(8) case pattern table (PCI device ID -> fw port flavor).
#

fwgetfile=$(mktemp -p /tmp ${DRIVER}-fwget.XXXXXX)
:> ${fwgetfile}

fwsl=$(list_fw | grep ^FWGET | sort)
# Get a count so we can automatically add \\ apart from the last line.
fn=$(echo "${fwsl}" | grep -c FWGET | awk '{ print $1 }')

if test ${fn} -gt 0; then

	# We need to check for same ID with multiple firmware.
	# The list ist sorted by ID so duplicates are next to each other.
	cs=$(echo "${fwsl}" | awk '{ print $2 }' | uniq -c | awk '{ print $1 }')

	#echo "==> cs=${cs}" >&2

	for n in ${cs}; do

		# Skip FWGET
		fwsl=${fwsl#*[[:space:]]}
		# get device ID
		did=${fwsl%%[[:space:]]*}
		fwsl=${fwsl#*[[:space:]]}
		# get flavor
		flav=${fwsl%%[[:space:]]*}
		fwsl=${fwsl#*[[:space:]]}

		# printf "===> did %s flav %s\n" ${did} ${flav} >&2

		if test ${n} -eq 1; then
			echo "${did} ${flav}" | awk -v drv=${DRIVER} '{
				printf "\t%s)\taddpkg \"wifi-firmware-%s-kmod-%s\"; return 1 ;;\n",
				    tolower($1), drv, tolower($2);
			}' >> ${fwgetfile}
		else
			echo "${did} ${flav}" | awk -v drv=${DRIVER} '{
				printf "\t%s)\taddpkg \"wifi-firmware-%s-kmod-%s\"\n",
				    tolower($1), drv, tolower($2);
			}' >> ${fwgetfile}

			i=1
			while test ${i} -lt ${n}; do
				# Skip FWGET
				fwsl=${fwsl#*[[:space:]]}
				# get device ID
				did=${fwsl%%[[:space:]]*}
				fwsl=${fwsl#*[[:space:]]}
				# get flavor
				flav=${fwsl%%[[:space:]]*}
				fwsl=${fwsl#*[[:space:]]}

				#printf "===> did %s flav %s\n" ${did} ${flav} >&2

				echo "${did} ${flav}" | awk -v drv=${DRIVER} '{
					printf "\t\taddpkg \"wifi-firmware-%s-kmod-%s\"\n",
					    drv, tolower($2);
				}' >> ${fwgetfile}

				i=$((i + 1))
			done

			printf "\t\treturn 1 ;;\n" >> ${fwgetfile}
		fi
	done
fi

printf "INFO: fwget pci_network_qca %s template at %s\n" ${DRIVER} ${fwgetfile} >&2

# end
