Add makeamitbin to generate images for other RDC-based devices, thanks sn9 !
[openwrt/svn-archive/archive.git] / tools / firmware-utils / src / makeamitbin.c
1 /*
2 * makeamitbin - create firmware binaries for MGB100
3 *
4 * Copyright (C) 2007 Volker Weiss <dev@tintuc.de>
5 * Christian Welzel <dev@welzel-online.ch>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27
28
29 /* defaults: Level One WAP-0007 */
30 static char *ascii1 = "DDC_RUS001";
31 static char *ascii2 = "Queen";
32
33 static struct hdrinfo {
34 char *name;
35 unsigned long unknown; /* can probably be any number, maybe version number */
36 int topalign;
37 unsigned int addr;
38 unsigned int size;
39 } hdrinfo[] = {
40 { "bios", 0xc76be111, 1, 0x3fa000, 0x006000 }, /* BIOS */
41 { "recovery", 0xc76be222, 0, 0x3f0000, 0x004000 }, /* Recovery Loader */
42 { "linux", 0xc76bee9d, 0, 0x000000, 0x100000 }, /* Linux */
43 { "ramdisk", 0xc76bee9d, 0, 0x100000, 0x280000 }, /* ramdisk */
44 { "amitconfig", 0xc76bee8b, 0, 0x380000, 0x060000 }, /* AMIT config */
45 { "redboot", 0x00000000, 1, 0x3d0000, 0x030000 }, /* Redboot 128kB image */
46 { "redbootlow", 0, 0, 0x3e0000, 0x18000 }, /* Redboot 1. part */
47 { "redboothigh", 0, 0, 0x3fa000, 0x6000 }, /* Redboot 2. part */
48 { "linux3g", 0xcb5f06b5, 0, 0x000000, 0x100000 }, /* Linux */
49 { "ramdisk3g", 0xcb5f06b5, 0, 0x100000, 0x280000 }, /* ramdisk */
50 { NULL }
51 };
52
53 /*
54 CHD2WLANU_R400b7
55
56 11e1 6bc7
57 22e2 6bc7
58 5dc3 47c8
59 5cc3 47c8
60 21c3 47c8
61 */
62
63 /*
64 20060106_DDC_WAP-0007_R400b4
65
66 11e1 6bc7
67 22e2 6bc7
68 9dee 6bc7
69 9dee 6bc7
70 8bee 6bc7
71 */
72
73 /*
74 WMU-6000FS_R400b6
75
76 11e1 6bc7
77 22e2 6bc7
78 6d2d 0fc8
79 6c2d 0fc8
80 542d 0fc8
81 */
82
83 /*
84 WAP-0007(R4.00b8)_2006-10-02
85
86 9979 5fc8
87 22e2 6bc7
88 c46e cec8
89 c36e cec8
90 a76e cec8
91 */
92
93
94
95 #define HDRSIZE 80
96
97 #define COPY_SHORT(d, o, v) d[o+0] = (unsigned char)((v) & 0xff); \
98 d[o+1] = (unsigned char)(((v) >> 8) & 0xff)
99 #define COPY_LONG(d, o, v) d[o+0] = (unsigned char)((v) & 0xff); \
100 d[o+1] = (unsigned char)(((v) >> 8) & 0xff); \
101 d[o+2] = (unsigned char)(((v) >> 16) & 0xff); \
102 d[o+3] = (unsigned char)(((v) >> 24) & 0xff)
103 #define READ_SHORT(d, o) ((unsigned short)(d[o+0]) + \
104 (((unsigned short)(d[o+1])) << 8))
105
106 /*
107 00..0d ASCII product ID
108 0e..0f checksum of payload
109 10..1b ASCII Queen
110 1c..1f AMIT BIOS: 11e1 6bc7, Recovery Tool: 22e2 6bc7
111 Linux: 5dc3 47c8, ramdisk: 5cc3 47c8
112 AMIT FS: 21c3 47c8 VERSION NUMBER??????
113 20..23 offset in flash aligned to segment boundary
114 24..27 length in flash aligned to segment boundary
115 28..2b offset in flash (payload)
116 2c..2f length (payload)
117 30..3f always 0
118 40..47 always 4248 0101 5000 0001 (last maybe .....0501)
119 48..4b same as 20..23
120 4c..4d always 0b00
121 4e..4f inverted checksum of header
122 */
123
124 unsigned short checksum(unsigned char *data, long size)
125 {
126 long n;
127 unsigned short d, cs = 0;
128 for (n = 0; n < size; n += 2)
129 {
130 d = READ_SHORT(data, n);
131 cs += d;
132 if (cs < d)
133 cs++;
134 }
135 if (size & 1)
136 {
137 d = data[n];
138 cs += d;
139 if (cs < d)
140 cs++;
141 }
142 return cs;
143 }
144
145 void showhdr(unsigned char *hdr)
146 {
147 int i, j;
148 for (j = 0; j < 5; j++)
149 {
150 for (i = 0; i < 16; i++)
151 {
152 printf("%02x ", (unsigned int)(hdr[j * 16 + i]));
153 }
154 printf(" ");
155 for (i = 0; i < 16; i++)
156 {
157 unsigned char d = hdr[j * 16 + i];
158 printf("%c", (d >= ' ' && d < 127) ? d : '.');
159 }
160 printf("\n");
161 }
162 }
163
164 void makehdr(unsigned char *hdr, struct hdrinfo *info,
165 unsigned char *data, long size, int last)
166 {
167 unsigned int offset = info->addr + 0x10;
168 memset(hdr, 0, HDRSIZE);
169 if (info->topalign)
170 offset = info->addr + info->size - size; /* top align */
171 strncpy((char *)hdr + 0x00, ascii1, 14);
172 strncpy((char *)hdr + 0x10, ascii2, 12);
173 COPY_LONG(hdr, 0x1c, info->unknown);
174 COPY_LONG(hdr, 0x20, info->addr);
175 COPY_LONG(hdr, 0x24, info->size);
176 COPY_LONG(hdr, 0x28, offset);
177 COPY_LONG(hdr, 0x2c, size);
178 COPY_LONG(hdr, 0x40, 0x01014842);
179 COPY_LONG(hdr, 0x44, last ? 0x01050050 : 0x01000050);
180 COPY_LONG(hdr, 0x48, info->addr);
181 COPY_SHORT(hdr, 0x4c, info->unknown == 0xcb5f06b5 ? 0x0016 : 0x000b);
182 COPY_SHORT(hdr, 0x0e, checksum(data, size));
183 COPY_SHORT(hdr, 0x4e, ~checksum(hdr, HDRSIZE));
184 }
185
186 unsigned char *read_file(const char *name, long *size)
187 {
188 FILE *f;
189 unsigned char *data = NULL;
190 *size = 0;
191 f = fopen(name, "r");
192 if (f != NULL)
193 {
194 if (fseek(f, 0, SEEK_END) == 0)
195 {
196 *size = ftell(f);
197 if (*size != -1)
198 {
199 if (fseek(f, 0, SEEK_SET) == 0)
200 {
201 data = (unsigned char *)malloc(*size);
202 if (data != NULL)
203 {
204 if (fread(data, sizeof(char), *size, f) != *size)
205 {
206 free(data);
207 data = NULL;
208 }
209 }
210 }
211 }
212 }
213 fclose(f);
214 }
215 return data;
216 }
217
218 struct hdrinfo *find_hdrinfo(const char *name)
219 {
220 int n;
221 for (n = 0; hdrinfo[n].name != NULL; n++)
222 {
223 if (strcmp(name, hdrinfo[n].name) == 0)
224 return &hdrinfo[n];
225 }
226 return NULL;
227 }
228
229 void oferror(FILE *f)
230 {
231 printf("file error\n");
232 exit(2);
233 }
234
235 void showhelp(void)
236 {
237 printf("Syntax: makeamitbin [options]\n");
238 printf("Options:\n");
239 printf(" -1 ID1\tFirmware identifier 1, e.g. 'DDC_RUS001' for manufacturer LevelOne\n");
240 printf(" -2 ID2\tFirmware identifier 2, 'Queen' in all known cases\n");
241 printf(" -o FILE\tOutput file\n");
242 printf(" -ids\t\tShow a list of known firmware identifiers.\n");
243 exit(1);
244 }
245
246 void show_fwids(void)
247 {
248 printf("List of known firmware identifiers:\n");
249 printf("Manufacturer\t\tProduct\t\tIdentifier\n");
250 printf("=====================================================\n");
251 printf("Conceptronic\t\tCHD2WLANU\tLLM_RUS001\n");
252 printf("Pearl\t\t\tPE6643\t\tQueen\n");
253 printf("Micronica\t\tMGB100\t\tQueen\n");
254 printf("LevelOne\t\tWAP-0007\tDDC_RUS001\n");
255 printf("SMC\t\t\tWAPS-G\t\tSMC_RUS001\n");
256 printf("OvisLink (AirLive)\tWMU-6\t\tOVS_RUS001\n");
257 printf("SafeCom SWSAPUR-5\tFMW\t\tSafeco_RPS001\n");
258 exit(1);
259 }
260
261 int main(int argc, char *argv[])
262 {
263 unsigned char hdr[HDRSIZE];
264 unsigned char *data;
265 FILE *of;
266 char *outfile = NULL;
267 char *type;
268 struct hdrinfo *info;
269 long size;
270 int last = 0;
271 int n;
272 for (n = 1; n < argc; n++)
273 {
274 if (strcmp(argv[n], "-1") == 0)
275 ascii1 = argv[n+1];
276 if (strcmp(argv[n], "-2") == 0)
277 ascii2 = argv[n+1];
278 if (strcmp(argv[n], "-o") == 0)
279 outfile = argv[n+1];
280 if (strcmp(argv[n], "-ids") == 0)
281 show_fwids();
282 }
283 if (ascii1 == NULL || ascii2 == NULL || outfile == NULL)
284 showhelp();
285 of = fopen(outfile, "w");
286 if (of == NULL)
287 oferror(of);
288 for (n = 1; n < argc; n++)
289 {
290 if (strncmp(argv[n], "-", 1) != 0)
291 {
292 type = argv[n++];
293 if (n >= argc)
294 showhelp();
295 last = ((n + 1) >= argc); /* dirty, options first! */
296 info = find_hdrinfo(type);
297 if (info == NULL)
298 showhelp();
299 data = read_file(argv[n], &size);
300 if (data == NULL)
301 showhelp();
302 makehdr(hdr, info, data, size, last);
303 /* showhdr(hdr); */
304 if (fwrite(hdr, HDRSIZE, 1, of) != 1)
305 oferror(of);
306 if (fwrite(data, size, 1, of) != 1)
307 oferror(of);
308 free(data);
309 }
310 else
311 n++;
312 }
313 if (fclose(of) != 0)
314 oferror(NULL);
315 return 0;
316 }