1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 - 2007 by Björn Stenberg
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
28 #include "gigabeats.h"
30 #include "telechips.h"
32 #include "iaudio_bl_flash.h"
34 int iaudio_encode(char *iname
, char *oname
, char *idstring
);
35 int ipod_encode(char *iname
, char *oname
, int fw_ver
, bool fake_rsrc
);
39 ARCHOS_PLAYER
, /* and V1 recorder */
46 static unsigned int size_limit
[] =
48 0x32000, /* ARCHOS_PLAYER */
49 0x64000, /* ARCHOS_V2RECORDER */
50 0x64000, /* ARCHOS_FMRECORDER */
51 0x64000, /* ARCHOS_ONDIO_SP */
52 0x64000 /* ARCHOS_ONDIO_FM */
55 void short2le(unsigned short val
, unsigned char* addr
)
58 addr
[1] = (val
>> 8) & 0xff;
61 unsigned int le2int(unsigned char* buf
)
63 unsigned int res
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
68 void int2le(unsigned int val
, unsigned char* addr
)
71 addr
[1] = (val
>> 8) & 0xff;
72 addr
[2] = (val
>> 16) & 0xff;
73 addr
[3] = (val
>> 24) & 0xff;
76 void int2be(unsigned int val
, unsigned char* addr
)
78 addr
[0] = (val
>> 24) & 0xff;
79 addr
[1] = (val
>> 16) & 0xff;
80 addr
[2] = (val
>> 8) & 0xff;
84 void short2be(unsigned short val
, unsigned char* addr
)
86 addr
[0] = (val
>> 8) & 0xff;
92 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
94 "\t-fm Archos FM recorder format\n"
95 "\t-v2 Archos V2 recorder format\n"
96 "\t-ofm Archos Ondio FM recorder format\n"
97 "\t-osp Archos Ondio SP format\n"
98 "\t-neo SSI Neo format\n"
99 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
100 "\t-iriver iRiver format\n"
101 "\t-iaudiox5 iAudio X5 format\n"
102 "\t-iaudiox5v iAudio X5V format\n"
103 "\t-iaudiom5 iAudio M5 format\n"
104 "\t-iaudiom3 iAudio M3 format\n");
105 printf("\t-ipod3g ipod firmware partition format (3rd Gen)\n"
106 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
107 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
108 "\t-creative=X Creative firmware structure format\n"
109 "\t (X values: zvm, zvm60, zenvision\n"
111 printf("\t-gigabeat Toshiba Gigabeat F/X format\n"
112 "\t-gigabeats Toshiba Gigabeat S format\n"
113 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
114 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
115 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
116 "\t All mi4 options take two optional arguments:\n");
117 printf("\t -model=XXXX where XXXX is the model id string\n"
118 "\t -type=XXXX where XXXX is a string indicating the \n"
119 "\t type of binary, eg. RBOS, RBBL\n"
120 "\t-tcc=X Telechips generic firmware format (X values: sum, crc)\n"
121 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
122 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
123 "\t ip3g, ip4g, mini, iax5, iam5, iam3, h10, h10_5gb,\n"
124 "\t tpj2, c200, e200, giga, gigs, m100, m500, d2,\n");
125 printf("\t 9200, 1630)\n");
126 printf("\nNo option results in Archos standard player/recorder format.\n");
131 int main (int argc
, char** argv
)
133 unsigned long length
,i
,slen
=0;
134 unsigned char *inbuf
,*outbuf
;
135 unsigned short crc
=0;
136 unsigned long chksum
=0; /* 32 bit checksum */
137 unsigned char header
[24];
138 char *iname
= argv
[1];
139 char *oname
= argv
[2];
140 char *xorstring
=NULL
;
144 unsigned long modelnum
;
147 enum { none
, scramble
, xor, tcc_sum
, tcc_crc
, add
} method
= scramble
;
149 model_id
= ARCHOS_PLAYER
;
155 if(!strcmp(argv
[1], "-fm")) {
160 model_id
= ARCHOS_FMRECORDER
;
163 else if(!strcmp(argv
[1], "-v2")) {
168 model_id
= ARCHOS_V2RECORDER
;
171 else if(!strcmp(argv
[1], "-ofm")) {
176 model_id
= ARCHOS_ONDIO_FM
;
179 else if(!strcmp(argv
[1], "-osp")) {
184 model_id
= ARCHOS_ONDIO_SP
;
187 else if(!strcmp(argv
[1], "-neo")) {
193 else if(!strncmp(argv
[1], "-mm=", 4)) {
198 version
= argv
[1][4];
202 printf("Multimedia needs an xor string\n");
206 else if(!strncmp(argv
[1], "-tcc=", 4)) {
211 if(!strcmp(&argv
[1][5], "sum"))
213 else if(!strcmp(&argv
[1][5], "crc"))
216 fprintf(stderr
, "unsupported TCC method: %s\n", &argv
[1][5]);
220 else if(!strncmp(argv
[1], "-add=", 5)) {
225 if(!strcmp(&argv
[1][5], "h120"))
227 else if(!strcmp(&argv
[1][5], "h140"))
228 modelnum
= 0; /* the same as the h120 */
229 else if(!strcmp(&argv
[1][5], "h100"))
231 else if(!strcmp(&argv
[1][5], "h300"))
233 else if(!strcmp(&argv
[1][5], "ipco"))
235 else if(!strcmp(&argv
[1][5], "nano"))
237 else if(!strcmp(&argv
[1][5], "ipvd"))
239 else if(!strcmp(&argv
[1][5], "fp7x"))
241 else if(!strcmp(&argv
[1][5], "ip3g"))
243 else if(!strcmp(&argv
[1][5], "ip4g"))
245 else if(!strcmp(&argv
[1][5], "mini"))
247 else if(!strcmp(&argv
[1][5], "iax5"))
249 else if(!strcmp(&argv
[1][5], "mn2g"))
251 else if(!strcmp(&argv
[1][5], "h10"))
253 else if(!strcmp(&argv
[1][5], "h10_5gb"))
255 else if(!strcmp(&argv
[1][5], "tpj2"))
257 else if(!strcmp(&argv
[1][5], "e200"))
259 else if(!strcmp(&argv
[1][5], "iam5"))
261 else if(!strcmp(&argv
[1][5], "giga"))
263 else if(!strcmp(&argv
[1][5], "1g2g"))
265 else if(!strcmp(&argv
[1][5], "c200"))
267 else if(!strcmp(&argv
[1][5], "gigs"))
269 else if(!strcmp(&argv
[1][5], "m500"))
271 else if(!strcmp(&argv
[1][5], "m100"))
273 else if(!strcmp(&argv
[1][5], "d2"))
275 else if(!strcmp(&argv
[1][5], "iam3"))
277 else if(!strcmp(&argv
[1][5], "9200")) /* Philips SA9200 */
279 else if(!strcmp(&argv
[1][5], "1630")) /* Philips HDD1630 */
282 fprintf(stderr
, "unsupported model: %s\n", &argv
[1][5]);
285 /* we store a 4-letter model name too, for humans */
286 strcpy(modelname
, &argv
[1][5]);
287 chksum
= modelnum
; /* start checksum calcs with this */
290 else if(!strcmp(argv
[1], "-iriver")) {
291 /* iRiver code dealt with in the iriver.c code */
294 return (iriver_encode(iname
, oname
, FALSE
) != 0) ? -1 : 0;
296 else if(!strcmp(argv
[1], "-gigabeat")) {
297 /* iRiver code dealt with in the iriver.c code */
300 gigabeat_code(iname
, oname
);
303 else if(!strcmp(argv
[1], "-gigabeats")) {
306 gigabeat_s_code(iname
, oname
);
309 else if(!strcmp(argv
[1], "-iaudiox5")) {
312 return iaudio_encode(iname
, oname
, "COWON_X5_FW");
314 else if(!strcmp(argv
[1], "-iaudiox5v")) {
317 return iaudio_encode(iname
, oname
, "COWON_X5V_FW");
319 else if(!strcmp(argv
[1], "-iaudiom5")) {
322 return iaudio_encode(iname
, oname
, "COWON_M5_FW");
324 else if(!strcmp(argv
[1], "-iaudiom3")) {
327 return iaudio_encode(iname
, oname
, "COWON_M3_FW");
329 else if(!strcmp(argv
[1], "-ipod3g")) {
332 return ipod_encode(iname
, oname
, 2, false); /* Firmware image v2 */
334 else if(!strcmp(argv
[1], "-ipod4g")) {
337 return ipod_encode(iname
, oname
, 3, false); /* Firmware image v3 */
339 else if(!strcmp(argv
[1], "-ipod5g")) {
342 return ipod_encode(iname
, oname
, 3, true); /* Firmware image v3 */
344 else if(!strncmp(argv
[1], "-creative=", 10)) {
347 if(!strcmp(&argv
[1][10], "zvm"))
348 return zvm_encode(iname
, oname
, ZENVISIONM
);
349 else if(!strcmp(&argv
[1][10], "zvm60"))
350 return zvm_encode(iname
, oname
, ZENVISIONM60
);
351 else if(!strcmp(&argv
[1][10], "zenvision"))
352 return zvm_encode(iname
, oname
, ZENVISION
);
353 else if(!strcmp(&argv
[1][10], "zenv"))
354 return zvm_encode(iname
, oname
, ZENV
);
355 else if(!strcmp(&argv
[1][10], "zen"))
356 return zvm_encode(iname
, oname
, ZEN
);
358 fprintf(stderr
, "unsupported Creative device: %s\n", &argv
[1][10]);
362 else if(!strncmp(argv
[1], "-mi4", 4)) {
367 if(!strcmp(&argv
[1][4], "v2")) {
368 mi4magic
= MI4_MAGIC_DEFAULT
;
369 version
= 0x00010201;
371 else if(!strcmp(&argv
[1][4], "v3")) {
372 mi4magic
= MI4_MAGIC_DEFAULT
;
373 version
= 0x00010301;
375 else if(!strcmp(&argv
[1][4], "r")) {
376 mi4magic
= MI4_MAGIC_R
;
377 version
= 0x00010301;
380 printf( "Invalid mi4 version: %s\n", &argv
[1][4]);
387 if(!strncmp(argv
[2], "-model=", 7)) {
390 strncpy(model
, &argv
[2][7], 4);
392 if(!strncmp(argv
[3], "-type=", 6)) {
395 strncpy(type
, &argv
[3][6], 4);
399 return mi4_encode(iname
, oname
, version
, mi4magic
, model
, type
);
403 file
= fopen(iname
,"rb");
408 fseek(file
,0,SEEK_END
);
409 length
= ftell(file
);
410 length
= (length
+ 3) & ~3; /* Round up to nearest 4 byte boundary */
412 if ((method
== scramble
) &&
413 ((length
+ headerlen
) >= size_limit
[model_id
])) {
414 printf("error: firmware image is %ld bytes while max size is %u!\n",
416 size_limit
[model_id
]);
421 fseek(file
,0,SEEK_SET
);
422 inbuf
= malloc(length
);
424 outbuf
= malloc(length
*2);
425 else if(method
== add
)
426 outbuf
= malloc(length
+ 8);
428 outbuf
= malloc(length
);
429 if ( !inbuf
|| !outbuf
) {
430 printf("out of memory!\n");
434 /* zero-fill the last 4 bytes to make sure there's no rubbish there
435 when we write the size-aligned file later */
436 memset(outbuf
+length
-4, 0, 4);
440 i
=fread(inbuf
,1,length
,file
);
450 for (i
= 0; i
< length
; i
++) {
451 /* add 8 unsigned bits but keep a 32 bit sum */
457 for (i
= 0; i
< length
; i
++) {
458 unsigned long addr
= (i
>> 2) + ((i
% 4) * slen
);
459 unsigned char data
= inbuf
[i
];
460 data
= ~((data
<< 1) | ((data
>> 7) & 1)); /* poor man's ROL */
468 for (i
=0; i
<length
; i
++) {
470 outbuf
[slen
++] = 0xff; /* all data is uncompressed */
471 outbuf
[slen
++] = inbuf
[i
];
476 /* dummy case just to silence picky compilers */
480 if((method
== none
) || (method
== scramble
) || (method
== xor)) {
481 /* calculate checksum */
482 for (i
=0;i
<length
;i
++)
486 memset(header
, 0, sizeof header
);
491 int2be(chksum
, header
); /* checksum, big-endian */
492 memcpy(&header
[4], modelname
, 4); /* 4 bytes model name */
493 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
499 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
500 telechips_encode_sum(outbuf
, length
);
504 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
505 telechips_encode_crc(outbuf
, length
);
509 if (headerlen
== 6) {
510 int2be(length
, header
);
511 header
[4] = (crc
>> 8) & 0xff;
512 header
[5] = crc
& 0xff;
518 header
[3] = 0xff; /* ??? */
520 header
[6] = (crc
>> 8) & 0xff;
521 header
[7] = crc
& 0xff;
523 header
[11] = version
;
525 header
[15] = headerlen
; /* really? */
527 int2be(length
, &header
[20]);
533 int xorlen
= strlen(xorstring
);
536 for (i
=0; i
<slen
; i
++)
537 outbuf
[i
] ^= xorstring
[i
& (xorlen
-1)];
539 /* calculate checksum */
540 for (i
=0; i
<slen
; i
++)
543 header
[0] = header
[2] = 'Z';
544 header
[1] = header
[3] = version
;
545 int2le(length
, &header
[4]);
546 int2le(slen
, &header
[8]);
547 int2le(crc
, &header
[12]);
552 #define MY_FIRMWARE_TYPE "Rockbox"
553 #define MY_HEADER_VERSION 1
555 strncpy((char *)header
, MY_FIRMWARE_TYPE
,9);
556 header
[9]='\0'; /*shouldn't have to, but to be SURE */
557 header
[10]=MY_HEADER_VERSION
&0xFF;
558 header
[11]=(crc
>>8)&0xFF;
560 int2be(sizeof(header
), &header
[12]);
565 file
= fopen(oname
,"wb");
571 if ( !fwrite(header
,headerlen
,1,file
) ) {
576 if ( !fwrite(outbuf
,length
,1,file
) ) {
588 int iaudio_encode(char *iname
, char *oname
, char *idstring
)
593 unsigned char *outbuf
;
595 unsigned char sum
= 0;
597 file
= fopen(iname
, "rb");
602 fseek(file
,0,SEEK_END
);
603 length
= ftell(file
);
605 fseek(file
,0,SEEK_SET
);
606 outbuf
= malloc(length
+0x1030);
609 printf("out of memory!\n");
613 len
= fread(outbuf
+0x1030, 1, length
, file
);
614 if(len
< (size_t) length
) {
619 memset(outbuf
, 0, 0x1030);
620 strcpy((char *)outbuf
, idstring
);
621 memcpy(outbuf
+0x20, iaudio_bl_flash
,
622 BMPWIDTH_iaudio_bl_flash
* (BMPHEIGHT_iaudio_bl_flash
/8) * 2);
623 short2be(BMPWIDTH_iaudio_bl_flash
, &outbuf
[0x10]);
624 short2be((BMPHEIGHT_iaudio_bl_flash
/8), &outbuf
[0x12]);
627 for(i
= 0; i
< length
;i
++)
628 sum
+= outbuf
[0x1030 + i
];
630 int2be(length
, &outbuf
[0x1024]);
631 outbuf
[0x102b] = sum
;
635 file
= fopen(oname
, "wb");
641 len
= fwrite(outbuf
, 1, length
+0x1030, file
);
642 if(len
< (size_t)length
) {
652 /* Create an ipod firmware partition image
654 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
656 This function doesn't yet handle the Broadcom resource image for the 5g,
657 so the resulting images won't be usable.
659 This has also only been tested on an ipod Photo
662 int ipod_encode(char *iname
, char *oname
, int fw_ver
, bool fake_rsrc
)
664 static const char *apple_stop_sign
= "{{~~ /-----\\ "\
685 unsigned int sum
= 0;
686 unsigned int rsrcsum
= 0;
687 unsigned char *outbuf
;
691 file
= fopen(iname
, "rb");
696 fseek(file
,0,SEEK_END
);
697 length
= ftell(file
);
699 fseek(file
,0,SEEK_SET
);
701 bufsize
=(length
+0x4600);
703 bufsize
= (bufsize
+ 0x400) & ~0x200;
706 outbuf
= malloc(bufsize
);
709 printf("out of memory!\n");
713 len
= fread(outbuf
+0x4600, 1, length
, file
);
714 if(len
< (size_t)length
) {
720 /* Calculate checksum for later use in header */
721 for(i
= 0x4600; i
< 0x4600+length
;i
++)
724 /* Clear the header area to zero */
725 memset(outbuf
, 0, 0x4600);
727 /* APPLE STOP SIGN */
728 strcpy((char *)outbuf
, apple_stop_sign
);
731 memcpy(&outbuf
[0x100],"]ih[",4); /* Magic */
732 int2le(0x4000, &outbuf
[0x104]); /* Firmware offset relative to 0x200 */
733 short2le(0x10c, &outbuf
[0x108]); /* Location of extended header */
734 short2le(fw_ver
, &outbuf
[0x10a]);
736 /* Firmware Directory - "osos" entry */
737 memcpy(&outbuf
[0x4200],"!ATAsoso",8); /* dev and type */
738 int2le(0, &outbuf
[0x4208]); /* id */
739 int2le(0x4400, &outbuf
[0x420c]); /* devOffset */
740 int2le(length
, &outbuf
[0x4210]); /* Length of firmware */
741 int2le(0x10000000, &outbuf
[0x4214]); /* Addr */
742 int2le(0, &outbuf
[0x4218]); /* Entry Offset */
743 int2le(sum
, &outbuf
[0x421c]); /* Checksum */
744 int2le(0x00006012, &outbuf
[0x4220]); /* vers - 0x6012 is a guess */
745 int2le(0xffffffff, &outbuf
[0x4224]); /* LoadAddr - for flash images */
747 /* "rsrc" entry (if applicable) */
749 rsrcoffset
=(length
+0x4600+0x200) & ~0x200;
753 memcpy(&outbuf
[0x4228],"!ATAcrsr",8); /* dev and type */
754 int2le(0, &outbuf
[0x4230]); /* id */
755 int2le(rsrcoffset
, &outbuf
[0x4234]); /* devOffset */
756 int2le(rsrclength
, &outbuf
[0x4238]); /* Length of firmware */
757 int2le(0x10000000, &outbuf
[0x423c]); /* Addr */
758 int2le(0, &outbuf
[0x4240]); /* Entry Offset */
759 int2le(rsrcsum
, &outbuf
[0x4244]); /* Checksum */
760 int2le(0x0000b000, &outbuf
[0x4248]); /* vers */
761 int2le(0xffffffff, &outbuf
[0x424c]); /* LoadAddr - for flash images */
764 file
= fopen(oname
, "wb");
770 len
= fwrite(outbuf
, 1, length
+0x4600, file
);
771 if(len
< (size_t)length
) {