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