fwcutter/make: Avoid _DEFAULT_SOURCE warning
[b43-tools.git] / disassembler / brcm80211-fwconv
1 #!/usr/bin/env python
2 """
3 #   Copyright (C) 2010  Michael Buesch <m@bues.ch>
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, sortByOffset):
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         if sortByOffset:
71                 sections.sort(key = lambda x: x[0]) # Sort by offset
72         else:
73                 sections.sort(key = lambda x: x[2]) # Sort by index
74         return sections
75
76 def generateHeaderData(sections):
77         data = []
78         for section in sections:
79                 (offset, length, index) = section
80                 data.append(chr(offset & 0xFF))
81                 data.append(chr((offset >> 8) & 0xFF))
82                 data.append(chr((offset >> 16) & 0xFF))
83                 data.append(chr((offset >> 24) & 0xFF))
84                 data.append(chr(length & 0xFF))
85                 data.append(chr((length >> 8) & 0xFF))
86                 data.append(chr((length >> 16) & 0xFF))
87                 data.append(chr((length >> 24) & 0xFF))
88                 data.append(chr(index & 0xFF))
89                 data.append(chr((index >> 8) & 0xFF))
90                 data.append(chr((index >> 16) & 0xFF))
91                 data.append(chr((index >> 24) & 0xFF))
92         return "".join(data)
93
94 def getSectionByIndex(sections, searchIndex):
95         for section in sections:
96                 (offset, length, index) = section
97                 if searchIndex == index:
98                         return section
99         return None
100
101 def parseHeaderFile(hdr_filepath, sortByOffset=False):
102         try:
103                 hdr_data = file(hdr_filepath, "rb").read()
104         except (IOError), e:
105                 print "Failed to read header file: %s" % e.strerror
106                 return None
107         if len(hdr_data) % (3 * 4) != 0:
108                 print "Invalid header file format"
109                 return None
110         return parseHeader(hdr_data, sortByOffset)
111
112 def dumpInfo(hdr_filepath):
113         sections = parseHeaderFile(hdr_filepath)
114         if not sections:
115                 return 1
116         for section in sections:
117                 (offset, length, index) = section
118                 print "Index %2d   %24s    ==>  offset:0x%08X  length:0x%08X" %\
119                         (index, indexToName(index), offset, length)
120         return 0
121
122 def extractSection(hdr_filepath, bin_filepath, extractIndex, outfilePath):
123         sections = parseHeaderFile(hdr_filepath)
124         if not sections:
125                 return 1
126         section = getSectionByIndex(sections, extractIndex)
127         if not section:
128                 print "Did not find a section with index %d" % extractIndex
129                 return 1
130         (offset, length, index) = section
131         try:
132                 bin_data = file(bin_filepath, "rb").read()
133         except (IOError), e:
134                 print "Failed to read bin file: %s" % e.strerror
135                 return 1
136         try:
137                 outfile = file(outfilePath, "wb")
138                 outfile.write(bin_data[offset : offset + length])
139         except IndexError:
140                 print "Binfile index error."
141                 return 1
142         except (IOError), e:
143                 print "Failed to write output file: %s" % e.strerror
144                 return 1
145         return 0
146
147 def mergeSection(hdr_filepath, bin_filepath, mergeIndex, mergefilePath):
148         sections = parseHeaderFile(hdr_filepath, sortByOffset=True)
149         if not sections:
150                 return 1
151         try:
152                 bin_data = file(bin_filepath, "rb").read()
153         except (IOError), e:
154                 print "Failed to read bin file: %s" % e.strerror
155                 return 1
156         try:
157                 merge_data = file(mergefilePath, "rb").read()
158         except (IOError), e:
159                 print "Failed to open merge output file: %s" % e.strerror
160                 return 1
161         newBin = []
162         newSections = []
163         newOffset = 0
164         foundIt = False
165         for section in sections:
166                 (offset, length, index) = section
167                 if index == mergeIndex:
168                         if foundIt:
169                                 print "Confused. Multiple sections with index %d?" % index
170                                 return 1
171                         foundIt = True
172                         # We overwrite this section
173                         newBin.append(merge_data)
174                         newSections.append( (newOffset, len(merge_data), index) )
175                         newOffset += len(merge_data)
176                 else:
177                         try:
178                                 newBin.append(bin_data[offset : offset + length])
179                         except IndexError:
180                                 print "Failed to read input data"
181                                 return 1
182                         newSections.append( (newOffset, length, index) )
183                         newOffset += length
184         if not foundIt:
185                 print "Did not find section with index %d" % mergeIndex
186                 return 1
187         newBin = "".join(newBin)
188         newHdr = generateHeaderData(newSections)
189         try:
190                 file(bin_filepath, "wb").write(newBin)
191                 file(hdr_filepath, "wb").write(newHdr)
192         except (IOError), e:
193                 print "Failed to write bin or header file: %s" % e.strerror
194                 return 1
195         return 0
196
197 def usage():
198         print "BRCM80211 firmware converter tool"
199         print ""
200         print "Usage: %s [OPTIONS]" % sys.argv[0]
201         print ""
202         print "  -H|--header FILE         Use FILE as header file"
203         print "  -B|--bin FILE            Use FILE as bin file"
204         print ""
205         print "Actions:"
206         print "  -d|--dump                Dump general information"
207         print "  -x|--extract INDEX:FILE  Extract the section with index INDEX to FILE"
208         print "  -m|--merge INDEX:FILE    Merges FILE into the bin file stream at INDEX"
209         print "                           A Merge modifies the files specified in -H and -B"
210         print ""
211         print "  -h|--help                Print this help text"
212
213 def main():
214         opt_header = None
215         opt_bin = None
216         opt_action = None
217         opt_index = None
218         opt_outfile = None
219         opt_mergefile = None
220
221         try:
222                 (opts, args) = getopt.getopt(sys.argv[1:],
223                         "hH:B:dx:m:",
224                         [ "help", "header=", "bin=", "dump", "extract=", "merge=", ])
225         except getopt.GetoptError:
226                 usage()
227                 return 1
228         for (o, v) in opts:
229                 if o in ("-h", "--help"):
230                         usage()
231                         return 0;
232                 if o in ("-H", "--header"):
233                         opt_header = v
234                 if o in ("-B", "--bin"):
235                         opt_bin = v
236                 if o in ("-d", "--dump"):
237                         opt_action = "dump"
238                 if o in ("-x", "--extract"):
239                         opt_action = "extract"
240                         try:
241                                 v = v.split(':')
242                                 opt_index = int(v[0])
243                                 opt_outfile = v[1]
244                         except IndexError, ValueError:
245                                 print "Invalid -x|--extract index number\n"
246                                 usage()
247                                 return 1
248                 if o in ("-m", "--merge"):
249                         opt_action = "merge"
250                         try:
251                                 v = v.split(':')
252                                 opt_index = int(v[0])
253                                 opt_mergefile = v[1]
254                         except IndexError, ValueError:
255                                 print "Invalid -m|--merge index and/or merge file name\n"
256                                 usage()
257                                 return 1
258         if not opt_action:
259                 print "No action specified\n"
260                 usage()
261                 return 1
262         if opt_action == "dump":
263                 if not opt_header:
264                         print "No header file specified\n"
265                         usage()
266                         return 1
267                 return dumpInfo(opt_header)
268         elif opt_action == "extract":
269                 if not opt_header or not opt_bin:
270                         print "No header or bin file specified\n"
271                         usage()
272                         return 1
273                 return extractSection(opt_header, opt_bin, opt_index, opt_outfile)
274         elif opt_action == "merge":
275                 if not opt_header or not opt_bin:
276                         print "No header or bin file specified\n"
277                         usage()
278                         return 1
279                 return mergeSection(opt_header, opt_bin, opt_index, opt_mergefile)
280         return 1
281
282 if __name__ == "__main__":
283         sys.exit(main())