blob: b5c4d6681b2e2dd698a39024c59c5512964e57f9 [file] [log] [blame]
David Ng3556e582012-07-27 23:52:11 +00001/*
2 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above
10 copyright notice, this list of conditions and the following
11 disclaimer in the documentation and/or other materials provided
12 with the distribution.
13 * Neither the name of The Linux Foundation nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#define _GNU_SOURCE
31#include <stdint.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <dirent.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <fcntl.h>
39#include <getopt.h>
40#include <errno.h>
41#include <unistd.h>
42
43#define QCDT_MAGIC "QCDT" /* Master DTB magic */
44#define QCDT_VERSION 1 /* QCDT version */
45#define QCDT_VERSION_NEW 2 /* QCDT version */
46
47#define QCDT_DT_TAG "qcom,msm-id = <"
48#define QCDT_BOARD_TAG "qcom,board-id = <"
49
50#define PAGE_SIZE_DEF 2048
51#define PAGE_SIZE_MAX (1024*1024)
52
53#define log_err(x...) printf(x)
54#define log_info(x...) printf(x)
55#define log_dbg(x...) { if (verbose) printf(x); }
56
57#define COPY_BLK 1024 /* File copy block size */
58
59#define RC_SUCCESS 0
60#define RC_ERROR -1
61
62struct chipInfo_t {
63 uint32_t chipset;
64 uint32_t platform;
65 uint32_t subtype;
66 uint32_t revNum;
67 uint32_t dtb_size;
68 char *dtb_file;
69 struct chipInfo_t *prev;
70 struct chipInfo_t *next;
71 struct chipInfo_t *master;
72 int wroteDtb;
73 uint32_t master_offset;
74 struct chipInfo_t *t_next;
75};
76
77struct chipInfo_t *chip_list;
78
79struct chipId_t {
80 uint32_t chipset;
81 uint32_t revNum;
82 struct chipId_t *next;
83 struct chipId_t *t_next;
84};
85
86struct chipSt_t {
87 uint32_t platform;
88 uint32_t subtype;
89 struct chipSt_t *next;
90 struct chipSt_t *t_next;
91};
92
93char *input_dir;
94char *output_file;
95char *dtc_path;
96int verbose;
97int page_size = PAGE_SIZE_DEF;
98int force_v2;
99
100
101void print_help()
102{
103 log_info("dtbTool version %d (kinda :) )\n", QCDT_VERSION);
104 log_info("dtbTool [options] -o <output file> <input DTB path>\n");
105 log_info(" options:\n");
106 log_info(" --output-file/-o output file\n");
107 log_info(" --dtc-path/-p path to dtc\n");
108 log_info(" --page-size/-s page size in bytes\n");
109 log_info(" --verbose/-v verbose\n");
110 log_info(" --force-v2/-2 use dtb v2 format\n");
111 log_info(" --help/-h this help screen\n");
112}
113
114int parse_commandline(int argc, char *const argv[])
115{
116 int c;
117
118 struct option long_options[] = {
119 {"output-file", 1, 0, 'o'},
120 {"dtc-path", 1, 0, 'p'},
121 {"page-size", 1, 0, 's'},
122 {"verbose", 0, 0, 'v'},
123 {"help", 0, 0, 'h'},
124 {"force-v2", 0, 0, '2'},
125 {0, 0, 0, 0}
126 };
127
128 while ((c = getopt_long(argc, argv, "-o:p:s:vh2", long_options, NULL))
129 != -1) {
130 switch (c) {
131 case 1:
132 if (!input_dir)
133 input_dir = optarg;
134 break;
135 case 'o':
136 output_file = optarg;
137 break;
138 case 'p':
139 dtc_path = optarg;
140 break;
141 case 's':
142 page_size = atoi(optarg);
143 if ((page_size <= 0) || (page_size > (PAGE_SIZE_MAX))) {
144 log_err("Invalid page size (> 0 and <=1MB\n");
145 return RC_ERROR;
146 }
147 break;
148 case 'v':
149 verbose = 1;
150 break;
151 case '2':
152 force_v2 = 1;
153 break;
154 case 'h':
155 default:
156 return RC_ERROR;
157 }
158 }
159
160 if (!output_file) {
161 log_err("Output file must be specified\n");
162 return RC_ERROR;
163 }
164
165 if (!input_dir)
166 input_dir = "./";
167
168 if (!dtc_path)
169 dtc_path = "";
170
171 return RC_SUCCESS;
172}
173
174/* Unique entry sorted list add (by chipset->platform->rev) */
175int chip_add(struct chipInfo_t *c)
176{
177 struct chipInfo_t *x = chip_list;
178
179 if (!chip_list) {
180 chip_list = c;
181 c->next = NULL;
182 c->prev = NULL;
183 return RC_SUCCESS;
184 }
185
186 while (1) {
187 if ((c->chipset < x->chipset) ||
188 ((c->chipset == x->chipset) &&
189 ((c->platform < x->platform) ||
190 ((c->platform == x->platform) &&
191 ((c->subtype < x->subtype) ||
192 ((c->subtype == x->subtype) &&
193 (c->revNum < x->revNum))))))) {
194 if (!x->prev) {
195 c->next = x;
196 c->prev = NULL;
197 x->prev = c;
198 chip_list = c;
199 break;
200 } else {
201 c->next = x;
202 c->prev = x->prev;
203 x->prev->next = c;
204 x->prev = c;
205 break;
206 }
207 }
208 if ((c->chipset == x->chipset) &&
209 (c->platform == x->platform) &&
210 (c->subtype == x->subtype) &&
211 (c->revNum == x->revNum)) {
212 return RC_ERROR; /* duplicate */
213 }
214 if (!x->next) {
215 c->prev = x;
216 c->next = NULL;
217 x->next = c;
218 break;
219 }
220 x = x->next;
221 }
222 return RC_SUCCESS;
223}
224
225void chip_deleteall()
226{
227 struct chipInfo_t *c = chip_list, *t;
228
229 while (c) {
230 t = c;
231 c = c->next;
232 if (t->dtb_file)
233 free(t->dtb_file);
234 free(t);
235 }
236}
237
238/*
239 For v1 Extract 'qcom,msm-id' parameter triplet from DTB
240 qcom,msm-id = <x y z>;
241
242 For v2 Extract 'qcom,msm-id', 'qcom,board-id' parameter double from DTB
243 qcom,msm-id = <x z> i.e chipset, revision number;
244 qcom,board-id = <y y'> i.e platform and sub-type;
245 */
246
247struct chipInfo_t *getChipInfo(const char *filename, int *num, uint32_t msmversion)
248{
249
250 const char str1[] = "dtc -I dtb -O dts \"";
251 const char str2[] = "\" 2>&1";
252 char *buf, *pos;
253 char *line = NULL;
254 size_t line_size;
255 FILE *pfile;
256 int llen;
257 struct chipInfo_t *chip = NULL, *tmp;
258 uint32_t data[3] = {0, 0, 0};
259 uint32_t data_st[2] = {0, 0};
260 char *tok, *sptr = NULL;
261 int i, entryValid, entryEnded;
262 int count = 0, count1 = 0, count2 =0;
263 int entryValidST, entryEndedST, entryValidDT, entryEndedDT;
264 struct chipId_t *chipId = NULL, *cId = NULL, *tmp_id = NULL;
265 struct chipSt_t *chipSt = NULL, *cSt = NULL, *tmp_st = NULL;
266
267 line_size = 1024;
268 line = (char *)malloc(line_size);
269 if (!line) {
270 log_err("Out of memory\n");
271 return NULL;
272 }
273
274 llen = sizeof(char) * (strlen(dtc_path) +
275 strlen(str1) +
276 strlen(str2) +
277 strlen(filename) + 1);
278 buf = (char *)malloc(llen);
279 if (!buf) {
280 log_err("Out of memory\n");
281 free(line);
282 return NULL;
283 }
284
285 strncpy(buf, dtc_path, llen);
286 strncat(buf, str1, llen);
287 strncat(buf, filename, llen);
288 strncat(buf, str2, llen);
289
290 pfile = popen(buf, "r");
291 free(buf);
292
293 if (pfile == NULL) {
294 log_err("... skip, fail to decompile dtb\n");
295 } else {
296 /* Find "qcom,msm-id" */
297 while ((llen = getline(&line, &line_size, pfile)) != -1) {
298 if (msmversion == 1) {
299 if ((pos = strstr(line, QCDT_DT_TAG)) != NULL) {
300 pos += strlen(QCDT_DT_TAG);
301
302 entryEnded = 0;
303 while (1) {
304 entryValid = 1;
305 for (i = 0; i < 3; i++) {
306 tok = strtok_r(pos, " \t", &sptr);
307 pos = NULL;
308 if (tok != NULL) {
309 if (*tok == '>') {
310 entryEnded = 1;
311 entryValid = 0;
312 break;
313 }
314 data[i] = strtoul(tok, NULL, 0);
315 } else {
316 data[i] = 0;
317 entryValid = 0;
318 entryEnded = 1;
319 }
320 }
321 if (entryEnded) {
322 free(line);
323 pclose(pfile);
324 *num = count;
325 return chip;
326 }
327 if (entryValid) {
328 tmp = (struct chipInfo_t *)
329 malloc(sizeof(struct chipInfo_t));
330 if (!tmp) {
331 log_err("Out of memory\n");
332 break;
333 }
334 if (!chip) {
335 chip = tmp;
336 chip->t_next = NULL;
337 } else {
338 tmp->t_next = chip->t_next;
339 chip->t_next = tmp;
340 }
341 tmp->chipset = data[0];
342 tmp->platform = data[1];
343 tmp->subtype = 0;
344 tmp->revNum = data[2];
345 tmp->dtb_size = 0;
346 tmp->dtb_file = NULL;
347 tmp->master = chip;
348 tmp->wroteDtb = 0;
349 tmp->master_offset = 0;
350 count++;
351 }
352 }
353
354 log_err("... skip, incorrect '%s' format\n", QCDT_DT_TAG);
355 break;
356 }
357 } else if (msmversion == 2) {
358 if ((pos = strstr(line, QCDT_DT_TAG)) != NULL) {
359 pos += strlen(QCDT_DT_TAG);
360
361 entryEndedDT = 0;
362 for (;entryEndedDT < 1;) {
363 entryValidDT = 1;
364 for (i = 0; i < 2; i++) {
365 tok = strtok_r(pos, " \t", &sptr);
366 pos = NULL;
367 if (tok != NULL) {
368 if (*tok == '>') {
369 entryEndedDT = 1;
370 entryValidDT = 0;
371 break;
372 }
373 data_st[i] = strtoul(tok, NULL, 0);
374 } else {
375 data_st[i] = 0;
376 entryValidDT = 0;
377 entryEndedDT = 1;
378 }
379 }
380
381 if (entryValidDT) {
382 tmp_id = (struct chipId_t *)
383 malloc(sizeof(struct chipId_t));
384 if (!tmp_id) {
385 log_err("Out of memory\n");
386 break;
387 }
388 if (!chipId) {
389 chipId = tmp_id;
390 cId = tmp_id;
391 chipId->t_next = NULL;
392 } else {
393 tmp_id->t_next = chipId->t_next;
394 chipId->t_next = tmp_id;
395 }
396 tmp_id->chipset = data_st[0];
397 tmp_id->revNum= data_st[1];
398 count1++;
399 }
400 }
401 }
402
403 if ((pos = strstr(line,QCDT_BOARD_TAG)) != NULL) {
404 pos += strlen(QCDT_BOARD_TAG);
405 entryEndedST = 0;
406 for (;entryEndedST < 1;) {
407 entryValidST = 1;
408 for (i = 0; i < 2; i++) {
409 tok = strtok_r(pos, " \t", &sptr);
410 pos = NULL;
411 if (tok != NULL) {
412 if (*tok == '>') {
413 entryEndedST = 1;
414 entryValidST = 0;
415 break;
416 }
417 data_st[i] = strtoul(tok, NULL, 0);
418 } else {
419 data_st[i] = 0;
420 entryValidST = 0;
421 entryEndedST = 1;
422 }
423 }
424 if (entryValidST) {
425 tmp_st = (struct chipSt_t *)
426 malloc(sizeof(struct chipSt_t));
427 if (!tmp_st) {
428 log_err("Out of memory\n");
429 break;
430 }
431
432 if (!chipSt) {
433 chipSt = tmp_st;
434 cSt = tmp_st;
435 chipSt->t_next = NULL;
436 } else {
437 tmp_st->t_next = chipSt->t_next;
438 chipSt->t_next = tmp_st;
439 }
440
441 tmp_st->platform = data_st[0];
442 tmp_st->subtype= data_st[1];
443 count2++;
444 }
445 }
446 }
447 }
448 }
449 }
450
451 if (line)
452 free(line);
453
454 if (force_v2 || msmversion == 2) {
455
456 if (count1 == 0) {
457 log_err("... skip, incorrect '%s' format\n", QCDT_DT_TAG);
458 return NULL;
459 }
460 if (count2 == 0) {
461 log_err("... skip, incorrect '%s' format\n", QCDT_BOARD_TAG);
462 return NULL;
463 }
464
465 tmp_st = cSt;
466 while (cId != NULL) {
467 while (cSt != NULL) {
468 tmp = (struct chipInfo_t *)
469 malloc(sizeof(struct chipInfo_t));
470 if (!tmp) {
471 log_err("Out of memory\n");
472 break;
473 }
474 if (!chip) {
475 chip = tmp;
476 chip->t_next = NULL;
477 } else {
478 tmp->t_next = chip->t_next;
479 chip->t_next = tmp;
480 }
481
482 tmp->chipset = cId->chipset;
483 tmp->platform = cSt->platform;
484 tmp->revNum = cId->revNum;
485 tmp->subtype = cSt->subtype;
486 tmp->dtb_size = 0;
487 tmp->dtb_file = NULL;
488 tmp->master = chip;
489 tmp->wroteDtb = 0;
490 tmp->master_offset = 0;
491
492 cSt = cSt->t_next;
493
494 }
495 cSt = tmp_st;
496 cId = cId->t_next;
497 }
498
499 if (entryEndedST == 1 && entryEndedDT == 1) {
500 pclose(pfile);
501 *num = count1;
502 free(chipSt);
503 free(chipId);
504 return chip;
505 }
506
507 } else {
508 pclose(pfile);
509 }
510
511 return NULL;
512}
513
514/* Get the version-id based on dtb files */
515int GetVersionInfo(const char *filename)
516{
517 const char str1[] = "dtc -I dtb -O dts \"";
518 const char str2[] = "\" 2>&1";
519 char *buf, *pos;
520 char *line = NULL;
521 size_t line_size;
522 FILE *pfile;
523 int llen;
524 int v = 1;
525
526 line_size = 1024;
527 line = (char *)malloc(line_size);
528 if (!line) {
529 log_err("Out of memory\n");
530 return 0;
531 }
532
533 llen = sizeof(char) * (strlen(dtc_path) +
534 strlen(str1) +
535 strlen(str2) +
536 strlen(filename) + 1);
537 buf = (char *)malloc(llen);
538 if (!buf) {
539 log_err("Out of memory\n");
540 free(line);
541 return 0;
542 }
543
544 strncpy(buf, dtc_path, llen);
545 strncat(buf, str1, llen);
546 strncat(buf, filename, llen);
547 strncat(buf, str2, llen);
548
549 pfile = popen(buf, "r");
550 free(buf);
551
552 if (pfile == NULL) {
553 log_err("... skip, fail to decompile dtb\n");
554 } else {
555 /* Find the type of version */
556 while ((llen = getline(&line, &line_size, pfile)) != -1) {
557 if ((pos = strstr(line,QCDT_BOARD_TAG)) != NULL) {
558 v = 2;
559 break;
560 }
561 }
562 }
563 if (v == 1)
564 log_info(" Old Version:%d\n", v);
565 free(line);
566
567 return v;
568}
569
570/* Extract 'qcom,msm-id' 'qcom,board-id' parameter from DTB
571 v1 format:
572 qcom,msm-id = <x y z> [, <x2 y2 z2> ...];
573 v2 format:
574 qcom,msm-id = <x z> [, <x2 z2> ...;
575 qcom,board-id = <y y'> [, <y2 y2'> ...;
576 Fields:
577 x = chipset
578 y = platform
579 y' = subtype
580 z = soc rev
581 */
582int main(int argc, char **argv)
583{
584 char buf[COPY_BLK];
585 struct chipInfo_t *chip, *t_chip;
586 struct dirent *dp;
587 FILE *pInputFile;
588 char *filename;
589 int padding;
590 uint8_t *filler = NULL;
591 int numBytesRead = 0;
592 int totBytesRead = 0;
593 int out_fd;
594 int flen;
595 int rc = RC_SUCCESS;
596 int dtb_count = 0, dtb_offset = 0;
597 size_t wrote = 0, expected = 0;
598 struct stat st;
599 uint32_t version = QCDT_VERSION;
600 int num;
601 uint32_t dtb_size;
602 int msmversion = 0;
603
604 log_info("DTB combiner:\n");
605
606 if (parse_commandline(argc, argv) != RC_SUCCESS) {
607 print_help();
608 return RC_ERROR;
609 }
610
611 log_info(" Input directory: '%s'\n", input_dir);
612 log_info(" Output file: '%s'\n", output_file);
613
614 DIR *dir = opendir(input_dir);
615 if (!dir) {
616 log_err("Failed to open input directory '%s'\n", input_dir);
617 return RC_ERROR;
618 }
619
620 filler = (uint8_t *)malloc(page_size);
621 if (!filler) {
622 log_err("Out of memory\n");
623 closedir(dir);
624 return RC_ERROR;
625 }
626 memset(filler, 0, page_size);
627
628 /* Open the .dtb files in the specified path, decompile and
629 extract "qcom,msm-id" parameter
630 */
631 while ((dp = readdir(dir)) != NULL) {
632 if ((dp->d_type == DT_REG)) {
633 flen = strlen(dp->d_name);
634 if ((flen > 4) &&
635 (strncmp(&dp->d_name[flen-4], ".dtb", 4) == 0)) {
636 log_info("Found file: %s ... ", dp->d_name);
637
638 flen = strlen(input_dir) + strlen(dp->d_name) + 1;
639 filename = (char *)malloc(flen);
640 if (!filename) {
641 log_err("Out of memory\n");
642 rc = RC_ERROR;
643 break;
644 }
645 strncpy(filename, input_dir, flen);
646 strncat(filename, dp->d_name, flen);
647
648 /* To identify the version number */
649 msmversion = force_v2 ? GetVersionInfo(filename) : 1;
650
651 num = 1;
652 chip = getChipInfo(filename, &num, msmversion);
653
654 if (msmversion == 1) {
655 if (!chip) {
656 log_err("skip, failed to scan for '%s' tag\n",
657 QCDT_DT_TAG);
658 free(filename);
659 continue;
660 }
661 }
662 if (msmversion == 2) {
663 if (!chip) {
664 log_err("skip, failed to scan for '%s' or '%s' tag\n",
665 QCDT_DT_TAG, QCDT_BOARD_TAG);
666 free(filename);
667 continue;
668 }
669 }
670
671 if ((stat(filename, &st) != 0) ||
672 (st.st_size == 0)) {
673 log_err("skip, failed to get DTB size\n");
674 free(filename);
675 continue;
676 }
677
678 log_info("chipset: %u, rev: %u, platform: %u, subtype: %u\n",
679 chip->chipset, chip->revNum, chip->platform, chip->subtype);
680
681 for (t_chip = chip->t_next; t_chip; t_chip = t_chip->t_next) {
682 log_info(" additional chipset: %u, rev: %u, platform: %u, subtype: %u\n",
683 t_chip->chipset, t_chip->revNum, t_chip->platform, t_chip->subtype);
684 }
685
686 rc = chip_add(chip);
687 if (rc != RC_SUCCESS) {
688 log_err("... duplicate info, skipped\n");
689 free(filename);
690 continue;
691 }
692
693 dtb_count++;
694
695 chip->dtb_size = st.st_size +
696 (page_size - (st.st_size % page_size));
697 chip->dtb_file = filename;
698
699 for (t_chip = chip->t_next; t_chip; t_chip = t_chip->t_next) {
700 rc = chip_add(t_chip);
701 if (rc != RC_SUCCESS) {
702 log_err("... duplicate info, skipped (chipset %u, rev: %u, platform: %u, subtype %u:\n",
703 t_chip->chipset, t_chip->revNum, t_chip->platform, t_chip->subtype);
704 continue;
705 }
706 dtb_count++;
707 }
708 }
709 }
710 }
711 closedir(dir);
712 log_info("=> Found %d unique DTB(s)\n", dtb_count);
713
714 if (!dtb_count)
715 goto cleanup;
716
717
718 /* Generate the master DTB file:
719
720 Simplify write error handling by just checking for actual vs
721 expected bytes written at the end.
722 */
723
724 log_info("\nGenerating master DTB... ");
725
726 out_fd = open(output_file, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
727 if (!out_fd < 0) {
728 log_err("Cannot create '%s'\n", output_file);
729 rc = RC_ERROR;
730 goto cleanup;
731 }
732
733 if (force_v2) {
734 version = QCDT_VERSION_NEW;
735 }
736
737 /* Write header info */
738 wrote += write(out_fd, QCDT_MAGIC, sizeof(uint8_t) * 4); /* magic */
739 wrote += write(out_fd, &version, sizeof(uint32_t)); /* version */
740 wrote += write(out_fd, (uint32_t *)&dtb_count, sizeof(uint32_t));
741 /* #DTB */
742
743 /* Calculate offset of first DTB block */
744 dtb_offset = 12 + /* header */
745 ((force_v2 ? 24 : 20) * dtb_count) + /* DTB table entries */
746 4; /* end of table indicator */
747 /* Round up to page size */
748 padding = page_size - (dtb_offset % page_size);
749 dtb_offset += padding;
750 expected = dtb_offset;
751
752 /* Write index table:
753 chipset
754 platform
755 subtype
756 soc rev
757 dtb offset
758 dtb size
759 */
760 for (chip = chip_list; chip; chip = chip->next) {
761 wrote += write(out_fd, &chip->chipset, sizeof(uint32_t));
762 wrote += write(out_fd, &chip->platform, sizeof(uint32_t));
763 if (force_v2)
764 wrote += write(out_fd, &chip->subtype, sizeof(uint32_t));
765 wrote += write(out_fd, &chip->revNum, sizeof(uint32_t));
766 if (chip->master->master_offset != 0) {
767 wrote += write(out_fd, &chip->master->master_offset, sizeof(uint32_t));
768 } else {
769 wrote += write(out_fd, &expected, sizeof(uint32_t));
770 chip->master->master_offset = expected;
771 expected += chip->master->dtb_size;
772 }
773 wrote += write(out_fd, &chip->master->dtb_size, sizeof(uint32_t));
774 }
775
776 rc = RC_SUCCESS;
777 wrote += write(out_fd, &rc, sizeof(uint32_t)); /* end of table indicator */
778 if (padding > 0)
779 wrote += write(out_fd, filler, padding);
780
781 /* Write DTB's */
782 for (chip = chip_list; chip; chip = chip->next) {
783 if (chip->master->wroteDtb) {
784 continue;
785 }
786
787 chip->master->wroteDtb = 1;
788 filename = chip->master->dtb_file;
789 dtb_size = chip->master->dtb_size;
790
791 log_dbg("\n (writing '%s' - %u bytes) ", filename, dtb_size);
792 pInputFile = fopen(filename, "r");
793 if (pInputFile != NULL) {
794 totBytesRead = 0;
795 while ((numBytesRead = fread(buf, 1, COPY_BLK, pInputFile)) > 0) {
796 wrote += write(out_fd, buf, numBytesRead);
797 totBytesRead += numBytesRead;
798 }
799 fclose(pInputFile);
800 padding = page_size - (totBytesRead % page_size);
801 if ((uint32_t)(totBytesRead + padding) != dtb_size) {
802 log_err("DTB size mismatch, please re-run: expected %d vs actual %d (%s)\n",
803 dtb_size, totBytesRead + padding,
804 filename);
805 rc = RC_ERROR;
806 break;
807 }
808 if (padding > 0)
809 wrote += write(out_fd, filler, padding);
810 } else {
811 log_err("failed to open DTB '%s'\n", filename);
812 rc = RC_ERROR;
813 break;
814 }
815 }
816 close(out_fd);
817
818 if (expected != wrote) {
819 log_err("error writing output file, please rerun: size mismatch %d vs %d\n",
820 expected, wrote);
821 rc = RC_ERROR;
822 } else
823 log_dbg("Total wrote %u bytes\n", wrote);
824
825 if (rc != RC_SUCCESS)
826 unlink(output_file);
827 else
828 log_info("completed\n");
829
830cleanup:
831 free(filler);
832 chip_deleteall();
833 return rc;
834}