fw_stub.awk revision 198277
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: head/sys/tools/fw_stub.awk 198277 2009-10-20 11:54:06Z fjoe $
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
124154974Smlaierprintc("#include <sys/param.h>\
125154974Smlaier#include <sys/errno.h>\
126154974Smlaier#include <sys/kernel.h>\
127154974Smlaier#include <sys/module.h>\
128154974Smlaier#include <sys/linker.h>\
129167165Sflz#include <sys/firmware.h>\
130167165Sflz#include <sys/systm.h>\n");
131154974Smlaier
132167165Sflzif (opt_l) {
133167165Sflz	printc("static long " opt_l "_license_ack = 0;");
134167165Sflz}
135167165Sflz
136154974Smlaierfor (file_i = 0; file_i < num_files; file_i++) {
137154974Smlaier	symb = filenames[file_i];
138154974Smlaier	# '-', '.' and '/' are converted to '_' by ld/objcopy
139154974Smlaier	gsub(/-|\.|\//, "_", symb);
140154974Smlaier	printc("extern char _binary_" symb "_start[], _binary_" symb "_end[];");
141154974Smlaier}
142154974Smlaier
143154974Smlaierprintc("\nstatic int\n"\
144198277Sfjoemodname "_fw_modevent(module_t mod, int type, void *unused)\
145154974Smlaier{\
146166756Sluigi	const struct firmware *fp, *parent;\
147159670Sjhb	int error;\
148154974Smlaier	switch (type) {\
149167165Sflz	case MOD_LOAD:\n");
150154974Smlaier
151167165Sflzif (opt_l) {
152167165Sflz		printc("\
153167165Sflz		TUNABLE_LONG_FETCH(\"legal." opt_l ".license_ack\", &" opt_l "_license_ack);\
154167165Sflz		if (!" opt_l "_license_ack) {\
155167165Sflz			printf(\"" opt_m ": You need to read the LICENSE file in /usr/share/doc/legal/" opt_l "/.\\n\");\
156167165Sflz			printf(\"" opt_m ": If you agree with the license, set legal." opt_l ".license_ack=1 in /boot/loader.conf.\\n\");\
157167165Sflz			return(EPERM);\
158167165Sflz		}\n");
159167165Sflz}
160167165Sflz
161154974Smlaierfor (file_i = 0; file_i < num_files; file_i++) {
162154974Smlaier	short = shortnames[file_i];
163154974Smlaier	symb = filenames[file_i];
164154974Smlaier	version = versions[file_i];
165154974Smlaier	# '-', '.' and '/' are converted to '_' by ld/objcopy
166154974Smlaier	gsub(/-|\.|\//, "_", symb);
167154974Smlaier
168159670Sjhb	reg = "\t\tfp = ";
169154974Smlaier	reg = reg "firmware_register(\"" short "\", _binary_" symb "_start , ";
170154974Smlaier	reg = reg "(size_t)(_binary_" symb "_end - _binary_" symb "_start), ";
171154974Smlaier	reg = reg version ", ";
172154974Smlaier
173154974Smlaier	if (file_i == 0)
174154974Smlaier		reg = reg "NULL);";
175154974Smlaier	else
176159670Sjhb		reg = reg "parent);";
177154974Smlaier
178154974Smlaier	printc(reg);
179159670Sjhb
180159670Sjhb	printc("\t\tif (fp == NULL)");
181159670Sjhb	printc("\t\t\tgoto fail_" file_i ";");
182159670Sjhb	if (file_i == 0)
183159670Sjhb		printc("\t\tparent = fp;");
184154974Smlaier}
185154974Smlaier
186159670Sjhbprintc("\t\treturn (0);");
187154974Smlaier
188159670Sjhbfor (file_i = num_files - 1; file_i > 0; file_i--) {
189167165Sflz	printc("fail_" file_i ":")
190159670Sjhb	printc("\t\t(void)firmware_unregister(\"" shortnames[file_i - 1] "\");");
191159670Sjhb}
192159670Sjhb
193159670Sjhbprintc("\tfail_0:");
194159670Sjhbprintc("\t\treturn (ENXIO);");
195159670Sjhb
196159670Sjhbprintc("\tcase MOD_UNLOAD:");
197159670Sjhb
198154974Smlaierfor (file_i = 1; file_i < num_files; file_i++) {
199159670Sjhb	printc("\t\terror = firmware_unregister(\"" shortnames[file_i] "\");");
200159670Sjhb	printc("\t\tif (error)");
201159670Sjhb	printc("\t\t\treturn (error);");
202154974Smlaier}
203154974Smlaier
204159670Sjhbprintc("\t\terror = firmware_unregister(\"" shortnames[0] "\");");
205154974Smlaier
206159670Sjhbprintc("\t\treturn (error);\
207154974Smlaier	}\
208154974Smlaier	return (EINVAL);\
209154974Smlaier}\
210154974Smlaier\
211198277Sfjoestatic moduledata_t " modname "_fw_mod = {\
212198277Sfjoe        \"" modname "_fw\",\
213198277Sfjoe        " modname "_fw_modevent,\
214154974Smlaier        0\
215154974Smlaier};\
216198277SfjoeDECLARE_MODULE(" modname "_fw, " modname "_fw_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);\
217198277SfjoeMODULE_VERSION(" modname "_fw, 1);\
218198277SfjoeMODULE_DEPEND(" modname "_fw, firmware, 1, 1, 1);\
219154974Smlaier");
220154974Smlaier
221154974Smlaierif (opt_c)
222154974Smlaier	if ((rc = system("mv -f " ctmpfilename " " cfilename))) {
223154974Smlaier		print "'mv -f " ctmpfilename " " cfilename "' failed: " rc \
224154974Smlaier		    > "/dev/stderr";
225154974Smlaier		exit 1;
226154974Smlaier	}
227154974Smlaier
228154974Smlaierexit 0;
229154974Smlaier
230154974Smlaier}
231