1154974Smlaier#!/usr/bin/awk -f
2154974Smlaier
3154974Smlaier#-
4154974Smlaier# Copyright (c) 2006 Max Laier.
5154974Smlaier# All rights reserved.
6154974Smlaier#
7154974Smlaier# Redistribution and use in source and binary forms, with or without
8154974Smlaier# modification, are permitted provided that the following conditions
9154974Smlaier# are met:
10154974Smlaier# 1. Redistributions of source code must retain the above copyright
11154974Smlaier#    notice, this list of conditions and the following disclaimer.
12154974Smlaier# 2. Redistributions in binary form must reproduce the above copyright
13154974Smlaier#    notice, this list of conditions and the following disclaimer in the
14154974Smlaier#    documentation and/or other materials provided with the distribution.
15154974Smlaier#
16154974Smlaier# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS'' AND
17154974Smlaier# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18154974Smlaier# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19154974Smlaier# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20154974Smlaier# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21154974Smlaier# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22154974Smlaier# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23154974Smlaier# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24154974Smlaier# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25154974Smlaier# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26154974Smlaier# SUCH DAMAGE.
27154974Smlaier#
28154974Smlaier# $FreeBSD$
29154974Smlaier
30154974Smlaier#
31154974Smlaier# Script to generate module .c file from a list of firmware images
32154974Smlaier#
33154974Smlaier
34154974Smlaierfunction usage ()
35154974Smlaier{
36167165Sflz	print "usage: fw_stub <firmware:name>* [-l name] [-m modname] [-c outfile]";
37154974Smlaier	exit 1;
38154974Smlaier}
39154974Smlaier
40154974Smlaier#   These are just for convenience ...
41154974Smlaierfunction printc(s)
42154974Smlaier{
43154974Smlaier	if (opt_c)
44154974Smlaier		print s > ctmpfilename;
45154974Smlaier	else
46154974Smlaier		print s > "/dev/stdout";
47154974Smlaier}
48154974Smlaier
49154974SmlaierBEGIN {
50154974Smlaier
51154974Smlaier#
52154974Smlaier#   Process the command line.
53154974Smlaier#
54154974Smlaier
55154974Smlaiernum_files = 0;
56154974Smlaier
57154974Smlaierfor (i = 1; i < ARGC; i++) {
58154974Smlaier	if (ARGV[i] ~ /^-/) {
59154974Smlaier		#
60154974Smlaier		#   awk doesn't have getopt(), so we have to do it ourselves.
61154974Smlaier		#   This is a bit clumsy, but it works.
62154974Smlaier		#
63154974Smlaier		for (j = 2; j <= length(ARGV[i]); j++) {
64154974Smlaier			o = substr(ARGV[i], j, 1);
65154974Smlaier			if (o == "c") {
66154974Smlaier				if (length(ARGV[i]) > j) {
67154974Smlaier					opt_c = substr(ARGV[i], j + 1);
68154974Smlaier					break;
69154974Smlaier				}
70154974Smlaier				else {
71154974Smlaier					if (++i < ARGC)
72154974Smlaier						opt_c = ARGV[i];
73154974Smlaier					else
74154974Smlaier						usage();
75154974Smlaier				}
76154974Smlaier			} else if (o == "m") {
77154974Smlaier				if (length(ARGV[i]) > j) {
78154974Smlaier					opt_m = substr(ARGV[i], j + 1);
79154974Smlaier					break;
80154974Smlaier				}
81154974Smlaier				else {
82154974Smlaier					if (++i < ARGC)
83154974Smlaier						opt_m = ARGV[i];
84154974Smlaier					else
85154974Smlaier						usage();
86154974Smlaier				}
87167165Sflz			} else if (o == "l") {
88167165Sflz				if (length(ARGV[i]) > j) {
89167165Sflz					opt_l = substr(ARGV[i], j + 1);
90167165Sflz					break;
91167165Sflz				}
92167165Sflz				else {
93167165Sflz					if (++i < ARGC)
94167165Sflz						opt_l = ARGV[i];
95167165Sflz					else
96167165Sflz						usage();
97167165Sflz				}
98154974Smlaier			} else
99154974Smlaier				usage();
100154974Smlaier		}
101154974Smlaier	} else {
102154974Smlaier		split(ARGV[i], curr, ":");
103154974Smlaier		filenames[num_files] = curr[1];
104154974Smlaier		if (length(curr[2]) > 0)
105154974Smlaier			shortnames[num_files] = curr[2];
106154974Smlaier		else
107167077Sflz			shortnames[num_files] = curr[1];
108154974Smlaier		if (length(curr[3]) > 0)
109154974Smlaier			versions[num_files] = int(curr[3]);
110154974Smlaier		else
111154974Smlaier			versions[num_files] = 0;
112154974Smlaier		num_files++;
113154974Smlaier	}
114154974Smlaier}
115154974Smlaier
116154974Smlaierif (!num_files || !opt_m)
117154974Smlaier	usage();
118154974Smlaier
119154974Smlaiercfilename = opt_c;
120154974Smlaierctmpfilename = cfilename ".tmp";
121198277Sfjoemodname = opt_m;
122198277Sfjoegsub(/[-\.]/, "_", modname);
123154974Smlaier
124198466Srpauloprintc("/*\
125198466Srpaulo * Automatically generated by:\
126198466Srpaulo * $FreeBSD$\
127220227Srstone */");
128220227Srstoneprintc("#include <sys/param.h>");
129220227Srstoneprintc("#include <sys/errno.h>");
130220227Srstoneprintc("#include <sys/kernel.h>");
131220227Srstoneprintc("#include <sys/module.h>");
132220227Srstoneprintc("#include <sys/linker.h>");
133220227Srstoneprintc("#include <sys/firmware.h>");
134220227Srstoneprintc("#include <sys/systm.h>\n");
135154974Smlaier
136167165Sflzif (opt_l) {
137167165Sflz	printc("static long " opt_l "_license_ack = 0;");
138167165Sflz}
139167165Sflz
140154974Smlaierfor (file_i = 0; file_i < num_files; file_i++) {
141154974Smlaier	symb = filenames[file_i];
142154974Smlaier	# '-', '.' and '/' are converted to '_' by ld/objcopy
143154974Smlaier	gsub(/-|\.|\//, "_", symb);
144154974Smlaier	printc("extern char _binary_" symb "_start[], _binary_" symb "_end[];");
145154974Smlaier}
146154974Smlaier
147154974Smlaierprintc("\nstatic int\n"\
148198277Sfjoemodname "_fw_modevent(module_t mod, int type, void *unused)\
149154974Smlaier{\
150166756Sluigi	const struct firmware *fp, *parent;\
151159670Sjhb	int error;\
152154974Smlaier	switch (type) {\
153167165Sflz	case MOD_LOAD:\n");
154154974Smlaier
155167165Sflzif (opt_l) {
156167165Sflz		printc("\
157167165Sflz		TUNABLE_LONG_FETCH(\"legal." opt_l ".license_ack\", &" opt_l "_license_ack);\
158167165Sflz		if (!" opt_l "_license_ack) {\
159167165Sflz			printf(\"" opt_m ": You need to read the LICENSE file in /usr/share/doc/legal/" opt_l "/.\\n\");\
160167165Sflz			printf(\"" opt_m ": If you agree with the license, set legal." opt_l ".license_ack=1 in /boot/loader.conf.\\n\");\
161167165Sflz			return(EPERM);\
162167165Sflz		}\n");
163167165Sflz}
164167165Sflz
165154974Smlaierfor (file_i = 0; file_i < num_files; file_i++) {
166154974Smlaier	short = shortnames[file_i];
167154974Smlaier	symb = filenames[file_i];
168154974Smlaier	version = versions[file_i];
169154974Smlaier	# '-', '.' and '/' are converted to '_' by ld/objcopy
170154974Smlaier	gsub(/-|\.|\//, "_", symb);
171154974Smlaier
172159670Sjhb	reg = "\t\tfp = ";
173154974Smlaier	reg = reg "firmware_register(\"" short "\", _binary_" symb "_start , ";
174154974Smlaier	reg = reg "(size_t)(_binary_" symb "_end - _binary_" symb "_start), ";
175154974Smlaier	reg = reg version ", ";
176154974Smlaier
177154974Smlaier	if (file_i == 0)
178154974Smlaier		reg = reg "NULL);";
179154974Smlaier	else
180159670Sjhb		reg = reg "parent);";
181154974Smlaier
182154974Smlaier	printc(reg);
183159670Sjhb
184159670Sjhb	printc("\t\tif (fp == NULL)");
185159670Sjhb	printc("\t\t\tgoto fail_" file_i ";");
186159670Sjhb	if (file_i == 0)
187159670Sjhb		printc("\t\tparent = fp;");
188154974Smlaier}
189154974Smlaier
190159670Sjhbprintc("\t\treturn (0);");
191154974Smlaier
192159670Sjhbfor (file_i = num_files - 1; file_i > 0; file_i--) {
193167165Sflz	printc("fail_" file_i ":")
194159670Sjhb	printc("\t\t(void)firmware_unregister(\"" shortnames[file_i - 1] "\");");
195159670Sjhb}
196159670Sjhb
197159670Sjhbprintc("\tfail_0:");
198159670Sjhbprintc("\t\treturn (ENXIO);");
199159670Sjhb
200159670Sjhbprintc("\tcase MOD_UNLOAD:");
201159670Sjhb
202154974Smlaierfor (file_i = 1; file_i < num_files; file_i++) {
203159670Sjhb	printc("\t\terror = firmware_unregister(\"" shortnames[file_i] "\");");
204159670Sjhb	printc("\t\tif (error)");
205159670Sjhb	printc("\t\t\treturn (error);");
206154974Smlaier}
207154974Smlaier
208159670Sjhbprintc("\t\terror = firmware_unregister(\"" shortnames[0] "\");");
209154974Smlaier
210159670Sjhbprintc("\t\treturn (error);\
211154974Smlaier	}\
212154974Smlaier	return (EINVAL);\
213154974Smlaier}\
214154974Smlaier\
215198277Sfjoestatic moduledata_t " modname "_fw_mod = {\
216198277Sfjoe        \"" modname "_fw\",\
217198277Sfjoe        " modname "_fw_modevent,\
218241394Skevlo        0\
219154974Smlaier};\
220198277SfjoeDECLARE_MODULE(" modname "_fw, " modname "_fw_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);\
221198277SfjoeMODULE_VERSION(" modname "_fw, 1);\
222198277SfjoeMODULE_DEPEND(" modname "_fw, firmware, 1, 1, 1);\
223154974Smlaier");
224154974Smlaier
225154974Smlaierif (opt_c)
226154974Smlaier	if ((rc = system("mv -f " ctmpfilename " " cfilename))) {
227154974Smlaier		print "'mv -f " ctmpfilename " " cfilename "' failed: " rc \
228154974Smlaier		    > "/dev/stderr";
229154974Smlaier		exit 1;
230154974Smlaier	}
231154974Smlaier
232154974Smlaierexit 0;
233154974Smlaier
234154974Smlaier}
235