mvebu: LS421DE: dts file improvements
[oweals/openwrt.git] / tools / firmware-utils / src / edimax_fw_header.c
1 /*
2  * Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 as published
6  * by the Free Software Foundation.
7  *
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <stdint.h>
13 #include <string.h>
14 #include <unistd.h>     /* for unlink() */
15 #include <libgen.h>
16 #include <getopt.h>     /* for getopt() */
17 #include <stdarg.h>
18 #include <errno.h>
19 #include <sys/stat.h>
20
21 #include <arpa/inet.h>
22 #include <netinet/in.h>
23
24 #define MAX_MAGIC_LEN           16
25 #define MAX_MODEL_LEN           32
26 #define MAX_VERSION_LEN         14
27 #define MAX_MTD_NAME_LEN        16
28
29 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
30
31 struct edimax_header {
32         char            magic[MAX_MAGIC_LEN];
33         char            model[MAX_MODEL_LEN];
34         unsigned char   force;
35         unsigned char   header_csum;
36         unsigned char   data_csum;
37         uint32_t        data_size;
38         uint32_t        start_addr;
39         uint32_t        end_addr;
40         char            fw_version[MAX_VERSION_LEN];
41         unsigned char   type;
42         char            mtd_name[MAX_MTD_NAME_LEN];
43 } __attribute__ ((packed));
44
45 /*
46  * Globals
47  */
48 static char *ofname;
49 static char *ifname;
50 static char *progname;
51
52 static char *model;
53 static char *magic = "eDiMaX";
54 static char *fw_version = "";
55 static char *mtd_name;
56 static int force;
57 static uint32_t start_addr;
58 static uint32_t end_addr;
59 static uint8_t image_type;
60 static int data_size;
61
62 /*
63  * Message macros
64  */
65 #define ERR(fmt, ...) do { \
66         fflush(0); \
67         fprintf(stderr, "[%s] *** error: " fmt "\n", \
68                         progname, ## __VA_ARGS__ ); \
69 } while (0)
70
71 #define ERRS(fmt, ...) do { \
72         int save = errno; \
73         fflush(0); \
74         fprintf(stderr, "[%s] *** error: " fmt " (%s)\n", \
75                         progname, ## __VA_ARGS__, strerror(save)); \
76 } while (0)
77
78 #define DBG(fmt, ...) do { \
79         fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
80 } while (0)
81
82 static void usage(int status)
83 {
84         FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
85
86         fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
87         fprintf(stream,
88 "\n"
89 "Options:\n"
90 "  -e <addr>       set end addr to <addr>\n"
91 "  -f              set force flag\n"
92 "  -h              show this screen\n"
93 "  -i <file>       read input data from the file <file>\n"
94 "  -o <file>       write output to the file <file>\n"
95 "  -m <model>      set model to <model>\n"
96 "  -M <magic>      set image magic to <magic>\n"
97 "  -n <name>       set MTD device name to <name>\n"
98 "  -s <addr>       set start address to <addr>\n"
99 "  -t <type>       set image type to <type>\n"
100 "  -v <version>    set firmware version to <version>\n"
101         );
102
103         exit(status);
104 }
105
106 int
107 str2u32(char *arg, uint32_t *val)
108 {
109         char *err = NULL;
110         uint32_t t;
111
112         errno=0;
113         t = strtoul(arg, &err, 0);
114         if (errno || (err==arg) || ((err != NULL) && *err)) {
115                 return -1;
116         }
117
118         *val = t;
119         return 0;
120 }
121
122 int
123 str2u8(char *arg, uint8_t *val)
124 {
125         char *err = NULL;
126         uint32_t t;
127
128         errno=0;
129         t = strtoul(arg, &err, 0);
130         if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
131                 return -1;
132         }
133
134         *val = t & 0xFF;
135         return 0;
136 }
137
138 static int get_file_size(char *name)
139 {
140         struct stat st;
141         int res;
142
143         res = stat(name, &st);
144         if (res){
145                 ERRS("stat failed on %s", name);
146                 return -1;
147         }
148
149         return st.st_size;
150 }
151
152 static int read_to_buf(char *name, char *buf, int buflen)
153 {
154         FILE *f;
155         int ret = EXIT_FAILURE;
156
157         f = fopen(name, "r");
158         if (f == NULL) {
159                 ERRS("could not open \"%s\" for reading", name);
160                 goto out;
161         }
162
163         errno = 0;
164         fread(buf, buflen, 1, f);
165         if (errno != 0) {
166                 ERRS("unable to read from file \"%s\"", name);
167                 goto out_close;
168         }
169
170         ret = EXIT_SUCCESS;
171
172 out_close:
173         fclose(f);
174 out:
175         return ret;
176 }
177
178 static int check_options(void)
179 {
180 #define CHKSTR(_name, _msg)                             \
181         do {                                            \
182                 if (_name == NULL) {                    \
183                         ERR("no %s specified", _msg);   \
184                         return -1;                      \
185                 }                                       \
186         } while (0)
187
188 #define CHKSTRLEN(_name, _msg)                                          \
189         do {                                                            \
190                 int field_len;                                          \
191                 CHKSTR(_name, _msg);                                    \
192                 field_len = FIELD_SIZEOF(struct edimax_header, _name) - 1; \
193                 if (strlen(_name) > field_len) {                        \
194                         ERR("'%s' is too long, max %s length is %d",    \
195                             _name, _msg, field_len);                    \
196                         return -1;                                      \
197                 }                                                       \
198         } while (0)
199
200         CHKSTR(ofname, "output file");
201         CHKSTR(ifname, "input file");
202
203         CHKSTRLEN(magic, "magic");
204         CHKSTRLEN(model, "model");
205         CHKSTRLEN(mtd_name, "MTD device name");
206         CHKSTRLEN(fw_version, "firware version");
207
208         data_size = get_file_size(ifname);
209         if (data_size < 0)
210                 return -1;
211
212         return 0;
213 }
214
215 static int write_fw(char *data, int len)
216 {
217         FILE *f;
218         int ret = EXIT_FAILURE;
219
220         f = fopen(ofname, "w");
221         if (f == NULL) {
222                 ERRS("could not open \"%s\" for writing", ofname);
223                 goto out;
224         }
225
226         errno = 0;
227         fwrite(data, len, 1, f);
228         if (errno) {
229                 ERRS("unable to write output file");
230                 goto out_flush;
231         }
232
233         DBG("firmware file \"%s\" completed", ofname);
234
235         ret = EXIT_SUCCESS;
236
237 out_flush:
238         fflush(f);
239         fclose(f);
240         if (ret != EXIT_SUCCESS) {
241                 unlink(ofname);
242         }
243 out:
244         return ret;
245 }
246
247 static unsigned char checksum(unsigned char *p, unsigned len)
248 {
249         unsigned char csum = 0;
250
251         while (len--)
252                 csum += *p++;
253
254         csum ^= 0xb9;
255
256         return csum;
257 }
258
259 static int build_fw(void)
260 {
261         int buflen;
262         char *buf;
263         char *data;
264         struct edimax_header *hdr;
265         int ret = EXIT_FAILURE;
266
267         buflen = sizeof(struct edimax_header) + data_size;
268
269         buf = malloc(buflen);
270         if (!buf) {
271                 ERR("no memory for buffer\n");
272                 goto out;
273         }
274
275         data = buf + sizeof(struct edimax_header);
276
277         /* read input file */
278         ret = read_to_buf(ifname, data, data_size);
279         if (ret)
280                 goto out_free_buf;
281
282         /* fill firmware header */
283         hdr = (struct edimax_header *)buf;
284         memset(hdr, 0, sizeof(struct edimax_header));
285
286         strncpy(hdr->model, model, sizeof(hdr->model));
287         strncpy(hdr->magic, magic, sizeof(hdr->magic));
288         strncpy(hdr->fw_version, fw_version, sizeof(hdr->fw_version));
289         strncpy(hdr->mtd_name, mtd_name, sizeof(hdr->mtd_name));
290
291         hdr->force = force;
292         hdr->start_addr = htonl(start_addr);
293         hdr->end_addr = htonl(end_addr);
294         hdr->data_size = htonl(data_size);
295         hdr->type = image_type;
296
297         hdr->data_csum = checksum((unsigned char *)data, data_size);
298         hdr->header_csum = checksum((unsigned char *)hdr,
299                                     sizeof(struct edimax_header));
300
301         ret = write_fw(buf, buflen);
302         if (ret)
303                 goto out_free_buf;
304
305         ret = EXIT_SUCCESS;
306
307 out_free_buf:
308         free(buf);
309 out:
310         return ret;
311 }
312
313 int main(int argc, char *argv[])
314 {
315         int ret = EXIT_FAILURE;
316
317         progname = basename(argv[0]);
318
319         while (1) {
320                 int c;
321
322                 c = getopt(argc, argv, "e:fhi:o:m:M:n:s:t:v:");
323                 if (c == -1)
324                         break;
325
326                 switch (c) {
327                 case 'e':
328                         if (str2u32(optarg, &end_addr)) {
329                                 ERR("%s is invalid '%s'",
330                                     "end address", optarg);
331                                 goto out;
332                         }
333                         break;
334                 case 'f':
335                         force = 1;
336                         break;
337                 case 'i':
338                         ifname = optarg;
339                         break;
340                 case 'h':
341                         usage(EXIT_SUCCESS);
342                         break;
343                 case 'o':
344                         ofname = optarg;
345                         break;
346                 case 'm':
347                         model = optarg;
348                         break;
349                 case 'M':
350                         magic = optarg;
351                         break;
352                 case 'n':
353                         mtd_name = optarg;
354                         break;
355                 case 's':
356                         if (str2u32(optarg, &start_addr)) {
357                                 ERR("%s is invalid '%s'",
358                                     "start address", optarg);
359                                 goto out;
360                         }
361                         break;
362                 case 't':
363                         if (str2u8(optarg, &image_type)) {
364                                 ERR("%s is invalid '%s'",
365                                     "image type", optarg);
366                                 goto out;
367                         }
368                         break;
369                 case 'v':
370                         fw_version = optarg;
371                         break;
372                 default:
373                         usage(EXIT_FAILURE);
374                         break;
375                 }
376         }
377
378         ret = check_options();
379         if (ret)
380                 goto out;
381
382         ret = build_fw();
383
384 out:
385         return ret;
386 }