1 /*
2 Xceive XC2028/3028 tuner module firmware manipulation tool
3
4 Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
5
6 Copyright (C) 2007, 2008 Mauro Carvalho Chehab <mchehab@kernel.org>
7 - Improve --list command
8 - Add --seek command
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation version 2
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <getopt.h>
29 #include <string.h>
30 #include <unistd.h>
31
32 #include <asm/byteorder.h>
33 #include <asm/types.h>
34
35 #include "tuner-xc2028-types.h"
36 #include "linux/videodev2.h"
37
38 #include "extract_head.h"
39 #include "standards.h"
40
41 #define LIST_ACTION (1<<0)
42 #define ADD_ACTION (1<<1)
43 #define DELETE_ACTION (1<<2)
44 #define SET_TYPE_ACTION (1<<3)
45 #define SET_ID_ACTION (1<<4)
46 #define SEEK_FIRM_ACTION (1<<5)
47
48 struct firmware_description {
49 uint32_t type;
50 uint64_t id;
51 unsigned char *data;
52 uint16_t int_freq;
53 uint32_t size;
54 };
55
56 struct firmware {
57 char* name;
58 struct firmware_description* desc;
59 uint16_t version;
60 uint16_t nr_desc;
61 };
62
63 #if 0
64 static struct firmware_description* alloc_firmware_description(void) {
65 struct firmware_description *d = malloc(sizeof(*d));
66 d->type = 0;
67 d->id = 0;
68 d->data = NULL;
69 d->size = 0;
70 return d;
71 }
72
73 static void free_firmware_description(struct firmware_description *d) {
74 free(d->data);
75 free(d);
76 }
77 #endif
78
alloc_firmware(void)79 static struct firmware* alloc_firmware(void) {
80 struct firmware *f = malloc(sizeof(*f));
81 f->name = NULL;
82 f->desc = NULL;
83 f->nr_desc = 0;
84 return f;
85 }
86
free_firmware(struct firmware * f)87 static void free_firmware(struct firmware *f) {
88 free(f->name);
89 if(f->desc) {
90 unsigned int i = 0;
91 for(i = 0; i < f->nr_desc; ++ i) {
92 free(f->desc[i].data);
93 }
94 }
95 free(f->desc);
96 free(f);
97 }
98
add_firmware_description(struct firmware * f,struct firmware_description * d)99 static void add_firmware_description(struct firmware *f,
100 struct firmware_description *d) {
101 struct firmware_description* new_desc;
102
103 new_desc = malloc((f->nr_desc + 1) * sizeof(*new_desc));
104 memcpy(new_desc, f->desc, f->nr_desc * sizeof(*new_desc));
105 memcpy(new_desc + f->nr_desc, d, sizeof(*d));
106 free(f->desc);
107 f->desc = new_desc;
108 ++f->nr_desc;
109 }
110
delete_firmware_description(struct firmware * f,uint16_t i)111 static void delete_firmware_description(struct firmware *f, uint16_t i) {
112 struct firmware_description* new_desc;
113
114 if(f->nr_desc == 0 || i >= f->nr_desc) {
115 return;
116 }
117
118 new_desc = malloc((f->nr_desc - 1) * sizeof(*new_desc));
119 memcpy(new_desc, f->desc, i * sizeof(*f->desc));
120 memcpy(new_desc + i, f->desc + i + 1, (f->nr_desc - i - 1) * sizeof(*f->desc));
121 free(f->desc);
122 f->desc = new_desc;
123 --f->nr_desc;
124 }
125
126 /* name[32] + version[2] + nr_desc[2] */
127 #define HEADER_LENGTH (32 + 2 + 2)
128 /* description header: 4 + 8 + 4.*/
129 #define DESC_HEADER_LENGTH (4 + 8 + 4)
130
read_firmware(unsigned char * data,off_t size,struct firmware ** f_res)131 static int read_firmware(unsigned char* data, off_t size, struct firmware** f_res) {
132 char *name = malloc(33);
133 unsigned char *p = data;
134 struct firmware* f = alloc_firmware();
135 unsigned int i;
136
137 if(size < HEADER_LENGTH) {
138 printf("Invalid firmware header length.\n");
139 free_firmware(f);
140 return -1;
141 }
142 name[32] = 0;
143 memcpy(name, data, 32);
144 f->name = name;
145 p += 32;
146 f->version = letoh16(*(uint16_t*)p);
147 p += sizeof(f->version);
148 f->nr_desc = letoh16(*(uint16_t*)p);
149 p += sizeof(f->nr_desc);
150 f->desc = malloc(f->nr_desc * sizeof(*(f->desc)));
151
152 for(i = 0; i < f->nr_desc; ++i) {
153 if(p + DESC_HEADER_LENGTH > data + size) {
154 printf("Invalid description header length.\n");
155 free_firmware(f);
156 return -1;
157 }
158 f->desc[i].type = letoh32(*(uint32_t*) p);
159 p += sizeof(f->desc[i].type);
160 f->desc[i].id = letoh64(*(uint64_t*) p);
161 p += sizeof(f->desc[i].id);
162
163 if (f->desc[i].type & HAS_IF) {
164 f->desc[i].int_freq = letoh16(*(uint16_t *) p);
165 p += sizeof(f->desc[i].int_freq);
166 }
167
168 f->desc[i].size = letoh32(*(uint32_t*) p);
169 p += sizeof(f->desc[i].size);
170
171 if(p + f->desc[i].size > data + size) {
172 printf("Invalid firmware standard length.\n");
173 f->nr_desc = (f->nr_desc == 0) ? 0 : f->nr_desc -1;
174 free_firmware(f);
175 return -1;
176 }
177
178 f->desc[i].data = malloc(f->desc[i].size);
179 memcpy(f->desc[i].data, p, f->desc[i].size);
180
181 p += f->desc[i].size;
182 }
183
184 *f_res = f;
185 return 0;
186 }
187
write_firmware(struct firmware * f,unsigned char ** r_data,off_t * r_size)188 static void write_firmware(struct firmware *f, unsigned char** r_data, off_t *r_size) {
189 off_t size;
190 unsigned int i = 0;
191 unsigned char* data;
192 unsigned char* p;
193
194 size = HEADER_LENGTH + f->nr_desc * DESC_HEADER_LENGTH;
195 for(i = 0; i < f->nr_desc; ++i) {
196 size += f->desc[i].size;
197 }
198
199 data = malloc(size);
200 p = data;
201
202 memcpy(p, f->name, 32);
203 p += 32;
204
205 *(uint16_t*)p = __cpu_to_le16(f->version);
206 p += sizeof(f->version);
207
208 *(uint16_t*)p = __cpu_to_le16(f->nr_desc);
209 p += sizeof(f->nr_desc);
210
211 for(i = 0; i < f->nr_desc; ++i) {
212 *(uint32_t*) p = __cpu_to_le32(f->desc[i].type);
213 p += sizeof(f->desc[i].type);
214
215 *(uint64_t*) p = __cpu_to_le64(f->desc[i].id);
216 p += sizeof(f->desc[i].id);
217
218 *(uint32_t*) p = __cpu_to_le32(f->desc[i].size);
219 p += sizeof(f->desc[i].size);
220
221 memcpy(p, f->desc[i].data, f->desc[i].size);
222 p += f->desc[i].size;
223 }
224
225 *r_data = data;
226 *r_size = size;
227 }
228
read_firmware_file(const char * filename)229 static struct firmware* read_firmware_file(const char* filename) {
230 struct stat buf;
231 unsigned char *ptr;
232 struct firmware *f;
233 int fd;
234
235 if(stat(filename, &buf) < 0) {
236 perror("Error during stat");
237 return NULL;
238 }
239
240 fd = open(filename, O_RDONLY);
241 if(fd < 0) {
242 perror("Error while opening the firmware file");
243 return NULL;
244 }
245
246 /* allocate firmware buffer*/
247 ptr = malloc(buf.st_size);
248
249 if(read(fd, ptr, buf.st_size) < 0) {
250 perror("Error while reading the firmware file");
251 free(ptr);
252 close(fd);
253 return NULL;
254 }
255
256 if(read_firmware(ptr, buf.st_size, &f) < 0) {
257 printf("Invalid firmware file!\n");
258 free(ptr);
259 close(fd);
260 return NULL;
261 }
262
263 close(fd);
264 free(ptr);
265 return f;
266 }
267
write_firmware_file(const char * filename,struct firmware * f)268 static void write_firmware_file(const char* filename, struct firmware *f) {
269 int fd;
270 unsigned char* data;
271 off_t size = 0;
272
273 fd = open(filename, O_WRONLY | O_CREAT, 0644);
274 if(fd < 0) {
275 perror("Error while opening the firmware file");
276 return;
277 }
278
279 if(ftruncate(fd, 0) < 0) {
280 perror("Error while deleting the firmware file");
281 close(fd);
282 return;
283 }
284
285 write_firmware(f, &data, &size);
286
287 if(write(fd, data, size) < 0) {
288 perror("Error while writing the firmware file");
289 close(fd);
290 return;
291 }
292
293 free(data);
294 close(fd);
295 }
296
dump_firm_type(FILE * fp,unsigned int type)297 static void dump_firm_type(FILE *fp, unsigned int type)
298 {
299 if (type & SCODE)
300 fprintf(fp, "SCODE FW ");
301 else if (type & BASE)
302 fprintf(fp, "BASE FW ");
303 else
304 fprintf(fp, "STD FW ");
305
306 if (type & F8MHZ)
307 fprintf(fp, "F8MHZ ");
308 if (type & MTS)
309 fprintf(fp, "MTS ");
310 if (type & D2620)
311 fprintf(fp, "D2620 ");
312 if (type & D2633)
313 fprintf(fp, "D2633 ");
314 if (type & DTV6)
315 fprintf(fp, "DTV6 ");
316 if (type & QAM)
317 fprintf(fp, "QAM ");
318 if (type & DTV7)
319 fprintf(fp, "DTV7 ");
320 if (type & DTV78)
321 fprintf(fp, "DTV78 ");
322 if (type & DTV8)
323 fprintf(fp, "DTV8 ");
324 if (type & FM)
325 fprintf(fp, "FM ");
326 if (type & INPUT1)
327 fprintf(fp, "INPUT1 ");
328 if (type & LCD)
329 fprintf(fp, "LCD ");
330 if (type & NOGD)
331 fprintf(fp, "NOGD ");
332 if (type & MONO)
333 fprintf(fp, "MONO ");
334 if (type & ATSC)
335 fprintf(fp, "ATSC ");
336 if (type & IF)
337 fprintf(fp, "IF ");
338 if (type & LG60)
339 fprintf(fp, "LG60 ");
340 if (type & ATI638)
341 fprintf(fp, "ATI638 ");
342 if (type & OREN538)
343 fprintf(fp, "OREN538 ");
344 if (type & OREN36)
345 fprintf(fp, "OREN36 ");
346 if (type & TOYOTA388)
347 fprintf(fp, "TOYOTA388 ");
348 if (type & TOYOTA794)
349 fprintf(fp, "TOYOTA794 ");
350 if (type & DIBCOM52)
351 fprintf(fp, "DIBCOM52 ");
352 if (type & ZARLINK456)
353 fprintf(fp, "ZARLINK456 ");
354 if (type & CHINA)
355 fprintf(fp, "CHINA ");
356 if (type & F6MHZ)
357 fprintf(fp, "F6MHZ ");
358 if (type & INPUT2)
359 fprintf(fp, "INPUT2 ");
360 if (type & HAS_IF)
361 fprintf(fp, "HAS IF ");
362 }
363
dump_firm_std(FILE * fp,v4l2_std_id id)364 static void dump_firm_std(FILE *fp, v4l2_std_id id)
365 {
366 v4l2_std_id old=-1, curr_id;
367
368 /* Dumps video standards */
369 while (old!=id) {
370 old=id;
371 if ( (id & V4L2_STD_PAL) == V4L2_STD_PAL) {
372 fprintf (fp, "PAL ");
373 curr_id = V4L2_STD_PAL;
374 } else if ( (id & V4L2_STD_MN) == V4L2_STD_MN) {
375 fprintf (fp, "NTSC PAL/M PAL/N ");
376 curr_id = V4L2_STD_PAL;
377 } else if ( (id & V4L2_STD_PAL_BG) == V4L2_STD_PAL_BG) {
378 fprintf (fp, "PAL/BG ");
379 curr_id = V4L2_STD_PAL_BG;
380 } else if ( (id & V4L2_STD_PAL_DK) == V4L2_STD_PAL_DK) {
381 fprintf (fp, "PAL/DK ");
382 curr_id = V4L2_STD_PAL_DK;
383 } else if ( (id & V4L2_STD_PAL_B) == V4L2_STD_PAL_B) {
384 fprintf (fp, "PAL/B ");
385 curr_id = V4L2_STD_PAL_B;
386 } else if ( (id & V4L2_STD_PAL_B1) == V4L2_STD_PAL_B1) {
387 fprintf (fp, "PAL/B1 ");
388 curr_id = V4L2_STD_PAL_B1;
389 } else if ( (id & V4L2_STD_PAL_G) == V4L2_STD_PAL_G) {
390 fprintf (fp, "PAL/G ");
391 curr_id = V4L2_STD_PAL_G;
392 } else if ( (id & V4L2_STD_PAL_H) == V4L2_STD_PAL_H) {
393 fprintf (fp, "PAL/H ");
394 curr_id = V4L2_STD_PAL_H;
395 } else if ( (id & V4L2_STD_PAL_I) == V4L2_STD_PAL_I) {
396 fprintf (fp, "PAL/I ");
397 curr_id = V4L2_STD_PAL_I;
398 } else if ( (id & V4L2_STD_PAL_D) == V4L2_STD_PAL_D) {
399 fprintf (fp, "PAL/D ");
400 curr_id = V4L2_STD_PAL_D;
401 } else if ( (id & V4L2_STD_PAL_D1) == V4L2_STD_PAL_D1) {
402 fprintf (fp, "PAL/D1 ");
403 curr_id = V4L2_STD_PAL_D1;
404 } else if ( (id & V4L2_STD_PAL_K) == V4L2_STD_PAL_K) {
405 fprintf (fp, "PAL/K ");
406 curr_id = V4L2_STD_PAL_K;
407 } else if ( (id & V4L2_STD_PAL_M) == V4L2_STD_PAL_M) {
408 fprintf (fp, "PAL/M ");
409 curr_id = V4L2_STD_PAL_M;
410 } else if ( (id & V4L2_STD_PAL_N) == V4L2_STD_PAL_N) {
411 fprintf (fp, "PAL/N ");
412 curr_id = V4L2_STD_PAL_N;
413 } else if ( (id & V4L2_STD_PAL_Nc) == V4L2_STD_PAL_Nc) {
414 fprintf (fp, "PAL/Nc ");
415 curr_id = V4L2_STD_PAL_Nc;
416 } else if ( (id & V4L2_STD_PAL_60) == V4L2_STD_PAL_60) {
417 fprintf (fp, "PAL/60 ");
418 curr_id = V4L2_STD_PAL_60;
419 } else if ( (id & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
420 fprintf (fp, "NTSC ");
421 curr_id = V4L2_STD_NTSC;
422 } else if ( (id & V4L2_STD_NTSC_M) == V4L2_STD_NTSC_M) {
423 fprintf (fp, "NTSC/M ");
424 curr_id = V4L2_STD_NTSC_M;
425 } else if ( (id & V4L2_STD_NTSC_M_JP) == V4L2_STD_NTSC_M_JP) {
426 fprintf (fp, "NTSC/M Jp ");
427 curr_id = V4L2_STD_NTSC_M_JP;
428 } else if ( (id & V4L2_STD_NTSC_443) == V4L2_STD_NTSC_443) {
429 fprintf (fp, "NTSC 443 ");
430 curr_id = V4L2_STD_NTSC_443;
431 } else if ( (id & V4L2_STD_NTSC_M_KR) == V4L2_STD_NTSC_M_KR) {
432 fprintf (fp, "NTSC/M Kr ");
433 curr_id = V4L2_STD_NTSC_M_KR;
434 } else if ( (id & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
435 fprintf (fp, "SECAM ");
436 curr_id = V4L2_STD_SECAM;
437 } else if ( (id & V4L2_STD_SECAM_DK) == V4L2_STD_SECAM_DK) {
438 fprintf (fp, "SECAM/DK ");
439 curr_id = V4L2_STD_SECAM_DK;
440 } else if ( (id & V4L2_STD_SECAM_B) == V4L2_STD_SECAM_B) {
441 fprintf (fp, "SECAM/B ");
442 curr_id = V4L2_STD_SECAM_B;
443 } else if ( (id & V4L2_STD_SECAM_D) == V4L2_STD_SECAM_D) {
444 fprintf (fp, "SECAM/D ");
445 curr_id = V4L2_STD_SECAM_D;
446 } else if ( (id & V4L2_STD_SECAM_G) == V4L2_STD_SECAM_G) {
447 fprintf (fp, "SECAM/G ");
448 curr_id = V4L2_STD_SECAM_G;
449 } else if ( (id & V4L2_STD_SECAM_H) == V4L2_STD_SECAM_H) {
450 fprintf (fp, "SECAM/H ");
451 curr_id = V4L2_STD_SECAM_H;
452 } else if ( (id & V4L2_STD_SECAM_K) == V4L2_STD_SECAM_K) {
453 fprintf (fp, "SECAM/K ");
454 curr_id = V4L2_STD_SECAM_K;
455 } else if ( (id & V4L2_STD_SECAM_K1) == V4L2_STD_SECAM_K1) {
456 fprintf (fp, "SECAM/K1 ");
457 curr_id = V4L2_STD_SECAM_K1;
458 } else if ( (id & V4L2_STD_SECAM_K3) == V4L2_STD_SECAM_K3) {
459 fprintf (fp, "SECAM/K3 ");
460 curr_id = V4L2_STD_SECAM_K3;
461 } else if ( (id & V4L2_STD_SECAM_L) == V4L2_STD_SECAM_L) {
462 fprintf (fp, "SECAM/L ");
463 curr_id = V4L2_STD_SECAM_L;
464 } else if ( (id & V4L2_STD_SECAM_LC) == V4L2_STD_SECAM_LC) {
465 fprintf (fp, "SECAM/Lc ");
466 curr_id = V4L2_STD_SECAM_LC;
467 } else if ( (id & V4L2_STD_A2) == V4L2_STD_A2) {
468 fprintf (fp, "A2 ");
469 curr_id = V4L2_STD_A2;
470 } else if ( (id & V4L2_STD_A2_A) == V4L2_STD_A2_A) {
471 fprintf (fp, "A2/A ");
472 curr_id = V4L2_STD_A2_A;
473 } else if ( (id & V4L2_STD_A2_B) == V4L2_STD_A2_B) {
474 fprintf (fp, "A2/B ");
475 curr_id = V4L2_STD_A2_B;
476 } else if ( (id & V4L2_STD_NICAM) == V4L2_STD_NICAM) {
477 fprintf (fp, "NICAM ");
478 curr_id = V4L2_STD_NICAM;
479 } else if ( (id & V4L2_STD_NICAM_A) == V4L2_STD_NICAM_A) {
480 fprintf (fp, "NICAM/A ");
481 curr_id = V4L2_STD_NICAM_A;
482 } else if ( (id & V4L2_STD_NICAM_B) == V4L2_STD_NICAM_B) {
483 fprintf (fp, "NICAM/B ");
484 curr_id = V4L2_STD_NICAM_B;
485 } else if ( (id & V4L2_STD_AM) == V4L2_STD_AM) {
486 fprintf (fp, "AM ");
487 curr_id = V4L2_STD_AM;
488 } else if ( (id & V4L2_STD_BTSC) == V4L2_STD_BTSC) {
489 fprintf (fp, "BTSC ");
490 curr_id = V4L2_STD_BTSC;
491 } else if ( (id & V4L2_STD_EIAJ) == V4L2_STD_EIAJ) {
492 fprintf (fp, "EIAJ ");
493 curr_id = V4L2_STD_EIAJ;
494 } else {
495 curr_id = 0;
496 break;
497 }
498 id &= ~curr_id;
499 }
500 }
501
list_firmware_desc(FILE * fp,struct firmware_description * desc)502 static void list_firmware_desc(FILE *fp, struct firmware_description *desc)
503 {
504 fprintf(fp, "type: ");
505 dump_firm_type(fp, desc->type);
506 fprintf(fp, "(0x%08x), ", desc->type);
507 if (desc->type & HAS_IF)
508 fprintf(fp, "IF = %.2f MHz ", desc->int_freq/1000.0);
509 fprintf(fp, "id: ");
510 dump_firm_std(fp, desc->id);
511 fprintf(fp, "(%016llx), ", desc->id);
512 fprintf(fp, "size: %u\n", desc->size);
513 }
514
list_firmware(struct firmware * f,unsigned int dump,char * binfile)515 static void list_firmware(struct firmware *f, unsigned int dump, char *binfile)
516 {
517 unsigned int i = 0;
518
519 printf("firmware name:\t%s\n", f->name);
520 printf("version:\t%d.%d (%u)\n", f->version >> 8, f->version & 0xff,
521 f->version);
522 printf("standards:\t%u\n", f->nr_desc);
523 for(i = 0; i < f->nr_desc; ++i) {
524 printf("Firmware %2u, ", i);
525 list_firmware_desc(stdout, &f->desc[i]);
526 if (dump) {
527 printf("\t");
528 unsigned j, k = 0;
529 for (j = 0; j < f->desc[i].size; j++) {
530 printf("%02x", f->desc[i].data[j]);
531
532 k++;
533 if (k >= 32) {
534 printf("\n\t");
535 k = 0;
536 } else if (!(k % 2))
537 printf(" ");
538 }
539 printf("\n");
540 }
541 if (binfile) {
542 char name[strlen(binfile)+4], *p;
543 p = strrchr(binfile,'.');
544 if (p) {
545 int n = p - binfile;
546 strncpy(name, binfile, n);
547 sprintf(name + n, "%03i", i);
548 strcat(name, p);
549 } else {
550 strcpy(name, binfile);
551 sprintf(name + strlen(name), "%03i", i);
552 }
553 FILE *fp;
554
555 fp = fopen(name,"w");
556 if (!fp) {
557 perror("Opening file to write");
558 return;
559 }
560 fwrite(f->desc[i].data, f->desc[i].size, 1, fp);
561 fclose(fp);
562 }
563 }
564 }
565
add_standard(struct firmware * f,char * firmware_file,char * standard_file)566 static void add_standard(struct firmware* f, char* firmware_file, char* standard_file) {
567 unsigned char* standard_data;
568 unsigned int len;
569 struct firmware_description desc;
570
571 create_standard_data(standard_file, &standard_data, &len);
572 if(!standard_data) {
573 fprintf(stderr, "Couldn't create the firmware standard data.\n");
574 return;
575 }
576 desc.id = 0;
577 desc.type = 0;
578 desc.size = len;
579 desc.data = standard_data;
580 add_firmware_description(f, &desc);
581 write_firmware_file(firmware_file, f);
582 }
583
delete_standard(struct firmware * f,char * firmware_file,uint16_t i)584 static void delete_standard(struct firmware* f, char* firmware_file, uint16_t i) {
585 delete_firmware_description(f, i);
586 write_firmware_file(firmware_file, f);
587 }
588
set_standard_type(struct firmware * f,char * firmware_file,uint16_t i,uint32_t type)589 static void set_standard_type(struct firmware* f, char* firmware_file, uint16_t i, uint32_t type) {
590 if(i > f->nr_desc) {
591 return;
592 }
593 f->desc[i].type = type;
594 write_firmware_file(firmware_file, f);
595 }
596
set_standard_id(struct firmware * f,char * firmware_file,uint16_t i,uint32_t id)597 static void set_standard_id(struct firmware* f, char* firmware_file, uint16_t i, uint32_t id) {
598 if(i > f->nr_desc) {
599 return;
600 }
601 f->desc[i].id = id;
602 write_firmware_file(firmware_file, f);
603 }
604
605 struct chunk_hunk;
606
607 struct chunk_hunk {
608 unsigned char *data;
609 long pos;
610 int size;
611 int need_fix_endian;
612 int hint_method;
613 struct chunk_hunk *next;
614 };
615
seek_chunks(struct chunk_hunk * fhunk,unsigned char * seek,unsigned char * endp,unsigned char * fdata,unsigned char * endf)616 static int seek_chunks(struct chunk_hunk *fhunk,
617 unsigned char *seek, unsigned char *endp, /* File to seek */
618 unsigned char *fdata, unsigned char *endf) /* Firmware */
619 {
620 unsigned char *fpos, *p, *p2;
621 int fsize;
622 unsigned char *temp_data;
623 struct chunk_hunk *hunk = fhunk;
624 /* Method 3 vars */
625 static unsigned char *base_start = 0;
626 int ini_sig = 8, sig_len = 14, end_sig = 8;
627
628 /* Method 1a: Seek for a complete firmware */
629 for (p = seek; p < endp; p++) {
630 fpos = p;
631 for (p2 = fdata; p2 < endf; p2++, fpos++) {
632 if (*fpos != *p2)
633 break;
634 }
635 if (p2 == endf) {
636 hunk->data = NULL;
637 hunk->pos = p - seek;
638 hunk->size = endf - fdata;
639 hunk->next = NULL;
640 hunk->need_fix_endian = 0;
641 hunk->hint_method = 0;
642 return 1;
643 }
644 }
645
646 fsize = endf - fdata;
647 temp_data = malloc(fsize);
648 memcpy(temp_data, fdata, fsize);
649
650 /* Try again, changing endian */
651 for (p2 = temp_data; p2 < temp_data + fsize;) {
652 unsigned char c;
653 int size = *p2 + (*(p2 + 1) << 8);
654 c = *p2;
655 *p2 = *(p2 + 1);
656 *(p2 + 1) = c;
657 p2+=2;
658 if ((size > 0) && (size < 0x8000))
659 p2 += size;
660 }
661
662 /* Method 1b: Seek for a complete firmware with changed endians */
663 for (p = seek; p < endp; p++) {
664 fpos = p;
665 for (p2 = temp_data; p2 < temp_data + fsize; p2++, fpos++) {
666 if (*fpos != *p2)
667 break;
668 }
669 if (p2 == temp_data + fsize) {
670 hunk->data = NULL;
671 hunk->pos = p - seek;
672 hunk->size = endf - fdata;
673 hunk->next = NULL;
674 hunk->need_fix_endian = 1;
675 hunk->hint_method = 0;
676 return 1;
677 }
678 }
679
680 free(temp_data);
681
682 /* Method 2: seek for base firmware */
683 if (!base_start)
684 base_start = seek;
685
686 /* Skip if firmware is not a base firmware */
687 if (endf - fdata < 1000)
688 goto method3;
689
690 for (p = base_start; p < endp; p++) {
691 fpos = p;
692 for (p2 = fdata + ini_sig;
693 p2 < fdata + ini_sig + sig_len; p2++,
694 fpos++) {
695 if (*fpos != *p2)
696 break;
697 }
698 if (p2 == fdata + ini_sig + sig_len) {
699 base_start = p - ini_sig;
700
701 p = memmem (base_start, endp-base_start,
702 temp_data + fsize - end_sig, end_sig);
703
704 if (p)
705 p = memmem (p + end_sig, endp-base_start,
706 temp_data + fsize - end_sig, end_sig);
707
708 if (!p) {
709 printf("Found something that looks like a firmware start at %lx\n",
710 (long)(base_start - seek));
711
712 base_start += ini_sig + sig_len;
713 goto method3;
714 }
715
716 p += end_sig;
717
718 printf("Found firmware at %lx, size = %ld\n",
719 (long)(base_start - seek),
720 (long)(p - base_start));
721
722 hunk->data = NULL;
723 hunk->pos = base_start - seek;
724 hunk->size = p - base_start;
725 hunk->next = NULL;
726 hunk->need_fix_endian = 1;
727 hunk->hint_method = 3;
728
729 base_start = p;
730
731 return 2;
732 }
733 }
734
735 method3:
736 #if 0
737 /* Method 3: Seek for each firmware chunk */
738 p = seek;
739 for (p2 = fdata; p2 < endf;) {
740 int size = *p2 + (*(p2 + 1) << 8);
741
742 /* Encode size/reset/sleep directly */
743 hunk->size = 2;
744 hunk->data = malloc(hunk->size);
745 memcpy(hunk->data, p2, hunk->size);
746 hunk->pos = -1;
747 hunk->next = calloc(1, sizeof(hunk));
748 hunk->need_fix_endian = 0;
749 hunk->hint_method = 0;
750
751 hunk = hunk->next;
752 p2 += 2;
753
754 if ((size > 0) && (size < 0x8000)) {
755 unsigned char *ep;
756 int found = 0;
757 ep = p2 + size;
758 ///////////////////
759 for (; p < endp; p++) {
760 unsigned char *p3;
761 fpos = p;
762 for (p3 = p2; p3 < ep; p3++, fpos++)
763 if (*fpos != *p3)
764 break;
765 if (p3 == ep) {
766 found = 1;
767 hunk->pos = p - seek;
768 hunk->size = size;
769 hunk->next = calloc(1, sizeof(hunk));
770 hunk->need_fix_endian = 0;
771 hunk->hint_method = 0;
772
773 hunk = hunk->next;
774 break;
775 }
776 }
777 if (!found) {
778 goto not_found;
779 }
780 p2 += size;
781 }
782 }
783 return 3;
784 not_found:
785 #endif
786 memset(fhunk, 0, sizeof(struct chunk_hunk));
787 printf("Couldn't find firmware\n");
788 return 0;
789
790 /* Method 4: Seek for first firmware chunks */
791 #if 0
792 seek_next:
793 for (p = seek; p < endp; p++) {
794 fpos = p;
795 for (p2 = fdata; p2 < endf; p2++, fpos++) {
796 if (*fpos != *p2)
797 break;
798 }
799 if (p2 > fdata + 3) {
800 int i = 0;
801 unsigned char *lastp;
802 printf("Found %ld equal bytes at %06x:\n",
803 p2 - fdata, p - seek);
804 fpos = p;
805 lastp = fpos;
806 for (p2 = fdata; p2 < endf; p2++, fpos++) {
807 if (*fpos != *p2)
808 break;
809 printf("%02x ",*p2);
810 }
811 for (i=0; p2 < endf && i <5 ; p2++, fpos++, i++) {
812 printf("%02x(%02x) ",*p2 , *fpos);
813 }
814 printf("\n");
815 /* Seek for the next chunk */
816 fdata = p2;
817
818 if (fdata == endf) {
819 printf ("Found all chunks.\n");
820 return 4;
821 }
822 }
823 }
824
825 printf ("NOT FOUND: %02x\n", *fdata);
826 fdata++;
827 goto seek_next;
828 #endif
829 }
830
seek_firmware(struct firmware * f,char * seek_file,char * write_file)831 static void seek_firmware(struct firmware *f, char *seek_file, char *write_file) {
832 unsigned int i = 0, j, nfound = 0;
833 long size, rd = 0;
834 unsigned char *seek, *p, *endp, *endp2;
835 /*FIXME: Calculate it, instead of using a hardcode value */
836 char *md5 = "0e44dbf63bb0169d57446aec21881ff2";
837 FILE *fp;
838
839 struct chunk_hunk hunks[f->nr_desc];
840 memset (hunks, 0, sizeof(struct chunk_hunk) * f->nr_desc);
841
842 fp=fopen(seek_file, "r");
843 if (!fp) {
844 perror("Opening seek file");
845 exit(-1);
846 }
847 fseek(fp, 0L, SEEK_END);
848 size = ftell(fp);
849 rewind(fp);
850 seek = malloc(size);
851 p = seek;
852
853 do {
854 i = fread(p, 1, 16768, fp);
855 if (i > 0) {
856 rd += i;
857 p += i;
858 }
859 } while (i > 0);
860
861 fclose(fp);
862
863 if (rd != size) {
864 fprintf(stderr, "Error while reading the seek file: "
865 "should read %ld, instead of %ld ", size, rd);
866 exit (-1);
867 }
868 endp = p;
869
870 printf("firmware name:\t%s\n", f->name);
871 printf("version:\t%d.%d (%u)\n", f->version >> 8, f->version & 0xff,
872 f->version);
873 printf("number of standards:\t%u\n", f->nr_desc);
874 for(i = 0; i < f->nr_desc; ++i) {
875 int found;
876
877 endp2 = f->desc[i].data + f->desc[i].size;
878
879 found = seek_chunks (&hunks[i],
880 seek, endp, f->desc[i].data, endp2);
881
882 if (!found) {
883 printf("NOT FOUND: Firmware %d ", i);
884 list_firmware_desc(stdout, &f->desc[i]);
885 } else {
886 nfound++;
887 printf("Found with method %d: Firmware %d ", found, i);
888 if (found == 2)
889 f->desc[i].size = hunks[i].size;
890 list_firmware_desc(stdout, &f->desc[i]);
891 }
892 }
893 printf ("Found %d complete firmwares\n", nfound);
894
895 if (!write_file)
896 return;
897
898 fp = fopen(write_file, "w");
899 if (!fp) {
900 perror("Writing firmware file");
901 exit(-1);
902 }
903
904 fprintf(fp, "%s", extract_header);
905 for (i = 0, j = -1; i < f->nr_desc; i++) {
906 struct chunk_hunk *hunk = &hunks[i];
907
908 if (!hunk->size)
909 continue;
910 j++;
911
912 if (hunk->hint_method)
913 fprintf(fp, "\n\t#\n\t# Guessed format ");
914
915 fprintf(fp, "\n\t#\n\t# Firmware %d, ", j);
916 list_firmware_desc(fp, &f->desc[i]);
917 fprintf(fp, "\t#\n\n");
918
919 fprintf(fp, "\twrite_le32(0x%08x);\t\t\t# Type\n",
920 f->desc[i].type);
921 fprintf(fp, "\twrite_le64(0x%08Lx, 0x%08Lx);\t# ID\n",
922 f->desc[i].id>>32, f->desc[i].id & 0xffffffff);
923 if (f->desc[i].type & HAS_IF)
924 fprintf(fp, "\twrite_le16(%d);\t\t\t# IF\n",
925 f->desc[i].int_freq);
926 fprintf(fp, "\twrite_le32(%d);\t\t\t# Size\n",
927 f->desc[i].size);
928 while (hunk) {
929 if (hunk->data) {
930 int k;
931 fprintf(fp, "\tsyswrite(OUTFILE, ");
932 for (k = 0; k < hunk->size; k++) {
933 fprintf(fp, "chr(%d)", hunk->data[k]);
934 if (k < hunk->size-1)
935 fprintf(fp,".");
936 }
937 fprintf(fp,");\n");
938 } else {
939 if (!hunk->size)
940 break;
941
942 if (hunk->need_fix_endian)
943 fprintf(fp, write_hunk_fix_endian,
944 hunk->pos, hunk->size);
945 else
946 fprintf(fp, write_hunk,
947 hunk->pos, hunk->size);
948 }
949 hunk = hunk->next;
950 }
951 }
952
953 fprintf(fp, end_extract, seek_file, md5, "xc3028-v27.fw",
954 f->name, f->version, nfound);
955 }
956
print_usage(void)957 static void print_usage(void)
958 {
959 printf("firmware-tool usage:\n");
960 printf("\t firmware-tool --list [--dump] [--write <bin-file>] <firmware-file>\n");
961 printf("\t firmware-tool --add <firmware-dump> <firmware-file>\n");
962 printf("\t firmware-tool --delete <index> <firmware-file>\n");
963 printf("\t firmware-tool --type <type> --index <i> <firmware-file>\n");
964 printf("\t firmware-tool --id <type> --index <i> <firmware-file>\n");
965 printf("\t firmware-tool --seek <seek-file> [--write <write-file>] <firmware-file>\n");
966 }
967
main(int argc,char * argv[])968 int main(int argc, char* argv[])
969 {
970 int c;
971 int nr_args;
972 unsigned int action = 0, dump = 0;
973 char* firmware_file, *file = NULL, *nr_str = NULL, *index_str = NULL;
974 char *seek_file = NULL, *write_file = NULL;
975 struct firmware *f;
976
977 while(1) {
978 static struct option long_options[] = {
979 {"list", no_argument, 0, 'l'},
980 {"add", required_argument, 0, 'a'},
981 {"delete", required_argument, 0, 'd'},
982 {"type", required_argument, 0, 't'},
983 {"id", required_argument, 0, 's'},
984 {"index", required_argument, 0, 'i'},
985 {"seek", required_argument, 0, 'k'},
986 {"write", required_argument , 0, 'w'},
987 {"dump", no_argument, 0, 'm'},
988 {0, 0, 0, 0}
989 };
990 int option_index = 0;
991
992 c = getopt_long(argc, argv, "", long_options, &option_index);
993
994 if (c == -1) {
995 break;
996 }
997
998 switch(c) {
999 case 'l':
1000 puts("list action\n");
1001 if(action != 0) {
1002 printf("Please specify only one action.\n");
1003 }
1004 action |= LIST_ACTION;
1005 break;
1006 case 'm':
1007 dump = 1;
1008 break;
1009 case 'a':
1010 puts("add action\n");
1011 if(action != 0) {
1012 printf("Please specify only one action.\n");
1013 }
1014 action |= ADD_ACTION;
1015 file = optarg;
1016 break;
1017 case 'd':
1018 puts("delete action\n");
1019 if(action != 0) {
1020 printf("Please specify only one action.\n");
1021 }
1022 action |= DELETE_ACTION;
1023 nr_str = optarg;
1024 break;
1025 case 't':
1026 puts("set-type action\n");
1027 if(action != 0) {
1028 printf("Please specify only one action.\n");
1029 }
1030 action |= SET_TYPE_ACTION;
1031 nr_str = optarg;
1032 break;
1033 case 's':
1034 puts("set-id action\n");
1035 if(action != 0) {
1036 printf("Please specify only one action.\n");
1037 }
1038 action |= SET_ID_ACTION;
1039 nr_str = optarg;
1040 break;
1041 case 'i':
1042 index_str = optarg;
1043 break;
1044 case 'k':
1045 puts("seek firmwares\n");
1046 action = SEEK_FIRM_ACTION;
1047 seek_file = optarg;
1048 break;
1049 case 'w':
1050 write_file = optarg;
1051 break;
1052 default:
1053 print_usage();
1054 return 0;
1055 }
1056 }
1057
1058 nr_args = (action == LIST_ACTION) ? 1 : 1;
1059 if(!(optind + nr_args == argc)) {
1060 printf("Wrong number of arguments!\n\n");
1061 print_usage();
1062 return -1;
1063 }
1064
1065 if(!action) {
1066 printf("Please specify an action!\n\n");
1067 print_usage();
1068 return -1;
1069 }
1070
1071 firmware_file = argv[optind];
1072
1073 printf("firmware file name: %s\n", firmware_file);
1074
1075 f = read_firmware_file(firmware_file);
1076 if(!f) {
1077 printf("Couldn't read the firmware file!\n");
1078 return -1;
1079 }
1080
1081 switch(action) {
1082 case LIST_ACTION:
1083 list_firmware(f, dump, write_file);
1084 break;
1085
1086 case ADD_ACTION:
1087 add_standard(f, firmware_file, file);
1088 break;
1089
1090 case DELETE_ACTION:
1091 delete_standard(f, firmware_file, strtoul(nr_str, NULL, 10));
1092 break;
1093
1094 case SET_TYPE_ACTION:
1095 set_standard_type(f, firmware_file, strtoul(index_str, NULL, 10), strtoul(nr_str, NULL, 10));
1096 break;
1097
1098 case SET_ID_ACTION:
1099 set_standard_id(f, firmware_file, strtoul(index_str, NULL, 10), strtoul(nr_str, NULL, 10));
1100
1101 case SEEK_FIRM_ACTION:
1102 seek_firmware(f, seek_file, write_file);
1103 break;
1104 }
1105 return 0;
1106 }
1107