Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/iwlwifi/zzz_fw_ports_fwget.sh
48253 views
1
#!/bin/sh
2
#-
3
# SPDX-License-Identifier: BSD-2-Clause
4
#
5
# Copyright (c) 2024-2025 The FreeBSD Foundation
6
#
7
# This software was developed by Björn Zeeb
8
# under sponsorship from the FreeBSD Foundation.
9
#
10
# This is neither efficient nor elegant but we need it few times
11
# a year and it does the job.
12
#
13
#
14
# USAGE: please check out the correct tag/hash for ports in the
15
# linux-firmware.git repository you point this script to.
16
#
17
# USAGE: please make sure to pre-load if_iwlwifi.ko so that we
18
# have access to the sysctl. You do not need to have a supported
19
# card in the system.
20
# In case that is not possible you can save the results to a file
21
# and provide that locally. It will be renamed at the end of the
22
# run.
23
#
24
25
set -e
26
27
# sysctl -n compat.linuxkpi.iwlwifi_pci_ids_name > iwlwifi_pci_ids_name.txt
28
PCI_IDS_FILE=iwlwifi_pci_ids_name.txt
29
D_PCI_IDS_FILE=`pwd`/${PCI_IDS_FILE}
30
31
################################################################################
32
#
33
# Check pre-reqs
34
#
35
if [ $# -ne 1 ]; then
36
printf "USAGE: %s /path/to/linux-firmware.git\n" $0 >&2
37
exit 1
38
fi
39
40
if [ ! -d cfg/ -o ! -e cfg/bz.c ]; then
41
printf "ERROR: run from iwlwifi driver directory; no cfg/bz.c here\n" >&2
42
exit 1
43
fi
44
45
LFWDIR=${1}
46
if test ! -d ${LFWDIR} -o ! -e ${LFWDIR}/WHENCE; then
47
printf "ERROR: cannot find linux-firmware.git at '%s'\n" ${LFWDIR} >&2
48
exit 1
49
fi
50
51
if test -r ${D_PCI_IDS_FILE}; then
52
printf "NOTICE: using proovided ${D_PCI_IDS_FILE}\n" >&2
53
else
54
55
kldstat -n if_iwlwifi.ko > /dev/null 2>&1
56
rc=$?
57
case ${rc} in
58
0) ;;
59
*) printf "ERROR: please pre-load if_iwlwifi.ko (you do not need a device)\n" >&2
60
exit 1
61
;;
62
esac
63
64
sysctl -N compat.linuxkpi.iwlwifi_pci_ids_name > /dev/null 2>&1
65
rc=$?
66
case ${rc} in
67
0) sysctl -n compat.linuxkpi.iwlwifi_pci_ids_name > ${D_PCI_IDS_FILE}
68
;;
69
*) printf "ERROR: cannot get compat.linuxkpi.iwlwifi_pci_ids_name\n" >&2
70
exit 1
71
;;
72
esac
73
fi
74
75
# We need to be in the config directory for simplicity.
76
cd cfg
77
78
################################################################################
79
80
# Get a list of all device/firmware flavors as seen/supported by the driver.
81
flavors=$(awk -F\\t '{
82
if (/^$/) { next; }
83
if ($5 == "undefined") { next; }
84
print tolower($5);
85
}' ${D_PCI_IDS_FILE} | sort -V | uniq)
86
87
################################################################################
88
#
89
# Helper functions.
90
#
91
92
#
93
# This uses a hack (cpp) to expand some macros for us and parses out the result
94
# which is the firmware name with the maximum FW version supported for that
95
# firmware.
96
# We then go and check that said firmware actually exists in linux-firmware.git.
97
# We try to find a lower version number if the "MAX" version given from the cpp
98
# output does not (yet) publicly exist.
99
# .pnvm files are now properly listed as MODULE_FIRMWARE so no more magic needed
100
# for them.
101
# Given the filename matches a "flavor" at this point, we then group all the
102
# available firmware files from this flavor together and print it as a ports
103
# Makefile variable.
104
#
105
# We also print some other meta-data that callers will filter out depending on
106
# their needs to generate other lists and mappings.
107
#
108
109
# For each get a list of firmware names we know.
110
list_fw()
111
{
112
for f in ${flavors}; do
113
#echo "==> ${f}"
114
#awk -F \\t -v flav=${f} '{
115
# if ($5 != flav) { next; }
116
# # No firmwre; skip.
117
# if ($3 ~ /^$/) { next; }
118
# if ($3 == "(null)") { next; };
119
# print $3;
120
#}' ${D_PCI_IDS_FILE} | sort | uniq
121
122
# For now the flavor names and the file names are 1:1 which makes this
123
# a lot easier (given some sysctl/file entries are not able to list
124
# their firmware but we know their "flavor".
125
l=$(cpp ${f}.c 2>&1 | awk '
126
/^MODULE_FIRMWARE\(/ {
127
gsub(/"/, "");
128
gsub("__stringify\\(", "");
129
gsub("\\);$", "");
130
gsub("\\)", "");
131
gsub("^MODULE_FIRMWARE\\(", "");
132
gsub(" ", "");
133
printf "%s\n", $0;
134
}' | sort -V | uniq)
135
#echo "${l}"
136
137
lx=""
138
for fx in ${l}; do
139
if test -e ${LFWDIR}/${fx}; then
140
lx="${lx} ${fx}"
141
142
# Check for matching .pnvm file.
143
# They are now properly listed in MODULE_FIRMWARE() as well so no more magic.
144
#px=$(echo ${fx} | awk '{ gsub("-[[:digit:]]*.ucode", ".pnvm"); print; }')
145
#if test -e ${LFWDIR}/${px}; then
146
# lx="${lx} ${px}"
147
#fi
148
else
149
case "${fx}" in
150
*.pnvm)
151
printf "NOTICE: pnvm file not found for '%s'\n" ${fx} >&2
152
;;
153
*.ucode)
154
# Try lowering the version number.
155
bn=$(echo ${fx} | awk '{ gsub("-[[:digit:]]*.ucode", ""); print; }')
156
vn=$(echo ${fx} | awk '{ gsub(".ucode$", ""); gsub("^.*-", ""); print; }')
157
#echo "BN ${bn} VN ${vn}"
158
# Single digits are not zero-padded so just ${i} will be fine.
159
for i in `jot ${vn} ${vn} 1`; do
160
xn="${bn}-${i}.ucode"
161
if test -e ${LFWDIR}/${xn}; then
162
lx="${lx} ${xn}"
163
break
164
fi
165
done
166
;;
167
*)
168
printf "NOTICE: file for unknown firmware type not found for '%s'\n" ${fx} >&2
169
;;
170
esac
171
fi
172
done
173
174
# Get a count so we can automatically add \\ apart from the last line.
175
fn=$(echo "${lx}" | wc -w | awk '{ print $1 }')
176
177
#echo "==> ${f} :: ${fn} :: ${lx}"
178
179
if test ${fn} -gt 0; then
180
181
# Ports FLAVOR names are [a-z0-9_]. If needed add more mangling magic here.
182
flav=`echo ${f} | awk '{ printf "%s", tolower($0); }'`
183
184
echo "FWS ${flav}"
185
echo "DISTFILES_${flav}= \\"
186
for fz in ${lx}; do echo "${fz}"; done | \
187
awk -v fn=$fn -v fwg=${flav} '{
188
if (FNR == fn) { x="" } else { x=" \\" };
189
printf "\t%s${DISTURL_SUFFIX}%s\n", $0, x;
190
fwn=$0;
191
gsub("-[[:digit:]]*\.ucode$", "", fwn);
192
printf "FWGET %s %s\n", fwg, fwn;
193
}'
194
fi
195
196
done
197
}
198
199
################################################################################
200
#
201
# Generate the PORTS file template.
202
#
203
204
fwsl=$(list_fw | grep ^FWS | awk '{ print $2 }')
205
# Get a count so we can automatically add \\ apart from the last line.
206
fn=$(echo "${fwsl}" | wc -w | awk '{ print $1 }')
207
208
if test ${fn} -gt 0; then
209
210
portsfile=$(mktemp -p /tmp iwlwifi-fwport.XXXXXX)
211
212
:> ${portsfile}
213
(
214
echo "FWSUBS= \\"
215
for sz in ${fwsl}; do echo "${sz}"; done | \
216
awk -v fn=$fn '{ if (FNR == fn) { x="" } else { x=" \\" }; printf "\t%s%s\n", $0, x; }'
217
218
echo
219
echo "# Do not prefix with empty \${FWSUBDIR}/!"
220
list_fw | grep -v ^FWS | grep -v ^FWGET
221
222
echo
223
echo "DISTFILES_\${FWDRV}= \\"
224
for sz in ${fwsl}; do echo "${sz}"; done | \
225
awk -v fn=$fn '{ if (FNR == fn) { x="" } else { x=" \\" }; printf "\t${DISTFILES_%s}%s\n", $0, x; }'
226
echo "DISTFILES_\${FWDRV}_lic="
227
) >> ${portsfile}
228
229
printf "INFO: wifi-firmware-iwlwifi-kmod template at %s\n" ${portsfile} >&2
230
fi
231
232
################################################################################
233
#
234
# Generate a temporary firmware -> flavor mapping table for fwget generation.
235
#
236
237
mapfile=$(mktemp -p /tmp iwlwifi-mapfile.XXXXXX)
238
:> ${mapfile}
239
240
fwgl=$(list_fw | grep FWGET)
241
# Get a count so we can automatically add \\ apart from the last line.
242
fn=$(echo "${fwgl}" | wc -w | awk '{ print $1 }')
243
if test ${fn} -gt 0; then
244
245
(
246
list_fw | grep FWGET | grep -v '.pnvm' | \
247
while read x flav fw; do
248
printf "%s\t%s\n" ${fw} ${flav}
249
done | \
250
sort -n | uniq
251
) >> ${mapfile}
252
fi
253
254
################################################################################
255
#
256
# Try to generate the PCI ID -> port flavor mapping
257
#
258
# We get PCI ID, description, firmware base from the sysctl and can work our
259
# way back from fw name base to flavor via the mapping table file.
260
#
261
262
fwgetfile=$(mktemp -p /tmp iwlwifi-fwget.XXXXXX)
263
:> ${fwgetfile}
264
265
awk 'BEGIN { FS="\t"; }
266
{
267
# Skip empty lines.
268
if (/^$/) { next; }
269
# Skip "undefined" flavors as we have no idea what chipset.
270
if ($5 == "undefined") { next; }
271
272
# No firmware name; do not skip!
273
# All we need is the flavor, which we now always have.
274
#if ($3 == "(null)") { next; };
275
276
FLAV=tolower($5);
277
278
split($1, i, "/");
279
gsub("\t.*$", "", i[4]);
280
281
# Not an Intel Vednor ID; skip.
282
if (i[1] != "0x8086") { next; };
283
284
# No defined device ID; skip.
285
if (i[2] == "0xffff") { next; };
286
287
# Adjust wildcards or a ill-printed 0.
288
if (i[3] == "0xffffffff") { i[3] = "*"; };
289
if (i[4] == "000000") { i[4] = "0x0000"; };
290
if (i[4] == "0xffffffff") { i[4] = "*"; };
291
if (i[4] == "0xffff") { i[4] = "*"; };
292
293
printf "%s\t%s/%s/%s\n", FLAV, i[2], i[3], i[4];
294
}' ${D_PCI_IDS_FILE} | \
295
sort -V | uniq | \
296
while read flav match; do
297
298
#flav=$(awk -v fw=$fw '{ if ($1 == fw) { print $2; } }' ${mapfile})
299
#echo "${fw} :: ${match} :: ${flav}"
300
301
if test "${flav}" != ""; then
302
printf "${flav}\t${match}\t${flav}\n"
303
else
304
#echo "NO FLAV ${fw} ${match}" >&2
305
fi
306
307
done | \
308
awk 'BEGIN { FS="\t"; FWN=""; }
309
{
310
FW=$1;
311
if (FWN != FW) { printf "\n\t# %s\n", FW; FWN=FW; };
312
313
printf "\t%s) addpkg \"wifi-firmware-iwlwifi-kmod-%s\"; return 1 ;;\n", $2, $3;
314
} END {
315
printf "\n";
316
}' >> ${fwgetfile}
317
318
printf "INFO: fwget pci_network_intel template at %s\n" ${fwgetfile} >&2
319
320
################################################################################
321
#
322
# Try to build the iwlwififw.4 bits too.
323
#
324
325
dl=$(grep -v ^$ ${D_PCI_IDS_FILE} | uniq | \
326
awk '
327
{
328
# Sourt out duplicate lines.
329
if (dup[$0]++) { next; }
330
331
split($0, a, "\t");
332
ids=a[1];
333
name=a[2];
334
fw=a[3];
335
flavor=a[5];
336
337
#my ($v, $d, $sv, $sd) = split("/", $ids);
338
split(ids, i, "/");
339
gsub("^0xffff+", "any", i[1]);
340
gsub("^0xffff+", "any", i[2]);
341
gsub("^0xffff+", "any", i[3]);
342
gsub("^0xffff+", "any", i[4]);
343
344
if (name == "") { name="(unknown)"; }
345
if (fw == "") { fw="(unknown)"; }
346
if (flavor == "") { flavor="iwlwifi"; }
347
if (flavor == "undefined") { flavor="iwlwifi"; }
348
349
# iwlwififw.4
350
printf ".It \"\"\n.It %s\n.It %s Ta %s Ta %s Ta %s Ta %s Ta %s\n", name, i[1], i[2], i[3], i[4], flavor, fw;
351
352
# wiki
353
# XXX TODO possibly quote some in `` to avoid automatic linking?
354
# || PCI IDs || Chipset Name || Firmware prefix || Comment ||
355
printf "WIKI || %s / %s / %s / %s || %s || %s || ||\n", i[1], i[2], i[3], i[4], name, fw;
356
if ((FNR % 25) == 0) { printf "WIKI \n"; }
357
}')
358
359
manfwfile=$(mktemp -p /tmp iwlwifi-iwlwififw4.XXXXXX)
360
:> ${manfwfile}
361
echo "${dl}" | grep -v ^WIKI >> ${manfwfile}
362
printf "INFO: share/man/man4/iwlwififw.4 template at %s\n" ${manfwfile} >&2
363
364
wikifile=$(mktemp -p /tmp iwlwifi-wiki.XXXXXX)
365
:> ${wikifile}
366
echo "${dl}" | awk '/^WIKI / { gsub("^WIKI ", ""); print; }' >> ${wikifile}
367
printf "INFO: WIKI template at %s\n" ${wikifile} >&2
368
369
370
################################################################################
371
#
372
# Cleanup
373
#
374
rm ${mapfile}
375
mv -f ${D_PCI_IDS_FILE} ${D_PCI_IDS_FILE}.old
376
377
# end
378
379