#!/bin/sh # Copyright (c) 2017 The DragonFly Project. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # Neither the name of The DragonFly Project nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific, prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS # IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # Prefixes for a files generated by parsing ISP driver C header file # with firmware. For their meaning see the parse_isp_firmware_header() # function info. license_file="license" name_file="name_" info_file="info_" data_file="data_" # Prefix for a binary file for firmware binary data. The binary file # contains output of sh execution of printf commands in "data_N" file. binary_file="binary_" # Suffix for output files which this script produces firmware_suffix=".fw.uu" # This string (and a number) will be added to the names of the other # variants of one firmware to form a unique filenames for the script # output files variant_string="_variant_" # Function usage: parse_isp_firmware_header FILE # # FILE - Path to ISP driver C header file with firmware data. # # Result of this function are files containing parts of the header # file and generated sh commands. One header file can contain multiple # firmware images. Because of that, each file which contains image # specific info has a number N appended to its name. N is integer # number starting from 0. Files with the same N belongs to the same # firmware image. # # license - Firmware license. # name_N - Image name. This will be the name of the final firmware .uu file. # info_N - Comment blocks with info about firmware image. # data_N - Printf calls that convert image words hex numbers to their # values. This file is intended to be executed by sh and the stdout # to be redirected to a file. # # NOTE: Resulting image words values will be in little-endian format. parse_isp_firmware_header() { awk ' # This function converts chars from "a" to "f" to decimal numbers from # 10 to 15 respectively. Every other character is returned as is. # Parameters "chars" and "char_array" are local variables. function hex_alpha_to_dec(a, chars, char_array) { chars = "a,b,c,d,e,f" split(chars, char_array, ",") if (a ~ /[abcdef]/) { for (j = 1; ; ++j) { if (char_array[j] == a) { return (10 + j - 1) } } } else { return a } } # This function converts two-digit hex number to decimal number. # The input hex number is without "0x" prefix and "h" suffix. # Parameters "a" and "b" are local variables. function hex_to_dec(h, a, b) { h = tolower(h) a = hex_alpha_to_dec(substr(h, 1, 1)) b = hex_alpha_to_dec(substr(h, 2, 1)) return ((a * 16) + b) } BEGIN { state = "license" license_file = "'"${license_file}"'" name_file = "'"${name_file}"'" info_file = "'"${info_file}"'" data_file = "'"${data_file}"'" image_number = 0 } # Filter out file information line(s) (file path, version, date, author, ...) /^\/\* \$.*\$ \*\// { next } # Print the first line of the license contained in one comment block (state == "license") && /\/\*/ { print $0 > license_file state = "inside_license" next } # Print the last line of the license contained in one comment block (state == "inside_license") && /\*\// { print $0 > license_file # License has been read, process comment blocks which contains info # about the next firmware state = "info" next } # Print lines inside the license comment block (state == "inside_license") { print $0 > license_file next } # Print info text of the next firmware contained in one comment block (state == "info") && /\/\*/,/\*\// { out = sprintf("%s%s", info_file, image_number); print $0 > out next } # Process array declaration line, get the name of the firmware and data type of # array values /\[\] = \{/ { state = "array" split($0, decl) split(decl[4], name, "_risc_code") array_name = name[1] array_type = decl[3] if (array_type ~ /int16/) { # Data type of the array values is 16-bit state = "data16" } else { # Data type of the array values is 32-bit state = "data32" } # Save the firmware name out = sprintf("%s%s", name_file, image_number); printf "%s", array_name > out next } # Current array has ended, process the next one ((state == "data16") || ((state == "data32"))) && /\}/ { state = "info" image_number++ next } # Process one line of array content definition # Generate shell printf calls for the array values (state == "data16") || (state == "data32") { gsub("[ \t]", "", $0) split($0, values, ",") for (i = 1; length(values[i]) > 0; ++i) { # Get the single bytes a = substr(values[i], 3, 2) b = substr(values[i], 5, 2) if (state == "data32") { c = substr(values[i], 7, 2) d = substr(values[i], 9, 2) } # POSIX printf needs the number to be in octal format in the escape # sequence # Swap the bytes to be in little-endian format v = "" if (state == "data32") { v = "\\" sprintf("%o", hex_to_dec(d)) "\\" sprintf("%o", hex_to_dec(c)) } v = v "\\" sprintf("%o", hex_to_dec(b)) "\\" sprintf("%o", hex_to_dec(a)) out = sprintf("%s%s", data_file, image_number); printf "printf \"%s\"\n", v > out } next } ' "$1" } # Check input file and its existence if [ $# -ne 1 ]; then printf "Usage: $0 HEADER_FILE\n" >&2 exit 1 elif [ ! -f "$1" ]; then printf "Error: file '$1' does not exists\n" >&2 exit 1 fi parse_isp_firmware_header "$1" # Concatenate the files to form a firmware .uu files image_number=0 while [ -f "${name_file}${image_number}" ]; do output_file="$(cat ${name_file}${image_number})" # Some ISP firmware header files (asm_2100.h) contains more # variants of the same firmware image. Append _var_M to the second # and the following image's names, where 1 <= M. Name of the first # image in the header file will get nothing appended. if [ -f "${output_file}${firmware_suffix}" ]; then # Find unused variant number variant_number=1 tmp_name="${output_file}${variant_string}${variant_number}" while [ -f "$tmp_name" ];do variant_number=$((variant_number + 1)) tmp_name="${output_file}${variant_string}${variant_number}" done # Add the suffix output_file="$tmp_name" fi output_file="${output_file}${firmware_suffix}" # Add the license cat "$license_file" > "$output_file" # Add the firmware information if it exists [ -f "${info_file}${image_number}" ] && \ cat "${info_file}${image_number}" >> "$output_file" # Generate firmware binary data cat "${data_file}${image_number}" | sh > "${binary_file}${image_number}" # uuencode the data and add it to the output file uuencode "${binary_file}${image_number}" \ "${binary_file}${image_number}" >> "$output_file" image_number=$((image_number + 1)) done # Remove temporary files generated by parsing the ISP driver C header # file with firmware data eval rm -f \"${license_file}\"\* \ \"${name_file}\"\* \ \"${info_file}\"\* \ \"${data_file}\"\* \ \"${binary_file}\"\*