# Contributor: Oliver Smith <ollieparanoid@postmarketos.org>
# Maintainer: Natanael Copa <ncopa@alpinelinux.org>
pkgname=linux-firmware
pkgver=20250509
pkgrel=0
pkgdesc="firmware files for linux"
url="https://git.kernel.org/?p=linux/kernel/git/firmware/linux-firmware.git;a=summary"
arch="noarch"
license="custom"
makedepends="findutils libarchive-tools coreutils parallel python3 rdfind zstd"
provides="linux-firmware-any"
provider_priority=2
options="!strip !check !archcheck !spdx !usrmerge"

_rpi_bt=2bbfb8438e824f5f61dae3f6ebb367a6129a4d63
_rpi_brcm=3900afffcd85198e3afab396fbf1d0abe5f76173

source="https://gitlab.com/kernel-firmware/linux-firmware/-/archive/$pkgver/linux-firmware-$pkgver.tar.gz
	bluez-firmware-$_rpi_bt.tar.gz::https://github.com/RPi-Distro/bluez-firmware/archive/$_rpi_bt.tar.gz
	brcm-firmware-$_rpi_brcm.tar.gz::https://github.com/RPi-Distro/firmware-nonfree/archive/$_rpi_brcm.tar.gz
	"

# Put /lib/firmware/* folders in subpackages
_folders="3com acenic adaptec advansys aeonsemi airoha amd amd-ucode amdgpu
	amdnpu amdtee amlogic amphion ar3k arm ath10k ath11k ath12k ath6k ath9k_htc
	atmel atusb av7110 bnx2 bnx2x brcm cadence cavium cirrus cis cnm cpia2 cxgb3
	cxgb4 cypress dabusb dpaa2 dsp56k e100 edgeport emi26 emi62 ene-ub6250 ess
	go7007 i915 imx inside-secure intel isci ixp4xx kaweth keyspan keyspan_pda korg
	libertas liquidio matrox mediatek mellanox meson microchip moxa mrvl mwl8k
	mwlwifi myricom netronome nvidia nxp ositech powervr qca qcom qed qlogic r128
	radeon realtek rockchip rsi rtl_bt rtl_nic rtlwifi rtw88 rtw89 sb16 slicoss sun
	sxg synaptics tehuti ti ti-connectivity ti-keystone tigon ttusb-budget
	ueagle-atm vicam vxge wfx xe yam yamaha"

subpackages="$pkgname-other $pkgname-none"
depends="linux-firmware-other=$pkgver-r$pkgrel"
for i in $_folders; do
	subpackages="$pkgname-$i:_folder $subpackages"
	depends="$pkgname-$i=$pkgver-r$pkgrel $depends"
done
subpackages="amd-ucode $subpackages"

# Add S5P MFC subpackage separately (it doesn't have its own folder)
subpackages="$pkgname-s5p-mfc:s5p_mfc $subpackages"
depends="$pkgname-s5p-mfc=$pkgver-r$pkgrel $depends"

package() {
	## install upstream linux-firmare files
	export ZSTD_NBTHREADS=4 ZSTD_CLEVEL=19
	make DESTDIR="$pkgdir" FIRMWAREDIR="/lib/firmware" install-zst
	# De-duplicate needs to be explicit since 20241017
	make DESTDIR="$pkgdir" FIRMWAREDIR="/lib/firmware" dedup

	## replace Pi bluez and wifi firmware files by original from Pi Foundation's
	rm -f "$pkgdir"/lib/firmware/brcm/*aspberry*
	for dir in brcm synaptics; do
		for f in "$srcdir"/bluez-firmware-"$_rpi_bt"/debian/firmware/"${dir/brcm/broadcom}"/*.hcd; do
			# add & rename Pi foundation base file if it collides with upstream
			if [ -e "$pkgdir/lib/firmware/$dir/$(basename "$f")".zst ]; then
				mv "$f" "${f/.hcd/.rpiltd.hcd}"
				f="${f/.hcd/.rpiltd.hcd}"
			fi
			zstd --compress --quiet "$f"
			cmp -s "$f".zst "$pkgdir/lib/firmware/$dir/$(basename "${f/.rpiltd/}")".zst || \
			install -Dm 644 "$f".zst -t "$pkgdir/lib/firmware/$dir"
		done
	done
	# add symlinks from bluez-firmware.links
	while read -r link_args; do
		dst="$(echo "$link_args" | awk '{print $2}')"
		dst="${pkgdir}${dst}"
		src="$(echo "$link_args" | awk '{print $1}')"
		if [ -e "${pkgdir}${src/.hcd/.rpiltd.hcd.zst}" ]; then
			src="${src/.hcd/.rpiltd.hcd}"
		fi
		src="${src/\/lib\/firmware\/brcm\//}"
		src="${src/\/lib\/firmware\/synaptics\//..\/synaptics\/}"
		ln -sv "$src".zst "$dst".zst
	done < "$srcdir/bluez-firmware-$_rpi_bt/debian/bluez-firmware.links"

	## add original Pi Foundation brcm wifi firmware files (except 43439)
	rm "$srcdir/firmware-nonfree-$_rpi_brcm"/debian/config/brcm80211/brcm/*43439*
	rm "$srcdir/firmware-nonfree-$_rpi_brcm"/debian/config/brcm80211/cypress/*43439*
	rm "$srcdir/firmware-nonfree-$_rpi_brcm"/debian/config/brcm80211/cypress/README.txt
	for dir in cypress brcm; do
		for f in "$srcdir/firmware-nonfree-$_rpi_brcm/debian/config/brcm80211/$dir"/*; do
			# add & rename Pi foundation base file if it collides with upstream
			if [ -e "$pkgdir/lib/firmware/$dir/$(basename "$f")".zst ]; then
				mv "$f" "${f%.*}.rpiltd.${f##*.}"
				f="${f%.*}.rpiltd.${f##*.}"
			fi
			if ! [ -L "$f" ]; then
				zstd --compress --quiet "$f"
				cmp -s "$f".zst "$pkgdir/lib/firmware/$dir/$(basename "${f/.rpiltd/}")".zst || \
				install -Dm 644 "$f".zst -t "$pkgdir/lib/firmware/$dir"
			else
				mv "$f" "$pkgdir/lib/firmware/$dir/$(basename "$f")".lnk #kept aside for 2nd pass relinking
			fi
		done
	done
	# we can use either Pi -standard or -minimal 43455 file so use standard by default
	ln -sv cyfmac43455-sdio-standard.bin.zst "$pkgdir"/lib/firmware/cypress/cyfmac43455-sdio.rpiltd.bin.zst
	# now remap downstream Pi brcm symlinks
	for f in "$pkgdir/lib/firmware/brcm"/*.lnk; do
		src="$(readlink "$f")"
		if [ -e "${pkgdir}/lib/firmware/brcm/${src%.*}.rpiltd.${src##*.}.zst" ] || \
			[ -L "${pkgdir}/lib/firmware/brcm/${src%.*}.rpiltd.${src##*.}.zst" ]; then
			src="${src%.*}.rpiltd.${src##*.}"
		fi
		rm -f "$f"
		f="$(basename "${f%.*}")"
		ln -sv "${src}.zst" "$pkgdir/lib/firmware/brcm/$f".zst
	done


	# Prevent recursive dependency between mrvl and libertas
	ln -nfv "$pkgdir"/lib/firmware/mrvl/sd8688.bin.zst "$pkgdir"/lib/firmware/libertas/sd8688.bin.zst
	ln -nfvs ../libertas/sd8688.bin.zst "$pkgdir"/lib/firmware/mrvl/sd8688.bin.zst
	ln -nfvs sd8682_helper.bin.zst "$pkgdir"/lib/firmware/libertas/sd8688_helper.bin.zst

	## symlinks for Visionfive1 riscv64 boards, till it fixed upstream
	ln -sfv ../cypress/cyfmac43430-sdio.bin.zst "$pkgdir"/lib/firmware/brcm/brcmfmac43430-sdio.starfive,visionfive-v1.bin.zst

	dangling=$(cd "$pkgdir" && find . -type l ! -exec test -e {} \; -print)
	if [ -n "$dangling" ]; then
		error "dangling symlinks:"
		echo "$dangling" >&2
		return 1
	fi
}

_folder() {
	local folder=${subpkgname##linux-firmware-}
	pkgdesc="firmware files for linux ($folder folder)"
	depends=""
	provides="linux-firmware-any"
	provider_priority=1

	local linkedbins= bin=
	cd "$pkgdir"
	# Move things that symlink into the target folder
	# this fixes the -other deps, because
	# - there are top-level files that are in -other (non-folder)
	# - but, they are actually symlinks into .e.g -mediatek
	# so, -other now depends on -mediatek due to symlink resolution
	# this moves the symlinks along with the thing they symlink to.
	linkedbins="$(find lib/firmware -maxdepth 1 -type l -exec sh -c "readlink \$1 | grep -qi $folder && echo \$1" - {} \;)"

	if [ -n "$linkedbins" ]; then
		for bin in $linkedbins; do
			amove "$bin"
		done
	fi

	# Move /lib/firmware/$folder (case insensitive)
	amove "$(find lib/firmware -iname "$folder" -type d)"
}

other() {
	# Requires subfolders to be split in subpackages
	local leftover=""
	local i
	for i in "$pkgdir"/lib/firmware/*; do
		[ -d "$i" ] && leftover="$leftover $(basename $i)"
	done
	if [ "$leftover" != "" ]; then
		local fixed
		error "Not all subfolders have been moved to subpackages!"
		error "Fix this by adjusting _folders as follows:"
		fixed="$(echo $_folders$leftover | tr " " "\n" | tr '[:upper:]' '[:lower:]' | sort)"
		echo "_folders=\"$(printf "%s" "$fixed" | tr "\n" " ")\"" | fold -s
		return 1
	fi

	# Move /lib/firmware (which doesn't have subfolders now)
	pkgdesc="firmware files for linux (uncategorized)"
	depends=""
	provides="linux-firmware-any"
	provider_priority=1

	amove /lib
}

none() {
	# dummy package with no firmware
	pkgdesc="Empty linux firwmare package for those who does not need any firmware"
	provides="linux-firmware-any"
	provider_priority=1
	depends=
	mkdir -p "$subpkgdir"
}

ucode() {
	pkgdesc="Microcode update files for AMD CPUs"
	provider_priority=
	provides=
	depends=

	# build ported from Arch Linux's PKGBUILD
	mkdir -p "$subpkgdir"/boot
	mkdir -p "$builddir"/kernel/x86/microcode
	cat "$pkgdir"/lib/firmware/amd-ucode/microcode_amd*.bin > "$builddir"/kernel/x86/microcode/AuthenticAMD.bin
	[ -n "$SOURCE_DATE_EPOCH" ] && touch -d @$SOURCE_DATE_EPOCH "$builddir"/kernel/x86/microcode/AuthenticAMD.bin
	cd "$builddir" && echo kernel/x86/microcode/AuthenticAMD.bin |
	  bsdtar --uid 0 --gid 0 -cnf - -T - |
	  bsdtar --null -cf - --format=newc @- > "$subpkgdir"/boot/amd-ucode.img
}

s5p_mfc() {
	# This needs its own function as the files are not in a directory,
	# but rather loose in the main directory.
	pkgdesc="firmware files for linux (S5P MFC firmware)"
	provides="linux-firmware-any"
	provider_priority=1
	depends=

	amove /lib/firmware/s5p-mfc*.fw.zst
}

sha512sums="
636448ad224df656175d1e15aa4b9d5db2bb4c36de43248f1dee7c8178d052c97a11196abf914f05e3cb3645c88acdc2694081e983d6895c5dfa9c9438c2a779  linux-firmware-20250509.tar.gz
62246630d710dabcdc98443a27ecd610e1c3fb047fbaf0fd905cd9a2d9406c0b38c589e55adb6385f288c5a208bbaca220510da5df882ddaa39967724592adc9  bluez-firmware-2bbfb8438e824f5f61dae3f6ebb367a6129a4d63.tar.gz
b4879ff8c9bbe82eb579a8eef86f332d525b59a649805080c15275f45be4c015a2089befc2acd5d78537277e02b5f66ef5060605fd833e0cb40f1e22a5f484b1  brcm-firmware-3900afffcd85198e3afab396fbf1d0abe5f76173.tar.gz
"
