1#!/bin/sh
2
3# Copyright (c) 2017 The DragonFly Project. All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9# Redistributions of source code must retain the above copyright notice,
10# this list of conditions and the following disclaimer.
11#
12# Redistributions in binary form must reproduce the above copyright
13# notice, this list of conditions and the following disclaimer in the
14# documentation and/or other materials provided with the distribution.
15#
16# Neither the name of The DragonFly Project nor the names of its
17# contributors may be used to endorse or promote products derived from
18# this software without specific, prior written permission.
19#
20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS
21# IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24# HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25# INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
29# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
30# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31# DAMAGE.
32
33# Prefixes for a files generated by parsing ISP driver C header file
34# with firmware. For their meaning see the parse_isp_firmware_header()
35# function info.
36license_file="license"
37name_file="name_"
38info_file="info_"
39data_file="data_"
40# Prefix for a binary file for firmware binary data. The binary file
41# contains output of sh execution of printf commands in "data_N" file.
42binary_file="binary_"
43# Suffix for output files which this script produces
44firmware_suffix=".fw.uu"
45# This string (and a number) will be added to the names of the other
46# variants of one firmware to form a unique filenames for the script
47# output files
48variant_string="_variant_"
49
50# Function usage: parse_isp_firmware_header FILE
51#
52#    FILE - Path to ISP driver C header file with firmware data.
53#
54# Result of this function are files containing parts of the header
55# file and generated sh commands. One header file can contain multiple
56# firmware images. Because of that, each file which contains image
57# specific info has a number N appended to its name. N is integer
58# number starting from 0. Files with the same N belongs to the same
59# firmware image.
60#
61#    license - Firmware license.
62#    name_N  - Image name. This will be the name of the final firmware .uu file.
63#    info_N  - Comment blocks with info about firmware image.
64#    data_N  - Printf calls that convert image words hex numbers to their
65#              values. This file is intended to be executed by sh and the stdout
66#              to be redirected to a file.
67#
68# NOTE: Resulting image words values will be in little-endian format.
69parse_isp_firmware_header()
70{
71    awk '
72# This function converts chars from "a" to "f" to decimal numbers from
73# 10 to 15 respectively. Every other character is returned as is.
74# Parameters "chars" and "char_array" are local variables.
75function hex_alpha_to_dec(a, chars, char_array) {
76  chars = "a,b,c,d,e,f"
77  split(chars, char_array, ",")
78
79  if (a ~ /[abcdef]/) {
80     for (j = 1; ; ++j) {
81       if (char_array[j] == a) {
82         return (10 + j - 1)
83       }
84     }
85  } else {
86    return a
87  }
88}
89
90# This function converts two-digit hex number to decimal number.
91# The input hex number is without "0x" prefix and "h" suffix.
92# Parameters "a" and "b" are local variables.
93function hex_to_dec(h, a, b) {
94  h = tolower(h)
95  a = hex_alpha_to_dec(substr(h, 1, 1))
96  b = hex_alpha_to_dec(substr(h, 2, 1))
97  return ((a * 16) + b)
98}
99
100BEGIN {
101  state = "license"
102  license_file = "'"${license_file}"'"
103  name_file = "'"${name_file}"'"
104  info_file = "'"${info_file}"'"
105  data_file = "'"${data_file}"'"
106  image_number = 0
107}
108
109# Filter out file information line(s) (file path, version, date, author, ...)
110/^\/\* \$.*\$ \*\// {
111  next
112}
113
114# Print the first line of the license contained in one comment block
115(state == "license") && /\/\*/ {
116  print $0 > license_file
117  state = "inside_license"
118  next
119}
120
121# Print the last line of the license contained in one comment block
122(state == "inside_license") && /\*\// {
123  print $0 > license_file
124  # License has been read, process comment blocks which contains info
125  # about the next firmware
126  state = "info"
127  next
128}
129
130# Print lines inside the license comment block
131(state == "inside_license") {
132  print $0 > license_file
133  next
134}
135
136# Print info text of the next firmware contained in one comment block
137(state == "info") && /\/\*/,/\*\// {
138  out = sprintf("%s%s", info_file, image_number);
139  print $0 > out
140  next
141}
142
143# Process array declaration line, get the name of the firmware and data type of
144# array values
145/\[\] = \{/ {
146  state = "array"
147  split($0, decl)
148  split(decl[4], name, "_risc_code")
149  array_name = name[1]
150  array_type = decl[3]
151
152  if (array_type ~ /int16/) {
153    # Data type of the array values is 16-bit
154    state = "data16"
155  } else {
156    # Data type of the array values is 32-bit
157    state = "data32"
158  }
159  # Save the firmware name
160  out = sprintf("%s%s", name_file, image_number);
161  printf "%s", array_name > out
162  next
163}
164
165# Current array has ended, process the next one
166((state == "data16") || ((state == "data32"))) && /\}/ {
167  state = "info"
168  image_number++
169  next
170}
171
172# Process one line of array content definition
173# Generate shell printf calls for the array values
174(state == "data16") || (state == "data32") {
175  gsub("[ \t]", "", $0)
176  split($0, values, ",")
177
178  for (i = 1; length(values[i]) > 0; ++i) {
179     # Get the single bytes
180     a = substr(values[i], 3, 2)
181     b = substr(values[i], 5, 2)
182     if (state == "data32") {
183       c = substr(values[i], 7, 2)
184       d = substr(values[i], 9, 2)
185     }
186     # POSIX printf needs the number to be in octal format in the escape
187     # sequence
188     # Swap the bytes to be in little-endian format
189     v = ""
190     if (state == "data32") {
191       v = "\\" sprintf("%o", hex_to_dec(d)) "\\" sprintf("%o", hex_to_dec(c))
192     }
193     v = v "\\" sprintf("%o", hex_to_dec(b)) "\\" sprintf("%o", hex_to_dec(a))
194     out = sprintf("%s%s", data_file, image_number);
195     printf "printf \"%s\"\n", v > out
196  }
197  next
198}
199' "$1"
200}
201
202# Check input file and its existence
203if [ $# -ne 1 ]; then
204    printf "Usage: $0 HEADER_FILE\n" >&2
205    exit 1
206elif [ ! -f "$1" ]; then
207    printf "Error: file '$1' does not exists\n" >&2
208    exit 1
209fi
210
211parse_isp_firmware_header "$1"
212
213# Concatenate the files to form a firmware .uu files
214image_number=0
215
216while [ -f "${name_file}${image_number}" ]; do
217    output_file="$(cat ${name_file}${image_number})"
218    # Some ISP firmware header files (asm_2100.h) contains more
219    # variants of the same firmware image. Append _var_M to the second
220    # and the following image's names, where 1 <= M. Name of the first
221    # image in the header file will get nothing appended.
222    if [ -f "${output_file}${firmware_suffix}" ]; then
223	# Find unused variant number
224	variant_number=1
225	tmp_name="${output_file}${variant_string}${variant_number}"
226	while [ -f "$tmp_name" ];do
227	    variant_number=$((variant_number + 1))
228	    tmp_name="${output_file}${variant_string}${variant_number}"
229	done
230	# Add the suffix
231	output_file="$tmp_name"
232    fi
233    output_file="${output_file}${firmware_suffix}"
234
235    # Add the license
236    cat "$license_file" > "$output_file"
237    # Add the firmware information if it exists
238    [ -f "${info_file}${image_number}" ] && \
239        cat "${info_file}${image_number}" >> "$output_file"
240    # Generate firmware binary data
241    cat "${data_file}${image_number}" | sh > "${binary_file}${image_number}"
242    # uuencode the data and add it to the output file
243    uuencode "${binary_file}${image_number}" \
244             "${binary_file}${image_number}" >> "$output_file"
245
246    image_number=$((image_number + 1))
247done
248
249# Remove temporary files generated by parsing the ISP driver C header
250# file with firmware data
251eval rm -f \"${license_file}\"\*  \
252     \"${name_file}\"\*  \
253     \"${info_file}\"\*  \
254     \"${data_file}\"\*  \
255     \"${binary_file}\"\*
256