Add ADM5120 based edimax image generation utilities
[openwrt.git] / tools / firmware-utils / src / mkcsysimg.c
1 /*
2  *  $Id$
3  *
4  *  Copyright (C) 2007 Gabor Juhos <juhosg@freemail.hu>
5  *
6  *  This program was based on the code found in various Linux 
7  *  source tarballs released by Edimax for it's devices.
8  *  Original author: David Hsu <davidhsu@realtek.com.tw>
9  *
10  *  This program is free software; you can redistribute it and/or
11  *  modify it under the terms of the GNU General Public License
12  *  as published by the Free Software Foundation; either version 2
13  *  of the License, or (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the
22  *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  *  Boston, MA  02110-1301, USA.
24  */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stdint.h>
29 #include <string.h>
30 #include <unistd.h>     /* for unlink() */
31 #include <libgen.h>
32 #include <getopt.h>     /* for getopt() */
33 #include <stdarg.h>
34 #include <errno.h>
35 #include <sys/stat.h>
36 #include <endian.h>     /* for __BYTE_ORDER */
37 #if defined(__CYGWIN__)
38 #  include <byteswap.h>
39 #endif
40
41 #include "csysimg.h"
42
43 #if (__BYTE_ORDER == __LITTLE_ENDIAN)
44 #  define HOST_TO_LE16(x)       (x)
45 #  define HOST_TO_LE32(x)       (x)
46 #  define LE16_TO_HOST(x)       (x)
47 #  define LE32_TO_HOST(x)       (x)
48 #else
49 #  define HOST_TO_LE16(x)       bswap_16(x)
50 #  define HOST_TO_LE32(x)       bswap_32(x)
51 #  define LE16_TO_HOST(x)       bswap_16(x)
52 #  define LE32_TO_HOST(x)       bswap_32(x)
53 #endif
54
55 #define ALIGN(x,y)      ((x)+((y)-1)) & ~((y)-1)
56
57 #define MAX_NUM_BLOCKS  8
58 #define MAX_ARG_COUNT   32
59 #define MAX_ARG_LEN     1024
60 #define FILE_BUF_LEN    (16*1024)
61 #define CSYS_PADC       0xFF
62
63 #define BLOCK_TYPE_BOOT 0
64 #define BLOCK_TYPE_CONF 1
65 #define BLOCK_TYPE_WEBP 2
66 #define BLOCK_TYPE_CODE 3
67 #define BLOCK_TYPE_XTRA 4
68
69
70 struct csum_state{
71         int     size;
72         uint16_t val;
73         uint16_t tmp;
74         int     odd;
75 };
76
77
78 struct csys_block {
79         int             type;   /* type of the block */
80
81         int             need_file;
82         char            *file_name;     /* name of the file */
83         uint32_t        file_size;      /* length of the file */
84
85         uint32_t        size;
86         int             size_set;
87         uint8_t         padc;
88
89         uint32_t        size_hdr;
90         uint32_t        size_csum;
91         uint32_t        size_avail;
92
93         unsigned char   sig[SIG_LEN];
94         uint32_t        addr;
95         int             addr_set;
96         struct csum_state *css;
97 };
98
99
100 struct board_info {
101         char *model;
102         char *name;
103         uint32_t flash_size;
104
105         char sig_boot[SIG_LEN];
106         char sig_conf[SIG_LEN];
107         char sig_webp[SIG_LEN];
108
109         uint32_t boot_size;
110         uint32_t conf_size;
111         uint32_t webp_size;
112         uint32_t webp_size_max;
113         uint32_t code_size;
114         
115         uint32_t addr_code;
116         uint32_t addr_webp;
117 };
118
119 #define BOARD(m, n, f, sigb, sigw, bs, cs, ws, ac, aw) {\
120         .model = m, .name = n, .flash_size = f<<20, \
121         .sig_boot = sigb, .sig_conf = SIG_CONF, .sig_webp = sigw, \
122         .boot_size = bs, .conf_size = cs, \
123         .webp_size = ws, .webp_size_max = 3*0x10000, \
124         .addr_code = ac, .addr_webp = aw \
125         }
126         
127 #define BOARD_ADM(m,n,f, sigw) BOARD(m,n,f, ADM_BOOT_SIG, sigw, \
128         ADM_BOOT_SIZE, ADM_CONF_SIZE, ADM_WEBP_SIZE, \
129         ADM_CODE_ADDR, ADM_WEBP_ADDR)
130
131
132 /*
133  * Globals
134  */
135 char *progname;
136 char *ofname = NULL;
137 int verblevel = 0;
138 int size_check = 1;
139
140 struct board_info *board = NULL;
141
142 struct csys_block *boot_block = NULL;
143 struct csys_block *conf_block = NULL;
144 struct csys_block *webp_block = NULL;
145 struct csys_block *code_block = NULL;
146
147 struct csys_block blocks[MAX_NUM_BLOCKS];
148 int num_blocks = 0;
149
150
151 static struct board_info boards[] = {
152         /* The original Edimax products */
153         BOARD_ADM("BR-6104K", "Edimax BR-6104K", 2, SIG_BR6104K),
154         BOARD_ADM("BR-6104KP", "Edimax BR-6104KP", 2, SIG_BR6104KP),
155         BOARD_ADM("BR-6114WG", "Edimax BR-6114WG", 2, SIG_BR6114WG),
156         BOARD_ADM("BR-6524K", "Edimax BR-6524K", 2, SIG_BR6524K),
157         BOARD_ADM("BR-6524KP", "Edimax BR-6524KP", 2, SIG_BR6524KP),
158         BOARD_ADM("BR-6524WG", "Edimax BR-6524WG", 4, SIG_BR6524WG),
159         BOARD_ADM("BR-6524WP", "Edimax BR-6524WP", 4, SIG_BR6524WP),
160         BOARD_ADM("BR-6541K", "Edimax BR-6541K", 2, SIG_BR6541K),
161         BOARD_ADM("BR-6541KP", "Edimax BR-6541K", 2, SIG_BR6541KP),
162         BOARD_ADM("BR-6541WP", "Edimax BR-6541WP", 4, SIG_BR6541WP),
163         BOARD_ADM("EW-7207APg", "Edimax EW-7207APg", 2, SIG_EW7207APg),
164         BOARD_ADM("PS-1205UWg", "Edimax PS-1205UWg", 2, SIG_PS1205UWg),
165         BOARD_ADM("PS-3205U", "Edimax PS-3205U", 2, SIG_PS3205U),
166         BOARD_ADM("PS-3205UWg", "Edimax PS-3205UWg", 2, SIG_PS3205UWg),
167
168         /* Hawking products */
169         BOARD_ADM("H2BR4", "Hawking H2BR4", 2, SIG_H2BR4),
170         BOARD_ADM("H2WR54G", "Hawking H2WR54G", 4, SIG_H2WR54G),
171
172         /* Planet products */
173         BOARD_ADM("XRT-401D", "Planet XRT-401D", 2, SIG_XRT401D),
174         BOARD_ADM("XRT-402D", "Planet XRT-402D", 2, SIG_XRT402D),
175         
176         {.model = NULL}
177 };
178
179 /*
180  * Helper routines
181  */
182 void
183 errmsgv(int syserr, const char *fmt, va_list arg_ptr)
184 {
185         int save = errno;
186
187         fflush(0);
188         fprintf(stderr, "%s: error, ", progname);
189         vfprintf(stderr, fmt, arg_ptr);
190         if (syserr != 0) {
191                 fprintf(stderr, " (%s)", strerror(save));
192         }
193         fprintf(stderr, "\n");
194 }
195
196 void
197 errmsg(int syserr, const char *fmt, ...)
198 {
199         va_list arg_ptr;
200         va_start(arg_ptr, fmt);
201         errmsgv(syserr, fmt, arg_ptr);
202         va_end(arg_ptr);
203 }
204
205 void
206 dbgmsg(int level, const char *fmt, ...)
207 {
208         va_list arg_ptr;
209         if (verblevel >= level) {
210                 fflush(0);
211                 va_start(arg_ptr, fmt);
212                 vfprintf(stderr, fmt, arg_ptr);
213                 fprintf(stderr, "\n");
214                 va_end(arg_ptr);
215         }
216 }
217
218
219 void
220 usage(int status)
221 {
222         FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
223         struct board_info *board;
224
225         fprintf(stream, "Usage: %s [OPTIONS...] <file>\n", progname);
226         fprintf(stream,
227 "\n"
228 "Options:\n"
229 "  -B <board>      create image for the board specified with <board>.\n"
230 "                  valid <board> values:\n"
231         );
232         for (board = boards; board->model != NULL; board++){
233                 fprintf(stream,
234 "               %-12s: %s\n",
235                  board->model, board->name);
236         };
237         fprintf(stream,
238 "  -d              disable check for available space\n"
239 "                  add boot code to the image\n"
240 "  -b <file>[:<len>[:<padc>]]\n"
241 "                  add boot code to the image\n"
242 "  -c <file>[:<len>[:<padc>]]\n"
243 "                  add configuration settings to the image\n"
244 "  -r <file>:[<addr>][:<len>[:<padc>]]\n"
245 "                  add runtime code to the image"
246 "  -w [<file>:[<addr>][:<len>[:<padc>]]]\n"
247 "                  add webpages to the image"
248 "  -x <file>[:<len>[:<padc>]]\n"
249 "                  add extra data at the end of the image\n"
250 "  -h              show this screen\n"
251 "Parameters:\n"
252 "  <file>          write output to the file <file>\n"
253         );
254
255         exit(status);
256 }
257
258
259 /*
260  * argument parsing
261  */
262 int
263 str2u32(char *arg, uint32_t *val)
264 {
265         char *err = NULL;
266         uint32_t t;
267         
268         errno=0;
269         t = strtoul(arg, &err, 0);
270         if (errno || (err==arg) || ((err != NULL) && *err)) {
271                 return -1;
272         }
273
274         *val = t;
275         return 0;
276 }
277
278
279 int
280 str2u16(char *arg, uint16_t *val)
281 {
282         char *err = NULL;
283         uint32_t t;
284
285         errno=0;
286         t = strtoul(arg, &err, 0);
287         if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
288                 return -1;
289         }
290         
291         *val = t & 0xFFFF;
292         return 0;
293 }
294
295 int
296 str2u8(char *arg, uint8_t *val)
297 {
298         char *err = NULL;
299         uint32_t t;
300
301         errno=0;
302         t = strtoul(arg, &err, 0);
303         if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
304                 return -1;
305         }
306         
307         *val = t & 0xFF;
308         return 0;
309 }
310
311 int
312 str2sig(char *arg, uint32_t *sig)
313 {
314         if (strlen(arg) != 4)
315                 return -1;
316
317         *sig = arg[0] | (arg[1] << 8) | (arg[2] << 16) | (arg[3] << 24);
318         
319         return 0;
320 }
321
322
323 int
324 parse_arg(char *arg, char *buf, char *argv[])
325 {
326         int res = 0;
327         size_t argl;
328         char *tok;
329         char **ap = &buf;
330         int i;
331
332         memset(argv, 0, MAX_ARG_COUNT * sizeof(void *));
333
334         if ((arg == NULL)) {
335                 /* no arguments */
336                 return 0;
337         }
338
339         argl = strlen(arg);
340         if (argl == 0) {
341                 /* no arguments */
342                 return 0;
343         }
344
345         if (argl >= MAX_ARG_LEN) {
346                 /* argument is too long */
347                 argl = MAX_ARG_LEN-1;
348         }
349
350         memcpy(buf, arg, argl);
351         buf[argl] = '\0';
352
353         for (i = 0; i < MAX_ARG_COUNT; i++) {
354                 tok = strsep(ap, ":");
355                 if (tok == NULL) {
356                         break;
357                 }
358 #if 0
359                 else if (tok[0] == '\0') {
360                         break;
361                 }
362 #endif
363                 argv[i] = tok;
364                 res++;
365         }
366
367         return res;
368 }
369
370
371 int
372 required_arg(char c, char *arg)
373 {
374         if (arg == NULL || *arg != '-')
375                 return 0;
376
377         errmsg(0,"option -%c requires an argument\n", c);
378         return -1;
379 }
380
381
382 int
383 is_empty_arg(char *arg)
384 {
385         int ret = 1;
386         if (arg != NULL) {
387                 if (*arg) ret = 0;
388         };
389         return ret;
390 }
391
392
393 void
394 csum8_update(uint8_t *p, uint32_t len, struct csum_state *css)
395 {
396         for ( ; len > 0; len --) {
397                 css->val += *p++;
398         }
399 }
400
401
402 uint16_t
403 csum8_get(struct csum_state *css)
404 {
405         uint8_t t;
406         
407         t = css->val;
408         return ~t + 1;
409 }
410
411
412 void
413 csum16_update(uint8_t *p, uint32_t len, struct csum_state *css)
414 {
415         uint16_t t;
416         
417         if (css->odd) {
418                 t = css->tmp + (p[0]<<8);
419                 css->val += LE16_TO_HOST(t);
420                 css->odd = 0;
421                 len--;
422                 p++;
423         }
424         
425         for ( ; len > 1; len -= 2, p +=2 ) {
426                 t = p[0] + (p[1] << 8);
427                 css->val += LE16_TO_HOST(t);
428         }
429
430         if (len == 1) {
431                 css->tmp = p[0];
432                 css->odd = 1;
433         }
434 }
435
436
437 uint16_t
438 csum16_get(struct csum_state *css)
439 {
440         char pad = 0;
441
442         csum16_update(&pad, 1, css);
443         return ~css->val + 1;
444 }
445
446
447 void
448 csum_init(struct csum_state *css, int size)
449 {
450         css->val = 0;
451         css->tmp = 0;
452         css->odd = 0;
453         css->size = size;
454 }
455
456
457 void
458 csum_update(uint8_t *p, uint32_t len, struct csum_state *css)
459 {
460         switch (css->size) {
461         case 1:
462                 csum8_update(p,len,css);
463                 break;
464         case 2:
465                 csum16_update(p,len,css);
466                 break;
467         }
468 }
469
470
471 uint16_t
472 csum_get(struct csum_state *css)
473 {
474         uint16_t ret;
475
476         switch (css->size) {
477         case 1:
478                 ret = csum8_get(css);
479                 break;
480         case 2:
481                 ret = csum16_get(css);
482                 break;
483         }
484
485         return ret;
486 }
487
488
489 /*
490  * routines to write data to the output file
491  */
492 int
493 write_out_data(FILE *outfile, uint8_t *data, size_t len,
494                 struct csum_state *css)
495 {
496         errno = 0;
497
498         fwrite(data, len, 1, outfile);
499         if (errno) {
500                 errmsg(1,"unable to write output file");
501                 return -1;
502         }
503
504         if (css) {
505                 csum_update(data, len, css);
506         }
507
508         return 0;
509 }
510
511
512 int
513 write_out_padding(FILE *outfile, size_t len, uint8_t padc,
514                  struct csum_state *css)
515 {
516         uint8_t buf[512];
517         size_t buflen = sizeof(buf);
518
519         memset(buf, padc, buflen);
520         while (len > 0) {
521                 if (len < buflen)
522                         buflen = len;
523
524                 if (write_out_data(outfile, buf, buflen, css))
525                         return -1;
526                         
527                 len -= buflen;
528         }
529
530         return 0;
531 }
532
533
534 int
535 block_stat_file(struct csys_block *block)
536 {
537         struct stat st;
538         int res;
539
540         if (block->file_name == NULL)
541                 return 0;
542
543         res = stat(block->file_name, &st);
544         if (res){
545                 errmsg(1, "stat failed on %s", block->file_name);
546                 return res;
547         }
548
549         block->file_size = st.st_size;
550         return 0;
551 }
552
553
554 int
555 block_writeout_hdr(FILE *outfile, struct csys_block *block)
556 {
557         struct csys_header hdr;
558         int res;
559
560         if (block->size_hdr == 0)
561                 return 0;
562
563         /* setup header fields */
564         memcpy(hdr.sig, block->sig, 4);
565         hdr.addr = HOST_TO_LE32(block->addr);
566         hdr.size = HOST_TO_LE32(block->size-block->size_hdr);
567
568         dbgmsg(1,"writing header for block");
569         res = write_out_data(outfile, (uint8_t *)&hdr, sizeof(hdr),NULL);
570         return res;
571
572 }
573
574
575 int
576 block_writeout_file(FILE *outfile, struct csys_block *block)
577 {
578         char buf[FILE_BUF_LEN];
579         size_t buflen = sizeof(buf);
580         FILE *f;
581         size_t len;
582         int res;
583
584         if (block->file_name == NULL)
585                 return 0;
586
587         if (block->file_size == 0)
588                 return 0;
589
590         errno = 0;
591         f = fopen(block->file_name,"r");
592         if (errno) {
593                 errmsg(1,"unable to open file: %s", block->file_name);
594                 return -1;
595         }
596
597         len = block->file_size;
598         while (len > 0) {
599                 if (len < buflen)
600                         buflen = len;
601
602                 /* read data from source file */
603                 errno = 0;
604                 fread(buf, buflen, 1, f);
605                 if (errno != 0) {
606                         errmsg(1,"unable to read from file: %s",
607                                 block->file_name);
608                         res = -1;
609                         break;
610                 }
611
612                 res = write_out_data(outfile, buf, buflen, block->css);
613                 if (res)
614                         break;
615
616                 len -= buflen;
617         }
618
619         fclose(f);
620         return res;
621 }
622
623
624 int 
625 block_writeout_data(FILE *outfile, struct csys_block *block)
626 {
627         int res;
628         size_t padlen;
629
630         res = block_writeout_file(outfile, block);
631         if (res)
632                 return res;
633
634         /* write padding data if neccesary */
635         padlen = block->size_avail - block->file_size;
636         dbgmsg(1,"padding block, length=%d", padlen);
637         res = write_out_padding(outfile, padlen, block->padc, block->css);
638
639         return res;
640 }
641
642
643 int 
644 block_writeout_csum(FILE *outfile, struct csys_block *block)
645 {
646         uint16_t csum;
647         int res;
648
649         if (block->size_csum == 0)
650                 return 0;
651
652         dbgmsg(1,"writing checksum for block");
653         csum = HOST_TO_LE16(csum_get(block->css));
654         res = write_out_data(outfile, (uint8_t *)&csum, block->size_csum, NULL);
655
656         return res;
657 }
658
659
660 int
661 block_writeout(FILE *outfile, struct csys_block *block)
662 {
663         int res;
664         struct csum_state css;
665         
666         res = 0;
667
668         if (block == NULL)
669                 return res;
670
671         block->css = NULL;
672
673         dbgmsg(2, "writing block, file=%s, file_size=%d, space=%d",
674                 block->file_name, block->file_size, block->size_avail);
675         res = block_writeout_hdr(outfile, block);
676         if (res)
677                 return res;
678
679         if (block->size_csum != 0) {
680                 block->css = &css;
681                 csum_init(&css, block->size_csum);
682         }
683
684         res = block_writeout_data(outfile, block);
685         if (res)
686                 return res;
687
688         res = block_writeout_csum(outfile, block);
689         if (res)
690                 return res;
691
692         return res;
693 }
694
695
696 int
697 write_out_blocks(FILE *outfile)
698 {
699         struct csys_block *block;
700         int i, res;
701
702         res = block_writeout(outfile, boot_block);
703         if (res)
704                 return res;
705
706         res = block_writeout(outfile, conf_block);
707         if (res)
708                 return res;
709
710         res = block_writeout(outfile, webp_block);
711         if (res)
712                 return res;
713
714         res = block_writeout(outfile, code_block);
715         if (res)
716                 return res;
717
718         res = 0;
719         for (i=0; i < num_blocks; i++) {
720                 block = &blocks[i];
721                 
722                 if (block->type != BLOCK_TYPE_XTRA)
723                         continue;
724                         
725                 res = block_writeout(outfile, block);
726                 if (res)
727                         break;
728         }
729         
730         return res;
731 }
732
733
734 struct board_info *
735 find_board(char *model)
736 {
737         struct board_info *ret;
738         struct board_info *board;
739
740         ret = NULL;
741         for (board = boards; board->model != NULL; board++){
742                 if (strcmp(model, board->model) == 0) {
743                         ret = board;
744                         break;
745                 }
746         };
747
748         return ret;
749 }
750
751
752 int
753 parse_opt_board(char ch, char *arg)
754 {
755
756         dbgmsg(1,"parsing board option: -%c %s", ch, arg);
757
758         if (board != NULL) {
759                 errmsg(0,"only one board option allowed");
760                 return -1;
761         }
762
763         if (required_arg(ch, arg))
764                 return -1;
765
766         board = find_board(arg);
767         if (board == NULL){
768                 errmsg(0,"invalid/unknown board specified: %s", arg);
769                 return -1;
770         }
771
772         return 0;
773 }
774
775
776 int
777 parse_opt_block(char ch, char *arg)
778 {
779         char buf[MAX_ARG_LEN];
780         char *argv[MAX_ARG_COUNT];
781         int argc;
782         char *p;
783         struct csys_block *block;
784         int i;
785
786         if ( num_blocks > MAX_NUM_BLOCKS ) {
787                 errmsg(0,"too many blocks specified");
788                 return -1;
789         }
790
791         block = &blocks[num_blocks];
792         
793         /* setup default field values */
794         block->need_file = 1;
795         block->padc = 0xFF;
796         
797         switch (ch) {
798         case 'b':
799                 if (boot_block) {
800                         errmsg(0,"only one boot block allowed");
801                         break;
802                 }
803                 block->type = BLOCK_TYPE_BOOT;
804                 boot_block = block;
805                 break;
806         case 'c':
807                 if (conf_block) {
808                         errmsg(0,"only one config block allowed");
809                         break;
810                 }
811                 block->type = BLOCK_TYPE_CONF;
812                 conf_block = block;
813                 break;
814         case 'w':
815                 if (webp_block) {
816                         errmsg(0,"only one web block allowed");
817                         break;
818                 }
819                 block->type = BLOCK_TYPE_WEBP;
820                 block->size_hdr = sizeof(struct csys_header);
821                 block->size_csum = 1;
822                 block->need_file = 0;
823                 webp_block = block;
824                 break;
825         case 'r':
826                 if (code_block) {
827                         errmsg(0,"only one runtime block allowed");
828                         break;
829                 }
830                 block->type = BLOCK_TYPE_CODE;
831                 block->size_hdr = sizeof(struct csys_header);
832                 block->size_csum = 2;
833                 code_block = block;
834                 break;
835         case 'x':
836                 block->type = BLOCK_TYPE_XTRA;
837                 break;
838         default:
839                 errmsg(0,"unknown block type \"%c\"", ch);
840                 return -1;
841         }
842
843         argc = parse_arg(arg, buf, argv);
844
845         i = 0;
846         p = argv[i++];
847         if (!is_empty_arg(p)) {
848                 block->file_name = strdup(p);
849                 if (block->file_name == NULL) {
850                         errmsg(0,"not enough memory");
851                         return -1;
852                 }
853         } else if (block->need_file){
854                 errmsg(0,"no file specified in %s", arg);
855                 return -1;
856         }
857
858         if (block->size_hdr) {
859                 p = argv[i++];
860                 if (!is_empty_arg(p)) {
861                         if (str2u32(p, &block->addr) != 0) {
862                                 errmsg(0,"invalid start address in %s", arg);
863                                 return -1;
864                         }
865                         block->addr_set = 1;
866                 }
867         }
868
869         p = argv[i++];
870         if (!is_empty_arg(p)) {
871                 if (str2u32(p, &block->size) != 0) {
872                         errmsg(0,"invalid block size in %s", arg);
873                         return -1;
874                 }
875                 block->size_set = 1;
876         }
877
878         p = argv[i++];
879         if (!is_empty_arg(p) && (str2u8(p, &block->padc) != 0)) {
880                 errmsg(0,"invalid paddig character in %s", arg);
881                 return -1;
882         }
883
884         num_blocks++;
885
886         return 0;
887 }
888
889
890 int
891 process_blocks(void)
892 {
893         struct csys_block *block;
894         uint32_t size_avail;
895         int i;
896         int res;
897
898         /* collecting stats */
899         for (i = 0; i < num_blocks; i++) {
900                 block = &blocks[i];
901                 res = block_stat_file(block);
902                 if (res)
903                         return res;
904         }
905
906         size_avail = board->flash_size;
907
908         /* bootloader */
909         block = boot_block;
910         if (block) {
911                 if (block->size_set) {
912                         board->boot_size= block->size;
913                 } else {
914                         block->size = board->boot_size;
915                 }
916                 if (block->size > size_avail) {
917                         errmsg(0,"boot block is too big");
918                         return -1;
919                 }
920         }
921         size_avail -= board->boot_size;
922
923         /* configuration data */
924         block = conf_block;
925         if (block) {
926                 if (block->size_set) {
927                         board->conf_size = block->size;
928                 } else {
929                         block->size = board->conf_size;
930                 }
931                 if (block->size > size_avail) {
932                         errmsg(0,"config block is too big");
933                         return -1;
934                 }
935
936         }
937         size_avail -= board->conf_size;
938
939         /* webpages */
940         block = webp_block;
941         if (block) {
942                 if (block->size_set == 0)
943                         block->size = board->webp_size;
944                 board->webp_size = block->size;
945                 if (block->size > board->webp_size_max) {
946                         errmsg(0,"webpages block is too big");
947                         return -1;
948                 }
949                 memcpy(block->sig, board->sig_webp, 4);
950                 if (block->addr_set == 0)
951                         block->addr = board->addr_webp;
952         }
953         size_avail -= board->webp_size;
954
955         /* runtime code */
956         block = code_block;
957         if (block) {
958                 if (block->size_set == 0) {
959                         block->size =ALIGN(block->file_size+ block->size_hdr +
960                                 block->size_csum, 0x10000);
961                 }
962                 board->code_size = block->size;
963                 if (board->code_size > size_avail) {
964                         errmsg(0,"code block is too big");
965                         if (size_check)
966                                 return -1;
967                 }
968                 memcpy(code_block->sig, SIG_CSYS, 4);
969                 if (code_block->addr_set == 0)
970                         code_block->addr = board->addr_code;
971         }
972         size_avail -= board->code_size;
973
974         for (i = 0; i < num_blocks; i++) {
975                 block = &blocks[i];
976
977                 if (block->type != BLOCK_TYPE_XTRA)
978                         continue;
979
980                 if (block->size_set == 0)
981                         block->size = ALIGN(block->file_size, 0x10000);
982
983                 if (block->size > size_avail) {
984                         errmsg(0,"no space for file %s",
985                                 block->file_name);
986                         if (size_check)
987                                 return -1;
988                 }
989
990                 size_avail -= block->size;
991         }
992
993         for (i = 0; i < num_blocks; i++) {
994                 block = &blocks[i];
995
996                 block->size_avail = block->size - block->size_hdr -
997                         block->size_csum;
998
999                 if (block->size_avail < block->file_size) {
1000                         errmsg(0,"file %s is too big, size=%d, avail=%d",
1001                                 block->file_name, block->file_size, 
1002                                 block->size_avail);
1003                         res = -1;
1004                         break;
1005                 }
1006         }
1007
1008         return res;
1009 }
1010
1011
1012 int
1013 main(int argc, char *argv[])
1014 {
1015         int optinvalid = 0;   /* flag for invalid option */
1016         int c;
1017         int res = EXIT_FAILURE;
1018
1019         FILE *outfile;
1020         
1021         progname=basename(argv[0]);
1022
1023         opterr = 0;  /* could not print standard getopt error messages */
1024         while ( 1 ) {
1025                 optinvalid = 0;
1026                 
1027                 c = getopt(argc, argv, "b:c:dB:hr:vw:x:");
1028                 if (c == -1)
1029                         break;
1030
1031                 switch (c) {
1032                 case 'b':
1033                 case 'c':
1034                 case 'r':
1035                 case 'x':
1036                         optinvalid = parse_opt_block(c,optarg);
1037                         break;
1038                 case 'w':
1039                         if (optarg != NULL && *optarg == '-') {
1040                                 /* rollback */
1041                                 optind--;
1042                                 optarg = NULL;
1043                         }
1044                         optinvalid = parse_opt_block(c,optarg);
1045                         break;
1046                 case 'd':
1047                         size_check = 0;
1048                         break;
1049                 case 'B':
1050                         optinvalid = parse_opt_board(c,optarg);
1051                         break;
1052                 case 'v':
1053                         verblevel++;
1054                         break;
1055                 case 'h':
1056                         usage(EXIT_SUCCESS);
1057                         break;
1058                 default:
1059                         optinvalid = 1;
1060                         break;
1061                 }
1062                 if (optinvalid != 0 ){
1063                         errmsg(0, "invalid option: -%c", optopt);
1064                         goto out;
1065                 }
1066         }
1067
1068         if (optind == argc) {
1069                 errmsg(0, "no output file specified");
1070                 goto out;
1071         }
1072
1073         ofname = argv[optind++];
1074
1075         if (optind < argc) {
1076                 errmsg(0, "invalid option: %s", argv[optind]);
1077                 goto out;
1078         }
1079         
1080
1081         if (board == NULL) {
1082                 errmsg(0, "no board specified");
1083                 goto out;
1084         }
1085
1086         if (process_blocks() != 0) {
1087                 goto out;
1088         }
1089
1090         outfile = fopen(ofname, "w");
1091         if (outfile == NULL) {
1092                 errmsg(1, "could not open \"%s\" for writing", ofname);
1093                 goto out;
1094         }
1095
1096         if (write_out_blocks(outfile) != 0)
1097                 goto out_flush;
1098
1099         dbgmsg(1,"Image file %s completed.", ofname);
1100
1101         res = EXIT_SUCCESS;
1102
1103 out_flush:
1104         fflush(outfile);
1105         fclose(outfile);
1106         if (res != EXIT_SUCCESS) {
1107                 unlink(ofname);
1108         }
1109 out:
1110         return res;
1111 }