1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 - 2007 by Björn Stenberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
26 #include "gigabeats.h"
28 #include "telechips.h"
30 int iaudio_encode(char *iname
, char *oname
, char *idstring
);
31 int ipod_encode(char *iname
, char *oname
, int fw_ver
, bool fake_rsrc
);
35 ARCHOS_PLAYER
, /* and V1 recorder */
44 0x32000, /* ARCHOS_PLAYER */
45 0x64000, /* ARCHOS_V2RECORDER */
46 0x64000, /* ARCHOS_FMRECORDER */
47 0x64000, /* ARCHOS_ONDIO_SP */
48 0x64000 /* ARCHOS_ONDIO_FM */
51 void short2le(unsigned short val
, unsigned char* addr
)
54 addr
[1] = (val
>> 8) & 0xff;
57 unsigned int le2int(unsigned char* buf
)
59 unsigned int res
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
64 void int2le(unsigned int val
, unsigned char* addr
)
67 addr
[1] = (val
>> 8) & 0xff;
68 addr
[2] = (val
>> 16) & 0xff;
69 addr
[3] = (val
>> 24) & 0xff;
72 void int2be(unsigned int val
, unsigned char* addr
)
74 addr
[0] = (val
>> 24) & 0xff;
75 addr
[1] = (val
>> 16) & 0xff;
76 addr
[2] = (val
>> 8) & 0xff;
82 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
84 "\t-fm Archos FM recorder format\n"
85 "\t-v2 Archos V2 recorder format\n"
86 "\t-ofm Archos Ondio FM recorder format\n"
87 "\t-osp Archos Ondio SP format\n"
88 "\t-neo SSI Neo format\n"
89 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
90 "\t-iriver iRiver format\n"
91 "\t-iaudiox5 iAudio X5 format\n"
92 "\t-iaudiox5v iAudio X5V format\n"
93 "\t-iaudiom5 iAudio M5 format\n"
94 "\t-ipod3g ipod firmware partition format (3rd Gen)\n"
95 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
96 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
97 "\t-gigabeat Toshiba Gigabeat F/X format\n"
98 "\t-gigabeats Toshiba Gigabeat S format\n"
99 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
100 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
101 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
102 "\t All mi4 options take two optional arguments:\n"
103 "\t -model=XXXX where XXXX is the model id string\n"
104 "\t -type=XXXX where XXXX is a string indicating the \n"
105 "\t type of binary, eg. RBOS, RBBL\n"
106 "\t-tcc=X Telechips generic firmware format (X values: sum, crc)\n"
107 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
108 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
109 "\t ip3g, ip4g, mini, iax5, h10, h10_5gb, tpj2,\n"
110 "\t c200, e200, giga, m500)\n"
111 "\nNo option results in Archos standard player/recorder format.\n");
116 int main (int argc
, char** argv
)
118 unsigned long length
,i
,slen
;
119 unsigned char *inbuf
,*outbuf
;
120 unsigned short crc
=0;
121 unsigned long chksum
=0; /* 32 bit checksum */
122 unsigned char header
[24];
123 char *iname
= argv
[1];
124 char *oname
= argv
[2];
129 unsigned long modelnum
;
132 enum { none
, scramble
, xor, tcc_sum
, tcc_crc
, add
} method
= scramble
;
134 model_id
= ARCHOS_PLAYER
;
140 if(!strcmp(argv
[1], "-fm")) {
145 model_id
= ARCHOS_FMRECORDER
;
148 else if(!strcmp(argv
[1], "-v2")) {
153 model_id
= ARCHOS_V2RECORDER
;
156 else if(!strcmp(argv
[1], "-ofm")) {
161 model_id
= ARCHOS_ONDIO_FM
;
164 else if(!strcmp(argv
[1], "-osp")) {
169 model_id
= ARCHOS_ONDIO_SP
;
172 else if(!strcmp(argv
[1], "-neo")) {
178 else if(!strncmp(argv
[1], "-mm=", 4)) {
183 version
= argv
[1][4];
187 printf("Multimedia needs an xor string\n");
191 else if(!strncmp(argv
[1], "-tcc=", 4)) {
196 if(!strcmp(&argv
[1][5], "sum"))
198 else if(!strcmp(&argv
[1][5], "crc"))
201 fprintf(stderr
, "unsupported TCC method: %s\n", &argv
[1][5]);
205 else if(!strncmp(argv
[1], "-add=", 5)) {
210 if(!strcmp(&argv
[1][5], "h120"))
212 else if(!strcmp(&argv
[1][5], "h140"))
213 modelnum
= 0; /* the same as the h120 */
214 else if(!strcmp(&argv
[1][5], "h100"))
216 else if(!strcmp(&argv
[1][5], "h300"))
218 else if(!strcmp(&argv
[1][5], "ipco"))
220 else if(!strcmp(&argv
[1][5], "nano"))
222 else if(!strcmp(&argv
[1][5], "ipvd"))
224 else if(!strcmp(&argv
[1][5], "fp7x"))
226 else if(!strcmp(&argv
[1][5], "ip3g"))
228 else if(!strcmp(&argv
[1][5], "ip4g"))
230 else if(!strcmp(&argv
[1][5], "mini"))
232 else if(!strcmp(&argv
[1][5], "iax5"))
234 else if(!strcmp(&argv
[1][5], "mn2g"))
236 else if(!strcmp(&argv
[1][5], "h10"))
238 else if(!strcmp(&argv
[1][5], "h10_5gb"))
240 else if(!strcmp(&argv
[1][5], "tpj2"))
242 else if(!strcmp(&argv
[1][5], "e200"))
244 else if(!strcmp(&argv
[1][5], "iam5"))
246 else if(!strcmp(&argv
[1][5], "giga"))
248 else if(!strcmp(&argv
[1][5], "1g2g"))
250 else if(!strcmp(&argv
[1][5], "c200"))
252 else if(!strcmp(&argv
[1][5], "gigs"))
254 else if(!strcmp(&argv
[1][5], "m500"))
257 fprintf(stderr
, "unsupported model: %s\n", &argv
[1][5]);
260 /* we store a 4-letter model name too, for humans */
261 strcpy(modelname
, &argv
[1][5]);
262 chksum
= modelnum
; /* start checksum calcs with this */
265 else if(!strcmp(argv
[1], "-iriver")) {
266 /* iRiver code dealt with in the iriver.c code */
269 iriver_encode(iname
, oname
, FALSE
);
272 else if(!strcmp(argv
[1], "-gigabeat")) {
273 /* iRiver code dealt with in the iriver.c code */
276 gigabeat_code(iname
, oname
);
279 else if(!strcmp(argv
[1], "-gigabeats")) {
282 gigabeat_s_code(iname
, oname
);
285 else if(!strcmp(argv
[1], "-iaudiox5")) {
288 return iaudio_encode(iname
, oname
, "COWON_X5_FW");
290 else if(!strcmp(argv
[1], "-iaudiox5v")) {
293 return iaudio_encode(iname
, oname
, "COWON_X5V_FW");
295 else if(!strcmp(argv
[1], "-iaudiom5")) {
298 return iaudio_encode(iname
, oname
, "COWON_M5_FW");
300 else if(!strcmp(argv
[1], "-ipod3g")) {
303 return ipod_encode(iname
, oname
, 2, false); /* Firmware image v2 */
305 else if(!strcmp(argv
[1], "-ipod4g")) {
308 return ipod_encode(iname
, oname
, 3, false); /* Firmware image v3 */
310 else if(!strcmp(argv
[1], "-ipod5g")) {
313 return ipod_encode(iname
, oname
, 3, true); /* Firmware image v3 */
315 else if(!strncmp(argv
[1], "-mi4", 4)) {
321 if(!strcmp(&argv
[1][4], "v2")) {
322 mi4magic
= MI4_MAGIC_DEFAULT
;
323 version
= 0x00010201;
325 else if(!strcmp(&argv
[1][4], "v3")) {
326 mi4magic
= MI4_MAGIC_DEFAULT
;
327 version
= 0x00010301;
329 else if(!strcmp(&argv
[1][4], "r")) {
330 mi4magic
= MI4_MAGIC_R
;
331 version
= 0x00010301;
334 printf( "Invalid mi4 version: %s\n", &argv
[1][4]);
341 if(!strncmp(argv
[2], "-model=", 7)) {
344 strncpy(model
, &argv
[2][7], 4);
346 if(!strncmp(argv
[3], "-type=", 6)) {
349 strncpy(type
, &argv
[3][6], 4);
353 return mi4_encode(iname
, oname
, version
, mi4magic
, model
, type
);
357 file
= fopen(iname
,"rb");
362 fseek(file
,0,SEEK_END
);
363 length
= ftell(file
);
364 length
= (length
+ 3) & ~3; /* Round up to nearest 4 byte boundary */
366 if ((method
== scramble
) &&
367 ((length
+ headerlen
) >= size_limit
[model_id
])) {
368 printf("error: firmware image is %d bytes while max size is %d!\n",
370 size_limit
[model_id
]);
375 fseek(file
,0,SEEK_SET
);
376 inbuf
= malloc(length
);
378 outbuf
= malloc(length
*2);
379 else if(method
== add
)
380 outbuf
= malloc(length
+ 8);
382 outbuf
= malloc(length
);
383 if ( !inbuf
|| !outbuf
) {
384 printf("out of memory!\n");
388 /* zero-fill the last 4 bytes to make sure there's no rubbish there
389 when we write the size-aligned file later */
390 memset(outbuf
+length
-4, 0, 4);
394 i
=fread(inbuf
,1,length
,file
);
404 for (i
= 0; i
< length
; i
++) {
405 /* add 8 unsigned bits but keep a 32 bit sum */
411 for (i
= 0; i
< length
; i
++) {
412 unsigned long addr
= (i
>> 2) + ((i
% 4) * slen
);
413 unsigned char data
= inbuf
[i
];
414 data
= ~((data
<< 1) | ((data
>> 7) & 1)); /* poor man's ROL */
422 for (i
=0; i
<length
; i
++) {
424 outbuf
[slen
++] = 0xff; /* all data is uncompressed */
425 outbuf
[slen
++] = inbuf
[i
];
430 if((method
== none
) || (method
== scramble
) || (method
== xor)) {
431 /* calculate checksum */
432 for (i
=0;i
<length
;i
++)
436 memset(header
, 0, sizeof header
);
441 int2be(chksum
, header
); /* checksum, big-endian */
442 memcpy(&header
[4], modelname
, 4); /* 4 bytes model name */
443 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
449 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
450 telechips_encode_sum(outbuf
, length
);
454 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
455 telechips_encode_crc(outbuf
, length
);
459 if (headerlen
== 6) {
460 int2be(length
, header
);
461 header
[4] = (crc
>> 8) & 0xff;
462 header
[5] = crc
& 0xff;
468 header
[3] = 0xff; /* ??? */
470 header
[6] = (crc
>> 8) & 0xff;
471 header
[7] = crc
& 0xff;
473 header
[11] = version
;
475 header
[15] = headerlen
; /* really? */
477 int2be(length
, &header
[20]);
483 int xorlen
= strlen(xorstring
);
486 for (i
=0; i
<slen
; i
++)
487 outbuf
[i
] ^= xorstring
[i
& (xorlen
-1)];
489 /* calculate checksum */
490 for (i
=0; i
<slen
; i
++)
493 header
[0] = header
[2] = 'Z';
494 header
[1] = header
[3] = version
;
495 int2le(length
, &header
[4]);
496 int2le(slen
, &header
[8]);
497 int2le(crc
, &header
[12]);
502 #define MY_FIRMWARE_TYPE "Rockbox"
503 #define MY_HEADER_VERSION 1
505 strncpy((char *)header
, MY_FIRMWARE_TYPE
,9);
506 header
[9]='\0'; /*shouldn't have to, but to be SURE */
507 header
[10]=MY_HEADER_VERSION
&0xFF;
508 header
[11]=(crc
>>8)&0xFF;
510 int2be(sizeof(header
), &header
[12]);
515 file
= fopen(oname
,"wb");
521 if ( !fwrite(header
,headerlen
,1,file
) ) {
526 if ( !fwrite(outbuf
,length
,1,file
) ) {
538 int iaudio_encode(char *iname
, char *oname
, char *idstring
)
543 unsigned char *outbuf
;
545 unsigned char sum
= 0;
547 file
= fopen(iname
, "rb");
552 fseek(file
,0,SEEK_END
);
553 length
= ftell(file
);
555 fseek(file
,0,SEEK_SET
);
556 outbuf
= malloc(length
+0x1030);
559 printf("out of memory!\n");
563 len
= fread(outbuf
+0x1030, 1, length
, file
);
569 memset(outbuf
, 0, 0x1030);
570 strcpy((char *)outbuf
, idstring
);
572 for(i
= 0; i
< length
;i
++)
573 sum
+= outbuf
[0x1030 + i
];
575 int2be(length
, &outbuf
[0x1024]);
576 outbuf
[0x102b] = sum
;
580 file
= fopen(oname
, "wb");
586 len
= fwrite(outbuf
, 1, length
+0x1030, file
);
596 /* Create an ipod firmware partition image
598 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
600 This function doesn't yet handle the Broadcom resource image for the 5g,
601 so the resulting images won't be usable.
603 This has also only been tested on an ipod Photo
606 int ipod_encode(char *iname
, char *oname
, int fw_ver
, bool fake_rsrc
)
608 static const char *apple_stop_sign
= "{{~~ /-----\\ "\
629 unsigned int sum
= 0;
630 unsigned int rsrcsum
= 0;
631 unsigned char *outbuf
;
635 file
= fopen(iname
, "rb");
640 fseek(file
,0,SEEK_END
);
641 length
= ftell(file
);
643 fseek(file
,0,SEEK_SET
);
645 bufsize
=(length
+0x4600);
647 bufsize
= (bufsize
+ 0x400) & ~0x200;
650 outbuf
= malloc(bufsize
);
653 printf("out of memory!\n");
657 len
= fread(outbuf
+0x4600, 1, length
, file
);
664 /* Calculate checksum for later use in header */
665 for(i
= 0x4600; i
< 0x4600+length
;i
++)
668 /* Clear the header area to zero */
669 memset(outbuf
, 0, 0x4600);
671 /* APPLE STOP SIGN */
672 strcpy((char *)outbuf
, apple_stop_sign
);
675 memcpy(&outbuf
[0x100],"]ih[",4); /* Magic */
676 int2le(0x4000, &outbuf
[0x104]); /* Firmware offset relative to 0x200 */
677 short2le(0x10c, &outbuf
[0x108]); /* Location of extended header */
678 short2le(fw_ver
, &outbuf
[0x10a]);
680 /* Firmware Directory - "osos" entry */
681 memcpy(&outbuf
[0x4200],"!ATAsoso",8); /* dev and type */
682 int2le(0, &outbuf
[0x4208]); /* id */
683 int2le(0x4400, &outbuf
[0x420c]); /* devOffset */
684 int2le(length
, &outbuf
[0x4210]); /* Length of firmware */
685 int2le(0x10000000, &outbuf
[0x4214]); /* Addr */
686 int2le(0, &outbuf
[0x4218]); /* Entry Offset */
687 int2le(sum
, &outbuf
[0x421c]); /* Checksum */
688 int2le(0x00006012, &outbuf
[0x4220]); /* vers - 0x6012 is a guess */
689 int2le(0xffffffff, &outbuf
[0x4224]); /* LoadAddr - for flash images */
691 /* "rsrc" entry (if applicable) */
693 rsrcoffset
=(length
+0x4600+0x200) & ~0x200;
697 memcpy(&outbuf
[0x4228],"!ATAcrsr",8); /* dev and type */
698 int2le(0, &outbuf
[0x4230]); /* id */
699 int2le(rsrcoffset
, &outbuf
[0x4234]); /* devOffset */
700 int2le(rsrclength
, &outbuf
[0x4238]); /* Length of firmware */
701 int2le(0x10000000, &outbuf
[0x423c]); /* Addr */
702 int2le(0, &outbuf
[0x4240]); /* Entry Offset */
703 int2le(rsrcsum
, &outbuf
[0x4244]); /* Checksum */
704 int2le(0x0000b000, &outbuf
[0x4248]); /* vers */
705 int2le(0xffffffff, &outbuf
[0x424c]); /* LoadAddr - for flash images */
708 file
= fopen(oname
, "wb");
714 len
= fwrite(outbuf
, 1, length
+0x4600, file
);