scripts: ath10k: add ath10k-fwencoder and ath10k-bdencoder

Scripts for handling ath10k firmware image container format.
This commit is contained in:
Kalle Valo 2015-12-03 17:41:27 +02:00
parent 41b194534b
commit b2b06517bb
2 changed files with 1128 additions and 0 deletions

View file

@ -0,0 +1,277 @@
#!/usr/bin/python
#
# Copyright (c) 2015 Qualcomm Atheros, Inc.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
import struct
import ctypes
import sys
import os.path
from optparse import OptionParser
import json
MAX_BUF_LEN = 200000
ATH10K_BOARD_SIGNATURE = "QCA-ATH10K-BOARD"
DEFAULT_BD_API = 2
DEFAULT_BOARD_FILE = 'board-%d.bin' % DEFAULT_BD_API
DEFAULT_JSON_FILE = 'board-%d.json' % DEFAULT_BD_API
TYPE_LENGTH_SIZE = 8
ATH10K_BD_IE_BOARD = 0
ATH10K_BD_IE_BOARD_NAME = 0
ATH10K_BD_IE_BOARD_DATA = 1
def padding_needed(len):
if len % 4 != 0:
return 4 - len % 4
return 0
def add_ie(buf, offset, id, value):
length = len(value)
padding_len = padding_needed(length)
length = length + padding_len
padding = ctypes.create_string_buffer(padding_len)
for i in range(padding_len):
struct.pack_into('<B', padding, i, 0x6d)
fmt = '<2i%ds%ds' % (len(value), padding_len)
struct.pack_into(fmt, buf, offset, id, len(value), value, padding.raw)
offset = offset + TYPE_LENGTH_SIZE + len(value) + padding_len
return offset
class BoardContainer:
def create_board(self, filename, names):
if os.path.getsize(filename) > MAX_BUF_LEN:
print "file %s is too large, maximum size is %d" % (filename,
MAX_BUF_LEN)
return -1
buf = ctypes.create_string_buffer(MAX_BUF_LEN)
offset = 0
# add name IEs
for name in names:
offset = add_ie(buf, offset, ATH10K_BD_IE_BOARD_NAME, str(name))
# add data IEs
f = open(filename, 'rb')
data = f.read()
offset = add_ie(buf, offset, ATH10K_BD_IE_BOARD_DATA, data)
f.close()
# return the full IE including padding
return buf[:offset]
def pack_boards(self, mapping):
for board in mapping:
filename = board['data']
payload = self.create_board(filename, board['names'])
self.buf_len = add_ie(self.buf, self.buf_len,
ATH10K_BD_IE_BOARD, payload)
def create_single_bin(self, name):
fd = open(name, 'wb')
fd.write(self.buf.raw[0:self.buf_len])
fd.close()
print "board binary file '%s' is created" % name
def add_signature(self, signature):
signature = signature + '\0'
length = len(signature)
pad_len = padding_needed(length)
length = length + pad_len
padding = ctypes.create_string_buffer(pad_len)
for i in range(pad_len):
struct.pack_into('<B', padding, i, 0x6d)
fmt = '<%ds%ds' % (len(signature), pad_len)
struct.pack_into(fmt, self.buf, self.buf_len, signature, padding.raw)
self.buf_len = self.buf_len + length
self.sig_len = length # signature length includes null byte+padding
def open(self, name):
f = open(name, 'rb')
self.buf = f.read()
f.close()
self.buf_len = len(self.buf)
offset = 0
self.boards = []
fmt = '<%dsb' % (len(ATH10K_BOARD_SIGNATURE))
(signature, null) = struct.unpack_from(fmt, self.buf, offset)
if signature != ATH10K_BOARD_SIGNATURE or null != 0:
print "invalid signature found in %s" % name
return 1
offset = offset + self.sig_len
i = 0
# FIXME: this supports only ATH10K_BD_IE_BOARD for now, needs
# to refactored to support more IEs
# looping main IEs
while offset < self.buf_len:
(ie_id, ie_len) = struct.unpack_from('<2i', self.buf, offset)
offset = offset + TYPE_LENGTH_SIZE
if offset + ie_len > self.buf_len:
print 'Error: Buffer too short (%d + %d > %d)' % (offset,
ie_len,
self.buf_len)
return 1
# skip if an unknown IE
if ie_id != ATH10K_BD_IE_BOARD:
offset = offset + ie_len + padding_needed(ie_len)
continue
board = {}
board['names'] = []
# looping board IEs
while ie_len > 0:
(board_ie_id, board_ie_len) = struct.unpack_from('<2i',
self.buf,
offset)
offset = offset + TYPE_LENGTH_SIZE
if board_ie_len > ie_len:
print 'Error: board_ie_len too big (%d > %d)' % (board_ie_len, ie_len)
return 1
if board_ie_id == ATH10K_BD_IE_BOARD_NAME:
fmt = '<%ds' % board_ie_len
(name, ) = struct.unpack_from(fmt, self.buf, offset)
board['names'].append(name)
elif board_ie_id == ATH10K_BD_IE_BOARD_DATA:
fmt = '<%ds' % board_ie_len
(board_data, ) = struct.unpack_from(fmt, self.buf, offset)
board['data'] = board_data
offset = offset + board_ie_len + padding_needed(board_ie_len)
ie_len = ie_len - TYPE_LENGTH_SIZE - board_ie_len - padding_needed(board_ie_len)
self.boards.append(board)
i = i + 1
def __init__(self):
self.buf = ctypes.create_string_buffer(MAX_BUF_LEN)
self.buf_len = 0
self.add_signature(ATH10K_BOARD_SIGNATURE)
def extract(options, args):
if len(args) != 1:
print "Error: extract option requires input filename\n"
usage()
return 1
cont = BoardContainer()
cont.open(args[0])
mapping = []
for board in cont.boards:
filename = board['names'][0] + '.bin'
b = {}
b['names'] = board['names']
b['data'] = filename
mapping.append(b)
f = open(filename, 'w')
f.write(board['data'])
f.close()
print "%s created size: %d" % (filename, len(board['data']))
filename = DEFAULT_JSON_FILE
f = open(filename, 'w')
f.write(json.dumps(mapping))
f.close()
print "%s created" % (filename)
def create(options):
mapping_file = options.create
if options.output:
output = options.output
else:
output = DEFAULT_BOARD_FILE
cont = BoardContainer()
if not os.path.exists(mapping_file):
print 'mapping file %s not found' % (mapping_file)
return
f = open(mapping_file, 'r')
mapping = json.loads(f.read())
cont.pack_boards(mapping)
f.close()
cont.create_single_bin(output)
def usage():
print "Usage:"
print "ath10k-board-encoder <-c or --create> <optional -o or --output> <FILE>"
print "ath10k-board-encoder <-e or --extract> <FILE>"
def main():
parser = OptionParser()
parser.add_option("-c", "--create", dest="create",
help='Create single board binary for ath10k from '
'mapping file')
parser.add_option("-e", "--extract", action="store_true", dest="extract",
help='extract board file from encoded single binary')
parser.add_option("-o", "--output", action="store", type="string",
dest="output", help='Name of output file')
(options, args) = parser.parse_args()
if options.create:
try:
return create(options)
except Exception as e:
print 'Create failed: %s' % e
sys.exit(2)
elif options.extract:
return extract(options, args)
else:
return usage()
if __name__ == "__main__":
main()

View file

@ -0,0 +1,851 @@
#!/usr/bin/python
#
# Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import ctypes
import struct
import optparse
import time
import math
import logging
import sys
import os.path
import traceback
import binascii
DEFAULT_FW_API_VERSION = 4
ATH10K_SIGNATURE = "QCA-ATH10K"
MAX_LEN = 2000000
ATH10K_FW_IE_FW_VERSION = 0
ATH10K_FW_IE_TIMESTAMP = 1
ATH10K_FW_IE_FEATURES = 2
ATH10K_FW_IE_FW_IMAGE = 3
ATH10K_FW_IE_OTP_IMAGE = 4
ATH10K_FW_IE_WMI_OP_VERSION = 5
ATH10K_FW_IE_HTT_OP_VERSION = 6
ATH10K_FW_IE_FW_CODE_SWAP_IMAGE = 7
# enum ath10k_fw_features from ath10k/core.h
ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0
ATH10K_FW_FEATURE_WMI_10X = 1
ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX = 2
ATH10K_FW_FEATURE_NO_P2P = 3
ATH10K_FW_FEATURE_WMI_10_2 = 4
ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT = 5
ATH10K_FW_FEATURE_WOWLAN_SUPPORT = 6
ATH10K_FW_FEATURE_IGNORE_OTP_RESULT = 7
ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING = 8
ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT = 9
ATH10K_FW_FEATURE_RAW_MODE_SUPPORT = 10
ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA = 11
ATH10K_FW_FEATURE_MFP_SUPPORT = 12
ATH10K_FW_FEATURE_MAX = 13
feature_map = {
'ext-wmi-mgmt-rx': ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX,
'wmi-10x': ATH10K_FW_FEATURE_WMI_10X,
'wmi-mgmt-tx': ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
'no-p2p': ATH10K_FW_FEATURE_NO_P2P,
'wmi-10-2': ATH10K_FW_FEATURE_WMI_10_2,
'multi-vif-ps': ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT,
'wowlan': ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
'ignore-otp-result': ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,
'no-nwifi-decap-4addr-padding':
ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING,
'skip-clock-init': ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT,
'raw-mode': ATH10K_FW_FEATURE_RAW_MODE_SUPPORT,
'adaptive-cca': ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA,
'mfp-support': ATH10K_FW_FEATURE_MFP_SUPPORT
}
# from enum ath10k_fw_wmi_op_version in ath10k/hw.h
ATH10K_FW_WMI_OP_VERSION_UNSET = 0
ATH10K_FW_WMI_OP_VERSION_MAIN = 1
ATH10K_FW_WMI_OP_VERSION_10_1 = 2
ATH10K_FW_WMI_OP_VERSION_10_2 = 3
ATH10K_FW_WMI_OP_VERSION_TLV = 4
ATH10K_FW_WMI_OP_VERSION_10_2_4 = 5
ATH10K_FW_WMI_OP_VERSION_10_4 = 6
wmi_op_version_map = {
'unset': ATH10K_FW_WMI_OP_VERSION_UNSET,
'main': ATH10K_FW_WMI_OP_VERSION_MAIN,
'10.1': ATH10K_FW_WMI_OP_VERSION_10_1,
'10.2': ATH10K_FW_WMI_OP_VERSION_10_2,
'tlv': ATH10K_FW_WMI_OP_VERSION_TLV,
'10.2.4': ATH10K_FW_WMI_OP_VERSION_10_2_4,
'10.4': ATH10K_FW_WMI_OP_VERSION_10_4,
}
# from enum ath10k_fw_wmi_op_version in ath10k/hw.h
ATH10K_FW_HTT_OP_VERSION_UNSET = 0
ATH10K_FW_HTT_OP_VERSION_MAIN = 1
ATH10K_FW_HTT_OP_VERSION_10_1 = 2
ATH10K_FW_HTT_OP_VERSION_TLV = 3
ATH10K_FW_HTT_OP_VERSION_10_4 = 4
htt_op_version_map = {
'unset': ATH10K_FW_HTT_OP_VERSION_UNSET,
'main': ATH10K_FW_HTT_OP_VERSION_MAIN,
'10.1': ATH10K_FW_HTT_OP_VERSION_10_1,
'tlv': ATH10K_FW_HTT_OP_VERSION_TLV,
'10.4': ATH10K_FW_HTT_OP_VERSION_10_4,
}
ETHTOOL_FWVERS_LEN = 32
# global variables
logger = None
class FWEncoderError(Exception):
pass
def get_output_name(fw_api=None):
if fw_api != None:
api = fw_api
else:
api = DEFAULT_FW_API_VERSION
return 'firmware-%s.bin' % api
class FirmwareContainer:
def add_element(self, type_id, value):
length = len(value)
padding_len = padding_needed(length)
length = length + padding_len
padding = ctypes.create_string_buffer(padding_len)
for i in range(padding_len):
struct.pack_into('<B', padding, i, 0x77)
logger.debug('adding id %d len(value) %d'
'padding_len %d' % (type_id,
len(value),
padding_len))
fmt = '<ii%ds%ds' % (len(value), padding_len)
struct.pack_into(fmt, self.buf, self.buf_len, type_id, len(value),
value, padding.raw)
self.buf_len = self.buf_len + 4 + 4 + len(value) + padding_len
def add_u32(self, type_id, value):
if not type(value) is int:
raise FWEncoderError('u32 IE %d is not int: %s' %
(type_id, str(value)))
buf = ctypes.create_string_buffer(4)
struct.pack_into("<i", buf, 0, value)
self.add_element(type_id, buf.raw)
def read_u32(self, type_id):
(val,) = struct.unpack_from("<i", self.elements[type_id])
return val
def add_bitmap(self, ie, enabled, maximum):
if (max(enabled) >= maximum):
logger.error("bitmap %d out of maximum (%d >= %d)" % \
(ie, max(enabled), maximum))
return
bytes = [0] * maximum
for i in range(maximum):
if i not in enabled:
continue
max_set = i
index = i / 8
bit = i % 8
bytes[index] = bytes[index] | (1 << bit)
# remove trailing null bits away, that changing only
# maximum doesn't affect created binary size
length = int(math.ceil(max_set / float(8)))
bytes = bytes[:length]
buf = ctypes.create_string_buffer(length)
for index in range(length):
struct.pack_into('<B', buf, index, bytes[index])
self.add_element(ie, buf.raw)
def read_bitmap(self, ie):
buf = self.elements[ie]
length = len(buf)
bits = []
for index in range(length):
val = struct.unpack_from('<B', buf, index)[0]
for bit in range(8):
if val & 0x1:
bits.append(index * 8 + bit)
val = val >> 1
return bits
def set_signature(self, signature):
self.signature = signature
self.signature_len = len(signature)
# include the null byte
length = len(signature) + 1
padding_len = padding_needed(length)
length = length + padding_len
padding = ctypes.create_string_buffer(padding_len)
for i in range(padding_len):
struct.pack_into('<B', padding, i, 0x77)
fmt = '<%dsb%ds' % (len(signature), padding_len)
struct.pack_into(fmt, self.buf, 0, signature, 0, padding.raw)
self.buf_len = length
def write(self, name):
f = open(name, 'wb')
f.write(self.buf.raw[:self.buf_len])
f.close()
return self.buf_len
def open(self, name):
f = open(name, 'rb')
self.buf = f.read()
self.buf_len = len(self.buf)
f.close()
offset = 0
fmt = '<%dsb' % (self.signature_len)
(signature, null) = struct.unpack_from(fmt, self.buf, offset)
offset = offset + self.signature_len + 1
if signature != self.signature or null != 0:
logger.error("Invalid signature!")
return False
offset = self.signature_len + 1
offset = offset + padding_needed(offset)
self.elements = {}
while offset + 4 + 4 < self.buf_len:
(type_id, length) = struct.unpack_from("<ii", self.buf, offset)
offset = offset + 4 + 4
if offset + length > self.buf_len:
logger.error("Buffer too short")
return
fmt = '<%ds' % length
(payload,) = struct.unpack_from(fmt, self.buf, offset)
offset = offset + length
offset = offset + padding_needed(offset)
self.elements[type_id] = payload
return True
def __init__(self, signature):
self.buf = ctypes.create_string_buffer(MAX_LEN)
self.buf_len = 0
self.set_signature(signature)
class Ath10kFirmwareContainer(object):
def _load_file(self, name):
if os.path.getsize(name) > MAX_LEN:
raise FWEncoderError('file %s is too large, maximum size is %d' %
(name, MAX_LEN))
f = open(name, 'rb')
buf = f.read()
f.close()
return buf
def set_fw_code_swap_image(self, fw_code_swap_image_name):
self.fw_code_swap_image = self._load_file(fw_code_swap_image_name)
def get_fw_code_swap_image(self):
return self.fw_code_swap_image
def set_htt_op_version(self, htt_op_version):
s = htt_op_version
# convert the string to integer
if s in htt_op_version_map:
version = htt_op_version_map[s]
elif is_int(s):
version = s
else:
print 'Error: Invalid HTT OP version: %s' % s
return 1
self.htt_op_version = version
def get_htt_op_version(self):
version = self.htt_op_version
# find value from the dict
try:
name = [key for key, value in htt_op_version_map.iteritems()
if value == version][0]
except IndexError:
name = str(version)
return name
def set_wmi_op_version(self, wmi_op_version):
s = wmi_op_version
# convert the string to integer
if s in wmi_op_version_map:
version = wmi_op_version_map[s]
elif is_int(s):
version = s
else:
print 'Error: Invalid WMI OP version: %s' % s
return 1
self.wmi_op_version = version
def get_wmi_op_version(self):
version = self.wmi_op_version
# find value from the dict
try:
name = [key for key, value in wmi_op_version_map.iteritems()
if value == version][0]
except IndexError:
name = str(version)
return name
def set_features(self, features):
self.features = features.split(',')
enabled = []
for capa in self.features:
if capa not in feature_map:
print "Error: '%s' not found from the feature map" % capa
return 1
enabled.append(feature_map[capa])
self.features_bitmap = enabled
def get_features(self):
s = ""
if self.features_bitmap == None:
return None
for capa in self.features_bitmap:
# find value from the dict
try:
name = [key for key, value in feature_map.iteritems()
if value == capa][0]
except IndexError:
name = str(capa)
s = s + name + ","
# strip last comma
if len(s) > 0:
s = s[:-1]
return s
def set_fw_image(self, fw_image_name):
self.fw_image = self._load_file(fw_image_name)
def get_fw_image(self):
return self.fw_image
def set_otp_image(self, otp_image_name):
self.otp_image = self._load_file(otp_image_name)
def get_otp_image(self):
return self.otp_image
def set_timestamp(self, timestamp):
self.timestamp = int(timestamp)
def get_timestamp(self):
return self.timestamp
def get_timestamp_as_iso8601(self):
if self.timestamp == None:
return None
return time.strftime('%Y-%m-%d %H:%M:%S',
time.localtime(self.timestamp))
def set_fw_version(self, fw_version):
self.fw_version = fw_version
# reserve one byte for null
if len(self.fw_version) > ETHTOOL_FWVERS_LEN - 1:
print 'Firmware version string too long: %d' % (len(self.fw_version))
return 1
def get_fw_version(self):
return self.fw_version
def load(self, filename):
c = FirmwareContainer(ATH10K_SIGNATURE)
c.open(filename)
self.file = c.buf
for e in c.elements:
if e == ATH10K_FW_IE_FW_VERSION:
self.fw_version = c.elements[e]
elif e == ATH10K_FW_IE_TIMESTAMP:
self.timestamp = c.read_u32(e)
elif e == ATH10K_FW_IE_OTP_IMAGE:
self.otp_image = c.elements[e]
elif e == ATH10K_FW_IE_FW_IMAGE:
self.fw_image = c.elements[e]
elif e == ATH10K_FW_IE_FEATURES:
self.features_bitmap = c.read_bitmap(ATH10K_FW_IE_FEATURES)
elif e == ATH10K_FW_IE_WMI_OP_VERSION:
self.wmi_op_version = c.read_u32(ATH10K_FW_IE_WMI_OP_VERSION)
elif e == ATH10K_FW_IE_HTT_OP_VERSION:
self.htt_op_version = c.read_u32(ATH10K_FW_IE_HTT_OP_VERSION)
elif e == ATH10K_FW_IE_FW_CODE_SWAP_IMAGE:
self.fw_code_swap_image = c.elements[e]
else:
print "Unknown IE: ", e
def save(self, filename):
self.container = FirmwareContainer(ATH10K_SIGNATURE)
if self.fw_version:
self.container.add_element(ATH10K_FW_IE_FW_VERSION,
self.fw_version)
if self.timestamp:
self.container.add_u32(ATH10K_FW_IE_TIMESTAMP, self.timestamp)
# FIXME: otp should be after fw_image but that breaks the
# current tests
if self.otp_image:
self.container.add_element(ATH10K_FW_IE_OTP_IMAGE, self.otp_image)
if self.fw_image:
self.container.add_element(ATH10K_FW_IE_FW_IMAGE, self.fw_image)
# FIXME: features should be before fw_image but that breaks
# the current tests
if self.features_bitmap:
self.container.add_bitmap(ATH10K_FW_IE_FEATURES,
self.features_bitmap,
ATH10K_FW_FEATURE_MAX)
if self.wmi_op_version:
self.container.add_u32(ATH10K_FW_IE_WMI_OP_VERSION, self.wmi_op_version)
if self.htt_op_version:
self.container.add_u32(ATH10K_FW_IE_HTT_OP_VERSION,
self.htt_op_version)
if self.fw_code_swap_image:
self.container.add_element(ATH10K_FW_IE_FW_CODE_SWAP_IMAGE,
self.fw_code_swap_image)
return self.container.write(filename)
def __init__(self):
self.fw_version = None
self.timestamp = None
self.features = None
self.features_bitmap = None
self.fw_image = None
self.otp_image = None
self.wmi_op_version = None
self.htt_op_version = None
self.fw_code_swap_image = None
# to workaround annoying python feature of returning negative hex values
def hex32(val):
return val & 0xffffffff
# match with kernel crc32_le(0, buf, buf_len) implementation
def _crc32(buf):
return hex32(~(hex32(binascii.crc32(buf, 0xffffffff))))
def padding_needed(length):
if length % 4 != 0:
return 4 - length % 4
return 0
def is_int(val):
try:
int(val)
return True
except ValueError:
return False
def write_file(filename, buf):
f = open(filename, 'w')
f.write(buf)
f.close
def info(options, args):
if len(args) != 1:
print 'Filename missing'
return 1
filename = args[0]
c = Ath10kFirmwareContainer()
c.load(filename)
s = ''
s = s + 'FileSize: %s\n' % (len(c.file))
s = s + 'FileCRC32: %08x\n' % (_crc32(c.file))
if c.get_fw_version():
s = s + 'FirmwareVersion: %s\n' % (c.get_fw_version())
if c.get_timestamp():
s = s + 'Timestamp: %s\n' % (c.get_timestamp_as_iso8601())
if c.get_features():
s = s + 'Features: %s\n' % (c.get_features())
if c.get_fw_image():
s = s + 'FirmwareImageSize: %s\n' % (len(c.get_fw_image()))
s = s + 'FirmwareImageCRC32: %08x\n' % (_crc32(c.get_fw_image()))
if c.get_otp_image():
s = s + 'OTPImageSize: %s\n' % (len(c.get_otp_image()))
s = s + 'OTPImageCRC32: %08x\n' % (_crc32(c.get_otp_image()))
if c.get_wmi_op_version():
s = s + 'WMIOpVersion: %s\n' % (c.get_wmi_op_version())
if c.get_htt_op_version():
s = s + 'HTTOpVersion: %s\n' % (c.get_htt_op_version())
if c.get_fw_code_swap_image():
s = s + 'FirmwareCodeSwapImageSize: %s\n' % (len(c.get_fw_code_swap_image()))
s = s + 'FirmwareCodeSwapImageCRC32: %08x\n' % (_crc32(c.get_fw_code_swap_image()))
print s.strip()
def dump(options, args):
if len(args) != 1:
print 'Filename missing'
return 1
filename = args[0]
c = Ath10kFirmwareContainer()
c.load(filename)
print "ath10k-fwencoder --create \\"
if c.get_fw_version():
print "--firmware-version=%s \\" % c.get_fw_version()
if c.get_timestamp() and options.show_timestamp:
print "--timestamp=%u \\" % c.get_timestamp()
if c.get_features():
print "--features=%s \\" % c.get_features()
if c.get_fw_image():
name = "athwlan.bin"
print "--firmware=%s \\" % name
if c.get_otp_image():
name = "otp.bin"
print "--otp=%s \\" % name
if c.get_wmi_op_version():
print '--set-wmi-op-version=%s \\' % c.get_wmi_op_version()
if c.get_htt_op_version():
print '--set-htt-op-version=%s \\' % (c.get_htt_op_version())
if c.get_fw_code_swap_image():
name = "athwlan.codeswap.bin"
print "--firmware-codeswap=%s \\" % name
print
def extract(options, args):
if len(args) != 1:
print 'Filename missing'
return 1
filename = args[0]
c = Ath10kFirmwareContainer()
c.load(filename)
if c.get_fw_image():
name = "athwlan.bin"
write_file(name, c.get_fw_image())
print '%s extracted: %d B' % (name, len(c.get_fw_image()))
if c.get_otp_image():
name = "otp.bin"
write_file(name, c.get_otp_image())
print '%s extracted: %d B' % (name, len(c.get_otp_image()))
if c.get_fw_code_swap_image():
name = "athwlan.codeswap.bin"
write_file(name, c.get_fw_code_swap_image())
print '%s extracted: %d B' % (name, len(c.get_fw_code_swap_image()))
print
def modify(options, args):
if len(args) != 1:
print 'Filename missing'
return 1
filename = args[0]
c = Ath10kFirmwareContainer()
c.load(filename)
if options.firmware_version:
c.set_fw_version(options.firmware_version)
if options.timestamp:
stamp = str(int(options.timestamp))
else:
# if no timestamp provided use the current time so that the
# timestamp shows the time of last modication
stamp = int(time.time())
c.set_timestamp(stamp)
if options.otp:
c.set_otp_image(options.otp)
if options.fw:
c.set_fw_image(options.fw)
if options.features:
c.set_features(options.features)
if options.wmi_op_version:
c.set_wmi_op_version(options.wmi_op_version)
if options.htt_op_version:
c.set_htt_op_version(options.htt_op_version)
if options.fw_codeswap:
c.set_fw_code_swap_image(options.fw_codeswap)
file_len = c.save(filename)
print '%s modified: %d B' % (filename, file_len)
def create(options):
output = get_output_name(options.fw_api)
if options.output:
output = options.output
c = Ath10kFirmwareContainer()
if options.firmware_version:
c.set_fw_version(options.firmware_version)
# always add a timestamp
if options.timestamp:
stamp = int(options.timestamp)
else:
stamp = int(time.time())
c.set_timestamp(stamp)
if options.otp:
c.set_otp_image(options.otp)
if options.fw:
c.set_fw_image(options.fw)
if options.features:
c.set_features(options.features)
if options.wmi_op_version:
c.set_wmi_op_version(options.wmi_op_version)
if options.htt_op_version:
c.set_htt_op_version(options.htt_op_version)
if options.fw_codeswap:
c.set_fw_code_swap_image(options.fw_codeswap)
file_len = c.save(output)
print '%s created: %d B' % (output, file_len)
def cmd_crc32(options, args):
if len(args) != 1:
print 'Filename missing'
return 1
filename = args[0]
f = open(filename, 'r')
buf = f.read()
print '%08x' % (_crc32(buf))
f.close()
def main():
global logger
logger = logging.getLogger('ath10k-fwencoder')
logging.basicConfig(format='%(levelname)s: %(message)s')
parser = optparse.OptionParser()
# actions
parser.add_option("-c", "--create", action="store_true", dest="create",
help='Create container file '
'for ath10k (%s)' % get_output_name())
parser.add_option("-D", "--dump-cmdline", action="store_true", dest="dump",
help='Show the cmdline used to create '
'this container file')
parser.add_option('--dump', action='store_true', dest='dump',
help='Same as --dump-cmdline '
'(for backwards compatibility)')
parser.add_option("-e", "--extract", action="store_true", dest="extract",
help='Extract binary files from the container file '
'and dump cmdline as well')
parser.add_option("--info", action="store_true", dest="info",
help='Show information about the container file')
parser.add_option("--modify", action="store_true", dest="modify",
help='Modify the container file')
parser.add_option('--crc32', action='store_true', dest='crc32',
help='Count crc32 checksum for a file')
# parameters
parser.add_option("-o", "--output", action="store", type="string",
dest="output", help='Name of output file')
# FW IEs, only use long style of option names!
parser.add_option("--otp", action="store", type="string",
dest="otp",
help='Name of otp.bin file')
parser.add_option("--firmware", action="store", type="string",
dest="fw",
help='Name of athwlan.bin file')
parser.add_option("--firmware-version", action="store",
type="string", dest="firmware_version",
help='Firmware version string to be used')
parser.add_option("--timestamp", action="store",
type="string", dest="timestamp",
help='Timestamp to be used (seconds)')
parser.add_option("--features", action="store",
type="string", dest="features",
help='feature bits to be enabled: %s' %
feature_map.keys())
parser.add_option("--set-wmi-op-version", action="store",
type="string", dest="wmi_op_version",
help='WMI op interface version: %s' %
wmi_op_version_map.keys())
parser.add_option("--set-fw-api", action="store",
type="string", dest="fw_api",
help='Set firmware API used in creating the name for '
'output file (Default: %s)' %
DEFAULT_FW_API_VERSION)
parser.add_option("--set-htt-op-version", action="store",
type="string", dest="htt_op_version",
help='HTT op interface version: %s' %
htt_op_version_map.keys())
parser.add_option("--firmware-codeswap", action="store", type="string",
dest="fw_codeswap",
help='Name of athwlan.codeswap.bin file')
# debug etc
parser.add_option('--show-timestamp', action='store_true',
dest='show_timestamp',
help='Show timestamp in --dump-cmdline action. '
'It is not shown by default so that the timestamp would be correct')
parser.add_option('-d', '--debug', action='store_true', dest='debug',
help='Enable debug messages')
(options, args) = parser.parse_args()
if options.debug:
logger.setLevel(logging.DEBUG)
if options.create:
try:
return create(options)
except FWEncoderError as e:
print 'Create failed: %s' % e
sys.exit(2)
except Exception as e:
print 'Create failed: %s' % e
traceback.print_exc()
sys.exit(3)
elif options.dump:
return dump(options, args)
elif options.extract:
return extract(options, args)
elif options.info:
return info(options, args)
elif options.modify:
return modify(options, args)
elif options.crc32:
return cmd_crc32(options, args)
else:
print 'Action command missing'
return 1
if __name__ == "__main__":
main()