mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-08 12:45:26 -05:00
ipodpatcher and rbutil support for the Nano2G - FS#10609 with a few further changes.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23142 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
e486241c01
commit
8e95cc4329
5 changed files with 531 additions and 35 deletions
|
|
@ -2,13 +2,26 @@ CFLAGS=-Wall -W
|
||||||
|
|
||||||
BOOT_H = ipod1g2g.h ipod3g.h ipod4g.h ipodcolor.h ipodmini.h ipodmini2g.h ipodnano.h ipodvideo.h
|
BOOT_H = ipod1g2g.h ipod3g.h ipod4g.h ipodcolor.h ipodmini.h ipodmini2g.h ipodnano.h ipodvideo.h
|
||||||
|
|
||||||
# Uncomment the next two lines to build with embedded bootloaders and the
|
# Enable the next two lines to build with embedded bootloaders and the
|
||||||
# --install option and interactive mode. You need the full set of Rockbox
|
# --install option and interactive mode. You need the full set of Rockbox
|
||||||
# bootloaders in this directory - download them from
|
# bootloaders in this directory - download them from
|
||||||
# http://download.rockbox.org/bootloader/ipod/bootloaders.zip
|
# http://download.rockbox.org/bootloader/ipod/bootloaders.zip
|
||||||
|
|
||||||
#BOOTSRC = ipod1g2g.c ipod3g.c ipod4g.c ipodcolor.c ipodmini.c ipodmini2g.c ipodnano.c ipodvideo.c
|
ifdef RELEASE
|
||||||
#CFLAGS += -DWITH_BOOTOBJS
|
CFLAGS+=-DRELEASE
|
||||||
|
BOOTOBJS=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef BOOTOBJS
|
||||||
|
BOOTSRC = ipod1g2g.c ipod3g.c ipod4g.c ipodcolor.c ipodmini.c ipodmini2g.c ipodnano.c ipodvideo.c ipodnano2g.c
|
||||||
|
CFLAGS += -DWITH_BOOTOBJS
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef VERSION
|
||||||
|
VERSION=$(shell ../../tools/version.sh)
|
||||||
|
endif
|
||||||
|
|
||||||
|
CFLAGS+=-DVERSION=\"$(VERSION)\"
|
||||||
|
|
||||||
ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
|
ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
|
||||||
OUTPUT=ipodpatcher.exe
|
OUTPUT=ipodpatcher.exe
|
||||||
|
|
@ -81,6 +94,9 @@ ipodnano.c: bootloader-ipodnano.ipod ipod2c
|
||||||
ipodvideo.c: bootloader-ipodvideo.ipod ipod2c
|
ipodvideo.c: bootloader-ipodvideo.ipod ipod2c
|
||||||
./ipod2c bootloader-ipodvideo.ipod ipodvideo
|
./ipod2c bootloader-ipodvideo.ipod ipodvideo
|
||||||
|
|
||||||
|
ipodnano2g.c: bootloader-ipodnano2g.ipodx ipod2c
|
||||||
|
./ipod2c bootloader-ipodnano2g.ipodx ipodnano2g
|
||||||
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f ipodpatcher.exe ipodpatcher-rc.o ipodpatcher-mac ipodpatcher-i386 ipodpatcher-ppc ipodpatcher ipod2c *~ $(BOOTSRC) $(BOOT_H)
|
rm -f ipodpatcher.exe ipodpatcher-rc.o ipodpatcher-mac ipodpatcher-i386 ipodpatcher-ppc ipodpatcher ipod2c *~ $(BOOTSRC) $(BOOT_H)
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@ enum firmwaretype_t {
|
||||||
FTYPE_OSOS = 0,
|
FTYPE_OSOS = 0,
|
||||||
FTYPE_RSRC,
|
FTYPE_RSRC,
|
||||||
FTYPE_AUPD,
|
FTYPE_AUPD,
|
||||||
FTYPE_HIBE
|
FTYPE_HIBE,
|
||||||
|
FTYPE_OSBK
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ipod_directory_t {
|
struct ipod_directory_t {
|
||||||
|
|
@ -71,6 +72,7 @@ struct ipod_t {
|
||||||
int num_heads;
|
int num_heads;
|
||||||
struct ipod_directory_t ipod_directory[MAX_IMAGES];
|
struct ipod_directory_t ipod_directory[MAX_IMAGES];
|
||||||
int nimages;
|
int nimages;
|
||||||
|
int ososimage;
|
||||||
off_t diroffset;
|
off_t diroffset;
|
||||||
off_t start; /* Offset in bytes of firmware partition from start of disk */
|
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 */
|
off_t fwoffset; /* Offset in bytes of start of firmware images from start of disk */
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
#include "ipodcolor.h"
|
#include "ipodcolor.h"
|
||||||
#include "ipodnano.h"
|
#include "ipodnano.h"
|
||||||
#include "ipodvideo.h"
|
#include "ipodvideo.h"
|
||||||
|
#include "ipodnano2g.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef RBUTIL
|
#ifndef RBUTIL
|
||||||
|
|
@ -389,7 +390,7 @@ int write_partition(struct ipod_t* ipod, int infile)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE" };
|
char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE", "OSBK" };
|
||||||
|
|
||||||
int diskmove(struct ipod_t* ipod, int delta)
|
int diskmove(struct ipod_t* ipod, int delta)
|
||||||
{
|
{
|
||||||
|
|
@ -470,6 +471,409 @@ int diskmove(struct ipod_t* ipod, int delta)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rename_image(struct ipod_t* ipod, char* from, char* to)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
int x;
|
||||||
|
int found;
|
||||||
|
int i;
|
||||||
|
unsigned char* p;
|
||||||
|
|
||||||
|
/* diroffset may not be sector-aligned */
|
||||||
|
x = ipod->diroffset % ipod->sector_size;
|
||||||
|
|
||||||
|
/* Read directory */
|
||||||
|
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
|
||||||
|
if (n < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Read of directory failed.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = ipod_sectorbuf + x;
|
||||||
|
|
||||||
|
/* A hack to detect 2nd gen Nanos - maybe there is a better way? */
|
||||||
|
if (p[0] == 0)
|
||||||
|
{
|
||||||
|
/* Adjust diroffset */
|
||||||
|
ipod->diroffset += ipod->sector_size - x;
|
||||||
|
|
||||||
|
n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
|
||||||
|
if (n < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Read of directory failed.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
p = ipod_sectorbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = 0;
|
||||||
|
for (i=0 ; !found && i < MAX_IMAGES; i++) {
|
||||||
|
if (memcmp(p + 4, from, 4) == 0) {
|
||||||
|
memcpy(p + 4, to, 4);
|
||||||
|
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
p += 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", from);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write directory back to disk */
|
||||||
|
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
|
||||||
|
if (n < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Write of directory failed in rename_image.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int delete_image(struct ipod_t* ipod, char* name)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
int x;
|
||||||
|
int found;
|
||||||
|
int i;
|
||||||
|
unsigned char* p;
|
||||||
|
|
||||||
|
/* diroffset may not be sector-aligned */
|
||||||
|
x = ipod->diroffset % ipod->sector_size;
|
||||||
|
|
||||||
|
/* Read directory */
|
||||||
|
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
|
||||||
|
if (n < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Read of directory failed.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = ipod_sectorbuf + x;
|
||||||
|
|
||||||
|
/* A hack to detect 2nd gen Nanos - maybe there is a better way? */
|
||||||
|
if (p[0] == 0)
|
||||||
|
{
|
||||||
|
/* Adjust diroffset */
|
||||||
|
ipod->diroffset += ipod->sector_size - x;
|
||||||
|
|
||||||
|
n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
|
||||||
|
if (n < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Read of directory failed.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
p = ipod_sectorbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = 0;
|
||||||
|
for (i=0 ; !found && i < MAX_IMAGES; i++) {
|
||||||
|
if (memcmp(p + 4, name, 4) == 0) {
|
||||||
|
memset(p, 0, 40); /* Delete directory entry */
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
p += 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write directory back to disk */
|
||||||
|
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
|
||||||
|
if (n < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Write of directory failed in delete_image.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_new_image(struct ipod_t* ipod, char* imagename, char* filename, int type)
|
||||||
|
{
|
||||||
|
int length;
|
||||||
|
int found;
|
||||||
|
int i;
|
||||||
|
int x;
|
||||||
|
int n;
|
||||||
|
int infile;
|
||||||
|
int newsize;
|
||||||
|
unsigned long chksum=0;
|
||||||
|
unsigned long filechksum=0;
|
||||||
|
unsigned long offset;
|
||||||
|
unsigned char header[8]; /* Header for .ipod file */
|
||||||
|
unsigned char* p;
|
||||||
|
|
||||||
|
#ifdef WITH_BOOTOBJS
|
||||||
|
if (type == FILETYPE_INTERNAL) {
|
||||||
|
fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
|
||||||
|
length = ipod->bootloader_len;
|
||||||
|
infile = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* First check that the input file is the correct type for this ipod. */
|
||||||
|
infile=open(filename,O_RDONLY);
|
||||||
|
if (infile < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type==FILETYPE_DOT_IPOD) {
|
||||||
|
n = read(infile,header,8);
|
||||||
|
if (n < 8) {
|
||||||
|
fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
|
||||||
|
close(infile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(header+4, ipod->modelname,4)!=0) {
|
||||||
|
fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
|
||||||
|
header[4],header[5],header[6],header[7], ipod->modelname);
|
||||||
|
close(infile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
filechksum = be2int(header);
|
||||||
|
|
||||||
|
length = filesize(infile)-8;
|
||||||
|
} else {
|
||||||
|
length = filesize(infile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
|
||||||
|
|
||||||
|
fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
|
||||||
|
length,newsize);
|
||||||
|
|
||||||
|
if (newsize > BUFFER_SIZE) {
|
||||||
|
fprintf(stderr,"[ERR] Input file too big for buffer\n");
|
||||||
|
if (infile >= 0) close(infile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Check if we have enough space in the partition for the new image */
|
||||||
|
|
||||||
|
#ifdef WITH_BOOTOBJS
|
||||||
|
if (type == FILETYPE_INTERNAL) {
|
||||||
|
memcpy(ipod_sectorbuf,ipod->bootloader,ipod->bootloader_len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
fprintf(stderr,"[INFO] Reading input file...\n");
|
||||||
|
|
||||||
|
n = read(infile,ipod_sectorbuf,length);
|
||||||
|
if (n < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Couldn't read input file\n");
|
||||||
|
close(infile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
close(infile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pad the data with zeros */
|
||||||
|
memset(ipod_sectorbuf+length,0,newsize-length);
|
||||||
|
|
||||||
|
if (type==FILETYPE_DOT_IPOD) {
|
||||||
|
chksum = ipod->modelnum;
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
/* add 8 unsigned bits but keep a 32 bit sum */
|
||||||
|
chksum += ipod_sectorbuf[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chksum == filechksum) {
|
||||||
|
fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
offset = ipod->fwoffset + ipod->ipod_directory[ipod->nimages - 1].devOffset +
|
||||||
|
ipod->ipod_directory[ipod->nimages - 1].len + ipod->sector_size;
|
||||||
|
|
||||||
|
/* 2nd Gen Nano has encrypted firmware, and the sector
|
||||||
|
preceeding the firmware contains hashes that need to be
|
||||||
|
preserved. Nano 2G images include these extra 2048 (0x800)
|
||||||
|
bytes
|
||||||
|
*/
|
||||||
|
if (ipod_seek(ipod, offset - (ipod->modelnum == 62 ? 0x800 : 0)) < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Seek failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((n = ipod_write(ipod,ipod_sectorbuf,newsize)) < 0) {
|
||||||
|
perror("[ERR] Write failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n < newsize) {
|
||||||
|
fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
|
||||||
|
,newsize,n);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
|
||||||
|
|
||||||
|
/* Now we need to create a new directory entry
|
||||||
|
|
||||||
|
NOTE: On the Nano 2G, the checksum is the checksum of the
|
||||||
|
unencrypted firmware. But this isn't checked by the NOR
|
||||||
|
bootloader (there are cryptographic hashes in the
|
||||||
|
firmware itself), so it doesn't matter that this is
|
||||||
|
wrong.
|
||||||
|
*/
|
||||||
|
chksum = 0;
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
/* add 8 unsigned bits but keep a 32 bit sum */
|
||||||
|
chksum += ipod_sectorbuf[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
x = ipod->diroffset % ipod->sector_size;
|
||||||
|
|
||||||
|
/* Read directory */
|
||||||
|
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
|
||||||
|
|
||||||
|
n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
|
||||||
|
if (n < 0) { return -1; }
|
||||||
|
|
||||||
|
/* Create a new directory entry */
|
||||||
|
|
||||||
|
/* Copy OSOS or OSBK details - we assume one of them exists */
|
||||||
|
p = ipod_sectorbuf + x;
|
||||||
|
found = 0;
|
||||||
|
for (i = 0; !found && i < ipod->nimages; i++) {
|
||||||
|
if ((memcmp(p + 4, "soso", 4)==0) || (memcmp(p + 4, "kbso", 4)==0)) {
|
||||||
|
found = 1;
|
||||||
|
} else {
|
||||||
|
p += 40;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
fprintf(stderr,"[ERR] No OSOS or OSBK image to copy directory from\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy directory image */
|
||||||
|
memcpy(ipod_sectorbuf + x + (ipod->nimages * 40), p, 40);
|
||||||
|
p = ipod_sectorbuf + x + (ipod->nimages * 40);
|
||||||
|
|
||||||
|
/* Modify directory. */
|
||||||
|
memcpy(p + 4, imagename, 4);
|
||||||
|
int2le(offset - ipod->fwoffset, p + 12); /* devOffset */
|
||||||
|
int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16); /* len */
|
||||||
|
int2le(chksum, p + 28); /* checksum */
|
||||||
|
|
||||||
|
/* Write directory */
|
||||||
|
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
|
||||||
|
n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
|
||||||
|
if (n < 0) { return -1; }
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Bootloader installation on the Nano2G consists of renaming the
|
||||||
|
OSOS image to OSBK and then writing the Rockbox bootloader as a
|
||||||
|
new OSOS image.
|
||||||
|
|
||||||
|
Maybe this approach can/should be adapted for other ipods, as it
|
||||||
|
prevents the Apple bootloader loading the original firmware into
|
||||||
|
RAM along with the Rockbox bootloader (and hence will give a
|
||||||
|
faster boot when the user just wants to start Rockbox).
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int add_bootloader_nano2g(struct ipod_t* ipod, char* filename, int type)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int has_osbk = 0;
|
||||||
|
|
||||||
|
/* Check if we already have an OSBK image */
|
||||||
|
for (i = 0; i < ipod->nimages; i++) {
|
||||||
|
if (ipod->ipod_directory[i].ftype==FTYPE_OSBK) {
|
||||||
|
has_osbk = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_osbk == 0) {
|
||||||
|
/* First-time install - rename OSOS to OSBK and create new OSOS for bootloader */
|
||||||
|
fprintf(stderr,"[INFO] Creating OSBK backup image of original firmware\n");
|
||||||
|
|
||||||
|
if (rename_image(ipod, "soso", "kbso") < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Could not rename OSOS image\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add our bootloader as a brand new image */
|
||||||
|
return add_new_image(ipod, "soso", filename, type);
|
||||||
|
} else {
|
||||||
|
/* This is an update, just replace OSOS with our bootloader */
|
||||||
|
|
||||||
|
return write_firmware(ipod, filename, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int delete_bootloader_nano2g(struct ipod_t* ipod)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int has_osbk = 0;
|
||||||
|
|
||||||
|
/* Check if we have an OSBK image */
|
||||||
|
for (i = 0; i < ipod->nimages; i++) {
|
||||||
|
if (ipod->ipod_directory[i].ftype==FTYPE_OSBK) {
|
||||||
|
has_osbk = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_osbk == 0) {
|
||||||
|
fprintf(stderr,"[ERR] No OSBK image found - nothing to uninstall\n");
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
/* Delete our bootloader image */
|
||||||
|
if (delete_image(ipod, "soso") < 0) {
|
||||||
|
fprintf(stderr,"[WARN] Could not delete OSOS image\n");
|
||||||
|
} else {
|
||||||
|
fprintf(stderr,"[INFO] OSOS image deleted\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rename_image(ipod, "kbso", "soso") < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Could not rename OSBK image\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fprintf(stderr,"[INFO] OSBK image renamed to OSOS - bootloader uninstalled.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int add_bootloader(struct ipod_t* ipod, char* filename, int type)
|
int add_bootloader(struct ipod_t* ipod, char* filename, int type)
|
||||||
{
|
{
|
||||||
int length;
|
int length;
|
||||||
|
|
@ -485,6 +889,11 @@ int add_bootloader(struct ipod_t* ipod, char* filename, int type)
|
||||||
unsigned char header[8]; /* Header for .ipod file */
|
unsigned char header[8]; /* Header for .ipod file */
|
||||||
unsigned char* bootloader_buf;
|
unsigned char* bootloader_buf;
|
||||||
|
|
||||||
|
/* The 2nd gen Nano is installed differently */
|
||||||
|
if (ipod->modelnum == 62) {
|
||||||
|
return add_bootloader_nano2g(ipod, filename, type);
|
||||||
|
}
|
||||||
|
|
||||||
/* Calculate the position in the OSOS image where our bootloader will go. */
|
/* Calculate the position in the OSOS image where our bootloader will go. */
|
||||||
if (ipod->ipod_directory[0].entryOffset>0) {
|
if (ipod->ipod_directory[0].entryOffset>0) {
|
||||||
/* Keep the same entryOffset */
|
/* Keep the same entryOffset */
|
||||||
|
|
@ -698,6 +1107,11 @@ int delete_bootloader(struct ipod_t* ipod)
|
||||||
int n;
|
int n;
|
||||||
unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
|
unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
|
||||||
|
|
||||||
|
/* The 2nd gen Nano is installed differently */
|
||||||
|
if (ipod->modelnum == 62) {
|
||||||
|
return delete_bootloader_nano2g(ipod);
|
||||||
|
}
|
||||||
|
|
||||||
/* Removing the bootloader involves adjusting the "length",
|
/* Removing the bootloader involves adjusting the "length",
|
||||||
"chksum" and "entryOffset" values in the osos image's directory
|
"chksum" and "entryOffset" values in the osos image's directory
|
||||||
entry. */
|
entry. */
|
||||||
|
|
@ -774,7 +1188,9 @@ int write_firmware(struct ipod_t* ipod, char* filename, int type)
|
||||||
int bytesavailable;
|
int bytesavailable;
|
||||||
unsigned long chksum=0;
|
unsigned long chksum=0;
|
||||||
unsigned long filechksum=0;
|
unsigned long filechksum=0;
|
||||||
|
unsigned long offset;
|
||||||
unsigned char header[8]; /* Header for .ipod file */
|
unsigned char header[8]; /* Header for .ipod file */
|
||||||
|
unsigned char* p;
|
||||||
|
|
||||||
#ifdef WITH_BOOTOBJS
|
#ifdef WITH_BOOTOBJS
|
||||||
if (type == FILETYPE_INTERNAL) {
|
if (type == FILETYPE_INTERNAL) {
|
||||||
|
|
@ -876,7 +1292,23 @@ int write_firmware(struct ipod_t* ipod, char* filename, int type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
|
|
||||||
|
offset = ipod->fwoffset+ipod->ipod_directory[ipod->ososimage].devOffset;
|
||||||
|
|
||||||
|
if (ipod->modelnum==62) {
|
||||||
|
|
||||||
|
/* 2nd Gen Nano has encrypted firmware, and the sector
|
||||||
|
preceeding the firmware contains hashes that need to be
|
||||||
|
preserved. Nano 2G images include these extra 2048 (0x800)
|
||||||
|
bytes
|
||||||
|
*/
|
||||||
|
|
||||||
|
offset -= 0x800;
|
||||||
|
|
||||||
|
/* TODO: The above checks need to take into account this 0x800 bytes */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipod_seek(ipod, offset) < 0) {
|
||||||
fprintf(stderr,"[ERR] Seek failed\n");
|
fprintf(stderr,"[ERR] Seek failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -893,7 +1325,14 @@ int write_firmware(struct ipod_t* ipod, char* filename, int type)
|
||||||
}
|
}
|
||||||
fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
|
fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
|
||||||
|
|
||||||
/* Now we need to update the "len", "entryOffset" and "chksum" fields */
|
/* Now we need to update the "len", "entryOffset" and "chksum" fields
|
||||||
|
|
||||||
|
NOTE: On the Nano 2G, the checksum is the checksum of the
|
||||||
|
unencrypted firmware. But this isn't checked by the NOR
|
||||||
|
bootloader (there are cryptographic hashes in the
|
||||||
|
firmware itself), so it doesn't matter that this is
|
||||||
|
wrong.
|
||||||
|
*/
|
||||||
chksum = 0;
|
chksum = 0;
|
||||||
for (i = 0; i < length; i++) {
|
for (i = 0; i < length; i++) {
|
||||||
/* add 8 unsigned bits but keep a 32 bit sum */
|
/* add 8 unsigned bits but keep a 32 bit sum */
|
||||||
|
|
@ -908,10 +1347,11 @@ int write_firmware(struct ipod_t* ipod, char* filename, int type)
|
||||||
n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
|
n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
|
||||||
if (n < 0) { return -1; }
|
if (n < 0) { return -1; }
|
||||||
|
|
||||||
/* Update entries for image 0 */
|
/* Update entries for image */
|
||||||
int2le(length,ipod_sectorbuf+x+16);
|
p = ipod_sectorbuf + x + (ipod->ososimage * 40);
|
||||||
int2le(0,ipod_sectorbuf+x+24);
|
int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16);
|
||||||
int2le(chksum,ipod_sectorbuf+x+28);
|
int2le(0, p + 24);
|
||||||
|
int2le(chksum, p + 28);
|
||||||
|
|
||||||
/* Write directory */
|
/* Write directory */
|
||||||
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
|
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
|
||||||
|
|
@ -927,26 +1367,36 @@ int read_firmware(struct ipod_t* ipod, char* filename, int type)
|
||||||
int i;
|
int i;
|
||||||
int outfile;
|
int outfile;
|
||||||
int n;
|
int n;
|
||||||
|
unsigned long offset;
|
||||||
unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
|
unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
|
||||||
unsigned char header[8]; /* Header for .ipod file */
|
unsigned char header[8]; /* Header for .ipod file */
|
||||||
|
|
||||||
if (ipod->ipod_directory[0].entryOffset != 0) {
|
if (ipod->ipod_directory[ipod->ososimage].entryOffset != 0) {
|
||||||
/* We have a bootloader... */
|
/* We have a bootloader... */
|
||||||
length = ipod->ipod_directory[0].entryOffset;
|
length = ipod->ipod_directory[ipod->ososimage].entryOffset;
|
||||||
} else {
|
} else {
|
||||||
length = ipod->ipod_directory[0].len;
|
length = ipod->ipod_directory[ipod->ososimage].len;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
|
fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
|
||||||
|
|
||||||
if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
|
offset = ipod->fwoffset + ipod->ipod_directory[ipod->ososimage].devOffset;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
|
i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
|
||||||
fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
|
fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
|
||||||
length,i);
|
length,i);
|
||||||
|
|
||||||
|
if (ipod->modelnum==62) {
|
||||||
|
/* 2nd Gen Nano has encrypted firmware, and we need to dump the
|
||||||
|
sector preceeding the image - it contains hashes */
|
||||||
|
offset -= 0x800;
|
||||||
|
length += 0x800;
|
||||||
|
i += 0x800;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipod_seek(ipod, offset)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if ((n = ipod_read(ipod,ipod_sectorbuf,i)) < 0) {
|
if ((n = ipod_read(ipod,ipod_sectorbuf,i)) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -1049,6 +1499,9 @@ int read_directory(struct ipod_t* ipod)
|
||||||
/* A hack to detect 2nd gen Nanos - maybe there is a better way? */
|
/* A hack to detect 2nd gen Nanos - maybe there is a better way? */
|
||||||
if (p[0] == 0)
|
if (p[0] == 0)
|
||||||
{
|
{
|
||||||
|
/* Adjust diroffset */
|
||||||
|
ipod->diroffset += ipod->sector_size - x;
|
||||||
|
|
||||||
n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
|
n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
fprintf(stderr,"[ERR] Read of directory failed.\n");
|
fprintf(stderr,"[ERR] Read of directory failed.\n");
|
||||||
|
|
@ -1057,15 +1510,19 @@ int read_directory(struct ipod_t* ipod)
|
||||||
p = ipod_sectorbuf;
|
p = ipod_sectorbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ipod->ososimage = -1;
|
||||||
while ((ipod->nimages < MAX_IMAGES) && (p < (ipod_sectorbuf + x + 400)) &&
|
while ((ipod->nimages < MAX_IMAGES) && (p < (ipod_sectorbuf + x + 400)) &&
|
||||||
((memcmp(p,"!ATA",4)==0) || (memcmp(p,"DNAN",4)==0))) {
|
((memcmp(p,"!ATA",4)==0) || (memcmp(p,"DNAN",4)==0))) {
|
||||||
p+=4;
|
p+=4;
|
||||||
if (memcmp(p,"soso",4)==0) {
|
if (memcmp(p,"soso",4)==0) {
|
||||||
ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS;
|
ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS;
|
||||||
|
ipod->ososimage = ipod->nimages;
|
||||||
} else if (memcmp(p,"crsr",4)==0) {
|
} else if (memcmp(p,"crsr",4)==0) {
|
||||||
ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC;
|
ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC;
|
||||||
} else if (memcmp(p,"dpua",4)==0) {
|
} else if (memcmp(p,"dpua",4)==0) {
|
||||||
ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD;
|
ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD;
|
||||||
|
} else if (memcmp(p,"kbso",4)==0) {
|
||||||
|
ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSBK;
|
||||||
} else if (memcmp(p,"ebih",4)==0) {
|
} else if (memcmp(p,"ebih",4)==0) {
|
||||||
ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE;
|
ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1092,12 +1549,17 @@ int read_directory(struct ipod_t* ipod)
|
||||||
ipod->nimages++;
|
ipod->nimages++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ipod->ososimage < 0) {
|
||||||
|
fprintf(stderr,"[ERR] No OSOS image found.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if ((ipod->nimages > 1) && (version==2)) {
|
if ((ipod->nimages > 1) && (version==2)) {
|
||||||
/* The 3g firmware image doesn't appear to have a version, so
|
/* The 3g firmware image doesn't appear to have a version, so
|
||||||
let's make one up... Note that this is never written back to the
|
let's make one up... Note that this is never written back to the
|
||||||
ipod, so it's OK to do. */
|
ipod, so it's OK to do. */
|
||||||
|
|
||||||
if (ipod->ipod_directory[0].vers == 0) { ipod->ipod_directory[0].vers = 3; }
|
if (ipod->ipod_directory[ipod->ososimage].vers == 0) { ipod->ipod_directory[ipod->ososimage].vers = 3; }
|
||||||
|
|
||||||
ipod->fwoffset = ipod->start;
|
ipod->fwoffset = ipod->start;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1247,11 +1709,12 @@ int getmodel(struct ipod_t* ipod, int ipod_version)
|
||||||
break;
|
break;
|
||||||
case 0x100:
|
case 0x100:
|
||||||
ipod->modelstr="2nd Generation Nano";
|
ipod->modelstr="2nd Generation Nano";
|
||||||
ipod->modelnum = 0;
|
ipod->modelnum = 62;
|
||||||
ipod->targetname = NULL;
|
ipod->modelname = "nn2x";
|
||||||
|
ipod->targetname = "ipodnano2g";
|
||||||
#ifdef WITH_BOOTOBJS
|
#ifdef WITH_BOOTOBJS
|
||||||
ipod->bootloader = NULL;
|
ipod->bootloader = ipodnano2g;
|
||||||
ipod->bootloader_len = 0;
|
ipod->bootloader_len = LEN_ipodnano2g;
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -1316,7 +1779,7 @@ int ipod_scan(struct ipod_t* ipod)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ipod_version=(ipod->ipod_directory[0].vers>>8);
|
ipod_version=(ipod->ipod_directory[ipod->ososimage].vers>>8);
|
||||||
/* Windows requires the ipod in R/W mode for SCSI Inquiry */
|
/* Windows requires the ipod in R/W mode for SCSI Inquiry */
|
||||||
ipod->ramsize = 0;
|
ipod->ramsize = 0;
|
||||||
ipod_reopen_rw(ipod);
|
ipod_reopen_rw(ipod);
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,11 @@
|
||||||
#include "ipodpatcher.h"
|
#include "ipodpatcher.h"
|
||||||
#include "ipodio.h"
|
#include "ipodio.h"
|
||||||
|
|
||||||
#define VERSION "3.0 with v3.0 bootloaders"
|
#ifdef RELEASE
|
||||||
|
#undef VERSION
|
||||||
|
#define VERSION "4.0 with v3.0 bootloaders (v1.0 for 2nd Gen Nano)"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
NONE,
|
NONE,
|
||||||
|
|
@ -80,14 +84,14 @@ void print_usage(void)
|
||||||
fprintf(stderr," -l, --list\n");
|
fprintf(stderr," -l, --list\n");
|
||||||
fprintf(stderr," -r, --read-partition bootpartition.bin\n");
|
fprintf(stderr," -r, --read-partition bootpartition.bin\n");
|
||||||
fprintf(stderr," -w, --write-partition bootpartition.bin\n");
|
fprintf(stderr," -w, --write-partition bootpartition.bin\n");
|
||||||
fprintf(stderr," -rf, --read-firmware filename.ipod\n");
|
fprintf(stderr," -rf, --read-firmware filename.ipod[x]\n");
|
||||||
fprintf(stderr," -rfb, --read-firmware-bin filename.bin\n");
|
fprintf(stderr," -rfb, --read-firmware-bin filename.bin\n");
|
||||||
fprintf(stderr," -wf, --write-firmware filename.ipod\n");
|
fprintf(stderr," -wf, --write-firmware filename.ipod[x]\n");
|
||||||
fprintf(stderr," -wfb, --write-firmware-bin filename.bin\n");
|
fprintf(stderr," -wfb, --write-firmware-bin filename.bin\n");
|
||||||
#ifdef WITH_BOOTOBJS
|
#ifdef WITH_BOOTOBJS
|
||||||
fprintf(stderr," -we, --write-embedded\n");
|
fprintf(stderr," -we, --write-embedded\n");
|
||||||
#endif
|
#endif
|
||||||
fprintf(stderr," -a, --add-bootloader filename.ipod\n");
|
fprintf(stderr," -a, --add-bootloader filename.ipod[x]\n");
|
||||||
fprintf(stderr," -ab, --add-bootloader-bin filename.bin\n");
|
fprintf(stderr," -ab, --add-bootloader-bin filename.bin\n");
|
||||||
fprintf(stderr," -d, --delete-bootloader\n");
|
fprintf(stderr," -d, --delete-bootloader\n");
|
||||||
fprintf(stderr," -f, --format\n");
|
fprintf(stderr," -f, --format\n");
|
||||||
|
|
@ -97,6 +101,8 @@ void print_usage(void)
|
||||||
fprintf(stderr," -x --dump-xml filename.xml\n");
|
fprintf(stderr," -x --dump-xml filename.xml\n");
|
||||||
fprintf(stderr,"\n");
|
fprintf(stderr,"\n");
|
||||||
|
|
||||||
|
fprintf(stderr,"The .ipodx extension is used for encrypted images for the 2nd Gen Nano.\n\n");
|
||||||
|
|
||||||
#ifdef __WIN32__
|
#ifdef __WIN32__
|
||||||
fprintf(stderr,"DISKNO is the number (e.g. 2) Windows has assigned to your ipod's hard disk.\n");
|
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,"The first hard disk in your computer (i.e. C:\\) will be disk 0, the next disk\n");
|
||||||
|
|
@ -148,7 +154,8 @@ int main(int argc, char* argv[])
|
||||||
int type;
|
int type;
|
||||||
struct ipod_t ipod;
|
struct ipod_t ipod;
|
||||||
|
|
||||||
fprintf(stderr,"ipodpatcher v" VERSION " - (C) Dave Chapman 2006-2007\n");
|
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,"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");
|
fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
|
||||||
|
|
||||||
|
|
@ -364,9 +371,9 @@ int main(int argc, char* argv[])
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getmodel(&ipod,(ipod.ipod_directory[0].vers>>8)) < 0) {
|
if (getmodel(&ipod,(ipod.ipod_directory[ipod.ososimage].vers>>8)) < 0) {
|
||||||
fprintf(stderr,"[ERR] Unknown version number in firmware (%08x)\n",
|
fprintf(stderr,"[ERR] Unknown version number in firmware (%08x)\n",
|
||||||
ipod.ipod_directory[0].vers);
|
ipod.ipod_directory[ipod.ososimage].vers);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -391,7 +398,7 @@ int main(int argc, char* argv[])
|
||||||
if (ipod.ramsize > 0) { printf("(%dMB RAM) ",ipod.ramsize); }
|
if (ipod.ramsize > 0) { printf("(%dMB RAM) ",ipod.ramsize); }
|
||||||
printf("(\"%s\")\n",ipod.macpod ? "macpod" : "winpod");
|
printf("(\"%s\")\n",ipod.macpod ? "macpod" : "winpod");
|
||||||
|
|
||||||
if (ipod.ipod_directory[0].vers == 0x10000) {
|
if (ipod.ipod_directory[ipod.ososimage].vers == 0x10000) {
|
||||||
fprintf(stderr,"[ERR] *** ipodpatcher does not support the 2nd Generation Nano! ***\n");
|
fprintf(stderr,"[ERR] *** ipodpatcher does not support the 2nd Generation Nano! ***\n");
|
||||||
#ifdef WITH_BOOTOBJS
|
#ifdef WITH_BOOTOBJS
|
||||||
printf("Press ENTER to exit ipodpatcher :");
|
printf("Press ENTER to exit ipodpatcher :");
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ platform25=ipodvideo64mb
|
||||||
platform26=ipodmini1g
|
platform26=ipodmini1g
|
||||||
platform27=ipodmini2g
|
platform27=ipodmini2g
|
||||||
platform28=ipodnano
|
platform28=ipodnano
|
||||||
|
platform29=ipodnano2g
|
||||||
platform30=iaudiox5
|
platform30=iaudiox5
|
||||||
platform31=iaudiom5
|
platform31=iaudiom5
|
||||||
platform32=iaudiox5v
|
platform32=iaudiox5v
|
||||||
|
|
@ -242,6 +243,16 @@ brand=Apple
|
||||||
configure_modelname=ipodnano
|
configure_modelname=ipodnano
|
||||||
encoder=rbspeex
|
encoder=rbspeex
|
||||||
|
|
||||||
|
[ipodnano2g]
|
||||||
|
name="Ipod Nano (2nd gen)"
|
||||||
|
buildserver_modelname=ipodnano2g
|
||||||
|
bootloadermethod=ipod
|
||||||
|
bootloadername=/ipod/bootloader-ipodnano2g.ipodx
|
||||||
|
manualname=
|
||||||
|
brand=Apple
|
||||||
|
configure_modelname=ipodnano2g
|
||||||
|
encoder=rbspeex
|
||||||
|
|
||||||
[ipod4gray]
|
[ipod4gray]
|
||||||
name="Ipod (4th gen, greyscale)"
|
name="Ipod (4th gen, greyscale)"
|
||||||
buildserver_modelname=ipod4gray
|
buildserver_modelname=ipod4gray
|
||||||
|
|
@ -527,9 +538,6 @@ usbid=0x04e85024
|
||||||
configure_modelname=yh925
|
configure_modelname=yh925
|
||||||
encoder=rbspeex
|
encoder=rbspeex
|
||||||
|
|
||||||
[05ac1260]
|
|
||||||
name="Apple Ipod Nano (Second Generation)"
|
|
||||||
|
|
||||||
[05ac1240]
|
[05ac1240]
|
||||||
name="Apple Ipod Nano (Second Generation, DFU Mode)"
|
name="Apple Ipod Nano (Second Generation, DFU Mode)"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue