Add script for brcm80211 firmware conversion
[b43-tools.git] / disassembler / brcm80211conv
1 #!/usr/bin/env python
2 """
3 #   Copyright (C) 2010  Michael Buesch <mb@bu3sch.de>
4 #
5 #   This program is free software; you can redistribute it and/or modify
6 #   it under the terms of the GNU General Public License version 2
7 #   as published by the Free Software Foundation.
8 #
9 #   This program is distributed in the hope that it will be useful,
10 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 #   GNU General Public License for more details.
13 """
14
15 import sys
16 import getopt
17
18 def indexToName(index):
19         D11UCODE_NAMETAG_START          = 0
20         D11LCN0BSINITVALS24             = 1
21         D11LCN0INITVALS24               = 2
22         D11LCN1BSINITVALS24             = 3
23         D11LCN1INITVALS24               = 4
24         D11LCN2BSINITVALS24             = 5
25         D11LCN2INITVALS24               = 6
26         D11N0ABSINITVALS16              = 7
27         D11N0BSINITVALS16               = 8
28         D11N0INITVALS16                 = 9
29         D11UCODE_OVERSIGHT16_MIMO       = 10
30         D11UCODE_OVERSIGHT16_MIMOSZ     = 11
31         D11UCODE_OVERSIGHT24_LCN        = 12
32         D11UCODE_OVERSIGHT24_LCNSZ      = 13
33         D11UCODE_OVERSIGHT_BOMMAJOR     = 14
34         D11UCODE_OVERSIGHT_BOMMINOR     = 15
35
36         namemap = {
37                 D11UCODE_NAMETAG_START          : "start",
38                 D11LCN0BSINITVALS24             : "LCN0 bs initvals 24",
39                 D11LCN0INITVALS24               : "LCN0 initvals 24",
40                 D11LCN1BSINITVALS24             : "LCN1 bs initvals 24",
41                 D11LCN1INITVALS24               : "LCN1 initvals 24",
42                 D11LCN2BSINITVALS24             : "LCN2 bs initvals 24",
43                 D11LCN2INITVALS24               : "LCN2 initvals 24",
44                 D11N0ABSINITVALS16              : "N0A bs initvals 16",
45                 D11N0BSINITVALS16               : "N0 bs initvals 16",
46                 D11N0INITVALS16                 : "N0 initvals 16",
47                 D11UCODE_OVERSIGHT16_MIMO       : "microcode 16 MIMO",
48                 D11UCODE_OVERSIGHT16_MIMOSZ     : "microcode 16 MIMO size",
49                 D11UCODE_OVERSIGHT24_LCN        : "microcode 24 LCN",
50                 D11UCODE_OVERSIGHT24_LCNSZ      : "microcode 24 LCN size",
51                 D11UCODE_OVERSIGHT_BOMMAJOR     : "bom major",
52                 D11UCODE_OVERSIGHT_BOMMINOR     : "bom minor",
53         }
54         try:
55                 return namemap[index]
56         except KeyError:
57                 return "Unknown"
58
59 def parseHeader(hdr_data):
60         sections = []
61         for i in range(0, len(hdr_data), 3 * 4):
62                 offset = ord(hdr_data[i + 0]) | (ord(hdr_data[i + 1]) << 8) |\
63                         (ord(hdr_data[i + 2]) << 16) | (ord(hdr_data[i + 3]) << 24)
64                 length = ord(hdr_data[i + 4]) | (ord(hdr_data[i + 5]) << 8) |\
65                         (ord(hdr_data[i + 6]) << 16) | (ord(hdr_data[i + 7]) << 24)
66                 index = ord(hdr_data[i + 8]) | (ord(hdr_data[i + 9]) << 8) |\
67                         (ord(hdr_data[i + 10]) << 16) | (ord(hdr_data[i + 11]) << 24)
68
69                 sections.append( (offset, length, index) )
70         sections.sort(key = lambda x: x[2]) # Sort by index
71         return sections
72
73 def getSectionByIndex(sections, searchIndex):
74         for section in sections:
75                 (offset, length, index) = section
76                 if searchIndex == index:
77                         return section
78         return None
79
80 def parseHeaderFile(hdr_filepath):
81         try:
82                 hdr_data = file(hdr_filepath, "rb").read()
83         except (IOError), e:
84                 print "Failed to read header file: %s" % e.strerror
85                 return None
86         if len(hdr_data) % (3 * 4) != 0:
87                 print "Invalid header file format"
88                 return None
89         return parseHeader(hdr_data)
90
91 def dumpInfo(hdr_filepath):
92         sections = parseHeaderFile(hdr_filepath)
93         if not sections:
94                 return 1
95         for section in sections:
96                 (offset, length, index) = section
97                 print "Index %2d   %24s    ==>  offset:0x%08X  length:0x%08X" %\
98                         (index, indexToName(index), offset, length)
99         return 0
100
101 def extractSection(hdr_filepath, bin_filepath, extractIndex, outfile):
102         sections = parseHeaderFile(hdr_filepath)
103         if not sections:
104                 return 1
105         section = getSectionByIndex(sections, extractIndex)
106         if not section:
107                 print "Did not find a section with index %d" % extractIndex
108                 return 1
109         (offset, length, index) = section
110         try:
111                 bin_data = file(bin_filepath, "rb").read()
112         except (IOError), e:
113                 print "Failed to read bin file: %s" % e.strerror
114                 return 1
115         try:
116                 outfile.write(bin_data[offset : offset + length])
117         except IndexError:
118                 print "Binfile index error."
119                 return 1
120         return 0
121
122 def usage():
123         print "BRCM80211 firmware converter tool"
124         print ""
125         print "Usage: %s [OPTIONS]" % sys.argv[0]
126         print ""
127         print "  -H|--header FILE       Use FILE as input header file"
128         print "  -B|--bin FILE          Use FILE as bin file"
129         print "  -O|--outfile FILE      Use FILE as output file. If not set, stdout is used."
130         print ""
131         print "Actions:"
132         print "  -d|--dump              Dump general information"
133         print "  -x|--extract INDEX     Extract the section with index INDEX"
134         print ""
135         print "  -h|--help              Print this help text"
136
137 def main():
138         opt_header = None
139         opt_bin = None
140         opt_action = None
141         opt_index = None
142         opt_outfile = sys.stdout
143
144         try:
145                 (opts, args) = getopt.getopt(sys.argv[1:],
146                         "hH:B:O:dx:",
147                         [ "help", "header=", "bin=", "outfile=", "dump", "extract=", ])
148         except getopt.GetoptError:
149                 usage()
150                 return 1
151         for (o, v) in opts:
152                 if o in ("-h", "--help"):
153                         usage()
154                         return 0;
155                 if o in ("-H", "--header"):
156                         opt_header = v
157                 if o in ("-B", "--bin"):
158                         opt_bin = v
159                 if o in ("-O", "--outfile"):
160                         try:
161                                 opt_outfile = file(v, "wb")
162                         except (IOError), e:
163                                 print "Failed to open output file: %s" % e.strerror
164                                 return 1
165                 if o in ("-d", "--dump"):
166                         opt_action = "dump"
167                 if o in ("-x", "--extract"):
168                         opt_action = "extract"
169                         try:
170                                 opt_index = int(v)
171                         except ValueError:
172                                 print "Invalid -x|--extract index number\n"
173                                 usage()
174                                 return 1
175         if not opt_action:
176                 print "No action specified\n"
177                 usage()
178                 return 1
179         if opt_action == "dump":
180                 if not opt_header:
181                         print "No header file specified\n"
182                         usage()
183                         return 1
184                 return dumpInfo(opt_header)
185         elif opt_action == "extract":
186                 if not opt_header or not opt_bin:
187                         print "No header or bin file specified\n"
188                         usage()
189                         return 1
190                 return extractSection(opt_header, opt_bin, opt_index, opt_outfile)
191         return 1
192
193 if __name__ == "__main__":
194         sys.exit(main())