Add firmware generation for other Compex boards based on myloader, thanks to Juhos...
[openwrt/staging/yousong.git] / tools / firmware-utils / src / mkmylofw.c
1 /*
2 * Copyright (C) 2006,2007 Gabor Juhos
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <stdint.h>
14 #include <string.h>
15 #include <unistd.h> /* for unlink() */
16 #include <libgen.h>
17 #include <getopt.h> /* for getopt() */
18 #include <stdarg.h>
19 #include <errno.h>
20 #include <sys/stat.h>
21 #include <endian.h> /* for __BYTE_ORDER */
22
23 #if defined(__CYGWIN__)
24 # include <byteswap.h>
25 #endif
26
27 #if (__BYTE_ORDER == __LITTLE_ENDIAN)
28 # define HOST_TO_LE16(x) (x)
29 # define HOST_TO_LE32(x) (x)
30 #else
31 # define HOST_TO_LE16(x) bswap_16(x)
32 # define HOST_TO_LE32(x) bswap_32(x)
33 #endif
34
35 #include "myloader.h"
36
37 #define MAX_FW_BLOCKS 32
38 #define MAX_ARG_COUNT 32
39 #define MAX_ARG_LEN 1024
40 #define FILE_BUF_LEN (16*1024)
41
42 struct fw_block {
43 uint32_t addr;
44 uint32_t blocklen; /* length of the block */
45 uint32_t flags;
46
47 char *name; /* name of the file */
48 uint32_t size; /* length of the file */
49 uint32_t crc; /* crc value of the file */
50 };
51
52 #define BLOCK_FLAG_HAVEHDR 0x0001
53
54 struct cpx_board {
55 char *model; /* model number*/
56 char *name; /* model name*/
57 char *desc; /* description */
58 uint16_t vid; /* vendor id */
59 uint16_t did; /* device id */
60 uint16_t svid; /* sub vendor id */
61 uint16_t sdid; /* sub device id */
62 uint32_t flash_size; /* size of flash */
63 };
64
65 #define BOARD(_vid, _did, _svid, _sdid, _flash, _mod, _name, _desc) { \
66 .model = _mod, .name = _name, .desc = _desc, \
67 .vid = _vid, .did = _did, .svid = _svid, .sdid = _sdid, \
68 .flash_size = (_flash << 20) }
69
70 #define CPX_BOARD(_did, _flash, _mod, _name, _desc) \
71 BOARD(VENID_COMPEX, _did, VENID_COMPEX, _did, _flash, _mod, _name, _desc)
72
73 char *progname;
74 char *ofname = NULL;
75
76 uint32_t flash_size = 0;
77 int fw_num_partitions = 0;
78 int fw_num_blocks = 0;
79 int verblevel = 0;
80
81 struct mylo_fw_header fw_header;
82 struct mylo_partition fw_partitions[MYLO_MAX_PARTITIONS];
83 struct fw_block fw_blocks[MAX_FW_BLOCKS];
84
85 struct cpx_board boards[] = {
86 CPX_BOARD(DEVID_COMPEX_NP18A, 4,
87 "NP18A", "Compex NetPassage 18A",
88 "Dualband Wireless A+G Internet Gateway"),
89 CPX_BOARD(DEVID_COMPEX_NP26G8M, 2,
90 "NP26G8M", "Compex NetPassage 26G (8M)",
91 "Wireless-G Broadband Multimedia Gateway"),
92 CPX_BOARD(DEVID_COMPEX_NP26G16M, 4,
93 "NP26G16M", "Compex NetPassage 26G (16M)",
94 "Wireless-G Broadband Multimedia Gateway"),
95 CPX_BOARD(DEVID_COMPEX_NP27G, 4,
96 "NP27G", "Compex NetPassage 27G",
97 "Wireless-G 54Mbps eXtended Range Router"),
98 CPX_BOARD(DEVID_COMPEX_NP28G, 4,
99 "NP28G", "Compex NetPassage 28G",
100 "Wireless 108Mbps Super-G XR Multimedia Router with 4 USB Ports"),
101 CPX_BOARD(DEVID_COMPEX_NP28GHS, 4,
102 "NP28GHS", "Compex NetPassage 28G (HotSpot)",
103 "HotSpot Solution"),
104 CPX_BOARD(DEVID_COMPEX_WP18, 4,
105 "WP18", "Compex NetPassage WP18",
106 "Wireless-G 54Mbps A+G Dualband Access Point"),
107 CPX_BOARD(DEVID_COMPEX_WP54G, 4,
108 "WP54G", "Compex WP54G",
109 "Wireless-G 54Mbps XR Access Point"),
110 CPX_BOARD(DEVID_COMPEX_WP54Gv1C, 2,
111 "WP54Gv1C", "Compex WP54G rev.1C",
112 "Wireless-G 54Mbps XR Access Point"),
113 CPX_BOARD(DEVID_COMPEX_WP54AG, 4,
114 "WP54AG", "Compex WP54AG",
115 "Wireless-AG 54Mbps XR Access Point"),
116 CPX_BOARD(DEVID_COMPEX_WPP54G, 4,
117 "WPP54G", "Compex WPP54G",
118 "Outdoor Access Point"),
119 CPX_BOARD(DEVID_COMPEX_WPP54AG, 4,
120 "WPP54AG", "Compex WPP54AG",
121 "Outdoor Access Point"),
122 {.model = NULL}
123 };
124
125 void
126 errmsgv(int syserr, const char *fmt, va_list arg_ptr)
127 {
128 int save = errno;
129
130 fflush(0);
131 fprintf(stderr, "[%s] Error: ", progname);
132 vfprintf(stderr, fmt, arg_ptr);
133 if (syserr != 0) {
134 fprintf(stderr, ": %s", strerror(save));
135 }
136 fprintf(stderr, "\n");
137 }
138
139 void
140 errmsg(int syserr, const char *fmt, ...)
141 {
142 va_list arg_ptr;
143 va_start(arg_ptr, fmt);
144 errmsgv(syserr, fmt, arg_ptr);
145 va_end(arg_ptr);
146 }
147
148 void
149 dbgmsg(int level, const char *fmt, ...)
150 {
151 va_list arg_ptr;
152 if (verblevel >= level) {
153 fflush(0);
154 va_start(arg_ptr, fmt);
155 vfprintf(stderr, fmt, arg_ptr);
156 fprintf(stderr, "\n");
157 va_end(arg_ptr);
158 }
159 }
160
161
162 void
163 usage(int status)
164 {
165 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
166 struct cpx_board *board;
167
168 fprintf(stream, "Usage: %s [OPTION...] <file>\n", progname);
169 fprintf(stream,
170 "\n"
171 " <file> write output to the <file>\n"
172 "\n"
173 "Options:\n"
174 " -B <board> create firmware for the board specified with <board>.\n"
175 " This option set vendor id, device id, subvendor id,\n"
176 " subdevice id, and flash size options to the right value.\n"
177 " valid <board> values:\n");
178 for (board = boards; board->model != NULL; board++){
179 fprintf(stream,
180 " %-12s: %s\n",
181 board->model, board->name);
182 };
183 fprintf(stream,
184 " -i <vid>:<did>[:<svid>[:<sdid>]]\n"
185 " create firmware for board with vendor id <vid>, device\n"
186 " id <did>, subvendor id <svid> and subdevice id <sdid>.\n"
187 " -r <rev> set board revision to <rev>.\n"
188 " -s <size> set flash size to <size>\n"
189 " -b <addr>:<len>[:[<flags>]:<file>]\n"
190 " define block at <addr> with length of <len>.\n"
191 " valid <flag> values:\n"
192 " h : add crc header before the file data.\n"
193 " -p <addr>:<len>[:<flags>[:<param>[:<file>]]]\n"
194 " add partition at <addr>, with size of <len> to the\n"
195 " partition table, set partition flags to <flags> and\n"
196 " partition parameter to <param>. If the <file> is specified\n"
197 " content of the file is also added to the firmware image.\n"
198 " valid <flag> values:\n"
199 " a: this is the active partition. The bootloader loads\n"
200 " the firmware from this partition.\n"
201 " h: the partition data have a header.\n"
202 " p: the bootloader loads data from this partition to\n"
203 " the RAM before decompress it.\n"
204 " -h show this screen\n"
205 );
206
207 exit(status);
208 }
209
210 /*
211 * Code to compute the CRC-32 table. Borrowed from
212 * gzip-1.0.3/makecrc.c.
213 */
214
215 static uint32_t crc_32_tab[256];
216
217 void
218 init_crc_table(void)
219 {
220 /* Not copyrighted 1990 Mark Adler */
221
222 uint32_t c; /* crc shift register */
223 uint32_t e; /* polynomial exclusive-or pattern */
224 int i; /* counter for all possible eight bit values */
225 int k; /* byte being shifted into crc apparatus */
226
227 /* terms of polynomial defining this crc (except x^32): */
228 static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
229
230 /* Make exclusive-or pattern from polynomial */
231 e = 0;
232 for (i = 0; i < sizeof(p)/sizeof(int); i++)
233 e |= 1L << (31 - p[i]);
234
235 crc_32_tab[0] = 0;
236
237 for (i = 1; i < 256; i++) {
238 c = 0;
239 for (k = i | 256; k != 1; k >>= 1) {
240 c = c & 1 ? (c >> 1) ^ e : c >> 1;
241 if (k & 1)
242 c ^= e;
243 }
244 crc_32_tab[i] = c;
245 }
246 }
247
248
249 void
250 update_crc(uint8_t *p, uint32_t len, uint32_t *crc)
251 {
252 uint32_t t;
253
254 t = *crc ^ 0xFFFFFFFFUL;
255 while (len--) {
256 t = crc_32_tab[(t ^ *p++) & 0xff] ^ (t >> 8);
257 }
258 *crc = t ^ 0xFFFFFFFFUL;
259 }
260
261
262 uint32_t
263 get_crc(uint8_t *p, uint32_t len)
264 {
265 uint32_t crc;
266
267 crc = 0;
268 update_crc(p ,len , &crc);
269 return crc;
270 }
271
272
273 int
274 str2u32(char *arg, uint32_t *val)
275 {
276 char *err = NULL;
277 uint32_t t;
278
279 errno=0;
280 t = strtoul(arg, &err, 0);
281 if (errno || (err==arg) || ((err != NULL) && *err)) {
282 return -1;
283 }
284
285 *val = t;
286 return 0;
287 }
288
289
290 int
291 str2u16(char *arg, uint16_t *val)
292 {
293 char *err = NULL;
294 uint32_t t;
295
296 errno=0;
297 t = strtoul(arg, &err, 0);
298 if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
299 return -1;
300 }
301
302 *val = t & 0xFFFF;
303 return 0;
304 }
305
306
307 struct cpx_board *
308 find_board(char *model){
309 struct cpx_board *board;
310 struct cpx_board *tmp;
311
312 board = NULL;
313 for (tmp = boards; tmp->model != NULL; tmp++){
314 if (strcmp(model, tmp->model) == 0) {
315 board = tmp;
316 break;
317 }
318 };
319
320 return board;
321 }
322
323
324 int
325 get_file_crc(struct fw_block *ff)
326 {
327 FILE *f;
328 uint8_t buf[FILE_BUF_LEN];
329 uint32_t readlen = sizeof(buf);
330 int res = -1;
331 size_t len;
332
333 if ((ff->flags & BLOCK_FLAG_HAVEHDR) == 0) {
334 res = 0;
335 goto out;
336 }
337
338 errno = 0;
339 f = fopen(ff->name,"r");
340 if (errno) {
341 errmsg(1,"unable to open file %s", ff->name);
342 goto out;
343 }
344
345 ff->crc = 0;
346 len = ff->size;
347 while (len > 0) {
348 if (len < readlen)
349 readlen = len;
350
351 errno = 0;
352 fread(buf, readlen, 1, f);
353 if (errno) {
354 errmsg(1,"unable to read from file %s", ff->name);
355 goto out_close;
356 }
357
358 update_crc(buf, readlen, &ff->crc);
359 len -= readlen;
360 }
361
362 res = 0;
363
364 out_close:
365 fclose(f);
366 out:
367 return res;
368 }
369
370
371 int
372 process_files(void)
373 {
374 struct fw_block *b;
375 struct stat st;
376 int i;
377
378 for (i = 0; i < fw_num_blocks; i++) {
379 b = &fw_blocks[i];
380 if ((b->addr + b->blocklen) > flash_size) {
381 errmsg(0, "block at 0x%08X is too big", b->addr);
382 return -1;
383 }
384 if (b->name == NULL)
385 continue;
386
387 if (stat(b->name, &st) < 0) {
388 errmsg(0, "stat failed on %s",b->name);
389 return -1;
390 }
391 if (b->blocklen == 0) {
392 b->blocklen = flash_size - b->addr;
393 }
394 if (st.st_size > b->blocklen) {
395 errmsg(0,"file %s is too big",b->name);
396 return -1;
397 }
398
399 b->size = st.st_size;
400 }
401
402 return 0;
403 }
404
405
406 int
407 process_partitions(void)
408 {
409 struct mylo_partition *part;
410 int i;
411
412 for (i = 0; i < fw_num_partitions; i++) {
413 part = &fw_partitions[i];
414
415 if (part->addr > flash_size) {
416 errmsg(0, "invalid partition at 0x%08X", part->addr);
417 return -1;
418 }
419
420 if ((part->addr + part->size) > flash_size) {
421 errmsg(0, "partition at 0x%08X is too big", part->addr);
422 return -1;
423 }
424 }
425
426 return 0;
427 }
428
429
430 /*
431 * routines to write data to the output file
432 */
433 int
434 write_out_data(FILE *outfile, uint8_t *data, size_t len, uint32_t *crc)
435 {
436 errno = 0;
437
438 fwrite(data, len, 1, outfile);
439 if (errno) {
440 errmsg(1,"unable to write output file");
441 return -1;
442 }
443
444 if (crc) {
445 update_crc(data, len, crc);
446 }
447
448 return 0;
449 }
450
451
452 inline int
453 write_out_desc(FILE *outfile, struct mylo_fw_blockdesc *desc, uint32_t *crc)
454 {
455 return write_out_data(outfile, (uint8_t *)desc,
456 sizeof(*desc), crc);
457 }
458
459
460 int
461 write_out_file(FILE *outfile, struct fw_block *block, uint32_t *crc)
462 {
463 char buff[FILE_BUF_LEN];
464 size_t buflen = sizeof(buff);
465 FILE *f;
466 size_t len;
467
468 errno = 0;
469
470 if (block->name == NULL) {
471 return 0;
472 }
473
474 if ((block->flags & BLOCK_FLAG_HAVEHDR) != 0) {
475 struct mylo_partition_header ph;
476
477 if (get_file_crc(block) != 0)
478 return -1;
479
480 ph.crc = HOST_TO_LE32(block->crc);
481 ph.len = HOST_TO_LE32(block->size);
482
483 if (write_out_data(outfile, (uint8_t *)&ph, sizeof(ph), crc) != 0)
484 return -1;
485 }
486
487 f = fopen(block->name,"r");
488 if (errno) {
489 errmsg(1,"unable to open file: %s", block->name);
490 return -1;
491 }
492
493 len = block->size;
494 while (len > 0) {
495 if (len < buflen)
496 buflen = len;
497
498 // read data from source file
499 errno = 0;
500 fread(buff, buflen, 1, f);
501 if (errno != 0) {
502 errmsg(1,"unable to read from file: %s",block->name);
503 return -1;
504 }
505
506 if (write_out_data(outfile, buff, buflen, crc) != 0)
507 return -1;
508
509 len -= buflen;
510 }
511
512 fclose(f);
513
514 dbgmsg(1,"file %s written out", block->name);
515 return 0;
516 }
517
518
519 int
520 write_out_header(FILE *outfile, uint32_t *crc)
521 {
522 struct mylo_fw_header hdr;
523
524 memset(&hdr, 0, sizeof(hdr));
525
526 hdr.magic = HOST_TO_LE32(MYLO_MAGIC_FIRMWARE);
527 hdr.crc = HOST_TO_LE32(fw_header.crc);
528 hdr.vid = HOST_TO_LE16(fw_header.vid);
529 hdr.did = HOST_TO_LE16(fw_header.did);
530 hdr.svid = HOST_TO_LE16(fw_header.svid);
531 hdr.sdid = HOST_TO_LE16(fw_header.sdid);
532 hdr.rev = HOST_TO_LE32(fw_header.rev);
533 hdr.fwhi = HOST_TO_LE32(fw_header.fwhi);
534 hdr.fwlo = HOST_TO_LE32(fw_header.fwlo);
535 hdr.flags = HOST_TO_LE32(fw_header.flags);
536
537 if (fseek(outfile, 0, SEEK_SET) != 0) {
538 errmsg(1,"fseek failed on output file");
539 return -1;
540 }
541
542 return write_out_data(outfile, (uint8_t *)&hdr, sizeof(hdr), crc);
543 }
544
545
546 int
547 write_out_partitions(FILE *outfile, uint32_t *crc)
548 {
549 struct mylo_partition_table p;
550 struct mylo_partition *p1, *p2;
551 int i;
552
553 if (fw_num_partitions == 0)
554 return 0;
555
556 memset(&p, 0, sizeof(p));
557
558 p.magic = HOST_TO_LE32(MYLO_MAGIC_PARTITIONS);
559 for (i = 0; i < fw_num_partitions; i++) {
560 p1 = &p.partitions[i];
561 p2 = &fw_partitions[i];
562 p1->flags = HOST_TO_LE16(p2->flags);
563 p1->type = HOST_TO_LE16(PARTITION_TYPE_USED);
564 p1->addr = HOST_TO_LE32(p2->addr);
565 p1->size = HOST_TO_LE32(p2->size);
566 p1->param = HOST_TO_LE32(p2->param);
567 }
568
569 return write_out_data(outfile, (uint8_t *)&p, sizeof(p), crc);
570 }
571
572
573 int
574 write_out_blocks(FILE *outfile, uint32_t *crc)
575 {
576 struct mylo_fw_blockdesc desc;
577 struct fw_block *b;
578 int i;
579
580 /*
581 * if at least one partition specified, write out block descriptor
582 * for the partition table
583 */
584 if (fw_num_partitions > 0) {
585
586 desc.type = HOST_TO_LE32(FW_DESC_TYPE_USED);
587 desc.addr = HOST_TO_LE32(0x10000);
588 desc.dlen = HOST_TO_LE32(sizeof(struct mylo_partition_table));
589 desc.blen = HOST_TO_LE32(0x10000);
590
591 if (write_out_desc(outfile, &desc, crc) != 0)
592 return -1;
593 }
594
595 /*
596 * write out block descriptors for each files
597 */
598 for (i = 0; i < fw_num_blocks; i++) {
599 b = &fw_blocks[i];
600 desc.type = HOST_TO_LE32(FW_DESC_TYPE_USED);
601 desc.addr = HOST_TO_LE32(b->addr);
602 desc.blen = HOST_TO_LE32(b->blocklen);
603 if ((b->flags & BLOCK_FLAG_HAVEHDR) != 0) {
604 desc.dlen = HOST_TO_LE32(b->size +
605 sizeof(struct mylo_partition_header));
606 } else {
607 desc.dlen = HOST_TO_LE32(b->size);
608 }
609 if (write_out_desc(outfile, &desc, crc) != 0)
610 return -1;
611 }
612
613 /*
614 * write out the null block descriptor
615 */
616 memset(&desc, 0, sizeof(desc));
617 if (write_out_desc(outfile, &desc, crc) != 0)
618 return -1;
619
620 if (write_out_partitions(outfile, crc) != 0)
621 return -1;
622
623 /*
624 * write out data for each blocks
625 */
626 for (i = 0; i < fw_num_blocks; i++) {
627 b = &fw_blocks[i];
628 if (write_out_file(outfile, b, crc) != 0)
629 return -1;
630 }
631
632 return 0;
633 }
634
635
636 /*
637 * argument parsing
638 */
639 int
640 parse_arg(char *arg, char *buf, char *argv[])
641 {
642 int res = 0;
643 size_t argl;
644 char *tok;
645 char **ap = &buf;
646 int i;
647
648 if ((arg == NULL)) {
649 /* invalid argument string */
650 return -1;
651 }
652
653 argl = strlen(arg);
654 if (argl == 0) {
655 /* no arguments */
656 return res;
657 }
658
659 if (argl >= MAX_ARG_LEN) {
660 /* argument is too long */
661 argl = MAX_ARG_LEN-1;
662 }
663
664 memset(argv, 0, MAX_ARG_COUNT * sizeof(void *));
665 memcpy(buf, arg, argl);
666 buf[argl] = '\0';
667
668 for (i = 0; i < MAX_ARG_COUNT; i++) {
669 tok = strsep(ap, ":");
670 if (tok == NULL) {
671 break;
672 }
673 #if 0
674 else if (tok[0] == '\0') {
675 break;
676 }
677 #endif
678 argv[i] = tok;
679 res++;
680 }
681
682 return res;
683 }
684
685
686 int
687 required_arg(char c, char *arg)
688 {
689 if ((optarg != NULL) && (*arg == '-')){
690 errmsg(0,"option %c requires an argument\n", c);
691 return -1;
692 }
693
694 return 0;
695 }
696
697
698 int
699 is_empty_arg(char *arg)
700 {
701 int ret = 1;
702 if (arg != NULL) {
703 if (*arg) ret = 0;
704 };
705 return ret;
706 }
707
708
709 int
710 parse_opt_flags(char ch, char *arg)
711 {
712 if (required_arg(ch, arg)) {
713 goto err_out;
714 }
715
716 if (str2u32(arg, &fw_header.flags) != 0) {
717 errmsg(0,"invalid firmware flags: %s", arg);
718 goto err_out;
719 }
720
721 dbgmsg(1, "firmware flags set to %X bytes", fw_header.flags);
722
723 return 0;
724
725 err_out:
726 return -1;
727 }
728
729
730 int
731 parse_opt_size(char ch, char *arg)
732 {
733 if (required_arg(ch, arg)) {
734 goto err_out;
735 }
736
737 if (str2u32(arg, &flash_size) != 0) {
738 errmsg(0,"invalid flash size: %s", arg);
739 goto err_out;
740 }
741
742 dbgmsg(1, "flash size set to %d bytes", flash_size);
743
744 return 0;
745
746 err_out:
747 return -1;
748 }
749
750
751 int
752 parse_opt_id(char ch, char *arg)
753 {
754 char buf[MAX_ARG_LEN];
755 char *argv[MAX_ARG_COUNT];
756 int argc;
757 char *p;
758
759 if (required_arg(ch, arg)) {
760 goto err_out;
761 }
762
763 argc = parse_arg(arg, buf, argv);
764
765 /* processing vendor ID*/
766 p = argv[0];
767 if (is_empty_arg(p)) {
768 errmsg(0,"vendor id is missing from -%c %s",ch, arg);
769 goto err_out;
770 } else if (str2u16(p, &fw_header.vid) != 0) {
771 errmsg(0,"invalid vendor id: %s", p);
772 goto err_out;
773 }
774
775 dbgmsg(1, "vendor id is set to 0x%04X", fw_header.vid);
776
777 /* processing device ID*/
778 p = argv[1];
779 if (is_empty_arg(p)) {
780 errmsg(0,"device id is missing from -%c %s",ch, arg);
781 goto err_out;
782 } else if (str2u16(p, &fw_header.did) != 0) {
783 errmsg(0,"invalid device id: %s", p);
784 goto err_out;
785 }
786
787 dbgmsg(1, "device id is set to 0x%04X", fw_header.did);
788
789 /* processing sub vendor ID*/
790 p = argv[2];
791 if (is_empty_arg(p)) {
792 fw_header.svid = fw_header.vid;
793 } else if (str2u16(p, &fw_header.svid) != 0) {
794 errmsg(0,"invalid sub vendor id: %s", p);
795 goto err_out;
796 }
797
798 dbgmsg(1, "sub vendor id is set to 0x%04X", fw_header.svid);
799
800 /* processing device ID*/
801 p = argv[3];
802 if (is_empty_arg(p)) {
803 fw_header.sdid = fw_header.did;
804 } else if (str2u16(p, &fw_header.sdid) != 0) {
805 errmsg(0,"invalid sub device id: %s", p);
806 goto err_out;
807 }
808
809 dbgmsg(1, "sub device id is set to 0x%04X", fw_header.sdid);
810
811 /* processing revision */
812 p = argv[4];
813 if (is_empty_arg(p)) {
814 fw_header.rev = 0;
815 } else if (str2u32(arg, &fw_header.rev) != 0) {
816 errmsg(0,"invalid revision number: %s", p);
817 goto err_out;
818 }
819
820 dbgmsg(1, "board revision is set to 0x%08X", fw_header.rev);
821
822 return 0;
823
824 err_out:
825 return -1;
826 }
827
828
829 int
830 parse_opt_block(char ch, char *arg)
831 {
832 char buf[MAX_ARG_LEN];
833 char *argv[MAX_ARG_COUNT];
834 int argc;
835 struct fw_block *b;
836 char *p;
837
838 if (required_arg(ch, arg)) {
839 goto err_out;
840 }
841
842 if (fw_num_blocks >= MAX_FW_BLOCKS) {
843 errmsg(0,"too many blocks specified");
844 goto err_out;
845 }
846
847 argc = parse_arg(arg, buf, argv);
848 dbgmsg(1,"processing block option %s, count %d", arg, argc);
849
850 b = &fw_blocks[fw_num_blocks++];
851
852 /* processing block address */
853 p = argv[0];
854 if (is_empty_arg(p)) {
855 errmsg(0,"no block address specified in %s", arg);
856 goto err_out;
857 } else if (str2u32(p, &b->addr) != 0) {
858 errmsg(0,"invalid block address: %s", p);
859 goto err_out;
860 }
861
862 /* processing block length */
863 p = argv[1];
864 if (is_empty_arg(p)) {
865 errmsg(0,"no block length specified in %s", arg);
866 goto err_out;
867 } else if (str2u32(p, &b->blocklen) != 0) {
868 errmsg(0,"invalid block length: %s", p);
869 goto err_out;
870 }
871
872 if (argc < 3) {
873 dbgmsg(1,"empty block %s", arg);
874 goto success;
875 }
876
877 /* processing flags */
878 p = argv[2];
879 if (is_empty_arg(p) == 0) {
880 for ( ; *p != '\0'; p++) {
881 switch (*p) {
882 case 'h':
883 b->flags |= BLOCK_FLAG_HAVEHDR;
884 break;
885 default:
886 errmsg(0, "invalid block flag \"%c\"", *p);
887 goto err_out;
888 }
889 }
890 }
891
892 /* processing file name */
893 p = argv[3];
894 if (is_empty_arg(p)) {
895 errmsg(0,"file name missing in %s", arg);
896 goto err_out;
897 }
898
899 b->name = strdup(p);
900 if (b->name == NULL) {
901 errmsg(0,"not enough memory");
902 goto err_out;
903 }
904
905 success:
906
907 return 0;
908
909 err_out:
910 return -1;
911 }
912
913
914 int
915 parse_opt_partition(char ch, char *arg)
916 {
917 char buf[MAX_ARG_LEN];
918 char *argv[MAX_ARG_COUNT];
919 int argc;
920 char *p;
921
922 struct mylo_partition *part;
923
924 if (required_arg(ch, arg)) {
925 goto err_out;
926 }
927
928 if (fw_num_partitions >= MYLO_MAX_PARTITIONS) {
929 errmsg(0, "too many partitions specified");
930 goto err_out;
931 }
932
933 part = &fw_partitions[fw_num_partitions++];
934
935 argc = parse_arg(arg, buf, argv);
936
937 /* processing partition address */
938 p = argv[0];
939 if (is_empty_arg(p)) {
940 errmsg(0,"partition address missing in -%c %s",ch, arg);
941 goto err_out;
942 } else if (str2u32(p, &part->addr) != 0) {
943 errmsg(0,"invalid partition address: %s", p);
944 goto err_out;
945 }
946
947 /* processing partition size */
948 p = argv[1];
949 if (is_empty_arg(p)) {
950 errmsg(0,"partition size missing in -%c %s",ch, arg);
951 goto err_out;
952 } else if (str2u32(p, &part->size) != 0) {
953 errmsg(0,"invalid partition size: %s", p);
954 goto err_out;
955 }
956
957 /* processing partition flags */
958 p = argv[2];
959 if (is_empty_arg(p) == 0) {
960 for ( ; *p != '\0'; p++) {
961 switch (*p) {
962 case 'a':
963 part->flags |= PARTITION_FLAG_ACTIVE;
964 break;
965 case 'p':
966 part->flags |= PARTITION_FLAG_PRELOAD;
967 break;
968 case 'h':
969 part->flags |= PARTITION_FLAG_HAVEHDR;
970 break;
971 default:
972 errmsg(0, "invalid partition flag \"%c\"", *p);
973 goto err_out;
974 }
975 }
976 }
977
978 /* processing partition parameter */
979 p = argv[3];
980 if (is_empty_arg(p)) {
981 /* set default partition parameter */
982 part->param = 0;
983 } else if (str2u32(p, &part->param) != 0) {
984 errmsg(0,"invalid partition parameter: %s", p);
985 goto err_out;
986 }
987
988 #if 1
989 if (part->size == 0) {
990 part->size = flash_size - part->addr;
991 }
992
993 /* processing file parameter */
994 p = argv[4];
995 if (is_empty_arg(p) == 0) {
996 struct fw_block *b;
997
998 if (fw_num_blocks == MAX_FW_BLOCKS) {
999 errmsg(0,"too many blocks specified", p);
1000 goto err_out;
1001 }
1002 b = &fw_blocks[fw_num_blocks++];
1003 b->name = strdup(p);
1004 b->addr = part->addr;
1005 b->blocklen = part->size;
1006 if (part->flags & PARTITION_FLAG_HAVEHDR) {
1007 b->flags |= BLOCK_FLAG_HAVEHDR;
1008 }
1009 }
1010 #endif
1011
1012 return 0;
1013
1014 err_out:
1015 return -1;
1016 }
1017
1018
1019 int
1020 parse_opt_board(char ch, char *arg)
1021 {
1022 struct cpx_board *board;
1023
1024 if (required_arg(ch, arg)) {
1025 goto err_out;
1026 }
1027
1028 board = find_board(arg);
1029 if (board == NULL){
1030 errmsg(0,"invalid/unknown board specified: %s", arg);
1031 goto err_out;
1032 }
1033
1034 fw_header.vid = board->vid;
1035 fw_header.did = board->did;
1036 fw_header.svid = board->svid;
1037 fw_header.sdid = board->sdid;
1038
1039 flash_size = board->flash_size;
1040
1041 return 0;
1042
1043 err_out:
1044 return -1;
1045 }
1046
1047
1048 int
1049 parse_opt_rev(char ch, char *arg)
1050 {
1051 if (required_arg(ch, arg)) {
1052 return -1;
1053 }
1054
1055 if (str2u32(arg, &fw_header.rev) != 0) {
1056 errmsg(0,"invalid revision number: %s", arg);
1057 return -1;
1058 }
1059
1060 return 0;
1061 }
1062
1063
1064 /*
1065 * main
1066 */
1067 int
1068 main(int argc, char *argv[])
1069 {
1070 int optinvalid = 0; /* flag for invalid option */
1071 int c;
1072 int res = EXIT_FAILURE;
1073
1074 FILE *outfile;
1075 uint32_t crc;
1076
1077 progname=basename(argv[0]);
1078
1079 memset(&fw_header, 0, sizeof(fw_header));
1080
1081 /* init header defaults */
1082 fw_header.vid = VENID_COMPEX;
1083 fw_header.did = DEVID_COMPEX_WP54G;
1084 fw_header.svid = VENID_COMPEX;
1085 fw_header.sdid = DEVID_COMPEX_WP54G;
1086 fw_header.fwhi = 0x20000;
1087 fw_header.fwlo = 0x20000;
1088 fw_header.flags = 0;
1089
1090 opterr = 0; /* could not print standard getopt error messages */
1091 while ((c = getopt(argc, argv, "b:B:f:hi:p:r:s:v")) != -1) {
1092 optinvalid = 0;
1093 switch (c) {
1094 case 'b':
1095 optinvalid = parse_opt_block(c,optarg);
1096 break;
1097 case 'B':
1098 optinvalid = parse_opt_board(c,optarg);
1099 break;
1100 case 'f':
1101 optinvalid = parse_opt_flags(c,optarg);
1102 break;
1103 case 'h':
1104 usage(EXIT_SUCCESS);
1105 break;
1106 case 'i':
1107 optinvalid = parse_opt_id(c,optarg);
1108 break;
1109 case 'p':
1110 optinvalid = parse_opt_partition(c,optarg);
1111 break;
1112 case 'r':
1113 optinvalid = parse_opt_rev(c,optarg);
1114 break;
1115 case 's':
1116 optinvalid = parse_opt_size(c,optarg);
1117 break;
1118 case 'v':
1119 verblevel++;
1120 break;
1121 default:
1122 optinvalid = 1;
1123 break;
1124 }
1125 if (optinvalid != 0 ){
1126 errmsg(0, "invalid option: -%c", optopt);
1127 goto out;
1128 }
1129 }
1130
1131 if (optind == argc) {
1132 errmsg(0, "no output file specified");
1133 goto out;
1134 }
1135
1136 ofname = argv[optind++];
1137
1138 if (optind < argc) {
1139 errmsg(0, "invalid option: %s", argv[optind]);
1140 goto out;
1141 }
1142
1143 if (flash_size == 0) {
1144 errmsg(0, "no flash size specified");
1145 goto out;
1146 }
1147
1148 if (process_files() != 0) {
1149 goto out;
1150 }
1151
1152 if (process_partitions() != 0) {
1153 goto out;
1154 }
1155
1156 outfile = fopen(ofname, "w");
1157 if (outfile == NULL) {
1158 errmsg(1, "could not open \"%s\" for writing", ofname);
1159 goto out;
1160 }
1161
1162 crc = 0;
1163 init_crc_table();
1164
1165 if (write_out_header(outfile, &crc) != 0)
1166 goto out_flush;
1167
1168 if (write_out_blocks(outfile, &crc) != 0)
1169 goto out_flush;
1170
1171 fw_header.crc = crc;
1172 if (write_out_header(outfile, NULL) != 0)
1173 goto out_flush;
1174
1175 dbgmsg(1,"Firmware file %s completed.", ofname);
1176
1177 res = EXIT_SUCCESS;
1178
1179 out_flush:
1180 fflush(outfile);
1181 fclose(outfile);
1182 if (res != EXIT_SUCCESS) {
1183 unlink(ofname);
1184 }
1185 out:
1186 return res;
1187 }