LinuxKPI based WiFi drivers: scripts to extract fwget(8) and port details

Add a "zzz_fw_ports_fwget.sh" script to each LinuxKPI based wireless
driver which in essential are all the same and in detail all different.
The scripts have been referenced in fwget(8) sources since d33f5a0afa
but were never committed.

The scripts do the full job compared to `single-line-scripts` I tried to
use before to ease maintainance life.  Some use hacks like calling cpp
and extracting bits from the output to piece them together over multiple
files.  It will be left as an exercise for the future to see if what was
done (a longer while ago) for iwlwifi(4) would be a good idea for some
other drivers too, to have a FreeBSD-specific sysctl to export some of
the accumulated data in an easily processable way.
The scripts are written in the "perl spirit" -- "to get the job done" --
and not to be nice or neat or efficient.  For that we do not need them
often enough or in any critical path.  People are welcome to improve
them if they feel like.
I've used them for two version updates now and even if ports enforce
some other (manual) editing to keep support for multiple branches for
now they worked extremly well.

For the most the scripts extract 2 parts: PCI IDs and firmware name;
then they add "flavor"s to both and put the information together.

That output is then separated into:
- fwget(8) lines of PCI ID to port/package
  wifi-firmware-${name}-kmod-${flavor} mappings and
- distfiles per flavor for the ports.
- For iwlwififw(4) we also generate the tables for the man page
  (and the wiki) and hopefully the .Sh HARDWARE section for iwlwifi.4
  soon too.

Depending on driver various other checks are done, e.g.,
- does the PCI ID have one or more firmware files/flavors associated,
- does the referenced firmware exist in the linux-firmware.git repo,
- are there duplicates,
- find the latest version of the firmware API.

Sponsored by:	The FreeBSD Foundation
Suggested by:	imp (to have automation in D44918)
MFC after:	3 days
This commit is contained in:
Bjoern A. Zeeb 2024-04-28 20:50:12 +00:00
parent b4c8f251d6
commit 96190b4fef
7 changed files with 1876 additions and 0 deletions

View file

@ -0,0 +1,286 @@
#!/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=ath10k
CHECKFILE=qmi_wlfw_v01.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
################################################################################
#
# 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.
# Checking MODULE_FIRMWARE was pointless as it had too many "dead" entries:
# NOTICE: no firmware file found for 'ath10k/QCA6174/hw2.1/firmware-4.bin'
# NOTICE: no firmware file found for 'ath10k/QCA6174/hw3.0/firmware-5.bin'
# NOTICE: no firmware file found for 'ath10k/QCA9887/hw1.0/board-2.bin'
# NOTICE: no firmware file found for 'ath10k/QCA988X/hw2.0/board-2.bin'
# NOTICE: no firmware file found for 'ath10k/QCA988X/hw2.0/firmware-2.bin'
# NOTICE: no firmware file found for 'ath10k/QCA988X/hw2.0/firmware-3.bin'
#
list_fw()
{
# List of already seen flavor (firmware directory).
sfwl=""
# List of "supported" device IDs (ignoring Ubiquity).
devidl=$(cpp pci.c 2> /dev/null | awk '/PCI_VDEVICE\(ATHEROS,/ { gsub("^.*, \\(", ""); gsub("\\)\\) },$", ""); print tolower($0); }')
# List of (device ID) -> (firware directory) mappings.
cpp core.c 2> /dev/null | egrep -E '\.(dev_id|dir) = ' | awk '{ if (/dev_id/) { printf "%s", $0; } else { print; } }' | grep -v 'dev_id = 0,' | sort | uniq | \
awk '{
gsub("^.*\\(", "");
gsub("),.* = ", "\t");
gsub(",$", "");
gsub(/"/, "");
gsub(" ", "");
print;
}' | \
while read did fwd; do
x=""
for d in ${devidl}; do
if test "${did}" == "${d}"; then
x="${d}"
break
fi
done
if test "${x}" == ""; then
# Device ID not in the list of PCI IDs we support.
# At least the Ubiquity one we hit here.
#printf "Device ID %s (%s) not in PCI ID list; skipping\n" ${did} ${fwd} >&2
continue
fi
if test ! -d ${LFWDIR}/${fwd}; then
# Leave this on as it MUST not happen.
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}/");
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}/");
printf "\t%s${DISTURL_SUFFIX}%s\n", $0, x;
}'
fi
fi
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

View file

@ -0,0 +1,317 @@
#!/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=ath11k
CHECKFILE=debugfs_htt_stats.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.
#
# Driver is there, the firmware not yet...?
# ==> 0x1101 -> ATH11K_HW_QCA6390_HW20 -> QCA6390/hw2.0
# ==> 0x1104 -> ATH11K_HW_QCN9074_HW10 -> QCN9074/hw1.0
# ==> 0x1103 -> ATH11K_HW_WCN6855_HW20 -> WCN6855/hw2.0
# ==> 0x1103 -> ATH11K_HW_WCN6855_HW21 -> WCN6855/hw2.1
# Firmware dir WCN6855/hw2.1 (for 0x1103) does not exist; skipping
#
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 core.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

View file

@ -0,0 +1,310 @@
#!/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

View file

@ -0,0 +1,374 @@
#!/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.
#
# USAGE: please make sure to pre-load if_iwlwifi.ko so that we
# have access to the sysctl. You do not need to have a supported
# card in the system.
# In case that is not possible you can save the results to a file
# and provide that locally. It will be renamed at the end of the
# run.
#
set -e
# sysctl -n compat.linuxkpi.iwlwifi_pci_ids_name > iwlwifi_pci_ids_name.txt
PCI_IDS_FILE=iwlwifi_pci_ids_name.txt
D_PCI_IDS_FILE=`pwd`/${PCI_IDS_FILE}
################################################################################
#
# Check pre-reqs
#
if [ $# -ne 1 ]; then
printf "USAGE: %s /path/to/linux-firmware.git\n" $0 >&2
exit 1
fi
if [ ! -d cfg/ -o ! -e cfg/bz.c ]; then
printf "ERROR: run from iwlwifi driver directory; no cfg/bz.c here\n" >&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
kldstat -n if_iwlwifi.ko > /dev/null 2>&1
rc=$?
case ${rc} in
0) ;;
*) printf "ERROR: please pre-load if_iwlwifi.ko (you do not need a device)\n" >&2
exit 1
;;
esac
if test -r ${D_PCI_IDS_FILE}; then
printf "NOTICE: using proovided ${D_PCI_IDS_FILE}\n" >&2
else
sysctl -N compat.linuxkpi.iwlwifi_pci_ids_name > /dev/null 2>&1
rc=$?
case ${rc} in
0) sysctl -n compat.linuxkpi.iwlwifi_pci_ids_name > ${D_PCI_IDS_FILE}
;;
*) printf "ERROR: cannot get compat.linuxkpi.iwlwifi_pci_ids_name\n" >&2
exit 1
;;
esac
fi
# We need to be in the config directory for simplicity.
cd cfg
################################################################################
# Get a list of all device/firmware flavors as seen/supported by the driver.
flavors=$(awk -F\\t '{
if (/^$/) { next; }
if ($5 == "undefined") { next; }
print tolower($5);
}' ${D_PCI_IDS_FILE} | sort -V | uniq)
################################################################################
#
# Helper functions.
#
#
# This uses a hack (cpp) to expand some macros for us and parses out the result
# which is the firmware name with the maximum FW version supported for that
# firmware.
# We then go and check that said firmware actually exists in linux-firmware.git.
# We try to find a lower version number if the "MAX" version given from the cpp
# output does not (yet) publicly exist.
# .pnvm files are now properly listed as MODULE_FIRMWARE so no more magic needed
# for them.
# Given the filename matches a "flavor" at this point, we then group all the
# available firmware files from this flavor together and print it as a ports
# Makefile variable.
#
# We also print some other meta-data that callers will filter out depending on
# their needs to generate other lists and mappings.
#
# For each get a list of firmware names we know.
list_fw()
{
for f in ${flavors}; do
#echo "==> ${f}"
#awk -F \\t -v flav=${f} '{
# if ($5 != flav) { next; }
# # No firmwre; skip.
# if ($3 ~ /^$/) { next; }
# if ($3 == "(null)") { next; };
# print $3;
#}' ${D_PCI_IDS_FILE} | sort | uniq
# For now the flavor names and the file names are 1:1 which makes this
# a lot easier (given some sysctl/file entries are not able to list
# their firmware but we know their "flavor".
l=$(cpp ${f}.c 2>&1 | awk '
/^MODULE_FIRMWARE\(/ {
gsub(/"/, "");
gsub("__stringify\\(", "");
gsub("\\);$", "");
gsub("\\)", "");
gsub("^MODULE_FIRMWARE\\(", "");
gsub(" ", "");
printf "%s\n", $0;
}' | sort -V | uniq)
#echo "${l}"
lx=""
for fx in ${l}; do
if test -e ${LFWDIR}/${fx}; then
lx="${lx} ${fx}"
# Check for matching .pnvm file.
# They are now properly listed in MODULE_FIRMWARE() as well so no more magic.
#px=$(echo ${fx} | awk '{ gsub("-[[:digit:]]*.ucode", ".pnvm"); print; }')
#if test -e ${LFWDIR}/${px}; then
# lx="${lx} ${px}"
#fi
else
case "${fx}" in
*.pnvm)
printf "NOTICE: pnvm file not found for '%s'\n" ${fx} >&2
;;
*.ucode)
# Try lowering the version number.
bn=$(echo ${fx} | awk '{ gsub("-[[:digit:]]*.ucode", ""); print; }')
vn=$(echo ${fx} | awk '{ gsub(".ucode$", ""); gsub("^.*-", ""); print; }')
#echo "BN ${bn} VN ${vn}"
# Single digits are not zero-padded so just ${i} will be fine.
for i in `jot ${vn} 1`; do
xn="${bn}-${i}.ucode"
if test -e ${LFWDIR}/${xn}; then
lx="${lx} ${xn}"
break 2;
fi
done
;;
*)
printf "NOTICE: file for unknown firmware type not found for '%s'\n" ${fx} >&2
;;
esac
fi
done
# Get a count so we can automatically add \\ apart from the last line.
fn=$(echo "${lx}" | wc -w | awk '{ print $1 }')
#echo "==> ${f} :: ${fn} :: ${lx}"
if test ${fn} -gt 0; then
# Ports FLAVOR names are [a-z0-9_]. If needed add more mangling magic here.
flav=`echo ${f} | awk '{ printf "%s", tolower($0); }'`
echo "FWS ${flav}"
echo "DISTFILES_${flav}= \\"
for fz in ${lx}; do echo "${fz}"; done | \
awk -v fn=$fn -v fwg=${flav} '{
if (FNR == fn) { x="" } else { x=" \\" };
printf "\t%s${DISTURL_SUFFIX}%s\n", $0, x;
fwn=$0;
gsub("-[[:digit:]]*\.ucode$", "", fwn);
printf "FWGET %s %s\n", fwg, fwn;
}'
fi
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 iwlwifi-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
echo "# Do not prefix with empty \${FWSUBDIR}/!"
list_fw | grep -v ^FWS | 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; }'
echo "DISTFILES_\${FWDRV}_lic="
) >> ${portsfile}
printf "INFO: wifi-firmware-iwlwifi-kmod template at %s\n" ${portsfile} >&2
fi
################################################################################
#
# Generate a temporary firmware -> flavor mapping table for fwget generation.
#
mapfile=$(mktemp -p /tmp iwlwifi-mapfile.XXXXXX)
:> ${mapfile}
fwgl=$(list_fw | grep FWGET)
# Get a count so we can automatically add \\ apart from the last line.
fn=$(echo "${fwgl}" | wc -w | awk '{ print $1 }')
if test ${fn} -gt 0; then
(
list_fw | grep FWGET | grep -v '.pnvm' | \
while read x flav fw; do
printf "%s\t%s\n" ${fw} ${flav}
done | \
sort -n | uniq
) >> ${mapfile}
fi
################################################################################
#
# Try to generate the PCI ID -> port flavor mapping
#
# We get PCI ID, description, firmware base from the sysctl and can work our
# way back from fw name base to flavor via the mapping table file.
#
fwgetfile=$(mktemp -p /tmp iwlwifi-fwget.XXXXXX)
:> ${fwgetfile}
awk 'BEGIN { FS="\t"; }
{
# Skip empty lines.
if (/^$/) { next; }
# Skip "undefined" flavors as we have no idea what chipset.
if ($5 == "undefined") { next; }
# No firmware name; do not skip!
# All we need is the flavor, which we now always have.
#if ($3 == "(null)") { next; };
FLAV=tolower($5);
split($1, i, "/");
gsub("\t.*$", "", i[4]);
# Not an Intel Vednor ID; skip.
if (i[1] != "0x8086") { next; };
# No defined device ID; skip.
if (i[2] == "0xffff") { next; };
# Adjust wildcards or a ill-printed 0.
if (i[3] == "0xffffffff") { i[3] = "*"; };
if (i[4] == "000000") { i[4] = "0x0000"; };
if (i[4] == "0xffffffff") { i[4] = "*"; };
if (i[4] == "0xffff") { i[4] = "*"; };
printf "%s\t%s/%s/%s\n", FLAV, i[2], i[3], i[4];
}' ${D_PCI_IDS_FILE} | \
sort -V | uniq | \
while read flav match; do
#flav=$(awk -v fw=$fw '{ if ($1 == fw) { print $2; } }' ${mapfile})
#echo "${fw} :: ${match} :: ${flav}"
if test "${flav}" != ""; then
printf "${flav}\t${match}\t${flav}\n"
else
#echo "NO FLAV ${fw} ${match}" >&2
fi
done | \
awk 'BEGIN { FS="\t"; FWN=""; }
{
FW=$1;
if (FWN != FW) { printf "\n\t# %s\n", FW; FWN=FW; };
printf "\t%s) addpkg \"wifi-firmware-iwlwifi-kmod-%s\"; return 1 ;;\n", $2, $3;
} END {
printf "\n";
}' >> ${fwgetfile}
printf "INFO: fwget pci_network_intel template at %s\n" ${fwgetfile} >&2
################################################################################
#
# Try to build the iwlwififw.4 bits too.
#
dl=$(grep -v ^$ ${D_PCI_IDS_FILE} | uniq | \
awk '
{
# Sourt out duplicate lines.
if (dup[$0]++) { next; }
# my ($ids, $name, $fw) = split /\t/;
split($0, a, "\t");
ids=a[1];
name=a[2];
fw=a[3];
#my ($v, $d, $sv, $sd) = split("/", $ids);
split(ids, i, "/");
gsub("^0xffff+", "any", i[1]);
gsub("^0xffff+", "any", i[2]);
gsub("^0xffff+", "any", i[3]);
gsub("^0xffff+", "any", i[4]);
if (name == "") { name="(unknown)"; }
if (fw == "") { fw="(unknown)"; }
# iwlwififw.4
printf ".It \"\"\n.It %s\n.It %s Ta %s Ta %s Ta %s Ta %s\n", name, i[1], i[2], i[3], i[4], fw;
# wiki
# XXX TODO possibly quote some in `` to avoid automatic linking?
# || PCI IDs || Chipset Name || Firmware prefix || Comment ||
printf "WIKI || %s / %s / %s / %s || %s || %s || ||\n", i[1], i[2], i[3], i[4], name, fw;
if ((FNR % 25) == 0) { printf "WIKI \n"; }
}')
manfwfile=$(mktemp -p /tmp iwlwifi-iwlwififw4.XXXXXX)
:> ${manfwfile}
echo "${dl}" | grep -v ^WIKI >> ${manfwfile}
printf "INFO: share/man/man4/iwlwififw.4 template at %s\n" ${manfwfile} >&2
wikifile=$(mktemp -p /tmp iwlwifi-wiki.XXXXXX)
:> ${wikifile}
echo "${dl}" | awk '/^WIKI / { gsub("^WIKI ", ""); print; }' >> ${wikifile}
printf "INFO: WIKI template at %s\n" ${wikifile} >&2
################################################################################
#
# Cleanup
#
rm ${mapfile}
mv -f ${D_PCI_IDS_FILE} ${D_PCI_IDS_FILE}.old
# end

View file

@ -0,0 +1,292 @@
#!/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.
#
# Valid flavors: mt7915 mt792x {for the drivers with x=[15]} mt7996
# To add a new one you need to add the mappings in the help functions.
#
set -e
DRIVER=mt76
FWSUBDIR=mediatek
CHECKFILE=mt792x.h
################################################################################
#
# 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
################################################################################
#
# Helper functions.
#
get_device_ids_by_flav()
{
for d in mt7915 mt7921 mt7925 mt7996; do
case ${d} in
mt7915) flav=${d} ;;
mt7921) flav=mt792x ;;
mt7925) flav=mt792x ;;
mt7996) flav=${d} ;;
*) printf "ERROR: unsupported directory/flavor '%s'\n" ${d} >&2
exit 1
;;
esac
awk -v flav=${flav} -v rege="/${d}_pci_device_table/" 'BEGIN { x = 0; } {
if (rege) { x=1 };
if (/^\};/) { x=0 };
if (x==1 && /PCI_DEVICE\(PCI_VENDOR_ID_MEDIATEK,/) {
gsub(").*", "", $3);
#printf "%s)\taddpkg \"wifi-firmware-mt76-kmod-%s\"; return 1 ;;\n", tolower($3), tolower(flav);
printf "%s\t%s\n", tolower(flav), tolower($3);
}
}' ${d}/pci.c
#grep -1r 'PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK' ${flav}
done
}
get_firmwares_by_flavor()
{
for h in mt7915/mt7915.h mt792x.h mt7996/mt7996.h; do
case ${h} in
mt7915/mt7915.h) flav=mt7915 ;;
mt792x.h) flav=mt792x ;;
mt7996/mt7996.h) flav=mt7996 ;;
*) printf "ERROR: unsupported header/flavor '%s'\n" ${h} >&2
exit 1
;;
esac
awk -v rege="${FWSUBDIR}/" -v flav=${flav} -F\" '{ if ($0 ~ rege) { printf "%s\t%s\n", tolower(flav), $2; } }' ${h} | \
while read flav fwn; do
if test ! -e ${LFWDIR}/${fwn}; then
#printf "Firmware %s (for %s) does not exist; skipping\n" ${fwn} ${flav} >&2
continue
fi
printf "%s\t%s\n" ${flav} ${fwn}
done
done
}
list_fw()
{
# List of already seen flavor (firmware directory).
sfwl=""
# List of "supported" device IDs.
devidl=`get_device_ids_by_flav`
#echo "===> ${devidl}" >&2
# List of (flavor) -> (firmware) mappings.
l=`get_firmwares_by_flavor`
#echo "===> ${l}" >&2
# For each flavor check we have at least 1 firmware file or skip it.
flavs=$(echo "${devidl}" | awk '{ print $1 }' | sort | uniq)
for flav in ${flavs}; do
lx=$(echo "${l}" | awk -v flav=${flav} '{ if ($1 ~ flav) { print $2 } }' | sort | uniq)
fn=$(echo "${lx}" | wc -l | awk '{ print $1 }')
#printf "=+=> %s -- %s -- %s\n" ${flav} ${lx} ${fn} >&2
if test ${fn} -le 0; then
printf "Flavor %s has %s firmware files; skipping\n" ${flav} ${fn} >&2
continue
fi
# Output the PCI ID/flav combinations for this flav.
echo "${devidl}" | \
while read _flav did; do
if test "${_flav}" == "${flav}"; then
# Print this first or otherwise if two device IDs have the same firmware
# we may not see that.
echo "FWGET ${did} ${flav}"
fi
done
x=""
for zf in ${sfwl}; do
if test "${zf}" == "${flav}"; then
x="${zf}"
break
fi
done
if test "${x}" != ""; then
printf "Flavor %s already seen; skipping\n" ${flav} >&2
continue
fi
sfwl="${sfwl} ${flav}"
# Handle ports bits.
echo "FWS ${flav}"
echo "DISTFILES_${flav}= \\"
for fz in ${lx}; do echo "${fz}"; done | \
awk -v fn=$fn -v fwg=${flav} -v drv=${FWSUBDIR} '{
if (FNR == fn) { x="" } else { x=" \\" };
gsub("^" drv "/", "${FWSUBDIR}/");
#gsub("^", "${FWSUBDIR}/");
printf "\t%s${DISTURL_SUFFIX}%s\n", $0, x;
}'
# Check for "lic" files.
# Known known to us, so no idea how to check for them.
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=${FWSUBDIR} '{
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=${FWSUBDIR} '{
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=${FWSUBDIR} '{
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

View file

@ -0,0 +1,145 @@
#!/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=rtw88
CHECKFILE=rtw8822c.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
################################################################################
#
# Helper functions.
#
list_fw()
{
for f in `ls -1 rtw?????.c rtw?????e.c`; do
l=$(awk '/^MODULE_FIRMWARE\(/ { gsub(/"/, ""); gsub("\\);$", ""); gsub("^MODULE_FIRMWARE\\(", ""); printf "%s\n", $0; }' ${f} | sort -n | uniq)
lx=""
for fx in ${l}; do
if test -e ${LFWDIR}/${fx}; then
lx="${lx} ${fx}"
# else
# printf "NOTICE: no firmware file found for '%s'\n" ${fx} >&2
fi
done
# Get a count so we can automatically add \\ apart from the last line.
fn=$(echo "${lx}" | wc -w | awk '{ print $1 }')
# echo "==> ${f} :: ${fn} :: ${lx}"
if test ${fn} -gt 0; then
# Ports FLAVOR names are [a-z0-9_]. If needed add more mangling magic here.
flav=`echo ${f%%.c} | awk '{ printf "%s", tolower($0); }'`
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}/");
printf "\t%s${DISTURL_SUFFIX}%s\n", $0, x;
}'
fi
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
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;
}'
) >> ${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}
for f in `ls -1 rtw?????.c rtw?????e.c`; do
# Ports FLAVOR names are [a-z0-9_]. If needed add more mangling magic here.
n=${f%.c};
n=${n%e};
awk -v n=${n} -v drv=${DRIVER} '/PCI_DEVICE\(PCI_VENDOR_ID_REALTEK,/ {
gsub(").*", "", $2);
printf "\t%s)\taddpkg \"wifi-firmware-%s-kmod-%s\"; return 1 ;;\n",
tolower($2), drv, tolower(n);
}' ${f}
done >> ${fwgetfile}
printf "INFO: fwget pci_network_realtek %s template at %s\n" ${DRIVER} ${fwgetfile} >&2
# end

View file

@ -0,0 +1,152 @@
#!/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=rtw89
CHECKFILE=rtw8922a.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
################################################################################
#
# Helper functions.
#
# This uses a hack (cpp) to expand some macros for us and parses out the result
# which is the firmware name with the maximum FW version supported for that
# firmware (where applicable).
#
list_fw()
{
for f in `ls -1 rtw?????.c rtw?????e.c`; do
l=$(cpp ${f} 2>&1 | awk '/^MODULE_FIRMWARE\(/ { gsub(/"/, ""); gsub("__stringify\\(", ""); gsub("\\);$", ""); gsub("\\)", ""); gsub("^MODULE_FIRMWARE\\(", ""); gsub(" ", ""); printf "%s\n", $0; }' | sort -n | uniq)
if test "${l}" == ""; then
continue
fi
lx=""
for fx in ${l}; do
if test -e ${LFWDIR}/${fx}; then
lx="${lx} ${fx}"
# else
# printf "NOTICE: no firmware file found for '%s'\n" ${fx} >&2
fi
done
# Get a count so we can automatically add \\ apart from the last line.
fn=$(echo "${lx}" | wc -w | awk '{ print $1 }')
# echo "==> ${f} :: ${fn} :: ${lx}"
if test ${fn} -gt 0; then
# Ports FLAVOR names are [a-z0-9_]. If needed add more mangling magic here.
flav=`echo ${f%%.c} | awk '{ printf "%s", tolower($0); }'`
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}/");
printf "\t%s${DISTURL_SUFFIX}%s\n", $0, x;
}'
fi
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
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;
}'
) >> ${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}
for f in `ls -1 rtw?????.c rtw?????e.c`; do
# Ports FLAVOR names are [a-z0-9_]. If needed add more mangling magic here.
n=${f%.c};
n=${n%e};
awk -v n=${n} -v drv=${DRIVER} '/PCI_DEVICE\(PCI_VENDOR_ID_REALTEK,/ {
gsub(").*", "", $2);
printf "\t%s)\taddpkg \"wifi-firmware-%s-kmod-%s\"; return 1 ;;\n",
tolower($2), drv, tolower(n);
}' ${f}
done >> ${fwgetfile}
printf "INFO: fwget pci_network_realtek %s template at %s\n" ${DRIVER} ${fwgetfile} >&2
# end