Merge branch 'vendor/DHCPCD'
[dragonfly.git] / tools / tools / firmware / fw_convert_ispfw.sh
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.
36 license_file="license"
37 name_file="name_"
38 info_file="info_"
39 data_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.
42 binary_file="binary_"
43 # Suffix for output files which this script produces
44 firmware_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
48 variant_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.
69 parse_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.
75 function 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.
93 function 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
100 BEGIN {
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
203 if [ $# -ne 1 ]; then
204     printf "Usage: $0 HEADER_FILE\n" >&2
205     exit 1
206 elif [ ! -f "$1" ]; then
207     printf "Error: file '$1' does not exists\n" >&2
208     exit 1
209 fi
210
211 parse_isp_firmware_header "$1"
212
213 # Concatenate the files to form a firmware .uu files
214 image_number=0
215
216 while [ -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))
247 done
248
249 # Remove temporary files generated by parsing the ISP driver C header
250 # file with firmware data
251 eval rm -f \"${license_file}\"\*  \
252      \"${name_file}\"\*  \
253      \"${info_file}\"\*  \
254      \"${data_file}\"\*  \
255      \"${binary_file}\"\*