forked from len0rd/rockbox
rbutil: Merge rbutil with utils folder.
rbutil uses several components from the utils folder, and can be considered part of utils too. Having it in a separate folder is an arbitrary split that doesn't help anymore these days, so merge them. This also allows other utils to easily use libtools.make without the need to navigate to a different folder. Change-Id: I3fc2f4de19e3e776553efb5dea5f779dfec0dc21
This commit is contained in:
parent
6c6f0757d7
commit
c876d3bbef
494 changed files with 13 additions and 13 deletions
23
utils/bspatch/LICENSE
Normal file
23
utils/bspatch/LICENSE
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
Copyright 2003-2005 Colin Percival
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted providing that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
17
utils/bspatch/Makefile
Normal file
17
utils/bspatch/Makefile
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
# $Id$
|
||||
#
|
||||
|
||||
LIBSOURCES := bspatch.c
|
||||
|
||||
SOURCES := main.c
|
||||
|
||||
OUTPUT := bspatch
|
||||
EXTRADEPS := libbz2.a
|
||||
|
||||
include ../libtools.make
|
||||
218
utils/bspatch/bspatch.c
Normal file
218
utils/bspatch/bspatch.c
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
/*-
|
||||
* Copyright 2003-2005 Colin Percival
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include "../bzip2/bzlib.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define errx err
|
||||
void err(int exitcode, const char * fmt, ...)
|
||||
{
|
||||
va_list valist;
|
||||
va_start(valist, fmt);
|
||||
vprintf(fmt, valist);
|
||||
va_end(valist);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
static long offtin(u_char *buf)
|
||||
{
|
||||
long y;
|
||||
|
||||
y = buf[7] & 0x7F;
|
||||
y = y * 256;y += buf[6];
|
||||
y = y * 256;y += buf[5];
|
||||
y = y * 256;y += buf[4];
|
||||
y = y * 256;y += buf[3];
|
||||
y = y * 256;y += buf[2];
|
||||
y = y * 256;y += buf[1];
|
||||
y = y * 256;y += buf[0];
|
||||
|
||||
if (buf[7] & 0x80) y = -y;
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
int apply_bspatch(const char *infile, const char *outfile, const char *patchfile)
|
||||
{
|
||||
FILE * f, *cpf, *dpf, *epf;
|
||||
BZFILE * cpfbz2, *dpfbz2, *epfbz2;
|
||||
int cbz2err, dbz2err, ebz2err;
|
||||
FILE * fs;
|
||||
long oldsize, newsize;
|
||||
long bzctrllen, bzdatalen;
|
||||
u_char header[32], buf[8];
|
||||
u_char *pold, *pnew;
|
||||
long oldpos, newpos;
|
||||
long ctrl[3];
|
||||
long lenread;
|
||||
long i;
|
||||
|
||||
/* Open patch file */
|
||||
if ((f = fopen(patchfile, "r")) == NULL)
|
||||
err(1, "fopen(%s)", patchfile);
|
||||
|
||||
/*
|
||||
File format:
|
||||
0 8 "BSDIFF40"
|
||||
8 8 X
|
||||
16 8 Y
|
||||
24 8 sizeof(newfile)
|
||||
32 X bzip2(control block)
|
||||
32+X Y bzip2(diff block)
|
||||
32+X+Y ??? bzip2(extra block)
|
||||
with control block a set of triples (x,y,z) meaning "add x bytes
|
||||
from oldfile to x bytes from the diff block; copy y bytes from the
|
||||
extra block; seek forwards in oldfile by z bytes".
|
||||
*/
|
||||
|
||||
/* Read header */
|
||||
if (fread(header, 1, 32, f) < 32) {
|
||||
if (feof(f))
|
||||
errx(1, "Corrupt patch\n");
|
||||
err(1, "fread(%s)", patchfile);
|
||||
}
|
||||
|
||||
/* Check for appropriate magic */
|
||||
if (memcmp(header, "BSDIFF40", 8) != 0)
|
||||
errx(1, "Corrupt patch\n");
|
||||
|
||||
/* Read lengths from header */
|
||||
bzctrllen = offtin(header + 8);
|
||||
bzdatalen = offtin(header + 16);
|
||||
newsize = offtin(header + 24);
|
||||
if ((bzctrllen < 0) || (bzdatalen < 0) || (newsize < 0))
|
||||
errx(1, "Corrupt patch\n");
|
||||
|
||||
/* Close patch file and re-open it via libbzip2 at the right places */
|
||||
if (fclose(f))
|
||||
err(1, "fclose(%s)", patchfile);
|
||||
if ((cpf = fopen(patchfile, "rb")) == NULL)
|
||||
err(1, "fopen(%s)", patchfile);
|
||||
if (fseek(cpf, 32, SEEK_SET))
|
||||
err(1, "fseeko(%s, %lld)", patchfile,
|
||||
(long long)32);
|
||||
if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)
|
||||
errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err);
|
||||
if ((dpf = fopen(patchfile, "rb")) == NULL)
|
||||
err(1, "fopen(%s)", patchfile);
|
||||
if (fseek(dpf, 32 + bzctrllen, SEEK_SET))
|
||||
err(1, "fseeko(%s, %lld)", patchfile,
|
||||
(long long)(32 + bzctrllen));
|
||||
if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)
|
||||
errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err);
|
||||
if ((epf = fopen(patchfile, "rb")) == NULL)
|
||||
err(1, "fopen(%s)", patchfile);
|
||||
if (fseek(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
|
||||
err(1, "fseeko(%s, %lld)", patchfile,
|
||||
(long long)(32 + bzctrllen + bzdatalen));
|
||||
if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)
|
||||
errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err);
|
||||
|
||||
fs = fopen(infile, "rb");
|
||||
if (fs == NULL)err(1, "Open failed :%s", infile);
|
||||
if (fseek(fs, 0, SEEK_END) != 0)err(1, "Seek failed :%s", infile);
|
||||
oldsize = ftell(fs);
|
||||
pold = (u_char *)malloc(oldsize + 1);
|
||||
if (pold == NULL) err(1, "Malloc failed :%s", infile);
|
||||
fseek(fs, 0, SEEK_SET);
|
||||
if (fread(pold, 1, oldsize, fs) == -1) err(1, "Read failed :%s", infile);
|
||||
if (fclose(fs) == -1) err(1, "Close failed :%s", infile);
|
||||
|
||||
pnew = malloc(newsize + 1);
|
||||
if (pnew == NULL)err(1, NULL);
|
||||
|
||||
oldpos = 0;newpos = 0;
|
||||
while (newpos < newsize) {
|
||||
/* Read control data */
|
||||
for (i = 0;i <= 2;i++) {
|
||||
lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);
|
||||
if ((lenread < 8) || ((cbz2err != BZ_OK) &&
|
||||
(cbz2err != BZ_STREAM_END)))
|
||||
errx(1, "Corrupt patch\n");
|
||||
ctrl[i] = offtin(buf);
|
||||
};
|
||||
|
||||
/* Sanity-check */
|
||||
if (newpos + ctrl[0] > newsize)
|
||||
errx(1, "Corrupt patch\n");
|
||||
|
||||
/* Read diff string */
|
||||
lenread = BZ2_bzRead(&dbz2err, dpfbz2, pnew + newpos, ctrl[0]);
|
||||
if ((lenread < ctrl[0]) ||
|
||||
((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
|
||||
errx(1, "Corrupt patch\n");
|
||||
|
||||
/* Add pold data to diff string */
|
||||
for (i = 0;i < ctrl[0];i++)
|
||||
if ((oldpos + i >= 0) && (oldpos + i < oldsize))
|
||||
pnew[newpos + i] += pold[oldpos + i];
|
||||
|
||||
/* Adjust pointers */
|
||||
newpos += ctrl[0];
|
||||
oldpos += ctrl[0];
|
||||
|
||||
/* Sanity-check */
|
||||
if (newpos + ctrl[1] > newsize)
|
||||
errx(1, "Corrupt patch\n");
|
||||
|
||||
/* Read extra string */
|
||||
lenread = BZ2_bzRead(&ebz2err, epfbz2, pnew + newpos, ctrl[1]);
|
||||
if ((lenread < ctrl[1]) ||
|
||||
((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
|
||||
errx(1, "Corrupt patch\n");
|
||||
|
||||
/* Adjust pointers */
|
||||
newpos += ctrl[1];
|
||||
oldpos += ctrl[2];
|
||||
};
|
||||
|
||||
/* Clean up the bzip2 reads */
|
||||
BZ2_bzReadClose(&cbz2err, cpfbz2);
|
||||
BZ2_bzReadClose(&dbz2err, dpfbz2);
|
||||
BZ2_bzReadClose(&ebz2err, epfbz2);
|
||||
if (fclose(cpf) || fclose(dpf) || fclose(epf))
|
||||
err(1, "fclose(%s)", patchfile);
|
||||
|
||||
/* Write the pnew file */
|
||||
fs = fopen(outfile, "wb");
|
||||
if (fs == NULL)err(1, "Create failed :%s", outfile);
|
||||
if (fwrite(pnew, 1, newsize, fs) == -1)err(1, "Write failed :%s", outfile);
|
||||
if (fclose(fs) == -1)err(1, "Close failed :%s", outfile);
|
||||
|
||||
free(pnew);
|
||||
free(pold);
|
||||
|
||||
return 0;
|
||||
}
|
||||
19
utils/bspatch/bspatch.h
Normal file
19
utils/bspatch/bspatch.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Simple wrapper for the bspatch entry point.
|
||||
*/
|
||||
|
||||
#ifndef _BSPATCH_H
|
||||
#define _BSPATCH_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int apply_bspatch(const char *infile, const char *outfile, const char *patchfile);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _BSPATCH_H */
|
||||
34
utils/bspatch/main.c
Normal file
34
utils/bspatch/main.c
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*-
|
||||
* Copyright 2003-2005 Colin Percival
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "bspatch.c"
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
if (argc != 4) errx(1, "usage: %s oldfile newfile patchfile\n", argv[0]);
|
||||
|
||||
apply_bspatch(argv[1], argv[2], argv[3]);
|
||||
}
|
||||
42
utils/bzip2/LICENSE
Normal file
42
utils/bzip2/LICENSE
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
This program, "bzip2", the associated library "libbzip2", and all
|
||||
documentation, are copyright (C) 1996-2010 Julian R Seward. All
|
||||
rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
3. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
4. The name of the author may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Julian Seward, jseward@bzip.org
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
15
utils/bzip2/Makefile
Normal file
15
utils/bzip2/Makefile
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
# $Id$
|
||||
#
|
||||
|
||||
LIBSOURCES := blocksort.c compress.c decompress.c randtable.c \
|
||||
bzlib.c crctable.c huffman.c
|
||||
|
||||
OUTPUT := bz2
|
||||
|
||||
include ../libtools.make
|
||||
1094
utils/bzip2/blocksort.c
Normal file
1094
utils/bzip2/blocksort.c
Normal file
File diff suppressed because it is too large
Load diff
1572
utils/bzip2/bzlib.c
Normal file
1572
utils/bzip2/bzlib.c
Normal file
File diff suppressed because it is too large
Load diff
282
utils/bzip2/bzlib.h
Normal file
282
utils/bzip2/bzlib.h
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Public header file for the library. ---*/
|
||||
/*--- bzlib.h ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#ifndef _BZLIB_H
|
||||
#define _BZLIB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BZ_RUN 0
|
||||
#define BZ_FLUSH 1
|
||||
#define BZ_FINISH 2
|
||||
|
||||
#define BZ_OK 0
|
||||
#define BZ_RUN_OK 1
|
||||
#define BZ_FLUSH_OK 2
|
||||
#define BZ_FINISH_OK 3
|
||||
#define BZ_STREAM_END 4
|
||||
#define BZ_SEQUENCE_ERROR (-1)
|
||||
#define BZ_PARAM_ERROR (-2)
|
||||
#define BZ_MEM_ERROR (-3)
|
||||
#define BZ_DATA_ERROR (-4)
|
||||
#define BZ_DATA_ERROR_MAGIC (-5)
|
||||
#define BZ_IO_ERROR (-6)
|
||||
#define BZ_UNEXPECTED_EOF (-7)
|
||||
#define BZ_OUTBUFF_FULL (-8)
|
||||
#define BZ_CONFIG_ERROR (-9)
|
||||
|
||||
typedef
|
||||
struct {
|
||||
char *next_in;
|
||||
unsigned int avail_in;
|
||||
unsigned int total_in_lo32;
|
||||
unsigned int total_in_hi32;
|
||||
|
||||
char *next_out;
|
||||
unsigned int avail_out;
|
||||
unsigned int total_out_lo32;
|
||||
unsigned int total_out_hi32;
|
||||
|
||||
void *state;
|
||||
|
||||
void *(*bzalloc)(void *,int,int);
|
||||
void (*bzfree)(void *,void *);
|
||||
void *opaque;
|
||||
}
|
||||
bz_stream;
|
||||
|
||||
|
||||
#ifndef BZ_IMPORT
|
||||
#define BZ_EXPORT
|
||||
#endif
|
||||
|
||||
#ifndef BZ_NO_STDIO
|
||||
/* Need a definitition for FILE */
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
# ifdef small
|
||||
/* windows.h define small to char */
|
||||
# undef small
|
||||
# endif
|
||||
# ifdef BZ_EXPORT
|
||||
# define BZ_API(func) WINAPI func
|
||||
# define BZ_EXTERN extern
|
||||
# else
|
||||
/* import windows dll dynamically */
|
||||
# define BZ_API(func) (WINAPI * func)
|
||||
# define BZ_EXTERN
|
||||
# endif
|
||||
#else
|
||||
# define BZ_API(func) func
|
||||
# define BZ_EXTERN extern
|
||||
#endif
|
||||
|
||||
|
||||
/*-- Core (low-level) library functions --*/
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzCompressInit) (
|
||||
bz_stream* strm,
|
||||
int blockSize100k,
|
||||
int verbosity,
|
||||
int workFactor
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzCompress) (
|
||||
bz_stream* strm,
|
||||
int action
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) (
|
||||
bz_stream* strm
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) (
|
||||
bz_stream *strm,
|
||||
int verbosity,
|
||||
int small
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzDecompress) (
|
||||
bz_stream* strm
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) (
|
||||
bz_stream *strm
|
||||
);
|
||||
|
||||
|
||||
|
||||
/*-- High(er) level library functions --*/
|
||||
|
||||
#ifndef BZ_NO_STDIO
|
||||
#define BZ_MAX_UNUSED 5000
|
||||
|
||||
typedef void BZFILE;
|
||||
|
||||
BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) (
|
||||
int* bzerror,
|
||||
FILE* f,
|
||||
int verbosity,
|
||||
int small,
|
||||
void* unused,
|
||||
int nUnused
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzReadClose) (
|
||||
int* bzerror,
|
||||
BZFILE* b
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) (
|
||||
int* bzerror,
|
||||
BZFILE* b,
|
||||
void** unused,
|
||||
int* nUnused
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzRead) (
|
||||
int* bzerror,
|
||||
BZFILE* b,
|
||||
void* buf,
|
||||
int len
|
||||
);
|
||||
|
||||
BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) (
|
||||
int* bzerror,
|
||||
FILE* f,
|
||||
int blockSize100k,
|
||||
int verbosity,
|
||||
int workFactor
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzWrite) (
|
||||
int* bzerror,
|
||||
BZFILE* b,
|
||||
void* buf,
|
||||
int len
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzWriteClose) (
|
||||
int* bzerror,
|
||||
BZFILE* b,
|
||||
int abandon,
|
||||
unsigned int* nbytes_in,
|
||||
unsigned int* nbytes_out
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) (
|
||||
int* bzerror,
|
||||
BZFILE* b,
|
||||
int abandon,
|
||||
unsigned int* nbytes_in_lo32,
|
||||
unsigned int* nbytes_in_hi32,
|
||||
unsigned int* nbytes_out_lo32,
|
||||
unsigned int* nbytes_out_hi32
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/*-- Utility functions --*/
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) (
|
||||
char* dest,
|
||||
unsigned int* destLen,
|
||||
char* source,
|
||||
unsigned int sourceLen,
|
||||
int blockSize100k,
|
||||
int verbosity,
|
||||
int workFactor
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) (
|
||||
char* dest,
|
||||
unsigned int* destLen,
|
||||
char* source,
|
||||
unsigned int sourceLen,
|
||||
int small,
|
||||
int verbosity
|
||||
);
|
||||
|
||||
|
||||
/*--
|
||||
Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
|
||||
to support better zlib compatibility.
|
||||
This code is not _officially_ part of libbzip2 (yet);
|
||||
I haven't tested it, documented it, or considered the
|
||||
threading-safeness of it.
|
||||
If this code breaks, please contact both Yoshioka and me.
|
||||
--*/
|
||||
|
||||
BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) (
|
||||
void
|
||||
);
|
||||
|
||||
#ifndef BZ_NO_STDIO
|
||||
BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) (
|
||||
const char *path,
|
||||
const char *mode
|
||||
);
|
||||
|
||||
BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) (
|
||||
int fd,
|
||||
const char *mode
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzread) (
|
||||
BZFILE* b,
|
||||
void* buf,
|
||||
int len
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzwrite) (
|
||||
BZFILE* b,
|
||||
void* buf,
|
||||
int len
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzflush) (
|
||||
BZFILE* b
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzclose) (
|
||||
BZFILE* b
|
||||
);
|
||||
|
||||
BZ_EXTERN const char * BZ_API(BZ2_bzerror) (
|
||||
BZFILE *b,
|
||||
int *errnum
|
||||
);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end bzlib.h ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
512
utils/bzip2/bzlib_private.h
Normal file
512
utils/bzip2/bzlib_private.h
Normal file
|
|
@ -0,0 +1,512 @@
|
|||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Private header file for the library. ---*/
|
||||
/*--- bzlib_private.h ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#ifndef _BZLIB_PRIVATE_H
|
||||
#define _BZLIB_PRIVATE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef BZ_NO_STDIO
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "bzlib.h"
|
||||
|
||||
|
||||
|
||||
/*-- General stuff. --*/
|
||||
|
||||
#define BZ_VERSION "1.0.6, 6-Sept-2010"
|
||||
|
||||
typedef char Char;
|
||||
typedef unsigned char Bool;
|
||||
typedef unsigned char UChar;
|
||||
typedef int Int32;
|
||||
typedef unsigned int UInt32;
|
||||
typedef short Int16;
|
||||
typedef unsigned short UInt16;
|
||||
|
||||
#define True ((Bool)1)
|
||||
#define False ((Bool)0)
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define __inline__ /* */
|
||||
#endif
|
||||
|
||||
#ifndef BZ_NO_STDIO
|
||||
|
||||
extern void BZ2_bz__AssertH__fail ( int errcode );
|
||||
#define AssertH(cond,errcode) \
|
||||
{ if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); }
|
||||
|
||||
#if BZ_DEBUG
|
||||
#define AssertD(cond,msg) \
|
||||
{ if (!(cond)) { \
|
||||
fprintf ( stderr, \
|
||||
"\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\
|
||||
exit(1); \
|
||||
}}
|
||||
#else
|
||||
#define AssertD(cond,msg) /* */
|
||||
#endif
|
||||
|
||||
#define VPrintf0(zf) \
|
||||
fprintf(stderr,zf)
|
||||
#define VPrintf1(zf,za1) \
|
||||
fprintf(stderr,zf,za1)
|
||||
#define VPrintf2(zf,za1,za2) \
|
||||
fprintf(stderr,zf,za1,za2)
|
||||
#define VPrintf3(zf,za1,za2,za3) \
|
||||
fprintf(stderr,zf,za1,za2,za3)
|
||||
#define VPrintf4(zf,za1,za2,za3,za4) \
|
||||
fprintf(stderr,zf,za1,za2,za3,za4)
|
||||
#define VPrintf5(zf,za1,za2,za3,za4,za5) \
|
||||
fprintf(stderr,zf,za1,za2,za3,za4,za5)
|
||||
|
||||
#else
|
||||
|
||||
extern void bz_internal_error ( int errcode );
|
||||
#define AssertH(cond,errcode) \
|
||||
{ if (!(cond)) bz_internal_error ( errcode ); }
|
||||
#define AssertD(cond,msg) do { } while (0)
|
||||
#define VPrintf0(zf) do { } while (0)
|
||||
#define VPrintf1(zf,za1) do { } while (0)
|
||||
#define VPrintf2(zf,za1,za2) do { } while (0)
|
||||
#define VPrintf3(zf,za1,za2,za3) do { } while (0)
|
||||
#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0)
|
||||
#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1)
|
||||
#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp))
|
||||
|
||||
|
||||
/*-- Header bytes. --*/
|
||||
|
||||
#define BZ_HDR_B 0x42 /* 'B' */
|
||||
#define BZ_HDR_Z 0x5a /* 'Z' */
|
||||
#define BZ_HDR_h 0x68 /* 'h' */
|
||||
#define BZ_HDR_0 0x30 /* '0' */
|
||||
|
||||
/*-- Constants for the back end. --*/
|
||||
|
||||
#define BZ_MAX_ALPHA_SIZE 258
|
||||
#define BZ_MAX_CODE_LEN 23
|
||||
|
||||
#define BZ_RUNA 0
|
||||
#define BZ_RUNB 1
|
||||
|
||||
#define BZ_N_GROUPS 6
|
||||
#define BZ_G_SIZE 50
|
||||
#define BZ_N_ITERS 4
|
||||
|
||||
#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE))
|
||||
|
||||
|
||||
|
||||
/*-- Stuff for randomising repetitive blocks. --*/
|
||||
|
||||
extern Int32 BZ2_rNums[512];
|
||||
|
||||
#define BZ_RAND_DECLS \
|
||||
Int32 rNToGo; \
|
||||
Int32 rTPos \
|
||||
|
||||
#define BZ_RAND_INIT_MASK \
|
||||
s->rNToGo = 0; \
|
||||
s->rTPos = 0 \
|
||||
|
||||
#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0)
|
||||
|
||||
#define BZ_RAND_UPD_MASK \
|
||||
if (s->rNToGo == 0) { \
|
||||
s->rNToGo = BZ2_rNums[s->rTPos]; \
|
||||
s->rTPos++; \
|
||||
if (s->rTPos == 512) s->rTPos = 0; \
|
||||
} \
|
||||
s->rNToGo--;
|
||||
|
||||
|
||||
|
||||
/*-- Stuff for doing CRCs. --*/
|
||||
|
||||
extern UInt32 BZ2_crc32Table[256];
|
||||
|
||||
#define BZ_INITIALISE_CRC(crcVar) \
|
||||
{ \
|
||||
crcVar = 0xffffffffL; \
|
||||
}
|
||||
|
||||
#define BZ_FINALISE_CRC(crcVar) \
|
||||
{ \
|
||||
crcVar = ~(crcVar); \
|
||||
}
|
||||
|
||||
#define BZ_UPDATE_CRC(crcVar,cha) \
|
||||
{ \
|
||||
crcVar = (crcVar << 8) ^ \
|
||||
BZ2_crc32Table[(crcVar >> 24) ^ \
|
||||
((UChar)cha)]; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-- States and modes for compression. --*/
|
||||
|
||||
#define BZ_M_IDLE 1
|
||||
#define BZ_M_RUNNING 2
|
||||
#define BZ_M_FLUSHING 3
|
||||
#define BZ_M_FINISHING 4
|
||||
|
||||
#define BZ_S_OUTPUT 1
|
||||
#define BZ_S_INPUT 2
|
||||
|
||||
#define BZ_N_RADIX 2
|
||||
#define BZ_N_QSORT 12
|
||||
#define BZ_N_SHELL 18
|
||||
#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2)
|
||||
|
||||
|
||||
|
||||
|
||||
/*-- Structure holding all the compression-side stuff. --*/
|
||||
|
||||
typedef
|
||||
struct {
|
||||
/* pointer back to the struct bz_stream */
|
||||
bz_stream* strm;
|
||||
|
||||
/* mode this stream is in, and whether inputting */
|
||||
/* or outputting data */
|
||||
Int32 mode;
|
||||
Int32 state;
|
||||
|
||||
/* remembers avail_in when flush/finish requested */
|
||||
UInt32 avail_in_expect;
|
||||
|
||||
/* for doing the block sorting */
|
||||
UInt32* arr1;
|
||||
UInt32* arr2;
|
||||
UInt32* ftab;
|
||||
Int32 origPtr;
|
||||
|
||||
/* aliases for arr1 and arr2 */
|
||||
UInt32* ptr;
|
||||
UChar* block;
|
||||
UInt16* mtfv;
|
||||
UChar* zbits;
|
||||
|
||||
/* for deciding when to use the fallback sorting algorithm */
|
||||
Int32 workFactor;
|
||||
|
||||
/* run-length-encoding of the input */
|
||||
UInt32 state_in_ch;
|
||||
Int32 state_in_len;
|
||||
BZ_RAND_DECLS;
|
||||
|
||||
/* input and output limits and current posns */
|
||||
Int32 nblock;
|
||||
Int32 nblockMAX;
|
||||
Int32 numZ;
|
||||
Int32 state_out_pos;
|
||||
|
||||
/* map of bytes used in block */
|
||||
Int32 nInUse;
|
||||
Bool inUse[256];
|
||||
UChar unseqToSeq[256];
|
||||
|
||||
/* the buffer for bit stream creation */
|
||||
UInt32 bsBuff;
|
||||
Int32 bsLive;
|
||||
|
||||
/* block and combined CRCs */
|
||||
UInt32 blockCRC;
|
||||
UInt32 combinedCRC;
|
||||
|
||||
/* misc administratium */
|
||||
Int32 verbosity;
|
||||
Int32 blockNo;
|
||||
Int32 blockSize100k;
|
||||
|
||||
/* stuff for coding the MTF values */
|
||||
Int32 nMTF;
|
||||
Int32 mtfFreq [BZ_MAX_ALPHA_SIZE];
|
||||
UChar selector [BZ_MAX_SELECTORS];
|
||||
UChar selectorMtf[BZ_MAX_SELECTORS];
|
||||
|
||||
UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
/* second dimension: only 3 needed; 4 makes index calculations faster */
|
||||
UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4];
|
||||
|
||||
}
|
||||
EState;
|
||||
|
||||
|
||||
|
||||
/*-- externs for compression. --*/
|
||||
|
||||
extern void
|
||||
BZ2_blockSort ( EState* );
|
||||
|
||||
extern void
|
||||
BZ2_compressBlock ( EState*, Bool );
|
||||
|
||||
extern void
|
||||
BZ2_bsInitWrite ( EState* );
|
||||
|
||||
extern void
|
||||
BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 );
|
||||
|
||||
extern void
|
||||
BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 );
|
||||
|
||||
|
||||
|
||||
/*-- states for decompression. --*/
|
||||
|
||||
#define BZ_X_IDLE 1
|
||||
#define BZ_X_OUTPUT 2
|
||||
|
||||
#define BZ_X_MAGIC_1 10
|
||||
#define BZ_X_MAGIC_2 11
|
||||
#define BZ_X_MAGIC_3 12
|
||||
#define BZ_X_MAGIC_4 13
|
||||
#define BZ_X_BLKHDR_1 14
|
||||
#define BZ_X_BLKHDR_2 15
|
||||
#define BZ_X_BLKHDR_3 16
|
||||
#define BZ_X_BLKHDR_4 17
|
||||
#define BZ_X_BLKHDR_5 18
|
||||
#define BZ_X_BLKHDR_6 19
|
||||
#define BZ_X_BCRC_1 20
|
||||
#define BZ_X_BCRC_2 21
|
||||
#define BZ_X_BCRC_3 22
|
||||
#define BZ_X_BCRC_4 23
|
||||
#define BZ_X_RANDBIT 24
|
||||
#define BZ_X_ORIGPTR_1 25
|
||||
#define BZ_X_ORIGPTR_2 26
|
||||
#define BZ_X_ORIGPTR_3 27
|
||||
#define BZ_X_MAPPING_1 28
|
||||
#define BZ_X_MAPPING_2 29
|
||||
#define BZ_X_SELECTOR_1 30
|
||||
#define BZ_X_SELECTOR_2 31
|
||||
#define BZ_X_SELECTOR_3 32
|
||||
#define BZ_X_CODING_1 33
|
||||
#define BZ_X_CODING_2 34
|
||||
#define BZ_X_CODING_3 35
|
||||
#define BZ_X_MTF_1 36
|
||||
#define BZ_X_MTF_2 37
|
||||
#define BZ_X_MTF_3 38
|
||||
#define BZ_X_MTF_4 39
|
||||
#define BZ_X_MTF_5 40
|
||||
#define BZ_X_MTF_6 41
|
||||
#define BZ_X_ENDHDR_2 42
|
||||
#define BZ_X_ENDHDR_3 43
|
||||
#define BZ_X_ENDHDR_4 44
|
||||
#define BZ_X_ENDHDR_5 45
|
||||
#define BZ_X_ENDHDR_6 46
|
||||
#define BZ_X_CCRC_1 47
|
||||
#define BZ_X_CCRC_2 48
|
||||
#define BZ_X_CCRC_3 49
|
||||
#define BZ_X_CCRC_4 50
|
||||
|
||||
|
||||
|
||||
/*-- Constants for the fast MTF decoder. --*/
|
||||
|
||||
#define MTFA_SIZE 4096
|
||||
#define MTFL_SIZE 16
|
||||
|
||||
|
||||
|
||||
/*-- Structure holding all the decompression-side stuff. --*/
|
||||
|
||||
typedef
|
||||
struct {
|
||||
/* pointer back to the struct bz_stream */
|
||||
bz_stream* strm;
|
||||
|
||||
/* state indicator for this stream */
|
||||
Int32 state;
|
||||
|
||||
/* for doing the final run-length decoding */
|
||||
UChar state_out_ch;
|
||||
Int32 state_out_len;
|
||||
Bool blockRandomised;
|
||||
BZ_RAND_DECLS;
|
||||
|
||||
/* the buffer for bit stream reading */
|
||||
UInt32 bsBuff;
|
||||
Int32 bsLive;
|
||||
|
||||
/* misc administratium */
|
||||
Int32 blockSize100k;
|
||||
Bool smallDecompress;
|
||||
Int32 currBlockNo;
|
||||
Int32 verbosity;
|
||||
|
||||
/* for undoing the Burrows-Wheeler transform */
|
||||
Int32 origPtr;
|
||||
UInt32 tPos;
|
||||
Int32 k0;
|
||||
Int32 unzftab[256];
|
||||
Int32 nblock_used;
|
||||
Int32 cftab[257];
|
||||
Int32 cftabCopy[257];
|
||||
|
||||
/* for undoing the Burrows-Wheeler transform (FAST) */
|
||||
UInt32 *tt;
|
||||
|
||||
/* for undoing the Burrows-Wheeler transform (SMALL) */
|
||||
UInt16 *ll16;
|
||||
UChar *ll4;
|
||||
|
||||
/* stored and calculated CRCs */
|
||||
UInt32 storedBlockCRC;
|
||||
UInt32 storedCombinedCRC;
|
||||
UInt32 calculatedBlockCRC;
|
||||
UInt32 calculatedCombinedCRC;
|
||||
|
||||
/* map of bytes used in block */
|
||||
Int32 nInUse;
|
||||
Bool inUse[256];
|
||||
Bool inUse16[16];
|
||||
UChar seqToUnseq[256];
|
||||
|
||||
/* for decoding the MTF values */
|
||||
UChar mtfa [MTFA_SIZE];
|
||||
Int32 mtfbase[256 / MTFL_SIZE];
|
||||
UChar selector [BZ_MAX_SELECTORS];
|
||||
UChar selectorMtf[BZ_MAX_SELECTORS];
|
||||
UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
|
||||
Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 minLens[BZ_N_GROUPS];
|
||||
|
||||
/* save area for scalars in the main decompress code */
|
||||
Int32 save_i;
|
||||
Int32 save_j;
|
||||
Int32 save_t;
|
||||
Int32 save_alphaSize;
|
||||
Int32 save_nGroups;
|
||||
Int32 save_nSelectors;
|
||||
Int32 save_EOB;
|
||||
Int32 save_groupNo;
|
||||
Int32 save_groupPos;
|
||||
Int32 save_nextSym;
|
||||
Int32 save_nblockMAX;
|
||||
Int32 save_nblock;
|
||||
Int32 save_es;
|
||||
Int32 save_N;
|
||||
Int32 save_curr;
|
||||
Int32 save_zt;
|
||||
Int32 save_zn;
|
||||
Int32 save_zvec;
|
||||
Int32 save_zj;
|
||||
Int32 save_gSel;
|
||||
Int32 save_gMinlen;
|
||||
Int32* save_gLimit;
|
||||
Int32* save_gBase;
|
||||
Int32* save_gPerm;
|
||||
|
||||
}
|
||||
DState;
|
||||
|
||||
|
||||
|
||||
/*-- Macros for decompression. --*/
|
||||
|
||||
#define BZ_GET_FAST(cccc) \
|
||||
/* c_tPos is unsigned, hence test < 0 is pointless. */ \
|
||||
if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
|
||||
s->tPos = s->tt[s->tPos]; \
|
||||
cccc = (UChar)(s->tPos & 0xff); \
|
||||
s->tPos >>= 8;
|
||||
|
||||
#define BZ_GET_FAST_C(cccc) \
|
||||
/* c_tPos is unsigned, hence test < 0 is pointless. */ \
|
||||
if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \
|
||||
c_tPos = c_tt[c_tPos]; \
|
||||
cccc = (UChar)(c_tPos & 0xff); \
|
||||
c_tPos >>= 8;
|
||||
|
||||
#define SET_LL4(i,n) \
|
||||
{ if (((i) & 0x1) == 0) \
|
||||
s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \
|
||||
s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \
|
||||
}
|
||||
|
||||
#define GET_LL4(i) \
|
||||
((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF)
|
||||
|
||||
#define SET_LL(i,n) \
|
||||
{ s->ll16[i] = (UInt16)(n & 0x0000ffff); \
|
||||
SET_LL4(i, n >> 16); \
|
||||
}
|
||||
|
||||
#define GET_LL(i) \
|
||||
(((UInt32)s->ll16[i]) | (GET_LL4(i) << 16))
|
||||
|
||||
#define BZ_GET_SMALL(cccc) \
|
||||
/* c_tPos is unsigned, hence test < 0 is pointless. */ \
|
||||
if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
|
||||
cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \
|
||||
s->tPos = GET_LL(s->tPos);
|
||||
|
||||
|
||||
/*-- externs for decompression. --*/
|
||||
|
||||
extern Int32
|
||||
BZ2_indexIntoF ( Int32, Int32* );
|
||||
|
||||
extern Int32
|
||||
BZ2_decompress ( DState* );
|
||||
|
||||
extern void
|
||||
BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*,
|
||||
Int32, Int32, Int32 );
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/
|
||||
|
||||
#ifdef BZ_NO_STDIO
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
#define _fdopen fdopen
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end bzlib_private.h ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
672
utils/bzip2/compress.c
Normal file
672
utils/bzip2/compress.c
Normal file
|
|
@ -0,0 +1,672 @@
|
|||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Compression machinery (not incl block sorting) ---*/
|
||||
/*--- compress.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
|
||||
/* CHANGES
|
||||
0.9.0 -- original version.
|
||||
0.9.0a/b -- no changes in this file.
|
||||
0.9.0c -- changed setting of nGroups in sendMTFValues()
|
||||
so as to do a bit better on small files
|
||||
*/
|
||||
|
||||
#include "bzlib_private.h"
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*--- Bit stream I/O ---*/
|
||||
/*---------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
void BZ2_bsInitWrite ( EState* s )
|
||||
{
|
||||
s->bsLive = 0;
|
||||
s->bsBuff = 0;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void bsFinishWrite ( EState* s )
|
||||
{
|
||||
while (s->bsLive > 0) {
|
||||
s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24);
|
||||
s->numZ++;
|
||||
s->bsBuff <<= 8;
|
||||
s->bsLive -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define bsNEEDW(nz) \
|
||||
{ \
|
||||
while (s->bsLive >= 8) { \
|
||||
s->zbits[s->numZ] \
|
||||
= (UChar)(s->bsBuff >> 24); \
|
||||
s->numZ++; \
|
||||
s->bsBuff <<= 8; \
|
||||
s->bsLive -= 8; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
__inline__
|
||||
void bsW ( EState* s, Int32 n, UInt32 v )
|
||||
{
|
||||
bsNEEDW ( n );
|
||||
s->bsBuff |= (v << (32 - s->bsLive - n));
|
||||
s->bsLive += n;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void bsPutUInt32 ( EState* s, UInt32 u )
|
||||
{
|
||||
bsW ( s, 8, (u >> 24) & 0xffL );
|
||||
bsW ( s, 8, (u >> 16) & 0xffL );
|
||||
bsW ( s, 8, (u >> 8) & 0xffL );
|
||||
bsW ( s, 8, u & 0xffL );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void bsPutUChar ( EState* s, UChar c )
|
||||
{
|
||||
bsW( s, 8, (UInt32)c );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*--- The back end proper ---*/
|
||||
/*---------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void makeMaps_e ( EState* s )
|
||||
{
|
||||
Int32 i;
|
||||
s->nInUse = 0;
|
||||
for (i = 0; i < 256; i++)
|
||||
if (s->inUse[i]) {
|
||||
s->unseqToSeq[i] = s->nInUse;
|
||||
s->nInUse++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void generateMTFValues ( EState* s )
|
||||
{
|
||||
UChar yy[256];
|
||||
Int32 i, j;
|
||||
Int32 zPend;
|
||||
Int32 wr;
|
||||
Int32 EOB;
|
||||
|
||||
/*
|
||||
After sorting (eg, here),
|
||||
s->arr1 [ 0 .. s->nblock-1 ] holds sorted order,
|
||||
and
|
||||
((UChar*)s->arr2) [ 0 .. s->nblock-1 ]
|
||||
holds the original block data.
|
||||
|
||||
The first thing to do is generate the MTF values,
|
||||
and put them in
|
||||
((UInt16*)s->arr1) [ 0 .. s->nblock-1 ].
|
||||
Because there are strictly fewer or equal MTF values
|
||||
than block values, ptr values in this area are overwritten
|
||||
with MTF values only when they are no longer needed.
|
||||
|
||||
The final compressed bitstream is generated into the
|
||||
area starting at
|
||||
(UChar*) (&((UChar*)s->arr2)[s->nblock])
|
||||
|
||||
These storage aliases are set up in bzCompressInit(),
|
||||
except for the last one, which is arranged in
|
||||
compressBlock().
|
||||
*/
|
||||
UInt32* ptr = s->ptr;
|
||||
UChar* block = s->block;
|
||||
UInt16* mtfv = s->mtfv;
|
||||
|
||||
makeMaps_e ( s );
|
||||
EOB = s->nInUse+1;
|
||||
|
||||
for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0;
|
||||
|
||||
wr = 0;
|
||||
zPend = 0;
|
||||
for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i;
|
||||
|
||||
for (i = 0; i < s->nblock; i++) {
|
||||
UChar ll_i;
|
||||
AssertD ( wr <= i, "generateMTFValues(1)" );
|
||||
j = ptr[i]-1; if (j < 0) j += s->nblock;
|
||||
ll_i = s->unseqToSeq[block[j]];
|
||||
AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" );
|
||||
|
||||
if (yy[0] == ll_i) {
|
||||
zPend++;
|
||||
} else {
|
||||
|
||||
if (zPend > 0) {
|
||||
zPend--;
|
||||
while (True) {
|
||||
if (zPend & 1) {
|
||||
mtfv[wr] = BZ_RUNB; wr++;
|
||||
s->mtfFreq[BZ_RUNB]++;
|
||||
} else {
|
||||
mtfv[wr] = BZ_RUNA; wr++;
|
||||
s->mtfFreq[BZ_RUNA]++;
|
||||
}
|
||||
if (zPend < 2) break;
|
||||
zPend = (zPend - 2) / 2;
|
||||
};
|
||||
zPend = 0;
|
||||
}
|
||||
{
|
||||
register UChar rtmp;
|
||||
register UChar* ryy_j;
|
||||
register UChar rll_i;
|
||||
rtmp = yy[1];
|
||||
yy[1] = yy[0];
|
||||
ryy_j = &(yy[1]);
|
||||
rll_i = ll_i;
|
||||
while ( rll_i != rtmp ) {
|
||||
register UChar rtmp2;
|
||||
ryy_j++;
|
||||
rtmp2 = rtmp;
|
||||
rtmp = *ryy_j;
|
||||
*ryy_j = rtmp2;
|
||||
};
|
||||
yy[0] = rtmp;
|
||||
j = ryy_j - &(yy[0]);
|
||||
mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (zPend > 0) {
|
||||
zPend--;
|
||||
while (True) {
|
||||
if (zPend & 1) {
|
||||
mtfv[wr] = BZ_RUNB; wr++;
|
||||
s->mtfFreq[BZ_RUNB]++;
|
||||
} else {
|
||||
mtfv[wr] = BZ_RUNA; wr++;
|
||||
s->mtfFreq[BZ_RUNA]++;
|
||||
}
|
||||
if (zPend < 2) break;
|
||||
zPend = (zPend - 2) / 2;
|
||||
};
|
||||
zPend = 0;
|
||||
}
|
||||
|
||||
mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++;
|
||||
|
||||
s->nMTF = wr;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define BZ_LESSER_ICOST 0
|
||||
#define BZ_GREATER_ICOST 15
|
||||
|
||||
static
|
||||
void sendMTFValues ( EState* s )
|
||||
{
|
||||
Int32 v, t, i, j, gs, ge, totc, bt, bc, iter;
|
||||
Int32 nSelectors, alphaSize, minLen, maxLen, selCtr;
|
||||
Int32 nGroups, nBytes;
|
||||
|
||||
/*--
|
||||
UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
is a global since the decoder also needs it.
|
||||
|
||||
Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
are also globals only used in this proc.
|
||||
Made global to keep stack frame size small.
|
||||
--*/
|
||||
|
||||
|
||||
UInt16 cost[BZ_N_GROUPS];
|
||||
Int32 fave[BZ_N_GROUPS];
|
||||
|
||||
UInt16* mtfv = s->mtfv;
|
||||
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf3( " %d in block, %d after MTF & 1-2 coding, "
|
||||
"%d+2 syms in use\n",
|
||||
s->nblock, s->nMTF, s->nInUse );
|
||||
|
||||
alphaSize = s->nInUse+2;
|
||||
for (t = 0; t < BZ_N_GROUPS; t++)
|
||||
for (v = 0; v < alphaSize; v++)
|
||||
s->len[t][v] = BZ_GREATER_ICOST;
|
||||
|
||||
/*--- Decide how many coding tables to use ---*/
|
||||
AssertH ( s->nMTF > 0, 3001 );
|
||||
if (s->nMTF < 200) nGroups = 2; else
|
||||
if (s->nMTF < 600) nGroups = 3; else
|
||||
if (s->nMTF < 1200) nGroups = 4; else
|
||||
if (s->nMTF < 2400) nGroups = 5; else
|
||||
nGroups = 6;
|
||||
|
||||
/*--- Generate an initial set of coding tables ---*/
|
||||
{
|
||||
Int32 nPart, remF, tFreq, aFreq;
|
||||
|
||||
nPart = nGroups;
|
||||
remF = s->nMTF;
|
||||
gs = 0;
|
||||
while (nPart > 0) {
|
||||
tFreq = remF / nPart;
|
||||
ge = gs-1;
|
||||
aFreq = 0;
|
||||
while (aFreq < tFreq && ge < alphaSize-1) {
|
||||
ge++;
|
||||
aFreq += s->mtfFreq[ge];
|
||||
}
|
||||
|
||||
if (ge > gs
|
||||
&& nPart != nGroups && nPart != 1
|
||||
&& ((nGroups-nPart) % 2 == 1)) {
|
||||
aFreq -= s->mtfFreq[ge];
|
||||
ge--;
|
||||
}
|
||||
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf5( " initial group %d, [%d .. %d], "
|
||||
"has %d syms (%4.1f%%)\n",
|
||||
nPart, gs, ge, aFreq,
|
||||
(100.0 * (float)aFreq) / (float)(s->nMTF) );
|
||||
|
||||
for (v = 0; v < alphaSize; v++)
|
||||
if (v >= gs && v <= ge)
|
||||
s->len[nPart-1][v] = BZ_LESSER_ICOST; else
|
||||
s->len[nPart-1][v] = BZ_GREATER_ICOST;
|
||||
|
||||
nPart--;
|
||||
gs = ge+1;
|
||||
remF -= aFreq;
|
||||
}
|
||||
}
|
||||
|
||||
/*---
|
||||
Iterate up to BZ_N_ITERS times to improve the tables.
|
||||
---*/
|
||||
for (iter = 0; iter < BZ_N_ITERS; iter++) {
|
||||
|
||||
for (t = 0; t < nGroups; t++) fave[t] = 0;
|
||||
|
||||
for (t = 0; t < nGroups; t++)
|
||||
for (v = 0; v < alphaSize; v++)
|
||||
s->rfreq[t][v] = 0;
|
||||
|
||||
/*---
|
||||
Set up an auxiliary length table which is used to fast-track
|
||||
the common case (nGroups == 6).
|
||||
---*/
|
||||
if (nGroups == 6) {
|
||||
for (v = 0; v < alphaSize; v++) {
|
||||
s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
|
||||
s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
|
||||
s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v];
|
||||
}
|
||||
}
|
||||
|
||||
nSelectors = 0;
|
||||
totc = 0;
|
||||
gs = 0;
|
||||
while (True) {
|
||||
|
||||
/*--- Set group start & end marks. --*/
|
||||
if (gs >= s->nMTF) break;
|
||||
ge = gs + BZ_G_SIZE - 1;
|
||||
if (ge >= s->nMTF) ge = s->nMTF-1;
|
||||
|
||||
/*--
|
||||
Calculate the cost of this group as coded
|
||||
by each of the coding tables.
|
||||
--*/
|
||||
for (t = 0; t < nGroups; t++) cost[t] = 0;
|
||||
|
||||
if (nGroups == 6 && 50 == ge-gs+1) {
|
||||
/*--- fast track the common case ---*/
|
||||
register UInt32 cost01, cost23, cost45;
|
||||
register UInt16 icv;
|
||||
cost01 = cost23 = cost45 = 0;
|
||||
|
||||
# define BZ_ITER(nn) \
|
||||
icv = mtfv[gs+(nn)]; \
|
||||
cost01 += s->len_pack[icv][0]; \
|
||||
cost23 += s->len_pack[icv][1]; \
|
||||
cost45 += s->len_pack[icv][2]; \
|
||||
|
||||
BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4);
|
||||
BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9);
|
||||
BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
|
||||
BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
|
||||
BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
|
||||
BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
|
||||
BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
|
||||
BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
|
||||
BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
|
||||
BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
|
||||
|
||||
# undef BZ_ITER
|
||||
|
||||
cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16;
|
||||
cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16;
|
||||
cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16;
|
||||
|
||||
} else {
|
||||
/*--- slow version which correctly handles all situations ---*/
|
||||
for (i = gs; i <= ge; i++) {
|
||||
UInt16 icv = mtfv[i];
|
||||
for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv];
|
||||
}
|
||||
}
|
||||
|
||||
/*--
|
||||
Find the coding table which is best for this group,
|
||||
and record its identity in the selector table.
|
||||
--*/
|
||||
bc = 999999999; bt = -1;
|
||||
for (t = 0; t < nGroups; t++)
|
||||
if (cost[t] < bc) { bc = cost[t]; bt = t; };
|
||||
totc += bc;
|
||||
fave[bt]++;
|
||||
s->selector[nSelectors] = bt;
|
||||
nSelectors++;
|
||||
|
||||
/*--
|
||||
Increment the symbol frequencies for the selected table.
|
||||
--*/
|
||||
if (nGroups == 6 && 50 == ge-gs+1) {
|
||||
/*--- fast track the common case ---*/
|
||||
|
||||
# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++
|
||||
|
||||
BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4);
|
||||
BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9);
|
||||
BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
|
||||
BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
|
||||
BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
|
||||
BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
|
||||
BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
|
||||
BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
|
||||
BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
|
||||
BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
|
||||
|
||||
# undef BZ_ITUR
|
||||
|
||||
} else {
|
||||
/*--- slow version which correctly handles all situations ---*/
|
||||
for (i = gs; i <= ge; i++)
|
||||
s->rfreq[bt][ mtfv[i] ]++;
|
||||
}
|
||||
|
||||
gs = ge+1;
|
||||
}
|
||||
if (s->verbosity >= 3) {
|
||||
VPrintf2 ( " pass %d: size is %d, grp uses are ",
|
||||
iter+1, totc/8 );
|
||||
for (t = 0; t < nGroups; t++)
|
||||
VPrintf1 ( "%d ", fave[t] );
|
||||
VPrintf0 ( "\n" );
|
||||
}
|
||||
|
||||
/*--
|
||||
Recompute the tables based on the accumulated frequencies.
|
||||
--*/
|
||||
/* maxLen was changed from 20 to 17 in bzip2-1.0.3. See
|
||||
comment in huffman.c for details. */
|
||||
for (t = 0; t < nGroups; t++)
|
||||
BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]),
|
||||
alphaSize, 17 /*20*/ );
|
||||
}
|
||||
|
||||
|
||||
AssertH( nGroups < 8, 3002 );
|
||||
AssertH( nSelectors < 32768 &&
|
||||
nSelectors <= (2 + (900000 / BZ_G_SIZE)),
|
||||
3003 );
|
||||
|
||||
|
||||
/*--- Compute MTF values for the selectors. ---*/
|
||||
{
|
||||
UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp;
|
||||
for (i = 0; i < nGroups; i++) pos[i] = i;
|
||||
for (i = 0; i < nSelectors; i++) {
|
||||
ll_i = s->selector[i];
|
||||
j = 0;
|
||||
tmp = pos[j];
|
||||
while ( ll_i != tmp ) {
|
||||
j++;
|
||||
tmp2 = tmp;
|
||||
tmp = pos[j];
|
||||
pos[j] = tmp2;
|
||||
};
|
||||
pos[0] = tmp;
|
||||
s->selectorMtf[i] = j;
|
||||
}
|
||||
};
|
||||
|
||||
/*--- Assign actual codes for the tables. --*/
|
||||
for (t = 0; t < nGroups; t++) {
|
||||
minLen = 32;
|
||||
maxLen = 0;
|
||||
for (i = 0; i < alphaSize; i++) {
|
||||
if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
|
||||
if (s->len[t][i] < minLen) minLen = s->len[t][i];
|
||||
}
|
||||
AssertH ( !(maxLen > 17 /*20*/ ), 3004 );
|
||||
AssertH ( !(minLen < 1), 3005 );
|
||||
BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]),
|
||||
minLen, maxLen, alphaSize );
|
||||
}
|
||||
|
||||
/*--- Transmit the mapping table. ---*/
|
||||
{
|
||||
Bool inUse16[16];
|
||||
for (i = 0; i < 16; i++) {
|
||||
inUse16[i] = False;
|
||||
for (j = 0; j < 16; j++)
|
||||
if (s->inUse[i * 16 + j]) inUse16[i] = True;
|
||||
}
|
||||
|
||||
nBytes = s->numZ;
|
||||
for (i = 0; i < 16; i++)
|
||||
if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0);
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
if (inUse16[i])
|
||||
for (j = 0; j < 16; j++) {
|
||||
if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0);
|
||||
}
|
||||
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes );
|
||||
}
|
||||
|
||||
/*--- Now the selectors. ---*/
|
||||
nBytes = s->numZ;
|
||||
bsW ( s, 3, nGroups );
|
||||
bsW ( s, 15, nSelectors );
|
||||
for (i = 0; i < nSelectors; i++) {
|
||||
for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1);
|
||||
bsW(s,1,0);
|
||||
}
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf1( "selectors %d, ", s->numZ-nBytes );
|
||||
|
||||
/*--- Now the coding tables. ---*/
|
||||
nBytes = s->numZ;
|
||||
|
||||
for (t = 0; t < nGroups; t++) {
|
||||
Int32 curr = s->len[t][0];
|
||||
bsW ( s, 5, curr );
|
||||
for (i = 0; i < alphaSize; i++) {
|
||||
while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ };
|
||||
while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ };
|
||||
bsW ( s, 1, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf1 ( "code lengths %d, ", s->numZ-nBytes );
|
||||
|
||||
/*--- And finally, the block data proper ---*/
|
||||
nBytes = s->numZ;
|
||||
selCtr = 0;
|
||||
gs = 0;
|
||||
while (True) {
|
||||
if (gs >= s->nMTF) break;
|
||||
ge = gs + BZ_G_SIZE - 1;
|
||||
if (ge >= s->nMTF) ge = s->nMTF-1;
|
||||
AssertH ( s->selector[selCtr] < nGroups, 3006 );
|
||||
|
||||
if (nGroups == 6 && 50 == ge-gs+1) {
|
||||
/*--- fast track the common case ---*/
|
||||
UInt16 mtfv_i;
|
||||
UChar* s_len_sel_selCtr
|
||||
= &(s->len[s->selector[selCtr]][0]);
|
||||
Int32* s_code_sel_selCtr
|
||||
= &(s->code[s->selector[selCtr]][0]);
|
||||
|
||||
# define BZ_ITAH(nn) \
|
||||
mtfv_i = mtfv[gs+(nn)]; \
|
||||
bsW ( s, \
|
||||
s_len_sel_selCtr[mtfv_i], \
|
||||
s_code_sel_selCtr[mtfv_i] )
|
||||
|
||||
BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4);
|
||||
BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9);
|
||||
BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
|
||||
BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
|
||||
BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
|
||||
BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
|
||||
BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
|
||||
BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
|
||||
BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
|
||||
BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
|
||||
|
||||
# undef BZ_ITAH
|
||||
|
||||
} else {
|
||||
/*--- slow version which correctly handles all situations ---*/
|
||||
for (i = gs; i <= ge; i++) {
|
||||
bsW ( s,
|
||||
s->len [s->selector[selCtr]] [mtfv[i]],
|
||||
s->code [s->selector[selCtr]] [mtfv[i]] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gs = ge+1;
|
||||
selCtr++;
|
||||
}
|
||||
AssertH( selCtr == nSelectors, 3007 );
|
||||
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf1( "codes %d\n", s->numZ-nBytes );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
void BZ2_compressBlock ( EState* s, Bool is_last_block )
|
||||
{
|
||||
if (s->nblock > 0) {
|
||||
|
||||
BZ_FINALISE_CRC ( s->blockCRC );
|
||||
s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
|
||||
s->combinedCRC ^= s->blockCRC;
|
||||
if (s->blockNo > 1) s->numZ = 0;
|
||||
|
||||
if (s->verbosity >= 2)
|
||||
VPrintf4( " block %d: crc = 0x%08x, "
|
||||
"combined CRC = 0x%08x, size = %d\n",
|
||||
s->blockNo, s->blockCRC, s->combinedCRC, s->nblock );
|
||||
|
||||
BZ2_blockSort ( s );
|
||||
}
|
||||
|
||||
s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]);
|
||||
|
||||
/*-- If this is the first block, create the stream header. --*/
|
||||
if (s->blockNo == 1) {
|
||||
BZ2_bsInitWrite ( s );
|
||||
bsPutUChar ( s, BZ_HDR_B );
|
||||
bsPutUChar ( s, BZ_HDR_Z );
|
||||
bsPutUChar ( s, BZ_HDR_h );
|
||||
bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) );
|
||||
}
|
||||
|
||||
if (s->nblock > 0) {
|
||||
|
||||
bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 );
|
||||
bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 );
|
||||
bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 );
|
||||
|
||||
/*-- Now the block's CRC, so it is in a known place. --*/
|
||||
bsPutUInt32 ( s, s->blockCRC );
|
||||
|
||||
/*--
|
||||
Now a single bit indicating (non-)randomisation.
|
||||
As of version 0.9.5, we use a better sorting algorithm
|
||||
which makes randomisation unnecessary. So always set
|
||||
the randomised bit to 'no'. Of course, the decoder
|
||||
still needs to be able to handle randomised blocks
|
||||
so as to maintain backwards compatibility with
|
||||
older versions of bzip2.
|
||||
--*/
|
||||
bsW(s,1,0);
|
||||
|
||||
bsW ( s, 24, s->origPtr );
|
||||
generateMTFValues ( s );
|
||||
sendMTFValues ( s );
|
||||
}
|
||||
|
||||
|
||||
/*-- If this is the last block, add the stream trailer. --*/
|
||||
if (is_last_block) {
|
||||
|
||||
bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 );
|
||||
bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 );
|
||||
bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 );
|
||||
bsPutUInt32 ( s, s->combinedCRC );
|
||||
if (s->verbosity >= 2)
|
||||
VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC );
|
||||
bsFinishWrite ( s );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end compress.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
104
utils/bzip2/crctable.c
Normal file
104
utils/bzip2/crctable.c
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Table for doing CRCs ---*/
|
||||
/*--- crctable.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#include "bzlib_private.h"
|
||||
|
||||
/*--
|
||||
I think this is an implementation of the AUTODIN-II,
|
||||
Ethernet & FDDI 32-bit CRC standard. Vaguely derived
|
||||
from code by Rob Warnock, in Section 51 of the
|
||||
comp.compression FAQ.
|
||||
--*/
|
||||
|
||||
UInt32 BZ2_crc32Table[256] = {
|
||||
|
||||
/*-- Ugly, innit? --*/
|
||||
|
||||
0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L,
|
||||
0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L,
|
||||
0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L,
|
||||
0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL,
|
||||
0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L,
|
||||
0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L,
|
||||
0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L,
|
||||
0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL,
|
||||
0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L,
|
||||
0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L,
|
||||
0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L,
|
||||
0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL,
|
||||
0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L,
|
||||
0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L,
|
||||
0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L,
|
||||
0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL,
|
||||
0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL,
|
||||
0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L,
|
||||
0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L,
|
||||
0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL,
|
||||
0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL,
|
||||
0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L,
|
||||
0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L,
|
||||
0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL,
|
||||
0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL,
|
||||
0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L,
|
||||
0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L,
|
||||
0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL,
|
||||
0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL,
|
||||
0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L,
|
||||
0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L,
|
||||
0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL,
|
||||
0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L,
|
||||
0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL,
|
||||
0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL,
|
||||
0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L,
|
||||
0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L,
|
||||
0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL,
|
||||
0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL,
|
||||
0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L,
|
||||
0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L,
|
||||
0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL,
|
||||
0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL,
|
||||
0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L,
|
||||
0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L,
|
||||
0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL,
|
||||
0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL,
|
||||
0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L,
|
||||
0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L,
|
||||
0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL,
|
||||
0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L,
|
||||
0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L,
|
||||
0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L,
|
||||
0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL,
|
||||
0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L,
|
||||
0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L,
|
||||
0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L,
|
||||
0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL,
|
||||
0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L,
|
||||
0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L,
|
||||
0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L,
|
||||
0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL,
|
||||
0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L,
|
||||
0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end crctable.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
646
utils/bzip2/decompress.c
Normal file
646
utils/bzip2/decompress.c
Normal file
|
|
@ -0,0 +1,646 @@
|
|||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Decompression machinery ---*/
|
||||
/*--- decompress.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#include "bzlib_private.h"
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void makeMaps_d ( DState* s )
|
||||
{
|
||||
Int32 i;
|
||||
s->nInUse = 0;
|
||||
for (i = 0; i < 256; i++)
|
||||
if (s->inUse[i]) {
|
||||
s->seqToUnseq[s->nInUse] = i;
|
||||
s->nInUse++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define RETURN(rrr) \
|
||||
{ retVal = rrr; goto save_state_and_return; };
|
||||
|
||||
#define GET_BITS(lll,vvv,nnn) \
|
||||
case lll: s->state = lll; \
|
||||
while (True) { \
|
||||
if (s->bsLive >= nnn) { \
|
||||
UInt32 v; \
|
||||
v = (s->bsBuff >> \
|
||||
(s->bsLive-nnn)) & ((1 << nnn)-1); \
|
||||
s->bsLive -= nnn; \
|
||||
vvv = v; \
|
||||
break; \
|
||||
} \
|
||||
if (s->strm->avail_in == 0) RETURN(BZ_OK); \
|
||||
s->bsBuff \
|
||||
= (s->bsBuff << 8) | \
|
||||
((UInt32) \
|
||||
(*((UChar*)(s->strm->next_in)))); \
|
||||
s->bsLive += 8; \
|
||||
s->strm->next_in++; \
|
||||
s->strm->avail_in--; \
|
||||
s->strm->total_in_lo32++; \
|
||||
if (s->strm->total_in_lo32 == 0) \
|
||||
s->strm->total_in_hi32++; \
|
||||
}
|
||||
|
||||
#define GET_UCHAR(lll,uuu) \
|
||||
GET_BITS(lll,uuu,8)
|
||||
|
||||
#define GET_BIT(lll,uuu) \
|
||||
GET_BITS(lll,uuu,1)
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define GET_MTF_VAL(label1,label2,lval) \
|
||||
{ \
|
||||
if (groupPos == 0) { \
|
||||
groupNo++; \
|
||||
if (groupNo >= nSelectors) \
|
||||
RETURN(BZ_DATA_ERROR); \
|
||||
groupPos = BZ_G_SIZE; \
|
||||
gSel = s->selector[groupNo]; \
|
||||
gMinlen = s->minLens[gSel]; \
|
||||
gLimit = &(s->limit[gSel][0]); \
|
||||
gPerm = &(s->perm[gSel][0]); \
|
||||
gBase = &(s->base[gSel][0]); \
|
||||
} \
|
||||
groupPos--; \
|
||||
zn = gMinlen; \
|
||||
GET_BITS(label1, zvec, zn); \
|
||||
while (1) { \
|
||||
if (zn > 20 /* the longest code */) \
|
||||
RETURN(BZ_DATA_ERROR); \
|
||||
if (zvec <= gLimit[zn]) break; \
|
||||
zn++; \
|
||||
GET_BIT(label2, zj); \
|
||||
zvec = (zvec << 1) | zj; \
|
||||
}; \
|
||||
if (zvec - gBase[zn] < 0 \
|
||||
|| zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \
|
||||
RETURN(BZ_DATA_ERROR); \
|
||||
lval = gPerm[zvec - gBase[zn]]; \
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
Int32 BZ2_decompress ( DState* s )
|
||||
{
|
||||
UChar uc;
|
||||
Int32 retVal;
|
||||
Int32 minLen, maxLen;
|
||||
bz_stream* strm = s->strm;
|
||||
|
||||
/* stuff that needs to be saved/restored */
|
||||
Int32 i;
|
||||
Int32 j;
|
||||
Int32 t;
|
||||
Int32 alphaSize;
|
||||
Int32 nGroups;
|
||||
Int32 nSelectors;
|
||||
Int32 EOB;
|
||||
Int32 groupNo;
|
||||
Int32 groupPos;
|
||||
Int32 nextSym;
|
||||
Int32 nblockMAX;
|
||||
Int32 nblock;
|
||||
Int32 es;
|
||||
Int32 N;
|
||||
Int32 curr;
|
||||
Int32 zt;
|
||||
Int32 zn;
|
||||
Int32 zvec;
|
||||
Int32 zj;
|
||||
Int32 gSel;
|
||||
Int32 gMinlen;
|
||||
Int32* gLimit;
|
||||
Int32* gBase;
|
||||
Int32* gPerm;
|
||||
|
||||
if (s->state == BZ_X_MAGIC_1) {
|
||||
/*initialise the save area*/
|
||||
s->save_i = 0;
|
||||
s->save_j = 0;
|
||||
s->save_t = 0;
|
||||
s->save_alphaSize = 0;
|
||||
s->save_nGroups = 0;
|
||||
s->save_nSelectors = 0;
|
||||
s->save_EOB = 0;
|
||||
s->save_groupNo = 0;
|
||||
s->save_groupPos = 0;
|
||||
s->save_nextSym = 0;
|
||||
s->save_nblockMAX = 0;
|
||||
s->save_nblock = 0;
|
||||
s->save_es = 0;
|
||||
s->save_N = 0;
|
||||
s->save_curr = 0;
|
||||
s->save_zt = 0;
|
||||
s->save_zn = 0;
|
||||
s->save_zvec = 0;
|
||||
s->save_zj = 0;
|
||||
s->save_gSel = 0;
|
||||
s->save_gMinlen = 0;
|
||||
s->save_gLimit = NULL;
|
||||
s->save_gBase = NULL;
|
||||
s->save_gPerm = NULL;
|
||||
}
|
||||
|
||||
/*restore from the save area*/
|
||||
i = s->save_i;
|
||||
j = s->save_j;
|
||||
t = s->save_t;
|
||||
alphaSize = s->save_alphaSize;
|
||||
nGroups = s->save_nGroups;
|
||||
nSelectors = s->save_nSelectors;
|
||||
EOB = s->save_EOB;
|
||||
groupNo = s->save_groupNo;
|
||||
groupPos = s->save_groupPos;
|
||||
nextSym = s->save_nextSym;
|
||||
nblockMAX = s->save_nblockMAX;
|
||||
nblock = s->save_nblock;
|
||||
es = s->save_es;
|
||||
N = s->save_N;
|
||||
curr = s->save_curr;
|
||||
zt = s->save_zt;
|
||||
zn = s->save_zn;
|
||||
zvec = s->save_zvec;
|
||||
zj = s->save_zj;
|
||||
gSel = s->save_gSel;
|
||||
gMinlen = s->save_gMinlen;
|
||||
gLimit = s->save_gLimit;
|
||||
gBase = s->save_gBase;
|
||||
gPerm = s->save_gPerm;
|
||||
|
||||
retVal = BZ_OK;
|
||||
|
||||
switch (s->state) {
|
||||
|
||||
GET_UCHAR(BZ_X_MAGIC_1, uc);
|
||||
if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC);
|
||||
|
||||
GET_UCHAR(BZ_X_MAGIC_2, uc);
|
||||
if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC);
|
||||
|
||||
GET_UCHAR(BZ_X_MAGIC_3, uc)
|
||||
if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC);
|
||||
|
||||
GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8)
|
||||
if (s->blockSize100k < (BZ_HDR_0 + 1) ||
|
||||
s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC);
|
||||
s->blockSize100k -= BZ_HDR_0;
|
||||
|
||||
if (s->smallDecompress) {
|
||||
s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) );
|
||||
s->ll4 = BZALLOC(
|
||||
((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar)
|
||||
);
|
||||
if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
|
||||
} else {
|
||||
s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) );
|
||||
if (s->tt == NULL) RETURN(BZ_MEM_ERROR);
|
||||
}
|
||||
|
||||
GET_UCHAR(BZ_X_BLKHDR_1, uc);
|
||||
|
||||
if (uc == 0x17) goto endhdr_2;
|
||||
if (uc != 0x31) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_BLKHDR_2, uc);
|
||||
if (uc != 0x41) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_BLKHDR_3, uc);
|
||||
if (uc != 0x59) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_BLKHDR_4, uc);
|
||||
if (uc != 0x26) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_BLKHDR_5, uc);
|
||||
if (uc != 0x53) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_BLKHDR_6, uc);
|
||||
if (uc != 0x59) RETURN(BZ_DATA_ERROR);
|
||||
|
||||
s->currBlockNo++;
|
||||
if (s->verbosity >= 2)
|
||||
VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo );
|
||||
|
||||
s->storedBlockCRC = 0;
|
||||
GET_UCHAR(BZ_X_BCRC_1, uc);
|
||||
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_BCRC_2, uc);
|
||||
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_BCRC_3, uc);
|
||||
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_BCRC_4, uc);
|
||||
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
|
||||
|
||||
GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
|
||||
|
||||
s->origPtr = 0;
|
||||
GET_UCHAR(BZ_X_ORIGPTR_1, uc);
|
||||
s->origPtr = (s->origPtr << 8) | ((Int32)uc);
|
||||
GET_UCHAR(BZ_X_ORIGPTR_2, uc);
|
||||
s->origPtr = (s->origPtr << 8) | ((Int32)uc);
|
||||
GET_UCHAR(BZ_X_ORIGPTR_3, uc);
|
||||
s->origPtr = (s->origPtr << 8) | ((Int32)uc);
|
||||
|
||||
if (s->origPtr < 0)
|
||||
RETURN(BZ_DATA_ERROR);
|
||||
if (s->origPtr > 10 + 100000*s->blockSize100k)
|
||||
RETURN(BZ_DATA_ERROR);
|
||||
|
||||
/*--- Receive the mapping table ---*/
|
||||
for (i = 0; i < 16; i++) {
|
||||
GET_BIT(BZ_X_MAPPING_1, uc);
|
||||
if (uc == 1)
|
||||
s->inUse16[i] = True; else
|
||||
s->inUse16[i] = False;
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++) s->inUse[i] = False;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
if (s->inUse16[i])
|
||||
for (j = 0; j < 16; j++) {
|
||||
GET_BIT(BZ_X_MAPPING_2, uc);
|
||||
if (uc == 1) s->inUse[i * 16 + j] = True;
|
||||
}
|
||||
makeMaps_d ( s );
|
||||
if (s->nInUse == 0) RETURN(BZ_DATA_ERROR);
|
||||
alphaSize = s->nInUse+2;
|
||||
|
||||
/*--- Now the selectors ---*/
|
||||
GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
|
||||
if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR);
|
||||
GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
|
||||
if (nSelectors < 1) RETURN(BZ_DATA_ERROR);
|
||||
for (i = 0; i < nSelectors; i++) {
|
||||
j = 0;
|
||||
while (True) {
|
||||
GET_BIT(BZ_X_SELECTOR_3, uc);
|
||||
if (uc == 0) break;
|
||||
j++;
|
||||
if (j >= nGroups) RETURN(BZ_DATA_ERROR);
|
||||
}
|
||||
s->selectorMtf[i] = j;
|
||||
}
|
||||
|
||||
/*--- Undo the MTF values for the selectors. ---*/
|
||||
{
|
||||
UChar pos[BZ_N_GROUPS], tmp, v;
|
||||
for (v = 0; v < nGroups; v++) pos[v] = v;
|
||||
|
||||
for (i = 0; i < nSelectors; i++) {
|
||||
v = s->selectorMtf[i];
|
||||
tmp = pos[v];
|
||||
while (v > 0) { pos[v] = pos[v-1]; v--; }
|
||||
pos[0] = tmp;
|
||||
s->selector[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/*--- Now the coding tables ---*/
|
||||
for (t = 0; t < nGroups; t++) {
|
||||
GET_BITS(BZ_X_CODING_1, curr, 5);
|
||||
for (i = 0; i < alphaSize; i++) {
|
||||
while (True) {
|
||||
if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
|
||||
GET_BIT(BZ_X_CODING_2, uc);
|
||||
if (uc == 0) break;
|
||||
GET_BIT(BZ_X_CODING_3, uc);
|
||||
if (uc == 0) curr++; else curr--;
|
||||
}
|
||||
s->len[t][i] = curr;
|
||||
}
|
||||
}
|
||||
|
||||
/*--- Create the Huffman decoding tables ---*/
|
||||
for (t = 0; t < nGroups; t++) {
|
||||
minLen = 32;
|
||||
maxLen = 0;
|
||||
for (i = 0; i < alphaSize; i++) {
|
||||
if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
|
||||
if (s->len[t][i] < minLen) minLen = s->len[t][i];
|
||||
}
|
||||
BZ2_hbCreateDecodeTables (
|
||||
&(s->limit[t][0]),
|
||||
&(s->base[t][0]),
|
||||
&(s->perm[t][0]),
|
||||
&(s->len[t][0]),
|
||||
minLen, maxLen, alphaSize
|
||||
);
|
||||
s->minLens[t] = minLen;
|
||||
}
|
||||
|
||||
/*--- Now the MTF values ---*/
|
||||
|
||||
EOB = s->nInUse+1;
|
||||
nblockMAX = 100000 * s->blockSize100k;
|
||||
groupNo = -1;
|
||||
groupPos = 0;
|
||||
|
||||
for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
|
||||
|
||||
/*-- MTF init --*/
|
||||
{
|
||||
Int32 ii, jj, kk;
|
||||
kk = MTFA_SIZE-1;
|
||||
for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
|
||||
for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
|
||||
s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj);
|
||||
kk--;
|
||||
}
|
||||
s->mtfbase[ii] = kk + 1;
|
||||
}
|
||||
}
|
||||
/*-- end MTF init --*/
|
||||
|
||||
nblock = 0;
|
||||
GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
|
||||
|
||||
while (True) {
|
||||
|
||||
if (nextSym == EOB) break;
|
||||
|
||||
if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
|
||||
|
||||
es = -1;
|
||||
N = 1;
|
||||
do {
|
||||
/* Check that N doesn't get too big, so that es doesn't
|
||||
go negative. The maximum value that can be
|
||||
RUNA/RUNB encoded is equal to the block size (post
|
||||
the initial RLE), viz, 900k, so bounding N at 2
|
||||
million should guard against overflow without
|
||||
rejecting any legitimate inputs. */
|
||||
if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR);
|
||||
if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
|
||||
if (nextSym == BZ_RUNB) es = es + (1+1) * N;
|
||||
N = N * 2;
|
||||
GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
|
||||
}
|
||||
while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
|
||||
|
||||
es++;
|
||||
uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
|
||||
s->unzftab[uc] += es;
|
||||
|
||||
if (s->smallDecompress)
|
||||
while (es > 0) {
|
||||
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
|
||||
s->ll16[nblock] = (UInt16)uc;
|
||||
nblock++;
|
||||
es--;
|
||||
}
|
||||
else
|
||||
while (es > 0) {
|
||||
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
|
||||
s->tt[nblock] = (UInt32)uc;
|
||||
nblock++;
|
||||
es--;
|
||||
};
|
||||
|
||||
continue;
|
||||
|
||||
} else {
|
||||
|
||||
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
|
||||
|
||||
/*-- uc = MTF ( nextSym-1 ) --*/
|
||||
{
|
||||
Int32 ii, jj, kk, pp, lno, off;
|
||||
UInt32 nn;
|
||||
nn = (UInt32)(nextSym - 1);
|
||||
|
||||
if (nn < MTFL_SIZE) {
|
||||
/* avoid general-case expense */
|
||||
pp = s->mtfbase[0];
|
||||
uc = s->mtfa[pp+nn];
|
||||
while (nn > 3) {
|
||||
Int32 z = pp+nn;
|
||||
s->mtfa[(z) ] = s->mtfa[(z)-1];
|
||||
s->mtfa[(z)-1] = s->mtfa[(z)-2];
|
||||
s->mtfa[(z)-2] = s->mtfa[(z)-3];
|
||||
s->mtfa[(z)-3] = s->mtfa[(z)-4];
|
||||
nn -= 4;
|
||||
}
|
||||
while (nn > 0) {
|
||||
s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--;
|
||||
};
|
||||
s->mtfa[pp] = uc;
|
||||
} else {
|
||||
/* general case */
|
||||
lno = nn / MTFL_SIZE;
|
||||
off = nn % MTFL_SIZE;
|
||||
pp = s->mtfbase[lno] + off;
|
||||
uc = s->mtfa[pp];
|
||||
while (pp > s->mtfbase[lno]) {
|
||||
s->mtfa[pp] = s->mtfa[pp-1]; pp--;
|
||||
};
|
||||
s->mtfbase[lno]++;
|
||||
while (lno > 0) {
|
||||
s->mtfbase[lno]--;
|
||||
s->mtfa[s->mtfbase[lno]]
|
||||
= s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
|
||||
lno--;
|
||||
}
|
||||
s->mtfbase[0]--;
|
||||
s->mtfa[s->mtfbase[0]] = uc;
|
||||
if (s->mtfbase[0] == 0) {
|
||||
kk = MTFA_SIZE-1;
|
||||
for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
|
||||
for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
|
||||
s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
|
||||
kk--;
|
||||
}
|
||||
s->mtfbase[ii] = kk + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-- end uc = MTF ( nextSym-1 ) --*/
|
||||
|
||||
s->unzftab[s->seqToUnseq[uc]]++;
|
||||
if (s->smallDecompress)
|
||||
s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else
|
||||
s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]);
|
||||
nblock++;
|
||||
|
||||
GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we know what nblock is, we can do a better sanity
|
||||
check on s->origPtr.
|
||||
*/
|
||||
if (s->origPtr < 0 || s->origPtr >= nblock)
|
||||
RETURN(BZ_DATA_ERROR);
|
||||
|
||||
/*-- Set up cftab to facilitate generation of T^(-1) --*/
|
||||
/* Check: unzftab entries in range. */
|
||||
for (i = 0; i <= 255; i++) {
|
||||
if (s->unzftab[i] < 0 || s->unzftab[i] > nblock)
|
||||
RETURN(BZ_DATA_ERROR);
|
||||
}
|
||||
/* Actually generate cftab. */
|
||||
s->cftab[0] = 0;
|
||||
for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
|
||||
for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
|
||||
/* Check: cftab entries in range. */
|
||||
for (i = 0; i <= 256; i++) {
|
||||
if (s->cftab[i] < 0 || s->cftab[i] > nblock) {
|
||||
/* s->cftab[i] can legitimately be == nblock */
|
||||
RETURN(BZ_DATA_ERROR);
|
||||
}
|
||||
}
|
||||
/* Check: cftab entries non-descending. */
|
||||
for (i = 1; i <= 256; i++) {
|
||||
if (s->cftab[i-1] > s->cftab[i]) {
|
||||
RETURN(BZ_DATA_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
s->state_out_len = 0;
|
||||
s->state_out_ch = 0;
|
||||
BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
|
||||
s->state = BZ_X_OUTPUT;
|
||||
if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
|
||||
|
||||
if (s->smallDecompress) {
|
||||
|
||||
/*-- Make a copy of cftab, used in generation of T --*/
|
||||
for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
|
||||
|
||||
/*-- compute the T vector --*/
|
||||
for (i = 0; i < nblock; i++) {
|
||||
uc = (UChar)(s->ll16[i]);
|
||||
SET_LL(i, s->cftabCopy[uc]);
|
||||
s->cftabCopy[uc]++;
|
||||
}
|
||||
|
||||
/*-- Compute T^(-1) by pointer reversal on T --*/
|
||||
i = s->origPtr;
|
||||
j = GET_LL(i);
|
||||
do {
|
||||
Int32 tmp = GET_LL(j);
|
||||
SET_LL(j, i);
|
||||
i = j;
|
||||
j = tmp;
|
||||
}
|
||||
while (i != s->origPtr);
|
||||
|
||||
s->tPos = s->origPtr;
|
||||
s->nblock_used = 0;
|
||||
if (s->blockRandomised) {
|
||||
BZ_RAND_INIT_MASK;
|
||||
BZ_GET_SMALL(s->k0); s->nblock_used++;
|
||||
BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
|
||||
} else {
|
||||
BZ_GET_SMALL(s->k0); s->nblock_used++;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/*-- compute the T^(-1) vector --*/
|
||||
for (i = 0; i < nblock; i++) {
|
||||
uc = (UChar)(s->tt[i] & 0xff);
|
||||
s->tt[s->cftab[uc]] |= (i << 8);
|
||||
s->cftab[uc]++;
|
||||
}
|
||||
|
||||
s->tPos = s->tt[s->origPtr] >> 8;
|
||||
s->nblock_used = 0;
|
||||
if (s->blockRandomised) {
|
||||
BZ_RAND_INIT_MASK;
|
||||
BZ_GET_FAST(s->k0); s->nblock_used++;
|
||||
BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
|
||||
} else {
|
||||
BZ_GET_FAST(s->k0); s->nblock_used++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RETURN(BZ_OK);
|
||||
|
||||
|
||||
|
||||
endhdr_2:
|
||||
|
||||
GET_UCHAR(BZ_X_ENDHDR_2, uc);
|
||||
if (uc != 0x72) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_ENDHDR_3, uc);
|
||||
if (uc != 0x45) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_ENDHDR_4, uc);
|
||||
if (uc != 0x38) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_ENDHDR_5, uc);
|
||||
if (uc != 0x50) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_ENDHDR_6, uc);
|
||||
if (uc != 0x90) RETURN(BZ_DATA_ERROR);
|
||||
|
||||
s->storedCombinedCRC = 0;
|
||||
GET_UCHAR(BZ_X_CCRC_1, uc);
|
||||
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_CCRC_2, uc);
|
||||
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_CCRC_3, uc);
|
||||
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_CCRC_4, uc);
|
||||
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
|
||||
|
||||
s->state = BZ_X_IDLE;
|
||||
RETURN(BZ_STREAM_END);
|
||||
|
||||
default: AssertH ( False, 4001 );
|
||||
}
|
||||
|
||||
AssertH ( False, 4002 );
|
||||
|
||||
save_state_and_return:
|
||||
|
||||
s->save_i = i;
|
||||
s->save_j = j;
|
||||
s->save_t = t;
|
||||
s->save_alphaSize = alphaSize;
|
||||
s->save_nGroups = nGroups;
|
||||
s->save_nSelectors = nSelectors;
|
||||
s->save_EOB = EOB;
|
||||
s->save_groupNo = groupNo;
|
||||
s->save_groupPos = groupPos;
|
||||
s->save_nextSym = nextSym;
|
||||
s->save_nblockMAX = nblockMAX;
|
||||
s->save_nblock = nblock;
|
||||
s->save_es = es;
|
||||
s->save_N = N;
|
||||
s->save_curr = curr;
|
||||
s->save_zt = zt;
|
||||
s->save_zn = zn;
|
||||
s->save_zvec = zvec;
|
||||
s->save_zj = zj;
|
||||
s->save_gSel = gSel;
|
||||
s->save_gMinlen = gMinlen;
|
||||
s->save_gLimit = gLimit;
|
||||
s->save_gBase = gBase;
|
||||
s->save_gPerm = gPerm;
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end decompress.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
205
utils/bzip2/huffman.c
Normal file
205
utils/bzip2/huffman.c
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Huffman coding low-level stuff ---*/
|
||||
/*--- huffman.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#include "bzlib_private.h"
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define WEIGHTOF(zz0) ((zz0) & 0xffffff00)
|
||||
#define DEPTHOF(zz1) ((zz1) & 0x000000ff)
|
||||
#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3))
|
||||
|
||||
#define ADDWEIGHTS(zw1,zw2) \
|
||||
(WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \
|
||||
(1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2)))
|
||||
|
||||
#define UPHEAP(z) \
|
||||
{ \
|
||||
Int32 zz, tmp; \
|
||||
zz = z; tmp = heap[zz]; \
|
||||
while (weight[tmp] < weight[heap[zz >> 1]]) { \
|
||||
heap[zz] = heap[zz >> 1]; \
|
||||
zz >>= 1; \
|
||||
} \
|
||||
heap[zz] = tmp; \
|
||||
}
|
||||
|
||||
#define DOWNHEAP(z) \
|
||||
{ \
|
||||
Int32 zz, yy, tmp; \
|
||||
zz = z; tmp = heap[zz]; \
|
||||
while (True) { \
|
||||
yy = zz << 1; \
|
||||
if (yy > nHeap) break; \
|
||||
if (yy < nHeap && \
|
||||
weight[heap[yy+1]] < weight[heap[yy]]) \
|
||||
yy++; \
|
||||
if (weight[tmp] < weight[heap[yy]]) break; \
|
||||
heap[zz] = heap[yy]; \
|
||||
zz = yy; \
|
||||
} \
|
||||
heap[zz] = tmp; \
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
void BZ2_hbMakeCodeLengths ( UChar *len,
|
||||
Int32 *freq,
|
||||
Int32 alphaSize,
|
||||
Int32 maxLen )
|
||||
{
|
||||
/*--
|
||||
Nodes and heap entries run from 1. Entry 0
|
||||
for both the heap and nodes is a sentinel.
|
||||
--*/
|
||||
Int32 nNodes, nHeap, n1, n2, i, j, k;
|
||||
Bool tooLong;
|
||||
|
||||
Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ];
|
||||
Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ];
|
||||
Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ];
|
||||
|
||||
for (i = 0; i < alphaSize; i++)
|
||||
weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
|
||||
|
||||
while (True) {
|
||||
|
||||
nNodes = alphaSize;
|
||||
nHeap = 0;
|
||||
|
||||
heap[0] = 0;
|
||||
weight[0] = 0;
|
||||
parent[0] = -2;
|
||||
|
||||
for (i = 1; i <= alphaSize; i++) {
|
||||
parent[i] = -1;
|
||||
nHeap++;
|
||||
heap[nHeap] = i;
|
||||
UPHEAP(nHeap);
|
||||
}
|
||||
|
||||
AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 );
|
||||
|
||||
while (nHeap > 1) {
|
||||
n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
|
||||
n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
|
||||
nNodes++;
|
||||
parent[n1] = parent[n2] = nNodes;
|
||||
weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
|
||||
parent[nNodes] = -1;
|
||||
nHeap++;
|
||||
heap[nHeap] = nNodes;
|
||||
UPHEAP(nHeap);
|
||||
}
|
||||
|
||||
AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 );
|
||||
|
||||
tooLong = False;
|
||||
for (i = 1; i <= alphaSize; i++) {
|
||||
j = 0;
|
||||
k = i;
|
||||
while (parent[k] >= 0) { k = parent[k]; j++; }
|
||||
len[i-1] = j;
|
||||
if (j > maxLen) tooLong = True;
|
||||
}
|
||||
|
||||
if (! tooLong) break;
|
||||
|
||||
/* 17 Oct 04: keep-going condition for the following loop used
|
||||
to be 'i < alphaSize', which missed the last element,
|
||||
theoretically leading to the possibility of the compressor
|
||||
looping. However, this count-scaling step is only needed if
|
||||
one of the generated Huffman code words is longer than
|
||||
maxLen, which up to and including version 1.0.2 was 20 bits,
|
||||
which is extremely unlikely. In version 1.0.3 maxLen was
|
||||
changed to 17 bits, which has minimal effect on compression
|
||||
ratio, but does mean this scaling step is used from time to
|
||||
time, enough to verify that it works.
|
||||
|
||||
This means that bzip2-1.0.3 and later will only produce
|
||||
Huffman codes with a maximum length of 17 bits. However, in
|
||||
order to preserve backwards compatibility with bitstreams
|
||||
produced by versions pre-1.0.3, the decompressor must still
|
||||
handle lengths of up to 20. */
|
||||
|
||||
for (i = 1; i <= alphaSize; i++) {
|
||||
j = weight[i] >> 8;
|
||||
j = 1 + (j / 2);
|
||||
weight[i] = j << 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
void BZ2_hbAssignCodes ( Int32 *code,
|
||||
UChar *length,
|
||||
Int32 minLen,
|
||||
Int32 maxLen,
|
||||
Int32 alphaSize )
|
||||
{
|
||||
Int32 n, vec, i;
|
||||
|
||||
vec = 0;
|
||||
for (n = minLen; n <= maxLen; n++) {
|
||||
for (i = 0; i < alphaSize; i++)
|
||||
if (length[i] == n) { code[i] = vec; vec++; };
|
||||
vec <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
void BZ2_hbCreateDecodeTables ( Int32 *limit,
|
||||
Int32 *base,
|
||||
Int32 *perm,
|
||||
UChar *length,
|
||||
Int32 minLen,
|
||||
Int32 maxLen,
|
||||
Int32 alphaSize )
|
||||
{
|
||||
Int32 pp, i, j, vec;
|
||||
|
||||
pp = 0;
|
||||
for (i = minLen; i <= maxLen; i++)
|
||||
for (j = 0; j < alphaSize; j++)
|
||||
if (length[j] == i) { perm[pp] = j; pp++; };
|
||||
|
||||
for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0;
|
||||
for (i = 0; i < alphaSize; i++) base[length[i]+1]++;
|
||||
|
||||
for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1];
|
||||
|
||||
for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0;
|
||||
vec = 0;
|
||||
|
||||
for (i = minLen; i <= maxLen; i++) {
|
||||
vec += (base[i+1] - base[i]);
|
||||
limit[i] = vec-1;
|
||||
vec <<= 1;
|
||||
}
|
||||
for (i = minLen + 1; i <= maxLen; i++)
|
||||
base[i] = ((limit[i-1] + 1) << 1) - base[i];
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end huffman.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
84
utils/bzip2/randtable.c
Normal file
84
utils/bzip2/randtable.c
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Table for randomising repetitive blocks ---*/
|
||||
/*--- randtable.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#include "bzlib_private.h"
|
||||
|
||||
|
||||
/*---------------------------------------------*/
|
||||
Int32 BZ2_rNums[512] = {
|
||||
619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
|
||||
985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
|
||||
733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
|
||||
419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
|
||||
878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
|
||||
862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
|
||||
150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
|
||||
170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
|
||||
73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
|
||||
909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
|
||||
641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
|
||||
161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
|
||||
382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
|
||||
98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
|
||||
227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
|
||||
469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
|
||||
184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
|
||||
715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
|
||||
951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
|
||||
652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
|
||||
645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
|
||||
609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
|
||||
653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
|
||||
411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
|
||||
170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
|
||||
857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
|
||||
669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
|
||||
944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
|
||||
344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
|
||||
897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
|
||||
433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
|
||||
686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
|
||||
946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
|
||||
978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
|
||||
680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
|
||||
707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
|
||||
297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
|
||||
134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
|
||||
343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
|
||||
140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
|
||||
170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
|
||||
369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
|
||||
804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
|
||||
896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
|
||||
661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
|
||||
768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
|
||||
61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
|
||||
372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
|
||||
780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
|
||||
920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
|
||||
645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
|
||||
936, 638
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end randtable.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
17
utils/chinachippatcher/Makefile
Normal file
17
utils/chinachippatcher/Makefile
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
# $Id$
|
||||
#
|
||||
CFLAGS += -g -Wall
|
||||
|
||||
OUTPUT = chinachippatcher
|
||||
|
||||
LIBSOURCES = chinachip.c
|
||||
SOURCES = main.c
|
||||
|
||||
include ../libtools.make
|
||||
|
||||
258
utils/chinachippatcher/chinachip.c
Normal file
258
utils/chinachippatcher/chinachip.c
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2009 by Maurus Cuelenaere
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "chinachip.h"
|
||||
|
||||
/* From http://www.rockbox.org/wiki/ChinaChip */
|
||||
struct header
|
||||
{
|
||||
uint32_t signature; /* WADF */
|
||||
uint32_t unk;
|
||||
int8_t timestamp[12]; /* 200805081100 */
|
||||
uint32_t size;
|
||||
uint32_t checksum;
|
||||
uint32_t unk2;
|
||||
int8_t identifier[32]; /* Chinachip PMP firmware V1.0 */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static inline void int2le(unsigned char* addr, unsigned int val)
|
||||
{
|
||||
addr[0] = val & 0xff;
|
||||
addr[1] = (val >> 8) & 0xff;
|
||||
addr[2] = (val >> 16) & 0xff;
|
||||
addr[3] = (val >> 24) & 0xff;
|
||||
}
|
||||
|
||||
static inline unsigned int le2int(unsigned char* buf)
|
||||
{
|
||||
return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
|
||||
}
|
||||
|
||||
static long int filesize(FILE* fd)
|
||||
{
|
||||
long int len;
|
||||
fseek(fd, 0, SEEK_END);
|
||||
len = ftell(fd);
|
||||
fseek(fd, 0, SEEK_SET);
|
||||
return len;
|
||||
}
|
||||
|
||||
#define FCLOSE(fd) fclose(fd); fd = NULL;
|
||||
#define CCPMPBIN_HEADER_SIZE (sizeof(uint32_t)*2 + sizeof(uint8_t) + 9)
|
||||
#define TOTAL_SIZE (fsize + CCPMPBIN_HEADER_SIZE + bsize)
|
||||
enum cc_error chinachip_patch(const char* firmware, const char* bootloader,
|
||||
const char* output, const char* ccpmp_backup)
|
||||
{
|
||||
char header_time[13];
|
||||
time_t cur_time;
|
||||
struct tm* time_info;
|
||||
unsigned char* buf = NULL;
|
||||
FILE *fd = NULL, *bd = NULL, *od = NULL;
|
||||
unsigned int ccpmp_size = 0, i, fsize, bsize;
|
||||
signed int checksum = 0, ccpmp_pos;
|
||||
int result = E_OK;
|
||||
|
||||
fd = fopen(firmware, "rb");
|
||||
if(!fd)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Can't open file %s!\n", firmware);
|
||||
result = E_OPEN_FIRMWARE;
|
||||
goto err;
|
||||
}
|
||||
bd = fopen(bootloader, "rb");
|
||||
if(!bd)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Can't open file %s!\n", bootloader);
|
||||
result = E_OPEN_BOOTLOADER;
|
||||
goto err;
|
||||
}
|
||||
|
||||
bsize = filesize(bd);
|
||||
fprintf(stderr, "[INFO] Bootloader size is %d bytes\n", bsize);
|
||||
FCLOSE(bd);
|
||||
|
||||
fsize = filesize(fd);
|
||||
fprintf(stderr, "[INFO] Firmware size is %d bytes\n", fsize);
|
||||
|
||||
buf = malloc(TOTAL_SIZE);
|
||||
if(buf == NULL)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Can't allocate %d bytes!\n", fsize);
|
||||
result = E_MEMALLOC;
|
||||
goto err;
|
||||
}
|
||||
memset(buf, 0, TOTAL_SIZE);
|
||||
|
||||
fprintf(stderr, "[INFO] Reading %s into memory...\n", firmware);
|
||||
if(fread(buf, fsize, 1, fd) != 1)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Can't read file %s to memory!\n", firmware);
|
||||
result = E_LOAD_FIRMWARE;
|
||||
goto err;
|
||||
}
|
||||
FCLOSE(fd);
|
||||
|
||||
if(memcmp(buf, "WADF", 4))
|
||||
{
|
||||
fprintf(stderr, "[ERR] File %s isn't a valid ChinaChip firmware!\n", firmware);
|
||||
result = E_INVALID_FILE;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ccpmp_pos = -1, i = 0x40;
|
||||
do
|
||||
{
|
||||
int filenamesize = le2int(&buf[i]);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
if(!strncmp((char*) &buf[i], "ccpmp.bin", 9))
|
||||
{
|
||||
ccpmp_pos = i;
|
||||
ccpmp_size = le2int(&buf[i + sizeof(uint8_t) + filenamesize]);
|
||||
}
|
||||
else
|
||||
i += filenamesize + le2int(&buf[i + sizeof(uint8_t) + filenamesize])
|
||||
+ sizeof(uint32_t) + sizeof(uint8_t);
|
||||
} while(ccpmp_pos < 0 && i < fsize);
|
||||
|
||||
if(i >= fsize)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Couldn't find ccpmp.bin in %s!\n", firmware);
|
||||
result = E_NO_CCPMP;
|
||||
goto err;
|
||||
}
|
||||
fprintf(stderr, "[INFO] Found ccpmp.bin at %d bytes\n", ccpmp_pos);
|
||||
|
||||
if(ccpmp_backup)
|
||||
{
|
||||
int ccpmp_data_pos = ccpmp_pos + 9;
|
||||
bd = fopen(ccpmp_backup, "wb");
|
||||
if(!bd)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Can't open file %s!\n", ccpmp_backup);
|
||||
result = E_OPEN_BACKUP;
|
||||
goto err;
|
||||
}
|
||||
|
||||
fprintf(stderr, "[INFO] Writing %d bytes to %s...\n", ccpmp_size, ccpmp_backup);
|
||||
if(fwrite(&buf[ccpmp_data_pos], ccpmp_size, 1, bd) != 1)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Can't write to file %s!\n", ccpmp_backup);
|
||||
result = E_WRITE_BACKUP;
|
||||
goto err;
|
||||
}
|
||||
FCLOSE(bd);
|
||||
}
|
||||
|
||||
fprintf(stderr, "[INFO] Renaming it to ccpmp.old...\n");
|
||||
buf[ccpmp_pos + 6] = 'o';
|
||||
buf[ccpmp_pos + 7] = 'l';
|
||||
buf[ccpmp_pos + 8] = 'd';
|
||||
|
||||
bd = fopen(bootloader, "rb");
|
||||
if(!bd)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Can't open file %s!\n", bootloader);
|
||||
result = E_OPEN_BOOTLOADER;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Also include path size */
|
||||
ccpmp_pos -= sizeof(uint32_t);
|
||||
|
||||
fprintf(stderr, "[INFO] Making place for ccpmp.bin...\n");
|
||||
memmove(&buf[ccpmp_pos + bsize + CCPMPBIN_HEADER_SIZE],
|
||||
&buf[ccpmp_pos], fsize - ccpmp_pos);
|
||||
|
||||
fprintf(stderr, "[INFO] Reading %s into memory...\n", bootloader);
|
||||
if(fread(&buf[ccpmp_pos + CCPMPBIN_HEADER_SIZE],
|
||||
bsize, 1, bd) != 1)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Can't read file %s to memory!\n", bootloader);
|
||||
result = E_LOAD_BOOTLOADER;
|
||||
goto err;
|
||||
}
|
||||
FCLOSE(bd);
|
||||
|
||||
fprintf(stderr, "[INFO] Adding header to %s...\n", bootloader);
|
||||
int2le(&buf[ccpmp_pos ], 9); /* Pathname Size */
|
||||
memcpy(&buf[ccpmp_pos + 4 ], "ccpmp.bin", 9); /* Pathname */
|
||||
memset(&buf[ccpmp_pos + 4 + 9 ], 0x20, sizeof(uint8_t)); /* File Type */
|
||||
int2le(&buf[ccpmp_pos + 4 + 9 + 1], bsize); /* File Size */
|
||||
|
||||
time(&cur_time);
|
||||
time_info = localtime(&cur_time);
|
||||
if(time_info == NULL)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Can't obtain current time!\n");
|
||||
result = E_GET_TIME;
|
||||
goto err;
|
||||
}
|
||||
|
||||
snprintf(header_time, 13, "%04d%02d%02d%02d%02d", time_info->tm_year + 1900,
|
||||
time_info->tm_mon,
|
||||
time_info->tm_mday,
|
||||
time_info->tm_hour,
|
||||
time_info->tm_min);
|
||||
|
||||
fprintf(stderr, "[INFO] Computing checksum...\n");
|
||||
for(i = sizeof(struct header); i < TOTAL_SIZE; i+=4)
|
||||
checksum += le2int(&buf[i]);
|
||||
|
||||
fprintf(stderr, "[INFO] Updating main header...\n");
|
||||
memcpy(&buf[offsetof(struct header, timestamp)], header_time, 12);
|
||||
int2le(&buf[offsetof(struct header, size) ], TOTAL_SIZE);
|
||||
int2le(&buf[offsetof(struct header, checksum) ], checksum);
|
||||
|
||||
od = fopen(output, "wb");
|
||||
if(!od)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Can't open file %s!\n", output);
|
||||
result = E_OPEN_OUTFILE;
|
||||
goto err;
|
||||
}
|
||||
|
||||
fprintf(stderr, "[INFO] Writing output to %s...\n", output);
|
||||
if(fwrite(buf, TOTAL_SIZE, 1, od) != 1)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Can't write to file %s!\n", output);
|
||||
result = E_WRITE_OUTFILE;
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
if(buf)
|
||||
free(buf);
|
||||
if(fd)
|
||||
fclose(fd);
|
||||
if(bd)
|
||||
fclose(bd);
|
||||
if(od)
|
||||
fclose(od);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
52
utils/chinachippatcher/chinachip.h
Normal file
52
utils/chinachippatcher/chinachip.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2009 by Maurus Cuelenaere
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __INCLUDE_CHINACHIP_H_
|
||||
#define __INCLUDE_CHINACHIP_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum cc_error {
|
||||
E_OK,
|
||||
E_OPEN_FIRMWARE,
|
||||
E_OPEN_BOOTLOADER,
|
||||
E_MEMALLOC,
|
||||
E_LOAD_FIRMWARE,
|
||||
E_INVALID_FILE,
|
||||
E_NO_CCPMP,
|
||||
E_OPEN_BACKUP,
|
||||
E_WRITE_BACKUP,
|
||||
E_LOAD_BOOTLOADER,
|
||||
E_GET_TIME,
|
||||
E_OPEN_OUTFILE,
|
||||
E_WRITE_OUTFILE,
|
||||
};
|
||||
|
||||
enum cc_error chinachip_patch(const char* firmware, const char* bootloader,
|
||||
const char* output, const char* ccpmp_backup);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INCLUDE_CHINACHIP_H_ */
|
||||
55
utils/chinachippatcher/main.c
Normal file
55
utils/chinachippatcher/main.c
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2009 by Maurus Cuelenaere
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "chinachip.h"
|
||||
|
||||
#ifndef VERSION /* allow setting version from outside for svn builds */
|
||||
#define VERSION "0.1"
|
||||
#endif
|
||||
#define PRINT(fmt, ...) fprintf(stderr, fmt"\n", ##__VA_ARGS__)
|
||||
|
||||
void usage(char* name)
|
||||
{
|
||||
PRINT("Usage:");
|
||||
PRINT(" %s <firmware> <bootloader> <firmware_output> [backup]", name);
|
||||
PRINT("\nExample:");
|
||||
PRINT(" %s VX747.HXF bootloader.bin output.HXF ccpmp.bak", name);
|
||||
PRINT(" This will copy ccpmp.bin in VX747.HXF as ccpmp.old and replace it\n"
|
||||
" with bootloader.bin, the output will get written to output.HXF.\n"
|
||||
" The old ccpmp.bin will get written to ccpmp.bak.\n");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
PRINT("ChinaChipPatcher v" VERSION " - (C) Maurus Cuelenaere 2009");
|
||||
PRINT("This is free software; see the source for copying conditions. There is NO");
|
||||
PRINT("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
|
||||
|
||||
if(argc < 4)
|
||||
{
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return chinachip_patch(argv[1], argv[2], argv[3], argc > 4 ? argv[4] : NULL);
|
||||
}
|
||||
|
||||
56
utils/e200rpatcher/Makefile
Normal file
56
utils/e200rpatcher/Makefile
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
CFLAGS=-Wall -W
|
||||
|
||||
ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
|
||||
OUTPUT=e200rpatcher.exe
|
||||
CROSS=
|
||||
CFLAGS+=-mno-cygwin
|
||||
else
|
||||
OUTPUT=e200rpatcher
|
||||
CROSS=i586-mingw32msvc-
|
||||
endif
|
||||
|
||||
LIBS = -lusb
|
||||
WINLIBS = -I libusb-win32-device-bin-0.1.12.1/include libusb-win32-device-bin-0.1.12.1/lib/dynamic/libusb_dyn.c
|
||||
|
||||
NATIVECC = gcc
|
||||
CC = $(CROSS)gcc
|
||||
WINDRES = $(CROSS)windres
|
||||
|
||||
all: $(OUTPUT)
|
||||
|
||||
e200rpatcher: e200rpatcher.c bootimg.c
|
||||
gcc $(CFLAGS) $(LIBS) -o e200rpatcher e200rpatcher.c bootimg.c
|
||||
strip e200rpatcher
|
||||
|
||||
e200rpatcher.exe: e200rpatcher.c bootimg.c e200rpatcher-rc.o
|
||||
$(CC) $(CFLAGS) $(WINLIBS) -o e200rpatcher.exe e200rpatcher.c bootimg.c e200rpatcher-rc.o
|
||||
$(CROSS)strip e200rpatcher.exe
|
||||
|
||||
e200rpatcher-rc.o: e200rpatcher.rc e200rpatcher.manifest
|
||||
$(WINDRES) -i e200rpatcher.rc -o e200rpatcher-rc.o
|
||||
|
||||
e200rpatcher-mac: e200rpatcher-i386 e200rpatcher-ppc
|
||||
lipo -create e200rpatcher-ppc e200rpatcher-i386 -output e200rpatcher-mac
|
||||
|
||||
e200rpatcher.dmg: e200rpatcher-mac
|
||||
mkdir -p e200rpatcher-dmg
|
||||
cp -p e200rpatcher-mac e200rpatcher-dmg
|
||||
hdiutil create -srcfolder e200rpatcher-dmg e200rpatcher.dmg
|
||||
|
||||
e200rpatcher-i386: e200rpatcher.c bootimg.c usb.h libusb-i386.a
|
||||
gcc -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 -framework iokit -framework coreservices -arch i386 $(CFLAGS) -o e200rpatcher-i386 e200rpatcher.c bootimg.c -I. libusb-i386.a
|
||||
strip e200rpatcher-i386
|
||||
|
||||
e200rpatcher-ppc: e200rpatcher.c bootimg.c usb.h libusb-ppc.a
|
||||
gcc -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 -framework iokit -framework coreservices -arch ppc $(CFLAGS) -o e200rpatcher-ppc e200rpatcher.c bootimg.c -I. libusb-ppc.a
|
||||
strip e200rpatcher-ppc
|
||||
|
||||
bin2c: ../tools/bin2c.c
|
||||
$(NATIVECC) $(CFLAGS) -o bin2c ../tools/bin2c.c
|
||||
|
||||
bootimg.c: bootloader.bin bin2c
|
||||
./bin2c bootloader.bin bootimg
|
||||
|
||||
clean:
|
||||
rm -f e200rpatcher.exe e200rpatcher-mac e200rpatcher-i386 e200rpatcher-ppc e200rpatcher bin2c bootimg.c bootimg.h *~ e200rpatcher.dmg
|
||||
rm -rf e200rpatcher-dmg
|
||||
48
utils/e200rpatcher/README
Normal file
48
utils/e200rpatcher/README
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
INTRODUCTION
|
||||
|
||||
e200rpatcher is a tool for uploading and executing an application to
|
||||
an E200R in manufacturing mode. It is intended to be used to upload
|
||||
the patching application to allow Rockbox installs.
|
||||
|
||||
e200rpatcher requires libusb (v0.1.2 has been tested successfully) for
|
||||
cross-platform USB access. No-one has yet successfully installed
|
||||
e200rpatcher on Windows, but it works on Linux and Mac OS X (and
|
||||
should be fine on other Unix-like systems that libusb supports).
|
||||
|
||||
GENERAL BUILD INSTRUCTIONS
|
||||
|
||||
A pre-requisite for compiling e200rpatcher is a file called
|
||||
"bootloader.bin" - this is the output of running an "I" (installer)
|
||||
build for the E200R target.
|
||||
|
||||
In the Rockbox source directory, do:
|
||||
|
||||
mkdir build-e200rbootbin
|
||||
cd build-e200rbootbin
|
||||
../tools/configure
|
||||
[Select E200R, then I for installer]
|
||||
make
|
||||
|
||||
This should give you a bootloader/bootloader/bin file which you should
|
||||
copy to the e200rpatcher source directory.
|
||||
|
||||
BUILDING ON LINUX
|
||||
|
||||
The Makefile expects libusb (and the headers) to be installed on your
|
||||
system and will link dynamically. Just type "make".
|
||||
|
||||
BUILDING ON A MAC
|
||||
|
||||
To build the mac version (target e200rpatcher-mac in the Makefile)
|
||||
requires three files from libusb to be copied to the current
|
||||
directory:
|
||||
|
||||
usb.h (copied from your libusb build directory)
|
||||
libusb-i386.a (copied and renamed from .libs/libusb.a in an i386 build)
|
||||
libusb-ppc.a (copied and renamed from .libs/libusb.a in a PPC build)
|
||||
|
||||
To build the required libusb.a files, just run ./configure && make for
|
||||
libusb. If anyone knows how to cross-compile a static libusb.a please
|
||||
make the information known - this is currently done by compiling
|
||||
natively on the appropriate hardware.
|
||||
|
||||
241
utils/e200rpatcher/e200rpatcher.c
Normal file
241
utils/e200rpatcher/e200rpatcher.c
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2007 Dave Chapman
|
||||
*
|
||||
* USB code based on ifp-line - http://ifp-driver.sourceforge.net
|
||||
*
|
||||
* ifp-line is (C) Pavel Kriz, Jun Yamishiro and Joe Roback and
|
||||
* licensed under the GPL (v2)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <usb.h>
|
||||
#include <string.h>
|
||||
#include "stdbool.h"
|
||||
|
||||
#include "bootimg.h"
|
||||
|
||||
#define VERSION "0.2"
|
||||
|
||||
/* USB IDs for Manufacturing Mode */
|
||||
#define E200R_VENDORID 0x0781
|
||||
#define E200R_PRODUCTID 0x0720
|
||||
|
||||
#define E200R_BULK_TO 1
|
||||
#define TOUT 5000
|
||||
#define MAX_TRANSFER 64 /* Number of bytes to send in one write */
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
#endif
|
||||
|
||||
static void put_int32le(uint32_t x, char* p)
|
||||
{
|
||||
p[0] = x & 0xff;
|
||||
p[1] = (x >> 8) & 0xff;
|
||||
p[2] = (x >> 16) & 0xff;
|
||||
p[3] = (x >> 24) & 0xff;
|
||||
}
|
||||
|
||||
int upload_app(usb_dev_handle* dh)
|
||||
{
|
||||
char buf[4];
|
||||
int err;
|
||||
int tosend;
|
||||
char* p = (char*)bootimg;
|
||||
int bytesleft = LEN_bootimg;
|
||||
|
||||
/* Write the data length */
|
||||
|
||||
put_int32le(LEN_bootimg, buf);
|
||||
|
||||
err = usb_bulk_write(dh, E200R_BULK_TO, buf, 4, TOUT);
|
||||
|
||||
if (err < 0)
|
||||
{
|
||||
fprintf(stderr,"[ERR] Error writing data length\n");
|
||||
fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now send the data, MAX_TRANSFER bytes at a time. */
|
||||
|
||||
while (bytesleft > 0)
|
||||
{
|
||||
tosend = MAX(MAX_TRANSFER, bytesleft);
|
||||
|
||||
err = usb_bulk_write(dh, E200R_BULK_TO, p, tosend, TOUT);
|
||||
|
||||
if (err < 0)
|
||||
{
|
||||
fprintf(stderr,"[ERR] Error writing data\n");
|
||||
fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
p += tosend;
|
||||
bytesleft -= tosend;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* The main function */
|
||||
|
||||
void do_patching(void)
|
||||
{
|
||||
struct usb_bus *busses;
|
||||
struct usb_bus *bus;
|
||||
struct usb_device *tmp_dev;
|
||||
struct usb_device *dev = NULL;
|
||||
usb_dev_handle *dh;
|
||||
int err;
|
||||
|
||||
fprintf(stderr,"[INFO] Searching for E200R\n");
|
||||
|
||||
usb_init();
|
||||
|
||||
if(usb_find_busses() < 0) {
|
||||
fprintf(stderr, "[ERR] Could not find any USB busses.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (usb_find_devices() < 0) {
|
||||
fprintf(stderr, "[ERR] USB devices not found(nor hubs!).\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* C calling convention, it's not nice to use global stuff */
|
||||
busses = usb_get_busses();
|
||||
|
||||
for (bus = busses; bus; bus = bus->next) {
|
||||
for (tmp_dev = bus->devices; tmp_dev; tmp_dev = tmp_dev->next) {
|
||||
if (tmp_dev->descriptor.idVendor == E200R_VENDORID &&
|
||||
tmp_dev->descriptor.idProduct == E200R_PRODUCTID ) {
|
||||
|
||||
dev = tmp_dev;
|
||||
goto found;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dev == NULL) {
|
||||
fprintf(stderr, "[ERR] E200R device not found.\n");
|
||||
fprintf(stderr, "[ERR] Ensure your E200R is in manufacturing mode and run e200rpatcher again.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
found:
|
||||
if ( (dh = usb_open(dev)) == NULL) {
|
||||
fprintf(stderr,"[ERR] Unable to open E200R device.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
err = usb_set_configuration(dh, 1);
|
||||
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "[ERR] usb_set_configuration failed (%d)\n", err);
|
||||
usb_close(dh);
|
||||
return;
|
||||
}
|
||||
|
||||
/* "must be called" written in the libusb documentation */
|
||||
err = usb_claim_interface(dh, dev->config->interface->altsetting->bInterfaceNumber);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "[ERR] Unable to claim interface (%d)\n", err);
|
||||
usb_close(dh);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr,"[INFO] Found E200R, uploading patching application.\n");
|
||||
|
||||
/* Now we can transfer the application to the device. */
|
||||
|
||||
if (upload_app(dh) < 0)
|
||||
{
|
||||
fprintf(stderr,"[ERR] Upload of application failed.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"[INFO] Patching application uploaded successfully!\n");
|
||||
}
|
||||
|
||||
/* release claimed interface */
|
||||
usb_release_interface(dh, dev->config->interface->altsetting->bInterfaceNumber);
|
||||
|
||||
usb_close(dh);
|
||||
}
|
||||
void print_usage(void)
|
||||
{
|
||||
fprintf(stderr,"Usage: e200rpatcher [options]\n");
|
||||
fprintf(stderr,"Options:\n");
|
||||
fprintf(stderr," -s, --silent\t\tDont display instructions\n");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
char input[4];
|
||||
int silent = 0;
|
||||
int i;
|
||||
|
||||
/* check args */
|
||||
if ((argc > 1) && ((strcmp(argv[1],"-h")==0) || (strcmp(argv[1],"--help")==0))) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
for (i=1;i<argc;i++)
|
||||
{
|
||||
if (!strcmp(argv[i], "--silent") || !strcmp(argv[i], "-s"))
|
||||
silent = 1;
|
||||
}
|
||||
|
||||
printf("e200rpatcher v" VERSION " - (C) 2007 Jonathan Gordon & Dave Chapman\n");
|
||||
printf("This is free software; see the source for copying conditions. There is NO\n");
|
||||
printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
|
||||
|
||||
if (!silent)
|
||||
{
|
||||
printf("Attach your E200R in \"manufacturing mode\" as follows:\n");
|
||||
printf(" 1) Power-off your E200R\n");
|
||||
printf(" 2) Turn ON the lock/hold switch\n");
|
||||
printf(" 3) Press and hold the SELECT button and whilst it is held down,\n");
|
||||
printf(" attach your E200R to your computer via USB\n");
|
||||
printf(" 4) After attaching to USB, keep the SELECT button held for 10 seconds.\n");
|
||||
printf("\n");
|
||||
printf("NOTE: If your E200R starts in the normal Sansa firmware, you have\n");
|
||||
printf(" failed to enter manufacturing mode and should try again at step 1).\n\n");
|
||||
|
||||
printf("[INFO] Press Enter to continue:");
|
||||
fgets(input, 4, stdin);
|
||||
}
|
||||
do_patching();
|
||||
|
||||
if (!silent)
|
||||
{
|
||||
printf("[INFO] Press ENTER to exit: ");
|
||||
fgets(input, 4, stdin);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
13
utils/e200rpatcher/e200rpatcher.manifest
Normal file
13
utils/e200rpatcher/e200rpatcher.manifest
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="e200rpatcher.exe" type="win32"/>
|
||||
|
||||
<!-- Identify the application security requirements. -->
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="requireAdministrator"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
</assembly>
|
||||
1
utils/e200rpatcher/e200rpatcher.rc
Normal file
1
utils/e200rpatcher/e200rpatcher.rc
Normal file
|
|
@ -0,0 +1 @@
|
|||
1 24 MOVEABLE PURE "e200rpatcher.manifest"
|
||||
14
utils/ibassoboot/jni/Android.mk
Normal file
14
utils/ibassoboot/jni/Android.mk
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := MangoPlayer
|
||||
LOCAL_SRC_FILES := ibassodualboot.c qdbmp.c
|
||||
|
||||
TARGET_ARCH=arm
|
||||
TARGET_PLATFORM=android-14
|
||||
TARGET_ARCH_ABI=armeabi
|
||||
|
||||
#LOCAL_CFLAGS := -DDEBUG
|
||||
#LOCAL_LDLIBS := -llog
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
BIN
utils/ibassoboot/jni/chooser.bmp
Normal file
BIN
utils/ibassoboot/jni/chooser.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 225 KiB |
771
utils/ibassoboot/jni/ibassodualboot.c
Normal file
771
utils/ibassoboot/jni/ibassodualboot.c
Normal file
|
|
@ -0,0 +1,771 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
*
|
||||
* Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
|
||||
* Copyright (C) 2014 by Mario Basister: iBasso DX90 port
|
||||
* Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
|
||||
* Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/input.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "qdbmp.h"
|
||||
|
||||
|
||||
/*- Android logcat ------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <android/log.h>
|
||||
|
||||
|
||||
static const char log_tag[] = "Rockbox Boot";
|
||||
|
||||
|
||||
void debugf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
__android_log_vprint(ANDROID_LOG_DEBUG, log_tag, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
void ldebugf(const char* file, int line, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
/* 13: 5 literal chars and 8 chars for the line number. */
|
||||
char buf[strlen(file) + strlen(fmt) + 13];
|
||||
snprintf(buf, sizeof(buf), "%s (%d): %s", file, line, fmt);
|
||||
va_start(ap, fmt);
|
||||
__android_log_vprint(ANDROID_LOG_DEBUG, log_tag, buf, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
void debug_trace(const char* function)
|
||||
{
|
||||
static const char trace_tag[] = "TRACE: ";
|
||||
char msg[strlen(trace_tag) + strlen(function) + 1];
|
||||
snprintf(msg, sizeof(msg), "%s%s", trace_tag, function);
|
||||
__android_log_write(ANDROID_LOG_DEBUG, log_tag, msg);
|
||||
}
|
||||
|
||||
|
||||
#define DEBUGF debugf
|
||||
#define TRACE debug_trace(__func__)
|
||||
#else
|
||||
#define DEBUGF(...)
|
||||
#define TRACE
|
||||
#endif /* DEBUG */
|
||||
|
||||
|
||||
/*- Vold monitor --------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*
|
||||
Without this socket iBasso Vold will not start.
|
||||
iBasso Vold uses this to send status messages about storage devices.
|
||||
*/
|
||||
static const char VOLD_MONITOR_SOCKET_NAME[] = "UNIX_domain";
|
||||
static int _vold_monitor_socket_fd = -1;
|
||||
|
||||
|
||||
static void vold_monitor_open_socket(void)
|
||||
{
|
||||
TRACE;
|
||||
|
||||
unlink(VOLD_MONITOR_SOCKET_NAME);
|
||||
|
||||
_vold_monitor_socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if(_vold_monitor_socket_fd < 0)
|
||||
{
|
||||
_vold_monitor_socket_fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_un addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, VOLD_MONITOR_SOCKET_NAME, sizeof(addr.sun_path) - 1);
|
||||
|
||||
if(bind(_vold_monitor_socket_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
|
||||
{
|
||||
close(_vold_monitor_socket_fd);
|
||||
unlink(VOLD_MONITOR_SOCKET_NAME);
|
||||
_vold_monitor_socket_fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if(listen(_vold_monitor_socket_fd, 1) < 0)
|
||||
{
|
||||
close(_vold_monitor_socket_fd);
|
||||
unlink(VOLD_MONITOR_SOCKET_NAME);
|
||||
_vold_monitor_socket_fd = -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
bionic does not have pthread_cancel.
|
||||
0: Vold monitor thread stopped/ending.
|
||||
1: Vold monitor thread started/running.
|
||||
*/
|
||||
static volatile sig_atomic_t _vold_monitor_active = 0;
|
||||
|
||||
|
||||
/* true: sdcard not mounted. */
|
||||
static bool _sdcard_not_mounted = true;
|
||||
|
||||
|
||||
/* Mutex for sdcard mounted flag. */
|
||||
static pthread_mutex_t _sdcard_mount_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
|
||||
/* Signal condition for sdcard mounted flag. */
|
||||
static pthread_cond_t _sdcard_mount_cond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
|
||||
static void* vold_monitor_run(void* nothing)
|
||||
{
|
||||
_vold_monitor_active = 1;
|
||||
|
||||
(void) nothing;
|
||||
|
||||
DEBUGF("DEBUG %s: Thread start.", __func__);
|
||||
|
||||
vold_monitor_open_socket();
|
||||
if(_vold_monitor_socket_fd < 0)
|
||||
{
|
||||
DEBUGF("ERROR %s: Thread end: No socket.", __func__);
|
||||
|
||||
_vold_monitor_active = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct pollfd fds[1];
|
||||
fds[0].fd = _vold_monitor_socket_fd;
|
||||
fds[0].events = POLLIN;
|
||||
|
||||
while(_vold_monitor_active == 1)
|
||||
{
|
||||
poll(fds, 1, 10);
|
||||
if(! (fds[0].revents & POLLIN))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int socket_fd = accept(_vold_monitor_socket_fd, NULL, NULL);
|
||||
|
||||
if(socket_fd < 0)
|
||||
{
|
||||
DEBUGF("ERROR %s: accept failed.", __func__);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
while(true)
|
||||
{
|
||||
char msg[1024];
|
||||
memset(msg, 0, sizeof(msg));
|
||||
int length = read(socket_fd, msg, sizeof(msg));
|
||||
|
||||
if(length <= 0)
|
||||
{
|
||||
close(socket_fd);
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUGF("DEBUG %s: msg: %s", __func__, msg);
|
||||
|
||||
if(strcmp(msg, "Volume flash /mnt/sdcard state changed from 3 (Checking) to 4 (Mounted)") == 0)
|
||||
{
|
||||
pthread_mutex_lock(&_sdcard_mount_mtx);
|
||||
_sdcard_not_mounted = false;
|
||||
pthread_cond_signal(&_sdcard_mount_cond);
|
||||
pthread_mutex_unlock(&_sdcard_mount_mtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(_vold_monitor_socket_fd);
|
||||
unlink(VOLD_MONITOR_SOCKET_NAME);
|
||||
_vold_monitor_socket_fd = -1;
|
||||
|
||||
DEBUGF("DEBUG %s: Thread end.", __func__);
|
||||
|
||||
_vold_monitor_active = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Vold monitor thread. */
|
||||
static pthread_t _vold_monitor_thread;
|
||||
|
||||
|
||||
static void vold_monitor_start(void)
|
||||
{
|
||||
TRACE;
|
||||
|
||||
if(_vold_monitor_active == 0)
|
||||
{
|
||||
pthread_create(&_vold_monitor_thread, NULL, vold_monitor_run, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void vold_monitor_stop(void)
|
||||
{
|
||||
TRACE;
|
||||
|
||||
if(_vold_monitor_active == 1)
|
||||
{
|
||||
_vold_monitor_active = 0;
|
||||
int ret = pthread_join(_vold_monitor_thread, NULL);
|
||||
DEBUGF("DEBUG %s: Thread joined: ret: %d.", __func__, ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*- Input handler -------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/* Input devices monitored with poll API. */
|
||||
static struct pollfd* _fds = NULL;
|
||||
|
||||
|
||||
/* Number of input devices monitored with poll API. */
|
||||
static nfds_t _nfds = 0;
|
||||
|
||||
|
||||
/* The names of the devices in _fds. */
|
||||
static char** _device_names = NULL;
|
||||
|
||||
|
||||
/* Open device device_name and add it to the list of polled devices. */
|
||||
static void open_device(const char* device_name)
|
||||
{
|
||||
int fd = open(device_name, O_RDONLY);
|
||||
if(fd == -1)
|
||||
{
|
||||
DEBUGF("ERROR %s: open failed on %s.", __func__, device_name);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
struct pollfd* new_fds = realloc(_fds, sizeof(struct pollfd) * (_nfds + 1));
|
||||
if(new_fds == NULL)
|
||||
{
|
||||
DEBUGF("ERROR %s: realloc for _fds failed.", __func__);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
_fds = new_fds;
|
||||
_fds[_nfds].fd = fd;
|
||||
_fds[_nfds].events = POLLIN;
|
||||
|
||||
char** new_device_names = realloc(_device_names, sizeof(char*) * (_nfds + 1));
|
||||
if(new_device_names == NULL)
|
||||
{
|
||||
DEBUGF("ERROR %s: realloc for _device_names failed.", __func__);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
_device_names = new_device_names;
|
||||
_device_names[_nfds] = strdup(device_name);
|
||||
if(_device_names[_nfds] == NULL)
|
||||
{
|
||||
DEBUGF("ERROR %s: strdup failed.", __func__);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
++_nfds;
|
||||
|
||||
DEBUGF("DEBUG %s: Opened device %s.", __func__, device_name);
|
||||
}
|
||||
|
||||
|
||||
static void button_init_device(void)
|
||||
{
|
||||
TRACE;
|
||||
|
||||
if((_fds != NULL) || (_nfds != 0) || (_device_names != NULL))
|
||||
{
|
||||
DEBUGF("ERROR %s: Allready initialized.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The input device directory. */
|
||||
static const char device_path[] = "/dev/input";
|
||||
|
||||
/* Path delimeter. */
|
||||
static const char delimeter[] = "/";
|
||||
|
||||
/* Open all devices in device_path. */
|
||||
DIR* dir = opendir(device_path);
|
||||
if(dir == NULL)
|
||||
{
|
||||
DEBUGF("ERROR %s: opendir failed: errno: %d.", __func__, errno);
|
||||
exit(errno);
|
||||
}
|
||||
|
||||
char device_name[PATH_MAX];
|
||||
strcpy(device_name, device_path);
|
||||
strcat(device_name, delimeter);
|
||||
char* device_name_idx = device_name + strlen(device_name);
|
||||
|
||||
struct dirent* dir_entry;
|
||||
while((dir_entry = readdir(dir)))
|
||||
{
|
||||
if( ((dir_entry->d_name[0] == '.') && (dir_entry->d_name[1] == '\0'))
|
||||
|| ((dir_entry->d_name[0] == '.') && (dir_entry->d_name[1] == '.') && (dir_entry->d_name[2] == '\0')))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
strcpy(device_name_idx, dir_entry->d_name);
|
||||
|
||||
/* Open and add device to _fds. */
|
||||
open_device(device_name);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
/* Sanity check. */
|
||||
if(_nfds < 2)
|
||||
{
|
||||
DEBUGF("ERROR %s: No input devices.", __func__);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define EVENT_TYPE_BUTTON 1
|
||||
|
||||
|
||||
#define EVENT_CODE_BUTTON_PWR_LONG 117
|
||||
#define EVENT_CODE_BUTTON_REV 160
|
||||
#define EVENT_CODE_BUTTON_NEXT 162
|
||||
|
||||
|
||||
#define EVENT_TYPE_TOUCHSCREEN 3
|
||||
|
||||
|
||||
#define EVENT_CODE_TOUCHSCREEN_X 53
|
||||
|
||||
|
||||
enum user_choice
|
||||
{
|
||||
CHOICE_NONE = -1,
|
||||
CHOICE_MANGO,
|
||||
CHOICE_ROCKBOX,
|
||||
CHOICE_POWEROFF
|
||||
};
|
||||
|
||||
|
||||
static int get_user_choice(void)
|
||||
{
|
||||
TRACE;
|
||||
|
||||
button_init_device();
|
||||
|
||||
enum user_choice choice = CHOICE_NONE;
|
||||
|
||||
while(choice == CHOICE_NONE)
|
||||
{
|
||||
/* Poll all input devices. */
|
||||
poll(_fds, _nfds, 0);
|
||||
|
||||
nfds_t fds_idx = 0;
|
||||
for( ; fds_idx < _nfds; ++fds_idx)
|
||||
{
|
||||
if(! (_fds[fds_idx].revents & POLLIN))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
struct input_event event;
|
||||
if(read(_fds[fds_idx].fd, &event, sizeof(event)) < (int) sizeof(event))
|
||||
{
|
||||
DEBUGF("ERROR %s: Read of input devices failed.", __func__);
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUGF("DEBUG %s: device: %s, event.type: %d, event.code: %d, event.value: %d", __func__, _device_names[fds_idx], event.type, event.code, event.value);
|
||||
|
||||
if(event.type == EVENT_TYPE_BUTTON)
|
||||
{
|
||||
switch(event.code)
|
||||
{
|
||||
case EVENT_CODE_BUTTON_REV:
|
||||
{
|
||||
choice = CHOICE_MANGO;
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_CODE_BUTTON_NEXT:
|
||||
{
|
||||
choice = CHOICE_ROCKBOX;
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_CODE_BUTTON_PWR_LONG:
|
||||
{
|
||||
choice = CHOICE_POWEROFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if((event.type == EVENT_TYPE_TOUCHSCREEN) && (event.code == EVENT_CODE_TOUCHSCREEN_X))
|
||||
{
|
||||
if(event.value < 160)
|
||||
{
|
||||
choice = CHOICE_MANGO;
|
||||
}
|
||||
else
|
||||
{
|
||||
choice = CHOICE_ROCKBOX;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(_fds)
|
||||
{
|
||||
nfds_t fds_idx = 0;
|
||||
for( ; fds_idx < _nfds; ++fds_idx)
|
||||
{
|
||||
close(_fds[fds_idx].fd);
|
||||
}
|
||||
free(_fds);
|
||||
_fds = NULL;
|
||||
}
|
||||
|
||||
if(_device_names)
|
||||
{
|
||||
nfds_t fds_idx = 0;
|
||||
for( ; fds_idx < _nfds; ++fds_idx)
|
||||
{
|
||||
free(_device_names[fds_idx]);
|
||||
}
|
||||
free(_device_names);
|
||||
_device_names = NULL;
|
||||
}
|
||||
|
||||
_nfds = 0;
|
||||
|
||||
return choice;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Changing bit, when hold switch is toggled.
|
||||
Bit is off when hold switch is engaged.
|
||||
*/
|
||||
#define HOLD_SWITCH_BIT 16
|
||||
|
||||
|
||||
static bool check_for_hold(void)
|
||||
{
|
||||
TRACE;
|
||||
|
||||
char hold_state;
|
||||
|
||||
FILE* f = fopen("/sys/class/axppower/holdkey", "r");
|
||||
fscanf(f, "%c", &hold_state);
|
||||
fclose(f);
|
||||
|
||||
return(! (hold_state & HOLD_SWITCH_BIT));
|
||||
}
|
||||
|
||||
|
||||
/*- Display -------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
static void draw(const char* file)
|
||||
{
|
||||
DEBUGF("DEBUG %s: file: %s.", __func__, file);
|
||||
|
||||
int dev_fd = open("/dev/graphics/fb0", O_RDWR);
|
||||
if(dev_fd == -1)
|
||||
{
|
||||
DEBUGF("ERROR %s: open failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
|
||||
exit(errno);
|
||||
}
|
||||
|
||||
/* Get fixed screen information. */
|
||||
struct fb_fix_screeninfo finfo;
|
||||
if(ioctl(dev_fd, FBIOGET_FSCREENINFO, &finfo) < 0)
|
||||
{
|
||||
DEBUGF("ERROR %s: ioctl FBIOGET_FSCREENINFO failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
|
||||
exit(errno);
|
||||
}
|
||||
|
||||
/* Get the changeable information. */
|
||||
struct fb_var_screeninfo vinfo;
|
||||
if(ioctl(dev_fd, FBIOGET_VSCREENINFO, &vinfo) < 0)
|
||||
{
|
||||
DEBUGF("ERROR %s: ioctl FBIOGET_VSCREENINFO failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
|
||||
exit(errno);
|
||||
}
|
||||
|
||||
DEBUGF("DEBUG %s: bits_per_pixel: %u, width: %u, height: %u.", __func__, vinfo.bits_per_pixel, vinfo.width, vinfo.height);
|
||||
|
||||
size_t screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
|
||||
|
||||
/* ToDo: Is this needed? */
|
||||
vinfo.xres = 320;
|
||||
vinfo.xres_virtual = 320;
|
||||
vinfo.width = 320;
|
||||
vinfo.yres = 240;
|
||||
vinfo.yres_virtual = 240;
|
||||
vinfo.height = 240;
|
||||
vinfo.xoffset = 0;
|
||||
vinfo.yoffset = 0;
|
||||
vinfo.sync = 0;
|
||||
vinfo.vmode = 0;
|
||||
vinfo.pixclock = 104377;
|
||||
vinfo.left_margin = 20;
|
||||
vinfo.right_margin = 50;
|
||||
vinfo.upper_margin = 2;
|
||||
vinfo.lower_margin = 4;
|
||||
vinfo.hsync_len = 10;
|
||||
vinfo.vsync_len = 2;
|
||||
vinfo.red.offset = 11;
|
||||
vinfo.red.length = 5;
|
||||
vinfo.red.msb_right = 0;
|
||||
vinfo.green.offset = 5;
|
||||
vinfo.green.length = 6;
|
||||
vinfo.green.msb_right = 0;
|
||||
vinfo.blue.offset = 0;
|
||||
vinfo.blue.length = 5;
|
||||
vinfo.blue.msb_right = 0;
|
||||
vinfo.transp.offset = 0;
|
||||
vinfo.transp.length = 0;
|
||||
vinfo.transp.msb_right = 0;
|
||||
vinfo.nonstd = 4;
|
||||
if(ioctl(dev_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0)
|
||||
{
|
||||
DEBUGF("ERROR %s: ioctl FBIOPUT_VSCREENINFO failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
|
||||
exit(errno);
|
||||
}
|
||||
|
||||
/* Map the device to memory. */
|
||||
char* dev_fb = (char*) mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, 0);
|
||||
if(dev_fb == MAP_FAILED)
|
||||
{
|
||||
DEBUGF("ERROR %s: mmap failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
|
||||
exit(errno);
|
||||
}
|
||||
|
||||
BMP* bmp = BMP_ReadFile(file);
|
||||
if(BMP_GetError() != BMP_OK )
|
||||
{
|
||||
DEBUGF("ERROR %s: BMP_ReadFile failed on %s: %d.", __func__, file, BMP_GetError());
|
||||
exit(BMP_GetError());
|
||||
}
|
||||
|
||||
int y = 0;
|
||||
for( ; y < 240; ++y)
|
||||
{
|
||||
int x = 0;
|
||||
for( ; x < 320; ++x)
|
||||
{
|
||||
long int position = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8 )
|
||||
+ (y + vinfo.yoffset) * finfo.line_length;
|
||||
UCHAR r, g, b;
|
||||
BMP_GetPixelRGB(bmp, x, y, &r, &g, &b);
|
||||
unsigned short int pixel = (r >> 3) << 11 | (g >> 2) << 5 | (b >> 3);
|
||||
*((unsigned short int*)(dev_fb + position)) = pixel;
|
||||
}
|
||||
}
|
||||
|
||||
BMP_Free(bmp);
|
||||
munmap(dev_fb, screensize);
|
||||
close(dev_fd);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
static const char ROCKBOX_BIN[] = "/mnt/sdcard/.rockbox/rockbox";
|
||||
static const char OF_PLAYER_BIN[] = "/system/bin/MangoPlayer_original";
|
||||
static const char PLAYER_FILE[] = "/data/chosen_player";
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
TRACE;
|
||||
|
||||
/*
|
||||
Create the iBasso Vold socket and monitor it.
|
||||
Do this early to not block Vold.
|
||||
*/
|
||||
vold_monitor_start();
|
||||
|
||||
int last_chosen_player = CHOICE_NONE;
|
||||
|
||||
FILE* f = fopen(PLAYER_FILE, "r");
|
||||
if(f != NULL)
|
||||
{
|
||||
fscanf(f, "%d", &last_chosen_player);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
DEBUGF("DEBUG %s: Current player choice: %d.", __func__, last_chosen_player);
|
||||
|
||||
if(check_for_hold() || (last_chosen_player == CHOICE_NONE))
|
||||
{
|
||||
draw("/system/chooser.bmp");
|
||||
|
||||
enum user_choice choice = get_user_choice();
|
||||
|
||||
if(choice == CHOICE_POWEROFF)
|
||||
{
|
||||
reboot(RB_POWER_OFF);
|
||||
while(true)
|
||||
{
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
if(choice != last_chosen_player)
|
||||
{
|
||||
last_chosen_player = choice;
|
||||
|
||||
f = fopen(PLAYER_FILE, "w");
|
||||
fprintf(f, "%d", last_chosen_player);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
DEBUGF("DEBUG %s: New player choice: %d.", __func__, last_chosen_player);
|
||||
}
|
||||
|
||||
/* true, Rockbox was started at least once. */
|
||||
bool rockboxStarted = false;
|
||||
|
||||
while(true)
|
||||
{
|
||||
/* Excecute OF MangoPlayer or Rockbox and restart it if it crashes. */
|
||||
|
||||
if(last_chosen_player == CHOICE_ROCKBOX)
|
||||
{
|
||||
if(rockboxStarted)
|
||||
{
|
||||
/*
|
||||
At this point it is assumed, that Rockbox has exited due to a USB connection
|
||||
triggering a remount of the internal storage for mass storage access.
|
||||
Rockbox will eventually restart, when /mnt/sdcard becomes available again.
|
||||
*/
|
||||
draw("/system/usb.bmp");
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&_sdcard_mount_mtx);
|
||||
while(_sdcard_not_mounted)
|
||||
{
|
||||
DEBUGF("DEBUG %s: Waiting on /mnt/sdcard/.", __func__);
|
||||
|
||||
pthread_cond_wait(&_sdcard_mount_cond, &_sdcard_mount_mtx);
|
||||
|
||||
DEBUGF("DEBUG %s: /mnt/sdcard/ available.", __func__);
|
||||
}
|
||||
pthread_mutex_unlock(&_sdcard_mount_mtx);
|
||||
|
||||
/* To be able to execute rockbox. */
|
||||
system("mount -o remount,exec /mnt/sdcard");
|
||||
|
||||
/* This symlink is needed mainly to keep themes functional. */
|
||||
system("ln -s /mnt/sdcard/.rockbox /.rockbox");
|
||||
|
||||
if(access(ROCKBOX_BIN, X_OK) != -1)
|
||||
{
|
||||
/* Start Rockbox. */
|
||||
|
||||
/* Rockbox has its own vold monitor. */
|
||||
vold_monitor_stop();
|
||||
|
||||
DEBUGF("DEBUG %s: Excecuting %s.", __func__, ROCKBOX_BIN);
|
||||
|
||||
int ret_code = system(ROCKBOX_BIN);
|
||||
rockboxStarted = true;
|
||||
|
||||
DEBUGF("DEBUG %s: ret_code: %d.", __func__, ret_code);
|
||||
|
||||
if(WIFEXITED(ret_code) && (WEXITSTATUS(ret_code) == 42))
|
||||
{
|
||||
/*
|
||||
Rockbox terminated to prevent a froced shutdown due to a USB connection
|
||||
triggering a remount of the internal storage for mass storage access.
|
||||
*/
|
||||
_sdcard_not_mounted = true;
|
||||
}
|
||||
/* else Rockbox crashed ... */
|
||||
|
||||
vold_monitor_start();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Rockbox executable missing. Show info screen for 30 seconds. */
|
||||
draw("/system/rbmissing.bmp");
|
||||
sleep(30);
|
||||
|
||||
/* Do not block Vold, so stop after sleep. */
|
||||
vold_monitor_stop();
|
||||
|
||||
#ifdef DEBUG
|
||||
system("setprop persist.sys.usb.config adb");
|
||||
system("setprop persist.usb.debug 1");
|
||||
#endif
|
||||
|
||||
DEBUGF("DEBUG %s: Rockbox missing, excecuting %s.", __func__, OF_PLAYER_BIN);
|
||||
|
||||
/* Start OF MangoPlayer. */
|
||||
int ret_code = system(OF_PLAYER_BIN);
|
||||
|
||||
DEBUGF("DEBUG %s: ret_code: %d.", __func__, ret_code);
|
||||
}
|
||||
}
|
||||
else /* if(last_chosen_player == CHOICE_MANGO) */
|
||||
{
|
||||
vold_monitor_stop();
|
||||
|
||||
DEBUGF("DEBUG %s: Excecuting %s.", __func__, OF_PLAYER_BIN);
|
||||
|
||||
int ret_code = system(OF_PLAYER_BIN);
|
||||
|
||||
DEBUGF("DEBUG %s: ret_code: %d.", __func__, ret_code);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
798
utils/ibassoboot/jni/qdbmp.c
Normal file
798
utils/ibassoboot/jni/qdbmp.c
Normal file
|
|
@ -0,0 +1,798 @@
|
|||
#include "qdbmp.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/* Bitmap header */
|
||||
typedef struct _BMP_Header
|
||||
{
|
||||
USHORT Magic; /* Magic identifier: "BM" */
|
||||
UINT FileSize; /* Size of the BMP file in bytes */
|
||||
USHORT Reserved1; /* Reserved */
|
||||
USHORT Reserved2; /* Reserved */
|
||||
UINT DataOffset; /* Offset of image data relative to the file's start */
|
||||
UINT HeaderSize; /* Size of the header in bytes */
|
||||
UINT Width; /* Bitmap's width */
|
||||
UINT Height; /* Bitmap's height */
|
||||
USHORT Planes; /* Number of color planes in the bitmap */
|
||||
USHORT BitsPerPixel; /* Number of bits per pixel */
|
||||
UINT CompressionType; /* Compression type */
|
||||
UINT ImageDataSize; /* Size of uncompressed image's data */
|
||||
UINT HPixelsPerMeter; /* Horizontal resolution (pixels per meter) */
|
||||
UINT VPixelsPerMeter; /* Vertical resolution (pixels per meter) */
|
||||
UINT ColorsUsed; /* Number of color indexes in the color table that are actually used by the bitmap */
|
||||
UINT ColorsRequired; /* Number of color indexes that are required for displaying the bitmap */
|
||||
} BMP_Header;
|
||||
|
||||
|
||||
/* Private data structure */
|
||||
struct _BMP
|
||||
{
|
||||
BMP_Header Header;
|
||||
UCHAR* Palette;
|
||||
UCHAR* Data;
|
||||
};
|
||||
|
||||
|
||||
/* Holds the last error code */
|
||||
static BMP_STATUS BMP_LAST_ERROR_CODE = 0;
|
||||
|
||||
|
||||
/* Error description strings */
|
||||
static const char* BMP_ERROR_STRING[] =
|
||||
{
|
||||
"",
|
||||
"General error",
|
||||
"Could not allocate enough memory to complete the operation",
|
||||
"File input/output error",
|
||||
"File not found",
|
||||
"File is not a supported BMP variant (must be uncompressed 8, 24 or 32 BPP)",
|
||||
"File is not a valid BMP image",
|
||||
"An argument is invalid or out of range",
|
||||
"The requested action is not compatible with the BMP's type"
|
||||
};
|
||||
|
||||
|
||||
/* Size of the palette data for 8 BPP bitmaps */
|
||||
#define BMP_PALETTE_SIZE ( 256 * 4 )
|
||||
|
||||
|
||||
|
||||
/*********************************** Forward declarations **********************************/
|
||||
int ReadHeader ( BMP* bmp, FILE* f );
|
||||
int WriteHeader ( BMP* bmp, FILE* f );
|
||||
|
||||
int ReadUINT ( UINT* x, FILE* f );
|
||||
int ReadUSHORT ( USHORT *x, FILE* f );
|
||||
|
||||
int WriteUINT ( UINT x, FILE* f );
|
||||
int WriteUSHORT ( USHORT x, FILE* f );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*********************************** Public methods **********************************/
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Creates a blank BMP image with the specified dimensions
|
||||
and bit depth.
|
||||
**************************************************************/
|
||||
BMP* BMP_Create( UINT width, UINT height, USHORT depth )
|
||||
{
|
||||
BMP* bmp;
|
||||
int bytes_per_pixel = depth >> 3;
|
||||
UINT bytes_per_row;
|
||||
|
||||
if ( height <= 0 || width <= 0 )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( depth != 8 && depth != 24 && depth != 32 )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Allocate the bitmap data structure */
|
||||
bmp = calloc( 1, sizeof( BMP ) );
|
||||
if ( bmp == NULL )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Set header' default values */
|
||||
bmp->Header.Magic = 0x4D42;
|
||||
bmp->Header.Reserved1 = 0;
|
||||
bmp->Header.Reserved2 = 0;
|
||||
bmp->Header.HeaderSize = 40;
|
||||
bmp->Header.Planes = 1;
|
||||
bmp->Header.CompressionType = 0;
|
||||
bmp->Header.HPixelsPerMeter = 0;
|
||||
bmp->Header.VPixelsPerMeter = 0;
|
||||
bmp->Header.ColorsUsed = 0;
|
||||
bmp->Header.ColorsRequired = 0;
|
||||
|
||||
|
||||
/* Calculate the number of bytes used to store a single image row. This is always
|
||||
rounded up to the next multiple of 4. */
|
||||
bytes_per_row = width * bytes_per_pixel;
|
||||
bytes_per_row += ( bytes_per_row % 4 ? 4 - bytes_per_row % 4 : 0 );
|
||||
|
||||
|
||||
/* Set header's image specific values */
|
||||
bmp->Header.Width = width;
|
||||
bmp->Header.Height = height;
|
||||
bmp->Header.BitsPerPixel = depth;
|
||||
bmp->Header.ImageDataSize = bytes_per_row * height;
|
||||
bmp->Header.FileSize = bmp->Header.ImageDataSize + 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 );
|
||||
bmp->Header.DataOffset = 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 );
|
||||
|
||||
|
||||
/* Allocate palette */
|
||||
if ( bmp->Header.BitsPerPixel == 8 )
|
||||
{
|
||||
bmp->Palette = (UCHAR*) calloc( BMP_PALETTE_SIZE, sizeof( UCHAR ) );
|
||||
if ( bmp->Palette == NULL )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
|
||||
free( bmp );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bmp->Palette = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Allocate pixels */
|
||||
bmp->Data = (UCHAR*) calloc( bmp->Header.ImageDataSize, sizeof( UCHAR ) );
|
||||
if ( bmp->Data == NULL )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
|
||||
free( bmp->Palette );
|
||||
free( bmp );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Frees all the memory used by the specified BMP image.
|
||||
**************************************************************/
|
||||
void BMP_Free( BMP* bmp )
|
||||
{
|
||||
if ( bmp == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( bmp->Palette != NULL )
|
||||
{
|
||||
free( bmp->Palette );
|
||||
}
|
||||
|
||||
if ( bmp->Data != NULL )
|
||||
{
|
||||
free( bmp->Data );
|
||||
}
|
||||
|
||||
free( bmp );
|
||||
|
||||
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Reads the specified BMP image file.
|
||||
**************************************************************/
|
||||
BMP* BMP_ReadFile( const char* filename )
|
||||
{
|
||||
BMP* bmp;
|
||||
FILE* f;
|
||||
|
||||
if ( filename == NULL )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Allocate */
|
||||
bmp = calloc( 1, sizeof( BMP ) );
|
||||
if ( bmp == NULL )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Open file */
|
||||
f = fopen( filename, "rb" );
|
||||
if ( f == NULL )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND;
|
||||
free( bmp );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Read header */
|
||||
if ( ReadHeader( bmp, f ) != BMP_OK || bmp->Header.Magic != 0x4D42 )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
|
||||
fclose( f );
|
||||
free( bmp );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Verify that the bitmap variant is supported */
|
||||
if ( ( bmp->Header.BitsPerPixel != 32 && bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 8 )
|
||||
|| bmp->Header.CompressionType != 0 || bmp->Header.HeaderSize != 40 )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED;
|
||||
fclose( f );
|
||||
free( bmp );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Allocate and read palette */
|
||||
if ( bmp->Header.BitsPerPixel == 8 )
|
||||
{
|
||||
bmp->Palette = (UCHAR*) malloc( BMP_PALETTE_SIZE * sizeof( UCHAR ) );
|
||||
if ( bmp->Palette == NULL )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
|
||||
fclose( f );
|
||||
free( bmp );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( fread( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
|
||||
fclose( f );
|
||||
free( bmp->Palette );
|
||||
free( bmp );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else /* Not an indexed image */
|
||||
{
|
||||
bmp->Palette = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Allocate memory for image data */
|
||||
bmp->Data = (UCHAR*) malloc( bmp->Header.ImageDataSize );
|
||||
if ( bmp->Data == NULL )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
|
||||
fclose( f );
|
||||
free( bmp->Palette );
|
||||
free( bmp );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Read image data */
|
||||
if ( fread( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
|
||||
fclose( f );
|
||||
free( bmp->Data );
|
||||
free( bmp->Palette );
|
||||
free( bmp );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
fclose( f );
|
||||
|
||||
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Writes the BMP image to the specified file.
|
||||
**************************************************************/
|
||||
void BMP_WriteFile( BMP* bmp, const char* filename )
|
||||
{
|
||||
FILE* f;
|
||||
|
||||
if ( filename == NULL )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Open file */
|
||||
f = fopen( filename, "wb" );
|
||||
if ( f == NULL )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Write header */
|
||||
if ( WriteHeader( bmp, f ) != BMP_OK )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
|
||||
fclose( f );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Write palette */
|
||||
if ( bmp->Palette )
|
||||
{
|
||||
if ( fwrite( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
|
||||
fclose( f );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Write data */
|
||||
if ( fwrite( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
|
||||
fclose( f );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||
fclose( f );
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Returns the image's width.
|
||||
**************************************************************/
|
||||
UINT BMP_GetWidth( BMP* bmp )
|
||||
{
|
||||
if ( bmp == NULL )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||
|
||||
return ( bmp->Header.Width );
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Returns the image's height.
|
||||
**************************************************************/
|
||||
UINT BMP_GetHeight( BMP* bmp )
|
||||
{
|
||||
if ( bmp == NULL )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||
|
||||
return ( bmp->Header.Height );
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Returns the image's color depth (bits per pixel).
|
||||
**************************************************************/
|
||||
USHORT BMP_GetDepth( BMP* bmp )
|
||||
{
|
||||
if ( bmp == NULL )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||
|
||||
return ( bmp->Header.BitsPerPixel );
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Populates the arguments with the specified pixel's RGB
|
||||
values.
|
||||
**************************************************************/
|
||||
void BMP_GetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b )
|
||||
{
|
||||
UCHAR* pixel;
|
||||
UINT bytes_per_row;
|
||||
UCHAR bytes_per_pixel;
|
||||
|
||||
if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||
|
||||
bytes_per_pixel = bmp->Header.BitsPerPixel >> 3;
|
||||
|
||||
/* Row's size is rounded up to the next multiple of 4 bytes */
|
||||
bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
|
||||
|
||||
/* Calculate the location of the relevant pixel (rows are flipped) */
|
||||
pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel );
|
||||
|
||||
|
||||
/* In indexed color mode the pixel's value is an index within the palette */
|
||||
if ( bmp->Header.BitsPerPixel == 8 )
|
||||
{
|
||||
pixel = bmp->Palette + *pixel * 4;
|
||||
}
|
||||
|
||||
/* Note: colors are stored in BGR order */
|
||||
if ( r ) *r = *( pixel + 2 );
|
||||
if ( g ) *g = *( pixel + 1 );
|
||||
if ( b ) *b = *( pixel + 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Sets the specified pixel's RGB values.
|
||||
**************************************************************/
|
||||
void BMP_SetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b )
|
||||
{
|
||||
UCHAR* pixel;
|
||||
UINT bytes_per_row;
|
||||
UCHAR bytes_per_pixel;
|
||||
|
||||
if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
else if ( bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 32 )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||
|
||||
bytes_per_pixel = bmp->Header.BitsPerPixel >> 3;
|
||||
|
||||
/* Row's size is rounded up to the next multiple of 4 bytes */
|
||||
bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
|
||||
|
||||
/* Calculate the location of the relevant pixel (rows are flipped) */
|
||||
pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel );
|
||||
|
||||
/* Note: colors are stored in BGR order */
|
||||
*( pixel + 2 ) = r;
|
||||
*( pixel + 1 ) = g;
|
||||
*( pixel + 0 ) = b;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Gets the specified pixel's color index.
|
||||
**************************************************************/
|
||||
void BMP_GetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR* val )
|
||||
{
|
||||
UCHAR* pixel;
|
||||
UINT bytes_per_row;
|
||||
|
||||
if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
else if ( bmp->Header.BitsPerPixel != 8 )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||
|
||||
/* Row's size is rounded up to the next multiple of 4 bytes */
|
||||
bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
|
||||
|
||||
/* Calculate the location of the relevant pixel */
|
||||
pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x );
|
||||
|
||||
|
||||
if ( val ) *val = *pixel;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Sets the specified pixel's color index.
|
||||
**************************************************************/
|
||||
void BMP_SetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR val )
|
||||
{
|
||||
UCHAR* pixel;
|
||||
UINT bytes_per_row;
|
||||
|
||||
if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
else if ( bmp->Header.BitsPerPixel != 8 )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||
|
||||
/* Row's size is rounded up to the next multiple of 4 bytes */
|
||||
bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
|
||||
|
||||
/* Calculate the location of the relevant pixel */
|
||||
pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x );
|
||||
|
||||
*pixel = val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Gets the color value for the specified palette index.
|
||||
**************************************************************/
|
||||
void BMP_GetPaletteColor( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b )
|
||||
{
|
||||
if ( bmp == NULL )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
else if ( bmp->Header.BitsPerPixel != 8 )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if ( r ) *r = *( bmp->Palette + index * 4 + 2 );
|
||||
if ( g ) *g = *( bmp->Palette + index * 4 + 1 );
|
||||
if ( b ) *b = *( bmp->Palette + index * 4 + 0 );
|
||||
|
||||
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Sets the color value for the specified palette index.
|
||||
**************************************************************/
|
||||
void BMP_SetPaletteColor( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b )
|
||||
{
|
||||
if ( bmp == NULL )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
else if ( bmp->Header.BitsPerPixel != 8 )
|
||||
{
|
||||
BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
*( bmp->Palette + index * 4 + 2 ) = r;
|
||||
*( bmp->Palette + index * 4 + 1 ) = g;
|
||||
*( bmp->Palette + index * 4 + 0 ) = b;
|
||||
|
||||
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Returns the last error code.
|
||||
**************************************************************/
|
||||
BMP_STATUS BMP_GetError()
|
||||
{
|
||||
return BMP_LAST_ERROR_CODE;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Returns a description of the last error code.
|
||||
**************************************************************/
|
||||
const char* BMP_GetErrorDescription()
|
||||
{
|
||||
if ( BMP_LAST_ERROR_CODE > 0 && BMP_LAST_ERROR_CODE < BMP_ERROR_NUM )
|
||||
{
|
||||
return BMP_ERROR_STRING[ BMP_LAST_ERROR_CODE ];
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*********************************** Private methods **********************************/
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Reads the BMP file's header into the data structure.
|
||||
Returns BMP_OK on success.
|
||||
**************************************************************/
|
||||
int ReadHeader( BMP* bmp, FILE* f )
|
||||
{
|
||||
if ( bmp == NULL || f == NULL )
|
||||
{
|
||||
return BMP_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
/* The header's fields are read one by one, and converted from the format's
|
||||
little endian to the system's native representation. */
|
||||
if ( !ReadUSHORT( &( bmp->Header.Magic ), f ) ) return BMP_IO_ERROR;
|
||||
if ( !ReadUINT( &( bmp->Header.FileSize ), f ) ) return BMP_IO_ERROR;
|
||||
if ( !ReadUSHORT( &( bmp->Header.Reserved1 ), f ) ) return BMP_IO_ERROR;
|
||||
if ( !ReadUSHORT( &( bmp->Header.Reserved2 ), f ) ) return BMP_IO_ERROR;
|
||||
if ( !ReadUINT( &( bmp->Header.DataOffset ), f ) ) return BMP_IO_ERROR;
|
||||
if ( !ReadUINT( &( bmp->Header.HeaderSize ), f ) ) return BMP_IO_ERROR;
|
||||
if ( !ReadUINT( &( bmp->Header.Width ), f ) ) return BMP_IO_ERROR;
|
||||
if ( !ReadUINT( &( bmp->Header.Height ), f ) ) return BMP_IO_ERROR;
|
||||
if ( !ReadUSHORT( &( bmp->Header.Planes ), f ) ) return BMP_IO_ERROR;
|
||||
if ( !ReadUSHORT( &( bmp->Header.BitsPerPixel ), f ) ) return BMP_IO_ERROR;
|
||||
if ( !ReadUINT( &( bmp->Header.CompressionType ), f ) ) return BMP_IO_ERROR;
|
||||
if ( !ReadUINT( &( bmp->Header.ImageDataSize ), f ) ) return BMP_IO_ERROR;
|
||||
if ( !ReadUINT( &( bmp->Header.HPixelsPerMeter ), f ) ) return BMP_IO_ERROR;
|
||||
if ( !ReadUINT( &( bmp->Header.VPixelsPerMeter ), f ) ) return BMP_IO_ERROR;
|
||||
if ( !ReadUINT( &( bmp->Header.ColorsUsed ), f ) ) return BMP_IO_ERROR;
|
||||
if ( !ReadUINT( &( bmp->Header.ColorsRequired ), f ) ) return BMP_IO_ERROR;
|
||||
|
||||
return BMP_OK;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Writes the BMP file's header into the data structure.
|
||||
Returns BMP_OK on success.
|
||||
**************************************************************/
|
||||
int WriteHeader( BMP* bmp, FILE* f )
|
||||
{
|
||||
if ( bmp == NULL || f == NULL )
|
||||
{
|
||||
return BMP_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
/* The header's fields are written one by one, and converted to the format's
|
||||
little endian representation. */
|
||||
if ( !WriteUSHORT( bmp->Header.Magic, f ) ) return BMP_IO_ERROR;
|
||||
if ( !WriteUINT( bmp->Header.FileSize, f ) ) return BMP_IO_ERROR;
|
||||
if ( !WriteUSHORT( bmp->Header.Reserved1, f ) ) return BMP_IO_ERROR;
|
||||
if ( !WriteUSHORT( bmp->Header.Reserved2, f ) ) return BMP_IO_ERROR;
|
||||
if ( !WriteUINT( bmp->Header.DataOffset, f ) ) return BMP_IO_ERROR;
|
||||
if ( !WriteUINT( bmp->Header.HeaderSize, f ) ) return BMP_IO_ERROR;
|
||||
if ( !WriteUINT( bmp->Header.Width, f ) ) return BMP_IO_ERROR;
|
||||
if ( !WriteUINT( bmp->Header.Height, f ) ) return BMP_IO_ERROR;
|
||||
if ( !WriteUSHORT( bmp->Header.Planes, f ) ) return BMP_IO_ERROR;
|
||||
if ( !WriteUSHORT( bmp->Header.BitsPerPixel, f ) ) return BMP_IO_ERROR;
|
||||
if ( !WriteUINT( bmp->Header.CompressionType, f ) ) return BMP_IO_ERROR;
|
||||
if ( !WriteUINT( bmp->Header.ImageDataSize, f ) ) return BMP_IO_ERROR;
|
||||
if ( !WriteUINT( bmp->Header.HPixelsPerMeter, f ) ) return BMP_IO_ERROR;
|
||||
if ( !WriteUINT( bmp->Header.VPixelsPerMeter, f ) ) return BMP_IO_ERROR;
|
||||
if ( !WriteUINT( bmp->Header.ColorsUsed, f ) ) return BMP_IO_ERROR;
|
||||
if ( !WriteUINT( bmp->Header.ColorsRequired, f ) ) return BMP_IO_ERROR;
|
||||
|
||||
return BMP_OK;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Reads a little-endian unsigned int from the file.
|
||||
Returns non-zero on success.
|
||||
**************************************************************/
|
||||
int ReadUINT( UINT* x, FILE* f )
|
||||
{
|
||||
UCHAR little[ 4 ]; /* BMPs use 32 bit ints */
|
||||
|
||||
if ( x == NULL || f == NULL )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( fread( little, 4, 1, f ) != 1 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
*x = ( little[ 3 ] << 24 | little[ 2 ] << 16 | little[ 1 ] << 8 | little[ 0 ] );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Reads a little-endian unsigned short int from the file.
|
||||
Returns non-zero on success.
|
||||
**************************************************************/
|
||||
int ReadUSHORT( USHORT *x, FILE* f )
|
||||
{
|
||||
UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */
|
||||
|
||||
if ( x == NULL || f == NULL )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( fread( little, 2, 1, f ) != 1 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
*x = ( little[ 1 ] << 8 | little[ 0 ] );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Writes a little-endian unsigned int to the file.
|
||||
Returns non-zero on success.
|
||||
**************************************************************/
|
||||
int WriteUINT( UINT x, FILE* f )
|
||||
{
|
||||
UCHAR little[ 4 ]; /* BMPs use 32 bit ints */
|
||||
|
||||
little[ 3 ] = (UCHAR)( ( x & 0xff000000 ) >> 24 );
|
||||
little[ 2 ] = (UCHAR)( ( x & 0x00ff0000 ) >> 16 );
|
||||
little[ 1 ] = (UCHAR)( ( x & 0x0000ff00 ) >> 8 );
|
||||
little[ 0 ] = (UCHAR)( ( x & 0x000000ff ) >> 0 );
|
||||
|
||||
return ( f && fwrite( little, 4, 1, f ) == 1 );
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Writes a little-endian unsigned short int to the file.
|
||||
Returns non-zero on success.
|
||||
**************************************************************/
|
||||
int WriteUSHORT( USHORT x, FILE* f )
|
||||
{
|
||||
UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */
|
||||
|
||||
little[ 1 ] = (UCHAR)( ( x & 0xff00 ) >> 8 );
|
||||
little[ 0 ] = (UCHAR)( ( x & 0x00ff ) >> 0 );
|
||||
|
||||
return ( f && fwrite( little, 2, 1, f ) == 1 );
|
||||
}
|
||||
|
||||
133
utils/ibassoboot/jni/qdbmp.h
Normal file
133
utils/ibassoboot/jni/qdbmp.h
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
#ifndef _BMP_H_
|
||||
#define _BMP_H_
|
||||
|
||||
|
||||
/**************************************************************
|
||||
|
||||
QDBMP - Quick n' Dirty BMP
|
||||
|
||||
v1.0.0 - 2007-04-07
|
||||
http://qdbmp.sourceforge.net
|
||||
|
||||
|
||||
The library supports the following BMP variants:
|
||||
1. Uncompressed 32 BPP (alpha values are ignored)
|
||||
2. Uncompressed 24 BPP
|
||||
3. Uncompressed 8 BPP (indexed color)
|
||||
|
||||
QDBMP is free and open source software, distributed
|
||||
under the MIT licence.
|
||||
|
||||
Copyright (c) 2007 Chai Braudo (braudo@users.sourceforge.net)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
**************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
/* Type definitions */
|
||||
#ifndef UINT
|
||||
#define UINT unsigned long int
|
||||
#endif
|
||||
|
||||
#ifndef USHORT
|
||||
#define USHORT unsigned short
|
||||
#endif
|
||||
|
||||
#ifndef UCHAR
|
||||
#define UCHAR unsigned char
|
||||
#endif
|
||||
|
||||
|
||||
/* Version */
|
||||
#define QDBMP_VERSION_MAJOR 1
|
||||
#define QDBMP_VERSION_MINOR 0
|
||||
#define QDBMP_VERSION_PATCH 1
|
||||
|
||||
|
||||
/* Error codes */
|
||||
typedef enum
|
||||
{
|
||||
BMP_OK = 0, /* No error */
|
||||
BMP_ERROR, /* General error */
|
||||
BMP_OUT_OF_MEMORY, /* Could not allocate enough memory to complete the operation */
|
||||
BMP_IO_ERROR, /* General input/output error */
|
||||
BMP_FILE_NOT_FOUND, /* File not found */
|
||||
BMP_FILE_NOT_SUPPORTED, /* File is not a supported BMP variant */
|
||||
BMP_FILE_INVALID, /* File is not a BMP image or is an invalid BMP */
|
||||
BMP_INVALID_ARGUMENT, /* An argument is invalid or out of range */
|
||||
BMP_TYPE_MISMATCH, /* The requested action is not compatible with the BMP's type */
|
||||
BMP_ERROR_NUM
|
||||
} BMP_STATUS;
|
||||
|
||||
|
||||
/* Bitmap image */
|
||||
typedef struct _BMP BMP;
|
||||
|
||||
|
||||
|
||||
|
||||
/*********************************** Public methods **********************************/
|
||||
|
||||
|
||||
/* Construction/destruction */
|
||||
BMP* BMP_Create ( UINT width, UINT height, USHORT depth );
|
||||
void BMP_Free ( BMP* bmp );
|
||||
|
||||
|
||||
/* I/O */
|
||||
BMP* BMP_ReadFile ( const char* filename );
|
||||
void BMP_WriteFile ( BMP* bmp, const char* filename );
|
||||
|
||||
|
||||
/* Meta info */
|
||||
UINT BMP_GetWidth ( BMP* bmp );
|
||||
UINT BMP_GetHeight ( BMP* bmp );
|
||||
USHORT BMP_GetDepth ( BMP* bmp );
|
||||
|
||||
|
||||
/* Pixel access */
|
||||
void BMP_GetPixelRGB ( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b );
|
||||
void BMP_SetPixelRGB ( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b );
|
||||
void BMP_GetPixelIndex ( BMP* bmp, UINT x, UINT y, UCHAR* val );
|
||||
void BMP_SetPixelIndex ( BMP* bmp, UINT x, UINT y, UCHAR val );
|
||||
|
||||
|
||||
/* Palette handling */
|
||||
void BMP_GetPaletteColor ( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b );
|
||||
void BMP_SetPaletteColor ( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b );
|
||||
|
||||
|
||||
/* Error handling */
|
||||
BMP_STATUS BMP_GetError ();
|
||||
const char* BMP_GetErrorDescription ();
|
||||
|
||||
|
||||
/* Useful macro that may be used after each BMP operation to check for an error */
|
||||
#define BMP_CHECK_ERROR( output_file, return_value ) \
|
||||
if ( BMP_GetError() != BMP_OK ) \
|
||||
{ \
|
||||
fprintf( ( output_file ), "BMP error: %s\n", BMP_GetErrorDescription() ); \
|
||||
return( return_value ); \
|
||||
} \
|
||||
|
||||
#endif
|
||||
BIN
utils/ibassoboot/jni/rbmissing.bmp
Normal file
BIN
utils/ibassoboot/jni/rbmissing.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 225 KiB |
BIN
utils/ibassoboot/jni/usb.bmp
Normal file
BIN
utils/ibassoboot/jni/usb.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 225 KiB |
53
utils/ipodpatcher/Makefile
Normal file
53
utils/ipodpatcher/Makefile
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
# $Id$
|
||||
#
|
||||
|
||||
CFLAGS += -Wall -W
|
||||
|
||||
# Build with "make BOOTOBJS=1" to build with embedded bootloaders and the
|
||||
# --install option and interactive mode. You need the full set of Rockbox
|
||||
# bootloaders in this directory - download them from
|
||||
# http://download.rockbox.org/bootloader/ipod/bootloaders.zip
|
||||
|
||||
# Releases of ipodpatcher are created with "make RELEASE=1". This
|
||||
# enables BOOTOBJS and uses the VERSION string defined in main.c
|
||||
ifdef RELEASE
|
||||
CFLAGS += -DRELEASE
|
||||
BOOTOBJS=1
|
||||
endif
|
||||
|
||||
ifdef BOOTOBJS
|
||||
BOOTSRC = ipod1g2g.c ipod3g.c ipod4g.c ipodcolor.c ipodmini1g.c \
|
||||
ipodmini2g.c ipodnano1g.c ipodvideo.c ipodnano2g.c
|
||||
CFLAGS += -DWITH_BOOTOBJS
|
||||
endif
|
||||
|
||||
# additional frameworks to link on on OS X
|
||||
LDOPTS_OSX = -framework CoreFoundation -framework IOKit
|
||||
|
||||
LIBSOURCES = ipodpatcher.c fat32format.c arc4.c \
|
||||
ipodio-posix.c ipodio-win32-scsi.c ipodio-win32.c
|
||||
SOURCES = main.c $(BOOTSRC)
|
||||
ipodpatcher: SOURCES+= ipodio-posix.c
|
||||
|
||||
OUTPUT = ipodpatcher
|
||||
include ../libtools.make
|
||||
|
||||
ipodpatcher.exe: $(OBJDIR)ipodpatcher-rc.o
|
||||
$(OBJDIR)ipodpatcher-rc.o: ipodpatcher.rc ipodpatcher.manifest
|
||||
@echo WINDRES $(notdir $<)
|
||||
$(SILENT)$(CROSS)$(WINDRES) -i $< -o $@
|
||||
|
||||
%.c: bootloader-%.ipod $(BIN2C)
|
||||
@echo BIN2C $<
|
||||
$(SILENT)$(BIN2C) -i $< $*
|
||||
|
||||
%.c: bootloader-%.ipodx $(BIN2C)
|
||||
@echo BIN2C $<
|
||||
$(SILENT)$(BIN2C) -i $< $*
|
||||
|
||||
108
utils/ipodpatcher/arc4.c
Normal file
108
utils/ipodpatcher/arc4.c
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* arc4.c
|
||||
* Release $Name: MATRIXSSL_1_8_3_OPEN $
|
||||
*
|
||||
* ARC4 stream cipher implementation
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) PeerSec Networks, 2002-2007. All Rights Reserved.
|
||||
* The latest version of this code is available at http://www.matrixssl.org
|
||||
*
|
||||
* This software is open source; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This General Public License does NOT permit incorporating this software
|
||||
* into proprietary programs. If you are unable to comply with the GPL, a
|
||||
* commercial license for this software may be purchased from PeerSec Networks
|
||||
* at http://www.peersec.com
|
||||
*
|
||||
* This program is distributed in WITHOUT ANY WARRANTY; without even the
|
||||
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
/******************************************************************************/
|
||||
|
||||
#include "arc4.h"
|
||||
|
||||
/*
|
||||
Some accounts, such as O'Reilly's Secure Programming Cookbook say that no
|
||||
more than 2^30 bytes should be processed without rekeying, so we
|
||||
enforce that limit here. FYI, this is equal to 1GB of data transferred.
|
||||
*/
|
||||
#define ARC4_MAX_BYTES 0x40000000
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
SSL_RSA_WITH_RC4_* cipher callbacks
|
||||
*/
|
||||
void matrixArc4Init(struct rc4_key_t *ctx, unsigned char *key, int32_t keylen)
|
||||
{
|
||||
unsigned char index1, index2, tmp, *state;
|
||||
int16_t counter;
|
||||
|
||||
ctx->byteCount = 0;
|
||||
state = &ctx->state[0];
|
||||
|
||||
for (counter = 0; counter < 256; counter++) {
|
||||
state[counter] = (unsigned char)counter;
|
||||
}
|
||||
ctx->x = 0;
|
||||
ctx->y = 0;
|
||||
index1 = 0;
|
||||
index2 = 0;
|
||||
|
||||
for (counter = 0; counter < 256; counter++) {
|
||||
index2 = (key[index1] + state[counter] + index2) & 0xff;
|
||||
|
||||
tmp = state[counter];
|
||||
state[counter] = state[index2];
|
||||
state[index2] = tmp;
|
||||
|
||||
index1 = (index1 + 1) % keylen;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t matrixArc4(struct rc4_key_t *ctx, unsigned char *in,
|
||||
unsigned char *out, int32_t len)
|
||||
{
|
||||
unsigned char x, y, *state, xorIndex, tmp;
|
||||
int counter; /* NOTE BY DAVE CHAPMAN: This was a short in
|
||||
the original code, which caused a segfault
|
||||
when attempting to process data > 32767
|
||||
bytes. */
|
||||
|
||||
ctx->byteCount += len;
|
||||
if (ctx->byteCount > ARC4_MAX_BYTES) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
x = ctx->x;
|
||||
y = ctx->y;
|
||||
state = &ctx->state[0];
|
||||
for (counter = 0; counter < len; counter++) {
|
||||
x = (x + 1) & 0xff;
|
||||
y = (state[x] + y) & 0xff;
|
||||
|
||||
tmp = state[x];
|
||||
state[x] = state[y];
|
||||
state[y] = tmp;
|
||||
|
||||
xorIndex = (state[x] + state[y]) & 0xff;
|
||||
|
||||
tmp = in[counter];
|
||||
tmp ^= state[xorIndex];
|
||||
out[counter] = tmp;
|
||||
}
|
||||
ctx->x = x;
|
||||
ctx->y = y;
|
||||
return len;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
47
utils/ipodpatcher/arc4.h
Normal file
47
utils/ipodpatcher/arc4.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
arc4.h - based on matrixssl-1-8-3-open
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) PeerSec Networks, 2002-2007. All Rights Reserved.
|
||||
* The latest version of this code is available at http://www.matrixssl.org
|
||||
*
|
||||
* This software is open source; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This General Public License does NOT permit incorporating this software
|
||||
* into proprietary programs. If you are unable to comply with the GPL, a
|
||||
* commercial license for this software may be purchased from PeerSec Networks
|
||||
* at http://www.peersec.com
|
||||
*
|
||||
* This program is distributed in WITHOUT ANY WARRANTY; without even the
|
||||
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef _ARC4_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct rc4_key_t
|
||||
{
|
||||
unsigned char state[256];
|
||||
uint32_t byteCount;
|
||||
unsigned char x;
|
||||
unsigned char y;
|
||||
};
|
||||
|
||||
void matrixArc4Init(struct rc4_key_t *ctx, unsigned char *key, int32_t keylen);
|
||||
int32_t matrixArc4(struct rc4_key_t *ctx, unsigned char *in,
|
||||
unsigned char *out, int32_t len);
|
||||
|
||||
#endif
|
||||
530
utils/ipodpatcher/fat32format.c
Normal file
530
utils/ipodpatcher/fat32format.c
Normal file
|
|
@ -0,0 +1,530 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
*
|
||||
* FAT32 formatting functions. Based on:
|
||||
*
|
||||
* Fat32 formatter version 1.03
|
||||
* (c) Tom Thornhill 2005
|
||||
* This software is covered by the GPL.
|
||||
* By using this tool, you agree to absolve Ridgecrop of an liabilities for
|
||||
* lost data.
|
||||
* Please backup any data you value before using this tool.
|
||||
*
|
||||
*
|
||||
* Modified June 2007 by Dave Chapman for use in ipodpatcher
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "ipodio.h"
|
||||
|
||||
static inline uint16_t swap16(uint16_t value)
|
||||
{
|
||||
return (value >> 8) | (value << 8);
|
||||
}
|
||||
|
||||
static inline uint32_t swap32(uint32_t value)
|
||||
{
|
||||
uint32_t hi = swap16(value >> 16);
|
||||
uint32_t lo = swap16(value & 0xffff);
|
||||
return (lo << 16) | hi;
|
||||
}
|
||||
|
||||
/* The following functions are not the most efficient, but are
|
||||
self-contained and don't require needing to know endianness of CPU
|
||||
at compile-time.
|
||||
|
||||
Note that htole16/htole32 exist on some platforms, so for
|
||||
simplicity we use different names.
|
||||
|
||||
*/
|
||||
|
||||
static uint16_t rb_htole16(uint16_t x)
|
||||
{
|
||||
uint16_t test = 0x1234;
|
||||
unsigned char* p = (unsigned char*)&test;
|
||||
|
||||
if (p[0]==0x12) {
|
||||
/* Big-endian */
|
||||
return swap16(x);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t rb_htole32(uint32_t x)
|
||||
{
|
||||
uint32_t test = 0x12345678;
|
||||
unsigned char* p = (unsigned char*)&test;
|
||||
|
||||
if (p[0]==0x12) {
|
||||
/* Big-endian */
|
||||
return swap32(x);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* TODO: Pass these as parameters to the various create_ functions */
|
||||
|
||||
/* can be zero for default or 1,2,4,8,16,32 or 64 */
|
||||
static int sectors_per_cluster = 0;
|
||||
|
||||
/* Recommended values */
|
||||
static uint32_t ReservedSectCount = 32;
|
||||
static uint32_t NumFATs = 2;
|
||||
static uint32_t BackupBootSect = 6;
|
||||
static uint32_t VolumeId=0; /* calculated before format */
|
||||
|
||||
/* Calculated later */
|
||||
static uint32_t FatSize=0;
|
||||
static uint32_t BytesPerSect=0;
|
||||
static uint32_t SectorsPerCluster=0;
|
||||
static uint32_t TotalSectors=0;
|
||||
static uint32_t SystemAreaSize=0;
|
||||
static uint32_t UserAreaSize=0;
|
||||
static uint8_t VolId[12] = "NO NAME ";
|
||||
|
||||
|
||||
struct FAT_BOOTSECTOR32
|
||||
{
|
||||
/* Common fields. */
|
||||
uint8_t sJmpBoot[3];
|
||||
char sOEMName[8];
|
||||
uint16_t wBytsPerSec;
|
||||
uint8_t bSecPerClus;
|
||||
uint16_t wRsvdSecCnt;
|
||||
uint8_t bNumFATs;
|
||||
uint16_t wRootEntCnt;
|
||||
uint16_t wTotSec16; /* if zero, use dTotSec32 instead */
|
||||
uint8_t bMedia;
|
||||
uint16_t wFATSz16;
|
||||
uint16_t wSecPerTrk;
|
||||
uint16_t wNumHeads;
|
||||
uint32_t dHiddSec;
|
||||
uint32_t dTotSec32;
|
||||
|
||||
/* Fat 32/16 only */
|
||||
uint32_t dFATSz32;
|
||||
uint16_t wExtFlags;
|
||||
uint16_t wFSVer;
|
||||
uint32_t dRootClus;
|
||||
uint16_t wFSInfo;
|
||||
uint16_t wBkBootSec;
|
||||
uint8_t Reserved[12];
|
||||
uint8_t bDrvNum;
|
||||
uint8_t Reserved1;
|
||||
uint8_t bBootSig; /* == 0x29 if next three fields are ok */
|
||||
uint32_t dBS_VolID;
|
||||
uint8_t sVolLab[11];
|
||||
uint8_t sBS_FilSysType[8];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct FAT_FSINFO {
|
||||
uint32_t dLeadSig; // 0x41615252
|
||||
uint8_t sReserved1[480]; // zeros
|
||||
uint32_t dStrucSig; // 0x61417272
|
||||
uint32_t dFree_Count; // 0xFFFFFFFF
|
||||
uint32_t dNxt_Free; // 0xFFFFFFFF
|
||||
uint8_t sReserved2[12]; // zeros
|
||||
uint32_t dTrailSig; // 0xAA550000
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* Write "count" zero sectors, starting at sector "sector" */
|
||||
static int zero_sectors(struct ipod_t* ipod, uint64_t sector, int count)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (ipod_seek(ipod, sector * ipod->sector_size) < 0) {
|
||||
fprintf(stderr,"[ERR] Seek failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(ipod->sectorbuf, 0, 128 * ipod->sector_size);
|
||||
|
||||
/* Write 128 sectors at a time */
|
||||
while (count) {
|
||||
if (count >= 128)
|
||||
n = 128;
|
||||
else
|
||||
n = count;
|
||||
|
||||
if (ipod_write(ipod,n * ipod->sector_size) < 0) {
|
||||
perror("[ERR] Write failed in zero_sectors\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
count -= n;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
28.2 CALCULATING THE VOLUME SERIAL NUMBER
|
||||
|
||||
For example, say a disk was formatted on 26 Dec 95 at 9:55 PM and 41.94
|
||||
seconds. DOS takes the date and time just before it writes it to the
|
||||
disk.
|
||||
|
||||
Low order word is calculated: Volume Serial Number is:
|
||||
Month & Day 12/26 0c1ah
|
||||
Sec & Hundrenths 41:94 295eh 3578:1d02
|
||||
-----
|
||||
3578h
|
||||
|
||||
High order word is calculated:
|
||||
Hours & Minutes 21:55 1537h
|
||||
Year 1995 07cbh
|
||||
-----
|
||||
1d02h
|
||||
*/
|
||||
static uint32_t get_volume_id ( )
|
||||
{
|
||||
/* TODO */
|
||||
#if 0
|
||||
SYSTEMTIME s;
|
||||
uint32_t d;
|
||||
uint16_t lo,hi,tmp;
|
||||
|
||||
GetLocalTime( &s );
|
||||
|
||||
lo = s.wDay + ( s.wMonth << 8 );
|
||||
tmp = (s.wMilliseconds/10) + (s.wSecond << 8 );
|
||||
lo += tmp;
|
||||
|
||||
hi = s.wMinute + ( s.wHour << 8 );
|
||||
hi += s.wYear;
|
||||
|
||||
d = lo + (hi << 16);
|
||||
return(d);
|
||||
#endif
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
This is the Microsoft calculation from FATGEN
|
||||
|
||||
uint32_t RootDirSectors = 0;
|
||||
uint32_t TmpVal1, TmpVal2, FATSz;
|
||||
|
||||
TmpVal1 = DskSize - ( ReservedSecCnt + RootDirSectors);
|
||||
TmpVal2 = (256 * SecPerClus) + NumFATs;
|
||||
TmpVal2 = TmpVal2 / 2;
|
||||
FATSz = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2;
|
||||
|
||||
return( FatSz );
|
||||
*/
|
||||
|
||||
|
||||
static uint32_t get_fat_size_sectors(uint32_t DskSize, uint32_t ReservedSecCnt,
|
||||
uint32_t SecPerClus, uint32_t NumFATs,
|
||||
uint32_t BytesPerSect)
|
||||
{
|
||||
uint64_t Numerator, Denominator;
|
||||
uint64_t FatElementSize = 4;
|
||||
uint64_t FatSz;
|
||||
|
||||
/* This is based on
|
||||
http://hjem.get2net.dk/rune_moeller_barnkob/filesystems/fat.html
|
||||
I've made the obvious changes for FAT32
|
||||
*/
|
||||
|
||||
Numerator = FatElementSize * ( DskSize - ReservedSecCnt );
|
||||
Denominator = ( SecPerClus * BytesPerSect ) + ( FatElementSize * NumFATs );
|
||||
FatSz = Numerator / Denominator;
|
||||
|
||||
/* round up */
|
||||
FatSz += 1;
|
||||
|
||||
return((uint32_t)FatSz);
|
||||
}
|
||||
|
||||
static uint8_t get_spc(uint32_t ClusterSizeKB, uint32_t BytesPerSect)
|
||||
{
|
||||
uint32_t spc = ( ClusterSizeKB * 1024 ) / BytesPerSect;
|
||||
return( (uint8_t) spc );
|
||||
}
|
||||
|
||||
static uint8_t get_sectors_per_cluster(uint32_t DiskSizeSectors,
|
||||
uint32_t BytesPerSect)
|
||||
{
|
||||
uint8_t ret = 0x01; /* 1 sector per cluster */
|
||||
uint64_t DiskSizeBytes = (uint64_t)DiskSizeSectors * (uint64_t)BytesPerSect;
|
||||
int64_t DiskSizeMB = DiskSizeBytes / ( 1024*1024 );
|
||||
|
||||
/* 512 MB to 8,191 MB 4 KB */
|
||||
if ( DiskSizeMB > 512 )
|
||||
ret = get_spc( 4, BytesPerSect ); /* ret = 0x8; */
|
||||
|
||||
/* 8,192 MB to 16,383 MB 8 KB */
|
||||
if ( DiskSizeMB > 8192 )
|
||||
ret = get_spc( 8, BytesPerSect ); /* ret = 0x10; */
|
||||
|
||||
/* 16,384 MB to 32,767 MB 16 KB */
|
||||
if ( DiskSizeMB > 16384 )
|
||||
ret = get_spc( 16, BytesPerSect ); /* ret = 0x20; */
|
||||
|
||||
/* Larger than 32,768 MB 32 KB */
|
||||
if ( DiskSizeMB > 32768 )
|
||||
ret = get_spc( 32, BytesPerSect ); /* ret = 0x40; */
|
||||
|
||||
return( ret );
|
||||
|
||||
}
|
||||
|
||||
static void create_boot_sector(unsigned char* buf,
|
||||
struct ipod_t* ipod, int partition)
|
||||
{
|
||||
struct FAT_BOOTSECTOR32* pFAT32BootSect = (struct FAT_BOOTSECTOR32*)buf;
|
||||
|
||||
/* fill out the boot sector and fs info */
|
||||
pFAT32BootSect->sJmpBoot[0]=0xEB;
|
||||
pFAT32BootSect->sJmpBoot[1]=0x5A;
|
||||
pFAT32BootSect->sJmpBoot[2]=0x90;
|
||||
memcpy(pFAT32BootSect->sOEMName, "MSWIN4.1", 8 );
|
||||
pFAT32BootSect->wBytsPerSec = rb_htole16(BytesPerSect);
|
||||
pFAT32BootSect->bSecPerClus = SectorsPerCluster ;
|
||||
pFAT32BootSect->wRsvdSecCnt = rb_htole16(ReservedSectCount);
|
||||
pFAT32BootSect->bNumFATs = NumFATs;
|
||||
pFAT32BootSect->wRootEntCnt = rb_htole16(0);
|
||||
pFAT32BootSect->wTotSec16 = rb_htole16(0);
|
||||
pFAT32BootSect->bMedia = 0xF8;
|
||||
pFAT32BootSect->wFATSz16 = rb_htole16(0);
|
||||
pFAT32BootSect->wSecPerTrk = rb_htole16(ipod->sectors_per_track);
|
||||
pFAT32BootSect->wNumHeads = rb_htole16(ipod->num_heads);
|
||||
pFAT32BootSect->dHiddSec = rb_htole16(ipod->pinfo[partition].start);
|
||||
pFAT32BootSect->dTotSec32 = rb_htole32(TotalSectors);
|
||||
pFAT32BootSect->dFATSz32 = rb_htole32(FatSize);
|
||||
pFAT32BootSect->wExtFlags = rb_htole16(0);
|
||||
pFAT32BootSect->wFSVer = rb_htole16(0);
|
||||
pFAT32BootSect->dRootClus = rb_htole32(2);
|
||||
pFAT32BootSect->wFSInfo = rb_htole16(1);
|
||||
pFAT32BootSect->wBkBootSec = rb_htole16(BackupBootSect);
|
||||
pFAT32BootSect->bDrvNum = 0x80;
|
||||
pFAT32BootSect->Reserved1 = 0;
|
||||
pFAT32BootSect->bBootSig = 0x29;
|
||||
pFAT32BootSect->dBS_VolID = rb_htole32(VolumeId);
|
||||
memcpy(pFAT32BootSect->sVolLab, VolId, 11);
|
||||
memcpy(pFAT32BootSect->sBS_FilSysType, "FAT32 ", 8 );
|
||||
|
||||
buf[510] = 0x55;
|
||||
buf[511] = 0xaa;
|
||||
}
|
||||
|
||||
static void create_fsinfo(unsigned char* buf)
|
||||
{
|
||||
struct FAT_FSINFO* pFAT32FsInfo = (struct FAT_FSINFO*)buf;
|
||||
|
||||
/* FSInfo sect */
|
||||
pFAT32FsInfo->dLeadSig = rb_htole32(0x41615252);
|
||||
pFAT32FsInfo->dStrucSig = rb_htole32(0x61417272);
|
||||
pFAT32FsInfo->dFree_Count = rb_htole32((uint32_t) -1);
|
||||
pFAT32FsInfo->dNxt_Free = rb_htole32((uint32_t) -1);
|
||||
pFAT32FsInfo->dTrailSig = rb_htole32(0xaa550000);
|
||||
pFAT32FsInfo->dFree_Count = rb_htole32((UserAreaSize/SectorsPerCluster)-1);
|
||||
|
||||
/* clusters 0-1 reserved, we used cluster 2 for the root dir */
|
||||
pFAT32FsInfo->dNxt_Free = rb_htole32(3);
|
||||
}
|
||||
|
||||
static void create_firstfatsector(unsigned char* buf)
|
||||
{
|
||||
uint32_t* p = (uint32_t*)buf; /* We know the buffer is aligned */
|
||||
|
||||
/* First FAT Sector */
|
||||
p[0] = rb_htole32(0x0ffffff8); /* Reserved cluster 1 media id in low byte */
|
||||
p[1] = rb_htole32(0x0fffffff); /* Reserved cluster 2 EOC */
|
||||
p[2] = rb_htole32(0x0fffffff); /* end of cluster chain for root dir */
|
||||
}
|
||||
|
||||
int format_partition(struct ipod_t* ipod, int partition)
|
||||
{
|
||||
uint32_t i;
|
||||
uint64_t qTotalSectors=0;
|
||||
uint64_t FatNeeded;
|
||||
|
||||
VolumeId = get_volume_id( );
|
||||
|
||||
/* Only support hard disks at the moment */
|
||||
if ( ipod->sector_size != 512 )
|
||||
{
|
||||
fprintf(stderr,"[ERR] Only disks with 512 bytes per sector are supported.\n");
|
||||
return -1;
|
||||
}
|
||||
BytesPerSect = ipod->sector_size;
|
||||
|
||||
/* Checks on Disk Size */
|
||||
qTotalSectors = ipod->pinfo[partition].size;
|
||||
|
||||
/* low end limit - 65536 sectors */
|
||||
if ( qTotalSectors < 65536 )
|
||||
{
|
||||
/* I suspect that most FAT32 implementations would mount this
|
||||
volume just fine, but the spec says that we shouldn't do
|
||||
this, so we won't */
|
||||
|
||||
fprintf(stderr,"[ERR] This drive is too small for FAT32 - there must be at least 64K clusters\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( qTotalSectors >= 0xffffffff )
|
||||
{
|
||||
/* This is a more fundamental limitation on FAT32 - the total
|
||||
sector count in the root dir is 32bit. With a bit of
|
||||
creativity, FAT32 could be extended to handle at least 2^28
|
||||
clusters There would need to be an extra field in the
|
||||
FSInfo sector, and the old sector count could be set to
|
||||
0xffffffff. This is non standard though, the Windows FAT
|
||||
driver FASTFAT.SYS won't understand this. Perhaps a future
|
||||
version of FAT32 and FASTFAT will handle this. */
|
||||
|
||||
fprintf(stderr,"[ERR] This drive is too big for FAT32 - max 2TB supported\n");
|
||||
}
|
||||
|
||||
if ( sectors_per_cluster ) {
|
||||
SectorsPerCluster = sectors_per_cluster;
|
||||
} else {
|
||||
SectorsPerCluster = get_sectors_per_cluster(ipod->pinfo[partition].size,
|
||||
BytesPerSect );
|
||||
}
|
||||
|
||||
TotalSectors = (uint32_t) qTotalSectors;
|
||||
|
||||
FatSize = get_fat_size_sectors(TotalSectors, ReservedSectCount,
|
||||
SectorsPerCluster, NumFATs, BytesPerSect );
|
||||
|
||||
UserAreaSize = TotalSectors - ReservedSectCount - (NumFATs*FatSize);
|
||||
|
||||
/* First zero out ReservedSect + FatSize * NumFats + SectorsPerCluster */
|
||||
SystemAreaSize = (ReservedSectCount+(NumFATs*FatSize) + SectorsPerCluster);
|
||||
|
||||
/* Work out the Cluster count */
|
||||
FatNeeded = UserAreaSize/SectorsPerCluster;
|
||||
|
||||
/* check for a cluster count of >2^28, since the upper 4 bits of
|
||||
the cluster values in the FAT are reserved. */
|
||||
if (FatNeeded > 0x0FFFFFFF) {
|
||||
fprintf(stderr,"[ERR] This drive has more than 2^28 clusters, try to specify a larger cluster size\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Sanity check, make sure the fat is big enough.
|
||||
Convert the cluster count into a Fat sector count, and check
|
||||
the fat size value we calculated earlier is OK. */
|
||||
|
||||
FatNeeded *=4;
|
||||
FatNeeded += (BytesPerSect-1);
|
||||
FatNeeded /= BytesPerSect;
|
||||
|
||||
if ( FatNeeded > FatSize ) {
|
||||
fprintf(stderr,"[ERR] Drive too big to format\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
Write boot sector, fats
|
||||
Sector 0 Boot Sector
|
||||
Sector 1 FSInfo
|
||||
Sector 2 More boot code - we write zeros here
|
||||
Sector 3 unused
|
||||
Sector 4 unused
|
||||
Sector 5 unused
|
||||
Sector 6 Backup boot sector
|
||||
Sector 7 Backup FSInfo sector
|
||||
Sector 8 Backup 'more boot code'
|
||||
zero'd sectors upto ReservedSectCount
|
||||
FAT1 ReservedSectCount to ReservedSectCount + FatSize
|
||||
...
|
||||
FATn ReservedSectCount to ReservedSectCount + FatSize
|
||||
RootDir - allocated to cluster2
|
||||
*/
|
||||
|
||||
fprintf(stderr,"[INFO] Heads - %d, sectors/track = %d\n",ipod->num_heads,ipod->sectors_per_track);
|
||||
fprintf(stderr,"[INFO] Size : %" PRIu64 "GB %u sectors\n",
|
||||
((uint64_t)ipod->pinfo[partition].size * (uint64_t)ipod->sector_size) / (1000*1000*1000), TotalSectors );
|
||||
fprintf(stderr,"[INFO] %d Bytes Per Sector, Cluster size %d bytes\n", BytesPerSect, SectorsPerCluster*BytesPerSect );
|
||||
fprintf(stderr,"[INFO] Volume ID is %x:%x\n", VolumeId>>16, VolumeId&0xffff );
|
||||
fprintf(stderr,"[INFO] %d Reserved Sectors, %d Sectors per FAT, %d fats\n", ReservedSectCount, FatSize, NumFATs );
|
||||
fprintf (stderr,"[INFO] %d Total clusters\n", UserAreaSize/SectorsPerCluster );
|
||||
|
||||
fprintf(stderr,"[INFO] Formatting partition %d:...\n",partition);
|
||||
|
||||
/* Once zero_sectors has run, any data on the drive is basically lost... */
|
||||
fprintf(stderr,"[INFO] Clearing out %d sectors for Reserved sectors, fats and root cluster...\n", SystemAreaSize );
|
||||
|
||||
zero_sectors(ipod, ipod->pinfo[partition].start, SystemAreaSize);
|
||||
|
||||
fprintf(stderr,"[INFO] Initialising reserved sectors and FATs...\n" );
|
||||
|
||||
/* Create the boot sector structure */
|
||||
create_boot_sector(ipod->sectorbuf, ipod, partition);
|
||||
create_fsinfo(ipod->sectorbuf + 512);
|
||||
|
||||
/* Write boot sector and fsinfo at start of partition */
|
||||
if (ipod_seek(ipod, ipod->pinfo[partition].start * ipod->sector_size) < 0) {
|
||||
fprintf(stderr,"[ERR] Seek failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (ipod_write(ipod,512 * 2) < 0) {
|
||||
perror("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Write backup copy of boot sector and fsinfo */
|
||||
if (ipod_seek(ipod, (ipod->pinfo[partition].start + BackupBootSect) * ipod->sector_size) < 0) {
|
||||
fprintf(stderr,"[ERR] Seek failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (ipod_write(ipod,512 * 2) < 0) {
|
||||
perror("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create the first FAT sector */
|
||||
create_firstfatsector(ipod->sectorbuf);
|
||||
|
||||
/* Write the first fat sector in the right places */
|
||||
for ( i=0; i<NumFATs; i++ ) {
|
||||
int SectorStart = ReservedSectCount + (i * FatSize );
|
||||
|
||||
if (ipod_seek(ipod, (ipod->pinfo[partition].start + SectorStart) * ipod->sector_size) < 0) {
|
||||
fprintf(stderr,"[ERR] Seek failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ipod_write(ipod,512) < 0) {
|
||||
perror("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr,"[INFO] Format successful\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
409
utils/ipodpatcher/ipodio-posix.c
Normal file
409
utils/ipodpatcher/ipodio-posix.c
Normal file
|
|
@ -0,0 +1,409 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2007 Dave Chapman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if !defined(_WIN32) /* all non-Windows platforms are considered POSIX. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "ipodio.h"
|
||||
|
||||
#if defined(linux) || defined (__linux)
|
||||
#include <sys/mount.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <scsi/scsi_ioctl.h>
|
||||
#include <scsi/sg.h>
|
||||
|
||||
#define IPOD_SECTORSIZE_IOCTL BLKSSZGET
|
||||
|
||||
static void get_geometry(struct ipod_t* ipod)
|
||||
{
|
||||
struct hd_geometry geometry;
|
||||
|
||||
if (!ioctl(ipod->dh, HDIO_GETGEO, &geometry)) {
|
||||
/* never use geometry.cylinders - it is truncated */
|
||||
ipod->num_heads = geometry.heads;
|
||||
ipod->sectors_per_track = geometry.sectors;
|
||||
} else {
|
||||
ipod->num_heads = 0;
|
||||
ipod->sectors_per_track = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Linux SCSI Inquiry code based on the documentation and example code from
|
||||
http://www.ibm.com/developerworks/linux/library/l-scsi-api/index.html
|
||||
*/
|
||||
|
||||
int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
|
||||
unsigned char* buf, int bufsize)
|
||||
{
|
||||
unsigned char cdb[6];
|
||||
struct sg_io_hdr hdr;
|
||||
unsigned char sense_buffer[255];
|
||||
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
|
||||
hdr.interface_id = 'S'; /* this is the only choice we have! */
|
||||
hdr.flags = SG_FLAG_LUN_INHIBIT; /* this would put the LUN to 2nd byte of cdb*/
|
||||
|
||||
/* Set xfer data */
|
||||
hdr.dxferp = buf;
|
||||
hdr.dxfer_len = bufsize;
|
||||
|
||||
/* Set sense data */
|
||||
hdr.sbp = sense_buffer;
|
||||
hdr.mx_sb_len = sizeof(sense_buffer);
|
||||
|
||||
/* Set the cdb format */
|
||||
cdb[0] = 0x12;
|
||||
cdb[1] = 1; /* Enable Vital Product Data (EVPD) */
|
||||
cdb[2] = page_code & 0xff;
|
||||
cdb[3] = 0;
|
||||
cdb[4] = 0xff;
|
||||
cdb[5] = 0; /* For control filed, just use 0 */
|
||||
|
||||
hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||||
hdr.cmdp = cdb;
|
||||
hdr.cmd_len = 6;
|
||||
|
||||
int ret = ioctl(ipod->dh, SG_IO, &hdr);
|
||||
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
|
||||
|| defined(__bsdi__) || defined(__DragonFly__)
|
||||
#include <sys/disk.h>
|
||||
#define IPOD_SECTORSIZE_IOCTL DIOCGSECTORSIZE
|
||||
|
||||
/* TODO: Implement this function for BSD */
|
||||
static void get_geometry(struct ipod_t* ipod)
|
||||
{
|
||||
/* Are these universal for all ipods? */
|
||||
ipod->num_heads = 255;
|
||||
ipod->sectors_per_track = 63;
|
||||
}
|
||||
|
||||
int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
|
||||
unsigned char* buf, int bufsize)
|
||||
{
|
||||
/* TODO: Implement for BSD */
|
||||
(void)ipod;
|
||||
(void)page_code;
|
||||
(void)buf;
|
||||
(void)bufsize;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
/* OS X IOKit includes don't like VERSION being defined! */
|
||||
#undef VERSION
|
||||
#include <sys/disk.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/scsi/SCSITaskLib.h>
|
||||
#include <IOKit/scsi/SCSICommandOperationCodes.h>
|
||||
#define IPOD_SECTORSIZE_IOCTL DKIOCGETBLOCKSIZE
|
||||
|
||||
/* TODO: Implement this function for Mac OS X */
|
||||
static void get_geometry(struct ipod_t* ipod)
|
||||
{
|
||||
/* Are these universal for all ipods? */
|
||||
ipod->num_heads = 255;
|
||||
ipod->sectors_per_track = 63;
|
||||
}
|
||||
|
||||
int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
|
||||
unsigned char* buf, int bufsize)
|
||||
{
|
||||
/* OS X doesn't allow to simply send out a SCSI inquiry request but
|
||||
* requires registering an interface handler first.
|
||||
* Currently this is done on each inquiry request which is somewhat
|
||||
* inefficient but the current ipodpatcher API doesn't really fit here.
|
||||
* Based on the documentation in Apple's document
|
||||
* "SCSI Architecture Model Device Interface Guide".
|
||||
*
|
||||
* WARNING: this code currently doesn't take the selected device into
|
||||
* account. It simply looks for an Ipod on the system and uses
|
||||
* the first match.
|
||||
*/
|
||||
(void)ipod;
|
||||
int result = 0;
|
||||
/* first, create a dictionary to match the device. This is needed to get the
|
||||
* service. */
|
||||
CFMutableDictionaryRef match_dict;
|
||||
match_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL);
|
||||
if(match_dict == NULL)
|
||||
return -1;
|
||||
|
||||
/* set value to match. In case of the Ipod this is "iPodUserClientDevice". */
|
||||
CFMutableDictionaryRef sub_dict;
|
||||
sub_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL);
|
||||
if(sub_dict == NULL)
|
||||
return -1;
|
||||
CFDictionarySetValue(sub_dict, CFSTR(kIOPropertySCSITaskDeviceCategory),
|
||||
CFSTR("iPodUserClientDevice"));
|
||||
CFDictionarySetValue(match_dict, CFSTR(kIOPropertyMatchKey), sub_dict);
|
||||
|
||||
/* get an iterator for searching for the service. */
|
||||
kern_return_t kr;
|
||||
io_iterator_t iterator = IO_OBJECT_NULL;
|
||||
/* get matching services from IO registry. Consumes one reference to
|
||||
* the dictionary, so no need to release that. */
|
||||
kr = IOServiceGetMatchingServices(kIOMasterPortDefault, match_dict, &iterator);
|
||||
|
||||
if(!iterator | (kr != kIOReturnSuccess))
|
||||
return -1;
|
||||
|
||||
/* get interface and obtain exclusive access */
|
||||
SInt32 score;
|
||||
HRESULT herr;
|
||||
kern_return_t err;
|
||||
IOCFPlugInInterface **plugin_interface = NULL;
|
||||
SCSITaskDeviceInterface **interface = NULL;
|
||||
io_service_t device = IO_OBJECT_NULL;
|
||||
device = IOIteratorNext(iterator);
|
||||
|
||||
err = IOCreatePlugInInterfaceForService(device, kIOSCSITaskDeviceUserClientTypeID,
|
||||
kIOCFPlugInInterfaceID, &plugin_interface,
|
||||
&score);
|
||||
|
||||
if(err != noErr) {
|
||||
return -1;
|
||||
}
|
||||
/* query the plugin interface for task interface */
|
||||
herr = (*plugin_interface)->QueryInterface(plugin_interface,
|
||||
CFUUIDGetUUIDBytes(kIOSCSITaskDeviceInterfaceID), (LPVOID*)&interface);
|
||||
if(herr != S_OK) {
|
||||
IODestroyPlugInInterface(plugin_interface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = (*interface)->ObtainExclusiveAccess(interface);
|
||||
if(err != noErr) {
|
||||
(*interface)->Release(interface);
|
||||
IODestroyPlugInInterface(plugin_interface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* do the inquiry */
|
||||
SCSITaskInterface **task = NULL;
|
||||
|
||||
task = (*interface)->CreateSCSITask(interface);
|
||||
if(task != NULL) {
|
||||
kern_return_t err;
|
||||
SCSITaskStatus task_status;
|
||||
IOVirtualRange* range;
|
||||
SCSI_Sense_Data sense_data;
|
||||
SCSICommandDescriptorBlock cdb;
|
||||
UInt64 transfer_count = 0;
|
||||
memset(buf, 0, bufsize);
|
||||
/* allocate virtual range for buffer. */
|
||||
range = (IOVirtualRange*) malloc(sizeof(IOVirtualRange));
|
||||
memset(&sense_data, 0, sizeof(sense_data));
|
||||
memset(cdb, 0, sizeof(cdb));
|
||||
/* set up range. address is buffer address, length is request size. */
|
||||
range->address = (IOVirtualAddress)buf;
|
||||
range->length = bufsize;
|
||||
/* setup CDB */
|
||||
cdb[0] = 0x12; /* inquiry */
|
||||
cdb[1] = 1;
|
||||
cdb[2] = page_code;
|
||||
cdb[4] = bufsize;
|
||||
|
||||
/* set cdb in task */
|
||||
err = (*task)->SetCommandDescriptorBlock(task, cdb, kSCSICDBSize_6Byte);
|
||||
if(err != kIOReturnSuccess) {
|
||||
result = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
err = (*task)->SetScatterGatherEntries(task, range, 1, bufsize,
|
||||
kSCSIDataTransfer_FromTargetToInitiator);
|
||||
if(err != kIOReturnSuccess) {
|
||||
result = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
/* set timeout */
|
||||
err = (*task)->SetTimeoutDuration(task, 10000);
|
||||
if(err != kIOReturnSuccess) {
|
||||
result = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* request data */
|
||||
err = (*task)->ExecuteTaskSync(task, &sense_data, &task_status, &transfer_count);
|
||||
if(err != kIOReturnSuccess) {
|
||||
result = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
/* cleanup */
|
||||
free(range);
|
||||
|
||||
/* release task interface */
|
||||
(*task)->Release(task);
|
||||
}
|
||||
else {
|
||||
result = -1;
|
||||
}
|
||||
cleanup:
|
||||
/* cleanup interface */
|
||||
(*interface)->ReleaseExclusiveAccess(interface);
|
||||
(*interface)->Release(interface);
|
||||
IODestroyPlugInInterface(plugin_interface);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
#error No sector-size detection implemented for this platform
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
static int ipod_unmount(struct ipod_t* ipod)
|
||||
{
|
||||
char cmd[4096];
|
||||
int res;
|
||||
|
||||
sprintf(cmd, "/usr/sbin/diskutil unmount \"%ss2\"",ipod->diskname);
|
||||
fprintf(stderr,"[INFO] ");
|
||||
res = system(cmd);
|
||||
|
||||
if (res==0) {
|
||||
return 0;
|
||||
} else {
|
||||
perror("Unmount failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void ipod_print_error(char* msg)
|
||||
{
|
||||
perror(msg);
|
||||
}
|
||||
|
||||
int ipod_open(struct ipod_t* ipod, int silent)
|
||||
{
|
||||
ipod->dh=open(ipod->diskname,O_RDONLY);
|
||||
if (ipod->dh < 0) {
|
||||
if (!silent) perror(ipod->diskname);
|
||||
if(errno == EACCES) return -2;
|
||||
else return -1;
|
||||
}
|
||||
|
||||
/* Read information about the disk */
|
||||
|
||||
if(ioctl(ipod->dh,IPOD_SECTORSIZE_IOCTL,&ipod->sector_size) < 0) {
|
||||
ipod->sector_size=512;
|
||||
if (!silent) {
|
||||
fprintf(stderr,"[ERR] ioctl() call to get sector size failed, defaulting to %d\n"
|
||||
,ipod->sector_size);
|
||||
}
|
||||
}
|
||||
|
||||
get_geometry(ipod);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ipod_reopen_rw(struct ipod_t* ipod)
|
||||
{
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
if (ipod_unmount(ipod) < 0)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
close(ipod->dh);
|
||||
ipod->dh=open(ipod->diskname,O_RDWR);
|
||||
if (ipod->dh < 0) {
|
||||
perror(ipod->diskname);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipod_close(struct ipod_t* ipod)
|
||||
{
|
||||
close(ipod->dh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipod_alloc_buffer(struct ipod_t* ipod, int bufsize)
|
||||
{
|
||||
ipod->sectorbuf = malloc(bufsize);
|
||||
if (ipod->sectorbuf== NULL) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipod_dealloc_buffer(struct ipod_t* ipod)
|
||||
{
|
||||
if (ipod->sectorbuf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
free(ipod->sectorbuf);
|
||||
ipod->sectorbuf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipod_seek(struct ipod_t* ipod, unsigned long pos)
|
||||
{
|
||||
off_t res;
|
||||
|
||||
res = lseek(ipod->dh, pos, SEEK_SET);
|
||||
|
||||
if (res == -1) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t ipod_read(struct ipod_t* ipod, int nbytes)
|
||||
{
|
||||
if(ipod->sectorbuf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return read(ipod->dh, ipod->sectorbuf, nbytes);
|
||||
}
|
||||
|
||||
ssize_t ipod_write(struct ipod_t* ipod, int nbytes)
|
||||
{
|
||||
if(ipod->sectorbuf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return write(ipod->dh, ipod->sectorbuf, nbytes);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
147
utils/ipodpatcher/ipodio-win32-scsi.c
Normal file
147
utils/ipodpatcher/ipodio-win32-scsi.c
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2009 Dave Chapman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
*
|
||||
* Based on the getCapsUsingSCSIPassThrough() function from "cddrv.cpp":
|
||||
* - http://www.farmanager.com/svn/trunk/unicode_far/cddrv.cpp
|
||||
*
|
||||
* Copyright (c) 1996 Eugene Roshal
|
||||
* Copyright (c) 2000 Far Group
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the authors may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ipodio.h"
|
||||
|
||||
/* from ddk/ntddscsi.h */
|
||||
#define SCSI_IOCTL_DATA_OUT 0
|
||||
#define SCSI_IOCTL_DATA_IN 1
|
||||
#define SCSI_IOCTL_DATA_UNSPECIFIED 2
|
||||
|
||||
#define IOCTL_SCSI_PASS_THROUGH \
|
||||
CTL_CODE(FILE_DEVICE_CONTROLLER, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
|
||||
|
||||
typedef struct _SCSI_PASS_THROUGH {
|
||||
USHORT Length;
|
||||
UCHAR ScsiStatus;
|
||||
UCHAR PathId;
|
||||
UCHAR TargetId;
|
||||
UCHAR Lun;
|
||||
UCHAR CdbLength;
|
||||
UCHAR SenseInfoLength;
|
||||
UCHAR DataIn;
|
||||
ULONG DataTransferLength;
|
||||
ULONG TimeOutValue;
|
||||
ULONG_PTR DataBufferOffset;
|
||||
ULONG SenseInfoOffset;
|
||||
UCHAR Cdb[16];
|
||||
} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
|
||||
|
||||
typedef struct _SCSI_PASS_THROUGH_WITH_BUFFERS {
|
||||
SCSI_PASS_THROUGH Spt;
|
||||
ULONG Filler; /* realign buffers to double word boundary */
|
||||
UCHAR SenseBuf[32];
|
||||
UCHAR DataBuf[512];
|
||||
} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS;
|
||||
|
||||
int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
|
||||
unsigned char* buf, int bufsize)
|
||||
{
|
||||
SCSI_PASS_THROUGH_WITH_BUFFERS sptwb;
|
||||
ULONG length;
|
||||
DWORD returned;
|
||||
BOOL status;
|
||||
|
||||
if (bufsize > 255) {
|
||||
fprintf(stderr,"[ERR] Invalid bufsize in ipod_scsi_inquiry\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&sptwb, 0, sizeof(sptwb));
|
||||
|
||||
sptwb.Spt.Length = sizeof(SCSI_PASS_THROUGH);
|
||||
sptwb.Spt.PathId = 0;
|
||||
sptwb.Spt.TargetId = 1;
|
||||
sptwb.Spt.Lun = 0;
|
||||
sptwb.Spt.CdbLength = 6;
|
||||
sptwb.Spt.SenseInfoLength = 32; /* sbuf size */;
|
||||
sptwb.Spt.DataIn = SCSI_IOCTL_DATA_IN;
|
||||
sptwb.Spt.DataTransferLength = bufsize;
|
||||
sptwb.Spt.TimeOutValue = 2; /* 2 seconds */
|
||||
sptwb.Spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuf);
|
||||
sptwb.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, SenseBuf);
|
||||
length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuf) +
|
||||
sptwb.Spt.DataTransferLength;
|
||||
|
||||
/* Set cdb info */
|
||||
sptwb.Spt.Cdb[0] = 0x12; /* SCSI Inquiry */
|
||||
sptwb.Spt.Cdb[1] = 1;
|
||||
sptwb.Spt.Cdb[2] = page_code;
|
||||
sptwb.Spt.Cdb[3] = 0;
|
||||
sptwb.Spt.Cdb[4] = bufsize;
|
||||
sptwb.Spt.Cdb[5] = 0;
|
||||
|
||||
status = DeviceIoControl(ipod->dh,
|
||||
IOCTL_SCSI_PASS_THROUGH,
|
||||
&sptwb,
|
||||
sizeof(SCSI_PASS_THROUGH),
|
||||
&sptwb,
|
||||
length,
|
||||
&returned,
|
||||
FALSE);
|
||||
|
||||
if (status) {
|
||||
/* W32 sometimes returns more bytes with additional garbage.
|
||||
* Make sure to not copy that garbage. */
|
||||
memcpy(buf, sptwb.DataBuf,
|
||||
(DWORD)bufsize >= returned ? returned : (DWORD)bufsize);
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
226
utils/ipodpatcher/ipodio-win32.c
Normal file
226
utils/ipodpatcher/ipodio-win32.c
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2007 Dave Chapman
|
||||
*
|
||||
* error(), lock_volume() and unlock_volume() functions and inspiration taken
|
||||
* from:
|
||||
* RawDisk - Direct Disk Read/Write Access for NT/2000/XP
|
||||
* Copyright (c) 2003 Jan Kiszka
|
||||
* http://www.stud.uni-hannover.de/user/73174/RawDisk/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <windows.h>
|
||||
#include <stddef.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
#include "ipodio.h"
|
||||
|
||||
static int lock_volume(HANDLE hDisk)
|
||||
{
|
||||
DWORD dummy;
|
||||
|
||||
return DeviceIoControl(hDisk, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0,
|
||||
&dummy, NULL);
|
||||
}
|
||||
|
||||
static int unlock_volume(HANDLE hDisk)
|
||||
{
|
||||
DWORD dummy;
|
||||
|
||||
return DeviceIoControl(hDisk, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0,
|
||||
&dummy, NULL);
|
||||
}
|
||||
|
||||
void ipod_print_error(char* msg)
|
||||
{
|
||||
LPSTR pMsgBuf = NULL;
|
||||
|
||||
printf(msg);
|
||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), pMsgBuf,
|
||||
0, NULL);
|
||||
printf(pMsgBuf);
|
||||
LocalFree(pMsgBuf);
|
||||
}
|
||||
|
||||
int ipod_open(struct ipod_t* ipod, int silent)
|
||||
{
|
||||
DISK_GEOMETRY_EX diskgeometry_ex;
|
||||
DISK_GEOMETRY diskgeometry;
|
||||
unsigned long n;
|
||||
|
||||
ipod->dh = CreateFileA(ipod->diskname, GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
||||
FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL);
|
||||
|
||||
if (ipod->dh == INVALID_HANDLE_VALUE) {
|
||||
if (!silent) ipod_print_error(" Error opening disk: ");
|
||||
if(GetLastError() == ERROR_ACCESS_DENIED)
|
||||
return -2;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!lock_volume(ipod->dh)) {
|
||||
if (!silent) ipod_print_error(" Error locking disk: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Defaults */
|
||||
ipod->num_heads = 0;
|
||||
ipod->sectors_per_track = 0;
|
||||
|
||||
if (!DeviceIoControl(ipod->dh,
|
||||
IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
|
||||
NULL,
|
||||
0,
|
||||
&diskgeometry_ex,
|
||||
sizeof(diskgeometry_ex),
|
||||
&n,
|
||||
NULL)) {
|
||||
if (!DeviceIoControl(ipod->dh,
|
||||
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
||||
NULL,
|
||||
0,
|
||||
&diskgeometry,
|
||||
sizeof(diskgeometry),
|
||||
&n,
|
||||
NULL)) {
|
||||
if (!silent) ipod_print_error(" Error reading disk geometry: ");
|
||||
return -1;
|
||||
} else {
|
||||
ipod->sector_size = diskgeometry.BytesPerSector;
|
||||
ipod->num_heads = diskgeometry.TracksPerCylinder;
|
||||
ipod->sectors_per_track = diskgeometry.SectorsPerTrack;
|
||||
}
|
||||
} else {
|
||||
ipod->sector_size = diskgeometry_ex.Geometry.BytesPerSector;
|
||||
ipod->num_heads = diskgeometry_ex.Geometry.TracksPerCylinder;
|
||||
ipod->sectors_per_track = diskgeometry_ex.Geometry.SectorsPerTrack;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipod_reopen_rw(struct ipod_t* ipod)
|
||||
{
|
||||
/* Close existing file and re-open for writing */
|
||||
unlock_volume(ipod->dh);
|
||||
CloseHandle(ipod->dh);
|
||||
|
||||
ipod->dh = CreateFileA(ipod->diskname, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
||||
FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL);
|
||||
|
||||
if (ipod->dh == INVALID_HANDLE_VALUE) {
|
||||
ipod_print_error(" Error opening disk: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!lock_volume(ipod->dh)) {
|
||||
ipod_print_error(" Error locking disk: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipod_close(struct ipod_t* ipod)
|
||||
{
|
||||
unlock_volume(ipod->dh);
|
||||
CloseHandle(ipod->dh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipod_alloc_buffer(struct ipod_t* ipod, int bufsize)
|
||||
{
|
||||
/* The ReadFile function requires a memory buffer aligned to a multiple of
|
||||
the disk sector size. */
|
||||
ipod->sectorbuf = (unsigned char*)VirtualAlloc(NULL, bufsize, MEM_COMMIT, PAGE_READWRITE);
|
||||
if (ipod->sectorbuf== NULL) {
|
||||
ipod_print_error(" Error allocating a buffer: ");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipod_dealloc_buffer(struct ipod_t* ipod)
|
||||
{
|
||||
if (ipod->sectorbuf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if(!VirtualFree(ipod->sectorbuf, 0, MEM_RELEASE)) {
|
||||
ipod_print_error(" Error releasing buffer ");
|
||||
return -1;
|
||||
}
|
||||
ipod->sectorbuf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipod_seek(struct ipod_t* ipod, unsigned long pos)
|
||||
{
|
||||
if (SetFilePointer(ipod->dh, pos, NULL, FILE_BEGIN)==0xffffffff) {
|
||||
ipod_print_error(" Seek error ");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t ipod_read(struct ipod_t* ipod, int nbytes)
|
||||
{
|
||||
unsigned long count;
|
||||
|
||||
if(ipod->sectorbuf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (!ReadFile(ipod->dh, ipod->sectorbuf, nbytes, &count, NULL)) {
|
||||
ipod_print_error(" Error reading from disk: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
ssize_t ipod_write(struct ipod_t* ipod, int nbytes)
|
||||
{
|
||||
unsigned long count;
|
||||
|
||||
if(ipod->sectorbuf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (!WriteFile(ipod->dh, ipod->sectorbuf, nbytes, &count, NULL)) {
|
||||
ipod_print_error(" Error writing to disk: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
115
utils/ipodpatcher/ipodio.h
Normal file
115
utils/ipodpatcher/ipodio.h
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2007 Dave Chapman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __IPODIO_H
|
||||
#define __IPODIO_H
|
||||
|
||||
#include <stdint.h>
|
||||
#if !defined(_WIN32)
|
||||
#include <unistd.h>
|
||||
#elif defined(_MSC_VER)
|
||||
/* MSVC uses a different name for ssize_t */
|
||||
#define ssize_t SSIZE_T
|
||||
#endif
|
||||
|
||||
#if defined(__WIN32__) || defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#define HANDLE int
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
/* The maximum number of images in a firmware partition - a guess... */
|
||||
#define MAX_IMAGES 10
|
||||
|
||||
enum firmwaretype_t {
|
||||
FTYPE_OSOS = 0,
|
||||
FTYPE_RSRC,
|
||||
FTYPE_AUPD,
|
||||
FTYPE_HIBE,
|
||||
FTYPE_OSBK
|
||||
};
|
||||
|
||||
struct ipod_directory_t {
|
||||
enum firmwaretype_t ftype;
|
||||
int id;
|
||||
uint32_t devOffset; /* Offset of image relative to one sector into bootpart*/
|
||||
uint32_t len;
|
||||
uint32_t addr;
|
||||
uint32_t entryOffset;
|
||||
uint32_t chksum;
|
||||
uint32_t vers;
|
||||
uint32_t loadAddr;
|
||||
};
|
||||
|
||||
/* A fake partition type - DOS partition tables can't include HFS partitions */
|
||||
#define PARTTYPE_HFS 0xffff
|
||||
|
||||
struct partinfo_t {
|
||||
uint32_t start; /* first sector (LBA) */
|
||||
uint32_t size; /* number of sectors */
|
||||
uint32_t type;
|
||||
};
|
||||
|
||||
struct ipod_t {
|
||||
unsigned char* sectorbuf;
|
||||
HANDLE dh;
|
||||
char diskname[4096];
|
||||
int sector_size;
|
||||
int sectors_per_track;
|
||||
int num_heads;
|
||||
struct ipod_directory_t ipod_directory[MAX_IMAGES];
|
||||
int nimages;
|
||||
int ososimage;
|
||||
off_t diroffset;
|
||||
off_t start; /* Offset in bytes of firmware partition from start of disk */
|
||||
off_t fwoffset; /* Offset in bytes of start of firmware images from start of disk */
|
||||
struct partinfo_t pinfo[4];
|
||||
int modelnum;
|
||||
char* modelname;
|
||||
char* modelstr;
|
||||
char* targetname;
|
||||
int macpod;
|
||||
char* xmlinfo; /* The XML Device Information (if available) */
|
||||
int xmlinfo_len;
|
||||
int ramsize; /* The amount of RAM in the ipod (if available) */
|
||||
#ifdef WITH_BOOTOBJS
|
||||
unsigned char* bootloader;
|
||||
int bootloader_len;
|
||||
#endif
|
||||
};
|
||||
|
||||
void ipod_print_error(char* msg);
|
||||
int ipod_open(struct ipod_t* ipod, int silent);
|
||||
int ipod_reopen_rw(struct ipod_t* ipod);
|
||||
int ipod_close(struct ipod_t* ipod);
|
||||
int ipod_seek(struct ipod_t* ipod, unsigned long pos);
|
||||
int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
|
||||
unsigned char* buf, int bufsize);
|
||||
ssize_t ipod_read(struct ipod_t* ipod, int nbytes);
|
||||
ssize_t ipod_write(struct ipod_t* ipod, int nbytes);
|
||||
int ipod_alloc_buffer(struct ipod_t* ipod, int bufsize);
|
||||
int ipod_dealloc_buffer(struct ipod_t* ipod);
|
||||
|
||||
/* In fat32format.c */
|
||||
int format_partition(struct ipod_t* ipod, int partition);
|
||||
|
||||
#endif
|
||||
2350
utils/ipodpatcher/ipodpatcher.c
Normal file
2350
utils/ipodpatcher/ipodpatcher.c
Normal file
File diff suppressed because it is too large
Load diff
84
utils/ipodpatcher/ipodpatcher.h
Normal file
84
utils/ipodpatcher/ipodpatcher.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2007 Dave Chapman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef IPODPATCHER_H
|
||||
#define IPODPATCHER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ipodio.h"
|
||||
|
||||
/* exit codes */
|
||||
#define IPOD_OK 0
|
||||
#define IPOD_WRONG_ARGUMENTS 1
|
||||
#define IPOD_OPEN_INFILE_FAILED 2
|
||||
#define IPOD_PARTITION_ERROR 3
|
||||
#define IPOD_OPEN_OUTFILE_FAILED 4
|
||||
#define IPOD_CANNOT_REOPEN 5
|
||||
#define IPOD_ACCESS_DENIED 10
|
||||
#define IPOD_NOT_FOUND 11
|
||||
#define IPOD_WRONG_DEVICE_COUNT 12
|
||||
#define IPOD_IMAGE_ERROR 13
|
||||
#define IPOD_DUMP_FAILED 14
|
||||
#define IPOD_MULTIPLE_DEVICES 15
|
||||
#define IPOD_WRONG_TYPE 16
|
||||
#define IPOD_UNKNOWN_FW_VERSION -1
|
||||
|
||||
/* Size of buffer for disk I/O - 8MB is large enough for any version
|
||||
of the Apple firmware, but not the Nano's RSRC image. */
|
||||
#define BUFFER_SIZE 8*1024*1024
|
||||
|
||||
extern int ipod_verbose;
|
||||
|
||||
#define FILETYPE_DOT_IPOD 0
|
||||
#define FILETYPE_DOT_BIN 1
|
||||
#ifdef WITH_BOOTOBJS
|
||||
#define FILETYPE_INTERNAL 2
|
||||
#endif
|
||||
|
||||
char* get_parttype(unsigned int pt);
|
||||
int read_partinfo(struct ipod_t* ipod, int silent);
|
||||
int read_partition(struct ipod_t* ipod, int outfile);
|
||||
int write_partition(struct ipod_t* ipod, int infile);
|
||||
int diskmove(struct ipod_t* ipod, int delta);
|
||||
int add_bootloader(struct ipod_t* ipod, char* filename, int type);
|
||||
int delete_bootloader(struct ipod_t* ipod);
|
||||
int write_firmware(struct ipod_t* ipod, char* filename, int type);
|
||||
int read_firmware(struct ipod_t* ipod, char* filename, int type);
|
||||
int read_directory(struct ipod_t* ipod);
|
||||
int list_images(struct ipod_t* ipod);
|
||||
int getmodel(struct ipod_t* ipod, int ipod_version);
|
||||
int ipod_scan(struct ipod_t* ipod);
|
||||
int write_dos_partition_table(struct ipod_t* ipod);
|
||||
int ipod_get_xmlinfo(struct ipod_t* ipod);
|
||||
void ipod_get_ramsize(struct ipod_t* ipod);
|
||||
int read_aupd(struct ipod_t* ipod, char* filename);
|
||||
int write_aupd(struct ipod_t* ipod, char* filename);
|
||||
off_t filesize(int fd);
|
||||
int ipod_has_bootloader(struct ipod_t* ipod);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
13
utils/ipodpatcher/ipodpatcher.manifest
Normal file
13
utils/ipodpatcher/ipodpatcher.manifest
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="ipodpatcher.exe" type="win32"/>
|
||||
|
||||
<!-- Identify the application security requirements. -->
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="requireAdministrator"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
</assembly>
|
||||
47
utils/ipodpatcher/ipodpatcher.pro
Normal file
47
utils/ipodpatcher/ipodpatcher.pro
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#
|
||||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
#
|
||||
# All files in this archive are subject to the GNU General Public License.
|
||||
# See the file COPYING in the source tree root for full license agreement.
|
||||
#
|
||||
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
# KIND, either express or implied.
|
||||
#
|
||||
|
||||
TEMPLATE = app
|
||||
TARGET = ipodpatcher
|
||||
QT -= core
|
||||
|
||||
SOURCES += \
|
||||
main.c \
|
||||
ipodpatcher.c \
|
||||
ipodio-posix.c \
|
||||
ipodio-win32-scsi.c \
|
||||
ipodio-win32.c \
|
||||
fat32format.c \
|
||||
arc4.c \
|
||||
|
||||
HEADERS += \
|
||||
arc4.h \
|
||||
ipodio.h \
|
||||
ipodpatcher.h \
|
||||
parttypes.h \
|
||||
|
||||
DEFINES += RELEASE=1 _LARGEFILE64_SOURCE
|
||||
|
||||
RC_FILE = ipodpatcher.rc
|
||||
|
||||
macx {
|
||||
LIBS += -framework CoreFoundation -framework IOKit
|
||||
}
|
||||
|
||||
|
||||
unix {
|
||||
target.path = /usr/local/bin
|
||||
INSTALLS += target
|
||||
}
|
||||
1
utils/ipodpatcher/ipodpatcher.rc
Normal file
1
utils/ipodpatcher/ipodpatcher.rc
Normal file
|
|
@ -0,0 +1 @@
|
|||
1 24 MOVEABLE PURE "ipodpatcher.manifest"
|
||||
622
utils/ipodpatcher/main.c
Normal file
622
utils/ipodpatcher/main.c
Normal file
|
|
@ -0,0 +1,622 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2007 Dave Chapman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "ipodpatcher.h"
|
||||
#include "ipodio.h"
|
||||
|
||||
#ifdef RELEASE
|
||||
#undef VERSION
|
||||
#define VERSION "5.0 with v4.0 bootloaders (v1.0 for 2nd Gen Nano)"
|
||||
#endif
|
||||
|
||||
|
||||
enum {
|
||||
NONE,
|
||||
#ifdef WITH_BOOTOBJS
|
||||
INSTALL,
|
||||
#endif
|
||||
INTERACTIVE,
|
||||
SHOW_INFO,
|
||||
LIST_IMAGES,
|
||||
DELETE_BOOTLOADER,
|
||||
ADD_BOOTLOADER,
|
||||
READ_FIRMWARE,
|
||||
WRITE_FIRMWARE,
|
||||
READ_AUPD,
|
||||
WRITE_AUPD,
|
||||
READ_PARTITION,
|
||||
WRITE_PARTITION,
|
||||
FORMAT_PARTITION,
|
||||
DUMP_XML,
|
||||
CONVERT_TO_FAT32
|
||||
};
|
||||
|
||||
void print_macpod_warning(void)
|
||||
{
|
||||
printf("[INFO] ************************************************************************\n");
|
||||
printf("[INFO] *** WARNING FOR ROCKBOX USERS\n");
|
||||
printf("[INFO] *** You must convert this ipod to FAT32 format (aka a \"winpod\")\n");
|
||||
printf("[INFO] *** if you want to run Rockbox. Rockbox WILL NOT work on this ipod.\n");
|
||||
printf("[INFO] *** See http://www.rockbox.org/wiki/IpodConversionToFAT32\n");
|
||||
printf("[INFO] ************************************************************************\n");
|
||||
}
|
||||
|
||||
void print_usage(void)
|
||||
{
|
||||
fprintf(stderr,"Usage: ipodpatcher --scan\n");
|
||||
#ifdef __WIN32__
|
||||
fprintf(stderr," or ipodpatcher [DISKNO] [action]\n");
|
||||
#else
|
||||
fprintf(stderr," or ipodpatcher [device] [action]\n");
|
||||
#endif
|
||||
fprintf(stderr,"\n");
|
||||
fprintf(stderr,"Where [action] is one of the following options:\n");
|
||||
#ifdef WITH_BOOTOBJS
|
||||
fprintf(stderr," --install\n");
|
||||
#endif
|
||||
fprintf(stderr," -l, --list\n");
|
||||
fprintf(stderr," -r, --read-partition bootpartition.bin\n");
|
||||
fprintf(stderr," -w, --write-partition bootpartition.bin\n");
|
||||
fprintf(stderr," -rf, --read-firmware filename.ipod[x]\n");
|
||||
fprintf(stderr," -rfb, --read-firmware-bin filename.bin\n");
|
||||
fprintf(stderr," -wf, --write-firmware filename.ipod[x]\n");
|
||||
fprintf(stderr," -wfb, --write-firmware-bin filename.bin\n");
|
||||
#ifdef WITH_BOOTOBJS
|
||||
fprintf(stderr," -we, --write-embedded\n");
|
||||
#endif
|
||||
fprintf(stderr," -a, --add-bootloader filename.ipod[x]\n");
|
||||
fprintf(stderr," -ab, --add-bootloader-bin filename.bin\n");
|
||||
fprintf(stderr," -d, --delete-bootloader\n");
|
||||
fprintf(stderr," -f, --format\n");
|
||||
fprintf(stderr," -c, --convert\n");
|
||||
fprintf(stderr," --read-aupd filename.bin\n");
|
||||
fprintf(stderr," --write-aupd filename.bin\n");
|
||||
fprintf(stderr," -x --dump-xml filename.xml\n");
|
||||
fprintf(stderr,"\n");
|
||||
|
||||
fprintf(stderr,"The .ipodx extension is used for encrypted images for the 2nd Gen Nano.\n\n");
|
||||
|
||||
#ifdef __WIN32__
|
||||
fprintf(stderr,"DISKNO is the number (e.g. 2) Windows has assigned to your ipod's hard disk.\n");
|
||||
fprintf(stderr,"The first hard disk in your computer (i.e. C:\\) will be disk 0, the next disk\n");
|
||||
fprintf(stderr,"will be disk 1 etc. ipodpatcher will refuse to access a disk unless it\n");
|
||||
fprintf(stderr,"can identify it as being an ipod.\n");
|
||||
fprintf(stderr,"\n");
|
||||
#else
|
||||
#if defined(linux) || defined (__linux)
|
||||
fprintf(stderr,"\"device\" is the device node (e.g. /dev/sda) assigned to your ipod.\n");
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
fprintf(stderr,"\"device\" is the device node (e.g. /dev/da1) assigned to your ipod.\n");
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
fprintf(stderr,"\"device\" is the device node (e.g. /dev/disk1) assigned to your ipod.\n");
|
||||
#endif
|
||||
fprintf(stderr,"ipodpatcher will refuse to access a disk unless it can identify it as being\n");
|
||||
fprintf(stderr,"an ipod.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void display_partinfo(struct ipod_t* ipod)
|
||||
{
|
||||
int i;
|
||||
double sectors_per_MB = (1024.0*1024.0)/ipod->sector_size;
|
||||
|
||||
printf("[INFO] Part Start Sector End Sector Size (MB) Type\n");
|
||||
for ( i = 0; i < 4; i++ ) {
|
||||
if (ipod->pinfo[i].start != 0) {
|
||||
printf("[INFO] %d %10ld %10ld %10.1f %s (0x%02x)\n",
|
||||
i,
|
||||
(long int)ipod->pinfo[i].start,
|
||||
(long int)ipod->pinfo[i].start+ipod->pinfo[i].size-1,
|
||||
ipod->pinfo[i].size/sectors_per_MB,
|
||||
get_parttype(ipod->pinfo[i].type),
|
||||
(int)ipod->pinfo[i].type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
char yesno[4];
|
||||
int i;
|
||||
int n;
|
||||
int infile, outfile;
|
||||
unsigned int inputsize;
|
||||
char* filename;
|
||||
int action = SHOW_INFO;
|
||||
int type;
|
||||
struct ipod_t ipod;
|
||||
|
||||
fprintf(stderr,"ipodpatcher " VERSION "\n");
|
||||
fprintf(stderr,"(C) Dave Chapman 2006-2009\n");
|
||||
fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n");
|
||||
fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
|
||||
|
||||
if ((argc > 1) && ((strcmp(argv[1],"-h")==0) || (strcmp(argv[1],"--help")==0))) {
|
||||
print_usage();
|
||||
return IPOD_OK;
|
||||
}
|
||||
|
||||
if (ipod_alloc_buffer(&ipod,BUFFER_SIZE) < 0) {
|
||||
fprintf(stderr,"Failed to allocate memory buffer\n");
|
||||
}
|
||||
|
||||
if ((argc > 1) && (strcmp(argv[1],"--scan")==0)) {
|
||||
if (ipod_scan(&ipod) == 0)
|
||||
fprintf(stderr,"[ERR] No ipods found.\n");
|
||||
return IPOD_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* If the first parameter doesn't start with -, then we interpret it as a device */
|
||||
if ((argc > 1) && (argv[1][0] != '-')) {
|
||||
ipod.diskname[0]=0;
|
||||
#ifdef __WIN32__
|
||||
snprintf(ipod.diskname,sizeof(ipod.diskname),"\\\\.\\PhysicalDrive%s",argv[1]);
|
||||
#else
|
||||
strncpy(ipod.diskname,argv[1],sizeof(ipod.diskname));
|
||||
#endif
|
||||
i = 2;
|
||||
} else {
|
||||
/* Autoscan for ipods */
|
||||
n = ipod_scan(&ipod);
|
||||
if (n==0) {
|
||||
fprintf(stderr,"[ERR] No ipods found, aborting\n");
|
||||
fprintf(stderr,"[ERR] Please connect your ipod and ensure it is in disk mode\n");
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
fprintf(stderr,"[ERR] Also ensure that itunes is closed, and that your ipod is not mounted.\n");
|
||||
#elif !defined(__WIN32__)
|
||||
if (geteuid()!=0) {
|
||||
fprintf(stderr,"[ERR] You may also need to run ipodpatcher as root.\n");
|
||||
}
|
||||
#endif
|
||||
fprintf(stderr,"[ERR] Please refer to the Rockbox manual if you continue to have problems.\n");
|
||||
} else if (n > 1) {
|
||||
fprintf(stderr,"[ERR] %d ipods found, aborting\n",n);
|
||||
fprintf(stderr,"[ERR] Please connect only one ipod and re-run ipodpatcher.\n");
|
||||
return IPOD_MULTIPLE_DEVICES;
|
||||
} else if (n == 1 && ipod.macpod) {
|
||||
return IPOD_WRONG_TYPE;
|
||||
}
|
||||
|
||||
if (n != 1) {
|
||||
#ifdef WITH_BOOTOBJS
|
||||
if (argc==1) {
|
||||
printf("\nPress ENTER to exit ipodpatcher :");
|
||||
fgets(yesno,4,stdin);
|
||||
}
|
||||
#endif
|
||||
return IPOD_NOT_FOUND;
|
||||
}
|
||||
|
||||
i = 1;
|
||||
}
|
||||
|
||||
#ifdef WITH_BOOTOBJS
|
||||
action = INTERACTIVE;
|
||||
#else
|
||||
action = NONE;
|
||||
#endif
|
||||
|
||||
while (i < argc) {
|
||||
if ((strcmp(argv[i],"-l")==0) || (strcmp(argv[i],"--list")==0)) {
|
||||
action = LIST_IMAGES;
|
||||
i++;
|
||||
#ifdef WITH_BOOTOBJS
|
||||
} else if (strcmp(argv[i],"--install")==0) {
|
||||
action = INSTALL;
|
||||
i++;
|
||||
#endif
|
||||
} else if ((strcmp(argv[i],"-d")==0) ||
|
||||
(strcmp(argv[i],"--delete-bootloader")==0)) {
|
||||
action = DELETE_BOOTLOADER;
|
||||
i++;
|
||||
} else if ((strcmp(argv[i],"-a")==0) ||
|
||||
(strcmp(argv[i],"--add-bootloader")==0)) {
|
||||
action = ADD_BOOTLOADER;
|
||||
type = FILETYPE_DOT_IPOD;
|
||||
i++;
|
||||
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
|
||||
filename=argv[i];
|
||||
i++;
|
||||
} else if ((strcmp(argv[i],"-ab")==0) ||
|
||||
(strcmp(argv[i],"--add-bootloader-bin")==0)) {
|
||||
action = ADD_BOOTLOADER;
|
||||
type = FILETYPE_DOT_BIN;
|
||||
i++;
|
||||
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
|
||||
filename=argv[i];
|
||||
i++;
|
||||
} else if ((strcmp(argv[i],"-rf")==0) ||
|
||||
(strcmp(argv[i],"--read-firmware")==0)) {
|
||||
action = READ_FIRMWARE;
|
||||
type = FILETYPE_DOT_IPOD;
|
||||
i++;
|
||||
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
|
||||
filename=argv[i];
|
||||
i++;
|
||||
} else if ((strcmp(argv[i],"-rfb")==0) ||
|
||||
(strcmp(argv[i],"--read-firmware-bin")==0)) {
|
||||
action = READ_FIRMWARE;
|
||||
type = FILETYPE_DOT_BIN;
|
||||
i++;
|
||||
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
|
||||
filename=argv[i];
|
||||
i++;
|
||||
#ifdef WITH_BOOTOBJS
|
||||
} else if ((strcmp(argv[i],"-we")==0) ||
|
||||
(strcmp(argv[i],"--write-embedded")==0)) {
|
||||
action = WRITE_FIRMWARE;
|
||||
type = FILETYPE_INTERNAL;
|
||||
filename="[embedded bootloader]"; /* Only displayed for user */
|
||||
i++;
|
||||
#endif
|
||||
} else if ((strcmp(argv[i],"-wf")==0) ||
|
||||
(strcmp(argv[i],"--write-firmware")==0)) {
|
||||
action = WRITE_FIRMWARE;
|
||||
type = FILETYPE_DOT_IPOD;
|
||||
i++;
|
||||
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
|
||||
filename=argv[i];
|
||||
i++;
|
||||
} else if ((strcmp(argv[i],"-wfb")==0) ||
|
||||
(strcmp(argv[i],"--write-firmware-bin")==0)) {
|
||||
action = WRITE_FIRMWARE;
|
||||
type = FILETYPE_DOT_BIN;
|
||||
i++;
|
||||
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
|
||||
filename=argv[i];
|
||||
i++;
|
||||
} else if ((strcmp(argv[i],"-r")==0) ||
|
||||
(strcmp(argv[i],"--read-partition")==0)) {
|
||||
action = READ_PARTITION;
|
||||
i++;
|
||||
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
|
||||
filename=argv[i];
|
||||
i++;
|
||||
} else if ((strcmp(argv[i],"-w")==0) ||
|
||||
(strcmp(argv[i],"--write-partition")==0)) {
|
||||
action = WRITE_PARTITION;
|
||||
i++;
|
||||
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
|
||||
filename=argv[i];
|
||||
i++;
|
||||
} else if ((strcmp(argv[i],"-v")==0) ||
|
||||
(strcmp(argv[i],"--verbose")==0)) {
|
||||
ipod_verbose++;
|
||||
i++;
|
||||
} else if ((strcmp(argv[i],"-f")==0) ||
|
||||
(strcmp(argv[i],"--format")==0)) {
|
||||
action = FORMAT_PARTITION;
|
||||
i++;
|
||||
} else if (strcmp(argv[i],"--read-aupd")==0) {
|
||||
action = READ_AUPD;
|
||||
i++;
|
||||
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
|
||||
filename=argv[i];
|
||||
i++;
|
||||
} else if (strcmp(argv[i],"--write-aupd")==0) {
|
||||
action = WRITE_AUPD;
|
||||
i++;
|
||||
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
|
||||
filename=argv[i];
|
||||
i++;
|
||||
} else if ((strcmp(argv[i],"-x")==0) ||
|
||||
(strcmp(argv[i],"--dump-xml")==0)) {
|
||||
action = DUMP_XML;
|
||||
i++;
|
||||
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
|
||||
filename=argv[i];
|
||||
i++;
|
||||
} else if ((strcmp(argv[i],"-c")==0) ||
|
||||
(strcmp(argv[i],"--convert")==0)) {
|
||||
action = CONVERT_TO_FAT32;
|
||||
i++;
|
||||
} else {
|
||||
print_usage(); return IPOD_WRONG_ARGUMENTS;
|
||||
}
|
||||
}
|
||||
|
||||
if (ipod.diskname[0]==0) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ipod_open(&ipod, 0) < 0) {
|
||||
return IPOD_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
fprintf(stderr,"[INFO] Reading partition table from %s\n",ipod.diskname);
|
||||
fprintf(stderr,"[INFO] Sector size is %d bytes\n",ipod.sector_size);
|
||||
|
||||
if (read_partinfo(&ipod,0) < 0) {
|
||||
return IPOD_PARTITION_ERROR;
|
||||
}
|
||||
|
||||
display_partinfo(&ipod);
|
||||
|
||||
if (ipod.pinfo[0].start==0) {
|
||||
fprintf(stderr,"[ERR] No partition 0 on disk:\n");
|
||||
display_partinfo(&ipod);
|
||||
return IPOD_PARTITION_ERROR;
|
||||
}
|
||||
|
||||
read_directory(&ipod);
|
||||
|
||||
if (ipod.nimages <= 0) {
|
||||
fprintf(stderr,"[ERR] Failed to read firmware directory - nimages=%d\n",ipod.nimages);
|
||||
return IPOD_IMAGE_ERROR;
|
||||
}
|
||||
|
||||
if (getmodel(&ipod,(ipod.ipod_directory[ipod.ososimage].vers>>8)) < 0) {
|
||||
fprintf(stderr,"[ERR] Unknown version number in firmware (%08x)\n",
|
||||
ipod.ipod_directory[ipod.ososimage].vers);
|
||||
return IPOD_UNKNOWN_FW_VERSION;
|
||||
}
|
||||
|
||||
#ifdef __WIN32__
|
||||
/* Windows requires the ipod in R/W mode for SCSI Inquiry */
|
||||
if (ipod_reopen_rw(&ipod) < 0) {
|
||||
return IPOD_CANNOT_REOPEN;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Read the XML info, and if successful, look for the ramsize
|
||||
(only available for some models - set to 0 if not known) */
|
||||
|
||||
ipod.ramsize = 0;
|
||||
|
||||
if (ipod_get_xmlinfo(&ipod) == 0) {
|
||||
ipod_get_ramsize(&ipod);
|
||||
}
|
||||
|
||||
printf("[INFO] Ipod model: %s ",ipod.modelstr);
|
||||
if (ipod.ramsize > 0) { printf("(%dMB RAM) ",ipod.ramsize); }
|
||||
printf("(\"%s\")\n",ipod.macpod ? "macpod" : "winpod");
|
||||
|
||||
if (ipod.macpod) {
|
||||
print_macpod_warning();
|
||||
}
|
||||
|
||||
if (action==LIST_IMAGES) {
|
||||
list_images(&ipod);
|
||||
#ifdef WITH_BOOTOBJS
|
||||
} else if (action==INTERACTIVE) {
|
||||
|
||||
printf("Enter i to install the Rockbox bootloader, u to uninstall\n or c to cancel and do nothing (i/u/c) :");
|
||||
|
||||
if (fgets(yesno,4,stdin)) {
|
||||
if (yesno[0]=='i') {
|
||||
if (ipod_reopen_rw(&ipod) < 0) {
|
||||
return IPOD_CANNOT_REOPEN;
|
||||
}
|
||||
|
||||
if (add_bootloader(&ipod, NULL, FILETYPE_INTERNAL)==0) {
|
||||
fprintf(stderr,"[INFO] Bootloader installed successfully.\n");
|
||||
} else {
|
||||
fprintf(stderr,"[ERR] --install failed.\n");
|
||||
}
|
||||
} else if (yesno[0]=='u') {
|
||||
if (ipod_reopen_rw(&ipod) < 0) {
|
||||
return IPOD_CANNOT_REOPEN;
|
||||
}
|
||||
|
||||
if (delete_bootloader(&ipod)==0) {
|
||||
fprintf(stderr,"[INFO] Bootloader removed.\n");
|
||||
} else {
|
||||
fprintf(stderr,"[ERR] Bootloader removal failed.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else if (action==DELETE_BOOTLOADER) {
|
||||
if (ipod_reopen_rw(&ipod) < 0) {
|
||||
return IPOD_CANNOT_REOPEN;
|
||||
}
|
||||
|
||||
if (ipod.ipod_directory[0].entryOffset==0) {
|
||||
fprintf(stderr,"[ERR] No bootloader detected.\n");
|
||||
} else {
|
||||
if (delete_bootloader(&ipod)==0) {
|
||||
fprintf(stderr,"[INFO] Bootloader removed.\n");
|
||||
} else {
|
||||
fprintf(stderr,"[ERR] --delete-bootloader failed.\n");
|
||||
}
|
||||
}
|
||||
} else if (action==ADD_BOOTLOADER) {
|
||||
if (ipod_reopen_rw(&ipod) < 0) {
|
||||
return IPOD_CANNOT_REOPEN;
|
||||
}
|
||||
|
||||
if (add_bootloader(&ipod, filename, type)==0) {
|
||||
fprintf(stderr,"[INFO] Bootloader %s written to device.\n",filename);
|
||||
} else {
|
||||
fprintf(stderr,"[ERR] --add-bootloader failed.\n");
|
||||
}
|
||||
#ifdef WITH_BOOTOBJS
|
||||
} else if (action==INSTALL) {
|
||||
if (ipod_reopen_rw(&ipod) < 0) {
|
||||
return IPOD_CANNOT_REOPEN;
|
||||
}
|
||||
|
||||
if (add_bootloader(&ipod, NULL, FILETYPE_INTERNAL)==0) {
|
||||
fprintf(stderr,"[INFO] Bootloader installed successfully.\n");
|
||||
} else {
|
||||
fprintf(stderr,"[ERR] --install failed.\n");
|
||||
}
|
||||
#endif
|
||||
} else if (action==WRITE_FIRMWARE) {
|
||||
if (ipod_reopen_rw(&ipod) < 0) {
|
||||
return IPOD_CANNOT_REOPEN;
|
||||
}
|
||||
|
||||
if (write_firmware(&ipod, filename,type)==0) {
|
||||
fprintf(stderr,"[INFO] Firmware %s written to device.\n",filename);
|
||||
} else {
|
||||
fprintf(stderr,"[ERR] --write-firmware failed.\n");
|
||||
}
|
||||
} else if (action==READ_FIRMWARE) {
|
||||
if (read_firmware(&ipod, filename, type)==0) {
|
||||
fprintf(stderr,"[INFO] Firmware read to file %s.\n",filename);
|
||||
} else {
|
||||
fprintf(stderr,"[ERR] --read-firmware failed.\n");
|
||||
}
|
||||
} else if (action==READ_AUPD) {
|
||||
if (read_aupd(&ipod, filename)==0) {
|
||||
fprintf(stderr,"[INFO] AUPD image read to file %s.\n",filename);
|
||||
} else {
|
||||
fprintf(stderr,"[ERR] --read-aupd failed.\n");
|
||||
}
|
||||
} else if (action==WRITE_AUPD) {
|
||||
if (ipod_reopen_rw(&ipod) < 0) {
|
||||
return IPOD_CANNOT_REOPEN;
|
||||
}
|
||||
|
||||
if (write_aupd(&ipod, filename)==0) {
|
||||
fprintf(stderr,"[INFO] AUPD image %s written to device.\n",filename);
|
||||
} else {
|
||||
fprintf(stderr,"[ERR] --write-aupd failed.\n");
|
||||
}
|
||||
} else if (action==DUMP_XML) {
|
||||
if (ipod.xmlinfo == NULL) {
|
||||
fprintf(stderr,"[ERR] No XML to write\n");
|
||||
return IPOD_DUMP_FAILED;
|
||||
}
|
||||
|
||||
outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE);
|
||||
if (outfile < 0) {
|
||||
perror(filename);
|
||||
return IPOD_OPEN_OUTFILE_FAILED;
|
||||
}
|
||||
|
||||
if (write(outfile, ipod.xmlinfo, ipod.xmlinfo_len) < 0) {
|
||||
fprintf(stderr,"[ERR] --dump-xml failed.\n");
|
||||
} else {
|
||||
fprintf(stderr,"[INFO] XML info written to %s.\n",filename);
|
||||
}
|
||||
close(outfile);
|
||||
} else if (action==READ_PARTITION) {
|
||||
outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE);
|
||||
if (outfile < 0) {
|
||||
perror(filename);
|
||||
return IPOD_OPEN_OUTFILE_FAILED;
|
||||
}
|
||||
|
||||
if (read_partition(&ipod, outfile) < 0) {
|
||||
fprintf(stderr,"[ERR] --read-partition failed.\n");
|
||||
} else {
|
||||
fprintf(stderr,"[INFO] Partition extracted to %s.\n",filename);
|
||||
}
|
||||
close(outfile);
|
||||
} else if (action==WRITE_PARTITION) {
|
||||
if (ipod_reopen_rw(&ipod) < 0) {
|
||||
return IPOD_CANNOT_REOPEN;
|
||||
}
|
||||
|
||||
infile = open(filename,O_RDONLY|O_BINARY);
|
||||
if (infile < 0) {
|
||||
perror(filename);
|
||||
return IPOD_OPEN_INFILE_FAILED;
|
||||
}
|
||||
|
||||
/* Check filesize is <= partition size */
|
||||
inputsize=filesize(infile);
|
||||
if (inputsize > 0) {
|
||||
if (inputsize <= (ipod.pinfo[0].size*ipod.sector_size)) {
|
||||
fprintf(stderr,"[INFO] Input file is %u bytes\n",inputsize);
|
||||
if (write_partition(&ipod,infile) < 0) {
|
||||
fprintf(stderr,"[ERR] --write-partition failed.\n");
|
||||
} else {
|
||||
fprintf(stderr,"[INFO] %s restored to partition\n",filename);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr,"[ERR] File is too large for firmware partition, aborting.\n");
|
||||
}
|
||||
}
|
||||
|
||||
close(infile);
|
||||
} else if (action==FORMAT_PARTITION) {
|
||||
printf("WARNING!!! YOU ARE ABOUT TO USE AN EXPERIMENTAL FEATURE.\n");
|
||||
printf("ALL DATA ON YOUR IPOD WILL BE ERASED.\n");
|
||||
printf("Are you sure you want to format your ipod? (y/n):");
|
||||
|
||||
if (fgets(yesno,4,stdin)) {
|
||||
if (yesno[0]=='y') {
|
||||
if (ipod_reopen_rw(&ipod) < 0) {
|
||||
return IPOD_CANNOT_REOPEN;
|
||||
}
|
||||
|
||||
if (format_partition(&ipod,1) < 0) {
|
||||
fprintf(stderr,"[ERR] Format failed.\n");
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr,"[INFO] Format cancelled.\n");
|
||||
}
|
||||
}
|
||||
} else if (action==CONVERT_TO_FAT32) {
|
||||
if (!ipod.macpod) {
|
||||
printf("[ERR] Ipod is already FAT32, aborting\n");
|
||||
} else {
|
||||
printf("WARNING!!! YOU ARE ABOUT TO USE AN EXPERIMENTAL FEATURE.\n");
|
||||
printf("ALL DATA ON YOUR IPOD WILL BE ERASED.\n");
|
||||
printf("Are you sure you want to convert your ipod to FAT32? (y/n):");
|
||||
|
||||
if (fgets(yesno,4,stdin)) {
|
||||
if (yesno[0]=='y') {
|
||||
if (ipod_reopen_rw(&ipod) < 0) {
|
||||
return IPOD_CANNOT_REOPEN;
|
||||
}
|
||||
|
||||
if (write_dos_partition_table(&ipod) < 0) {
|
||||
fprintf(stderr,"[ERR] Partition conversion failed.\n");
|
||||
}
|
||||
|
||||
if (format_partition(&ipod,1) < 0) {
|
||||
fprintf(stderr,"[ERR] Format failed.\n");
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr,"[INFO] Format cancelled.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ipod_close(&ipod);
|
||||
|
||||
#ifdef WITH_BOOTOBJS
|
||||
if (action==INTERACTIVE) {
|
||||
printf("Press ENTER to exit ipodpatcher :");
|
||||
fgets(yesno,4,stdin);
|
||||
}
|
||||
#endif
|
||||
|
||||
ipod_dealloc_buffer(&ipod);
|
||||
return IPOD_OK;
|
||||
}
|
||||
109
utils/ipodpatcher/parttypes.h
Normal file
109
utils/ipodpatcher/parttypes.h
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/* DOS partition types - taken from fdisk */
|
||||
|
||||
struct parttype {
|
||||
unsigned char type;
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct parttype parttypes[] = {
|
||||
{0x00, "Empty"},
|
||||
{0x01, "FAT12"},
|
||||
{0x02, "XENIX root"},
|
||||
{0x03, "XENIX usr"},
|
||||
{0x04, "FAT16 <32M"},
|
||||
{0x05, "Extended"}, /* DOS 3.3+ extended partition */
|
||||
{0x06, "FAT16"}, /* DOS 16-bit >=32M */
|
||||
{0x07, "HPFS/NTFS"}, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
|
||||
{0x08, "AIX"}, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
|
||||
{0x09, "AIX bootable"}, /* AIX data or Coherent */
|
||||
{0x0a, "OS/2 Boot Manager"},/* OS/2 Boot Manager */
|
||||
{0x0b, "W95 FAT32"},
|
||||
{0x0c, "W95 FAT32 (LBA)"},/* LBA really is `Extended Int 13h' */
|
||||
{0x0e, "W95 FAT16 (LBA)"},
|
||||
{0x0f, "W95 Ext'd (LBA)"},
|
||||
{0x10, "OPUS"},
|
||||
{0x11, "Hidden FAT12"},
|
||||
{0x12, "Compaq diagnostics"},
|
||||
{0x14, "Hidden FAT16 <32M"},
|
||||
{0x16, "Hidden FAT16"},
|
||||
{0x17, "Hidden HPFS/NTFS"},
|
||||
{0x18, "AST SmartSleep"},
|
||||
{0x1b, "Hidden W95 FAT32"},
|
||||
{0x1c, "Hidden W95 FAT32 (LBA)"},
|
||||
{0x1e, "Hidden W95 FAT16 (LBA)"},
|
||||
{0x24, "NEC DOS"},
|
||||
{0x39, "Plan 9"},
|
||||
{0x3c, "PartitionMagic recovery"},
|
||||
{0x40, "Venix 80286"},
|
||||
{0x41, "PPC PReP Boot"},
|
||||
{0x42, "SFS"},
|
||||
{0x4d, "QNX4.x"},
|
||||
{0x4e, "QNX4.x 2nd part"},
|
||||
{0x4f, "QNX4.x 3rd part"},
|
||||
{0x50, "OnTrack DM"},
|
||||
{0x51, "OnTrack DM6 Aux1"}, /* (or Novell) */
|
||||
{0x52, "CP/M"}, /* CP/M or Microport SysV/AT */
|
||||
{0x53, "OnTrack DM6 Aux3"},
|
||||
{0x54, "OnTrackDM6"},
|
||||
{0x55, "EZ-Drive"},
|
||||
{0x56, "Golden Bow"},
|
||||
{0x5c, "Priam Edisk"},
|
||||
{0x61, "SpeedStor"},
|
||||
{0x63, "GNU HURD or SysV"}, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
|
||||
{0x64, "Novell Netware 286"},
|
||||
{0x65, "Novell Netware 386"},
|
||||
{0x70, "DiskSecure Multi-Boot"},
|
||||
{0x75, "PC/IX"},
|
||||
{0x80, "Old Minix"}, /* Minix 1.4a and earlier */
|
||||
{0x81, "Minix / old Linux"},/* Minix 1.4b and later */
|
||||
{0x82, "Linux swap / Solaris"},
|
||||
{0x83, "Linux"},
|
||||
{0x84, "OS/2 hidden C: drive"},
|
||||
{0x85, "Linux extended"},
|
||||
{0x86, "NTFS volume set"},
|
||||
{0x87, "NTFS volume set"},
|
||||
{0x88, "Linux plaintext"},
|
||||
{0x8e, "Linux LVM"},
|
||||
{0x93, "Amoeba"},
|
||||
{0x94, "Amoeba BBT"}, /* (bad block table) */
|
||||
{0x9f, "BSD/OS"}, /* BSDI */
|
||||
{0xa0, "IBM Thinkpad hibernation"},
|
||||
{0xa5, "FreeBSD"}, /* various BSD flavours */
|
||||
{0xa6, "OpenBSD"},
|
||||
{0xa7, "NeXTSTEP"},
|
||||
{0xa8, "Darwin UFS"},
|
||||
{0xa9, "NetBSD"},
|
||||
{0xab, "Darwin boot"},
|
||||
{0xb7, "BSDI fs"},
|
||||
{0xb8, "BSDI swap"},
|
||||
{0xbb, "Boot Wizard hidden"},
|
||||
{0xbe, "Solaris boot"},
|
||||
{0xbf, "Solaris"},
|
||||
{0xc1, "DRDOS/sec (FAT-12)"},
|
||||
{0xc4, "DRDOS/sec (FAT-16 < 32M)"},
|
||||
{0xc6, "DRDOS/sec (FAT-16)"},
|
||||
{0xc7, "Syrinx"},
|
||||
{0xda, "Non-FS data"},
|
||||
{0xdb, "CP/M / CTOS / ..."},/* CP/M or Concurrent CP/M or
|
||||
Concurrent DOS or CTOS */
|
||||
{0xde, "Dell Utility"}, /* Dell PowerEdge Server utilities */
|
||||
{0xdf, "BootIt"}, /* BootIt EMBRM */
|
||||
{0xe1, "DOS access"}, /* DOS access or SpeedStor 12-bit FAT
|
||||
extended partition */
|
||||
{0xe3, "DOS R/O"}, /* DOS R/O or SpeedStor */
|
||||
{0xe4, "SpeedStor"}, /* SpeedStor 16-bit FAT extended
|
||||
partition < 1024 cyl. */
|
||||
{0xeb, "BeOS fs"},
|
||||
{0xee, "EFI GPT"}, /* Intel EFI GUID Partition Table */
|
||||
{0xef, "EFI (FAT-12/16/32)"},/* Intel EFI System Partition */
|
||||
{0xf0, "Linux/PA-RISC boot"},/* Linux/PA-RISC boot loader */
|
||||
{0xf1, "SpeedStor"},
|
||||
{0xf4, "SpeedStor"}, /* SpeedStor large partition */
|
||||
{0xf2, "DOS secondary"}, /* DOS 3.3+ secondary */
|
||||
{0xfd, "Linux raid autodetect"},/* New (2.2.x) raid partition with
|
||||
autodetect using persistent
|
||||
superblock */
|
||||
{0xfe, "LANstep"}, /* SpeedStor >1024 cyl. or LANstep */
|
||||
{0xff, "BBT"}, /* Xenix Bad Block Table */
|
||||
{ 0, 0 }
|
||||
};
|
||||
47
utils/jztool/Makefile
Normal file
47
utils/jztool/Makefile
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
|
||||
CFLAGS += -Wall -Wextra -Iinclude -I../../tools/ucl/include -I../../lib/microtar/src
|
||||
OUTPUT = jztool
|
||||
|
||||
ifdef RELEASE
|
||||
CFLAGS += -Os -DNDEBUG
|
||||
else
|
||||
CFLAGS += -O0 -ggdb
|
||||
endif
|
||||
|
||||
LIBSOURCES := src/buffer.c src/context.c src/device_info.c \
|
||||
src/identify_file.c src/ucl_unpack.c src/usb.c src/x1000.c
|
||||
SOURCES := $(LIBSOURCES) jztool.c
|
||||
EXTRADEPS := libucl.a libmicrotar.a
|
||||
|
||||
CPPDEFINES := $(shell echo foo | $(CROSS)$(CC) -dM -E -)
|
||||
|
||||
ifeq ($(findstring WIN32,$(CPPDEFINES)),WIN32)
|
||||
# TODO: support Windows
|
||||
else
|
||||
ifeq ($(findstring APPLE,$(CPPDEFINES)),APPLE)
|
||||
# Mac, tested on x86 only -- may need to adjust paths if building on ARM.
|
||||
# paths should work with homebrew libusb.
|
||||
LIBUSB_CFLAGS ?= -I/usr/local/include/libusb-1.0
|
||||
ifdef STATIC
|
||||
LIBUSB_LDOPTS ?= /usr/local/lib/libusb-1.0.a -framework IOKit -framework CoreFoundation
|
||||
else
|
||||
LIBUSB_LDOPTS ?= -L/usr/local/lib -lusb-1.0
|
||||
endif
|
||||
else
|
||||
# Linux; note for static builds you need to build a copy of libusb without
|
||||
# udev support and specify the includes / libs manually
|
||||
LIBUSB_CFLAGS ?= `pkg-config --cflags libusb-1.0`
|
||||
LIBUSB_LDOPTS ?= `pkg-config --libs libusb-1.0`
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS += $(LIBUSB_CFLAGS)
|
||||
LDOPTS += $(LIBUSB_LDOPTS)
|
||||
|
||||
include ../libtools.make
|
||||
135
utils/jztool/README.md
Normal file
135
utils/jztool/README.md
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
# jztool -- Ingenic device utility & bootloader installer
|
||||
|
||||
The `jztool` utility can help install, backup, and restore the bootloader on
|
||||
Rockbox players based on a supported Ingenic SoC (currently only the X1000).
|
||||
|
||||
## Running jztool
|
||||
|
||||
### Getting a bootloader
|
||||
|
||||
To use `jztool` you need to compile or download a bootloader for your player.
|
||||
It's recommended to use only official released bootloaders, since bootloaders
|
||||
compiled from Git are not tested and might be buggy.
|
||||
|
||||
You can download released bootloaders from <https://download.rockbox.org/>.
|
||||
|
||||
The bootloader file is named after the target: for example, the FiiO M3K
|
||||
bootloader is called `bootloader.m3k`. The FiiO M3K is used as an example
|
||||
here, but the instructions apply to all X1000-based players.
|
||||
|
||||
Use `jztool --help` to find out the model name of your player.
|
||||
|
||||
### Entering USB boot mode
|
||||
|
||||
USB boot mode is a low-level mode provided by the CPU which allows a computer
|
||||
to load firmware onto the device. You need to put your player into this mode
|
||||
manually before using `jztool` (unfortunately, it can't be done automatically.)
|
||||
|
||||
To connect the player in USB boot mode, follow these steps:
|
||||
|
||||
1. Ensure the player is fully powered off.
|
||||
2. Plug one end of the USB cable into your player.
|
||||
3. Hold down your player's USB boot key (see below).
|
||||
4. Plug the other end of the USB cable into your computer.
|
||||
5. Let go of the USB boot key.
|
||||
|
||||
The USB boot key depends on your player:
|
||||
|
||||
- FiiO M3K: Volume Down
|
||||
- Shanling Q1: Play
|
||||
- Eros Q: Menu
|
||||
|
||||
### Linux/Mac
|
||||
|
||||
Run the following command in a terminal. Note that on Linux, you will need to
|
||||
have root access to allow libusb to access the USB device.
|
||||
|
||||
```sh
|
||||
# Linux / Mac
|
||||
# NOTE: root permissions are required on Linux to access the USB device
|
||||
# eg. with 'sudo' or 'su -c' depending on your distro.
|
||||
$ ./jztool fiiom3k load bootloader.m3k
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
To allow `jztool` access to your player in USB boot mode, you need to install
|
||||
the WinUSB driver. The recommended way to install it is using Zadig, which
|
||||
may be downloaded from its homepage <https://zadig.akeo.ie>. Please note
|
||||
this is 3rd party software not maintained or supported by Rockbox developers.
|
||||
(Zadig will require administrator access on the machine you are using.)
|
||||
|
||||
When running Zadig you must select the WinUSB driver; the other driver options
|
||||
will not work properly with `jztool`. You will have to select the correct USB
|
||||
device in Zadig. All X1000-based players use the same USB ID while in USB boot
|
||||
mode, listed below. NOTE: the device name may show only as "X" and a hollow
|
||||
square in Zadig. The IDs will not change, so those are the most reliable way
|
||||
to confirm you have selected the correct device.
|
||||
|
||||
```
|
||||
Name: Ingenic Semiconductor Co.,Ltd X1000
|
||||
USB ID: A108 1000
|
||||
```
|
||||
|
||||
Assuming you installed the WinUSB driver successfully, open a command prompt
|
||||
in the folder containing `jztool`. Administrator access is not required for
|
||||
this step.
|
||||
|
||||
Type the following command to load the Rockbox bootloader:
|
||||
|
||||
```sh
|
||||
# Windows
|
||||
$ jztool.exe fiiom3k load bootloader.m3k
|
||||
```
|
||||
|
||||
## Using the recovery menu
|
||||
|
||||
If `jztool` runs successfully your player will display the Rockbox bootloader's
|
||||
recovery menu. If you want to permanently install Rockbox to your device, copy
|
||||
the bootloader file you downloaded to the root of your SD card, insert the SD
|
||||
card to your player, and choose "Install/update bootloader" from the menu.
|
||||
|
||||
It is _highly_ recommended that you take a backup of your existing bootloader
|
||||
in case of any trouble -- choose "Backup bootloader" from the recovery menu.
|
||||
The backup file is called `PLAYER-boot.bin`, where `PLAYER` is the model name.
|
||||
(Example: `fiiom3k-boot.bin`.)
|
||||
|
||||
You can restore the backup later by putting it on the root of your SD card and
|
||||
selecting "Restor bootloader" in the recovery menu.
|
||||
|
||||
After installing the Rockbox bootloader, you can access the recovery menu by
|
||||
holding a key while booting:
|
||||
|
||||
- FiiO M3K: Volume Up
|
||||
- Shanling Q1: Next (button on the lower left)
|
||||
- Eros Q: Volume Up
|
||||
|
||||
### Known issues
|
||||
|
||||
- When using the bootloader's USB mode, you may get stuck on "Waiting for USB"
|
||||
even though the cable is already plugged in. If this occurs, unplug the USB
|
||||
cable and plug it back in to trigger the connection.
|
||||
|
||||
|
||||
## TODO list
|
||||
|
||||
### Add better documentation and logging
|
||||
|
||||
There's only a bare minimum of documentation, and logging is sparse, not
|
||||
really enough to debug problems.
|
||||
|
||||
Some of the error messages could be friendlier too.
|
||||
|
||||
### Integration with the Rockbox utility
|
||||
|
||||
Adding support to the Rockbox utility should be mostly boilerplate since the
|
||||
jztool library wraps all the troublesome details.
|
||||
|
||||
Permissions are an issue on Linux because by default only root can access
|
||||
"raw" USB devices. If we want to package rbutil for distro we can install
|
||||
a udev rule to allow access to the specific USB IDs we need, eg. allowing
|
||||
users in the "wheel" group to access the device.
|
||||
|
||||
On Windows and Mac, no special permissions are needed to access USB devices
|
||||
assuming the drivers are set up. (Zadig does require administrator access
|
||||
to run, but that's external to the Rockbox utility.)
|
||||
202
utils/jztool/include/jztool.h
Normal file
202
utils/jztool/include/jztool.h
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef JZTOOL_H
|
||||
#define JZTOOL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* Types, enumerations, etc
|
||||
*/
|
||||
|
||||
#define JZ_CPUINFO_BUFLEN 9
|
||||
|
||||
typedef struct jz_context jz_context;
|
||||
typedef struct jz_usbdev jz_usbdev;
|
||||
typedef struct jz_device_info jz_device_info;
|
||||
typedef struct jz_cpu_info jz_cpu_info;
|
||||
typedef struct jz_buffer jz_buffer;
|
||||
|
||||
typedef enum jz_error jz_error;
|
||||
typedef enum jz_identify_error jz_identify_error;
|
||||
typedef enum jz_log_level jz_log_level;
|
||||
typedef enum jz_device_type jz_device_type;
|
||||
typedef enum jz_cpu_type jz_cpu_type;
|
||||
|
||||
typedef void(*jz_log_cb)(jz_log_level, const char*);
|
||||
|
||||
enum jz_error {
|
||||
JZ_SUCCESS = 0,
|
||||
JZ_ERR_OUT_OF_MEMORY = -1,
|
||||
JZ_ERR_OPEN_FILE = -2,
|
||||
JZ_ERR_FILE_IO = -3,
|
||||
JZ_ERR_USB = -4,
|
||||
JZ_ERR_NO_DEVICE = -5,
|
||||
JZ_ERR_BAD_FILE_FORMAT = -6,
|
||||
JZ_ERR_FLASH_ERROR = -7,
|
||||
JZ_ERR_OTHER = -99,
|
||||
};
|
||||
|
||||
enum jz_identify_error {
|
||||
JZ_IDERR_OTHER = -1,
|
||||
JZ_IDERR_WRONG_SIZE = -2,
|
||||
JZ_IDERR_BAD_HEADER = -3,
|
||||
JZ_IDERR_BAD_CHECKSUM = -4,
|
||||
JZ_IDERR_UNRECOGNIZED_MODEL = -5,
|
||||
};
|
||||
|
||||
enum jz_log_level {
|
||||
JZ_LOG_IGNORE = -1,
|
||||
JZ_LOG_ERROR = 0,
|
||||
JZ_LOG_WARNING = 1,
|
||||
JZ_LOG_NOTICE = 2,
|
||||
JZ_LOG_DETAIL = 3,
|
||||
JZ_LOG_DEBUG = 4,
|
||||
};
|
||||
|
||||
enum jz_device_type {
|
||||
JZ_DEVICE_FIIOM3K,
|
||||
JZ_DEVICE_SHANLINGQ1,
|
||||
JZ_DEVICE_EROSQ,
|
||||
JZ_NUM_DEVICES,
|
||||
};
|
||||
|
||||
enum jz_cpu_type {
|
||||
JZ_CPU_X1000,
|
||||
JZ_NUM_CPUS,
|
||||
};
|
||||
|
||||
struct jz_device_info {
|
||||
/* internal device name and file extension */
|
||||
const char* name;
|
||||
const char* file_ext;
|
||||
|
||||
/* human-readable name */
|
||||
const char* description;
|
||||
|
||||
/* device and CPU type */
|
||||
jz_device_type device_type;
|
||||
jz_cpu_type cpu_type;
|
||||
|
||||
/* USB IDs of the device in mass storage mode */
|
||||
uint16_t vendor_id;
|
||||
uint16_t product_id;
|
||||
};
|
||||
|
||||
struct jz_cpu_info {
|
||||
/* CPU info string, as reported by the boot ROM */
|
||||
const char* info_str;
|
||||
|
||||
/* USB IDs of the boot ROM */
|
||||
uint16_t vendor_id;
|
||||
uint16_t product_id;
|
||||
|
||||
/* default addresses for running binaries */
|
||||
uint32_t stage1_load_addr;
|
||||
uint32_t stage1_exec_addr;
|
||||
uint32_t stage2_load_addr;
|
||||
uint32_t stage2_exec_addr;
|
||||
};
|
||||
|
||||
struct jz_buffer {
|
||||
size_t size;
|
||||
uint8_t* data;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* Library context and general functions
|
||||
*/
|
||||
|
||||
jz_context* jz_context_create(void);
|
||||
void jz_context_destroy(jz_context* jz);
|
||||
|
||||
void jz_context_set_user_data(jz_context* jz, void* ptr);
|
||||
void* jz_context_get_user_data(jz_context* jz);
|
||||
|
||||
void jz_context_set_log_cb(jz_context* jz, jz_log_cb cb);
|
||||
void jz_context_set_log_level(jz_context* jz, jz_log_level lev);
|
||||
|
||||
void jz_log(jz_context* jz, jz_log_level lev, const char* fmt, ...);
|
||||
void jz_log_cb_stderr(jz_log_level lev, const char* msg);
|
||||
|
||||
void jz_sleepms(int ms);
|
||||
|
||||
/******************************************************************************
|
||||
* Device and file info
|
||||
*/
|
||||
|
||||
const jz_device_info* jz_get_device_info(jz_device_type type);
|
||||
const jz_device_info* jz_get_device_info_named(const char* name);
|
||||
const jz_device_info* jz_get_device_info_indexed(int index);
|
||||
|
||||
const jz_cpu_info* jz_get_cpu_info(jz_cpu_type type);
|
||||
const jz_cpu_info* jz_get_cpu_info_named(const char* info_str);
|
||||
|
||||
int jz_identify_x1000_spl(const void* data, size_t len);
|
||||
int jz_identify_scramble_image(const void* data, size_t len);
|
||||
|
||||
/******************************************************************************
|
||||
* USB boot ROM protocol
|
||||
*/
|
||||
|
||||
int jz_usb_open(jz_context* jz, jz_usbdev** devptr, uint16_t vend_id, uint16_t prod_id);
|
||||
void jz_usb_close(jz_usbdev* dev);
|
||||
|
||||
int jz_usb_send(jz_usbdev* dev, uint32_t addr, size_t len, const void* data);
|
||||
int jz_usb_recv(jz_usbdev* dev, uint32_t addr, size_t len, void* data);
|
||||
int jz_usb_start1(jz_usbdev* dev, uint32_t addr);
|
||||
int jz_usb_start2(jz_usbdev* dev, uint32_t addr);
|
||||
int jz_usb_flush_caches(jz_usbdev* dev);
|
||||
int jz_usb_get_cpu_info(jz_usbdev* dev, char* buffer, size_t buflen);
|
||||
|
||||
/******************************************************************************
|
||||
* Rockbox loader (all functions are model-specific, see docs)
|
||||
*/
|
||||
|
||||
int jz_x1000_boot(jz_usbdev* dev, jz_device_type type, const char* filename);
|
||||
|
||||
/******************************************************************************
|
||||
* Buffer API and other functions
|
||||
*/
|
||||
|
||||
jz_buffer* jz_buffer_alloc(size_t size, const void* data);
|
||||
void jz_buffer_free(jz_buffer* buf);
|
||||
|
||||
int jz_buffer_load(jz_buffer** buf, const char* filename);
|
||||
int jz_buffer_save(jz_buffer* buf, const char* filename);
|
||||
|
||||
jz_buffer* jz_ucl_unpack(const uint8_t* src, uint32_t src_len, uint32_t* dst_len);
|
||||
|
||||
/******************************************************************************
|
||||
* END
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* JZTOOL_H */
|
||||
212
utils/jztool/jztool.c
Normal file
212
utils/jztool/jztool.c
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "jztool.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
jz_context* jz = NULL;
|
||||
jz_usbdev* usbdev = NULL;
|
||||
const jz_device_info* dev_info = NULL;
|
||||
const jz_cpu_info* cpu_info = NULL;
|
||||
|
||||
void usage_x1000(void)
|
||||
{
|
||||
printf(
|
||||
"Usage:\n"
|
||||
" jztool fiiom3k load <bootloader.m3k>\n"
|
||||
" jztool shanlingq1 load <bootloader.q1>\n"
|
||||
" jztool erosq load <bootloader.erosq>\n"
|
||||
"\n"
|
||||
"The 'load' command is used to boot the Rockbox bootloader in recovery\n"
|
||||
"mode, which allows you to install the Rockbox bootloader and backup or\n"
|
||||
"restore bootloader images. You need to connect your player in USB boot\n"
|
||||
"mode in order to use this tool.\n"
|
||||
"\n"
|
||||
"To connect the player in USB boot mode, follow these steps:\n"
|
||||
"\n"
|
||||
"1. Ensure the player is fully powered off.\n"
|
||||
"2. Plug one end of the USB cable into your player.\n"
|
||||
"3. Hold down your player's USB boot key (see below).\n"
|
||||
"4. Plug the other end of the USB cable into your computer.\n"
|
||||
"5. Let go of the USB boot key.\n"
|
||||
"\n"
|
||||
"USB boot keys:\n"
|
||||
"\n"
|
||||
" FiiO M3K - Volume Down\n"
|
||||
" Shanling Q1 - Play\n"
|
||||
" Eros Q - Menu\n"
|
||||
"\n"
|
||||
"Not all players give a visible indication that they are in USB boot mode.\n"
|
||||
"If you're having trouble connecting your player, try resetting it by\n"
|
||||
"holding the power button for 10 seconds, and try the above steps again.\n"
|
||||
"\n"
|
||||
"Note for Windows users: you need to install the WinUSB driver using a\n"
|
||||
"3rd-party tool such as Zadig <https://zadig.akeo.ie> before this tool\n"
|
||||
"can access your player in USB boot mode. You need to run Zadig while the\n"
|
||||
"player is plugged in and in USB boot mode. For more details check the\n"
|
||||
"jztool README.md file or visit <https://rockbox.org/wiki/IngenicX1000>.\n"
|
||||
"\n");
|
||||
|
||||
exit(4);
|
||||
}
|
||||
|
||||
int cmdline_x1000(int argc, char** argv)
|
||||
{
|
||||
if(argc < 2 || strcmp(argv[0], "load")) {
|
||||
usage_x1000();
|
||||
return 2;
|
||||
}
|
||||
|
||||
int rc = jz_usb_open(jz, &usbdev, cpu_info->vendor_id, cpu_info->product_id);
|
||||
if(rc < 0) {
|
||||
jz_log(jz, JZ_LOG_ERROR, "Cannot open USB device: %d", rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = jz_x1000_boot(usbdev, dev_info->device_type, argv[1]);
|
||||
if(rc < 0) {
|
||||
jz_log(jz, JZ_LOG_ERROR, "Boot failed: %d", rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf("Usage:\n"
|
||||
" jztool [global options] <device> <command> [command arguments]\n"
|
||||
"\n"
|
||||
"Global options:\n"
|
||||
" -h, --help Display this help\n"
|
||||
" -q, --quiet Don't log anything except errors\n"
|
||||
" -v, --verbose Display detailed logging output\n\n");
|
||||
|
||||
printf("Supported devices:\n\n");
|
||||
for(int i = 0; i < JZ_NUM_DEVICES; ++i) {
|
||||
const jz_device_info* info = jz_get_device_info_indexed(i);
|
||||
printf(" %s - %s\n", info->name, info->description);
|
||||
}
|
||||
|
||||
printf("\n"
|
||||
"For device-specific help run 'jztool DEVICE' without arguments,\n"
|
||||
"eg. 'jztool fiiom3k' will display help for the FiiO M3K.\n");
|
||||
|
||||
exit(4);
|
||||
}
|
||||
|
||||
void cleanup(void)
|
||||
{
|
||||
if(usbdev)
|
||||
jz_usb_close(usbdev);
|
||||
if(jz)
|
||||
jz_context_destroy(jz);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if(argc < 2)
|
||||
usage();
|
||||
|
||||
/* Library initialization */
|
||||
jz = jz_context_create();
|
||||
if(!jz) {
|
||||
fprintf(stderr, "ERROR: Can't create context");
|
||||
return 1;
|
||||
}
|
||||
|
||||
atexit(cleanup);
|
||||
jz_context_set_log_cb(jz, jz_log_cb_stderr);
|
||||
jz_context_set_log_level(jz, JZ_LOG_NOTICE);
|
||||
|
||||
/* Parse global options */
|
||||
--argc, ++argv;
|
||||
while(argc > 0 && argv[0][0] == '-') {
|
||||
if(!strcmp(*argv, "-h") || !strcmp(*argv, "--help"))
|
||||
usage();
|
||||
else if(!strcmp(*argv, "-q") || !strcmp(*argv, "--quiet"))
|
||||
jz_context_set_log_level(jz, JZ_LOG_ERROR);
|
||||
else if(!strcmp(*argv, "-v") || !strcmp(*argv, "--verbose"))
|
||||
jz_context_set_log_level(jz, JZ_LOG_DETAIL);
|
||||
else if(!strcmp(*argv, "-l") || !strcmp(*argv, "--loglevel")) {
|
||||
++argv;
|
||||
if(--argc == 0) {
|
||||
jz_log(jz, JZ_LOG_ERROR, "Missing argument to option %s", *argv);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
enum jz_log_level level;
|
||||
if(!strcmp(*argv, "ignore"))
|
||||
level = JZ_LOG_IGNORE;
|
||||
else if(!strcmp(*argv, "error"))
|
||||
level = JZ_LOG_ERROR;
|
||||
else if(!strcmp(*argv, "warning"))
|
||||
level = JZ_LOG_WARNING;
|
||||
else if(!strcmp(*argv, "notice"))
|
||||
level = JZ_LOG_NOTICE;
|
||||
else if(!strcmp(*argv, "detail"))
|
||||
level = JZ_LOG_DETAIL;
|
||||
else if(!strcmp(*argv, "debug"))
|
||||
level = JZ_LOG_DEBUG;
|
||||
else {
|
||||
jz_log(jz, JZ_LOG_ERROR, "Invalid log level '%s'", *argv);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
jz_context_set_log_level(jz, level);
|
||||
} else {
|
||||
jz_log(jz, JZ_LOG_ERROR, "Invalid global option '%s'", *argv);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
--argc, ++argv;
|
||||
}
|
||||
|
||||
/* Read the device type */
|
||||
if(argc == 0) {
|
||||
jz_log(jz, JZ_LOG_ERROR, "No device specified (try jztool --help)");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
dev_info = jz_get_device_info_named(*argv);
|
||||
if(!dev_info) {
|
||||
jz_log(jz, JZ_LOG_ERROR, "Unknown device '%s' (try jztool --help)", *argv);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
cpu_info = jz_get_cpu_info(dev_info->cpu_type);
|
||||
|
||||
/* Dispatch to device handler */
|
||||
--argc, ++argv;
|
||||
switch(dev_info->device_type) {
|
||||
case JZ_DEVICE_FIIOM3K:
|
||||
case JZ_DEVICE_SHANLINGQ1:
|
||||
case JZ_DEVICE_EROSQ:
|
||||
return cmdline_x1000(argc, argv);
|
||||
|
||||
default:
|
||||
jz_log(jz, JZ_LOG_ERROR, "INTERNAL ERROR: unhandled device type");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
134
utils/jztool/src/buffer.c
Normal file
134
utils/jztool/src/buffer.c
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "jztool.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/** \brief Allocate a buffer, optionally providing its contents.
|
||||
* \param size Number of bytes to allocate
|
||||
* \param data Initial contents of the buffer, must be at least `size` bytes
|
||||
* \return Pointer to buffer or NULL if out of memory.
|
||||
* \note The buffer will not take ownership of the `data` pointer, instead it
|
||||
* allocates a fresh buffer and copies the contents of `data` into it.
|
||||
*/
|
||||
jz_buffer* jz_buffer_alloc(size_t size, const void* data)
|
||||
{
|
||||
jz_buffer* buf = malloc(sizeof(struct jz_buffer));
|
||||
if(!buf)
|
||||
return NULL;
|
||||
|
||||
buf->data = malloc(size);
|
||||
if(!buf->data) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(data)
|
||||
memcpy(buf->data, data, size);
|
||||
|
||||
buf->size = size;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/** \brief Free a buffer
|
||||
*/
|
||||
void jz_buffer_free(jz_buffer* buf)
|
||||
{
|
||||
if(buf) {
|
||||
free(buf->data);
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief Load a buffer from a file
|
||||
* \param buf Returns loaded buffer on success, unmodified on error
|
||||
* \param filename Path to the file
|
||||
* \return either JZ_SUCCESS, or one of the following errors
|
||||
* \retval JZ_ERR_OPEN_FILE file cannot be opened
|
||||
* \retval JZ_ERR_OUT_OF_MEMORY cannot allocate buffer to hold file contents
|
||||
* \retval JZ_ERR_FILE_IO problem reading file data
|
||||
*/
|
||||
int jz_buffer_load(jz_buffer** buf, const char* filename)
|
||||
{
|
||||
FILE* f;
|
||||
jz_buffer* b;
|
||||
int rc;
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if(!f)
|
||||
return JZ_ERR_OPEN_FILE;
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
int size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
b = jz_buffer_alloc(size, NULL);
|
||||
if(!b) {
|
||||
rc = JZ_ERR_OUT_OF_MEMORY;
|
||||
goto err_fclose;
|
||||
}
|
||||
|
||||
if(fread(b->data, size, 1, f) != 1) {
|
||||
rc = JZ_ERR_FILE_IO;
|
||||
goto err_free_buf;
|
||||
}
|
||||
|
||||
rc = JZ_SUCCESS;
|
||||
*buf = b;
|
||||
|
||||
err_fclose:
|
||||
fclose(f);
|
||||
return rc;
|
||||
|
||||
err_free_buf:
|
||||
jz_buffer_free(b);
|
||||
goto err_fclose;
|
||||
}
|
||||
|
||||
/** \brief Save a buffer to a file
|
||||
* \param buf Buffer to be written out
|
||||
* \param filename Path to the file
|
||||
* \return either JZ_SUCCESS, or one of the following errors
|
||||
* \retval JZ_ERR_OPEN_FILE file cannot be opened
|
||||
* \retval JZ_ERR_FILE_IO problem writing file data
|
||||
*/
|
||||
int jz_buffer_save(jz_buffer* buf, const char* filename)
|
||||
{
|
||||
int rc;
|
||||
FILE* f;
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
if(!f)
|
||||
return JZ_ERR_OPEN_FILE;
|
||||
|
||||
if(fwrite(buf->data, buf->size, 1, f) != 1) {
|
||||
rc = JZ_ERR_FILE_IO;
|
||||
goto err_fclose;
|
||||
}
|
||||
|
||||
rc = JZ_SUCCESS;
|
||||
|
||||
err_fclose:
|
||||
fclose(f);
|
||||
return rc;
|
||||
}
|
||||
177
utils/jztool/src/context.c
Normal file
177
utils/jztool/src/context.c
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "jztool_private.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef WIN32
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
/** \brief Allocate a library context
|
||||
* \returns New context or NULL if out of memory
|
||||
*/
|
||||
jz_context* jz_context_create(void)
|
||||
{
|
||||
jz_context* jz = malloc(sizeof(struct jz_context));
|
||||
if(!jz)
|
||||
return NULL;
|
||||
|
||||
memset(jz, 0, sizeof(struct jz_context));
|
||||
jz->log_level = JZ_LOG_ERROR;
|
||||
return jz;
|
||||
}
|
||||
|
||||
/** \brief Destroy the context and free its memory */
|
||||
void jz_context_destroy(jz_context* jz)
|
||||
{
|
||||
if(jz->usb_ctx) {
|
||||
jz_log(jz, JZ_LOG_ERROR, "BUG: USB was not cleaned up properly");
|
||||
libusb_exit(jz->usb_ctx);
|
||||
}
|
||||
|
||||
free(jz);
|
||||
}
|
||||
|
||||
/** \brief Set a user data pointer. Useful for callbacks. */
|
||||
void jz_context_set_user_data(jz_context* jz, void* ptr)
|
||||
{
|
||||
jz->user_data = ptr;
|
||||
}
|
||||
|
||||
/** \brief Get the user data pointer */
|
||||
void* jz_context_get_user_data(jz_context* jz)
|
||||
{
|
||||
return jz->user_data;
|
||||
}
|
||||
|
||||
/** \brief Set the log message callback.
|
||||
* \note By default, no message callback is set! No messages will be logged
|
||||
* in this case, so ensure you set a callback if messages are desired.
|
||||
*/
|
||||
void jz_context_set_log_cb(jz_context* jz, jz_log_cb cb)
|
||||
{
|
||||
jz->log_cb = cb;
|
||||
}
|
||||
|
||||
/** \brief Set the log level.
|
||||
*
|
||||
* Messages of less importance than the set log level are not logged.
|
||||
* The default log level is `JZ_LOG_WARNING`. The special log level
|
||||
* `JZ_LOG_IGNORE` can be used to disable all logging temporarily.
|
||||
*
|
||||
* The `JZ_LOG_DEBUG` log level is extremely verbose and will log all calls,
|
||||
* normally it's only useful for catching bugs.
|
||||
*/
|
||||
void jz_context_set_log_level(jz_context* jz, jz_log_level lev)
|
||||
{
|
||||
jz->log_level = lev;
|
||||
}
|
||||
|
||||
/** \brief Log an informational message.
|
||||
* \param lev Log level for this message
|
||||
* \param fmt `printf` style message format string
|
||||
*/
|
||||
void jz_log(jz_context* jz, jz_log_level lev, const char* fmt, ...)
|
||||
{
|
||||
if(!jz->log_cb)
|
||||
return;
|
||||
if(lev == JZ_LOG_IGNORE)
|
||||
return;
|
||||
if(lev > jz->log_level)
|
||||
return;
|
||||
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
int n = vsnprintf(NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if(n < 0)
|
||||
return;
|
||||
|
||||
char* buf = malloc(n + 1);
|
||||
if(!buf)
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
n = vsnprintf(buf, n + 1, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if(n >= 0)
|
||||
jz->log_cb(lev, buf);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/** \brief Log callback which writes messages to `stderr`.
|
||||
*/
|
||||
void jz_log_cb_stderr(jz_log_level lev, const char* msg)
|
||||
{
|
||||
static const char* const tags[] =
|
||||
{"ERROR", "WARNING", "NOTICE", "DETAIL", "DEBUG"};
|
||||
fprintf(stderr, "[%7s] %s\n", tags[lev], msg);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
/** \brief Sleep for `ms` milliseconds.
|
||||
*/
|
||||
void jz_sleepms(int ms)
|
||||
{
|
||||
#ifdef WIN32
|
||||
Sleep(ms);
|
||||
#else
|
||||
struct timespec ts;
|
||||
long ns = ms % 1000;
|
||||
ts.tv_nsec = ns * 1000 * 1000;
|
||||
ts.tv_sec = ms / 1000;
|
||||
nanosleep(&ts, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \brief Add reference to libusb context, allocating it if necessary */
|
||||
int jz_context_ref_libusb(jz_context* jz)
|
||||
{
|
||||
if(jz->usb_ctxref == 0) {
|
||||
int rc = libusb_init(&jz->usb_ctx);
|
||||
if(rc < 0) {
|
||||
jz_log(jz, JZ_LOG_ERROR, "libusb_init: %s", libusb_strerror(rc));
|
||||
return JZ_ERR_USB;
|
||||
}
|
||||
}
|
||||
|
||||
jz->usb_ctxref += 1;
|
||||
return JZ_SUCCESS;
|
||||
}
|
||||
|
||||
/** \brief Remove reference to libusb context, freeing if it hits zero */
|
||||
void jz_context_unref_libusb(jz_context* jz)
|
||||
{
|
||||
if(--jz->usb_ctxref == 0) {
|
||||
libusb_exit(jz->usb_ctx);
|
||||
jz->usb_ctx = NULL;
|
||||
}
|
||||
}
|
||||
109
utils/jztool/src/device_info.c
Normal file
109
utils/jztool/src/device_info.c
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "jztool.h"
|
||||
#include <string.h>
|
||||
|
||||
static const jz_device_info infotable[JZ_NUM_DEVICES] = {
|
||||
[JZ_DEVICE_FIIOM3K] = {
|
||||
.name = "fiiom3k",
|
||||
.file_ext = "m3k",
|
||||
.description = "FiiO M3K",
|
||||
.device_type = JZ_DEVICE_FIIOM3K,
|
||||
.cpu_type = JZ_CPU_X1000,
|
||||
.vendor_id = 0x2972,
|
||||
.product_id = 0x0003,
|
||||
},
|
||||
[JZ_DEVICE_SHANLINGQ1] = {
|
||||
.name = "shanlingq1",
|
||||
.file_ext = "q1",
|
||||
.description = "Shanling Q1",
|
||||
.device_type = JZ_DEVICE_SHANLINGQ1,
|
||||
.cpu_type = JZ_CPU_X1000,
|
||||
.vendor_id = 0x0525,
|
||||
.product_id = 0xa4a5,
|
||||
},
|
||||
[JZ_DEVICE_EROSQ] = {
|
||||
.name = "erosq",
|
||||
.file_ext = "erosq",
|
||||
.description = "AIGO Eros Q",
|
||||
.device_type = JZ_DEVICE_EROSQ,
|
||||
.cpu_type = JZ_CPU_X1000,
|
||||
.vendor_id = 0xc502,
|
||||
.product_id = 0x0023,
|
||||
},
|
||||
};
|
||||
|
||||
static const jz_cpu_info cputable[JZ_NUM_CPUS] = {
|
||||
[JZ_CPU_X1000] = {
|
||||
.info_str = "X1000_v1",
|
||||
.vendor_id = 0xa108,
|
||||
.product_id = 0x1000,
|
||||
.stage1_load_addr = 0xf4001000,
|
||||
.stage1_exec_addr = 0xf4001800,
|
||||
.stage2_load_addr = 0x80004000,
|
||||
.stage2_exec_addr = 0x80004000,
|
||||
},
|
||||
};
|
||||
|
||||
/** \brief Lookup info for a device by type, returns NULL if not found. */
|
||||
const jz_device_info* jz_get_device_info(jz_device_type type)
|
||||
{
|
||||
return jz_get_device_info_indexed(type);
|
||||
}
|
||||
|
||||
/** \brief Lookup info for a device by name, returns NULL if not found. */
|
||||
const jz_device_info* jz_get_device_info_named(const char* name)
|
||||
{
|
||||
for(int i = 0; i < JZ_NUM_DEVICES; ++i)
|
||||
if(!strcmp(infotable[i].name, name))
|
||||
return &infotable[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** \brief Get a device info entry by index, returns NULL if out of range. */
|
||||
const jz_device_info* jz_get_device_info_indexed(int index)
|
||||
{
|
||||
if(index < JZ_NUM_DEVICES)
|
||||
return &infotable[index];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** \brief Lookup info for a CPU, returns NULL if not found. */
|
||||
const jz_cpu_info* jz_get_cpu_info(jz_cpu_type type)
|
||||
{
|
||||
if(type < JZ_NUM_CPUS)
|
||||
return &cputable[type];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** \brief Lookup info for a CPU by info string, returns NULL if not found. */
|
||||
const jz_cpu_info* jz_get_cpu_info_named(const char* info_str)
|
||||
{
|
||||
for(int i = 0; i < JZ_NUM_CPUS; ++i)
|
||||
if(!strcmp(cputable[i].info_str, info_str))
|
||||
return &cputable[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
170
utils/jztool/src/identify_file.c
Normal file
170
utils/jztool/src/identify_file.c
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "jztool.h"
|
||||
#include <string.h>
|
||||
|
||||
/* Following is copied from mkspl-x1000, basically */
|
||||
struct x1000_spl_header {
|
||||
uint8_t magic[8];
|
||||
uint8_t type;
|
||||
uint8_t crc7;
|
||||
uint8_t ppb;
|
||||
uint8_t bpp;
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
static const uint8_t x1000_spl_header_magic[8] =
|
||||
{0x06, 0x05, 0x04, 0x03, 0x02, 0x55, 0xaa, 0x55};
|
||||
|
||||
static const size_t X1000_SPL_HEADER_SIZE = 2 * 1024;
|
||||
|
||||
static uint8_t crc7(const uint8_t* buf, size_t len)
|
||||
{
|
||||
/* table-based computation of CRC7 */
|
||||
static const uint8_t t[256] = {
|
||||
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f,
|
||||
0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
|
||||
0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26,
|
||||
0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e,
|
||||
0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d,
|
||||
0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45,
|
||||
0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14,
|
||||
0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c,
|
||||
0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b,
|
||||
0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13,
|
||||
0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42,
|
||||
0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a,
|
||||
0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69,
|
||||
0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21,
|
||||
0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70,
|
||||
0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38,
|
||||
0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e,
|
||||
0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36,
|
||||
0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67,
|
||||
0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f,
|
||||
0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
|
||||
0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04,
|
||||
0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55,
|
||||
0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d,
|
||||
0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a,
|
||||
0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52,
|
||||
0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03,
|
||||
0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b,
|
||||
0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28,
|
||||
0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60,
|
||||
0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31,
|
||||
0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79
|
||||
};
|
||||
|
||||
uint8_t crc = 0;
|
||||
while(len--)
|
||||
crc = t[(crc << 1) ^ *buf++];
|
||||
return crc;
|
||||
}
|
||||
|
||||
/** \brief Identify a file as an SPL for X1000 CPUs
|
||||
* \param data File data buffer
|
||||
* \param len Length of file
|
||||
* \return JZ_SUCCESS if file looks correct, or one of the following errors
|
||||
* \retval JZ_IDERR_WRONG_SIZE file too small or size doesn't match header
|
||||
* \retval JZ_IDERR_BAD_HEADER missing magic bytes from header
|
||||
* \retval JZ_IDERR_BAD_CHECKSUM CRC7 mismatch
|
||||
*/
|
||||
int jz_identify_x1000_spl(const void* data, size_t len)
|
||||
{
|
||||
/* Use <= check because a header-only file is not really valid,
|
||||
* it should have at least one byte in it... */
|
||||
if(len <= X1000_SPL_HEADER_SIZE)
|
||||
return JZ_IDERR_WRONG_SIZE;
|
||||
|
||||
/* Look for header magic bytes */
|
||||
const struct x1000_spl_header* header = (const struct x1000_spl_header*)data;
|
||||
if(memcmp(header->magic, x1000_spl_header_magic, 8))
|
||||
return JZ_IDERR_BAD_HEADER;
|
||||
|
||||
/* Length stored in the header should equal the length of the file */
|
||||
if(header->length != len)
|
||||
return JZ_IDERR_WRONG_SIZE;
|
||||
|
||||
/* Compute the CRC7 checksum; it only covers the SPL code */
|
||||
const uint8_t* dat = (const uint8_t*)data;
|
||||
uint8_t sum = crc7(&dat[X1000_SPL_HEADER_SIZE], len - X1000_SPL_HEADER_SIZE);
|
||||
if(header->crc7 != sum)
|
||||
return JZ_IDERR_BAD_CHECKSUM;
|
||||
|
||||
return JZ_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
static const struct scramble_model_info {
|
||||
const char* name;
|
||||
int model_num;
|
||||
size_t offset_crc;
|
||||
size_t offset_name;
|
||||
size_t offset_data;
|
||||
} scramble_models[] = {
|
||||
{"fiio", 114, 0, 4, 8},
|
||||
{"shq1", 115, 0, 4, 8},
|
||||
{"eros", 116, 0, 4, 8},
|
||||
{NULL, 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
/** \brief Identify a file as a Rockbox `scramble` image
|
||||
* \param data File data buffer
|
||||
* \param len Length of file
|
||||
* \return JZ_SUCCESS if file looks correct, or one of the following errors
|
||||
* \retval JZ_IDERR_UNRECOGNIZED_MODEL unsupported/unknown model type
|
||||
* \retval JZ_IDERR_BAD_CHECKSUM checksum mismatch
|
||||
*/
|
||||
int jz_identify_scramble_image(const void* data, size_t len)
|
||||
{
|
||||
const uint8_t* dat;
|
||||
const struct scramble_model_info* model_info;
|
||||
uint32_t sum, file_sum;
|
||||
|
||||
dat = (const uint8_t*)data;
|
||||
model_info = &scramble_models[0];
|
||||
|
||||
/* Look up the model number */
|
||||
for(; model_info->name != NULL; ++model_info) {
|
||||
if(model_info->offset_name + 4 > len)
|
||||
continue;
|
||||
if(!memcmp(&dat[model_info->offset_name], model_info->name, 4))
|
||||
break;
|
||||
}
|
||||
|
||||
if(model_info->name == NULL)
|
||||
return JZ_IDERR_UNRECOGNIZED_MODEL;
|
||||
|
||||
/* Compute the checksum */
|
||||
sum = model_info->model_num;
|
||||
for(size_t i = model_info->offset_data; i < len; ++i)
|
||||
sum += dat[i];
|
||||
|
||||
/* Compare with file's checksum, it's stored in big-endian form */
|
||||
dat += model_info->offset_crc;
|
||||
file_sum = (dat[0] << 24) | (dat[1] << 16) | (dat[2] << 8) | dat[3];
|
||||
if(sum != file_sum)
|
||||
return JZ_IDERR_BAD_CHECKSUM;
|
||||
|
||||
return JZ_SUCCESS;
|
||||
}
|
||||
44
utils/jztool/src/jztool_private.h
Normal file
44
utils/jztool/src/jztool_private.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef JZTOOL_PRIVATE_H
|
||||
#define JZTOOL_PRIVATE_H
|
||||
|
||||
#include "jztool.h"
|
||||
#include <libusb.h>
|
||||
|
||||
struct jz_context {
|
||||
void* user_data;
|
||||
jz_log_cb log_cb;
|
||||
jz_log_level log_level;
|
||||
libusb_context* usb_ctx;
|
||||
int usb_ctxref;
|
||||
};
|
||||
|
||||
struct jz_usbdev {
|
||||
jz_context* jz;
|
||||
libusb_device_handle* handle;
|
||||
};
|
||||
|
||||
int jz_context_ref_libusb(jz_context* jz);
|
||||
void jz_context_unref_libusb(jz_context* jz);
|
||||
|
||||
#endif /* JZTOOL_PRIVATE_H */
|
||||
128
utils/jztool/src/ucl_unpack.c
Normal file
128
utils/jztool/src/ucl_unpack.c
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "jztool.h"
|
||||
#include "ucl/ucl.h"
|
||||
|
||||
static uint32_t xread32(const uint8_t* d)
|
||||
{
|
||||
uint32_t r = 0;
|
||||
r |= d[0] << 24;
|
||||
r |= d[1] << 16;
|
||||
r |= d[2] << 8;
|
||||
r |= d[3] << 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* adapted from firmware/common/ucl_decompress.c */
|
||||
jz_buffer* jz_ucl_unpack(const uint8_t* src, uint32_t src_len, uint32_t* dst_len)
|
||||
{
|
||||
static const uint8_t magic[8] =
|
||||
{0x00, 0xe9, 0x55, 0x43, 0x4c, 0xff, 0x01, 0x1a};
|
||||
|
||||
jz_buffer* buffer = NULL;
|
||||
|
||||
/* make sure there are enough bytes for the header */
|
||||
if(src_len < 18)
|
||||
goto error;
|
||||
|
||||
/* avoid memcmp for reasons of code size */
|
||||
for(size_t i = 0; i < sizeof(magic); ++i)
|
||||
if(src[i] != magic[i])
|
||||
goto error;
|
||||
|
||||
/* read the other header fields */
|
||||
/* uint32_t flags = xread32(&src[8]); */
|
||||
uint8_t method = src[12];
|
||||
/* uint8_t level = src[13]; */
|
||||
uint32_t block_size = xread32(&src[14]);
|
||||
|
||||
/* check supported compression method */
|
||||
if(method != 0x2e)
|
||||
goto error;
|
||||
|
||||
/* validate */
|
||||
if(block_size < 1024 || block_size > 8*1024*1024)
|
||||
goto error;
|
||||
|
||||
src += 18;
|
||||
src_len -= 18;
|
||||
|
||||
/* Calculate amount of space that we might need & allocate a buffer:
|
||||
* - subtract 4 to account for end of file marker
|
||||
* - each block is block_size bytes + 8 bytes of header
|
||||
* - add one to nr_blocks to account for case where file size < block size
|
||||
* - total size = max uncompressed size of block * nr_blocks
|
||||
*/
|
||||
uint32_t nr_blocks = (src_len - 4) / (8 + block_size) + 1;
|
||||
uint32_t max_size = nr_blocks * (block_size + block_size/8 + 256);
|
||||
buffer = jz_buffer_alloc(max_size, NULL);
|
||||
if(!buffer)
|
||||
goto error;
|
||||
|
||||
/* perform the decompression */
|
||||
uint32_t dst_ilen = buffer->size;
|
||||
uint8_t* dst = buffer->data;
|
||||
while(1) {
|
||||
if(src_len < 4)
|
||||
goto error;
|
||||
|
||||
uint32_t out_len = xread32(src); src += 4, src_len -= 4;
|
||||
if(out_len == 0)
|
||||
break;
|
||||
|
||||
if(src_len < 4)
|
||||
goto error;
|
||||
|
||||
uint32_t in_len = xread32(src); src += 4, src_len -= 4;
|
||||
if(in_len > block_size || out_len > block_size ||
|
||||
in_len == 0 || in_len > out_len)
|
||||
goto error;
|
||||
|
||||
if(src_len < in_len)
|
||||
goto error;
|
||||
|
||||
if(in_len < out_len) {
|
||||
uint32_t actual_out_len = dst_ilen;
|
||||
int rc = ucl_nrv2e_decompress_safe_8(src, in_len, dst, &actual_out_len, NULL);
|
||||
if(rc != UCL_E_OK)
|
||||
goto error;
|
||||
if(actual_out_len != out_len)
|
||||
goto error;
|
||||
} else {
|
||||
for(size_t i = 0; i < in_len; ++i)
|
||||
dst[i] = src[i];
|
||||
}
|
||||
|
||||
src += in_len;
|
||||
src_len -= in_len;
|
||||
dst += out_len;
|
||||
dst_ilen -= out_len;
|
||||
}
|
||||
|
||||
/* subtract leftover number of bytes to get size of compressed output */
|
||||
*dst_len = buffer->size - dst_ilen;
|
||||
return buffer;
|
||||
|
||||
error:
|
||||
jz_buffer_free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
291
utils/jztool/src/usb.c
Normal file
291
utils/jztool/src/usb.c
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "jztool_private.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#define VR_GET_CPU_INFO 0
|
||||
#define VR_SET_DATA_ADDRESS 1
|
||||
#define VR_SET_DATA_LENGTH 2
|
||||
#define VR_FLUSH_CACHES 3
|
||||
#define VR_PROGRAM_START1 4
|
||||
#define VR_PROGRAM_START2 5
|
||||
|
||||
/** \brief Open a USB device
|
||||
* \param jz Context
|
||||
* \param devptr Returns pointer to the USB device upon success
|
||||
* \param vend_id USB vendor ID
|
||||
* \param prod_id USB product ID
|
||||
* \return either JZ_SUCCESS if device was opened, or an error below
|
||||
* \retval JZ_ERR_OUT_OF_MEMORY malloc failed
|
||||
* \retval JZ_ERR_USB libusb error (details are logged)
|
||||
* \retval JZ_ERR_NO_DEVICE can't unambiguously find the device
|
||||
*/
|
||||
int jz_usb_open(jz_context* jz, jz_usbdev** devptr, uint16_t vend_id, uint16_t prod_id)
|
||||
{
|
||||
int rc;
|
||||
jz_usbdev* dev = NULL;
|
||||
libusb_device_handle* usb_handle = NULL;
|
||||
libusb_device** dev_list = NULL;
|
||||
ssize_t dev_index = -1, dev_count;
|
||||
|
||||
rc = jz_context_ref_libusb(jz);
|
||||
if(rc < 0)
|
||||
return rc;
|
||||
|
||||
dev = malloc(sizeof(struct jz_usbdev));
|
||||
if(!dev) {
|
||||
rc = JZ_ERR_OUT_OF_MEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev_count = libusb_get_device_list(jz->usb_ctx, &dev_list);
|
||||
if(dev_count < 0) {
|
||||
jz_log(jz, JZ_LOG_ERROR, "libusb_get_device_list: %s", libusb_strerror(dev_count));
|
||||
rc = JZ_ERR_USB;
|
||||
goto error;
|
||||
}
|
||||
|
||||
for(ssize_t i = 0; i < dev_count; ++i) {
|
||||
struct libusb_device_descriptor desc;
|
||||
rc = libusb_get_device_descriptor(dev_list[i], &desc);
|
||||
if(rc < 0) {
|
||||
jz_log(jz, JZ_LOG_WARNING, "libusb_get_device_descriptor: %s",
|
||||
libusb_strerror(rc));
|
||||
continue;
|
||||
}
|
||||
|
||||
if(desc.idVendor != vend_id || desc.idProduct != prod_id)
|
||||
continue;
|
||||
|
||||
if(dev_index >= 0) {
|
||||
/* not the best, but it is the safest thing */
|
||||
jz_log(jz, JZ_LOG_ERROR, "Multiple devices match ID %04x:%04x",
|
||||
(unsigned int)vend_id, (unsigned int)prod_id);
|
||||
jz_log(jz, JZ_LOG_ERROR, "Please ensure only one player is plugged in, and try again");
|
||||
rc = JZ_ERR_NO_DEVICE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev_index = i;
|
||||
}
|
||||
|
||||
if(dev_index < 0) {
|
||||
jz_log(jz, JZ_LOG_ERROR, "No device with ID %04x:%04x found",
|
||||
(unsigned int)vend_id, (unsigned int)prod_id);
|
||||
rc = JZ_ERR_NO_DEVICE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = libusb_open(dev_list[dev_index], &usb_handle);
|
||||
if(rc < 0) {
|
||||
jz_log(jz, JZ_LOG_ERROR, "libusb_open: %s", libusb_strerror(rc));
|
||||
rc = JZ_ERR_USB;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = libusb_claim_interface(usb_handle, 0);
|
||||
if(rc < 0) {
|
||||
jz_log(jz, JZ_LOG_ERROR, "libusb_claim_interface: %s", libusb_strerror(rc));
|
||||
rc = JZ_ERR_USB;
|
||||
goto error;
|
||||
}
|
||||
|
||||
jz_log(jz, JZ_LOG_DEBUG, "Opened device (%p, ID %04x:%04x)",
|
||||
dev, (unsigned int)vend_id, (unsigned int)prod_id);
|
||||
dev->jz = jz;
|
||||
dev->handle = usb_handle;
|
||||
*devptr = dev;
|
||||
rc = JZ_SUCCESS;
|
||||
|
||||
exit:
|
||||
if(dev_list)
|
||||
libusb_free_device_list(dev_list, true);
|
||||
return rc;
|
||||
|
||||
error:
|
||||
if(dev)
|
||||
free(dev);
|
||||
if(usb_handle)
|
||||
libusb_close(usb_handle);
|
||||
jz_context_unref_libusb(jz);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/** \brief Close a USB device
|
||||
* \param dev Device to close; memory will be freed automatically
|
||||
*/
|
||||
void jz_usb_close(jz_usbdev* dev)
|
||||
{
|
||||
jz_log(dev->jz, JZ_LOG_DEBUG, "Closing device (%p)", dev);
|
||||
libusb_release_interface(dev->handle, 0);
|
||||
libusb_close(dev->handle);
|
||||
jz_context_unref_libusb(dev->jz);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
// Does an Ingenic-specific vendor request
|
||||
// Written with X1000 in mind but other Ingenic CPUs have the same commands
|
||||
static int jz_usb_vendor_req(jz_usbdev* dev, int req, uint32_t arg,
|
||||
void* buffer, int buflen)
|
||||
{
|
||||
int rc = libusb_control_transfer(dev->handle,
|
||||
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||
req, arg >> 16, arg & 0xffff, buffer, buflen, 1000);
|
||||
|
||||
if(rc < 0) {
|
||||
jz_log(dev->jz, JZ_LOG_ERROR, "libusb_control_transfer: %s", libusb_strerror(rc));
|
||||
rc = JZ_ERR_USB;
|
||||
} else {
|
||||
static const char* req_names[] = {
|
||||
"GET_CPU_INFO",
|
||||
"SET_DATA_ADDRESS",
|
||||
"SET_DATA_LENGTH",
|
||||
"FLUSH_CACHES",
|
||||
"PROGRAM_START1",
|
||||
"PROGRAM_START2",
|
||||
};
|
||||
|
||||
jz_log(dev->jz, JZ_LOG_DEBUG, "Issued %s %08lu",
|
||||
req_names[req], (unsigned long)arg);
|
||||
rc = JZ_SUCCESS;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Bulk transfer wrapper
|
||||
static int jz_usb_transfer(jz_usbdev* dev, bool write, size_t len, void* buf)
|
||||
{
|
||||
int xfered = 0;
|
||||
int ep = write ? LIBUSB_ENDPOINT_OUT|1 : LIBUSB_ENDPOINT_IN|1;
|
||||
int rc = libusb_bulk_transfer(dev->handle, ep, buf, len, &xfered, 10000);
|
||||
|
||||
if(rc < 0) {
|
||||
jz_log(dev->jz, JZ_LOG_ERROR, "libusb_bulk_transfer: %s", libusb_strerror(rc));
|
||||
rc = JZ_ERR_USB;
|
||||
} else if(xfered != (int)len) {
|
||||
jz_log(dev->jz, JZ_LOG_ERROR, "libusb_bulk_transfer: incorrect amount of data transfered");
|
||||
rc = JZ_ERR_USB;
|
||||
} else {
|
||||
jz_log(dev->jz, JZ_LOG_DEBUG, "Transferred %zu bytes %s",
|
||||
len, write ? "to device" : "from device");
|
||||
rc = JZ_SUCCESS;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Memory send/receive primitive, performs the necessary vendor requests
|
||||
// and then tranfers data using the bulk endpoint
|
||||
static int jz_usb_sendrecv(jz_usbdev* dev, bool write, uint32_t addr,
|
||||
size_t len, void* data)
|
||||
{
|
||||
int rc;
|
||||
rc = jz_usb_vendor_req(dev, VR_SET_DATA_ADDRESS, addr, NULL, 0);
|
||||
if(rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = jz_usb_vendor_req(dev, VR_SET_DATA_LENGTH, len, NULL, 0);
|
||||
if(rc < 0)
|
||||
return rc;
|
||||
|
||||
return jz_usb_transfer(dev, write, len, data);
|
||||
}
|
||||
|
||||
/** \brief Write data to device memory
|
||||
* \param dev USB device
|
||||
* \param addr Address where data should be written
|
||||
* \param len Length of the data, in bytes, should be positive
|
||||
* \param data Data buffer
|
||||
* \return either JZ_SUCCESS on success or a failure code
|
||||
*/
|
||||
int jz_usb_send(jz_usbdev* dev, uint32_t addr, size_t len, const void* data)
|
||||
{
|
||||
return jz_usb_sendrecv(dev, true, addr, len, (void*)data);
|
||||
}
|
||||
|
||||
/** \brief Read data to device memory
|
||||
* \param dev USB device
|
||||
* \param addr Address to read from
|
||||
* \param len Length of the data, in bytes, should be positive
|
||||
* \param data Data buffer
|
||||
* \return either JZ_SUCCESS on success or a failure code
|
||||
*/
|
||||
int jz_usb_recv(jz_usbdev* dev, uint32_t addr, size_t len, void* data)
|
||||
{
|
||||
return jz_usb_sendrecv(dev, false, addr, len, data);
|
||||
}
|
||||
|
||||
/** \brief Execute stage1 program jumping to the specified address
|
||||
* \param dev USB device
|
||||
* \param addr Address to begin execution at
|
||||
* \return either JZ_SUCCESS on success or a failure code
|
||||
*/
|
||||
int jz_usb_start1(jz_usbdev* dev, uint32_t addr)
|
||||
{
|
||||
return jz_usb_vendor_req(dev, VR_PROGRAM_START1, addr, NULL, 0);
|
||||
}
|
||||
|
||||
/** \brief Execute stage2 program jumping to the specified address
|
||||
* \param dev USB device
|
||||
* \param addr Address to begin execution at
|
||||
* \return either JZ_SUCCESS on success or a failure code
|
||||
*/
|
||||
int jz_usb_start2(jz_usbdev* dev, uint32_t addr)
|
||||
{
|
||||
return jz_usb_vendor_req(dev, VR_PROGRAM_START2, addr, NULL, 0);
|
||||
}
|
||||
|
||||
/** \brief Ask device to flush CPU caches
|
||||
* \param dev USB device
|
||||
* \return either JZ_SUCCESS on success or a failure code
|
||||
*/
|
||||
int jz_usb_flush_caches(jz_usbdev* dev)
|
||||
{
|
||||
return jz_usb_vendor_req(dev, VR_FLUSH_CACHES, 0, NULL, 0);
|
||||
}
|
||||
|
||||
/** \brief Ask device for CPU info string
|
||||
* \param dev USB device
|
||||
* \param buffer Buffer to hold the info string
|
||||
* \param buflen Size of the buffer, in bytes
|
||||
* \return either JZ_SUCCESS on success or a failure code
|
||||
*
|
||||
* The buffer will always be null terminated, but to ensure the info string is
|
||||
* not truncated the buffer needs to be at least `JZ_CPUINFO_BUFLEN` byes long.
|
||||
*/
|
||||
int jz_usb_get_cpu_info(jz_usbdev* dev, char* buffer, size_t buflen)
|
||||
{
|
||||
char tmpbuf[JZ_CPUINFO_BUFLEN];
|
||||
int rc = jz_usb_vendor_req(dev, VR_GET_CPU_INFO, 0, tmpbuf, 8);
|
||||
if(rc != JZ_SUCCESS)
|
||||
return rc;
|
||||
|
||||
if(buflen > 0) {
|
||||
strncpy(buffer, tmpbuf, buflen);
|
||||
buffer[buflen - 1] = 0;
|
||||
}
|
||||
|
||||
return JZ_SUCCESS;
|
||||
}
|
||||
180
utils/jztool/src/x1000.c
Normal file
180
utils/jztool/src/x1000.c
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "jztool.h"
|
||||
#include "jztool_private.h"
|
||||
#include "microtar-stdio.h"
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
/* TODO: these functions could be refactored to be CPU-agnostic */
|
||||
static int run_stage1(jz_usbdev* dev, jz_buffer* buf)
|
||||
{
|
||||
int rc = jz_usb_send(dev, 0xf4001000, buf->size, buf->data);
|
||||
if(rc < 0)
|
||||
return rc;
|
||||
|
||||
return jz_usb_start1(dev, 0xf4001800);
|
||||
}
|
||||
|
||||
static int run_stage2(jz_usbdev* dev, jz_buffer* buf)
|
||||
{
|
||||
int rc = jz_usb_send(dev, 0x80004000, buf->size, buf->data);
|
||||
if(rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = jz_usb_flush_caches(dev);
|
||||
if(rc < 0)
|
||||
return rc;
|
||||
|
||||
return jz_usb_start2(dev, 0x80004000);
|
||||
}
|
||||
|
||||
static int get_file(jz_context* jz, mtar_t* tar, const char* file,
|
||||
bool decompress, jz_buffer** buf)
|
||||
{
|
||||
jz_buffer* buffer = NULL;
|
||||
const mtar_header_t* h;
|
||||
int rc;
|
||||
|
||||
rc = mtar_find(tar, file);
|
||||
if(rc != MTAR_ESUCCESS) {
|
||||
jz_log(jz, JZ_LOG_ERROR, "can't find %s in boot file, tar error %d", file, rc);
|
||||
return JZ_ERR_BAD_FILE_FORMAT;
|
||||
}
|
||||
|
||||
h = mtar_get_header(tar);
|
||||
buffer = jz_buffer_alloc(h->size, NULL);
|
||||
if(!buffer)
|
||||
return JZ_ERR_OUT_OF_MEMORY;
|
||||
|
||||
rc = mtar_read_data(tar, buffer->data, buffer->size);
|
||||
if(rc < 0 || (unsigned)rc != buffer->size) {
|
||||
jz_buffer_free(buffer);
|
||||
jz_log(jz, JZ_LOG_ERROR, "can't read %s in boot file, tar error %d", file, rc);
|
||||
return JZ_ERR_BAD_FILE_FORMAT;
|
||||
}
|
||||
|
||||
if(decompress) {
|
||||
uint32_t dst_len;
|
||||
jz_buffer* nbuf = jz_ucl_unpack(buffer->data, buffer->size, &dst_len);
|
||||
jz_buffer_free(buffer);
|
||||
if(!nbuf) {
|
||||
jz_log(jz, JZ_LOG_ERROR, "error decompressing %s in boot file", file);
|
||||
return JZ_ERR_BAD_FILE_FORMAT;
|
||||
}
|
||||
|
||||
/* for simplicity just forget original size of buffer */
|
||||
nbuf->size = dst_len;
|
||||
buffer = nbuf;
|
||||
}
|
||||
|
||||
*buf = buffer;
|
||||
return JZ_SUCCESS;
|
||||
}
|
||||
|
||||
static int show_version(jz_context* jz, jz_buffer* info_file)
|
||||
{
|
||||
/* Extract the version string and log it for informational purposes */
|
||||
char* boot_version = (char*)info_file->data;
|
||||
char* endpos = memchr(boot_version, '\n', info_file->size);
|
||||
if(!endpos) {
|
||||
jz_log(jz, JZ_LOG_ERROR, "invalid metadata in boot file");
|
||||
return JZ_ERR_BAD_FILE_FORMAT;
|
||||
}
|
||||
|
||||
*endpos = 0;
|
||||
jz_log(jz, JZ_LOG_NOTICE, "Rockbox bootloader version: %s", boot_version);
|
||||
return JZ_SUCCESS;
|
||||
}
|
||||
|
||||
/** \brief Load the Rockbox bootloader on an X1000 device
|
||||
* \param dev USB device freshly returned by jz_usb_open()
|
||||
* \param filename Path to the "bootloader.target" file
|
||||
* \return either JZ_SUCCESS or an error code
|
||||
*/
|
||||
int jz_x1000_boot(jz_usbdev* dev, jz_device_type type, const char* filename)
|
||||
{
|
||||
const jz_device_info* dev_info;
|
||||
char spl_filename[32];
|
||||
jz_buffer* spl = NULL, *bootloader = NULL, *info_file = NULL;
|
||||
mtar_t tar;
|
||||
int rc;
|
||||
|
||||
/* In retrospect using a model-dependent archive format was not a good
|
||||
* idea, but it's not worth fixing just yet... */
|
||||
dev_info = jz_get_device_info(type);
|
||||
if(!dev_info)
|
||||
return JZ_ERR_OTHER;
|
||||
/* use of sprintf is safe since file_ext is short */
|
||||
sprintf(spl_filename, "spl.%s", dev_info->file_ext);
|
||||
|
||||
/* Now open the archive */
|
||||
rc = mtar_open(&tar, filename, "rb");
|
||||
if(rc != MTAR_ESUCCESS) {
|
||||
jz_log(dev->jz, JZ_LOG_ERROR, "cannot open file %s (tar error: %d)", filename, rc);
|
||||
return JZ_ERR_OPEN_FILE;
|
||||
}
|
||||
|
||||
/* Extract all necessary files */
|
||||
rc = get_file(dev->jz, &tar, spl_filename, false, &spl);
|
||||
if(rc != JZ_SUCCESS)
|
||||
goto error;
|
||||
|
||||
rc = get_file(dev->jz, &tar, "bootloader.ucl", true, &bootloader);
|
||||
if(rc != JZ_SUCCESS)
|
||||
goto error;
|
||||
|
||||
rc = get_file(dev->jz, &tar, "bootloader-info.txt", false, &info_file);
|
||||
if(rc != JZ_SUCCESS)
|
||||
goto error;
|
||||
|
||||
/* Display the version string */
|
||||
rc = show_version(dev->jz, info_file);
|
||||
if(rc != JZ_SUCCESS)
|
||||
goto error;
|
||||
|
||||
/* Stage1 boot of SPL to set up hardware */
|
||||
rc = run_stage1(dev, spl);
|
||||
if(rc != JZ_SUCCESS)
|
||||
goto error;
|
||||
|
||||
/* Need a bit of time for SPL to handle init */
|
||||
jz_sleepms(500);
|
||||
|
||||
/* Stage2 boot into the bootloader's recovery menu
|
||||
* User has to take manual action from there */
|
||||
rc = run_stage2(dev, bootloader);
|
||||
if(rc != JZ_SUCCESS)
|
||||
goto error;
|
||||
|
||||
rc = JZ_SUCCESS;
|
||||
|
||||
error:
|
||||
if(spl)
|
||||
jz_buffer_free(spl);
|
||||
if(bootloader)
|
||||
jz_buffer_free(bootloader);
|
||||
if(info_file)
|
||||
jz_buffer_free(info_file);
|
||||
mtar_close(&tar);
|
||||
return rc;
|
||||
}
|
||||
183
utils/libtools.make
Normal file
183
utils/libtools.make
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
|
||||
# libtools.make
|
||||
#
|
||||
# Common Makefile for tools used by Rockbox Utility.
|
||||
# Provides rules for building as library, universal library (OS X) and
|
||||
# standalone binary.
|
||||
#
|
||||
# LIBSOURCES is a list of files to build the lib
|
||||
# SOURCES is a list of files to build for the main binary
|
||||
# EXTRADEPS is a list of make targets dependencies
|
||||
#
|
||||
ifndef V
|
||||
SILENT = @
|
||||
endif
|
||||
|
||||
# Get directory this Makefile is in for relative paths.
|
||||
TOP := $(dir $(lastword $(MAKEFILE_LIST)))
|
||||
ifeq ($(OS),Windows_NT)
|
||||
SHELL = cmd.exe
|
||||
mkdir = if not exist $(subst /,\,$(1)) mkdir $(subst /,\,$(1))
|
||||
rm = if exist $(subst /,\,$(1)) del /q /s $(subst /,\,$(1))
|
||||
else
|
||||
mkdir = mkdir -p $(1)
|
||||
rm = rm -rf $(1)
|
||||
endif
|
||||
|
||||
# overwrite for releases
|
||||
APPVERSION ?= $(shell $(TOP)/../tools/version.sh $(TOP)/..)
|
||||
GCCFLAGS += -DVERSION=\"$(APPVERSION)\"
|
||||
TARGET_DIR ?= $(abspath .)/
|
||||
|
||||
CC := gcc
|
||||
CXX := g++
|
||||
# use either CC or CXX to link: this makes sure the compiler knows about its
|
||||
# internal dependencies. Use CXX if we have at least one c++ file, since we
|
||||
# then need to link the c++ standard library (which CXX does for us).
|
||||
ifeq ($(strip $(filter %.cpp,$(SOURCES) $(LIBSOURCES))),)
|
||||
LD := $(CC)
|
||||
else
|
||||
LD := $(CXX)
|
||||
endif
|
||||
CPPDEFINES := $(shell echo foo | $(CROSS)$(CC) -dM -E -)
|
||||
|
||||
BINARY = $(OUTPUT)
|
||||
# when building a Windows binary add the correct file suffix
|
||||
ifeq ($(findstring CYGWIN,$(CPPDEFINES)),CYGWIN)
|
||||
BINARY = $(OUTPUT).exe
|
||||
GCCFLAGS += -mno-cygwin
|
||||
COMPILETARGET = cygwin
|
||||
else
|
||||
ifeq ($(findstring MINGW,$(CPPDEFINES)),MINGW)
|
||||
BINARY = $(OUTPUT).exe
|
||||
COMPILETARGET = mingw
|
||||
# use POSIX/C99 printf on windows
|
||||
GCCFLAGS += -D__USE_MINGW_ANSI_STDIO=1
|
||||
else
|
||||
ifeq ($(findstring APPLE,$(CPPDEFINES)),APPLE)
|
||||
COMPILETARGET = darwin
|
||||
LDOPTS += $(LDOPTS_OSX)
|
||||
else
|
||||
COMPILETARGET = posix
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
$(info Compiler creates $(COMPILETARGET) binaries)
|
||||
|
||||
# OS X specifics. Needs to consider cross compiling for Windows.
|
||||
ifeq ($(findstring APPLE,$(CPPDEFINES)),APPLE)
|
||||
# When building for 10.4+ we need to use gcc. Otherwise clang is used, so use
|
||||
# that to determine if we need to set arch and isysroot.
|
||||
ifeq ($(findstring __clang__,$(CPPDEFINES)),__clang__)
|
||||
GCCFLAGS += -mmacosx-version-min=10.5
|
||||
ifneq ($(ISYSROOT),)
|
||||
GCCFLAGS += -isysroot $(ISYSROOT)
|
||||
endif
|
||||
else
|
||||
# when building libs for OS X 10.4+ build for both i386 and ppc at the same time.
|
||||
# This creates fat objects, and ar can only create the archive but not operate
|
||||
# on it. As a result the ar call must NOT use the u (update) flag.
|
||||
ARCHFLAGS += -arch ppc -arch i386
|
||||
# building against SDK 10.4 is not compatible with gcc-4.2 (default on newer Xcode)
|
||||
# might need adjustment for older Xcode.
|
||||
CC = gcc-4.0
|
||||
GCCFLAGS += -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4
|
||||
endif
|
||||
endif
|
||||
|
||||
BUILD_DIR ?= $(TARGET_DIR)build$(COMPILETARGET)
|
||||
OBJDIR = $(abspath $(BUILD_DIR))/
|
||||
|
||||
all: $(BINARY)
|
||||
|
||||
OBJS := $(addsuffix .o,$(addprefix $(OBJDIR),$(notdir $(SOURCES))))
|
||||
LIBOBJS := $(addsuffix .o,$(addprefix $(OBJDIR),$(notdir $(LIBSOURCES))))
|
||||
|
||||
# create dependency files. Make sure to use the same prefix as with OBJS!
|
||||
$(foreach src,$(SOURCES) $(LIBSOURCES),$(eval $(addprefix $(OBJDIR),$(notdir $(src).o)): $(src)))
|
||||
$(foreach src,$(SOURCES) $(LIBSOURCES),$(eval $(addprefix $(OBJDIR),$(notdir $(src).d)): $(src)))
|
||||
DEPS = $(addprefix $(OBJDIR),$(addsuffix .d,$(notdir $(SOURCES) $(LIBSOURCES))))
|
||||
-include $(DEPS)
|
||||
|
||||
# additional link dependencies for the standalone executable
|
||||
# extra dependencies: libucl
|
||||
LIBUCL = libucl.a
|
||||
$(LIBUCL): $(OBJDIR)$(LIBUCL)
|
||||
|
||||
$(OBJDIR)$(LIBUCL):
|
||||
$(SILENT)$(MAKE) -C $(TOP)/../tools/ucl/src TARGET_DIR=$(OBJDIR) CC=$(CC) $@
|
||||
|
||||
LIBBZIP2 = libbz2.a
|
||||
$(LIBBZIP2): $(OBJDIR)$(LIBBZIP2)
|
||||
$(OBJDIR)$(LIBBZIP2):
|
||||
$(SILENT)$(MAKE) -C $(TOP)/bzip2 TARGET_DIR=$(OBJDIR) CC=$(CC) $@
|
||||
|
||||
LIBMICROTAR = libmicrotar.a
|
||||
$(LIBMICROTAR): $(OBJDIR)$(LIBMICROTAR)
|
||||
|
||||
$(OBJDIR)$(LIBMICROTAR):
|
||||
$(SILENT)$(MAKE) -C $(TOP)/../lib/microtar/src TARGET_DIR=$(OBJDIR) CC=$(CC) $@
|
||||
|
||||
# building the standalone executable
|
||||
$(BINARY): $(OBJS) $(EXTRADEPS) $(addprefix $(OBJDIR),$(EXTRALIBOBJS)) $(TARGET_DIR)lib$(OUTPUT).a
|
||||
$(info LD $@)
|
||||
$(SILENT)$(call mkdir,$(dir $@))
|
||||
# EXTRADEPS need to be built into OBJDIR.
|
||||
$(SILENT)$(CROSS)$(LD) $(ARCHFLAGS) $(LDFLAGS) -o $(BINARY) \
|
||||
$(OBJS) $(addprefix $(OBJDIR),$(EXTRADEPS)) \
|
||||
$(addprefix $(OBJDIR),$(EXTRALIBOBJS)) lib$(OUTPUT).a $(addprefix $(OBJDIR),$(EXTRADEPS)) $(LDOPTS)
|
||||
|
||||
# common rules
|
||||
$(OBJDIR)%.c.o:
|
||||
$(info CC $<)
|
||||
$(SILENT)$(call mkdir,$(dir $@))
|
||||
$(SILENT)$(CROSS)$(CC) $(ARCHFLAGS) $(GCCFLAGS) $(CFLAGS) -MMD -c -o $@ $<
|
||||
|
||||
$(OBJDIR)%.cpp.o:
|
||||
$(info CXX $<)
|
||||
$(SILENT)$(call mkdir,$(dir $@))
|
||||
$(SILENT)$(CROSS)$(CXX) $(ARCHFLAGS) $(GCCFLAGS) $(CXXFLAGS) -MMD -c -o $@ $<
|
||||
|
||||
# lib rules
|
||||
lib$(OUTPUT).a: $(TARGET_DIR)lib$(OUTPUT).a
|
||||
lib$(OUTPUT): $(TARGET_DIR)lib$(OUTPUT).a
|
||||
|
||||
$(TARGET_DIR)lib$(OUTPUT).a: $(LIBOBJS) \
|
||||
$(addprefix $(OBJDIR),$(EXTRALIBOBJS))
|
||||
# rules to build a DLL. Only works for W32 as target (i.e. MinGW toolchain)
|
||||
dll: $(OUTPUT).dll
|
||||
$(OUTPUT).dll: $(TARGET_DIR)$(OUTPUT).dll
|
||||
$(TARGET_DIR)$(OUTPUT).dll: $(LIBOBJS) $(addprefix $(OBJDIR),$(EXTRALIBOBJS))
|
||||
$(info DLL $(notdir $@))
|
||||
$(SILENT)$(call mkdir,$(dir $@))
|
||||
$(SILENT)$(CROSS)$(CC) $(ARCHFLAGS) $(GCCFLAGS) -shared -o $@ $^ \
|
||||
-Wl,--output-def,$(TARGET_DIR)$(OUTPUT).def
|
||||
|
||||
# create lib file from objects
|
||||
$(TARGET_DIR)lib$(OUTPUT).a: $(LIBOBJS) $(addprefix $(OBJDIR),$(EXTRALIBOBJS))
|
||||
$(info AR $(notdir $@))
|
||||
$(SILENT)$(call mkdir,$(dir $@))
|
||||
$(SILENT)$(call rm,$@)
|
||||
$(SILENT)$(CROSS)$(AR) rcs $@ $^
|
||||
|
||||
clean:
|
||||
$(call rm, $(OBJS) $(OUTPUT) $(TARGET_DIR)lib$(OUTPUT)*.a $(OUTPUT).dmg)
|
||||
$(call rm, $(OUTPUT)-* i386 ppc $(OBJDIR))
|
||||
|
||||
# extra tools
|
||||
BIN2C = $(TOP)/tools/bin2c
|
||||
$(BIN2C):
|
||||
$(MAKE) -C $(TOP)/tools
|
||||
|
||||
# OS X specifics
|
||||
$(OUTPUT).dmg: $(OUTPUT)
|
||||
$(info DMG $@)
|
||||
$(SILENT)$(call mkdir,"$(OUTPUT)-$(APPVERSION)")
|
||||
$(SILENT)cp -p $(OUTPUT) "$(OUTPUT)-$(APPVERSION)"
|
||||
$(SILENT)hdiutil create -srcfolder "$(OUTPUT)-$(APPVERSION)" $@
|
||||
2
utils/mkamsboot/.gitignore
vendored
Normal file
2
utils/mkamsboot/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
build/
|
||||
mkamsboot
|
||||
31
utils/mkamsboot/Makefile
Normal file
31
utils/mkamsboot/Makefile
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
|
||||
# We use the UCL code available in the Rockbox tools/ directory
|
||||
CFLAGS += -I../../tools/ucl/include -Wall
|
||||
|
||||
OUTPUT = mkamsboot
|
||||
LIBUCL = libucl.a
|
||||
|
||||
# inputs
|
||||
LIBSOURCES := dualboot.c md5.c mkamsboot.c
|
||||
SOURCES := main.c
|
||||
# additional link dependencies for the standalone executable
|
||||
EXTRADEPS := $(LIBUCL)
|
||||
|
||||
include ../libtools.make
|
||||
# explicit dependencies on dualboot.{c,h} and mkamsboot.h
|
||||
$(OBJDIR)mkamsboot.o: dualboot.h dualboot.c mkamsboot.c mkamsboot.h
|
||||
$(OBJDIR)main.o: dualboot.h dualboot.c main.c mkamsboot.h
|
||||
|
||||
|
||||
$(TARGET_DIR)$(OUTPUT).dll: EXTRALIBOBJS += $(TARGET_DIR)ucl.dll
|
||||
$(TARGET_DIR)$(OUTPUT).dll: $(TARGET_DIR)ucl.dll
|
||||
$(TARGET_DIR)ucl.dll:
|
||||
$(SILENT)$(MAKE) -C ../../tools/ucl/src/ \
|
||||
BUILD_DIR=$(BUILD_DIR) CC=$(CC) CROSS=$(CROSS) \
|
||||
TARGET_DIR=$(TARGET_DIR)/ ucl.dll
|
||||
67
utils/mkamsboot/README
Normal file
67
utils/mkamsboot/README
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
mkamsboot
|
||||
---------
|
||||
|
||||
A tool to inject a bootloader into a Sansa V2 (AMS) firmware file.
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
mkamsboot <firmware file> <boot file> <output file>
|
||||
|
||||
<firmware file> is an original Sansa firmware file obtained from the Sansa
|
||||
forums for example : http://forums.sandisk.com/sansa/?category.id=devices
|
||||
|
||||
<boot file> is the code you want to execute (a rockbox bootloader), previously
|
||||
scrambled with tools/scramble utility.
|
||||
|
||||
<output file> is the resulting firmware file which you'll have to copy on your
|
||||
Sansa player. See "Firmware filenames".
|
||||
|
||||
|
||||
Supported models
|
||||
----------------
|
||||
|
||||
Sansa Clip : firmware version starting with "01."
|
||||
Sansa Clip+ : firmware version starting with "01."
|
||||
Sansa Clipv2: firmware version starting with "02."
|
||||
Sansa ClipZip: firmware version starting with "01."
|
||||
Sansa Fuze : firmware version starting with "01."
|
||||
Sansa Fuzev2: firmware version starting with "02."
|
||||
Sansa E200v2: firmware version starting with "03."
|
||||
Sansa C200v2: firmware version starting with "03."
|
||||
Sansa M200v4: firmware version starting with "4."
|
||||
|
||||
|
||||
Firmware filenames
|
||||
------------------
|
||||
|
||||
For the firmware upgrade to happen, the firmware has to be named specially:
|
||||
|
||||
clip v2 : m30pa.bin
|
||||
clip : m300a.bin
|
||||
clip+ : clppa.bin
|
||||
clip zip: clpza.bin
|
||||
fuze : fuzea.bin
|
||||
fuzev2 : fuzpa.bin
|
||||
e200v2 : e200pa.bin
|
||||
c200v2 : c200pa.bin
|
||||
m200v4 : m200a.bin
|
||||
|
||||
|
||||
Dual-Boot
|
||||
---------
|
||||
|
||||
The purpose of this program is to provide dual-boot between the original
|
||||
firmware and the new (rockbox) firmware.
|
||||
|
||||
By default the player will boot into the new firmware.
|
||||
|
||||
To boot into the Original Firmware, you need to press the Left key.
|
||||
***Note : on the Clip+ you can alternatively press the Home key.
|
||||
***Note : on the Clip Zip you can alternatively press the Vol- key.
|
||||
|
||||
Hacking
|
||||
-------
|
||||
|
||||
See comments in mkamsboot.c and dualboot/dualboot.S for more information.
|
||||
152
utils/mkamsboot/dualboot.c
Normal file
152
utils/mkamsboot/dualboot.c
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/* Generated by bin2c */
|
||||
|
||||
#include "dualboot.h"
|
||||
|
||||
unsigned char nrv2e_d8[168] = {
|
||||
0x0f, 0x18, 0x01, 0x24, 0x65, 0x42, 0xe4, 0x07, 0x05, 0x26, 0x36, 0x02, 0x0a, 0xe0, 0x00, 0x20,
|
||||
0x00, 0x47, 0x04, 0x78, 0x64, 0x41, 0x01, 0x30, 0x24, 0x06, 0xf7, 0x46, 0x03, 0x78, 0x01, 0x30,
|
||||
0x13, 0x70, 0x01, 0x32, 0x24, 0x19, 0xfe, 0x46, 0xf3, 0xd0, 0xf7, 0xd2, 0x01, 0x21, 0x04, 0xe0,
|
||||
0x01, 0x39, 0x24, 0x19, 0xfe, 0x46, 0xec, 0xd0, 0x49, 0x41, 0x24, 0x19, 0xfe, 0x46, 0xe8, 0xd0,
|
||||
0x49, 0x41, 0x24, 0x19, 0xfe, 0x46, 0xe4, 0xd0, 0xf2, 0xd3, 0xcb, 0x1e, 0x00, 0x21, 0x08, 0xd3,
|
||||
0x1b, 0x02, 0x05, 0x78, 0x01, 0x30, 0x1d, 0x43, 0xed, 0x43, 0xd8, 0xd0, 0x6d, 0x10, 0x13, 0xd2,
|
||||
0x03, 0xe0, 0x24, 0x19, 0xfe, 0x46, 0xd4, 0xd0, 0x0e, 0xd2, 0x01, 0x21, 0x24, 0x19, 0xfe, 0x46,
|
||||
0xcf, 0xd0, 0x09, 0xd2, 0x24, 0x19, 0xfe, 0x46, 0xcb, 0xd0, 0x49, 0x41, 0x24, 0x19, 0xfe, 0x46,
|
||||
0xc7, 0xd0, 0xf7, 0xd3, 0x04, 0x31, 0x04, 0xe0, 0x24, 0x19, 0xfe, 0x46, 0xc1, 0xd0, 0x49, 0x41,
|
||||
0x02, 0x31, 0xee, 0x42, 0x00, 0xd2, 0x01, 0x31, 0x13, 0x78, 0x53, 0x5d, 0x13, 0x70, 0x01, 0x32,
|
||||
0x01, 0x39, 0xfa, 0xd1, 0xbe, 0xe7, 0x00, 0x00
|
||||
};
|
||||
unsigned char dualboot_clip[196] = {
|
||||
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
|
||||
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
|
||||
0x2c, 0x30, 0x0f, 0xe5, 0x6c, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
|
||||
0x00, 0x10, 0x80, 0xe5, 0x60, 0x00, 0x9f, 0xe5, 0x20, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
|
||||
0x80, 0x10, 0x80, 0xe5, 0x54, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
|
||||
0x04, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x1a, 0x70, 0x00, 0x1f, 0xe5,
|
||||
0x70, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x84, 0x00, 0x1f, 0xe5, 0x84, 0x10, 0x1f, 0xe5,
|
||||
0x7c, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4,
|
||||
0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2,
|
||||
0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x00, 0x00, 0x0d, 0xc8,
|
||||
0x00, 0x00, 0x0c, 0xc8
|
||||
};
|
||||
unsigned char dualboot_e200v2[176] = {
|
||||
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
|
||||
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
|
||||
0x2c, 0x30, 0x0f, 0xe5, 0x5c, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
|
||||
0x00, 0x10, 0x80, 0xe5, 0x50, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
|
||||
0x20, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x60, 0x00, 0x1f, 0xe5,
|
||||
0x60, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x74, 0x00, 0x1f, 0xe5, 0x74, 0x10, 0x1f, 0xe5,
|
||||
0x6c, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4,
|
||||
0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2,
|
||||
0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x00, 0x00, 0x0d, 0xc8
|
||||
};
|
||||
unsigned char dualboot_c200v2[272] = {
|
||||
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
|
||||
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
|
||||
0x2c, 0x30, 0x0f, 0xe5, 0xa8, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
|
||||
0x00, 0x10, 0x80, 0xe5, 0x9c, 0x00, 0x9f, 0xe5, 0x08, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x80, 0xe5,
|
||||
0x94, 0x20, 0x9f, 0xe5, 0x0c, 0x10, 0xa0, 0xe3, 0x20, 0x14, 0x82, 0xe5, 0x8c, 0x20, 0x9f, 0xe5,
|
||||
0xff, 0x10, 0xa0, 0xe3, 0x20, 0x14, 0x82, 0xe5, 0x84, 0x00, 0x9f, 0xe5, 0x91, 0x1a, 0xa0, 0xe3,
|
||||
0x08, 0x10, 0x80, 0xe5, 0x7c, 0x10, 0x9f, 0xe5, 0x10, 0x10, 0x80, 0xe5, 0x0c, 0x10, 0x90, 0xe5,
|
||||
0x01, 0x1b, 0x11, 0xe2, 0xfc, 0xff, 0xff, 0x0a, 0x6c, 0x10, 0x9f, 0xe5, 0x08, 0x10, 0x80, 0xe5,
|
||||
0x0c, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x11, 0xe2, 0xfc, 0xff, 0xff, 0x0a, 0xb4, 0x11, 0xd0, 0xe1,
|
||||
0x04, 0x00, 0x11, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0xac, 0x00, 0x1f, 0xe5, 0xac, 0x10, 0x1f, 0xe5,
|
||||
0x01, 0x00, 0x00, 0xea, 0xc0, 0x00, 0x1f, 0xe5, 0xc0, 0x10, 0x1f, 0xe5, 0xb8, 0x30, 0x1f, 0xe5,
|
||||
0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4, 0x01, 0x20, 0x43, 0xe4,
|
||||
0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2, 0x00, 0x20, 0xa0, 0xe3,
|
||||
0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x38, 0x00, 0x0f, 0xc8, 0x00, 0x00, 0x0c, 0xc8,
|
||||
0x00, 0x00, 0x0d, 0xc8, 0x00, 0x00, 0x12, 0xc8, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0x90, 0x08, 0x00
|
||||
};
|
||||
unsigned char dualboot_m200v4[180] = {
|
||||
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
|
||||
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
|
||||
0x2c, 0x30, 0x0f, 0xe5, 0x60, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
|
||||
0x00, 0x10, 0x80, 0xe5, 0x54, 0x00, 0x9f, 0xe5, 0x20, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
|
||||
0x80, 0x10, 0x80, 0xe5, 0x04, 0x20, 0x90, 0xe5, 0x00, 0x00, 0x52, 0xe3, 0x02, 0x00, 0x00, 0x1a,
|
||||
0x64, 0x00, 0x1f, 0xe5, 0x64, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x78, 0x00, 0x1f, 0xe5,
|
||||
0x78, 0x10, 0x1f, 0xe5, 0x70, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0,
|
||||
0x01, 0x20, 0x50, 0xe4, 0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
|
||||
0x01, 0x00, 0x83, 0xe2, 0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8,
|
||||
0x00, 0x00, 0x0b, 0xc8
|
||||
};
|
||||
unsigned char dualboot_fuze[176] = {
|
||||
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
|
||||
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
|
||||
0x2c, 0x30, 0x0f, 0xe5, 0x5c, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
|
||||
0x00, 0x10, 0x80, 0xe5, 0x50, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
|
||||
0x20, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x60, 0x00, 0x1f, 0xe5,
|
||||
0x60, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x74, 0x00, 0x1f, 0xe5, 0x74, 0x10, 0x1f, 0xe5,
|
||||
0x6c, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4,
|
||||
0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2,
|
||||
0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x00, 0x00, 0x0d, 0xc8
|
||||
};
|
||||
unsigned char dualboot_clipv2[240] = {
|
||||
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
|
||||
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
|
||||
0x2c, 0x30, 0x0f, 0xe5, 0x98, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
|
||||
0x00, 0x10, 0x80, 0xe5, 0x8c, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x0c, 0x10, 0xc1, 0xe3,
|
||||
0x00, 0x10, 0x80, 0xe5, 0x80, 0x00, 0x9f, 0xe5, 0x38, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
|
||||
0x08, 0x10, 0xa0, 0xe3, 0x20, 0x10, 0x80, 0xe5, 0x10, 0x10, 0xa0, 0xe3, 0x40, 0x10, 0x80, 0xe5,
|
||||
0x20, 0x10, 0xa0, 0xe3, 0x80, 0x10, 0x80, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x40, 0x10, 0x80, 0xe5,
|
||||
0x05, 0x10, 0xa0, 0xe3, 0x01, 0x10, 0x51, 0xe2, 0xfd, 0xff, 0xff, 0x1a, 0x04, 0x10, 0x90, 0xe5,
|
||||
0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x9c, 0x00, 0x1f, 0xe5, 0x9c, 0x10, 0x1f, 0xe5,
|
||||
0x01, 0x00, 0x00, 0xea, 0xb0, 0x00, 0x1f, 0xe5, 0xb0, 0x10, 0x1f, 0xe5, 0xa8, 0x30, 0x1f, 0xe5,
|
||||
0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4, 0x01, 0x20, 0x43, 0xe4,
|
||||
0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2, 0x00, 0x20, 0xa0, 0xe3,
|
||||
0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x0c, 0x00, 0x10, 0xc8, 0x00, 0x00, 0x0e, 0xc8
|
||||
};
|
||||
unsigned char dualboot_clipplus[184] = {
|
||||
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
|
||||
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
|
||||
0x2c, 0x30, 0x0f, 0xe5, 0x60, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
|
||||
0x00, 0x10, 0x80, 0xe5, 0x54, 0x00, 0x9f, 0xe5, 0x20, 0x10, 0x90, 0xe5, 0x50, 0x00, 0x9f, 0xe5,
|
||||
0x08, 0x20, 0x90, 0xe5, 0x01, 0x20, 0x82, 0xe1, 0x00, 0x00, 0x52, 0xe3, 0x02, 0x00, 0x00, 0x1a,
|
||||
0x64, 0x00, 0x1f, 0xe5, 0x64, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x78, 0x00, 0x1f, 0xe5,
|
||||
0x78, 0x10, 0x1f, 0xe5, 0x70, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0,
|
||||
0x01, 0x20, 0x50, 0xe4, 0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
|
||||
0x01, 0x00, 0x83, 0xe2, 0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8,
|
||||
0x00, 0x00, 0x0d, 0xc8, 0x00, 0x00, 0x0b, 0xc8
|
||||
};
|
||||
unsigned char dualboot_fuzev2[176] = {
|
||||
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
|
||||
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
|
||||
0x2c, 0x30, 0x0f, 0xe5, 0x5c, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
|
||||
0x00, 0x10, 0x80, 0xe5, 0x50, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
|
||||
0x20, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x1a, 0x60, 0x00, 0x1f, 0xe5,
|
||||
0x60, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x74, 0x00, 0x1f, 0xe5, 0x74, 0x10, 0x1f, 0xe5,
|
||||
0x6c, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4,
|
||||
0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2,
|
||||
0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x00, 0x00, 0x0d, 0xc8
|
||||
};
|
||||
unsigned char dualboot_clipzip[232] = {
|
||||
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
|
||||
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
|
||||
0x2c, 0x30, 0x0f, 0xe5, 0x90, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
|
||||
0x00, 0x10, 0x80, 0xe5, 0x84, 0x00, 0x9f, 0xe5, 0x00, 0x11, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3,
|
||||
0x11, 0x00, 0x00, 0x1a, 0x78, 0x00, 0x9f, 0xe5, 0x00, 0x14, 0x90, 0xe5, 0x06, 0x10, 0x81, 0xe3,
|
||||
0x20, 0x10, 0xc1, 0xe3, 0x00, 0x14, 0x80, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x08, 0x10, 0x80, 0xe5,
|
||||
0x04, 0x10, 0xa0, 0xe3, 0x10, 0x10, 0x80, 0xe5, 0x32, 0x10, 0xa0, 0xe3, 0x01, 0x10, 0x51, 0xe2,
|
||||
0xfd, 0xff, 0xff, 0x1a, 0x80, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x1a,
|
||||
0x94, 0x00, 0x1f, 0xe5, 0x94, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0xa8, 0x00, 0x1f, 0xe5,
|
||||
0xa8, 0x10, 0x1f, 0xe5, 0xa0, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0,
|
||||
0x01, 0x20, 0x50, 0xe4, 0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
|
||||
0x01, 0x00, 0x83, 0xe2, 0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8,
|
||||
0x00, 0x00, 0x0b, 0xc8, 0x00, 0x00, 0x0d, 0xc8
|
||||
};
|
||||
12
utils/mkamsboot/dualboot.h
Normal file
12
utils/mkamsboot/dualboot.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/* Generated by bin2c */
|
||||
|
||||
extern unsigned char nrv2e_d8[168];
|
||||
extern unsigned char dualboot_clip[196];
|
||||
extern unsigned char dualboot_e200v2[176];
|
||||
extern unsigned char dualboot_c200v2[272];
|
||||
extern unsigned char dualboot_m200v4[180];
|
||||
extern unsigned char dualboot_fuze[176];
|
||||
extern unsigned char dualboot_clipv2[240];
|
||||
extern unsigned char dualboot_clipplus[184];
|
||||
extern unsigned char dualboot_fuzev2[176];
|
||||
extern unsigned char dualboot_clipzip[232];
|
||||
3
utils/mkamsboot/dualboot/.gitignore
vendored
Normal file
3
utils/mkamsboot/dualboot/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
*.arm-bin
|
||||
*.o
|
||||
bin2c
|
||||
61
utils/mkamsboot/dualboot/Makefile
Normal file
61
utils/mkamsboot/dualboot/Makefile
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
CC=gcc
|
||||
CROSS_PREFIX?=arm-elf-eabi
|
||||
# Edit the following variables (plus copy/paste another set of rules) when
|
||||
# adding a new target. mkamsboot.c also needs to be edited to refer to these
|
||||
# new images.
|
||||
|
||||
BOOTOBJS = nrv2e_d8.o dualboot_clip.o dualboot_e200v2.o dualboot_c200v2.o dualboot_m200v4.o dualboot_fuze.o dualboot_clipv2.o dualboot_clipplus.o dualboot_fuzev2.o dualboot_clipzip.o
|
||||
BOOTBINS = nrv2e_d8.arm-bin dualboot_clip.arm-bin dualboot_e200v2.arm-bin dualboot_c200v2.arm-bin dualboot_m200v4.arm-bin dualboot_fuze.arm-bin dualboot_clipv2.arm-bin dualboot_clipplus.arm-bin dualboot_fuzev2.arm-bin dualboot_clipzip.arm-bin
|
||||
|
||||
all: ../dualboot.h ../dualboot.c
|
||||
|
||||
# Dualboot bootloaders
|
||||
|
||||
dualboot_clip.o: dualboot.S
|
||||
$(CROSS_PREFIX)-$(CC) -DSANSA_CLIP -c -o dualboot_clip.o dualboot.S
|
||||
|
||||
dualboot_fuze.o: dualboot.S
|
||||
$(CROSS_PREFIX)-$(CC) -DSANSA_FUZE -c -o dualboot_fuze.o dualboot.S
|
||||
|
||||
dualboot_e200v2.o: dualboot.S
|
||||
$(CROSS_PREFIX)-$(CC) -DSANSA_E200V2 -c -o dualboot_e200v2.o dualboot.S
|
||||
|
||||
dualboot_m200v4.o: dualboot.S
|
||||
$(CROSS_PREFIX)-$(CC) -DSANSA_M200V4 -c -o dualboot_m200v4.o dualboot.S
|
||||
|
||||
dualboot_c200v2.o: dualboot.S
|
||||
$(CROSS_PREFIX)-$(CC) -DSANSA_C200V2 -c -o dualboot_c200v2.o dualboot.S
|
||||
|
||||
dualboot_clipv2.o: dualboot.S
|
||||
$(CROSS_PREFIX)-$(CC) -DSANSA_CLIPV2 -c -o dualboot_clipv2.o dualboot.S
|
||||
|
||||
dualboot_clipplus.o: dualboot.S
|
||||
$(CROSS_PREFIX)-$(CC) -DSANSA_CLIPPLUS -c -o dualboot_clipplus.o dualboot.S
|
||||
|
||||
dualboot_fuzev2.o: dualboot.S
|
||||
$(CROSS_PREFIX)-$(CC) -DSANSA_FUZEV2 -c -o dualboot_fuzev2.o dualboot.S
|
||||
|
||||
dualboot_clipzip.o: dualboot.S
|
||||
$(CROSS_PREFIX)-$(CC) -DSANSA_CLIPZIP -c -o dualboot_clipzip.o dualboot.S
|
||||
|
||||
# Rules for the ucl unpack function
|
||||
nrv2e_d8.o: nrv2e_d8.S
|
||||
$(CROSS_PREFIX)-$(CC) -DPURE_THUMB -c -o nrv2e_d8.o nrv2e_d8.S
|
||||
|
||||
# Rules for the ARM code embedded in mkamsboot - assemble, link, then extract
|
||||
# the binary code and finally convert to .h for building in mkamsboot
|
||||
|
||||
%.arm-elf: %.o
|
||||
$(CROSS_PREFIX)-ld -e 0 -Ttext=0 -o $@ $<
|
||||
|
||||
%.arm-bin: %.arm-elf
|
||||
$(CROSS_PREFIX)-objcopy -O binary $< $@
|
||||
|
||||
../dualboot.c ../dualboot.h: $(BOOTBINS) bin2c
|
||||
./bin2c ../dualboot $(BOOTBINS)
|
||||
|
||||
bin2c: bin2c.c
|
||||
$(CC) -o bin2c bin2c.c
|
||||
|
||||
clean:
|
||||
rm -f *~ bin2c $(BOOTBINS) $(BOOTOBJS)
|
||||
140
utils/mkamsboot/dualboot/bin2c.c
Normal file
140
utils/mkamsboot/dualboot/bin2c.c
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2007 Dave Chapman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
static off_t filesize(int fd)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
fstat(fd,&buf);
|
||||
return buf.st_size;
|
||||
}
|
||||
|
||||
static void write_cfile(const unsigned char* buf, off_t len, FILE* fp, const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf(fp,"unsigned char %s[%ld] = {",name,len);
|
||||
|
||||
for (i=0;i<len;i++) {
|
||||
if ((i % 16) == 0) {
|
||||
fprintf(fp,"\n ");
|
||||
}
|
||||
if (i == (len-1)) {
|
||||
fprintf(fp,"0x%02x",buf[i]);
|
||||
} else if ((i % 16) == 15) {
|
||||
fprintf(fp,"0x%02x,",buf[i]);
|
||||
} else {
|
||||
fprintf(fp,"0x%02x, ",buf[i]);
|
||||
}
|
||||
}
|
||||
fprintf(fp,"\n};\n");
|
||||
}
|
||||
|
||||
int main (int argc, char* argv[])
|
||||
{
|
||||
char* cname;
|
||||
int i;
|
||||
FILE *cfile, *hfile;
|
||||
char cfilename[256], hfilename[256];
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr,"Usage: bin2c cname file1 [file2 [file3 ...]]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cname=argv[1];
|
||||
|
||||
snprintf(cfilename,256,"%s.c",cname);
|
||||
cfile = fopen(cfilename,"w+");
|
||||
if (cfile == NULL) {
|
||||
fprintf(stderr,"Couldn't open %s\n",cfilename);
|
||||
return 2;
|
||||
}
|
||||
|
||||
snprintf(hfilename,256,"%s.h",cname);
|
||||
hfile = fopen(hfilename,"w+");
|
||||
if (hfile == NULL) {
|
||||
fprintf(stderr,"Couldn't open %s\n",hfilename);
|
||||
fclose(cfile);
|
||||
return 3;
|
||||
}
|
||||
|
||||
fprintf(cfile,"/* Generated by bin2c */\n\n");
|
||||
fprintf(cfile,"#include \"%s\"\n\n", basename(hfilename));
|
||||
fprintf(hfile,"/* Generated by bin2c */\n\n");
|
||||
|
||||
for(i=0; i < argc - 2; i++) {
|
||||
unsigned char* buf;
|
||||
off_t len;
|
||||
off_t orig_len;
|
||||
char *ext;
|
||||
char *array = argv[2+i];
|
||||
|
||||
int fd = open(array,O_RDONLY|O_BINARY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr,"Can not open %s\n",argv[2+i]);
|
||||
fclose(cfile);
|
||||
fclose(hfile);
|
||||
return 4;
|
||||
}
|
||||
|
||||
orig_len = filesize(fd);
|
||||
/* pad to 32bit */
|
||||
len = (orig_len + 3) & ~3;
|
||||
|
||||
buf = malloc(len);
|
||||
if (read(fd,buf,orig_len) < orig_len) {
|
||||
fprintf(stderr,"Short read, aborting\n");
|
||||
return 5;
|
||||
}
|
||||
|
||||
/* pad to 32bit with zeros */
|
||||
if (len > orig_len)
|
||||
memset(buf+orig_len, 0, len-orig_len);
|
||||
|
||||
/* remove file extension */
|
||||
ext = strchr (array, '.');
|
||||
if (ext != NULL)
|
||||
*ext = '\0';
|
||||
write_cfile (buf, len, cfile, array);
|
||||
fprintf(hfile,"extern unsigned char %s[%ld];\n",array,len);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
fclose(cfile);
|
||||
fclose(hfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
307
utils/mkamsboot/dualboot/dualboot.S
Normal file
307
utils/mkamsboot/dualboot/dualboot.S
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2008 Rafaël Carré
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
.text
|
||||
|
||||
/* AS3525 hardware registers */
|
||||
.set GPIOA, 0xC80B0000
|
||||
.set GPIOB, 0xC80C0000
|
||||
.set GPIOC, 0xC80D0000
|
||||
.set GPIOD, 0xC80E0000
|
||||
.set CGU_PROC, 0xC80F0010
|
||||
.set CGU_PERI, 0xC80F0014
|
||||
.set CGU_DBOP, 0xC80F0038
|
||||
.set CCU_IO, 0xC810000C
|
||||
.set DBOP, 0xC8120000
|
||||
.set I2C_BASE, 0xC8070000
|
||||
.set I2C_DATA, 0x00
|
||||
.set I2C_SLAD0, 0x04
|
||||
.set I2C_CNTRL, 0x0c
|
||||
.set I2C_DACNT, 0x10
|
||||
.set I2C_CPSR0, 0x1c
|
||||
.set I2C_CPSR1, 0x20
|
||||
.set I2C_IMR, 0x24
|
||||
.set I2C_SR, 0x30
|
||||
.set I2C_SADDR, 0x44
|
||||
.set AS3514_I2C_ADDR, 0x46
|
||||
.set AS3514_IRQ_ENRD0, 0x25
|
||||
.set PCLK, 24000000
|
||||
.set I2C_CLK, 400000
|
||||
.set I2C_PRESCALER, ((PCLK + I2C_CLK -1) / I2C_CLK)
|
||||
.set I2C_PRESCALER_LOW, (I2C_PRESCALER & 0xff)
|
||||
.set I2C_PRESCALER_HIGH, (I2C_PRESCALER >> 8)
|
||||
#if I2C_PRESCALER_HIGH > 3
|
||||
#error i2c prescaler too big!
|
||||
#endif
|
||||
|
||||
b start @ skip our data
|
||||
|
||||
/* These values are filled in by mkamsboot - don't move them from offset 0x4 */
|
||||
|
||||
uclunpack_end: .word 0 /* End of the ucl_unpack function */
|
||||
uclunpack_size: .word 0 /* Size in bytes of the ucl_unpack function */
|
||||
|
||||
ucl_of_end: .word 0 /* End of the ucl-compressed OF image */
|
||||
ucl_of_size: .word 0 /* Size in bytes of the compressed OF image */
|
||||
|
||||
ucl_rb_end: .word 0 /* End of the ucl-compressed RB image */
|
||||
ucl_rb_size: .word 0 /* Size in bytes of the compressed RB image */
|
||||
|
||||
ucl_dest: .word 0 /* End of our destination buffer (end of memory) */
|
||||
|
||||
start:
|
||||
/* First copy the UCL unpack function to the end of RAM */
|
||||
ldr r0, uclunpack_end /* Source */
|
||||
ldr r1, uclunpack_size /* Source length */
|
||||
sub r2, r0, r1 /* Source start - 1*/
|
||||
|
||||
ldr r3, ucl_dest /* Destination end */
|
||||
|
||||
uclcopy:
|
||||
ldrb r4, [r0], #-1
|
||||
strb r4, [r3], #-1
|
||||
cmp r2, r0
|
||||
bne uclcopy
|
||||
|
||||
/* store the new destination buffer */
|
||||
str r3, ucl_dest
|
||||
|
||||
/* enable gpio clock */
|
||||
ldr r0, =CGU_PERI
|
||||
ldr r1, [r0]
|
||||
orr r1, r1, #(1<<16)
|
||||
str r1, [r0]
|
||||
|
||||
/* Here are model specific tests for dual boot (test left button) */
|
||||
|
||||
#ifdef SANSA_CLIP
|
||||
.set row, (1<<5) /* enable output on C5 */
|
||||
.set col, (1<<0) /* read keyscan column B0 */
|
||||
|
||||
ldr r0, =GPIOC
|
||||
mov r1, #row
|
||||
str r1, [r0, #0x400]
|
||||
str r1, [r0, #(4*row)]
|
||||
|
||||
ldr r0, =GPIOB
|
||||
mov r1, #0
|
||||
str r1, [r0, #0x400]
|
||||
ldr r1, [r0, #(4*col)]
|
||||
|
||||
cmp r1, #0
|
||||
bne boot_of
|
||||
#elif defined(SANSA_CLIPV2)
|
||||
.set row, (1<<4) /* enable output on D4 */
|
||||
.set col, (1<<0) /* read keyscan column D0 */
|
||||
|
||||
ldr r0, =CCU_IO
|
||||
ldr r1, [r0]
|
||||
bic r1, r1, #(3<<2) @ XPD works as general purpose IO
|
||||
str r1, [r0]
|
||||
|
||||
ldr r0, =GPIOD
|
||||
mov r1, #((1<<5)|(1<<4)|(1<<3)) /* all rows as output */
|
||||
str r1, [r0, #0x400]
|
||||
|
||||
/* all rows high */
|
||||
mov r1, #(1<<3)
|
||||
str r1, [r0, #(4*(1<<3))]
|
||||
mov r1, #(1<<4)
|
||||
str r1, [r0, #(4*(1<<4))]
|
||||
mov r1, #(1<<5)
|
||||
str r1, [r0, #(4*(1<<5))]
|
||||
|
||||
mov r1, #0 /* button row low */
|
||||
str r1, [r0, #(4*row)]
|
||||
|
||||
mov r1, #5 /* small delay */
|
||||
1: subs r1, r1, #1
|
||||
bne 1b
|
||||
|
||||
ldr r1, [r0, #(4*col)]
|
||||
|
||||
cmp r1, #0
|
||||
beq boot_of
|
||||
#elif defined(SANSA_E200V2) || defined(SANSA_FUZE)
|
||||
ldr r0, =GPIOC
|
||||
mov r1, #0
|
||||
str r1, [r0, #0x400]
|
||||
ldr r1, [r0, #0x20] /* read pin C3 */
|
||||
|
||||
cmp r1, #0 /* C3 = #0 means button pressed */
|
||||
beq boot_of
|
||||
|
||||
#elif defined(SANSA_FUZEV2)
|
||||
ldr r0, =GPIOC
|
||||
mov r1, #0
|
||||
str r1, [r0, #0x400]
|
||||
ldr r1, [r0, #0x20] /* read pin C3 */
|
||||
|
||||
cmp r1, #0 /* C3 != #0 means button pressed */
|
||||
bne boot_of
|
||||
|
||||
#elif defined(SANSA_CLIPPLUS)
|
||||
@ read pins
|
||||
ldr r0, =GPIOC
|
||||
ldr r1, [r0, #4*(1<<3)] @ read pin C3 "|<<"
|
||||
|
||||
ldr r0, =GPIOA
|
||||
ldr r2, [r0, #4*(1<<1)] @ read pin A1 "Home"
|
||||
|
||||
orr r2, r2, r1 @ c3 || A1
|
||||
|
||||
cmp r2, #0 @ test input from pins
|
||||
bne boot_of @ branch directly to OF if either pin high
|
||||
|
||||
#elif defined(SANSA_CLIPZIP)
|
||||
@ read pins
|
||||
ldr r0, =GPIOA
|
||||
ldr r1, [r0, #4*(1<<6)] @ read GPIO A6 "vol-"
|
||||
|
||||
cmp r1, #0 @ test input from pins
|
||||
bne boot_of @ branch directly to OF if either pin high
|
||||
|
||||
ldr r0, =GPIOC
|
||||
|
||||
ldr r1, [r0, #0x400]
|
||||
orr r1, r1, #((1<<1)|(1<<2)) @ output
|
||||
bic r1, r1, #(1<<5) @ input
|
||||
str r1, [r0, #0x400]
|
||||
|
||||
mov r1, #0
|
||||
str r1, [r0, #4*(1<<1)] @ zero C1
|
||||
mov r1, #(1<<2)
|
||||
str r1, [r0, #4*(1<<2)] @ set C2
|
||||
|
||||
mov r1, #50 /* small delay */
|
||||
1: subs r1, r1, #1
|
||||
bne 1b
|
||||
|
||||
ldr r1, [r0, #4*(1<<5)] @ read C5 = left
|
||||
|
||||
cmp r1, #0
|
||||
bne boot_of
|
||||
|
||||
#elif defined(SANSA_C200V2)
|
||||
.set BUTTON_LEFT, (1<< 2)
|
||||
.set BUTTON_DOWN, (1<< 3)
|
||||
.set BUTTON_SELECT, (1<< 4)
|
||||
.set BUTTON_UP, (1<< 5)
|
||||
.set BUTTON_RIGHT, (1<< 6)
|
||||
.set BUTTON_HOLD, (1<<12)
|
||||
|
||||
ldr r0, =CGU_DBOP
|
||||
mov r1, #(1<<3) @ DBOP freq = PCLK, clock enabled
|
||||
str r1, [r0]
|
||||
|
||||
@ AFSEL needs to be set for this to work
|
||||
ldr r2, =GPIOB
|
||||
mov r1, #0xc
|
||||
str r1, [r2, #0x420] @ GPIOB_AFSEL
|
||||
ldr r2, =GPIOC
|
||||
mov r1, #0xff
|
||||
str r1, [r2, #0x420] @ GPIOC_AFSEL
|
||||
|
||||
ldr r0, =DBOP
|
||||
@ TIMPOL doesn't matter here since we don't need
|
||||
@ the control signals.
|
||||
|
||||
@ 16 bit data width
|
||||
@ enable write
|
||||
@ tri-state output
|
||||
ldr r1, =0x00091000
|
||||
str r1, [r0, #8] @ DBOP_CTRL
|
||||
|
||||
ldr r1, =0xf0ff @ precharge
|
||||
str r1, [r0, #0x10] @ DBOP_DOUT
|
||||
|
||||
2: ldr r1, [r0, #0xc] @ DOBP_STAT
|
||||
ands r1, r1, #(1<<10)
|
||||
beq 2b @ make sure fifo is empty
|
||||
|
||||
@ 16 bit data width
|
||||
@ start read
|
||||
@ tri-state output
|
||||
@ strobe time 31
|
||||
ldr r1, =0x0008901f
|
||||
str r1, [r0, #8] @ DBOP_CTRL
|
||||
|
||||
3: ldr r1, [r0, #0xc] @ DOBP_STAT
|
||||
ands r1, r1, #(1<<16)
|
||||
beq 3b @ wait for valid data
|
||||
|
||||
ldrh r1, [r0, #0x14] @ DBOP_DIN
|
||||
|
||||
tst r1, #BUTTON_LEFT @ boot of?
|
||||
beq boot_of
|
||||
#elif defined(SANSA_M200V4)
|
||||
.set row, (1<<5) /* enable output on A5 */
|
||||
.set col, (1<<0) /* read keyscan column A0 */
|
||||
|
||||
ldr r0, =GPIOA
|
||||
mov r1, #row
|
||||
str r1, [r0, #0x400]
|
||||
str r1, [r0, #(4*row)]
|
||||
|
||||
ldr r2, [r0, #(4*col)]
|
||||
|
||||
/* check value read (1 means button pressed) */
|
||||
cmp r2, #0
|
||||
bne boot_of
|
||||
#else
|
||||
#error No target-specific key check defined!
|
||||
#endif
|
||||
|
||||
/* The dualboot button was not held, so we boot rockbox */
|
||||
ldr r0, ucl_rb_end /* Address of compressed image */
|
||||
ldr r1, ucl_rb_size /* Compressed size */
|
||||
b decompress
|
||||
|
||||
boot_of:
|
||||
ldr r0, ucl_of_end /* Address of compressed image */
|
||||
ldr r1, ucl_of_size /* Compressed size */
|
||||
|
||||
|
||||
decompress:
|
||||
/* At this point: */
|
||||
/* r0 = source_end for UCL image to copy */
|
||||
/* r1 = size of UCL image to copy */
|
||||
|
||||
ldr r3, ucl_dest
|
||||
add r5, r3, #2 /* r5 is entry point of copy of uclunpack */
|
||||
/* function, plus one (for thumb mode */
|
||||
|
||||
sub r4, r3, r1 /* r4 := destination_start - 1 */
|
||||
|
||||
fw_copy:
|
||||
ldrb r2, [r0], #-1
|
||||
strb r2, [r3], #-1
|
||||
cmp r3, r4 /* Stop when we reached dest_start-1 */
|
||||
bne fw_copy
|
||||
|
||||
/* Call the ucl decompress function, which will branch to 0x0 */
|
||||
/* on completion */
|
||||
add r0, r3, #1 /* r0 := Start of compressed image */
|
||||
/* r1 already contains compressed size */
|
||||
mov r2, #0 /* r2 := Destination for unpacking */
|
||||
bx r5 /* Branch to uclunpack, switching to thumb */
|
||||
|
||||
/* never reached : uclunpack will branch to the reset vector (0x0) */
|
||||
198
utils/mkamsboot/dualboot/nrv2e_d8.S
Normal file
198
utils/mkamsboot/dualboot/nrv2e_d8.S
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
/* arm_nrv2e_d8.S -- ARM decompressor for NRV2E
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2008 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996-2008 Laszlo Molnar
|
||||
Copyright (C) 2000-2008 John F. Reiser
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer Laszlo Molnar
|
||||
<markus@oberhumer.com> <ml1050@users.sourceforge.net>
|
||||
|
||||
John F. Reiser
|
||||
<jreiser@users.sourceforge.net>
|
||||
*/
|
||||
#define SAFE 0 /* 1 for src+dst bounds checking: cost 40 bytes */
|
||||
|
||||
#define src r0
|
||||
#define len r1 /* overlaps 'cnt' */
|
||||
#define dst r2
|
||||
#define tmp r3
|
||||
#define bits r4
|
||||
#define off r5
|
||||
#define wrnk r6 /* 0x500 M2_MAX_OFFSET before "wrinkle" */
|
||||
#define srclim r7
|
||||
#if 1==SAFE /*{*/
|
||||
#define dstlim r12
|
||||
#endif /*}*/
|
||||
|
||||
#define cnt r1 /* overlaps 'len' while reading an offset */
|
||||
|
||||
#if 1==SAFE /*{*/
|
||||
#define CHECK_SRC cmp src,srclim; bhs bad_src_n2e
|
||||
#define CHECK_DST cmp dst,dstlim; bhs bad_dst_n2e
|
||||
#else /*}{*/
|
||||
#define CHECK_SRC /*empty*/
|
||||
#define CHECK_DST /*empty*/
|
||||
#endif /*}*/
|
||||
|
||||
#if 0 /*{ DEBUG only: check newly-decompressed against original dst */
|
||||
#define CHECK_BYTE \
|
||||
push {wrnk}; \
|
||||
ldrb wrnk,[dst]; \
|
||||
cmp wrnk,tmp; beq 0f; bkpt; \
|
||||
0: pop {wrnk}
|
||||
#else /*}{*/
|
||||
#define CHECK_BYTE /*empty*/
|
||||
#endif /*}*/
|
||||
|
||||
/* "mov lr,pc; bxx ..." implements conditional subroutine call
|
||||
*
|
||||
* NOTE: the lsb will not be set, so you MUST NOT use 'bx lr' to return,
|
||||
* else the T bit will be cleared and processor will go in ARM state */
|
||||
#define GETBIT add bits,bits; mov lr,pc; beq get1_n2e
|
||||
|
||||
#define getnextb(reg) GETBIT; adc reg,reg
|
||||
#define jnextb0 GETBIT; bcc
|
||||
#define jnextb1 GETBIT; bcs
|
||||
|
||||
#ifndef PURE_THUMB
|
||||
ucl_nrv2e_decompress_8: .globl ucl_nrv2e_decompress_8 @ ARM mode
|
||||
.type ucl_nrv2e_decompress_8, %function
|
||||
/* error = (*)(char const *src, int len_src, char *dst, int *plen_dst)
|
||||
Actual decompressed length is stored through plen_dst.
|
||||
For SAFE mode: at call, *plen_dst must be allowed length of output buffer.
|
||||
*/
|
||||
adr r12,1+.thumb_nrv2e_d8; bx r12 @ enter THUMB mode
|
||||
#endif
|
||||
.code 16 @ THUMB mode
|
||||
.thumb_func
|
||||
|
||||
.thumb_nrv2e_d8:
|
||||
#if 0
|
||||
push {r2,r3, r4,r5,r6,r7, lr}
|
||||
#define sp_DST0 0 /* stack offset of original dst */
|
||||
#endif
|
||||
add srclim,len,src @ srclim= eof_src;
|
||||
#if 1==SAFE /*{*/
|
||||
ldr tmp,[r3] @ len_dst
|
||||
add tmp,dst
|
||||
mov dstlim,tmp
|
||||
#endif /*}*/
|
||||
mov bits,#1; neg off,bits @ off= -1 initial condition
|
||||
lsl bits,#31 @ 1<<31: refill next time
|
||||
mov wrnk,#5
|
||||
lsl wrnk,#8 @ 0x500 @ nrv2e M2_MAX_OFFSET
|
||||
b top_n2e
|
||||
|
||||
#if 1==SAFE /*{*/
|
||||
bad_dst_n2e: # return value will be 2
|
||||
add src,srclim,#1
|
||||
bad_src_n2e: # return value will be 1
|
||||
add src,#1
|
||||
#endif /*}*/
|
||||
eof_n2e:
|
||||
#if 0
|
||||
pop {r3,r4} @ r3= orig_dst; r4= plen_dst
|
||||
sub src,srclim @ 0 if actual src length equals expected length
|
||||
sub dst,r3 @ actual dst length
|
||||
str dst,[r4]
|
||||
pop {r4,r5,r6,r7 /*,pc*/}
|
||||
pop {r1}; bx r1 @ "pop {,pc}" fails return to ARM mode on ARMv4T
|
||||
#else
|
||||
mov r0, #0
|
||||
bx r0 /* Branch to 0x0, switch to ARM mode */
|
||||
#endif
|
||||
|
||||
get1_n2e: @ In: Carry set [from adding 0x80000000 (1<<31) to itself]
|
||||
ldrb bits,[src] @ zero-extend next byte
|
||||
adc bits,bits @ double and insert CarryIn as low bit
|
||||
CHECK_SRC
|
||||
add src,#1
|
||||
lsl bits,#24 @ move to top byte, and set CarryOut from old bit 8
|
||||
/* NOTE: the following instruction will not work on ARMv7+, because
|
||||
* it will update the T bit and return into ARM state */
|
||||
mov pc,lr @ return, stay in current (THUMB) mode
|
||||
|
||||
lit_n2e:
|
||||
CHECK_SRC; ldrb tmp,[src]; add src,#1
|
||||
CHECK_BYTE
|
||||
CHECK_DST; strb tmp,[dst]; add dst,#1
|
||||
top_n2e:
|
||||
jnextb1 lit_n2e
|
||||
mov cnt,#1; b getoff_n2e
|
||||
|
||||
off_n2e:
|
||||
sub cnt,#1
|
||||
getnextb(cnt)
|
||||
getoff_n2e:
|
||||
getnextb(cnt)
|
||||
jnextb0 off_n2e
|
||||
|
||||
sub tmp,cnt,#3 @ set Carry
|
||||
mov len,#0 @ Carry unaffected
|
||||
blo offprev_n2e @ cnt was 2; tests Carry only
|
||||
lsl tmp,#8
|
||||
CHECK_SRC; ldrb off,[src]; add src,#1 @ low 7+1 bits
|
||||
orr off,tmp
|
||||
mvn off,off; beq eof_n2e @ off= ~off
|
||||
asr off,#1; bcs lenlast_n2e
|
||||
b lenmore_n2e
|
||||
|
||||
offprev_n2e:
|
||||
jnextb1 lenlast_n2e
|
||||
lenmore_n2e:
|
||||
mov len,#1
|
||||
jnextb1 lenlast_n2e
|
||||
len_n2e:
|
||||
getnextb(len)
|
||||
jnextb0 len_n2e
|
||||
add len,#6-2
|
||||
b gotlen_n2e
|
||||
|
||||
lenlast_n2e:
|
||||
getnextb(len) @ 0,1,2,3
|
||||
add len,#2
|
||||
gotlen_n2e: @ 'cmn': add the inputs, set condition codes, discard the sum
|
||||
cmn wrnk,off; bcs near_n2e @ within M2_MAX_OFFSET
|
||||
add len,#1 @ too far away, so minimum match length is 3
|
||||
near_n2e:
|
||||
#if 1==SAFE /*{*/
|
||||
ldr tmp,[sp,#sp_DST0]
|
||||
sub tmp,dst
|
||||
sub tmp,off; bhi bad_dst_n2e @ reaching back too far
|
||||
|
||||
add tmp,dst,cnt
|
||||
cmp tmp,dstlim; bhi bad_dst_n2e @ too much output
|
||||
#endif /*}*/
|
||||
ldrb tmp,[dst] @ force cacheline allocate
|
||||
copy_n2e:
|
||||
ldrb tmp,[dst,off]
|
||||
CHECK_BYTE
|
||||
strb tmp,[dst]; add dst,#1
|
||||
sub len,#1; bne copy_n2e
|
||||
b top_n2e
|
||||
|
||||
#ifndef PURE_THUMB
|
||||
.size ucl_nrv2e_decompress_8, .-ucl_nrv2e_decompress_8
|
||||
#endif
|
||||
|
||||
/*
|
||||
vi:ts=8:et:nowrap
|
||||
*/
|
||||
174
utils/mkamsboot/main.c
Normal file
174
utils/mkamsboot/main.c
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* mkamsboot - a tool for merging bootloader code into an Sansa V2
|
||||
* (AMS) firmware file
|
||||
*
|
||||
* Copyright (C) 2008 Dave Chapman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ucl/ucl.h>
|
||||
|
||||
#include "mkamsboot.h"
|
||||
|
||||
/* Header for ARM code binaries */
|
||||
#include "dualboot.h"
|
||||
|
||||
/* Win32 compatibility */
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
/* standalone executable */
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
char *infile, *bootfile, *outfile;
|
||||
int fdout;
|
||||
off_t len;
|
||||
uint32_t n;
|
||||
unsigned char* buf;
|
||||
int firmware_size;
|
||||
int bootloader_size;
|
||||
unsigned char* of_packed;
|
||||
int of_packedsize;
|
||||
unsigned char* rb_packed;
|
||||
int rb_packedsize;
|
||||
int patchable;
|
||||
int totalsize;
|
||||
int model;
|
||||
char errstr[200];
|
||||
struct md5sums sum;
|
||||
char md5sum[33]; /* 32 digits + \0 */
|
||||
|
||||
sum.md5 = md5sum;
|
||||
|
||||
/* VERSION comes frome the Makefile */
|
||||
fprintf(stderr,
|
||||
"mkamsboot Version " VERSION "\n"
|
||||
"This is free software; see the source for copying conditions. There is NO\n"
|
||||
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
|
||||
"\n");
|
||||
|
||||
if(argc != 4) {
|
||||
printf("Usage: mkamsboot <firmware file> <boot file> <output file>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
infile = argv[1];
|
||||
bootfile = argv[2];
|
||||
outfile = argv[3];
|
||||
|
||||
/* Load bootloader file */
|
||||
rb_packed = load_rockbox_file(bootfile, &model, &bootloader_size,
|
||||
&rb_packedsize, errstr, sizeof(errstr));
|
||||
if (rb_packed == NULL) {
|
||||
fprintf(stderr, "%s", errstr);
|
||||
fprintf(stderr, "[ERR] Could not load %s\n", bootfile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Load original firmware file */
|
||||
buf = load_of_file(infile, model, &len, &sum,
|
||||
&firmware_size, &of_packed, &of_packedsize, errstr, sizeof(errstr));
|
||||
|
||||
if (buf == NULL) {
|
||||
free(rb_packed);
|
||||
fprintf(stderr, "%s", errstr);
|
||||
fprintf(stderr, "[ERR] Could not load %s\n", infile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "[INFO] Original firmware MD5 checksum match\n");
|
||||
fprintf(stderr, "[INFO] Model: Sansa %s v%d - Firmware version: %s\n",
|
||||
ams_identity[sum.model].model_name,
|
||||
ams_identity[sum.model].hw_revision, sum.version);
|
||||
|
||||
|
||||
printf("[INFO] Firmware patching has begun !\n\n");
|
||||
|
||||
fprintf(stderr, "[INFO] Original firmware size: %8d bytes\n",
|
||||
firmware_size);
|
||||
fprintf(stderr, "[INFO] Packed OF size: %8d bytes\n",
|
||||
of_packedsize);
|
||||
fprintf(stderr, "[INFO] Bootloader size: %8d bytes\n",
|
||||
bootloader_size);
|
||||
fprintf(stderr, "[INFO] Packed bootloader size: %8d bytes\n",
|
||||
rb_packedsize);
|
||||
fprintf(stderr, "[INFO] Dual-boot function size: %8d bytes\n",
|
||||
ams_identity[sum.model].bootloader_size);
|
||||
fprintf(stderr, "[INFO] UCL unpack function size: %8zu bytes\n",
|
||||
sizeof(nrv2e_d8));
|
||||
fprintf(stderr, "[INFO] Original firmware version: %8u bytes\n",
|
||||
0x200);
|
||||
|
||||
patchable = check_sizes(sum.model, rb_packedsize, bootloader_size,
|
||||
of_packedsize, firmware_size, &totalsize, errstr, sizeof(errstr));
|
||||
|
||||
fprintf(stderr, "[INFO] Total size of new image: %8d bytes\n", totalsize);
|
||||
|
||||
if (!patchable) {
|
||||
fprintf(stderr, "%s", errstr);
|
||||
free(buf);
|
||||
free(of_packed);
|
||||
free(rb_packed);
|
||||
return 1;
|
||||
}
|
||||
|
||||
patch_firmware(sum.model, ams_identity[sum.model].fw_revision,
|
||||
firmware_size, buf, len, of_packed, of_packedsize, rb_packed,
|
||||
rb_packedsize);
|
||||
|
||||
/* Write the new firmware */
|
||||
fdout = open(outfile, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666);
|
||||
|
||||
if (fdout < 0) {
|
||||
fprintf(stderr, "[ERR] Could not open %s for writing\n", outfile);
|
||||
free(buf);
|
||||
free(of_packed);
|
||||
free(rb_packed);
|
||||
return 1;
|
||||
}
|
||||
|
||||
n = write(fdout, buf, len);
|
||||
|
||||
if (n != (unsigned)len) {
|
||||
fprintf(stderr, "[ERR] Could not write firmware file\n");
|
||||
free(buf);
|
||||
free(of_packed);
|
||||
free(rb_packed);
|
||||
return 1;
|
||||
}
|
||||
|
||||
close(fdout);
|
||||
free(buf);
|
||||
free(of_packed);
|
||||
free(rb_packed);
|
||||
fprintf(stderr, "\n[INFO] Patching succeeded!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
246
utils/mkamsboot/md5.c
Normal file
246
utils/mkamsboot/md5.c
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* RFC 1321 compliant MD5 implementation
|
||||
*
|
||||
* Copyright (C) 2001-2003 Christophe Devine
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
#define GET_UINT32(n,b,i) \
|
||||
{ \
|
||||
(n) = ( (uint32) (b)[(i) ] ) \
|
||||
| ( (uint32) (b)[(i) + 1] << 8 ) \
|
||||
| ( (uint32) (b)[(i) + 2] << 16 ) \
|
||||
| ( (uint32) (b)[(i) + 3] << 24 ); \
|
||||
}
|
||||
|
||||
#define PUT_UINT32(n,b,i) \
|
||||
{ \
|
||||
(b)[(i) ] = (uint8) ( (n) ); \
|
||||
(b)[(i) + 1] = (uint8) ( (n) >> 8 ); \
|
||||
(b)[(i) + 2] = (uint8) ( (n) >> 16 ); \
|
||||
(b)[(i) + 3] = (uint8) ( (n) >> 24 ); \
|
||||
}
|
||||
|
||||
void md5_starts( md5_context *ctx )
|
||||
{
|
||||
ctx->total[0] = 0;
|
||||
ctx->total[1] = 0;
|
||||
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xEFCDAB89;
|
||||
ctx->state[2] = 0x98BADCFE;
|
||||
ctx->state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
void md5_process( md5_context *ctx, uint8 data[64] )
|
||||
{
|
||||
uint32 X[16], A, B, C, D;
|
||||
|
||||
GET_UINT32( X[0], data, 0 );
|
||||
GET_UINT32( X[1], data, 4 );
|
||||
GET_UINT32( X[2], data, 8 );
|
||||
GET_UINT32( X[3], data, 12 );
|
||||
GET_UINT32( X[4], data, 16 );
|
||||
GET_UINT32( X[5], data, 20 );
|
||||
GET_UINT32( X[6], data, 24 );
|
||||
GET_UINT32( X[7], data, 28 );
|
||||
GET_UINT32( X[8], data, 32 );
|
||||
GET_UINT32( X[9], data, 36 );
|
||||
GET_UINT32( X[10], data, 40 );
|
||||
GET_UINT32( X[11], data, 44 );
|
||||
GET_UINT32( X[12], data, 48 );
|
||||
GET_UINT32( X[13], data, 52 );
|
||||
GET_UINT32( X[14], data, 56 );
|
||||
GET_UINT32( X[15], data, 60 );
|
||||
|
||||
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
|
||||
|
||||
#define P(a,b,c,d,k,s,t) \
|
||||
{ \
|
||||
a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
|
||||
}
|
||||
|
||||
A = ctx->state[0];
|
||||
B = ctx->state[1];
|
||||
C = ctx->state[2];
|
||||
D = ctx->state[3];
|
||||
|
||||
#define F(x,y,z) (z ^ (x & (y ^ z)))
|
||||
|
||||
P( A, B, C, D, 0, 7, 0xD76AA478 );
|
||||
P( D, A, B, C, 1, 12, 0xE8C7B756 );
|
||||
P( C, D, A, B, 2, 17, 0x242070DB );
|
||||
P( B, C, D, A, 3, 22, 0xC1BDCEEE );
|
||||
P( A, B, C, D, 4, 7, 0xF57C0FAF );
|
||||
P( D, A, B, C, 5, 12, 0x4787C62A );
|
||||
P( C, D, A, B, 6, 17, 0xA8304613 );
|
||||
P( B, C, D, A, 7, 22, 0xFD469501 );
|
||||
P( A, B, C, D, 8, 7, 0x698098D8 );
|
||||
P( D, A, B, C, 9, 12, 0x8B44F7AF );
|
||||
P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
|
||||
P( B, C, D, A, 11, 22, 0x895CD7BE );
|
||||
P( A, B, C, D, 12, 7, 0x6B901122 );
|
||||
P( D, A, B, C, 13, 12, 0xFD987193 );
|
||||
P( C, D, A, B, 14, 17, 0xA679438E );
|
||||
P( B, C, D, A, 15, 22, 0x49B40821 );
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (y ^ (z & (x ^ y)))
|
||||
|
||||
P( A, B, C, D, 1, 5, 0xF61E2562 );
|
||||
P( D, A, B, C, 6, 9, 0xC040B340 );
|
||||
P( C, D, A, B, 11, 14, 0x265E5A51 );
|
||||
P( B, C, D, A, 0, 20, 0xE9B6C7AA );
|
||||
P( A, B, C, D, 5, 5, 0xD62F105D );
|
||||
P( D, A, B, C, 10, 9, 0x02441453 );
|
||||
P( C, D, A, B, 15, 14, 0xD8A1E681 );
|
||||
P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
|
||||
P( A, B, C, D, 9, 5, 0x21E1CDE6 );
|
||||
P( D, A, B, C, 14, 9, 0xC33707D6 );
|
||||
P( C, D, A, B, 3, 14, 0xF4D50D87 );
|
||||
P( B, C, D, A, 8, 20, 0x455A14ED );
|
||||
P( A, B, C, D, 13, 5, 0xA9E3E905 );
|
||||
P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
|
||||
P( C, D, A, B, 7, 14, 0x676F02D9 );
|
||||
P( B, C, D, A, 12, 20, 0x8D2A4C8A );
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (x ^ y ^ z)
|
||||
|
||||
P( A, B, C, D, 5, 4, 0xFFFA3942 );
|
||||
P( D, A, B, C, 8, 11, 0x8771F681 );
|
||||
P( C, D, A, B, 11, 16, 0x6D9D6122 );
|
||||
P( B, C, D, A, 14, 23, 0xFDE5380C );
|
||||
P( A, B, C, D, 1, 4, 0xA4BEEA44 );
|
||||
P( D, A, B, C, 4, 11, 0x4BDECFA9 );
|
||||
P( C, D, A, B, 7, 16, 0xF6BB4B60 );
|
||||
P( B, C, D, A, 10, 23, 0xBEBFBC70 );
|
||||
P( A, B, C, D, 13, 4, 0x289B7EC6 );
|
||||
P( D, A, B, C, 0, 11, 0xEAA127FA );
|
||||
P( C, D, A, B, 3, 16, 0xD4EF3085 );
|
||||
P( B, C, D, A, 6, 23, 0x04881D05 );
|
||||
P( A, B, C, D, 9, 4, 0xD9D4D039 );
|
||||
P( D, A, B, C, 12, 11, 0xE6DB99E5 );
|
||||
P( C, D, A, B, 15, 16, 0x1FA27CF8 );
|
||||
P( B, C, D, A, 2, 23, 0xC4AC5665 );
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (y ^ (x | ~z))
|
||||
|
||||
P( A, B, C, D, 0, 6, 0xF4292244 );
|
||||
P( D, A, B, C, 7, 10, 0x432AFF97 );
|
||||
P( C, D, A, B, 14, 15, 0xAB9423A7 );
|
||||
P( B, C, D, A, 5, 21, 0xFC93A039 );
|
||||
P( A, B, C, D, 12, 6, 0x655B59C3 );
|
||||
P( D, A, B, C, 3, 10, 0x8F0CCC92 );
|
||||
P( C, D, A, B, 10, 15, 0xFFEFF47D );
|
||||
P( B, C, D, A, 1, 21, 0x85845DD1 );
|
||||
P( A, B, C, D, 8, 6, 0x6FA87E4F );
|
||||
P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
|
||||
P( C, D, A, B, 6, 15, 0xA3014314 );
|
||||
P( B, C, D, A, 13, 21, 0x4E0811A1 );
|
||||
P( A, B, C, D, 4, 6, 0xF7537E82 );
|
||||
P( D, A, B, C, 11, 10, 0xBD3AF235 );
|
||||
P( C, D, A, B, 2, 15, 0x2AD7D2BB );
|
||||
P( B, C, D, A, 9, 21, 0xEB86D391 );
|
||||
|
||||
#undef F
|
||||
|
||||
ctx->state[0] += A;
|
||||
ctx->state[1] += B;
|
||||
ctx->state[2] += C;
|
||||
ctx->state[3] += D;
|
||||
}
|
||||
|
||||
void md5_update( md5_context *ctx, uint8 *input, uint32 length )
|
||||
{
|
||||
uint32 left, fill;
|
||||
|
||||
if( ! length ) return;
|
||||
|
||||
left = ctx->total[0] & 0x3F;
|
||||
fill = 64 - left;
|
||||
|
||||
ctx->total[0] += length;
|
||||
ctx->total[0] &= 0xFFFFFFFF;
|
||||
|
||||
if( ctx->total[0] < length )
|
||||
ctx->total[1]++;
|
||||
|
||||
if( left && length >= fill )
|
||||
{
|
||||
memcpy( (void *) (ctx->buffer + left),
|
||||
(void *) input, fill );
|
||||
md5_process( ctx, ctx->buffer );
|
||||
length -= fill;
|
||||
input += fill;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
while( length >= 64 )
|
||||
{
|
||||
md5_process( ctx, input );
|
||||
length -= 64;
|
||||
input += 64;
|
||||
}
|
||||
|
||||
if( length )
|
||||
{
|
||||
memcpy( (void *) (ctx->buffer + left),
|
||||
(void *) input, length );
|
||||
}
|
||||
}
|
||||
|
||||
static uint8 md5_padding[64] =
|
||||
{
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
void md5_finish( md5_context *ctx, uint8 digest[16] )
|
||||
{
|
||||
uint32 last, padn;
|
||||
uint32 high, low;
|
||||
uint8 msglen[8];
|
||||
|
||||
high = ( ctx->total[0] >> 29 )
|
||||
| ( ctx->total[1] << 3 );
|
||||
low = ( ctx->total[0] << 3 );
|
||||
|
||||
PUT_UINT32( low, msglen, 0 );
|
||||
PUT_UINT32( high, msglen, 4 );
|
||||
|
||||
last = ctx->total[0] & 0x3F;
|
||||
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
|
||||
|
||||
md5_update( ctx, md5_padding, padn );
|
||||
md5_update( ctx, msglen, 8 );
|
||||
|
||||
PUT_UINT32( ctx->state[0], digest, 0 );
|
||||
PUT_UINT32( ctx->state[1], digest, 4 );
|
||||
PUT_UINT32( ctx->state[2], digest, 8 );
|
||||
PUT_UINT32( ctx->state[3], digest, 12 );
|
||||
}
|
||||
|
||||
25
utils/mkamsboot/md5.h
Normal file
25
utils/mkamsboot/md5.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef _MD5_H
|
||||
#define _MD5_H
|
||||
|
||||
#ifndef uint8
|
||||
#define uint8 unsigned char
|
||||
#endif
|
||||
|
||||
#ifndef uint32
|
||||
#define uint32 unsigned long int
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32 total[2];
|
||||
uint32 state[4];
|
||||
uint8 buffer[64];
|
||||
}
|
||||
md5_context;
|
||||
|
||||
void md5_starts( md5_context *ctx );
|
||||
void md5_update( md5_context *ctx, uint8 *input, uint32 length );
|
||||
void md5_finish( md5_context *ctx, uint8 digest[16] );
|
||||
|
||||
#endif /* md5.h */
|
||||
|
||||
595
utils/mkamsboot/mkamsboot.c
Normal file
595
utils/mkamsboot/mkamsboot.c
Normal file
|
|
@ -0,0 +1,595 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* mkamsboot.c - a tool for merging bootloader code into an Sansa V2
|
||||
* (AMS) firmware file
|
||||
*
|
||||
* Copyright (C) 2008 Dave Chapman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
|
||||
Insert a Rockbox bootloader into a Sansa AMS original firmware file.
|
||||
|
||||
Layout of a Sansa AMS original firmware file:
|
||||
|
||||
---------------------- 0x0
|
||||
| HEADER |
|
||||
|----------------------| 0x400
|
||||
| FIRMWARE BLOCK | (contains the OF version on some fuzev2 firmwares
|
||||
|----------------------| 0x600
|
||||
| FIRMWARE BLOCK |
|
||||
|----------------------| 0x400 + firmware block size
|
||||
| LIBRARIES/DATA |
|
||||
---------------------- END
|
||||
|
||||
We replace the main firmware block while preserving the potential OF version
|
||||
(bytes 0x600..0x400+firmware_size) as follows:
|
||||
|
||||
|
||||
---------------------- 0x0
|
||||
| |
|
||||
| Dual-boot code |
|
||||
| |
|
||||
|----------------------|
|
||||
| EMPTY SPACE |
|
||||
|----------------------|
|
||||
| |
|
||||
| compressed RB image |
|
||||
| |
|
||||
|----------------------|
|
||||
| |
|
||||
| compressed OF image |
|
||||
| |
|
||||
|----------------------|
|
||||
| UCL unpack function |
|
||||
----------------------
|
||||
|
||||
This entire block fits into the space previously occupied by the main
|
||||
firmware block - the space saved by compressing the OF image is used
|
||||
to store the compressed version of the Rockbox bootloader.
|
||||
|
||||
On version 1 firmwares, the OF image is typically about 120KB, which allows
|
||||
us to store a Rockbox bootloader with an uncompressed size of about 60KB-70KB.
|
||||
Version 2 firmwares are bigger and are stored in SDRAM (instead of IRAM).
|
||||
In both cases, the RAM we are using is mapped at offset 0x0.
|
||||
|
||||
mkamsboot then corrects the checksums and writes a new legal firmware
|
||||
file which can be installed on the device.
|
||||
|
||||
When the Sansa device boots, this firmware block is loaded to RAM at
|
||||
address 0x0 and executed.
|
||||
|
||||
Firstly, the dual-boot code will copy the UCL unpack function to the
|
||||
end of RAM.
|
||||
|
||||
Then, depending on the detection of the dual-boot keypress, either the
|
||||
OF image or the Rockbox image is copied to the end of RAM (just before
|
||||
the ucl unpack function) and uncompressed to the start of RAM.
|
||||
|
||||
Finally, the ucl unpack function branches to address 0x0, passing
|
||||
execution to the uncompressed firmware.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ucl/ucl.h>
|
||||
|
||||
#include "mkamsboot.h"
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
/* Header for ARM code binaries */
|
||||
#include "dualboot.h"
|
||||
|
||||
/* Win32 compatibility */
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
/* fw_revision: version 2 is used in Clipv2, Clip+ and Fuzev2 firmwares */
|
||||
/* hw_revision: 4 for m200, 2 for e200/c200, 1 or 2 for fuze/clip, 1 for clip+ */
|
||||
const struct ams_models ams_identity[] = {
|
||||
[MODEL_C200V2] = { 2, 1, "c200", dualboot_c200v2, sizeof(dualboot_c200v2), "c2v2", 44 },
|
||||
[MODEL_CLIPPLUS]= { 1, 2, "Clip+", dualboot_clipplus, sizeof(dualboot_clipplus), "cli+", 66 },
|
||||
[MODEL_CLIPV2] = { 2, 2, "Clip", dualboot_clipv2, sizeof(dualboot_clipv2), "clv2", 60 },
|
||||
[MODEL_CLIP] = { 1, 1, "Clip", dualboot_clip, sizeof(dualboot_clip), "clip", 40 },
|
||||
[MODEL_E200V2] = { 2, 1, "e200", dualboot_e200v2, sizeof(dualboot_e200v2), "e2v2", 41 },
|
||||
[MODEL_FUZEV2] = { 2, 2, "Fuze", dualboot_fuzev2, sizeof(dualboot_fuzev2), "fuz2", 68 },
|
||||
[MODEL_FUZE] = { 1, 1, "Fuze", dualboot_fuze, sizeof(dualboot_fuze), "fuze", 43 },
|
||||
[MODEL_M200V4] = { 4, 1, "m200", dualboot_m200v4, sizeof(dualboot_m200v4), "m2v4", 42 },
|
||||
[MODEL_CLIPZIP] = { 1, 2, "ClipZip", dualboot_clipzip, sizeof(dualboot_clipzip), "clzp", 79 },
|
||||
};
|
||||
|
||||
|
||||
/* Checksums of unmodified original firmwares - for safety, and device
|
||||
detection */
|
||||
static struct md5sums sansasums[] = {
|
||||
/* NOTE: Different regional versions of the firmware normally only
|
||||
differ in the filename - the md5sums are identical */
|
||||
|
||||
/* model version md5 */
|
||||
{ MODEL_E200V2, "3.01.11", "e622ca8cb6df423f54b8b39628a1f0a3" },
|
||||
{ MODEL_E200V2, "3.01.14", "2c1d0383fc3584b2cc83ba8cc2243af6" },
|
||||
{ MODEL_E200V2, "3.01.16", "12563ad71b25a1034cf2092d1e0218c4" },
|
||||
|
||||
{ MODEL_FUZE, "1.01.11", "cac8ffa03c599330ac02c4d41de66166" },
|
||||
{ MODEL_FUZE, "1.01.15", "df0e2c1612727f722c19a3c764cff7f2" },
|
||||
{ MODEL_FUZE, "1.01.22", "5aff5486fe8dd64239cc71eac470af98" },
|
||||
{ MODEL_FUZE, "1.02.26", "7c632c479461c48c8833baed74eb5e4f" },
|
||||
{ MODEL_FUZE, "1.02.28", "5b34260f6470e75f702a9c6825471752" },
|
||||
{ MODEL_FUZE, "1.02.31", "66d01b37462a5ef7ccc6ad37188b4235" },
|
||||
|
||||
{ MODEL_C200V2, "3.02.05", "b6378ebd720b0ade3fad4dc7ab61c1a5" },
|
||||
|
||||
{ MODEL_M200V4, "4.00.45", "82e3194310d1514e3bbcd06e84c4add3" },
|
||||
{ MODEL_M200V4, "4.01.08-A", "fc9dd6116001b3e6a150b898f1b091f0" },
|
||||
{ MODEL_M200V4, "4.01.08-E", "d3fb7d8ec8624ee65bc99f8dab0e2369" },
|
||||
|
||||
{ MODEL_CLIP, "1.01.17", "12caad785d506219d73f538772afd99e" },
|
||||
{ MODEL_CLIP, "1.01.18", "d720b266bd5afa38a198986ef0508a45" },
|
||||
{ MODEL_CLIP, "1.01.20", "236d8f75189f468462c03f6d292cf2ac" },
|
||||
{ MODEL_CLIP, "1.01.29", "c12711342169c66e209540cd1f27cd26" },
|
||||
{ MODEL_CLIP, "1.01.30", "f2974d47c536549c9d8259170f1dbe4d" },
|
||||
{ MODEL_CLIP, "1.01.32", "d835d12342500732ffb9c4ee54abec15" },
|
||||
{ MODEL_CLIP, "1.01.35", "b4d0edb3b8f2a4e8eee0a344f7f8e480" },
|
||||
|
||||
{ MODEL_CLIPV2, "2.01.16", "c57fb3fcbe07c2c9b360f060938f80cb" },
|
||||
{ MODEL_CLIPV2, "2.01.32", "0ad3723e52022509089d938d0fbbf8c5" },
|
||||
{ MODEL_CLIPV2, "2.01.35", "a3cbbd22b9508d7f8a9a1a39acc342c2" },
|
||||
|
||||
{ MODEL_CLIPPLUS, "01.02.09", "656d38114774c2001dc18e6726df3c5d" },
|
||||
{ MODEL_CLIPPLUS, "01.02.13", "5f89872b79ef440b0e5ee3a7a44328b2" },
|
||||
{ MODEL_CLIPPLUS, "01.02.15", "680a4f521e790ad25b93b1b16f3a207d" },
|
||||
{ MODEL_CLIPPLUS, "01.02.16", "055a53de1dfb09f6cb71c504ad48bd13" },
|
||||
{ MODEL_CLIPPLUS, "01.02.18", "80b547244438b113e2a55ff0305f12c0" },
|
||||
|
||||
{ MODEL_FUZEV2, "2.01.17", "8b85fb05bf645d08a4c8c3e344ec9ebe" },
|
||||
{ MODEL_FUZEV2, "2.02.26", "d4f6f85c3e4a8ea8f2e5acc421641801" },
|
||||
{ MODEL_FUZEV2, "2.03.31", "74fb197ccd51707388f3b233402186a6" },
|
||||
{ MODEL_FUZEV2, "2.03.33", "1599cc73d02ea7fe53fe2d4379c24b66" },
|
||||
|
||||
{ MODEL_CLIPZIP, "1.01.12", "45adea0873326b5af34f096e5c402f78" },
|
||||
{ MODEL_CLIPZIP, "1.01.15", "f62af954334cd9ba1a87a7fa58ec6074" },
|
||||
{ MODEL_CLIPZIP, "1.01.17", "27bcb343d6950f35dc261629e22ba60c" },
|
||||
{ MODEL_CLIPZIP, "1.01.18", "ef16aa9e02b49885ebede5aa149502e8" },
|
||||
{ MODEL_CLIPZIP, "1.01.20", "d88c8977cc6a952d3f51ece105869d97" },
|
||||
{ MODEL_CLIPZIP, "1.01.21", "92c814d6e3250189706a36d2b49b6152" },
|
||||
};
|
||||
|
||||
#define NUM_MD5S (sizeof(sansasums)/sizeof(sansasums[0]))
|
||||
|
||||
static unsigned int model_memory_size(int model)
|
||||
{
|
||||
/* The OF boots with IRAM (320kB) mapped at 0x0 */
|
||||
|
||||
if(model == MODEL_CLIPV2)
|
||||
{
|
||||
/* The decompressed Clipv2 OF is around 380kB.
|
||||
* Let's use the full IRAM (1MB on AMSv2)
|
||||
*/
|
||||
return 1 << 20;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The IRAM is 320kB on AMSv1, and 320 will be enough on Fuzev1/Clip+ */
|
||||
return 320 << 10;
|
||||
}
|
||||
}
|
||||
|
||||
int firmware_revision(int model)
|
||||
{
|
||||
return ams_identity[model].fw_revision;
|
||||
}
|
||||
|
||||
static off_t filesize(int fd)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
if (fstat(fd, &buf) < 0) {
|
||||
perror("[ERR] Checking filesize of input file");
|
||||
return -1;
|
||||
} else {
|
||||
return(buf.st_size);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t get_uint32le(unsigned char* p)
|
||||
{
|
||||
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
||||
}
|
||||
|
||||
static uint32_t get_uint32be(unsigned char* p)
|
||||
{
|
||||
return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
|
||||
}
|
||||
|
||||
static void put_uint32le(unsigned char* p, uint32_t x)
|
||||
{
|
||||
p[0] = x & 0xff;
|
||||
p[1] = (x >> 8) & 0xff;
|
||||
p[2] = (x >> 16) & 0xff;
|
||||
p[3] = (x >> 24) & 0xff;
|
||||
}
|
||||
|
||||
void calc_MD5(unsigned char* buf, int len, char *md5str)
|
||||
{
|
||||
int i;
|
||||
md5_context ctx;
|
||||
unsigned char md5sum[16];
|
||||
|
||||
md5_starts(&ctx);
|
||||
md5_update(&ctx, buf, len);
|
||||
md5_finish(&ctx, md5sum);
|
||||
|
||||
for (i = 0; i < 16; ++i)
|
||||
sprintf(md5str + 2*i, "%02x", md5sum[i]);
|
||||
}
|
||||
|
||||
/* Calculate a simple checksum used in Sansa Original Firmwares */
|
||||
static uint32_t calc_checksum(unsigned char* buf, uint32_t n)
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
uint32_t i;
|
||||
|
||||
for (i=0;i<n;i+=4)
|
||||
sum += get_uint32le(buf + i);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/* Compress using nrv2e algorithm : Thumb decompressor fits in 168 bytes ! */
|
||||
static unsigned char* uclpack(unsigned char* inbuf, int insize, int* outsize)
|
||||
{
|
||||
int maxsize;
|
||||
unsigned char* outbuf;
|
||||
int r;
|
||||
|
||||
/* The following formula comes from the UCL documentation */
|
||||
maxsize = insize + (insize / 8) + 256;
|
||||
|
||||
/* Allocate some memory for the output buffer */
|
||||
outbuf = malloc(maxsize);
|
||||
|
||||
if (outbuf == NULL)
|
||||
return NULL;
|
||||
|
||||
r = ucl_nrv2e_99_compress(
|
||||
(const ucl_bytep) inbuf,
|
||||
(ucl_uint) insize,
|
||||
(ucl_bytep) outbuf,
|
||||
(ucl_uintp) outsize,
|
||||
0, 10, NULL, NULL);
|
||||
|
||||
if (r != UCL_E_OK || *outsize > maxsize) {
|
||||
/* this should NEVER happen, and implies memory corruption */
|
||||
fprintf(stderr, "internal error - compression failed: %d\n", r);
|
||||
free(outbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return outbuf;
|
||||
}
|
||||
|
||||
#define ERROR(format, ...) \
|
||||
do { \
|
||||
snprintf(errstr, errstrsize, format, __VA_ARGS__); \
|
||||
goto error; \
|
||||
} while(0)
|
||||
|
||||
/* Loads a Sansa AMS Original Firmware file into memory */
|
||||
unsigned char* load_of_file(
|
||||
char* filename, int model, off_t* bufsize, struct md5sums *sum,
|
||||
int* firmware_size, unsigned char** of_packed,
|
||||
int* of_packedsize, char* errstr, int errstrsize)
|
||||
{
|
||||
int fd;
|
||||
unsigned char* buf =NULL;
|
||||
off_t n;
|
||||
unsigned int i=0;
|
||||
uint32_t checksum;
|
||||
unsigned int last_word;
|
||||
|
||||
fd = open(filename, O_RDONLY|O_BINARY);
|
||||
if (fd < 0)
|
||||
ERROR("[ERR] Could not open %s for reading\n", filename);
|
||||
|
||||
*bufsize = filesize(fd);
|
||||
|
||||
buf = malloc(*bufsize);
|
||||
if (buf == NULL)
|
||||
ERROR("[ERR] Could not allocate memory for %s\n", filename);
|
||||
|
||||
n = read(fd, buf, *bufsize);
|
||||
|
||||
if (n != *bufsize)
|
||||
ERROR("[ERR] Could not read file %s\n", filename);
|
||||
|
||||
/* check the file */
|
||||
|
||||
/* Calculate MD5 checksum of OF */
|
||||
calc_MD5(buf, *bufsize, sum->md5);
|
||||
|
||||
while ((i < NUM_MD5S) && (strcmp(sansasums[i].md5, sum->md5) != 0))
|
||||
i++;
|
||||
|
||||
if (i < NUM_MD5S) {
|
||||
*sum = sansasums[i];
|
||||
if(sum->model != model) {
|
||||
ERROR("[ERR] OF File provided is %sv%d version %s, not for %sv%d\n",
|
||||
ams_identity[sum->model].model_name, ams_identity[sum->model].hw_revision,
|
||||
sum->version, ams_identity[model].model_name, ams_identity[model].hw_revision
|
||||
);
|
||||
}
|
||||
} else {
|
||||
/* OF unknown, give a list of tested versions for the requested model */
|
||||
|
||||
char tested_versions[100];
|
||||
tested_versions[0] = '\0';
|
||||
|
||||
for (i = 0; i < NUM_MD5S ; i++)
|
||||
if (sansasums[i].model == model) {
|
||||
if (tested_versions[0] != '\0') {
|
||||
strncat(tested_versions, ", ",
|
||||
sizeof(tested_versions) - strlen(tested_versions) - 1);
|
||||
}
|
||||
strncat(tested_versions, sansasums[i].version,
|
||||
sizeof(tested_versions) - strlen(tested_versions) - 1);
|
||||
}
|
||||
|
||||
ERROR("[ERR] Original firmware unknown, please try another version."
|
||||
" Tested %sv%d versions are: %s\n",
|
||||
ams_identity[model].model_name, ams_identity[model].hw_revision, tested_versions);
|
||||
}
|
||||
|
||||
/* TODO: Do some more sanity checks on the OF image. Some images (like
|
||||
m200v4) dont have a checksum at the end, only padding (0xdeadbeef). */
|
||||
last_word = *bufsize - 4;
|
||||
checksum = get_uint32le(buf + last_word);
|
||||
if (checksum != 0xefbeadde && checksum != calc_checksum(buf, last_word))
|
||||
ERROR("%s", "[ERR] Whole file checksum failed\n");
|
||||
|
||||
if (ams_identity[sum->model].bootloader == NULL)
|
||||
ERROR("[ERR] Unsupported model - \"%s\"\n", ams_identity[sum->model].model_name);
|
||||
|
||||
/* Get the firmware size */
|
||||
if (ams_identity[sum->model].fw_revision == 1)
|
||||
*firmware_size = get_uint32le(&buf[0x0c]);
|
||||
else if (ams_identity[sum->model].fw_revision == 2)
|
||||
*firmware_size = get_uint32le(&buf[0x10]);
|
||||
|
||||
/* Compress the original firmware image */
|
||||
*of_packed = uclpack(buf + 0x400, *firmware_size, of_packedsize);
|
||||
if (*of_packed == NULL)
|
||||
ERROR("[ERR] Could not compress %s\n", filename);
|
||||
|
||||
return buf;
|
||||
|
||||
error:
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Loads a rockbox bootloader file into memory */
|
||||
unsigned char* load_rockbox_file(
|
||||
char* filename, int *model, int* bufsize, int* rb_packedsize,
|
||||
char* errstr, int errstrsize)
|
||||
{
|
||||
int fd;
|
||||
unsigned char* buf = NULL;
|
||||
unsigned char* packed = NULL;
|
||||
unsigned char header[8];
|
||||
uint32_t sum;
|
||||
off_t n;
|
||||
int i;
|
||||
|
||||
fd = open(filename, O_RDONLY|O_BINARY);
|
||||
if (fd < 0)
|
||||
ERROR("[ERR] Could not open %s for reading\n", filename);
|
||||
|
||||
/* Read Rockbox header */
|
||||
n = read(fd, header, sizeof(header));
|
||||
if (n != sizeof(header))
|
||||
ERROR("[ERR] Could not read file %s\n", filename);
|
||||
|
||||
for(*model = 0; *model < NUM_MODELS; (*model)++)
|
||||
if (memcmp(ams_identity[*model].rb_model_name, header + 4, 4) == 0)
|
||||
break;
|
||||
|
||||
if(*model == NUM_MODELS)
|
||||
ERROR("[ERR] Model name \"%4.4s\" unknown. Is this really a rockbox bootloader?\n", header + 4);
|
||||
|
||||
*bufsize = filesize(fd) - sizeof(header);
|
||||
|
||||
buf = malloc(*bufsize);
|
||||
if (buf == NULL)
|
||||
ERROR("[ERR] Could not allocate memory for %s\n", filename);
|
||||
|
||||
n = read(fd, buf, *bufsize);
|
||||
|
||||
if (n != *bufsize)
|
||||
ERROR("[ERR] Could not read file %s\n", filename);
|
||||
|
||||
/* Check checksum */
|
||||
sum = ams_identity[*model].rb_model_num;
|
||||
for (i = 0; i < *bufsize; i++) {
|
||||
/* add 8 unsigned bits but keep a 32 bit sum */
|
||||
sum += buf[i];
|
||||
}
|
||||
|
||||
if (sum != get_uint32be(header))
|
||||
ERROR("[ERR] Checksum mismatch in %s\n", filename);
|
||||
|
||||
packed = uclpack(buf, *bufsize, rb_packedsize);
|
||||
if(packed == NULL)
|
||||
ERROR("[ERR] Could not compress %s\n", filename);
|
||||
|
||||
free(buf);
|
||||
return packed;
|
||||
|
||||
error:
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#undef ERROR
|
||||
|
||||
/* Patches a Sansa AMS Original Firmware file */
|
||||
void patch_firmware(
|
||||
int model, int fw_revision, int firmware_size, unsigned char* buf,
|
||||
int len, unsigned char* of_packed, int of_packedsize,
|
||||
unsigned char* rb_packed, int rb_packedsize)
|
||||
{
|
||||
unsigned char *p;
|
||||
uint32_t sum, filesum;
|
||||
uint32_t ucl_dest;
|
||||
unsigned int i;
|
||||
|
||||
/* Zero the original firmware area - not needed, but helps debugging */
|
||||
memset(buf + 0x600, 0, firmware_size);
|
||||
|
||||
/* Insert dual-boot bootloader at offset 0x200, we preserve the OF
|
||||
* version string located between 0x0 and 0x200 */
|
||||
memcpy(buf + 0x600, ams_identity[model].bootloader, ams_identity[model].bootloader_size);
|
||||
|
||||
/* Insert vectors, they won't overwrite the OF version string */
|
||||
static const uint32_t goto_start = 0xe3a0fc02; // mov pc, #0x200
|
||||
static const uint32_t infinite_loop = 0xeafffffe; // 1: b 1b
|
||||
/* ALL vectors: infinite loop */
|
||||
for (i=0; i < 8; i++)
|
||||
put_uint32le(buf + 0x400 + 4*i, infinite_loop);
|
||||
/* Now change only the interesting vectors */
|
||||
/* Reset/SWI vectors: branch to our dualboot code at 0x200 */
|
||||
put_uint32le(buf + 0x400 + 4*0, goto_start); // Reset
|
||||
put_uint32le(buf + 0x400 + 4*2, goto_start); // SWI
|
||||
|
||||
/* We are filling the firmware buffer backwards from the end */
|
||||
p = buf + 0x400 + firmware_size;
|
||||
|
||||
/* 1 - UCL unpack function */
|
||||
p -= sizeof(nrv2e_d8);
|
||||
memcpy(p, nrv2e_d8, sizeof(nrv2e_d8));
|
||||
|
||||
/* 2 - Compressed copy of original firmware */
|
||||
p -= of_packedsize;
|
||||
memcpy(p, of_packed, of_packedsize);
|
||||
|
||||
/* 3 - Compressed copy of Rockbox bootloader */
|
||||
p -= rb_packedsize;
|
||||
memcpy(p, rb_packed, rb_packedsize);
|
||||
|
||||
/* Write the locations of the various images to the variables at the
|
||||
start of the dualboot image - we save the location of the last byte
|
||||
in each image, along with the size in bytes */
|
||||
|
||||
/* UCL unpack function */
|
||||
put_uint32le(&buf[0x604], firmware_size - 1);
|
||||
put_uint32le(&buf[0x608], sizeof(nrv2e_d8));
|
||||
|
||||
/* Compressed original firmware image */
|
||||
put_uint32le(&buf[0x60c], firmware_size - sizeof(nrv2e_d8) - 1);
|
||||
put_uint32le(&buf[0x610], of_packedsize);
|
||||
|
||||
/* Compressed Rockbox image */
|
||||
put_uint32le(&buf[0x614], firmware_size - sizeof(nrv2e_d8) - of_packedsize
|
||||
- 1);
|
||||
put_uint32le(&buf[0x618], rb_packedsize);
|
||||
|
||||
ucl_dest = model_memory_size(model) - 1; /* last byte of memory */
|
||||
put_uint32le(&buf[0x61c], ucl_dest);
|
||||
|
||||
/* Update the firmware block checksum */
|
||||
sum = calc_checksum(buf + 0x400, firmware_size);
|
||||
|
||||
if (fw_revision == 1) {
|
||||
put_uint32le(&buf[0x04], sum);
|
||||
put_uint32le(&buf[0x204], sum);
|
||||
} else if (fw_revision == 2) {
|
||||
put_uint32le(&buf[0x08], sum);
|
||||
put_uint32le(&buf[0x208], sum);
|
||||
|
||||
/* Update the header checksums */
|
||||
put_uint32le(&buf[0x1fc], calc_checksum(buf, 0x1fc));
|
||||
put_uint32le(&buf[0x3fc], calc_checksum(buf + 0x200, 0x1fc));
|
||||
}
|
||||
|
||||
/* Update the whole-file checksum */
|
||||
filesum = 0;
|
||||
for (i=0;i < (unsigned)len - 4; i+=4)
|
||||
filesum += get_uint32le(&buf[i]);
|
||||
|
||||
put_uint32le(buf + len - 4, filesum);
|
||||
}
|
||||
|
||||
/* returns != 0 if the firmware can be safely patched */
|
||||
int check_sizes(int model, int rb_packed_size, int rb_unpacked_size,
|
||||
int of_packed_size, int of_unpacked_size, int *total_size,
|
||||
char *errstr, int errstrsize)
|
||||
{
|
||||
/* XXX: we keep the first 0x200 bytes block unmodified, we just replace
|
||||
* the ARM vectors */
|
||||
unsigned int packed_size = ams_identity[model].bootloader_size + sizeof(nrv2e_d8) +
|
||||
of_packed_size + rb_packed_size + 0x200;
|
||||
|
||||
/* how much memory is available */
|
||||
unsigned int memory_size = model_memory_size(model);
|
||||
|
||||
/* the memory used when unpacking the OF */
|
||||
unsigned int ram_of = sizeof(nrv2e_d8) + of_packed_size + of_unpacked_size;
|
||||
|
||||
/* the memory used when unpacking the bootloader */
|
||||
unsigned int ram_rb = sizeof(nrv2e_d8) + rb_packed_size + rb_unpacked_size;
|
||||
|
||||
*total_size = packed_size;
|
||||
|
||||
#define ERROR(format, ...) \
|
||||
do { \
|
||||
snprintf(errstr, errstrsize, format, __VA_ARGS__); \
|
||||
return 0; \
|
||||
} while(0)
|
||||
|
||||
/* will packed data fit in the OF file ? */
|
||||
if(packed_size > of_unpacked_size)
|
||||
ERROR(
|
||||
"[ERR] Packed data (%d bytes) doesn't fit in the firmware "
|
||||
"(%d bytes)\n", packed_size, of_unpacked_size
|
||||
);
|
||||
|
||||
else if(ram_rb > memory_size)
|
||||
ERROR("[ERR] Rockbox can't be unpacked at runtime, needs %d bytes "
|
||||
"of memory and only %d available\n", ram_rb, memory_size
|
||||
);
|
||||
|
||||
else if(ram_of > memory_size)
|
||||
ERROR("[ERR] OF can't be unpacked at runtime, needs %d bytes "
|
||||
"of memory and only %d available\n", ram_of, memory_size
|
||||
);
|
||||
|
||||
return 1;
|
||||
|
||||
#undef ERROR
|
||||
}
|
||||
195
utils/mkamsboot/mkamsboot.h
Normal file
195
utils/mkamsboot/mkamsboot.h
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* mkamsboot.h - a tool for merging bootloader code into an Sansa V2
|
||||
* (AMS) firmware file
|
||||
*
|
||||
* Copyright (C) 2008 Dave Chapman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef MKAMSBOOT_H
|
||||
#define MKAMSBOOT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Supported models */
|
||||
enum {
|
||||
MODEL_UNKNOWN = -1,
|
||||
MODEL_FUZE = 0,
|
||||
MODEL_CLIP,
|
||||
MODEL_CLIPV2,
|
||||
MODEL_E200V2,
|
||||
MODEL_M200V4,
|
||||
MODEL_C200V2,
|
||||
MODEL_CLIPPLUS,
|
||||
MODEL_FUZEV2,
|
||||
MODEL_CLIPZIP,
|
||||
/* new models go here */
|
||||
|
||||
NUM_MODELS
|
||||
};
|
||||
|
||||
|
||||
/* Holds info about the OF */
|
||||
struct md5sums {
|
||||
int model;
|
||||
char *version;
|
||||
char *md5;
|
||||
};
|
||||
|
||||
struct ams_models {
|
||||
unsigned short hw_revision;
|
||||
unsigned short fw_revision;
|
||||
/* Descriptive name of this model */
|
||||
const char* model_name;
|
||||
/* Dualboot functions for this model */
|
||||
const unsigned char* bootloader;
|
||||
/* Size of dualboot functions for this model */
|
||||
int bootloader_size;
|
||||
/* Model name used in the Rockbox header in ".sansa" files - these match the
|
||||
-add parameter to the "scramble" tool */
|
||||
const char* rb_model_name;
|
||||
/* Model number used to initialise the checksum in the Rockbox header in
|
||||
".sansa" files - these are the same as MODEL_NUMBER in config-target.h */
|
||||
const int rb_model_num;
|
||||
};
|
||||
extern const struct ams_models ams_identity[];
|
||||
|
||||
/* load_rockbox_file()
|
||||
*
|
||||
* Loads a rockbox bootloader file into memory
|
||||
*
|
||||
* ARGUMENTS
|
||||
*
|
||||
* filename : bootloader file to load
|
||||
* model : will be set to this bootloader's model
|
||||
* bootloader_size : set to the uncompressed bootloader size
|
||||
* rb_packed_size : set to the size of compressed bootloader
|
||||
* errstr : provided buffer to store an eventual error
|
||||
* errstrsize : size of provided error buffer
|
||||
*
|
||||
* RETURN VALUE
|
||||
* pointer to allocated memory containing the content of compressed bootloader
|
||||
* or NULL in case of error (errstr will hold a description of the error)
|
||||
*/
|
||||
|
||||
unsigned char* load_rockbox_file(
|
||||
char* filename, int *model, int* bootloader_size, int* rb_packedsize,
|
||||
char* errstr, int errstrsize);
|
||||
|
||||
|
||||
/* load_of_file()
|
||||
*
|
||||
* Loads a Sansa AMS Original Firmware file into memory
|
||||
*
|
||||
* ARGUMENTS
|
||||
*
|
||||
* filename : firmware file to load
|
||||
* model : desired player's model
|
||||
* bufsize : set to firmware file size
|
||||
* md5sum : set to file md5sum, must be at least 33 bytes long
|
||||
* firmware_size : set to firmware block's size
|
||||
* of_packed : pointer to allocated memory containing the compressed
|
||||
* original firmware block
|
||||
* of_packedsize : size of compressed original firmware block
|
||||
* errstr : provided buffer to store an eventual error
|
||||
* errstrsize : size of provided error buffer
|
||||
*
|
||||
* RETURN VALUE
|
||||
* pointer to allocated memory containing the content of Original Firmware
|
||||
* or NULL in case of error (errstr will hold a description of the error)
|
||||
*/
|
||||
|
||||
unsigned char* load_of_file(
|
||||
char* filename, int model, off_t* bufsize, struct md5sums *sum,
|
||||
int* firmware_size, unsigned char** of_packed,
|
||||
int* of_packedsize, char* errstr, int errstrsize);
|
||||
|
||||
|
||||
/* patch_firmware()
|
||||
*
|
||||
* Patches a Sansa AMS Original Firmware file
|
||||
*
|
||||
* ARGUMENTS
|
||||
*
|
||||
* model : firmware model (MODEL_XXX)
|
||||
* fw_version : firmware format version (1 or 2)
|
||||
* firmware_size : size of uncompressed original firmware block
|
||||
* buf : pointer to original firmware file
|
||||
* len : size of original firmware file
|
||||
* of_packed : pointer to compressed original firmware block
|
||||
* of_packedsize : size of compressed original firmware block
|
||||
* rb_packed : pointer to compressed rockbox bootloader
|
||||
* rb_packed_size : size of compressed rockbox bootloader
|
||||
*/
|
||||
|
||||
void patch_firmware(
|
||||
int model, int fw_version, int firmware_size, unsigned char* buf,
|
||||
int len, unsigned char* of_packed, int of_packedsize,
|
||||
unsigned char* rb_packed, int rb_packedsize);
|
||||
|
||||
|
||||
/* check_sizes()
|
||||
*
|
||||
* Verify if the given bootloader can be embedded in the OF file, while still
|
||||
* allowing both the bootloader and the OF to be unpacked at runtime
|
||||
*
|
||||
* ARGUMENTS
|
||||
*
|
||||
* model : firmware model (MODEL_XXX)
|
||||
* rb_packed_size : size of compressed rockbox bootloader
|
||||
* rb_unpacked_size : size of compressed rockbox bootloader
|
||||
* of_packed_size : size of compressed original firmware block
|
||||
* of_unpacked_size : size of compressed original firmware block
|
||||
* total_size : will contain the size of useful data that would be
|
||||
* written to the firmware block, even in case of an
|
||||
* error
|
||||
* errstr : provided buffer to store an eventual error
|
||||
* errstrsize : size of provided error buffer
|
||||
*
|
||||
* RETURN VALUE
|
||||
* 0 if the conditions aren't met, 1 if we can go and patch the firmware
|
||||
*/
|
||||
|
||||
int check_sizes(int model, int rb_packed_size, int rb_unpacked_size,
|
||||
int of_packed_size, int of_unpacked_size, int *total_size,
|
||||
char *errstr, int errstrsize);
|
||||
|
||||
/* firmware_revision()
|
||||
*
|
||||
* returns the firmware revision for a particular model
|
||||
*
|
||||
* ARGUMENTS
|
||||
*
|
||||
* model : firmware model (MODEL_XXX)
|
||||
*
|
||||
* RETURN VALUE
|
||||
* firmware version
|
||||
*/
|
||||
int firmware_revision(int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
46
utils/mkimxboot/Makefile
Normal file
46
utils/mkimxboot/Makefile
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
|
||||
# We use the SB code available in the Rockbox utils/sbtools directory
|
||||
|
||||
IMXTOOLS_DIR=../../utils/imxtools/sbtools/
|
||||
|
||||
COMPILEFLAGS := -Wall -g -O3 -I$(IMXTOOLS_DIR)
|
||||
|
||||
# std=gnu99 is required by MinGW on Windows (c99 is sufficient for Linux / MXE)
|
||||
CFLAGS += -std=gnu99 $(COMPILEFLAGS)
|
||||
|
||||
TOMCRYPT_DIR := ../../utils/tomcrypt
|
||||
|
||||
CFLAGS += -I$(TOMCRYPT_DIR)/src/headers
|
||||
LDOPTS += -lpthread $(TOMCRYPT_DIR)/librbtomcrypt.a
|
||||
|
||||
OUTPUT = mkimxboot
|
||||
|
||||
# inputs for lib
|
||||
IMXTOOLS_SOURCES = misc.c sb.c crypto.c crc.c elf.c
|
||||
LIBSOURCES := dualboot.c mkimxboot.c md5.c \
|
||||
$(addprefix $(IMXTOOLS_DIR),$(IMXTOOLS_SOURCES))
|
||||
|
||||
# for now build tomcrypt as part of the lib.
|
||||
LIBSOURCES += $(addprefix $(TOMCRYPT_DIR),$(TOMCRYPT_SOURCES))
|
||||
|
||||
# inputs for binary only
|
||||
SOURCES := $(LIBSOURCES) main.c
|
||||
# dependencies for binary
|
||||
EXTRADEPS :=
|
||||
|
||||
include ../libtools.make
|
||||
|
||||
# explicit dependencies on dualboot.{c,h} and mkimxboot.h
|
||||
$(OBJDIR)mkimxboot.o: dualboot.h dualboot.c mkimxboot.c mkimxboot.h
|
||||
$(OBJDIR)main.o: dualboot.h dualboot.c main.c mkimxboot.h
|
||||
$(BINARY): librbtomcrypt.a
|
||||
|
||||
librbtomcrypt.a:
|
||||
$(MAKE) -C ../../utils/tomcrypt
|
||||
|
||||
293
utils/mkimxboot/dualboot.c
Normal file
293
utils/mkimxboot/dualboot.c
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
/* Generated by bin2c */
|
||||
|
||||
#include "dualboot.h"
|
||||
|
||||
unsigned char dualboot_fuzeplus[728] = {
|
||||
0x10, 0x40, 0x2d, 0xe9, 0x30, 0x00, 0x00, 0xeb, 0x10, 0x80, 0xbd, 0xe8, 0x40, 0x30, 0x9f, 0xe5,
|
||||
0xb0, 0x30, 0x93, 0xe5, 0x03, 0x18, 0xa0, 0xe1, 0x21, 0x18, 0xa0, 0xe1, 0x34, 0x20, 0x9f, 0xe5,
|
||||
0x02, 0x00, 0x51, 0xe1, 0x08, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x50, 0xe3, 0x01, 0x38, 0x03, 0x02,
|
||||
0x23, 0x08, 0xa0, 0x01, 0x1e, 0xff, 0x2f, 0x01, 0x01, 0x00, 0x50, 0xe3, 0x02, 0x00, 0x00, 0x1a,
|
||||
0x06, 0x38, 0x03, 0xe2, 0xa3, 0x08, 0xa0, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0xa0, 0xe3,
|
||||
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x04, 0x40, 0x2d, 0xe5,
|
||||
0x5c, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x92, 0xe5, 0x03, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xa0, 0xe1,
|
||||
0x50, 0x20, 0x9f, 0xe5, 0x02, 0x00, 0x54, 0xe1, 0x02, 0x30, 0xa0, 0x11, 0x00, 0x00, 0x50, 0xe3,
|
||||
0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x09, 0x00, 0x00, 0x1a, 0x04, 0x00, 0x00, 0xea,
|
||||
0x01, 0x38, 0xc3, 0xe3, 0x01, 0x18, 0xa0, 0xe1, 0x01, 0x18, 0x01, 0xe2, 0x01, 0x30, 0x83, 0xe1,
|
||||
0x03, 0x00, 0x00, 0xea, 0x06, 0x38, 0xc3, 0xe3, 0x81, 0x18, 0xa0, 0xe1, 0x06, 0x18, 0x01, 0xe2,
|
||||
0x01, 0x30, 0x83, 0xe1, 0x08, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x82, 0xe5, 0x10, 0x00, 0xbd, 0xe8,
|
||||
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x70, 0x40, 0x2d, 0xe9,
|
||||
0x00, 0x40, 0xa0, 0xe1, 0x01, 0x60, 0xa0, 0xe1, 0xd8, 0x31, 0x9f, 0xe5, 0x03, 0x00, 0x50, 0xe1,
|
||||
0x34, 0x00, 0x00, 0x1a, 0xd0, 0x31, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3, 0x08, 0x20, 0x83, 0xe5,
|
||||
0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0xff, 0x24, 0xc2, 0xe3,
|
||||
0x02, 0x21, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x0f, 0x28, 0xc2, 0xe3,
|
||||
0x01, 0x28, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x7f, 0x2e, 0xc2, 0xe3,
|
||||
0x0f, 0x20, 0xc2, 0xe3, 0xc8, 0x20, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0x01, 0x26, 0xa0, 0xe3,
|
||||
0xd4, 0x20, 0x83, 0xe5, 0x34, 0x21, 0x83, 0xe5, 0x30, 0x11, 0x93, 0xe5, 0x03, 0x18, 0xc1, 0xe3,
|
||||
0x02, 0x18, 0x81, 0xe3, 0x30, 0x11, 0x83, 0xe5, 0x03, 0x39, 0x43, 0xe2, 0x30, 0x10, 0x93, 0xe5,
|
||||
0x0f, 0x1c, 0xc1, 0xe3, 0x01, 0x1c, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x30, 0x10, 0x93, 0xe5,
|
||||
0x3f, 0x10, 0xc1, 0xe3, 0x10, 0x10, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x01, 0x18, 0xa0, 0xe3,
|
||||
0x38, 0x10, 0x83, 0xe5, 0x80, 0x10, 0x93, 0xe5, 0x02, 0x15, 0x81, 0xe3, 0x80, 0x10, 0x83, 0xe5,
|
||||
0x18, 0x20, 0x83, 0xe5, 0x10, 0x20, 0x93, 0xe5, 0x3f, 0x2a, 0xc2, 0xe3, 0x01, 0x28, 0x82, 0xe3,
|
||||
0x10, 0x20, 0x83, 0xe5, 0x01, 0x39, 0x43, 0xe2, 0x00, 0x10, 0xa0, 0xe3, 0x20, 0x20, 0x93, 0xe5,
|
||||
0x01, 0x2a, 0x82, 0xe3, 0x20, 0x20, 0x83, 0xe5, 0x90, 0x1f, 0x07, 0xee, 0x00, 0x00, 0xa0, 0xe1,
|
||||
0x00, 0x00, 0xa0, 0xe1, 0xf8, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3,
|
||||
0xa5, 0xff, 0xff, 0xeb, 0x01, 0x00, 0xa0, 0xe3, 0x8f, 0xff, 0xff, 0xeb, 0x00, 0x50, 0xa0, 0xe1,
|
||||
0x01, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x9f, 0xff, 0xff, 0xeb, 0x01, 0x00, 0x55, 0xe3,
|
||||
0x25, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x55, 0xe3, 0x04, 0x00, 0x00, 0x1a, 0x01, 0x27, 0xa0, 0xe3,
|
||||
0xc8, 0x30, 0x9f, 0xe5, 0x78, 0x20, 0x83, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0x70, 0x80, 0xbd, 0xe8,
|
||||
0xbc, 0x30, 0x9f, 0xe5, 0xc0, 0x30, 0x93, 0xe5, 0x3f, 0x34, 0x03, 0xe2, 0x23, 0x3c, 0xa0, 0xe1,
|
||||
0x20, 0x00, 0x13, 0xe3, 0x01, 0x30, 0xa0, 0x13, 0x02, 0x00, 0x00, 0x1a, 0x10, 0x00, 0x13, 0xe3,
|
||||
0x02, 0x30, 0xa0, 0x13, 0x00, 0x30, 0xa0, 0x03, 0x98, 0x20, 0x9f, 0xe5, 0x10, 0x26, 0x92, 0xe5,
|
||||
0x01, 0x01, 0x12, 0xe3, 0x10, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x53, 0xe3, 0x10, 0x00, 0x00, 0x1a,
|
||||
0x03, 0x20, 0xa0, 0xe1, 0x78, 0x00, 0x9f, 0xe5, 0x7c, 0x10, 0x9f, 0xe5, 0xc0, 0xc0, 0x90, 0xe5,
|
||||
0x03, 0xc6, 0x0c, 0xe2, 0x01, 0x06, 0x5c, 0xe3, 0x01, 0x20, 0x82, 0x02, 0x01, 0x30, 0x83, 0xe2,
|
||||
0x01, 0x00, 0x53, 0xe1, 0xf8, 0xff, 0xff, 0x1a, 0x60, 0x30, 0x9f, 0xe5, 0x03, 0x00, 0x52, 0xe1,
|
||||
0x03, 0x00, 0x00, 0xca, 0x05, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe3,
|
||||
0x70, 0x80, 0xbd, 0xe8, 0x00, 0x40, 0x86, 0xe5, 0x01, 0x00, 0xa0, 0xe3, 0x70, 0x80, 0xbd, 0xe8,
|
||||
0x30, 0x30, 0x9f, 0xe5, 0x03, 0x27, 0xa0, 0xe3, 0x04, 0x21, 0x83, 0xe5, 0x02, 0x2c, 0xa0, 0xe3,
|
||||
0x00, 0x27, 0x83, 0xe5, 0x00, 0x25, 0x83, 0xe5, 0x24, 0x20, 0x9f, 0xe5, 0x0b, 0x39, 0x83, 0xe2,
|
||||
0x00, 0x21, 0x83, 0xe5, 0xef, 0xff, 0xff, 0xea, 0x63, 0x68, 0x72, 0x67, 0x00, 0x00, 0x05, 0x80,
|
||||
0x00, 0xc0, 0x05, 0x80, 0x00, 0x40, 0x04, 0x80, 0x00, 0x80, 0x01, 0x80, 0x70, 0x64, 0x08, 0x00,
|
||||
0x7f, 0x1a, 0x06, 0x00, 0x01, 0x00, 0xff, 0xff
|
||||
};
|
||||
unsigned char dualboot_zenxfi2[608] = {
|
||||
0x10, 0x40, 0x2d, 0xe9, 0x30, 0x00, 0x00, 0xeb, 0x10, 0x80, 0xbd, 0xe8, 0x40, 0x30, 0x9f, 0xe5,
|
||||
0xb0, 0x30, 0x93, 0xe5, 0x03, 0x18, 0xa0, 0xe1, 0x21, 0x18, 0xa0, 0xe1, 0x34, 0x20, 0x9f, 0xe5,
|
||||
0x02, 0x00, 0x51, 0xe1, 0x08, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x50, 0xe3, 0x01, 0x38, 0x03, 0x02,
|
||||
0x23, 0x08, 0xa0, 0x01, 0x1e, 0xff, 0x2f, 0x01, 0x01, 0x00, 0x50, 0xe3, 0x02, 0x00, 0x00, 0x1a,
|
||||
0x06, 0x38, 0x03, 0xe2, 0xa3, 0x08, 0xa0, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0xa0, 0xe3,
|
||||
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x04, 0x40, 0x2d, 0xe5,
|
||||
0x5c, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x92, 0xe5, 0x03, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xa0, 0xe1,
|
||||
0x50, 0x20, 0x9f, 0xe5, 0x02, 0x00, 0x54, 0xe1, 0x02, 0x30, 0xa0, 0x11, 0x00, 0x00, 0x50, 0xe3,
|
||||
0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x09, 0x00, 0x00, 0x1a, 0x04, 0x00, 0x00, 0xea,
|
||||
0x01, 0x38, 0xc3, 0xe3, 0x01, 0x18, 0xa0, 0xe1, 0x01, 0x18, 0x01, 0xe2, 0x01, 0x30, 0x83, 0xe1,
|
||||
0x03, 0x00, 0x00, 0xea, 0x06, 0x38, 0xc3, 0xe3, 0x81, 0x18, 0xa0, 0xe1, 0x06, 0x18, 0x01, 0xe2,
|
||||
0x01, 0x30, 0x83, 0xe1, 0x08, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x82, 0xe5, 0x10, 0x00, 0xbd, 0xe8,
|
||||
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x70, 0x40, 0x2d, 0xe9,
|
||||
0x00, 0x40, 0xa0, 0xe1, 0x01, 0x60, 0xa0, 0xe1, 0x6c, 0x31, 0x9f, 0xe5, 0x03, 0x00, 0x50, 0xe1,
|
||||
0x34, 0x00, 0x00, 0x1a, 0x64, 0x31, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3, 0x08, 0x20, 0x83, 0xe5,
|
||||
0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0xff, 0x24, 0xc2, 0xe3,
|
||||
0x02, 0x21, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x0f, 0x28, 0xc2, 0xe3,
|
||||
0x01, 0x28, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x7f, 0x2e, 0xc2, 0xe3,
|
||||
0x0f, 0x20, 0xc2, 0xe3, 0xc8, 0x20, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0x01, 0x26, 0xa0, 0xe3,
|
||||
0xd4, 0x20, 0x83, 0xe5, 0x34, 0x21, 0x83, 0xe5, 0x30, 0x11, 0x93, 0xe5, 0x03, 0x18, 0xc1, 0xe3,
|
||||
0x02, 0x18, 0x81, 0xe3, 0x30, 0x11, 0x83, 0xe5, 0x03, 0x39, 0x43, 0xe2, 0x30, 0x10, 0x93, 0xe5,
|
||||
0x0f, 0x1c, 0xc1, 0xe3, 0x01, 0x1c, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x30, 0x10, 0x93, 0xe5,
|
||||
0x3f, 0x10, 0xc1, 0xe3, 0x10, 0x10, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x01, 0x18, 0xa0, 0xe3,
|
||||
0x38, 0x10, 0x83, 0xe5, 0x80, 0x10, 0x93, 0xe5, 0x02, 0x15, 0x81, 0xe3, 0x80, 0x10, 0x83, 0xe5,
|
||||
0x18, 0x20, 0x83, 0xe5, 0x10, 0x20, 0x93, 0xe5, 0x3f, 0x2a, 0xc2, 0xe3, 0x01, 0x28, 0x82, 0xe3,
|
||||
0x10, 0x20, 0x83, 0xe5, 0x01, 0x39, 0x43, 0xe2, 0x00, 0x10, 0xa0, 0xe3, 0x20, 0x20, 0x93, 0xe5,
|
||||
0x01, 0x2a, 0x82, 0xe3, 0x20, 0x20, 0x83, 0xe5, 0x90, 0x1f, 0x07, 0xee, 0x00, 0x00, 0xa0, 0xe1,
|
||||
0x00, 0x00, 0xa0, 0xe1, 0xf8, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3,
|
||||
0xa5, 0xff, 0xff, 0xeb, 0x01, 0x00, 0xa0, 0xe3, 0x8f, 0xff, 0xff, 0xeb, 0x00, 0x50, 0xa0, 0xe1,
|
||||
0x01, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x9f, 0xff, 0xff, 0xeb, 0x01, 0x00, 0x55, 0xe3,
|
||||
0x17, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x55, 0xe3, 0x04, 0x00, 0x00, 0x1a, 0x01, 0x27, 0xa0, 0xe3,
|
||||
0x5c, 0x30, 0x9f, 0xe5, 0x78, 0x20, 0x83, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0x70, 0x80, 0xbd, 0xe8,
|
||||
0x50, 0x30, 0x9f, 0xe5, 0xc0, 0x30, 0x93, 0xe5, 0x02, 0x02, 0x13, 0xe3, 0x04, 0x00, 0x00, 0x1a,
|
||||
0x44, 0x30, 0x9f, 0xe5, 0x00, 0x36, 0x93, 0xe5, 0x01, 0x09, 0x13, 0xe3, 0x08, 0x00, 0x00, 0x0a,
|
||||
0x04, 0x00, 0x00, 0xea, 0x2c, 0x30, 0x9f, 0xe5, 0xc0, 0x30, 0x93, 0xe5, 0x03, 0x36, 0x03, 0xe2,
|
||||
0x01, 0x06, 0x53, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x00, 0x40, 0x86, 0xe5, 0x01, 0x00, 0xa0, 0xe3,
|
||||
0x70, 0x80, 0xbd, 0xe8, 0x00, 0x00, 0xa0, 0xe3, 0x70, 0x80, 0xbd, 0xe8, 0x63, 0x68, 0x72, 0x67,
|
||||
0x00, 0x00, 0x05, 0x80, 0x00, 0xc0, 0x05, 0x80, 0x00, 0x40, 0x04, 0x80, 0x00, 0x80, 0x01, 0x80
|
||||
};
|
||||
unsigned char dualboot_zenxfi3[572] = {
|
||||
0x10, 0x40, 0x2d, 0xe9, 0x30, 0x00, 0x00, 0xeb, 0x10, 0x80, 0xbd, 0xe8, 0x40, 0x30, 0x9f, 0xe5,
|
||||
0xb0, 0x30, 0x93, 0xe5, 0x03, 0x18, 0xa0, 0xe1, 0x21, 0x18, 0xa0, 0xe1, 0x34, 0x20, 0x9f, 0xe5,
|
||||
0x02, 0x00, 0x51, 0xe1, 0x08, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x50, 0xe3, 0x01, 0x38, 0x03, 0x02,
|
||||
0x23, 0x08, 0xa0, 0x01, 0x1e, 0xff, 0x2f, 0x01, 0x01, 0x00, 0x50, 0xe3, 0x02, 0x00, 0x00, 0x1a,
|
||||
0x06, 0x38, 0x03, 0xe2, 0xa3, 0x08, 0xa0, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0xa0, 0xe3,
|
||||
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x04, 0x40, 0x2d, 0xe5,
|
||||
0x5c, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x92, 0xe5, 0x03, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xa0, 0xe1,
|
||||
0x50, 0x20, 0x9f, 0xe5, 0x02, 0x00, 0x54, 0xe1, 0x02, 0x30, 0xa0, 0x11, 0x00, 0x00, 0x50, 0xe3,
|
||||
0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x09, 0x00, 0x00, 0x1a, 0x04, 0x00, 0x00, 0xea,
|
||||
0x01, 0x38, 0xc3, 0xe3, 0x01, 0x18, 0xa0, 0xe1, 0x01, 0x18, 0x01, 0xe2, 0x01, 0x30, 0x83, 0xe1,
|
||||
0x03, 0x00, 0x00, 0xea, 0x06, 0x38, 0xc3, 0xe3, 0x81, 0x18, 0xa0, 0xe1, 0x06, 0x18, 0x01, 0xe2,
|
||||
0x01, 0x30, 0x83, 0xe1, 0x08, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x82, 0xe5, 0x10, 0x00, 0xbd, 0xe8,
|
||||
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x70, 0x40, 0x2d, 0xe9,
|
||||
0x00, 0x40, 0xa0, 0xe1, 0x01, 0x60, 0xa0, 0xe1, 0x48, 0x31, 0x9f, 0xe5, 0x03, 0x00, 0x50, 0xe1,
|
||||
0x34, 0x00, 0x00, 0x1a, 0x40, 0x31, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3, 0x08, 0x20, 0x83, 0xe5,
|
||||
0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0xff, 0x24, 0xc2, 0xe3,
|
||||
0x02, 0x21, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x0f, 0x28, 0xc2, 0xe3,
|
||||
0x01, 0x28, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x7f, 0x2e, 0xc2, 0xe3,
|
||||
0x0f, 0x20, 0xc2, 0xe3, 0xc8, 0x20, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0x01, 0x26, 0xa0, 0xe3,
|
||||
0xd4, 0x20, 0x83, 0xe5, 0x34, 0x21, 0x83, 0xe5, 0x30, 0x11, 0x93, 0xe5, 0x03, 0x18, 0xc1, 0xe3,
|
||||
0x02, 0x18, 0x81, 0xe3, 0x30, 0x11, 0x83, 0xe5, 0x03, 0x39, 0x43, 0xe2, 0x30, 0x10, 0x93, 0xe5,
|
||||
0x0f, 0x1c, 0xc1, 0xe3, 0x01, 0x1c, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x30, 0x10, 0x93, 0xe5,
|
||||
0x3f, 0x10, 0xc1, 0xe3, 0x10, 0x10, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x01, 0x18, 0xa0, 0xe3,
|
||||
0x38, 0x10, 0x83, 0xe5, 0x80, 0x10, 0x93, 0xe5, 0x02, 0x15, 0x81, 0xe3, 0x80, 0x10, 0x83, 0xe5,
|
||||
0x18, 0x20, 0x83, 0xe5, 0x10, 0x20, 0x93, 0xe5, 0x3f, 0x2a, 0xc2, 0xe3, 0x01, 0x28, 0x82, 0xe3,
|
||||
0x10, 0x20, 0x83, 0xe5, 0x01, 0x39, 0x43, 0xe2, 0x00, 0x10, 0xa0, 0xe3, 0x20, 0x20, 0x93, 0xe5,
|
||||
0x01, 0x2a, 0x82, 0xe3, 0x20, 0x20, 0x83, 0xe5, 0x90, 0x1f, 0x07, 0xee, 0x00, 0x00, 0xa0, 0xe1,
|
||||
0x00, 0x00, 0xa0, 0xe1, 0xf8, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3,
|
||||
0xa5, 0xff, 0xff, 0xeb, 0x01, 0x00, 0xa0, 0xe3, 0x8f, 0xff, 0xff, 0xeb, 0x00, 0x50, 0xa0, 0xe1,
|
||||
0x01, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x9f, 0xff, 0xff, 0xeb, 0x01, 0x00, 0x55, 0xe3,
|
||||
0x0e, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x55, 0xe3, 0x04, 0x00, 0x00, 0x1a, 0x01, 0x27, 0xa0, 0xe3,
|
||||
0x38, 0x30, 0x9f, 0xe5, 0x78, 0x20, 0x83, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0x70, 0x80, 0xbd, 0xe8,
|
||||
0x2c, 0x30, 0x9f, 0xe5, 0xc0, 0x30, 0x93, 0xe5, 0x28, 0x30, 0x9f, 0xe5, 0x20, 0x36, 0x93, 0xe5,
|
||||
0x80, 0x00, 0x13, 0xe3, 0x00, 0x40, 0x86, 0x15, 0x01, 0x00, 0xa0, 0x13, 0x70, 0x80, 0xbd, 0x18,
|
||||
0x00, 0x00, 0xa0, 0xe3, 0x70, 0x80, 0xbd, 0xe8, 0x63, 0x68, 0x72, 0x67, 0x00, 0x00, 0x05, 0x80,
|
||||
0x00, 0xc0, 0x05, 0x80, 0x00, 0x40, 0x04, 0x80, 0x00, 0x80, 0x01, 0x80
|
||||
};
|
||||
unsigned char dualboot_nwze370[896] = {
|
||||
0x10, 0x40, 0x2d, 0xe9, 0x48, 0x00, 0x00, 0xeb, 0x10, 0x80, 0xbd, 0xe8, 0x40, 0x30, 0x9f, 0xe5,
|
||||
0xb0, 0x30, 0x93, 0xe5, 0x03, 0x18, 0xa0, 0xe1, 0x21, 0x18, 0xa0, 0xe1, 0x34, 0x20, 0x9f, 0xe5,
|
||||
0x02, 0x00, 0x51, 0xe1, 0x08, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x50, 0xe3, 0x01, 0x38, 0x03, 0x02,
|
||||
0x23, 0x08, 0xa0, 0x01, 0x1e, 0xff, 0x2f, 0x01, 0x01, 0x00, 0x50, 0xe3, 0x02, 0x00, 0x00, 0x1a,
|
||||
0x06, 0x38, 0x03, 0xe2, 0xa3, 0x08, 0xa0, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0xa0, 0xe3,
|
||||
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x04, 0x40, 0x2d, 0xe5,
|
||||
0x5c, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x92, 0xe5, 0x03, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xa0, 0xe1,
|
||||
0x50, 0x20, 0x9f, 0xe5, 0x02, 0x00, 0x54, 0xe1, 0x02, 0x30, 0xa0, 0x11, 0x00, 0x00, 0x50, 0xe3,
|
||||
0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x09, 0x00, 0x00, 0x1a, 0x04, 0x00, 0x00, 0xea,
|
||||
0x01, 0x38, 0xc3, 0xe3, 0x01, 0x18, 0xa0, 0xe1, 0x01, 0x18, 0x01, 0xe2, 0x01, 0x30, 0x83, 0xe1,
|
||||
0x03, 0x00, 0x00, 0xea, 0x06, 0x38, 0xc3, 0xe3, 0x81, 0x18, 0xa0, 0xe1, 0x06, 0x18, 0x01, 0xe2,
|
||||
0x01, 0x30, 0x83, 0xe1, 0x08, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x82, 0xe5, 0x10, 0x00, 0xbd, 0xe8,
|
||||
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x54, 0x30, 0x9f, 0xe5,
|
||||
0x01, 0x20, 0xa0, 0xe3, 0x18, 0x20, 0x83, 0xe5, 0x04, 0x20, 0x83, 0xe5, 0x03, 0x20, 0xa0, 0xe1,
|
||||
0x10, 0x30, 0x92, 0xe5, 0x01, 0x00, 0x13, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x34, 0x30, 0x9f, 0xe5,
|
||||
0x50, 0x00, 0x93, 0xe5, 0xff, 0x04, 0xc0, 0xe3, 0x3f, 0x07, 0xc0, 0xe3, 0x41, 0x3e, 0x40, 0xe2,
|
||||
0x0a, 0x30, 0x43, 0xe2, 0x63, 0x00, 0x53, 0xe3, 0x02, 0x00, 0xa0, 0x93, 0x1e, 0xff, 0x2f, 0x91,
|
||||
0x16, 0x0d, 0x40, 0xe2, 0x0c, 0x00, 0x40, 0xe2, 0x63, 0x00, 0x50, 0xe3, 0x00, 0x00, 0xa0, 0x83,
|
||||
0x01, 0x00, 0xa0, 0x93, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x05, 0x80, 0xf0, 0x41, 0x2d, 0xe9,
|
||||
0x00, 0x60, 0xa0, 0xe1, 0x01, 0x70, 0xa0, 0xe1, 0x28, 0x32, 0x9f, 0xe5, 0x03, 0x00, 0x50, 0xe1,
|
||||
0x34, 0x00, 0x00, 0x1a, 0x20, 0x32, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3, 0x08, 0x20, 0x83, 0xe5,
|
||||
0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0xff, 0x24, 0xc2, 0xe3,
|
||||
0x02, 0x21, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x0f, 0x28, 0xc2, 0xe3,
|
||||
0x01, 0x28, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x7f, 0x2e, 0xc2, 0xe3,
|
||||
0x0f, 0x20, 0xc2, 0xe3, 0xc8, 0x20, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0x01, 0x26, 0xa0, 0xe3,
|
||||
0xd4, 0x20, 0x83, 0xe5, 0x34, 0x21, 0x83, 0xe5, 0x30, 0x11, 0x93, 0xe5, 0x03, 0x18, 0xc1, 0xe3,
|
||||
0x02, 0x18, 0x81, 0xe3, 0x30, 0x11, 0x83, 0xe5, 0x03, 0x39, 0x43, 0xe2, 0x30, 0x10, 0x93, 0xe5,
|
||||
0x0f, 0x1c, 0xc1, 0xe3, 0x01, 0x1c, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x30, 0x10, 0x93, 0xe5,
|
||||
0x3f, 0x10, 0xc1, 0xe3, 0x10, 0x10, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x01, 0x18, 0xa0, 0xe3,
|
||||
0x38, 0x10, 0x83, 0xe5, 0x80, 0x10, 0x93, 0xe5, 0x02, 0x15, 0x81, 0xe3, 0x80, 0x10, 0x83, 0xe5,
|
||||
0x18, 0x20, 0x83, 0xe5, 0x10, 0x20, 0x93, 0xe5, 0x3f, 0x2a, 0xc2, 0xe3, 0x01, 0x28, 0x82, 0xe3,
|
||||
0x10, 0x20, 0x83, 0xe5, 0x01, 0x39, 0x43, 0xe2, 0x00, 0x10, 0xa0, 0xe3, 0x20, 0x20, 0x93, 0xe5,
|
||||
0x01, 0x2a, 0x82, 0xe3, 0x20, 0x20, 0x83, 0xe5, 0x90, 0x1f, 0x07, 0xee, 0x00, 0x00, 0xa0, 0xe1,
|
||||
0x00, 0x00, 0xa0, 0xe1, 0xf8, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3,
|
||||
0x8d, 0xff, 0xff, 0xeb, 0x01, 0x00, 0xa0, 0xe3, 0x77, 0xff, 0xff, 0xeb, 0x00, 0x40, 0xa0, 0xe1,
|
||||
0x01, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x87, 0xff, 0xff, 0xeb, 0x01, 0x00, 0x54, 0xe3,
|
||||
0x31, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x54, 0xe3, 0x04, 0x00, 0x00, 0x1a, 0x01, 0x27, 0xa0, 0xe3,
|
||||
0x18, 0x31, 0x9f, 0xe5, 0x78, 0x20, 0x83, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0xf0, 0x81, 0xbd, 0xe8,
|
||||
0x0c, 0x31, 0x9f, 0xe5, 0xc0, 0x30, 0x93, 0xe5, 0x3f, 0x34, 0x03, 0xe2, 0x23, 0x3c, 0xa0, 0xe1,
|
||||
0x20, 0x00, 0x13, 0xe3, 0x01, 0x00, 0x00, 0x1a, 0x10, 0x00, 0x13, 0xe3, 0x24, 0x00, 0x00, 0x0a,
|
||||
0xe4, 0x30, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3, 0x08, 0x20, 0x83, 0xe5, 0x03, 0x21, 0x82, 0xe2,
|
||||
0x08, 0x20, 0x83, 0xe5, 0x3f, 0x21, 0x82, 0xe2, 0x48, 0x21, 0x83, 0xe5, 0x00, 0x20, 0xa0, 0xe3,
|
||||
0x44, 0x21, 0x83, 0xe5, 0x3f, 0x24, 0x82, 0xe2, 0x58, 0x20, 0x83, 0xe5, 0xc2, 0x24, 0x82, 0xe2,
|
||||
0x24, 0x20, 0x83, 0xe5, 0x84, 0xff, 0xff, 0xeb, 0x00, 0x40, 0x50, 0xe2, 0x06, 0x00, 0x00, 0x1a,
|
||||
0x0a, 0x00, 0x00, 0xea, 0x80, 0xff, 0xff, 0xeb, 0x00, 0x00, 0x54, 0xe1, 0x0a, 0x00, 0x00, 0x1a,
|
||||
0xc0, 0x30, 0x98, 0xe5, 0x03, 0x00, 0x55, 0xe1, 0xf9, 0xff, 0xff, 0x8a, 0x01, 0x00, 0x54, 0xe3,
|
||||
0x02, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x54, 0xe3, 0x03, 0x00, 0x00, 0x1a, 0x06, 0x00, 0x00, 0xea,
|
||||
0x00, 0x60, 0x87, 0xe5, 0x01, 0x00, 0xa0, 0xe3, 0xf0, 0x81, 0xbd, 0xe8, 0x74, 0x20, 0x9f, 0xe5,
|
||||
0x6c, 0x30, 0x9f, 0xe5, 0x00, 0x21, 0x83, 0xe5, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe3,
|
||||
0xf0, 0x81, 0xbd, 0xe8, 0x50, 0x30, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3, 0x08, 0x20, 0x83, 0xe5,
|
||||
0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0x3f, 0x21, 0x82, 0xe2, 0x48, 0x21, 0x83, 0xe5,
|
||||
0x00, 0x20, 0xa0, 0xe3, 0x44, 0x21, 0x83, 0xe5, 0x3f, 0x24, 0x82, 0xe2, 0x58, 0x20, 0x83, 0xe5,
|
||||
0xc2, 0x24, 0x82, 0xe2, 0x24, 0x20, 0x83, 0xe5, 0x5f, 0xff, 0xff, 0xeb, 0x00, 0x40, 0xa0, 0xe1,
|
||||
0x24, 0x30, 0x9f, 0xe5, 0xc0, 0x50, 0x93, 0xe5, 0x3d, 0x59, 0x85, 0xe2, 0x09, 0x5d, 0x85, 0xe2,
|
||||
0x03, 0x80, 0xa0, 0xe1, 0xd9, 0xff, 0xff, 0xea, 0x63, 0x68, 0x72, 0x67, 0x00, 0x00, 0x05, 0x80,
|
||||
0x00, 0xc0, 0x05, 0x80, 0x00, 0x40, 0x04, 0x80, 0x01, 0x00, 0xff, 0xff, 0x00, 0xc0, 0x01, 0x80
|
||||
};
|
||||
unsigned char dualboot_nwze360[944] = {
|
||||
0x10, 0x40, 0x2d, 0xe9, 0x4e, 0x00, 0x00, 0xeb, 0x10, 0x80, 0xbd, 0xe8, 0x40, 0x30, 0x9f, 0xe5,
|
||||
0xb0, 0x30, 0x93, 0xe5, 0x03, 0x18, 0xa0, 0xe1, 0x21, 0x18, 0xa0, 0xe1, 0x34, 0x20, 0x9f, 0xe5,
|
||||
0x02, 0x00, 0x51, 0xe1, 0x08, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x50, 0xe3, 0x01, 0x38, 0x03, 0x02,
|
||||
0x23, 0x08, 0xa0, 0x01, 0x1e, 0xff, 0x2f, 0x01, 0x01, 0x00, 0x50, 0xe3, 0x02, 0x00, 0x00, 0x1a,
|
||||
0x06, 0x38, 0x03, 0xe2, 0xa3, 0x08, 0xa0, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0xa0, 0xe3,
|
||||
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x04, 0x40, 0x2d, 0xe5,
|
||||
0x5c, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x92, 0xe5, 0x03, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xa0, 0xe1,
|
||||
0x50, 0x20, 0x9f, 0xe5, 0x02, 0x00, 0x54, 0xe1, 0x02, 0x30, 0xa0, 0x11, 0x00, 0x00, 0x50, 0xe3,
|
||||
0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x09, 0x00, 0x00, 0x1a, 0x04, 0x00, 0x00, 0xea,
|
||||
0x01, 0x38, 0xc3, 0xe3, 0x01, 0x18, 0xa0, 0xe1, 0x01, 0x18, 0x01, 0xe2, 0x01, 0x30, 0x83, 0xe1,
|
||||
0x03, 0x00, 0x00, 0xea, 0x06, 0x38, 0xc3, 0xe3, 0x81, 0x18, 0xa0, 0xe1, 0x06, 0x18, 0x01, 0xe2,
|
||||
0x01, 0x30, 0x83, 0xe1, 0x08, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x82, 0xe5, 0x10, 0x00, 0xbd, 0xe8,
|
||||
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x68, 0x30, 0x9f, 0xe5,
|
||||
0x01, 0x20, 0xa0, 0xe3, 0x18, 0x20, 0x83, 0xe5, 0x04, 0x20, 0x83, 0xe5, 0x03, 0x20, 0xa0, 0xe1,
|
||||
0x10, 0x30, 0x92, 0xe5, 0x01, 0x00, 0x13, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x48, 0x30, 0x9f, 0xe5,
|
||||
0x50, 0x30, 0x93, 0xe5, 0x44, 0x20, 0x9f, 0xe5, 0x00, 0x26, 0x92, 0xe5, 0x02, 0x0c, 0x12, 0xe3,
|
||||
0x00, 0x00, 0xa0, 0x03, 0x1e, 0xff, 0x2f, 0x01, 0xff, 0x34, 0xc3, 0xe3, 0x3f, 0x37, 0xc3, 0xe3,
|
||||
0x41, 0x2e, 0x43, 0xe2, 0x0a, 0x20, 0x42, 0xe2, 0x63, 0x00, 0x52, 0xe3, 0x02, 0x00, 0xa0, 0x93,
|
||||
0x1e, 0xff, 0x2f, 0x91, 0x16, 0x3d, 0x43, 0xe2, 0x0c, 0x30, 0x43, 0xe2, 0x63, 0x00, 0x53, 0xe3,
|
||||
0x00, 0x00, 0xa0, 0x83, 0x01, 0x00, 0xa0, 0x93, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x05, 0x80,
|
||||
0x00, 0x80, 0x01, 0x80, 0xf0, 0x41, 0x2d, 0xe9, 0x00, 0x60, 0xa0, 0xe1, 0x01, 0x70, 0xa0, 0xe1,
|
||||
0x40, 0x32, 0x9f, 0xe5, 0x03, 0x00, 0x50, 0xe1, 0x34, 0x00, 0x00, 0x1a, 0x38, 0x32, 0x9f, 0xe5,
|
||||
0x02, 0x21, 0xa0, 0xe3, 0x08, 0x20, 0x83, 0xe5, 0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5,
|
||||
0xd0, 0x20, 0x93, 0xe5, 0xff, 0x24, 0xc2, 0xe3, 0x02, 0x21, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5,
|
||||
0xd0, 0x20, 0x93, 0xe5, 0x0f, 0x28, 0xc2, 0xe3, 0x01, 0x28, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5,
|
||||
0xd0, 0x20, 0x93, 0xe5, 0x7f, 0x2e, 0xc2, 0xe3, 0x0f, 0x20, 0xc2, 0xe3, 0xc8, 0x20, 0x82, 0xe3,
|
||||
0xd0, 0x20, 0x83, 0xe5, 0x01, 0x26, 0xa0, 0xe3, 0xd4, 0x20, 0x83, 0xe5, 0x34, 0x21, 0x83, 0xe5,
|
||||
0x30, 0x11, 0x93, 0xe5, 0x03, 0x18, 0xc1, 0xe3, 0x02, 0x18, 0x81, 0xe3, 0x30, 0x11, 0x83, 0xe5,
|
||||
0x03, 0x39, 0x43, 0xe2, 0x30, 0x10, 0x93, 0xe5, 0x0f, 0x1c, 0xc1, 0xe3, 0x01, 0x1c, 0x81, 0xe3,
|
||||
0x30, 0x10, 0x83, 0xe5, 0x30, 0x10, 0x93, 0xe5, 0x3f, 0x10, 0xc1, 0xe3, 0x10, 0x10, 0x81, 0xe3,
|
||||
0x30, 0x10, 0x83, 0xe5, 0x01, 0x18, 0xa0, 0xe3, 0x38, 0x10, 0x83, 0xe5, 0x80, 0x10, 0x93, 0xe5,
|
||||
0x02, 0x15, 0x81, 0xe3, 0x80, 0x10, 0x83, 0xe5, 0x18, 0x20, 0x83, 0xe5, 0x10, 0x20, 0x93, 0xe5,
|
||||
0x3f, 0x2a, 0xc2, 0xe3, 0x01, 0x28, 0x82, 0xe3, 0x10, 0x20, 0x83, 0xe5, 0x01, 0x39, 0x43, 0xe2,
|
||||
0x00, 0x10, 0xa0, 0xe3, 0x20, 0x20, 0x93, 0xe5, 0x01, 0x2a, 0x82, 0xe3, 0x20, 0x20, 0x83, 0xe5,
|
||||
0x90, 0x1f, 0x07, 0xee, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0xf8, 0xff, 0xff, 0xea,
|
||||
0x00, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3, 0x87, 0xff, 0xff, 0xeb, 0x01, 0x00, 0xa0, 0xe3,
|
||||
0x71, 0xff, 0xff, 0xeb, 0x00, 0x40, 0xa0, 0xe1, 0x01, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3,
|
||||
0x81, 0xff, 0xff, 0xeb, 0x01, 0x00, 0x54, 0xe3, 0x34, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x54, 0xe3,
|
||||
0x04, 0x00, 0x00, 0x1a, 0x01, 0x27, 0xa0, 0xe3, 0x30, 0x31, 0x9f, 0xe5, 0x78, 0x20, 0x83, 0xe5,
|
||||
0x00, 0x00, 0xa0, 0xe3, 0xf0, 0x81, 0xbd, 0xe8, 0x24, 0x31, 0x9f, 0xe5, 0xc0, 0x30, 0x93, 0xe5,
|
||||
0x3f, 0x34, 0x03, 0xe2, 0x23, 0x3c, 0xa0, 0xe1, 0x20, 0x00, 0x13, 0xe3, 0x01, 0x00, 0x00, 0x1a,
|
||||
0x10, 0x00, 0x13, 0xe3, 0x27, 0x00, 0x00, 0x0a, 0xfc, 0x30, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3,
|
||||
0x08, 0x20, 0x83, 0xe5, 0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0x3f, 0x21, 0x82, 0xe2,
|
||||
0x48, 0x21, 0x83, 0xe5, 0x00, 0x20, 0xa0, 0xe3, 0x44, 0x21, 0x83, 0xe5, 0x3f, 0x24, 0x82, 0xe2,
|
||||
0x58, 0x20, 0x83, 0xe5, 0xc2, 0x24, 0x82, 0xe2, 0x24, 0x20, 0x83, 0xe5, 0x02, 0x2c, 0xa0, 0xe3,
|
||||
0x0e, 0x39, 0x43, 0xe2, 0x04, 0x24, 0x83, 0xe5, 0x7b, 0xff, 0xff, 0xeb, 0x00, 0x40, 0x50, 0xe2,
|
||||
0x06, 0x00, 0x00, 0x1a, 0x0a, 0x00, 0x00, 0xea, 0x77, 0xff, 0xff, 0xeb, 0x00, 0x00, 0x54, 0xe1,
|
||||
0x0a, 0x00, 0x00, 0x1a, 0xc0, 0x30, 0x98, 0xe5, 0x03, 0x00, 0x55, 0xe1, 0xf9, 0xff, 0xff, 0x8a,
|
||||
0x01, 0x00, 0x54, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x54, 0xe3, 0x03, 0x00, 0x00, 0x1a,
|
||||
0x06, 0x00, 0x00, 0xea, 0x00, 0x60, 0x87, 0xe5, 0x01, 0x00, 0xa0, 0xe3, 0xf0, 0x81, 0xbd, 0xe8,
|
||||
0x80, 0x20, 0x9f, 0xe5, 0x78, 0x30, 0x9f, 0xe5, 0x00, 0x21, 0x83, 0xe5, 0xfe, 0xff, 0xff, 0xea,
|
||||
0x00, 0x00, 0xa0, 0xe3, 0xf0, 0x81, 0xbd, 0xe8, 0x5c, 0x30, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3,
|
||||
0x08, 0x20, 0x83, 0xe5, 0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0x3f, 0x21, 0x82, 0xe2,
|
||||
0x48, 0x21, 0x83, 0xe5, 0x00, 0x20, 0xa0, 0xe3, 0x44, 0x21, 0x83, 0xe5, 0x3f, 0x24, 0x82, 0xe2,
|
||||
0x58, 0x20, 0x83, 0xe5, 0xc2, 0x24, 0x82, 0xe2, 0x24, 0x20, 0x83, 0xe5, 0x02, 0x2c, 0xa0, 0xe3,
|
||||
0x0e, 0x39, 0x43, 0xe2, 0x04, 0x24, 0x83, 0xe5, 0x53, 0xff, 0xff, 0xeb, 0x00, 0x40, 0xa0, 0xe1,
|
||||
0x24, 0x30, 0x9f, 0xe5, 0xc0, 0x50, 0x93, 0xe5, 0x3d, 0x59, 0x85, 0xe2, 0x09, 0x5d, 0x85, 0xe2,
|
||||
0x03, 0x80, 0xa0, 0xe1, 0xd6, 0xff, 0xff, 0xea, 0x63, 0x68, 0x72, 0x67, 0x00, 0x00, 0x05, 0x80,
|
||||
0x00, 0xc0, 0x05, 0x80, 0x00, 0x40, 0x04, 0x80, 0x01, 0x00, 0xff, 0xff, 0x00, 0xc0, 0x01, 0x80
|
||||
};
|
||||
unsigned char dualboot_zenxfistyle[660] = {
|
||||
0x10, 0x40, 0x2d, 0xe9, 0x30, 0x00, 0x00, 0xeb, 0x10, 0x80, 0xbd, 0xe8, 0x40, 0x30, 0x9f, 0xe5,
|
||||
0xb0, 0x30, 0x93, 0xe5, 0x03, 0x18, 0xa0, 0xe1, 0x21, 0x18, 0xa0, 0xe1, 0x34, 0x20, 0x9f, 0xe5,
|
||||
0x02, 0x00, 0x51, 0xe1, 0x08, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x50, 0xe3, 0x01, 0x38, 0x03, 0x02,
|
||||
0x23, 0x08, 0xa0, 0x01, 0x1e, 0xff, 0x2f, 0x01, 0x01, 0x00, 0x50, 0xe3, 0x02, 0x00, 0x00, 0x1a,
|
||||
0x06, 0x38, 0x03, 0xe2, 0xa3, 0x08, 0xa0, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0xa0, 0xe3,
|
||||
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x04, 0x40, 0x2d, 0xe5,
|
||||
0x5c, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x92, 0xe5, 0x03, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xa0, 0xe1,
|
||||
0x50, 0x20, 0x9f, 0xe5, 0x02, 0x00, 0x54, 0xe1, 0x02, 0x30, 0xa0, 0x11, 0x00, 0x00, 0x50, 0xe3,
|
||||
0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x09, 0x00, 0x00, 0x1a, 0x04, 0x00, 0x00, 0xea,
|
||||
0x01, 0x38, 0xc3, 0xe3, 0x01, 0x18, 0xa0, 0xe1, 0x01, 0x18, 0x01, 0xe2, 0x01, 0x30, 0x83, 0xe1,
|
||||
0x03, 0x00, 0x00, 0xea, 0x06, 0x38, 0xc3, 0xe3, 0x81, 0x18, 0xa0, 0xe1, 0x06, 0x18, 0x01, 0xe2,
|
||||
0x01, 0x30, 0x83, 0xe1, 0x08, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x82, 0xe5, 0x10, 0x00, 0xbd, 0xe8,
|
||||
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x70, 0x40, 0x2d, 0xe9,
|
||||
0x00, 0x40, 0xa0, 0xe1, 0x01, 0x60, 0xa0, 0xe1, 0xa4, 0x31, 0x9f, 0xe5, 0x03, 0x00, 0x50, 0xe1,
|
||||
0x34, 0x00, 0x00, 0x1a, 0x9c, 0x31, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3, 0x08, 0x20, 0x83, 0xe5,
|
||||
0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0xff, 0x24, 0xc2, 0xe3,
|
||||
0x02, 0x21, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x0f, 0x28, 0xc2, 0xe3,
|
||||
0x01, 0x28, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x7f, 0x2e, 0xc2, 0xe3,
|
||||
0x0f, 0x20, 0xc2, 0xe3, 0xc8, 0x20, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0x01, 0x26, 0xa0, 0xe3,
|
||||
0xd4, 0x20, 0x83, 0xe5, 0x34, 0x21, 0x83, 0xe5, 0x30, 0x11, 0x93, 0xe5, 0x03, 0x18, 0xc1, 0xe3,
|
||||
0x02, 0x18, 0x81, 0xe3, 0x30, 0x11, 0x83, 0xe5, 0x03, 0x39, 0x43, 0xe2, 0x30, 0x10, 0x93, 0xe5,
|
||||
0x0f, 0x1c, 0xc1, 0xe3, 0x01, 0x1c, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x30, 0x10, 0x93, 0xe5,
|
||||
0x3f, 0x10, 0xc1, 0xe3, 0x10, 0x10, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x01, 0x18, 0xa0, 0xe3,
|
||||
0x38, 0x10, 0x83, 0xe5, 0x80, 0x10, 0x93, 0xe5, 0x02, 0x15, 0x81, 0xe3, 0x80, 0x10, 0x83, 0xe5,
|
||||
0x18, 0x20, 0x83, 0xe5, 0x10, 0x20, 0x93, 0xe5, 0x3f, 0x2a, 0xc2, 0xe3, 0x01, 0x28, 0x82, 0xe3,
|
||||
0x10, 0x20, 0x83, 0xe5, 0x01, 0x39, 0x43, 0xe2, 0x00, 0x10, 0xa0, 0xe3, 0x20, 0x20, 0x93, 0xe5,
|
||||
0x01, 0x2a, 0x82, 0xe3, 0x20, 0x20, 0x83, 0xe5, 0x90, 0x1f, 0x07, 0xee, 0x00, 0x00, 0xa0, 0xe1,
|
||||
0x00, 0x00, 0xa0, 0xe1, 0xf8, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3,
|
||||
0xa5, 0xff, 0xff, 0xeb, 0x01, 0x00, 0xa0, 0xe3, 0x8f, 0xff, 0xff, 0xeb, 0x00, 0x50, 0xa0, 0xe1,
|
||||
0x01, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x9f, 0xff, 0xff, 0xeb, 0x01, 0x00, 0x55, 0xe3,
|
||||
0x25, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x55, 0xe3, 0x04, 0x00, 0x00, 0x1a, 0x01, 0x27, 0xa0, 0xe3,
|
||||
0x94, 0x30, 0x9f, 0xe5, 0x78, 0x20, 0x83, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0x70, 0x80, 0xbd, 0xe8,
|
||||
0x88, 0x30, 0x9f, 0xe5, 0xc0, 0x30, 0x93, 0xe5, 0x78, 0x30, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3,
|
||||
0x08, 0x20, 0x83, 0xe5, 0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0x0f, 0x2c, 0xa0, 0xe3,
|
||||
0x48, 0x21, 0x83, 0xe5, 0x0d, 0x2c, 0x42, 0xe2, 0x44, 0x21, 0x83, 0xe5, 0x3f, 0x24, 0xa0, 0xe3,
|
||||
0x78, 0x20, 0x83, 0xe5, 0xc5, 0x24, 0x82, 0xe2, 0x24, 0x20, 0x83, 0xe5, 0x04, 0x20, 0xa0, 0xe3,
|
||||
0x18, 0x20, 0x83, 0xe5, 0x04, 0x20, 0x83, 0xe5, 0x10, 0x20, 0x93, 0xe5, 0x04, 0x00, 0x12, 0xe3,
|
||||
0xfc, 0xff, 0xff, 0x0a, 0x2c, 0x30, 0x9f, 0xe5, 0x70, 0x30, 0x93, 0xe5, 0xff, 0x34, 0xc3, 0xe3,
|
||||
0x3f, 0x37, 0xc3, 0xe3, 0xcb, 0x3f, 0x43, 0xe2, 0x03, 0x30, 0x43, 0xe2, 0x63, 0x00, 0x53, 0xe3,
|
||||
0x00, 0x40, 0x86, 0x85, 0x01, 0x00, 0xa0, 0x83, 0x70, 0x80, 0xbd, 0x88, 0x00, 0x00, 0xa0, 0xe3,
|
||||
0x70, 0x80, 0xbd, 0xe8, 0x63, 0x68, 0x72, 0x67, 0x00, 0x00, 0x05, 0x80, 0x00, 0xc0, 0x05, 0x80,
|
||||
0x00, 0x40, 0x04, 0x80
|
||||
};
|
||||
8
utils/mkimxboot/dualboot.h
Normal file
8
utils/mkimxboot/dualboot.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/* Generated by bin2c */
|
||||
|
||||
extern unsigned char dualboot_fuzeplus[728];
|
||||
extern unsigned char dualboot_zenxfi2[608];
|
||||
extern unsigned char dualboot_zenxfi3[572];
|
||||
extern unsigned char dualboot_nwze370[896];
|
||||
extern unsigned char dualboot_nwze360[944];
|
||||
extern unsigned char dualboot_zenxfistyle[660];
|
||||
48
utils/mkimxboot/dualboot/Makefile
Normal file
48
utils/mkimxboot/dualboot/Makefile
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
CC=gcc
|
||||
LD=ld
|
||||
OC=objcopy
|
||||
PREFIX?=arm-elf-eabi-
|
||||
IMX233_PATH=../../../firmware/target/arm/imx233
|
||||
CFLAGS=-mcpu=arm926ej-s -std=gnu99 -I. -I$(IMX233_PATH) -nostdlib -ffreestanding -fomit-frame-pointer -O
|
||||
# Edit the following variables when adding a new target.
|
||||
# mkimxboot.c also needs to be edited to refer to these
|
||||
# To add a new target x you need to:
|
||||
# 1) add x to the list in TARGETS
|
||||
# 2) create a variable named OPT_x of the form:
|
||||
# OPT_x=target specific defines
|
||||
TARGETS=fuzeplus zenxfi2 zenxfi3 nwze370 nwze360 zenxfistyle
|
||||
OPT_fuzeplus=-DSANSA_FUZEPLUS -DIMX233_SUBTARGET=3780
|
||||
OPT_zenxfi2=-DCREATIVE_ZENXFI2 -DIMX233_SUBTARGET=3780
|
||||
OPT_zenxfi3=-DCREATIVE_ZENXFI3 -DIMX233_SUBTARGET=3780
|
||||
OPT_nwze370=-DSONY_NWZE370 -DIMX233_SUBTARGET=3780
|
||||
OPT_nwze360=-DSONY_NWZE360 -DIMX233_SUBTARGET=3780
|
||||
OPT_zenxfistyle=-DCREATIVE_ZENXFISTYLE -DIMX233_SUBTARGET=3780
|
||||
|
||||
BOOTOBJS=$(patsubst %, dualboot_%.o, $(TARGETS))
|
||||
BOOTBINS=$(patsubst %, dualboot_%.arm-bin, $(TARGETS))
|
||||
BOOTELFS=$(patsubst %, dualboot_%.arm-elf, $(TARGETS))
|
||||
|
||||
all: ../dualboot.h ../dualboot.c $(BOOTELFS)
|
||||
|
||||
# Dualboot bootloaders
|
||||
|
||||
dualboot_%.o: dualboot.c
|
||||
$(PREFIX)$(CC) $(CFLAGS) $(OPT_$(@:dualboot_%.o=%)) -c -o $@ $^
|
||||
|
||||
dualboot_%.arm-elf: dualboot_%.o
|
||||
$(PREFIX)$(LD) $(LDFLAGS) -Tdualboot.lds -o $@ $<
|
||||
|
||||
# Rules for the ARM code embedded in mkamsboot - assemble, link, then extract
|
||||
# the binary code and finally convert to .h for building in mkamsboot
|
||||
|
||||
%.arm-bin: %.arm-elf
|
||||
$(PREFIX)$(OC) -O binary $< $@
|
||||
|
||||
../dualboot.c ../dualboot.h: $(BOOTBINS) bin2c
|
||||
./bin2c ../dualboot $(BOOTBINS)
|
||||
|
||||
bin2c: bin2c.c
|
||||
$(CC) -o bin2c bin2c.c
|
||||
|
||||
clean:
|
||||
rm -f *~ bin2c $(BOOTBINS) $(BOOTOBJS) $(BOOTELFS)
|
||||
140
utils/mkimxboot/dualboot/bin2c.c
Normal file
140
utils/mkimxboot/dualboot/bin2c.c
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2007 Dave Chapman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
static off_t filesize(int fd)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
fstat(fd,&buf);
|
||||
return buf.st_size;
|
||||
}
|
||||
|
||||
static void write_cfile(const unsigned char* buf, off_t len, FILE* fp, const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf(fp,"unsigned char %s[%ld] = {",name,len);
|
||||
|
||||
for (i=0;i<len;i++) {
|
||||
if ((i % 16) == 0) {
|
||||
fprintf(fp,"\n ");
|
||||
}
|
||||
if (i == (len-1)) {
|
||||
fprintf(fp,"0x%02x",buf[i]);
|
||||
} else if ((i % 16) == 15) {
|
||||
fprintf(fp,"0x%02x,",buf[i]);
|
||||
} else {
|
||||
fprintf(fp,"0x%02x, ",buf[i]);
|
||||
}
|
||||
}
|
||||
fprintf(fp,"\n};\n");
|
||||
}
|
||||
|
||||
int main (int argc, char* argv[])
|
||||
{
|
||||
char* cname;
|
||||
int i;
|
||||
FILE *cfile, *hfile;
|
||||
char cfilename[256], hfilename[256];
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr,"Usage: bin2c cname file1 [file2 [file3 ...]]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cname=argv[1];
|
||||
|
||||
snprintf(cfilename,256,"%s.c",cname);
|
||||
cfile = fopen(cfilename,"w+");
|
||||
if (cfile == NULL) {
|
||||
fprintf(stderr,"Couldn't open %s\n",cfilename);
|
||||
return 2;
|
||||
}
|
||||
|
||||
snprintf(hfilename,256,"%s.h",cname);
|
||||
hfile = fopen(hfilename,"w+");
|
||||
if (hfile == NULL) {
|
||||
fprintf(stderr,"Couldn't open %s\n",hfilename);
|
||||
fclose(cfile);
|
||||
return 3;
|
||||
}
|
||||
|
||||
fprintf(cfile,"/* Generated by bin2c */\n\n");
|
||||
fprintf(cfile,"#include \"%s\"\n\n", basename(hfilename));
|
||||
fprintf(hfile,"/* Generated by bin2c */\n\n");
|
||||
|
||||
for(i=0; i < argc - 2; i++) {
|
||||
unsigned char* buf;
|
||||
off_t len;
|
||||
off_t orig_len;
|
||||
char *ext;
|
||||
char *array = argv[2+i];
|
||||
|
||||
int fd = open(array,O_RDONLY|O_BINARY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr,"Can not open %s\n",argv[2+i]);
|
||||
fclose(cfile);
|
||||
fclose(hfile);
|
||||
return 4;
|
||||
}
|
||||
|
||||
orig_len = filesize(fd);
|
||||
/* pad to 32bit */
|
||||
len = (orig_len + 3) & ~3;
|
||||
|
||||
buf = malloc(len);
|
||||
if (read(fd,buf,orig_len) < orig_len) {
|
||||
fprintf(stderr,"Short read, aborting\n");
|
||||
return 5;
|
||||
}
|
||||
|
||||
/* pad to 32bit with zeros */
|
||||
if (len > orig_len)
|
||||
memset(buf+orig_len, 0, len-orig_len);
|
||||
|
||||
/* remove file extension */
|
||||
ext = strchr (array, '.');
|
||||
if (ext != NULL)
|
||||
*ext = '\0';
|
||||
write_cfile (buf, len, cfile, array);
|
||||
fprintf(hfile,"extern unsigned char %s[%ld];\n",array,len);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
fclose(cfile);
|
||||
fclose(hfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
26
utils/mkimxboot/dualboot/config.h
Normal file
26
utils/mkimxboot/dualboot/config.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2013 by Amaury Pouly
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/** mostly empty, used by register files and dualboot */
|
||||
#define COMPILE_DUALBOOT_STUB
|
||||
|
||||
/* obviously we have the dualboot stub! */
|
||||
#define HAVE_DUALBOOT_STUB
|
||||
323
utils/mkimxboot/dualboot/dualboot.c
Normal file
323
utils/mkimxboot/dualboot/dualboot.c
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2013 by Amaury Pouly
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "regs/pinctrl.h"
|
||||
#include "regs/power.h"
|
||||
#include "regs/lradc.h"
|
||||
#include "regs/digctl.h"
|
||||
#include "regs/clkctrl.h"
|
||||
|
||||
#define BOOT_ROM_CONTINUE 0 /* continue boot */
|
||||
#define BOOT_ROM_SECTION 1 /* switch to new section *result_id */
|
||||
|
||||
#define BOOT_ARG_CHARGE ('c' | 'h' << 8 | 'r' << 16 | 'g' << 24)
|
||||
/** additional defines */
|
||||
#define BP_LRADC_CTRL4_LRADCxSELECT(x) (4 * (x))
|
||||
#define BM_LRADC_CTRL4_LRADCxSELECT(x) (0xf << (4 * (x)))
|
||||
|
||||
typedef unsigned long uint32_t;
|
||||
|
||||
/* we include the dualboot rtc code directly */
|
||||
#include "dualboot-imx233.h"
|
||||
#include "dualboot-imx233.c"
|
||||
|
||||
// target specific boot context
|
||||
enum context_t
|
||||
{
|
||||
CONTEXT_NORMAL, /* normal boot */
|
||||
CONTEXT_USB, /* USB plugged boot */
|
||||
CONTEXT_RTC, /* RTC wake up boot */
|
||||
};
|
||||
// target specific boot decision
|
||||
enum boot_t
|
||||
{
|
||||
BOOT_STOP, /* power down */
|
||||
BOOT_ROCK, /* boot to Rockbox */
|
||||
BOOT_OF, /* boot to OF */
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper functions
|
||||
*/
|
||||
|
||||
static inline int __attribute__((always_inline)) read_gpio(int bank, int pin)
|
||||
{
|
||||
return (HW_PINCTRL_DINn(bank) >> pin) & 1;
|
||||
}
|
||||
|
||||
static inline int __attribute__((always_inline)) read_pswitch(void)
|
||||
{
|
||||
#if IMX233_SUBTARGET >= 3700
|
||||
return BF_RD(POWER_STS, PSWITCH);
|
||||
#else
|
||||
return BF_RD(DIGCTL_STATUS, PSWITCH);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* only works for channels <=7, always divide by 2, never accumulates */
|
||||
static inline void __attribute__((always_inline)) setup_lradc(int src)
|
||||
{
|
||||
BF_CLR(LRADC_CTRL0, SFTRST);
|
||||
BF_CLR(LRADC_CTRL0, CLKGATE);
|
||||
#if IMX233_SUBTARGET >= 3700
|
||||
HW_LRADC_CTRL4_CLR = BM_LRADC_CTRL4_LRADCxSELECT(src);
|
||||
HW_LRADC_CTRL4_SET = src << BP_LRADC_CTRL4_LRADCxSELECT(src);
|
||||
#endif
|
||||
HW_LRADC_CHn_CLR(src) = BM_OR(LRADC_CHn, NUM_SAMPLES, ACCUMULATE);
|
||||
BF_WR(LRADC_CTRL2_SET, DIVIDE_BY_TWO(1 << src));
|
||||
}
|
||||
|
||||
#define BP_LRADC_CTRL1_LRADCx_IRQ(x) (x)
|
||||
#define BM_LRADC_CTRL1_LRADCx_IRQ(x) (1 << (x))
|
||||
|
||||
static inline int __attribute__((always_inline)) read_lradc(int src)
|
||||
{
|
||||
BF_CLR(LRADC_CTRL1, LRADCx_IRQ(src));
|
||||
BF_WR(LRADC_CTRL0_SET, SCHEDULE(1 << src));
|
||||
while(!BF_RD(LRADC_CTRL1, LRADCx_IRQ(src)));
|
||||
return BF_RD(LRADC_CHn(src), VALUE);
|
||||
}
|
||||
|
||||
static inline void __attribute__((noreturn)) power_down()
|
||||
{
|
||||
#ifdef SANSA_FUZEPLUS
|
||||
/* B0P09: this pin seems to be important to shutdown the hardware properly */
|
||||
HW_PINCTRL_MUXSELn_SET(0) = 3 << 18;
|
||||
HW_PINCTRL_DOEn(0) = 1 << 9;
|
||||
HW_PINCTRL_DOUTn(0) = 1 << 9;
|
||||
#endif
|
||||
/* power down */
|
||||
HW_POWER_RESET = BM_OR(POWER_RESET, UNLOCK, PWD);
|
||||
while(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Boot decision functions
|
||||
*/
|
||||
|
||||
#if defined(SANSA_FUZEPLUS)
|
||||
static enum boot_t boot_decision(enum context_t context)
|
||||
{
|
||||
/* if volume down is hold, boot to OF */
|
||||
if(!read_gpio(1, 30))
|
||||
return BOOT_OF;
|
||||
/* on normal boot, make sure power button is hold long enough */
|
||||
if(context == CONTEXT_NORMAL)
|
||||
{
|
||||
// monitor PSWITCH
|
||||
int count = 0;
|
||||
for(int i = 0; i < 550000; i++)
|
||||
if(read_pswitch() == 1)
|
||||
count++;
|
||||
if(count < 400000)
|
||||
return BOOT_STOP;
|
||||
}
|
||||
return BOOT_ROCK;
|
||||
}
|
||||
#elif defined(CREATIVE_ZENXFI2)
|
||||
static int boot_decision(int context)
|
||||
{
|
||||
/* We are lacking buttons on the Zen X-Fi2 because on USB, the select button
|
||||
* enters recovery mode ! So we can only use power but power is used to power up
|
||||
* on normal boots and then select is free ! Thus use a non-uniform scheme:
|
||||
* - normal boot/RTC:
|
||||
* - no key: Rockbox
|
||||
* - select: OF
|
||||
* - USB boot:
|
||||
* - no key: Rockbox
|
||||
* - power: OF
|
||||
*/
|
||||
if(context == CONTEXT_USB)
|
||||
return read_pswitch() == 1 ? BOOT_OF : BOOT_ROCK;
|
||||
else
|
||||
return !read_gpio(0, 14) ? BOOT_OF : BOOT_ROCK;
|
||||
}
|
||||
#elif defined(CREATIVE_ZENXFI3)
|
||||
static int boot_decision(int context)
|
||||
{
|
||||
/* if volume down is hold, boot to OF */
|
||||
return !read_gpio(2, 7) ? BOOT_OF : BOOT_ROCK;
|
||||
}
|
||||
#elif defined(SONY_NWZE360) || defined(SONY_NWZE370)
|
||||
static int local_decision(void)
|
||||
{
|
||||
/* read keys and pswitch */
|
||||
int val = read_lradc(0);
|
||||
/* if hold is on, power off
|
||||
* if back is pressed, boot to OF
|
||||
* if play is pressed, boot RB
|
||||
* otherwise power off */
|
||||
#ifdef SONY_NWZE360
|
||||
if(read_gpio(0, 9) == 0)
|
||||
return BOOT_STOP;
|
||||
#endif
|
||||
if(val >= 1050 && val < 1150)
|
||||
return BOOT_OF;
|
||||
if(val >= 1420 && val < 1520)
|
||||
return BOOT_ROCK;
|
||||
return BOOT_STOP;
|
||||
}
|
||||
|
||||
static int boot_decision(int context)
|
||||
{
|
||||
setup_lradc(0); // setup LRADC channel 0 to read keys
|
||||
#ifdef SONY_NWZE360
|
||||
HW_PINCTRL_PULLn_SET(0) = 1 << 9; // enable pullup on hold key (B0P09)
|
||||
#endif
|
||||
/* make a decision */
|
||||
int decision = local_decision();
|
||||
/* in USB or alarm context, stick to it */
|
||||
if(context == CONTEXT_USB || context == CONTEXT_RTC)
|
||||
{
|
||||
/* never power down so replace power off decision by rockbox */
|
||||
return decision == BOOT_STOP ? BOOT_ROCK : decision;
|
||||
}
|
||||
/* otherwise start a 1 second timeout. Any decision change
|
||||
* will result in power down */
|
||||
uint32_t tmo = HW_DIGCTL_MICROSECONDS + 1000000;
|
||||
while(HW_DIGCTL_MICROSECONDS < tmo)
|
||||
{
|
||||
int new_dec = local_decision();
|
||||
if(new_dec != decision)
|
||||
return BOOT_STOP;
|
||||
}
|
||||
return decision;
|
||||
}
|
||||
#elif defined(CREATIVE_ZENXFISTYLE)
|
||||
static int boot_decision(int context)
|
||||
{
|
||||
setup_lradc(2); // setup LRADC channel 2 to read keys
|
||||
/* make a decision */
|
||||
int val = read_lradc(2);
|
||||
/* boot to OF if left is hold
|
||||
* NOTE: VDDIO is set to 3.1V initially and the resistor ladder is wired to
|
||||
* VDDIO so these values are not the same as in the main binary which is
|
||||
* calibrated for VDDIO=3.3V */
|
||||
if(val >= 815 && val < 915)
|
||||
return BOOT_OF;
|
||||
return BOOT_ROCK;
|
||||
}
|
||||
#else
|
||||
#warning You should define a target specific boot decision function
|
||||
static int boot_decision(int context)
|
||||
{
|
||||
return BOOT_ROCK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Context functions
|
||||
*/
|
||||
static inline enum context_t get_context(void)
|
||||
{
|
||||
#if IMX233_SUBTARGET >= 3780
|
||||
/* On the imx233 it's easy because we know the power up source */
|
||||
unsigned pwrup_src = BF_RD(POWER_STS, PWRUP_SOURCE);
|
||||
if(pwrup_src & (1 << 5))
|
||||
return CONTEXT_USB;
|
||||
else if(pwrup_src & (1 << 4))
|
||||
return CONTEXT_RTC;
|
||||
else
|
||||
return CONTEXT_NORMAL;
|
||||
#else
|
||||
/* On the other targets, we need to poke a few more registers */
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Charging function
|
||||
*/
|
||||
static inline void do_charge(void)
|
||||
{
|
||||
BF_CLR(LRADC_CTRL0, SFTRST);
|
||||
BF_CLR(LRADC_CTRL0, CLKGATE);
|
||||
BF_WR(LRADC_DELAYn(0), TRIGGER_LRADCS(0x80));
|
||||
BF_WR(LRADC_DELAYn(0), TRIGGER_DELAYS(0x1));
|
||||
BF_WR(LRADC_DELAYn(0), DELAY(200));
|
||||
BF_SET(LRADC_DELAYn(0), KICK);
|
||||
BF_SET(LRADC_CONVERSION, AUTOMATIC);
|
||||
BF_WR(LRADC_CONVERSION, SCALE_FACTOR_V(LI_ION));
|
||||
BF_WR(POWER_CHARGE, STOP_ILIMIT(1));
|
||||
BF_WR(POWER_CHARGE, BATTCHRG_I(0x10));
|
||||
BF_CLR(POWER_CHARGE, PWD_BATTCHRG);
|
||||
#if IMX233_SUBTARGET >= 3780
|
||||
BF_WR(POWER_DCDC4P2, ENABLE_4P2(1));
|
||||
BF_CLR(POWER_5VCTRL, PWD_CHARGE_4P2);
|
||||
BF_WR(POWER_5VCTRL, CHARGE_4P2_ILIMIT(0x10));
|
||||
#endif
|
||||
while(1)
|
||||
{
|
||||
BF_WR(CLKCTRL_CPU, INTERRUPT_WAIT(1));
|
||||
asm volatile (
|
||||
"mcr p15, 0, %0, c7, c0, 4 \n" /* Wait for interrupt */
|
||||
"nop\n" /* Datasheet unclear: "The lr sent to handler points here after RTI"*/
|
||||
"nop\n"
|
||||
: : "r"(0)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_updater_bits(void)
|
||||
{
|
||||
/* The OF will continue to updater if we clear 18 of PERSISTENT1.
|
||||
* See dualboot-imx233.c in firmware/ for more explanation */
|
||||
HW_RTC_PERSISTENT1_CLR = 1 << 18;
|
||||
}
|
||||
|
||||
int main(uint32_t arg, uint32_t *result_id)
|
||||
{
|
||||
if(arg == BOOT_ARG_CHARGE)
|
||||
do_charge();
|
||||
/* tell rockbox that we can handle boot mode */
|
||||
imx233_dualboot_set_field(DUALBOOT_CAP_BOOT, 1);
|
||||
/* if we were asked to boot in a special mode, do so */
|
||||
unsigned boot_mode = imx233_dualboot_get_field(DUALBOOT_BOOT);
|
||||
/* clear boot mode to avoid any loop */
|
||||
imx233_dualboot_set_field(DUALBOOT_BOOT, IMX233_BOOT_NORMAL);
|
||||
switch(boot_mode)
|
||||
{
|
||||
case IMX233_BOOT_UPDATER:
|
||||
set_updater_bits();
|
||||
/* fallthrough */
|
||||
case IMX233_BOOT_OF:
|
||||
/* continue booting */
|
||||
return BOOT_ROM_CONTINUE;
|
||||
case IMX233_BOOT_NORMAL:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* normal boot */
|
||||
switch(boot_decision(get_context()))
|
||||
{
|
||||
case BOOT_ROCK:
|
||||
*result_id = arg;
|
||||
return BOOT_ROM_SECTION;
|
||||
case BOOT_OF:
|
||||
return BOOT_ROM_CONTINUE;
|
||||
case BOOT_STOP:
|
||||
default:
|
||||
power_down();
|
||||
}
|
||||
}
|
||||
|
||||
int __attribute__((section(".start"))) start(uint32_t arg, uint32_t *result_id)
|
||||
{
|
||||
return main(arg, result_id);
|
||||
}
|
||||
17
utils/mkimxboot/dualboot/dualboot.lds
Normal file
17
utils/mkimxboot/dualboot/dualboot.lds
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
ENTRY(start)
|
||||
OUTPUT_FORMAT(elf32-littlearm)
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
OCRAM : ORIGIN = 0, LENGTH = 0x8000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text 0 :
|
||||
{
|
||||
*(.start*)
|
||||
*(.text*)
|
||||
} > OCRAM
|
||||
}
|
||||
289
utils/mkimxboot/main.c
Normal file
289
utils/mkimxboot/main.c
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2011 by Amaury Pouly
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "mkimxboot.h"
|
||||
|
||||
struct imx_variant_t
|
||||
{
|
||||
const char *name;
|
||||
enum imx_firmware_variant_t variant;
|
||||
};
|
||||
|
||||
static struct imx_variant_t imx_variants[] =
|
||||
{
|
||||
{ "default", VARIANT_DEFAULT },
|
||||
{ "zenxfi2-recovery", VARIANT_ZENXFI2_RECOVERY },
|
||||
{ "zenxfi2-nand", VARIANT_ZENXFI2_NAND },
|
||||
{ "zenxfi2-sd", VARIANT_ZENXFI2_SD },
|
||||
{ "zenxfistyle-recovery", VARIANT_ZENXFISTYLE_RECOVERY },
|
||||
{ "zenstyle-recovery", VARIANT_ZENSTYLE_RECOVERY },
|
||||
};
|
||||
|
||||
#define NR_VARIANTS sizeof(imx_variants) / sizeof(imx_variants[0])
|
||||
|
||||
struct model_t
|
||||
{
|
||||
const char *name;
|
||||
enum imx_model_t model;
|
||||
};
|
||||
|
||||
struct model_t imx_models[] =
|
||||
{
|
||||
{ "unknown", MODEL_UNKNOWN },
|
||||
{ "fuzeplus", MODEL_FUZEPLUS },
|
||||
{ "zenxfi2", MODEL_ZENXFI2 },
|
||||
{ "zenxfi3", MODEL_ZENXFI3 },
|
||||
{ "zenxfistyle", MODEL_ZENXFISTYLE },
|
||||
{ "zenstyle", MODEL_ZENSTYLE },
|
||||
{ "nwze370", MODEL_NWZE370 },
|
||||
{ "nwze360", MODEL_NWZE360 },
|
||||
};
|
||||
|
||||
#define NR_MODELS sizeof(imx_models) / sizeof(imx_models[0])
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: mkimxboot [options | file]...\n");
|
||||
printf("Options:\n");
|
||||
printf(" -?/--help Display this message\n");
|
||||
printf(" -o <file> Set output file\n");
|
||||
printf(" -i <file> Set input file\n");
|
||||
printf(" -b <file> Set boot file\n");
|
||||
printf(" -d/--debug Enable debug output\n");
|
||||
printf(" -t <type> Set type (dualboot, singleboot, recovery, origfw, charge)\n");
|
||||
printf(" -v <v> Set variant\n");
|
||||
printf(" -x Dump device informations\n");
|
||||
printf(" -p <ver> Force product and component version\n");
|
||||
printf(" -5 <type> Compute <type> MD5 sum of the input file\n");
|
||||
printf(" -m <model> Specify model (useful for soft MD5 sum)\n");
|
||||
printf("Supported variants: (default is standard)\n");
|
||||
printf(" ");
|
||||
for(size_t i = 0; i < NR_VARIANTS; i++)
|
||||
{
|
||||
if(i != 0)
|
||||
printf(", ");
|
||||
printf("%s", imx_variants[i].name);
|
||||
}
|
||||
printf("\n");
|
||||
printf("Supported models: (default is unknown)\n");
|
||||
for(size_t i = 0; i < NR_MODELS; i++)
|
||||
{
|
||||
if(i != 0)
|
||||
printf(", ");
|
||||
printf("%s", imx_models[i].name);
|
||||
}
|
||||
printf("\n");
|
||||
printf("By default a dualboot image is built\n");
|
||||
printf("This tools supports the following format for the boot file:\n");
|
||||
printf("- rockbox scramble format\n");
|
||||
printf("- elf format\n");
|
||||
printf("Additional checks will be performed on rockbox scramble format to\n");
|
||||
printf("ensure soundness of operation.\n");
|
||||
printf("There are two types of MD5 sums: 'full' or 'soft'.\n");
|
||||
printf("- full MD5 sum applies to the whole file\n");
|
||||
printf("- soft MD5 sum for SB files accounts for relevant parts only\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int print_md5(const char *file, const char *type)
|
||||
{
|
||||
uint8_t md5sum[16];
|
||||
enum imx_error_t err;
|
||||
if(strcmp(type, "full") == 0)
|
||||
err = compute_md5sum(file, md5sum);
|
||||
else if(strcmp(type, "soft") == 0)
|
||||
err = compute_soft_md5sum(file, md5sum);
|
||||
else
|
||||
{
|
||||
printf("Invalid md5sum type '%s'\n", type);
|
||||
return 1;
|
||||
}
|
||||
if(err != IMX_SUCCESS)
|
||||
{
|
||||
printf("There was an error when computing the MD5 sum: %d\n", err);
|
||||
return 2;
|
||||
}
|
||||
printf("%s MD5 sum: ", type);
|
||||
for(int i = 0; i < 16; i++)
|
||||
printf("%02x", md5sum[i]);
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *infile = NULL;
|
||||
char *outfile = NULL;
|
||||
char *bootfile = NULL;
|
||||
enum imx_firmware_variant_t variant = VARIANT_DEFAULT;
|
||||
enum imx_output_type_t type = IMX_DUALBOOT;
|
||||
enum imx_model_t model = MODEL_UNKNOWN;
|
||||
bool debug = false;
|
||||
const char *md5type = NULL;
|
||||
const char *force_version = NULL;
|
||||
|
||||
if(argc == 1)
|
||||
usage();
|
||||
|
||||
while(1)
|
||||
{
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"in-file", no_argument, 0, 'i'},
|
||||
{"out-file", required_argument, 0, 'o'},
|
||||
{"boot-file", required_argument, 0, 'b'},
|
||||
{"debug", no_argument, 0, 'd'},
|
||||
{"type", required_argument, 0, 't'},
|
||||
{"variant", required_argument, 0, 'v'},
|
||||
{"dev-info", no_argument, 0, 'x'},
|
||||
{"model", required_argument, 0, 'm'},
|
||||
{"md5", required_argument, 0, '5'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
int c = getopt_long(argc, argv, "hdi:o:b:t:v:xp:m:5:", long_options, NULL);
|
||||
if(c == -1)
|
||||
break;
|
||||
switch(c)
|
||||
{
|
||||
case 'd':
|
||||
debug = true;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
case 'o':
|
||||
outfile = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
infile = optarg;
|
||||
break;
|
||||
case 'b':
|
||||
bootfile = optarg;
|
||||
break;
|
||||
case 't':
|
||||
if(strcmp(optarg, "dualboot") == 0)
|
||||
type = IMX_DUALBOOT;
|
||||
else if(strcmp(optarg, "singleboot") == 0)
|
||||
type = IMX_SINGLEBOOT;
|
||||
else if(strcmp(optarg, "recovery") == 0)
|
||||
type = IMX_RECOVERY;
|
||||
else if(strcmp(optarg, "charge") == 0)
|
||||
type = IMX_CHARGE;
|
||||
else if(strcmp(optarg, "origfw") == 0)
|
||||
type = IMX_ORIG_FW;
|
||||
else
|
||||
{
|
||||
printf("Invalid boot type '%s'\n", optarg);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
{
|
||||
for(size_t i = 0; i < NR_VARIANTS; i++)
|
||||
{
|
||||
if(strcmp(optarg, imx_variants[i].name) == 0)
|
||||
{
|
||||
variant = imx_variants[i].variant;
|
||||
goto Lok;
|
||||
}
|
||||
}
|
||||
printf("Invalid variant '%s'\n", optarg);
|
||||
return 1;
|
||||
|
||||
Lok:
|
||||
break;
|
||||
}
|
||||
case 'x':
|
||||
dump_imx_dev_info("");
|
||||
printf("variant mapping:\n");
|
||||
for(int i = 0; i < sizeof(imx_variants) / sizeof(imx_variants[0]); i++)
|
||||
printf(" %s -> variant=%d\n", imx_variants[i].name, imx_variants[i].variant);
|
||||
break;
|
||||
case 'p':
|
||||
force_version = optarg;
|
||||
break;
|
||||
case '5':
|
||||
md5type = optarg;
|
||||
break;
|
||||
case 'm':
|
||||
if(model != MODEL_UNKNOWN)
|
||||
{
|
||||
printf("You cannot specify two models\n");
|
||||
return 1;
|
||||
}
|
||||
for(int i = 0; i < NR_MODELS; i++)
|
||||
if(strcmp(optarg, imx_models[i].name) == 0)
|
||||
{
|
||||
model = imx_models[i].model;
|
||||
break;
|
||||
}
|
||||
if(model == MODEL_UNKNOWN)
|
||||
printf("Unknown model '%s'\n", optarg);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if(!infile)
|
||||
{
|
||||
printf("You must specify an input file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(md5type)
|
||||
return print_md5(infile, md5type);
|
||||
|
||||
if(!outfile)
|
||||
{
|
||||
printf("You must specify an output file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!bootfile && type != IMX_ORIG_FW)
|
||||
{
|
||||
printf("You must specify an boot file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(optind != argc)
|
||||
{
|
||||
printf("Extra arguments on command line\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct imx_option_t opt;
|
||||
memset(&opt, 0, sizeof(opt));
|
||||
opt.debug = debug;
|
||||
opt.output = type;
|
||||
opt.fw_variant = variant;
|
||||
opt.force_version = force_version;
|
||||
opt.model = model;
|
||||
enum imx_error_t err = mkimxboot(infile, bootfile, outfile, opt);
|
||||
printf("Result: %d (%s)\n", err, imx_error_to_string(err));
|
||||
return 0;
|
||||
}
|
||||
246
utils/mkimxboot/md5.c
Normal file
246
utils/mkimxboot/md5.c
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* RFC 1321 compliant MD5 implementation
|
||||
*
|
||||
* Copyright (C) 2001-2003 Christophe Devine
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
#define GET_UINT32(n,b,i) \
|
||||
{ \
|
||||
(n) = ( (uint32) (b)[(i) ] ) \
|
||||
| ( (uint32) (b)[(i) + 1] << 8 ) \
|
||||
| ( (uint32) (b)[(i) + 2] << 16 ) \
|
||||
| ( (uint32) (b)[(i) + 3] << 24 ); \
|
||||
}
|
||||
|
||||
#define PUT_UINT32(n,b,i) \
|
||||
{ \
|
||||
(b)[(i) ] = (uint8) ( (n) ); \
|
||||
(b)[(i) + 1] = (uint8) ( (n) >> 8 ); \
|
||||
(b)[(i) + 2] = (uint8) ( (n) >> 16 ); \
|
||||
(b)[(i) + 3] = (uint8) ( (n) >> 24 ); \
|
||||
}
|
||||
|
||||
void md5_starts( md5_context *ctx )
|
||||
{
|
||||
ctx->total[0] = 0;
|
||||
ctx->total[1] = 0;
|
||||
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xEFCDAB89;
|
||||
ctx->state[2] = 0x98BADCFE;
|
||||
ctx->state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
void md5_process( md5_context *ctx, uint8 data[64] )
|
||||
{
|
||||
uint32 X[16], A, B, C, D;
|
||||
|
||||
GET_UINT32( X[0], data, 0 );
|
||||
GET_UINT32( X[1], data, 4 );
|
||||
GET_UINT32( X[2], data, 8 );
|
||||
GET_UINT32( X[3], data, 12 );
|
||||
GET_UINT32( X[4], data, 16 );
|
||||
GET_UINT32( X[5], data, 20 );
|
||||
GET_UINT32( X[6], data, 24 );
|
||||
GET_UINT32( X[7], data, 28 );
|
||||
GET_UINT32( X[8], data, 32 );
|
||||
GET_UINT32( X[9], data, 36 );
|
||||
GET_UINT32( X[10], data, 40 );
|
||||
GET_UINT32( X[11], data, 44 );
|
||||
GET_UINT32( X[12], data, 48 );
|
||||
GET_UINT32( X[13], data, 52 );
|
||||
GET_UINT32( X[14], data, 56 );
|
||||
GET_UINT32( X[15], data, 60 );
|
||||
|
||||
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
|
||||
|
||||
#define P(a,b,c,d,k,s,t) \
|
||||
{ \
|
||||
a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
|
||||
}
|
||||
|
||||
A = ctx->state[0];
|
||||
B = ctx->state[1];
|
||||
C = ctx->state[2];
|
||||
D = ctx->state[3];
|
||||
|
||||
#define F(x,y,z) (z ^ (x & (y ^ z)))
|
||||
|
||||
P( A, B, C, D, 0, 7, 0xD76AA478 );
|
||||
P( D, A, B, C, 1, 12, 0xE8C7B756 );
|
||||
P( C, D, A, B, 2, 17, 0x242070DB );
|
||||
P( B, C, D, A, 3, 22, 0xC1BDCEEE );
|
||||
P( A, B, C, D, 4, 7, 0xF57C0FAF );
|
||||
P( D, A, B, C, 5, 12, 0x4787C62A );
|
||||
P( C, D, A, B, 6, 17, 0xA8304613 );
|
||||
P( B, C, D, A, 7, 22, 0xFD469501 );
|
||||
P( A, B, C, D, 8, 7, 0x698098D8 );
|
||||
P( D, A, B, C, 9, 12, 0x8B44F7AF );
|
||||
P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
|
||||
P( B, C, D, A, 11, 22, 0x895CD7BE );
|
||||
P( A, B, C, D, 12, 7, 0x6B901122 );
|
||||
P( D, A, B, C, 13, 12, 0xFD987193 );
|
||||
P( C, D, A, B, 14, 17, 0xA679438E );
|
||||
P( B, C, D, A, 15, 22, 0x49B40821 );
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (y ^ (z & (x ^ y)))
|
||||
|
||||
P( A, B, C, D, 1, 5, 0xF61E2562 );
|
||||
P( D, A, B, C, 6, 9, 0xC040B340 );
|
||||
P( C, D, A, B, 11, 14, 0x265E5A51 );
|
||||
P( B, C, D, A, 0, 20, 0xE9B6C7AA );
|
||||
P( A, B, C, D, 5, 5, 0xD62F105D );
|
||||
P( D, A, B, C, 10, 9, 0x02441453 );
|
||||
P( C, D, A, B, 15, 14, 0xD8A1E681 );
|
||||
P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
|
||||
P( A, B, C, D, 9, 5, 0x21E1CDE6 );
|
||||
P( D, A, B, C, 14, 9, 0xC33707D6 );
|
||||
P( C, D, A, B, 3, 14, 0xF4D50D87 );
|
||||
P( B, C, D, A, 8, 20, 0x455A14ED );
|
||||
P( A, B, C, D, 13, 5, 0xA9E3E905 );
|
||||
P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
|
||||
P( C, D, A, B, 7, 14, 0x676F02D9 );
|
||||
P( B, C, D, A, 12, 20, 0x8D2A4C8A );
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (x ^ y ^ z)
|
||||
|
||||
P( A, B, C, D, 5, 4, 0xFFFA3942 );
|
||||
P( D, A, B, C, 8, 11, 0x8771F681 );
|
||||
P( C, D, A, B, 11, 16, 0x6D9D6122 );
|
||||
P( B, C, D, A, 14, 23, 0xFDE5380C );
|
||||
P( A, B, C, D, 1, 4, 0xA4BEEA44 );
|
||||
P( D, A, B, C, 4, 11, 0x4BDECFA9 );
|
||||
P( C, D, A, B, 7, 16, 0xF6BB4B60 );
|
||||
P( B, C, D, A, 10, 23, 0xBEBFBC70 );
|
||||
P( A, B, C, D, 13, 4, 0x289B7EC6 );
|
||||
P( D, A, B, C, 0, 11, 0xEAA127FA );
|
||||
P( C, D, A, B, 3, 16, 0xD4EF3085 );
|
||||
P( B, C, D, A, 6, 23, 0x04881D05 );
|
||||
P( A, B, C, D, 9, 4, 0xD9D4D039 );
|
||||
P( D, A, B, C, 12, 11, 0xE6DB99E5 );
|
||||
P( C, D, A, B, 15, 16, 0x1FA27CF8 );
|
||||
P( B, C, D, A, 2, 23, 0xC4AC5665 );
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (y ^ (x | ~z))
|
||||
|
||||
P( A, B, C, D, 0, 6, 0xF4292244 );
|
||||
P( D, A, B, C, 7, 10, 0x432AFF97 );
|
||||
P( C, D, A, B, 14, 15, 0xAB9423A7 );
|
||||
P( B, C, D, A, 5, 21, 0xFC93A039 );
|
||||
P( A, B, C, D, 12, 6, 0x655B59C3 );
|
||||
P( D, A, B, C, 3, 10, 0x8F0CCC92 );
|
||||
P( C, D, A, B, 10, 15, 0xFFEFF47D );
|
||||
P( B, C, D, A, 1, 21, 0x85845DD1 );
|
||||
P( A, B, C, D, 8, 6, 0x6FA87E4F );
|
||||
P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
|
||||
P( C, D, A, B, 6, 15, 0xA3014314 );
|
||||
P( B, C, D, A, 13, 21, 0x4E0811A1 );
|
||||
P( A, B, C, D, 4, 6, 0xF7537E82 );
|
||||
P( D, A, B, C, 11, 10, 0xBD3AF235 );
|
||||
P( C, D, A, B, 2, 15, 0x2AD7D2BB );
|
||||
P( B, C, D, A, 9, 21, 0xEB86D391 );
|
||||
|
||||
#undef F
|
||||
|
||||
ctx->state[0] += A;
|
||||
ctx->state[1] += B;
|
||||
ctx->state[2] += C;
|
||||
ctx->state[3] += D;
|
||||
}
|
||||
|
||||
void md5_update( md5_context *ctx, uint8 *input, uint32 length )
|
||||
{
|
||||
uint32 left, fill;
|
||||
|
||||
if( ! length ) return;
|
||||
|
||||
left = ctx->total[0] & 0x3F;
|
||||
fill = 64 - left;
|
||||
|
||||
ctx->total[0] += length;
|
||||
ctx->total[0] &= 0xFFFFFFFF;
|
||||
|
||||
if( ctx->total[0] < length )
|
||||
ctx->total[1]++;
|
||||
|
||||
if( left && length >= fill )
|
||||
{
|
||||
memcpy( (void *) (ctx->buffer + left),
|
||||
(void *) input, fill );
|
||||
md5_process( ctx, ctx->buffer );
|
||||
length -= fill;
|
||||
input += fill;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
while( length >= 64 )
|
||||
{
|
||||
md5_process( ctx, input );
|
||||
length -= 64;
|
||||
input += 64;
|
||||
}
|
||||
|
||||
if( length )
|
||||
{
|
||||
memcpy( (void *) (ctx->buffer + left),
|
||||
(void *) input, length );
|
||||
}
|
||||
}
|
||||
|
||||
static uint8 md5_padding[64] =
|
||||
{
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
void md5_finish( md5_context *ctx, uint8 digest[16] )
|
||||
{
|
||||
uint32 last, padn;
|
||||
uint32 high, low;
|
||||
uint8 msglen[8];
|
||||
|
||||
high = ( ctx->total[0] >> 29 )
|
||||
| ( ctx->total[1] << 3 );
|
||||
low = ( ctx->total[0] << 3 );
|
||||
|
||||
PUT_UINT32( low, msglen, 0 );
|
||||
PUT_UINT32( high, msglen, 4 );
|
||||
|
||||
last = ctx->total[0] & 0x3F;
|
||||
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
|
||||
|
||||
md5_update( ctx, md5_padding, padn );
|
||||
md5_update( ctx, msglen, 8 );
|
||||
|
||||
PUT_UINT32( ctx->state[0], digest, 0 );
|
||||
PUT_UINT32( ctx->state[1], digest, 4 );
|
||||
PUT_UINT32( ctx->state[2], digest, 8 );
|
||||
PUT_UINT32( ctx->state[3], digest, 12 );
|
||||
}
|
||||
|
||||
25
utils/mkimxboot/md5.h
Normal file
25
utils/mkimxboot/md5.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef _MD5_H
|
||||
#define _MD5_H
|
||||
|
||||
#ifndef uint8
|
||||
#define uint8 unsigned char
|
||||
#endif
|
||||
|
||||
#ifndef uint32
|
||||
#define uint32 unsigned long int
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32 total[2];
|
||||
uint32 state[4];
|
||||
uint8 buffer[64];
|
||||
}
|
||||
md5_context;
|
||||
|
||||
void md5_starts( md5_context *ctx );
|
||||
void md5_update( md5_context *ctx, uint8 *input, uint32 length );
|
||||
void md5_finish( md5_context *ctx, uint8 digest[16] );
|
||||
|
||||
#endif /* md5.h */
|
||||
|
||||
1123
utils/mkimxboot/mkimxboot.c
Normal file
1123
utils/mkimxboot/mkimxboot.c
Normal file
File diff suppressed because it is too large
Load diff
116
utils/mkimxboot/mkimxboot.h
Normal file
116
utils/mkimxboot/mkimxboot.h
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2011 by Amaury Pouly
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef MKIMXBOOT_H
|
||||
#define MKIMXBOOT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum imx_error_t
|
||||
{
|
||||
IMX_SUCCESS = 0,
|
||||
IMX_ERROR = -1,
|
||||
IMX_OPEN_ERROR = -2,
|
||||
IMX_READ_ERROR = -3,
|
||||
IMX_NO_MATCH = -4,
|
||||
IMX_BOOT_INVALID = -5,
|
||||
IMX_BOOT_MISMATCH = -6,
|
||||
IMX_BOOT_CHECKSUM_ERROR = -7,
|
||||
IMX_DONT_KNOW_HOW_TO_PATCH = -8,
|
||||
IMX_VARIANT_MISMATCH = -9,
|
||||
IMX_WRITE_ERROR = -10,
|
||||
IMX_FIRST_SB_ERROR = -11,
|
||||
IMX_MODEL_MISMATCH = -12,
|
||||
};
|
||||
|
||||
enum imx_output_type_t
|
||||
{
|
||||
IMX_DUALBOOT = 0,
|
||||
IMX_RECOVERY,
|
||||
IMX_SINGLEBOOT,
|
||||
IMX_CHARGE,
|
||||
IMX_ORIG_FW,
|
||||
};
|
||||
|
||||
/* Supported models */
|
||||
enum imx_model_t
|
||||
{
|
||||
MODEL_UNKNOWN = 0,
|
||||
MODEL_FUZEPLUS,
|
||||
MODEL_ZENXFI2,
|
||||
MODEL_ZENXFI3,
|
||||
MODEL_ZENXFISTYLE,
|
||||
MODEL_ZENSTYLE, /* Style 100 and Style 300 */
|
||||
MODEL_NWZE370,
|
||||
MODEL_NWZE360,
|
||||
/* Last */
|
||||
MODEL_COUNT
|
||||
};
|
||||
|
||||
/* Supported firmware variants */
|
||||
enum imx_firmware_variant_t
|
||||
{
|
||||
VARIANT_DEFAULT = 0,
|
||||
/* For the Creative ZEN X-Fi2 */
|
||||
VARIANT_ZENXFI2_NAND,
|
||||
VARIANT_ZENXFI2_SD,
|
||||
VARIANT_ZENXFI2_RECOVERY,
|
||||
/* For the Creative X-Fi Style */
|
||||
VARIANT_ZENXFISTYLE_RECOVERY,
|
||||
/* For the Creative Zen Style 100/300 */
|
||||
VARIANT_ZENSTYLE_RECOVERY,
|
||||
/* Last */
|
||||
VARIANT_COUNT
|
||||
};
|
||||
|
||||
struct imx_option_t
|
||||
{
|
||||
bool debug;
|
||||
enum imx_model_t model;
|
||||
enum imx_output_type_t output;
|
||||
enum imx_firmware_variant_t fw_variant;
|
||||
const char *force_version; // set to NULL to ignore
|
||||
};
|
||||
|
||||
/* Print internal information to stdout about device database */
|
||||
void dump_imx_dev_info(const char *prefix);
|
||||
/* Build a SB image from an input firmware and a bootloader, input firmware
|
||||
* can either be a firmware update or another SB file produced by this tool */
|
||||
enum imx_error_t mkimxboot(const char *infile, const char *bootfile,
|
||||
const char *outfile, struct imx_option_t opt);
|
||||
/* Compute MD5 sum of an entire file */
|
||||
enum imx_error_t compute_md5sum(const char *file, uint8_t file_md5sum[16]);
|
||||
/* Compute "soft" MD5 sum of a SB file */
|
||||
enum imx_error_t compute_soft_md5sum(const char *file, uint8_t soft_md5sum[16]);
|
||||
/* Translate error */
|
||||
const char *imx_error_to_string(enum imx_error_t err);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
23
utils/mkmpioboot/Makefile
Normal file
23
utils/mkmpioboot/Makefile
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
|
||||
TARGET_DIR ?= $(shell pwd)/
|
||||
# We use the UCL code available in the Rockbox tools/ directory
|
||||
CFLAGS += -I../../tools/ucl/include -Wall
|
||||
|
||||
OUTPUT = mkmpioboot
|
||||
|
||||
# inputs
|
||||
LIBSOURCES = mkmpioboot.c
|
||||
SOURCES = main.c
|
||||
EXTRADEPS = $(LIBUCL)
|
||||
|
||||
include ../libtools.make
|
||||
|
||||
# explicit dependencies
|
||||
$(OBJDIR)mkmpioboot.o: mkmpioboot.c mkmpioboot.h
|
||||
|
||||
55
utils/mkmpioboot/main.c
Normal file
55
utils/mkmpioboot/main.c
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id:$
|
||||
*
|
||||
* Copyright (C) 2010 by Marcin Bukat
|
||||
*
|
||||
* code taken mostly from mkboot.c
|
||||
* Copyright (C) 2005 by Linus Nielsen Feltzing
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "mkmpioboot.h"
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("usage: mkmpioboot <firmware file> <boot file> <output file>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *infile, *bootfile, *outfile;
|
||||
int origin = 0xe0000; /* MPIO HD200 bootloader address */
|
||||
|
||||
fprintf(stderr,
|
||||
"mkmpioboot Version " VERSION "\n"
|
||||
"This is free software; see the source for copying conditions. There is NO\n"
|
||||
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
|
||||
"\n");
|
||||
|
||||
if(argc < 3) {
|
||||
usage();
|
||||
}
|
||||
|
||||
infile = argv[1];
|
||||
bootfile = argv[2];
|
||||
outfile = argv[3];
|
||||
|
||||
return mkmpioboot(infile, bootfile, outfile, origin);
|
||||
}
|
||||
243
utils/mkmpioboot/mkmpioboot.c
Normal file
243
utils/mkmpioboot/mkmpioboot.c
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id:$
|
||||
*
|
||||
* Copyright (C) 2010 by Marcin Bukat
|
||||
*
|
||||
* code taken mostly from mkboot.c
|
||||
* Copyright (C) 2005 by Linus Nielsen Feltzing
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "mkmpioboot.h"
|
||||
|
||||
#define OF_FIRMWARE_LEN 0x100000 /* size of the OF file */
|
||||
#define MPIO_STRING_OFFSET 0xfffe0 /* offset of the version string in OF */
|
||||
#define BOOTLOADER_MAX_SIZE 0x1f800 /* free space size */
|
||||
|
||||
struct mpio_model {
|
||||
/* Descriptive name of this model */
|
||||
const char* model_name;
|
||||
/* Model name used in the Rockbox header in ".mpio" files - these match the
|
||||
-add parameter to the "scramble" tool */
|
||||
const char* rb_model_name;
|
||||
/* Model number used to initialise the checksum in the Rockbox header in
|
||||
".mpio" files - these are the same as MODEL_NUMBER in config-target.h */
|
||||
const int rb_model_num;
|
||||
/* Strings which indentifies OF version */
|
||||
const char* of_model_string;
|
||||
};
|
||||
|
||||
static const struct mpio_model mpio_models[] = {
|
||||
[MODEL_HD200] =
|
||||
{ "MPIO HD200", "hd20", 69, "HD200 HDD Audio Ver113005" },
|
||||
[MODEL_HD300] =
|
||||
{ "MPIO HD300", "hd30", 70, "HD300 HDD Audio Ver113006" },
|
||||
};
|
||||
|
||||
|
||||
/* MPIO HD200 and HD300 firmware is plain binary image
|
||||
* 4 bytes of initial SP (loaded on reset)
|
||||
* 4 bytes of initial PC (loaded on reset)
|
||||
* binary image with entry point 0x00000008
|
||||
*
|
||||
* We put our bootloader code at 0x000e0000
|
||||
* and patch reset vector to jump directly
|
||||
* into our code on reset
|
||||
*/
|
||||
|
||||
static unsigned char image[OF_FIRMWARE_LEN];
|
||||
|
||||
static unsigned int get_uint32be(unsigned char* p)
|
||||
{
|
||||
return ((p[0] << 24) | (p[1] << 16) | (p[2]<<8) | p[3]);
|
||||
}
|
||||
|
||||
static long checksum(unsigned char* buf, int model, unsigned long length)
|
||||
{
|
||||
unsigned long chksum = model;
|
||||
unsigned long i;
|
||||
|
||||
if(buf == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
chksum += *buf++;
|
||||
}
|
||||
|
||||
return chksum;
|
||||
}
|
||||
|
||||
int mkmpioboot(const char* infile, const char* bootfile, const char* outfile, int origin)
|
||||
{
|
||||
FILE *f;
|
||||
int i;
|
||||
int len;
|
||||
int model_index;
|
||||
unsigned long file_checksum;
|
||||
unsigned char header[8];
|
||||
|
||||
memset(image, 0xff, sizeof(image));
|
||||
|
||||
/* First, read the mpio original firmware into the image */
|
||||
f = fopen(infile, "rb");
|
||||
if(!f)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Can not open %s file for reading\n", infile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
i = fread(image, 1, OF_FIRMWARE_LEN, f);
|
||||
if(i < OF_FIRMWARE_LEN)
|
||||
{
|
||||
fprintf(stderr, "[ERR] %s file read error\n", infile);
|
||||
fclose(f);
|
||||
return -2;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
/* Now check if we have OF file loaded based on presence
|
||||
* of the version string in firmware
|
||||
*/
|
||||
|
||||
for(model_index = 0; model_index < NUM_MODELS; model_index++)
|
||||
if (strcmp(mpio_models[model_index].of_model_string,
|
||||
(char*)(image + MPIO_STRING_OFFSET)) == 0)
|
||||
break;
|
||||
|
||||
if(model_index == NUM_MODELS)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Unknown MPIO original firmware version\n");
|
||||
return -3;
|
||||
}
|
||||
|
||||
fprintf(stderr, "[INFO] Loading original firmware file for %s\n",
|
||||
mpio_models[model_index].model_name);
|
||||
|
||||
/* Now, read the boot loader into the image */
|
||||
f = fopen(bootfile, "rb");
|
||||
if(!f)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Can not open %s file for reading\n", bootfile);
|
||||
return -4;
|
||||
}
|
||||
|
||||
fprintf(stderr, "[INFO] Loading Rockbox bootloader file\n");
|
||||
|
||||
/* get bootloader size
|
||||
* excluding header
|
||||
*/
|
||||
fseek(f, 0, SEEK_END);
|
||||
len = ftell(f) - 8;
|
||||
|
||||
if (len > BOOTLOADER_MAX_SIZE)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Bootloader doesn't fit in firmware file.\n");
|
||||
fprintf(stderr, "[ERR] This bootloader is %d bytes long\n", len);
|
||||
fprintf(stderr, "[ERR] and maximum allowed size is %d bytes\n",
|
||||
BOOTLOADER_MAX_SIZE);
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* Now check if the place we want to put
|
||||
* our bootloader is free
|
||||
*/
|
||||
for(i=0;i<len;i++)
|
||||
{
|
||||
if (image[origin+i] != 0)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Place for bootloader in OF file not empty\n");
|
||||
return -6;
|
||||
}
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
/* get bootloader header*/
|
||||
fread(header,1,8,f);
|
||||
|
||||
if ( memcmp(header + 4, mpio_models[model_index].rb_model_name, 4) != 0 )
|
||||
{
|
||||
fprintf(stderr, "[ERR] Original firmware and rockbox bootloader mismatch!\n");
|
||||
fprintf(stderr, "[ERR] Double check that you have bootloader for %s\n",
|
||||
mpio_models[model_index].model_name);
|
||||
return -7;
|
||||
}
|
||||
|
||||
/* omit header */
|
||||
fseek(f, 8, SEEK_SET);
|
||||
|
||||
i = fread(image + origin, 1, len, f);
|
||||
if(i < len)
|
||||
{
|
||||
fprintf(stderr, "[ERR] %s file read error\n", bootfile);
|
||||
fclose(f);
|
||||
return -8;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
/* calculate checksum and compare with data
|
||||
* from header
|
||||
*/
|
||||
file_checksum = checksum(image + origin, mpio_models[model_index].rb_model_num, len);
|
||||
|
||||
if ( file_checksum != get_uint32be(header) )
|
||||
{
|
||||
fprintf(stderr,"[ERR] Bootloader checksum error\n");
|
||||
return -9;
|
||||
}
|
||||
|
||||
f = fopen(outfile, "wb");
|
||||
if(!f)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Can not open %s file for writing\n" ,outfile);
|
||||
return -10;
|
||||
}
|
||||
|
||||
fprintf(stderr, "[INFO] Patching reset vector\n");
|
||||
|
||||
/* Patch the stack pointer address */
|
||||
image[0] = image[origin + 0];
|
||||
image[1] = image[origin + 1];
|
||||
image[2] = image[origin + 2];
|
||||
image[3] = image[origin + 3];
|
||||
|
||||
/* Patch the reset vector to start the boot loader */
|
||||
image[4] = image[origin + 4];
|
||||
image[5] = image[origin + 5];
|
||||
image[6] = image[origin + 6];
|
||||
image[7] = image[origin + 7];
|
||||
|
||||
i = fwrite(image, 1, OF_FIRMWARE_LEN, f);
|
||||
if(i < OF_FIRMWARE_LEN)
|
||||
{
|
||||
fprintf(stderr,"[ERR] %s file write error\n", outfile);
|
||||
fclose(f);
|
||||
return -11;
|
||||
}
|
||||
|
||||
fprintf(stderr,"[INFO] Wrote 0x%x bytes in %s\n", OF_FIRMWARE_LEN, outfile);
|
||||
fprintf(stderr,"[INFO] Patching succeeded!\n");
|
||||
|
||||
fclose(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
46
utils/mkmpioboot/mkmpioboot.h
Normal file
46
utils/mkmpioboot/mkmpioboot.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id:$
|
||||
*
|
||||
* Copyright (C) 2010 by Marcin Bukat
|
||||
* code based mainly on mkboot.h
|
||||
* Copyright (C) 2008 by Dominik Riebeling
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef MKMPIOBOOT_H
|
||||
#define MKMPIOBOOT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Supported models */
|
||||
enum {
|
||||
MODEL_UNKNOWN = -1,
|
||||
MODEL_HD200 = 0,
|
||||
MODEL_HD300,
|
||||
|
||||
NUM_MODELS
|
||||
};
|
||||
|
||||
int mkmpioboot(const char* infile, const char* bootfile, const char* outfile, int origin);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
52
utils/mknwzboot/Makefile
Normal file
52
utils/mknwzboot/Makefile
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
|
||||
# We use the SB code available in the Rockbox utils/sbtools directory
|
||||
UPGTOOLS_DIR=../../utils/nwztools/upgtools/
|
||||
CFLAGS += -I$(UPGTOOLS_DIR) -Wall
|
||||
# std=gnu99 is required by MinGW on Windows (c99 is sufficient for Linux / MXE)
|
||||
CFLAGS += -std=gnu99 -g -O3
|
||||
# dependencies
|
||||
# FIXME make it work for windows and maybe embed crypto++
|
||||
|
||||
# Location to pkg-config binary.
|
||||
PKGCONFIG := pkg-config
|
||||
|
||||
# Distros could use different names for the crypto library. We try a list
|
||||
# of candidate names, only one of them should be the valid one.
|
||||
LIBCRYPTO_NAMES = libcryptopp libcrypto++ cryptopp crypto++
|
||||
|
||||
$(foreach l,$(LIBCRYPTO_NAMES),\
|
||||
$(eval LDOPTS += $(shell $(PKGCONFIG) --silence-errors --libs $(l))))
|
||||
$(foreach l,$(LIBCRYPTO_NAMES),\
|
||||
$(eval CFLAGS += $(shell $(PKGCONFIG) --silence-errors --cflags $(l))))
|
||||
$(foreach l,$(LIBCRYPTO_NAMES),\
|
||||
$(eval CXXFLAGS += $(shell $(PKGCONFIG) --silence-errors --cflags $(l))))
|
||||
LDOPTS += -lpthread
|
||||
|
||||
OUTPUT = mknwzboot
|
||||
|
||||
# inputs for lib
|
||||
UPGTOOLS_SOURCES = misc.c upg.c fwp.c mg.cpp md5.cpp
|
||||
LIBSOURCES := mknwzboot.c install_script.c uninstall_script.c \
|
||||
$(addprefix $(UPGTOOLS_DIR),$(UPGTOOLS_SOURCES))
|
||||
# inputs for binary only
|
||||
SOURCES := $(LIBSOURCES) main.c
|
||||
# dependencies for binary
|
||||
EXTRADEPS :=
|
||||
|
||||
include ../libtools.make
|
||||
|
||||
install_script.c install_script.h: install_script.sh $(BIN2C)
|
||||
$(BIN2C) install_script.sh install_script
|
||||
|
||||
uninstall_script.c uninstall_script.h: uninstall_script.sh $(BIN2C)
|
||||
$(BIN2C) uninstall_script.sh uninstall_script
|
||||
|
||||
# explicit dependencies on install_script.{c,h} and mknwzboot.h
|
||||
$(OBJDIR)mknwzboot.o: install_script.h install_script.c uninstall_script.h uninstall_script.c mknwzboot.h
|
||||
$(OBJDIR)main.o: main.c mknwzboot.h
|
||||
157
utils/mknwzboot/install_script.sh
Normal file
157
utils/mknwzboot/install_script.sh
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
#!/bin/sh
|
||||
|
||||
# NOTE: busybox is using ash, a very posix and very pedantic shell, make sure
|
||||
# you test your scripts with
|
||||
# busybox sh -n <script>
|
||||
# and if you really, really don't want to download busybox to try it, then go
|
||||
# ahead and brick your device
|
||||
|
||||
# The updater script on the NWZ has a major bug/feature:
|
||||
# it does NOT clear the update flag if the update scrit fails
|
||||
# thus causing a update/reboot loop and a bricked device
|
||||
# always clear to make sure we don't end up being screwed
|
||||
nvpflag fup 0xFFFFFFFF
|
||||
|
||||
# go to /tmp
|
||||
cd /tmp
|
||||
|
||||
# get content partition path
|
||||
CONTENTS="/contents"
|
||||
CONTENTS_PART=`mount | grep contents | awk '{ print $1 }'`
|
||||
|
||||
# print a message to the screen and also on the standard output
|
||||
# lcdprint x,y msg
|
||||
lcdprint ()
|
||||
{
|
||||
echo $2
|
||||
lcdmsg -f /usr/local/bin/font_08x12.bmp -l $1 "$2"
|
||||
}
|
||||
|
||||
# clear screen
|
||||
lcdmsg -c ""
|
||||
lcdprint 0,3 "Contents partition:\n$CONTENTS_PART"
|
||||
|
||||
# We need to remount the contents partition in read-write mode be able to
|
||||
# write something on it
|
||||
lcdprint 0,6 "Remount $CONTENTS rw"
|
||||
mount -o remount,rw $CONTENTS_PART $CONTENTS
|
||||
if [ "$?" != 0 ]; then
|
||||
lcdprint 0,15 "ERROR: remount failed"
|
||||
sleep 3
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# redirect all output to a log file
|
||||
exec > "$CONTENTS/install_dualboot_log.txt" 2>&1
|
||||
|
||||
# import constants
|
||||
. /install_script/constant.txt
|
||||
_UPDATE_FN_=`nvpstr ufn`
|
||||
ROOTFS_TMP_DIR=/tmp/rootfs
|
||||
SPIDERAPP_PATH=$ROOTFS_TMP_DIR/usr/local/bin/SpiderApp
|
||||
|
||||
# mount root partition
|
||||
lcdprint 0,7 "Mount root filesystem"
|
||||
mkdir $ROOTFS_TMP_DIR
|
||||
if [ "$?" != 0 ]; then
|
||||
lcdprint 0,15 "ERROR: mkdir failed"
|
||||
sleep 3
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# If there is an ext4 mounter, try it. Otherwise or on failure, try ext3 and
|
||||
# then ext2.
|
||||
# NOTE some platforms probably use an mtd and this might need some fixing
|
||||
if [ -e /usr/local/bin/icx_mount.ext4 ]; then
|
||||
/usr/local/bin/icx_mount.ext4 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
|
||||
else
|
||||
false
|
||||
fi
|
||||
if [ "$?" != 0 ]; then
|
||||
mount -t ext3 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
|
||||
fi
|
||||
if [ "$?" != 0 ]; then
|
||||
mount -t ext2 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
|
||||
fi
|
||||
if [ "$?" != 0 ]; then
|
||||
lcdprint 0,15 "ERROR: mount failed"
|
||||
sleep 3
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# rename the previous main application unless there is already a copy
|
||||
lcdprint 0,8 "Backup OF"
|
||||
if [ ! -e $SPIDERAPP_PATH.of ]; then
|
||||
mv $SPIDERAPP_PATH $SPIDERAPP_PATH.of
|
||||
fi
|
||||
|
||||
# extract our payload: the second file in the upgrade is a tar file
|
||||
# the files in the archive have paths of the form ./absolute/path and we extract
|
||||
# it at the rootfs mount it, so it can create/overwrite any file
|
||||
#
|
||||
# we need a small trick here: we want to pipe directly the output of the decryption
|
||||
# tool to tar, to avoid using space in /tmp/ or on the user partition
|
||||
lcdprint 0,9 "Install rockbox"
|
||||
FIFO_FILE=/tmp/rb.fifo
|
||||
mkfifo $FIFO_FILE
|
||||
if [ "$?" != 0 ]; then
|
||||
umount "$ROOTFS_TMP_DIR"
|
||||
lcdprint 0,15 "ERROR: cannot create fifo"
|
||||
sleep 3
|
||||
exit 0
|
||||
fi
|
||||
fwpchk -f /contents/$_UPDATE_FN_.UPG -c -1 $FIFO_FILE &
|
||||
#tar -tvf $FIFO_FILE
|
||||
tar -C $ROOTFS_TMP_DIR -xvf $FIFO_FILE
|
||||
if [ "$?" != 0 ]; then
|
||||
umount "$ROOTFS_TMP_DIR"
|
||||
lcdprint 0,15 "ERROR: extraction failed"
|
||||
sleep 3
|
||||
exit 0
|
||||
fi
|
||||
# wait for fwpchk
|
||||
wait
|
||||
if [ "$?" != 0 ]; then
|
||||
umount "$ROOTFS_TMP_DIR"
|
||||
lcdprint 0,15 "ERROR: no file to extract"
|
||||
sleep 3
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# create a symlink from /.rockbox to /contents/.rockbox (see dualboot code
|
||||
# for why)
|
||||
lcdprint 0,10 "Create rockbox symlink"
|
||||
rm -f "$ROOTFS_TMP_DIR/.rockbox"
|
||||
ln -s "$CONTENTS/.rockbox" "$ROOTFS_TMP_DIR/.rockbox"
|
||||
if [ "$?" != 0 ]; then
|
||||
umount "$ROOTFS_TMP_DIR"
|
||||
lcdprint 0,15 "ERROR: cannot create rockbox symlink"
|
||||
sleep 3
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# unmount root partition
|
||||
lcdprint 0,11 "Unmount root filesystem"
|
||||
sync
|
||||
if [ "$?" != 0 ]; then
|
||||
umount "$ROOTFS_TMP_DIR"
|
||||
lcdprint 0,15 "ERROR: sync failed"
|
||||
sleep 3
|
||||
exit 0
|
||||
fi
|
||||
|
||||
umount $ROOTFS_TMP_DIR
|
||||
if [ "$?" != 0 ]; then
|
||||
lcdprint 0,15 "ERROR: umount failed"
|
||||
sleep 3
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Success screen
|
||||
lcdprint 0,15 "Rebooting in 3 seconds."
|
||||
sleep 3
|
||||
sync
|
||||
|
||||
echo "Installation successful"
|
||||
# finish
|
||||
exit 0
|
||||
126
utils/mknwzboot/main.c
Normal file
126
utils/mknwzboot/main.c
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2011 by Amaury Pouly
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "mknwzboot.h"
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: mknwzboot [options | file]...\n");
|
||||
printf("Options:\n");
|
||||
printf(" -h/--help Display this message\n");
|
||||
printf(" -o <file> Set output file\n");
|
||||
printf(" -b <file> Set boot file\n");
|
||||
printf(" -d/--debug Enable debug output\n");
|
||||
printf(" -x Dump device informations\n");
|
||||
printf(" -u Create uninstall update\n");
|
||||
printf(" -m <model> Specify model\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *outfile = NULL;
|
||||
char *bootfile = NULL;
|
||||
bool debug = false;
|
||||
bool install = true;
|
||||
const char *model = NULL;
|
||||
|
||||
if(argc == 1)
|
||||
usage();
|
||||
|
||||
while(1)
|
||||
{
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"out-file", required_argument, 0, 'o'},
|
||||
{"boot-file", required_argument, 0, 'b'},
|
||||
{"debug", no_argument, 0, 'd'},
|
||||
{"dev-info", no_argument, 0, 'x'},
|
||||
{"uninstall", no_argument, 0, 'u'},
|
||||
{"model", required_argument, 0, 'm'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
int c = getopt_long(argc, argv, "ho:b:dxum:", long_options, NULL);
|
||||
if(c == -1)
|
||||
break;
|
||||
switch(c)
|
||||
{
|
||||
case 'd':
|
||||
debug = true;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
case 'o':
|
||||
outfile = optarg;
|
||||
break;
|
||||
case 'b':
|
||||
bootfile = optarg;
|
||||
break;
|
||||
case 'x':
|
||||
dump_nwz_dev_info("");
|
||||
return 0;
|
||||
case 'u':
|
||||
install = false;
|
||||
break;
|
||||
case 'm':
|
||||
model = optarg;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if(!outfile)
|
||||
{
|
||||
printf("You must specify an output file\n");
|
||||
return 1;
|
||||
}
|
||||
if(install && !bootfile)
|
||||
{
|
||||
printf("You must specify a boot file for installation\n");
|
||||
return 1;
|
||||
}
|
||||
if(!install && !model)
|
||||
{
|
||||
printf("You must provide a model for uninstallation\n");
|
||||
return 1;
|
||||
}
|
||||
if(optind != argc)
|
||||
{
|
||||
printf("Extra arguments on command line\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int err;
|
||||
if(install)
|
||||
err = mknwzboot(bootfile, outfile, debug);
|
||||
else
|
||||
err = mknwzboot_uninst(model, outfile, debug);
|
||||
printf("Result: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
294
utils/mknwzboot/mknwzboot.c
Normal file
294
utils/mknwzboot/mknwzboot.c
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2011 by Amaury Pouly
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "mknwzboot.h"
|
||||
#include "upg.h"
|
||||
|
||||
#include "install_script.h"
|
||||
#include "uninstall_script.h"
|
||||
|
||||
struct nwz_model_desc_t
|
||||
{
|
||||
/* Descriptive name of this model */
|
||||
const char *model_name;
|
||||
/* Model name used in the Rockbox header in ".sansa" files - these match the
|
||||
-add parameter to the "scramble" tool */
|
||||
const char *rb_model_name;
|
||||
/* Model number used to initialise the checksum in the Rockbox header in
|
||||
".sansa" files - these are the same as MODEL_NUMBER in config-target.h */
|
||||
const int rb_model_num;
|
||||
/* Codename used in upgtool */
|
||||
const char *codename;
|
||||
};
|
||||
|
||||
static const struct nwz_model_desc_t nwz_models[] =
|
||||
{
|
||||
{ "Sony NWZ-E350 Series", "e350", 109, "nwz-e350" },
|
||||
{ "Sony NWZ-E450 Series", "e450", 100, "nwz-e450" },
|
||||
{ "Sony NWZ-E460 Series", "e460", 101, "nwz-e460" },
|
||||
{ "Sony NWZ-E470 Series", "e470", 103, "nwz-e470" },
|
||||
{ "Sony NWZ-E580 Series", "e580", 102, "nwz-e580" },
|
||||
{ "Sony NWZ-A10 Series", "a10", 104, "nwz-a10" },
|
||||
{ "Sony NW-A20 Series", "a20", 106, "nw-a20" },
|
||||
{ "Sony NWZ-A860 Series", "a860", 107, "nwz-a860" },
|
||||
{ "Sony NWZ-S750 Series", "s750", 108, "nwz-s750" },
|
||||
};
|
||||
|
||||
#define NR_NWZ_MODELS (sizeof(nwz_models) / sizeof(nwz_models[0]))
|
||||
|
||||
void dump_nwz_dev_info(const char *prefix)
|
||||
{
|
||||
printf("%smknwzboot models:\n", prefix);
|
||||
for(int i = 0; i < NR_NWZ_MODELS; i++)
|
||||
{
|
||||
printf("%s %s: rb_model=%s rb_num=%d codename=%s\n", prefix,
|
||||
nwz_models[i].model_name, nwz_models[i].rb_model_name,
|
||||
nwz_models[i].rb_model_num, nwz_models[i].codename);
|
||||
}
|
||||
}
|
||||
|
||||
/* read a file to a buffer */
|
||||
static void *read_file(const char *file, size_t *size)
|
||||
{
|
||||
FILE *f = fopen(file, "rb");
|
||||
if(f == NULL)
|
||||
{
|
||||
printf("[ERR] Cannot open file '%s' for reading: %m\n", file);
|
||||
return NULL;
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
*size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
void *buffer = malloc(*size);
|
||||
if(fread(buffer, *size, 1, f) != 1)
|
||||
{
|
||||
free(buffer);
|
||||
fclose(f);
|
||||
printf("[ERR] Cannot read file '%s': %m\n", file);
|
||||
return NULL;
|
||||
}
|
||||
fclose(f);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* write a file from a buffer */
|
||||
static bool write_file(const char *file, void *buffer, size_t size)
|
||||
{
|
||||
FILE *f = fopen(file, "wb");
|
||||
if(f == NULL)
|
||||
{
|
||||
printf("[ERR] Cannot open file '%s' for writing: %m\n", file);
|
||||
return false;
|
||||
}
|
||||
if(fwrite(buffer, size, 1, f) != 1)
|
||||
{
|
||||
fclose(f);
|
||||
printf("[ERR] Cannot write file '%s': %m\n", file);
|
||||
return false;
|
||||
}
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned int be2int(unsigned char* buf)
|
||||
{
|
||||
return ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
|
||||
}
|
||||
|
||||
static int find_model(uint8_t *boot, size_t boot_size)
|
||||
{
|
||||
if(boot_size < 8)
|
||||
{
|
||||
printf("[ERR] Boot file is too small to be valid\n");
|
||||
return -1;
|
||||
}
|
||||
/* find model by comparing magic scramble value */
|
||||
int model = 0;
|
||||
for(; model < NR_NWZ_MODELS; model++)
|
||||
if(memcmp(boot + 4, nwz_models[model].rb_model_name, 4) == 0)
|
||||
break;
|
||||
if(model == NR_NWZ_MODELS)
|
||||
{
|
||||
printf("[ERR] This player is not supported: %.4s\n", boot + 4);
|
||||
return -1;
|
||||
}
|
||||
printf("[INFO] Bootloader file for %s\n", nwz_models[model].model_name);
|
||||
/* verify checksum */
|
||||
uint32_t sum = nwz_models[model].rb_model_num;
|
||||
for(int i = 8; i < boot_size; i++)
|
||||
sum += boot[i];
|
||||
if(sum != be2int(boot))
|
||||
{
|
||||
printf("[ERR] Checksum mismatch\n");
|
||||
return -1;
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
static int find_model2(const char *model_str)
|
||||
{
|
||||
/* since it can be confusing for the user, we accept both rbmodel and codename */
|
||||
/* find model by comparing magic scramble value */
|
||||
int model = 0;
|
||||
for(; model < NR_NWZ_MODELS; model++)
|
||||
if(strcmp(nwz_models[model].rb_model_name, model_str) == 0 ||
|
||||
strcmp(nwz_models[model].codename, model_str) == 0)
|
||||
break;
|
||||
if(model == NR_NWZ_MODELS)
|
||||
{
|
||||
printf("[ERR] Unknown model: %s\n", model_str);
|
||||
return -1;
|
||||
}
|
||||
printf("[INFO] Bootloader file for %s\n", nwz_models[model].model_name);
|
||||
return model;
|
||||
}
|
||||
|
||||
static bool get_model_keysig(int model, char key[NWZ_KEY_SIZE], char sig[NWZ_SIG_SIZE])
|
||||
{
|
||||
const char *codename = nwz_models[model].codename;
|
||||
for(int i = 0; g_model_list[i].model; i++)
|
||||
if(strcmp(g_model_list[i].model, codename) == 0)
|
||||
{
|
||||
if(decrypt_keysig(g_model_list[i].kas, key, sig) == 0)
|
||||
return true;
|
||||
printf("[ERR] Cannot decrypt kas '%s'\n", g_model_list[i].kas);
|
||||
return false;
|
||||
}
|
||||
printf("[ERR] Codename '%s' matches to entry in upg database\n", codename);
|
||||
return false;
|
||||
}
|
||||
|
||||
void nwz_printf(void *u, bool err, color_t c, const char *f, ...)
|
||||
{
|
||||
(void)err;
|
||||
(void)c;
|
||||
bool *debug = u;
|
||||
va_list args;
|
||||
va_start(args, f);
|
||||
if(err || *debug)
|
||||
vprintf(f, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void *memdup(void *data, size_t size)
|
||||
{
|
||||
void *buf = malloc(size);
|
||||
memcpy(buf, data, size);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int mknwzboot(const char *bootfile, const char *outfile, bool debug)
|
||||
{
|
||||
size_t boot_size;
|
||||
uint8_t *boot = read_file(bootfile, &boot_size);
|
||||
if(boot == NULL)
|
||||
{
|
||||
printf("[ERR] Cannot open boot file\n");
|
||||
return 1;
|
||||
}
|
||||
/* check that it is a valid scrambled file */
|
||||
int model = find_model(boot, boot_size);
|
||||
if(model < 0)
|
||||
{
|
||||
free(boot);
|
||||
printf("[ERR] Invalid boot file\n");
|
||||
return 2;
|
||||
}
|
||||
/* find keys */
|
||||
char key[NWZ_KEY_SIZE];
|
||||
char sig[NWZ_SIG_SIZE];
|
||||
if(!get_model_keysig(model, key, sig))
|
||||
{
|
||||
printf("[ERR][INTERNAL] Cannot get keys for model\n");
|
||||
return 3;
|
||||
}
|
||||
/* create the upg file */
|
||||
struct upg_file_t *upg = upg_new();
|
||||
/* first file is the install script: we have to copy data because upg_free()
|
||||
* will free it */
|
||||
upg_append(upg, memdup(install_script, LEN_install_script), LEN_install_script);
|
||||
/* second file is the bootloader content (expected to be a tar file): we have
|
||||
* to copy data because upg_free() will free it */
|
||||
upg_append(upg, memdup(boot + 8, boot_size - 8), boot_size - 8);
|
||||
free(boot);
|
||||
/* write file to buffer */
|
||||
size_t upg_size;
|
||||
void *upg_buf = upg_write_memory(upg, key, sig, &upg_size, &debug, nwz_printf);
|
||||
upg_free(upg);
|
||||
if(upg_buf == NULL)
|
||||
{
|
||||
printf("[ERR] Cannot create UPG file\n");
|
||||
return 4;
|
||||
}
|
||||
if(!write_file(outfile, upg_buf, upg_size))
|
||||
{
|
||||
free(upg_buf);
|
||||
printf("[ERR] Cannpt write UPG file\n");
|
||||
return 5;
|
||||
}
|
||||
free(upg_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mknwzboot_uninst(const char *model_string, const char *outfile, bool debug)
|
||||
{
|
||||
/* check that it is a valid scrambled file */
|
||||
int model = find_model2(model_string);
|
||||
if(model < 0)
|
||||
{
|
||||
printf("[ERR] Invalid model\n");
|
||||
return 2;
|
||||
}
|
||||
/* find keys */
|
||||
char key[NWZ_KEY_SIZE];
|
||||
char sig[NWZ_SIG_SIZE];
|
||||
if(!get_model_keysig(model, key, sig))
|
||||
{
|
||||
printf("[ERR][INTERNAL] Cannot get keys for model\n");
|
||||
return 3;
|
||||
}
|
||||
/* create the upg file */
|
||||
struct upg_file_t *upg = upg_new();
|
||||
/* first file is the uninstall script: we have to copy data because upg_free()
|
||||
* will free it */
|
||||
upg_append(upg, memdup(uninstall_script, LEN_uninstall_script), LEN_uninstall_script);
|
||||
/* write file to buffer */
|
||||
size_t upg_size;
|
||||
void *upg_buf = upg_write_memory(upg, key, sig, &upg_size, &debug, nwz_printf);
|
||||
upg_free(upg);
|
||||
if(upg_buf == NULL)
|
||||
{
|
||||
printf("[ERR] Cannot create UPG file\n");
|
||||
return 4;
|
||||
}
|
||||
if(!write_file(outfile, upg_buf, upg_size))
|
||||
{
|
||||
free(upg_buf);
|
||||
printf("[ERR] Cannpt write UPG file\n");
|
||||
return 5;
|
||||
}
|
||||
free(upg_buf);
|
||||
return 0;
|
||||
}
|
||||
42
utils/mknwzboot/mknwzboot.h
Normal file
42
utils/mknwzboot/mknwzboot.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2011 by Amaury Pouly
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef MKIMXBOOT_H
|
||||
#define MKIMXBOOT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void dump_nwz_dev_info(const char *prefix);
|
||||
/* return 0 on success */
|
||||
int mknwzboot(const char *bootfile, const char *outfile, bool debug);
|
||||
int mknwzboot_uninst(const char *model, const char *outfile, bool debug);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
122
utils/mknwzboot/uninstall_script.sh
Normal file
122
utils/mknwzboot/uninstall_script.sh
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
#!/bin/sh
|
||||
|
||||
# NOTE: busybox is using ash, a very posix and very pedantic shell, make sure
|
||||
# you test your scripts with
|
||||
# busybox sh -n <script>
|
||||
# and if you really, really don't want to download busybox to try it, then go
|
||||
# ahead and brick your device
|
||||
|
||||
# The updater script on the NWZ has a major bug/feature:
|
||||
# it does NOT clear the update flag if the update scrit fails
|
||||
# thus causing a update/reboot loop and a bricked device
|
||||
# always clear to make sure we don't end up being screwed
|
||||
nvpflag fup 0xFFFFFFFF
|
||||
|
||||
# go to /tmp
|
||||
cd /tmp
|
||||
|
||||
# get content partition path
|
||||
CONTENTS="/contents"
|
||||
CONTENTS_PART=`mount | grep contents | awk '{ print $1 }'`
|
||||
|
||||
# print a message to the screen and also on the standard output
|
||||
# lcdprint x,y msg
|
||||
lcdprint ()
|
||||
{
|
||||
echo $2
|
||||
lcdmsg -f /usr/local/bin/font_08x12.bmp -l $1 "$2"
|
||||
}
|
||||
|
||||
# clear screen
|
||||
lcdmsg -c ""
|
||||
lcdprint 0,3 "Contents partition:\n$CONTENTS_PART"
|
||||
|
||||
# We need to remount the contents partition in read-write mode be able to
|
||||
# write something on it
|
||||
lcdprint 0,6 "Remount $CONTENTS rw"
|
||||
mount -o remount,rw $CONTENTS_PART $CONTENTS
|
||||
if [ "$?" != 0 ]; then
|
||||
lcdprint 0,15 "ERROR: remount failed"
|
||||
sleep 3
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# redirect all output to a log file
|
||||
exec > "$CONTENTS/uninstall_dualboot_log.txt" 2>&1
|
||||
|
||||
# import constants
|
||||
. /install_script/constant.txt
|
||||
ROOTFS_TMP_DIR=/tmp/rootfs
|
||||
SPIDERAPP_PATH=$ROOTFS_TMP_DIR/usr/local/bin/SpiderApp
|
||||
|
||||
# mount root partition
|
||||
lcdprint 0,7 "Mount root filesystem"
|
||||
mkdir $ROOTFS_TMP_DIR
|
||||
if [ "$?" != 0 ]; then
|
||||
lcdprint 0,15 "ERROR: mkdir failed"
|
||||
sleep 3
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# If there is an ext4 mounter, try it. Otherwise or on failure, try ext3 and
|
||||
# then ext2.
|
||||
# NOTE some platforms probably use an mtd and this might need some fixing
|
||||
if [ -e /usr/local/bin/icx_mount.ext4 ]; then
|
||||
/usr/local/bin/icx_mount.ext4 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
|
||||
else
|
||||
false
|
||||
fi
|
||||
if [ "$?" != 0 ]; then
|
||||
mount -t ext3 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
|
||||
fi
|
||||
if [ "$?" != 0 ]; then
|
||||
mount -t ext2 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
|
||||
fi
|
||||
if [ "$?" != 0 ]; then
|
||||
lcdprint 0,15 "ERROR: mount failed"
|
||||
sleep 3
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# the installer renames the OF to $SPIDERAPP_PATH.of so if it does not exists
|
||||
# print an error
|
||||
lcdprint 0,8 "Restore OF"
|
||||
if [ ! -e $SPIDERAPP_PATH.of ]; then
|
||||
lcdprint 0,15 "ERROR: cannot find OF"
|
||||
lcdprint 0,16 "ERROR: is Rockbox installed?"
|
||||
sleep 3
|
||||
exit 0
|
||||
fi
|
||||
# restore the OF
|
||||
mv $SPIDERAPP_PATH.of $SPIDERAPP_PATH
|
||||
if [ "$?" != 0 ]; then
|
||||
lcdprint 0,15 "ERROR: restore failed"
|
||||
sleep 3
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# unmount root partition
|
||||
lcdprint 0,11 "Unmount root filesystem"
|
||||
sync
|
||||
if [ "$?" != 0 ]; then
|
||||
umount "$ROOTFS_TMP_DIR"
|
||||
lcdprint 0,15 "ERROR: sync failed"
|
||||
sleep 3
|
||||
exit 0
|
||||
fi
|
||||
|
||||
umount $ROOTFS_TMP_DIR
|
||||
if [ "$?" != 0 ]; then
|
||||
lcdprint 0,15 "ERROR: umount failed"
|
||||
sleep 3
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Success screen
|
||||
lcdprint 0,15 "Rebooting in 3 seconds."
|
||||
sleep 3
|
||||
sync
|
||||
|
||||
echo "Uninstallation successful"
|
||||
# finish
|
||||
exit 0
|
||||
39
utils/mkrk27boot/Makefile
Normal file
39
utils/mkrk27boot/Makefile
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
# $Id$
|
||||
#
|
||||
|
||||
FIRMWARE = ../../firmware/
|
||||
|
||||
DRIVERS = $(FIRMWARE)drivers/
|
||||
EXPORT = $(FIRMWARE)export/
|
||||
|
||||
BUILDDATE=$(shell date -u +'-DYEAR=%Y -DMONTH=%m -DDAY=%d')
|
||||
INCLUDE = -I$(EXPORT) -I$(FIRMWARE)include -I$(FIRMWARE)target/hosted -I$(FIRMWARE)target/hosted/sdl
|
||||
DEFINES = -DTEST_FAT -DDISK_WRITE -DHAVE_FAT16SUPPORT -D__PCTOOL__
|
||||
|
||||
CFLAGS = -Wall -g -std=gnu99 -Wno-pointer-sign $(DEFINES) -I. $(INCLUDE)
|
||||
SIM_FLAGS = $(CFLAGS) $(BUILDDATE) -I$(FIRMWARE)/libc/include
|
||||
|
||||
OUTPUT = mkrk27boot
|
||||
|
||||
# inputs
|
||||
LIBSOURCES := $(DRIVERS)fat.c $(FIRMWARE)libc/ctype.c $(FIRMWARE)libc/strtok.c \
|
||||
$(FIRMWARE)libc/errno.c $(FIRMWARE)common/strlcpy.c $(FIRMWARE)common/unicode.c \
|
||||
$(FIRMWARE)common/file.c $(FIRMWARE)common/dir_uncached.c $(FIRMWARE)common/disk.c ata-sim.c mkrk27boot.c
|
||||
|
||||
SOURCES := $(LIBSOURCES) main.c
|
||||
|
||||
include ../libtools.make
|
||||
|
||||
SIMOBJS = $(addprefix $(OBJDIR),fat.o ctype.o strtok.o errno.o disk.o dir_uncached.o file.o unicode.o strlcpy.o)
|
||||
|
||||
$(SIMOBJS):
|
||||
@echo CC $<
|
||||
$(SILENT)mkdir -p $(dir $@)
|
||||
$(SILENT)$(CROSS)$(CC) $(SIM_FLAGS) -c -o $@ $<
|
||||
|
||||
122
utils/mkrk27boot/ata-sim.c
Normal file
122
utils/mkrk27boot/ata-sim.c
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id:$
|
||||
*
|
||||
* Copyright (C) 2012 by Andrew Ryabinin
|
||||
*
|
||||
* major portion of code is taken from firmware/test/fat/ata-sim.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "debug.h"
|
||||
#include "dir.h"
|
||||
|
||||
#define BLOCK_SIZE 512
|
||||
|
||||
static FILE* file;
|
||||
|
||||
extern char *img_filename;
|
||||
|
||||
void mutex_init(struct mutex* l) {}
|
||||
void mutex_lock(struct mutex* l) {}
|
||||
void mutex_unlock(struct mutex* l) {}
|
||||
|
||||
void panicf( char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start( ap, fmt );
|
||||
fprintf(stderr,"***PANIC*** ");
|
||||
vfprintf(stderr, fmt, ap );
|
||||
va_end( ap );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void debugf(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start( ap, fmt );
|
||||
fprintf(stderr,"DEBUGF: ");
|
||||
vfprintf( stderr, fmt, ap );
|
||||
va_end( ap );
|
||||
}
|
||||
|
||||
void ldebugf(const char* file, int line, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start( ap, fmt );
|
||||
fprintf( stderr, "%s:%d ", file, line );
|
||||
vfprintf( stderr, fmt, ap );
|
||||
va_end( ap );
|
||||
}
|
||||
|
||||
int storage_read_sectors(unsigned long start, int count, void* buf)
|
||||
{
|
||||
if ( count > 1 )
|
||||
DEBUGF("[Reading %d blocks: 0x%lx to 0x%lx]\n",
|
||||
count, start, start+count-1);
|
||||
else
|
||||
DEBUGF("[Reading block 0x%lx]\n", start);
|
||||
|
||||
if(fseek(file,start*BLOCK_SIZE,SEEK_SET)) {
|
||||
perror("fseek");
|
||||
return -1;
|
||||
}
|
||||
if(!fread(buf,BLOCK_SIZE,count,file)) {
|
||||
DEBUGF("ata_write_sectors(0x%lx, 0x%x, %p)\n", start, count, buf );
|
||||
perror("fread");
|
||||
panicf("Disk error\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int storage_write_sectors(unsigned long start, int count, void* buf)
|
||||
{
|
||||
if ( count > 1 )
|
||||
DEBUGF("[Writing %d blocks: 0x%lx to 0x%lx]\n",
|
||||
count, start, start+count-1);
|
||||
else
|
||||
DEBUGF("[Writing block 0x%lx]\n", start);
|
||||
|
||||
if (start == 0)
|
||||
panicf("Writing on sector 0!\n");
|
||||
|
||||
if(fseek(file,start*BLOCK_SIZE,SEEK_SET)) {
|
||||
perror("fseek");
|
||||
return -1;
|
||||
}
|
||||
if(!fwrite(buf,BLOCK_SIZE,count,file)) {
|
||||
DEBUGF("ata_write_sectors(0x%lx, 0x%x, %p)\n", start, count, buf );
|
||||
perror("fwrite");
|
||||
panicf("Disk error\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ata_init(void)
|
||||
{
|
||||
file=fopen(img_filename,"rb+");
|
||||
if(!file) {
|
||||
fprintf(stderr, "read_disk() - Could not find \"%s\"\n",img_filename);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ata_exit(void)
|
||||
{
|
||||
fclose(file);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue