Root/tools/firmware-utils/src/mkmylofw.c

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

Archive Download this file



interactive