diff options
author | Dave Chapman <dave@dchapman.com> | 2009-10-13 08:02:59 +0000 |
---|---|---|
committer | Dave Chapman <dave@dchapman.com> | 2009-10-13 08:02:59 +0000 |
commit | 8e95cc432935df1225a7bcc8e87e04f9f16bb643 (patch) | |
tree | cff528d4f69aed098f178236eee1ee26c759bf5e | |
parent | e486241c0143580ef81c79dbc75b69b0abbc5b2c (diff) | |
download | rockbox-8e95cc432935df1225a7bcc8e87e04f9f16bb643.tar.gz rockbox-8e95cc432935df1225a7bcc8e87e04f9f16bb643.zip |
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
-rw-r--r-- | rbutil/ipodpatcher/Makefile | 22 | ||||
-rw-r--r-- | rbutil/ipodpatcher/ipodio.h | 4 | ||||
-rw-r--r-- | rbutil/ipodpatcher/ipodpatcher.c | 503 | ||||
-rw-r--r-- | rbutil/ipodpatcher/main.c | 23 | ||||
-rw-r--r-- | rbutil/rbutilqt/rbutil.ini | 14 |
5 files changed, 531 insertions, 35 deletions
diff --git a/rbutil/ipodpatcher/Makefile b/rbutil/ipodpatcher/Makefile index 9c32587fa1..713c21b546 100644 --- a/rbutil/ipodpatcher/Makefile +++ b/rbutil/ipodpatcher/Makefile | |||
@@ -2,13 +2,26 @@ CFLAGS=-Wall -W | |||
2 | 2 | ||
3 | BOOT_H = ipod1g2g.h ipod3g.h ipod4g.h ipodcolor.h ipodmini.h ipodmini2g.h ipodnano.h ipodvideo.h | 3 | BOOT_H = ipod1g2g.h ipod3g.h ipod4g.h ipodcolor.h ipodmini.h ipodmini2g.h ipodnano.h ipodvideo.h |
4 | 4 | ||
5 | # Uncomment the next two lines to build with embedded bootloaders and the | 5 | # Enable the next two lines to build with embedded bootloaders and the |
6 | # --install option and interactive mode. You need the full set of Rockbox | 6 | # --install option and interactive mode. You need the full set of Rockbox |
7 | # bootloaders in this directory - download them from | 7 | # bootloaders in this directory - download them from |
8 | # http://download.rockbox.org/bootloader/ipod/bootloaders.zip | 8 | # http://download.rockbox.org/bootloader/ipod/bootloaders.zip |
9 | 9 | ||
10 | #BOOTSRC = ipod1g2g.c ipod3g.c ipod4g.c ipodcolor.c ipodmini.c ipodmini2g.c ipodnano.c ipodvideo.c | 10 | ifdef RELEASE |
11 | #CFLAGS += -DWITH_BOOTOBJS | 11 | CFLAGS+=-DRELEASE |
12 | BOOTOBJS=1 | ||
13 | endif | ||
14 | |||
15 | ifdef BOOTOBJS | ||
16 | BOOTSRC = ipod1g2g.c ipod3g.c ipod4g.c ipodcolor.c ipodmini.c ipodmini2g.c ipodnano.c ipodvideo.c ipodnano2g.c | ||
17 | CFLAGS += -DWITH_BOOTOBJS | ||
18 | endif | ||
19 | |||
20 | ifndef VERSION | ||
21 | VERSION=$(shell ../../tools/version.sh) | ||
22 | endif | ||
23 | |||
24 | CFLAGS+=-DVERSION=\"$(VERSION)\" | ||
12 | 25 | ||
13 | ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN) | 26 | ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN) |
14 | OUTPUT=ipodpatcher.exe | 27 | OUTPUT=ipodpatcher.exe |
@@ -81,6 +94,9 @@ ipodnano.c: bootloader-ipodnano.ipod ipod2c | |||
81 | ipodvideo.c: bootloader-ipodvideo.ipod ipod2c | 94 | ipodvideo.c: bootloader-ipodvideo.ipod ipod2c |
82 | ./ipod2c bootloader-ipodvideo.ipod ipodvideo | 95 | ./ipod2c bootloader-ipodvideo.ipod ipodvideo |
83 | 96 | ||
97 | ipodnano2g.c: bootloader-ipodnano2g.ipodx ipod2c | ||
98 | ./ipod2c bootloader-ipodnano2g.ipodx ipodnano2g | ||
99 | |||
84 | 100 | ||
85 | clean: | 101 | clean: |
86 | rm -f ipodpatcher.exe ipodpatcher-rc.o ipodpatcher-mac ipodpatcher-i386 ipodpatcher-ppc ipodpatcher ipod2c *~ $(BOOTSRC) $(BOOT_H) | 102 | rm -f ipodpatcher.exe ipodpatcher-rc.o ipodpatcher-mac ipodpatcher-i386 ipodpatcher-ppc ipodpatcher ipod2c *~ $(BOOTSRC) $(BOOT_H) |
diff --git a/rbutil/ipodpatcher/ipodio.h b/rbutil/ipodpatcher/ipodio.h index e0692ca6d9..5c098ab60c 100644 --- a/rbutil/ipodpatcher/ipodio.h +++ b/rbutil/ipodpatcher/ipodio.h | |||
@@ -39,7 +39,8 @@ enum firmwaretype_t { | |||
39 | FTYPE_OSOS = 0, | 39 | FTYPE_OSOS = 0, |
40 | FTYPE_RSRC, | 40 | FTYPE_RSRC, |
41 | FTYPE_AUPD, | 41 | FTYPE_AUPD, |
42 | FTYPE_HIBE | 42 | FTYPE_HIBE, |
43 | FTYPE_OSBK | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | struct ipod_directory_t { | 46 | struct ipod_directory_t { |
@@ -71,6 +72,7 @@ struct ipod_t { | |||
71 | int num_heads; | 72 | int num_heads; |
72 | struct ipod_directory_t ipod_directory[MAX_IMAGES]; | 73 | struct ipod_directory_t ipod_directory[MAX_IMAGES]; |
73 | int nimages; | 74 | int nimages; |
75 | int ososimage; | ||
74 | off_t diroffset; | 76 | off_t diroffset; |
75 | off_t start; /* Offset in bytes of firmware partition from start of disk */ | 77 | off_t start; /* Offset in bytes of firmware partition from start of disk */ |
76 | off_t fwoffset; /* Offset in bytes of start of firmware images from start of disk */ | 78 | off_t fwoffset; /* Offset in bytes of start of firmware images from start of disk */ |
diff --git a/rbutil/ipodpatcher/ipodpatcher.c b/rbutil/ipodpatcher/ipodpatcher.c index 79357fde06..7116056350 100644 --- a/rbutil/ipodpatcher/ipodpatcher.c +++ b/rbutil/ipodpatcher/ipodpatcher.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include "ipodcolor.h" | 42 | #include "ipodcolor.h" |
43 | #include "ipodnano.h" | 43 | #include "ipodnano.h" |
44 | #include "ipodvideo.h" | 44 | #include "ipodvideo.h" |
45 | #include "ipodnano2g.h" | ||
45 | #endif | 46 | #endif |
46 | 47 | ||
47 | #ifndef RBUTIL | 48 | #ifndef RBUTIL |
@@ -389,7 +390,7 @@ int write_partition(struct ipod_t* ipod, int infile) | |||
389 | return 0; | 390 | return 0; |
390 | } | 391 | } |
391 | 392 | ||
392 | char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE" }; | 393 | char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE", "OSBK" }; |
393 | 394 | ||
394 | int diskmove(struct ipod_t* ipod, int delta) | 395 | int diskmove(struct ipod_t* ipod, int delta) |
395 | { | 396 | { |
@@ -470,6 +471,409 @@ int diskmove(struct ipod_t* ipod, int delta) | |||
470 | return 0; | 471 | return 0; |
471 | } | 472 | } |
472 | 473 | ||
474 | static int rename_image(struct ipod_t* ipod, char* from, char* to) | ||
475 | { | ||
476 | int n; | ||
477 | int x; | ||
478 | int found; | ||
479 | int i; | ||
480 | unsigned char* p; | ||
481 | |||
482 | /* diroffset may not be sector-aligned */ | ||
483 | x = ipod->diroffset % ipod->sector_size; | ||
484 | |||
485 | /* Read directory */ | ||
486 | if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { | ||
487 | fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset); | ||
488 | return -1; | ||
489 | } | ||
490 | |||
491 | n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size); | ||
492 | if (n < 0) { | ||
493 | fprintf(stderr,"[ERR] Read of directory failed.\n"); | ||
494 | return -1; | ||
495 | } | ||
496 | |||
497 | p = ipod_sectorbuf + x; | ||
498 | |||
499 | /* A hack to detect 2nd gen Nanos - maybe there is a better way? */ | ||
500 | if (p[0] == 0) | ||
501 | { | ||
502 | /* Adjust diroffset */ | ||
503 | ipod->diroffset += ipod->sector_size - x; | ||
504 | |||
505 | n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size); | ||
506 | if (n < 0) { | ||
507 | fprintf(stderr,"[ERR] Read of directory failed.\n"); | ||
508 | return -1; | ||
509 | } | ||
510 | p = ipod_sectorbuf; | ||
511 | } | ||
512 | |||
513 | found = 0; | ||
514 | for (i=0 ; !found && i < MAX_IMAGES; i++) { | ||
515 | if (memcmp(p + 4, from, 4) == 0) { | ||
516 | memcpy(p + 4, to, 4); | ||
517 | |||
518 | found = 1; | ||
519 | } | ||
520 | p += 40; | ||
521 | } | ||
522 | |||
523 | if (!found) { | ||
524 | fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", from); | ||
525 | return -1; | ||
526 | } | ||
527 | |||
528 | /* Write directory back to disk */ | ||
529 | if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { | ||
530 | fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset); | ||
531 | return -1; | ||
532 | } | ||
533 | |||
534 | n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size); | ||
535 | if (n < 0) { | ||
536 | fprintf(stderr,"[ERR] Write of directory failed in rename_image.\n"); | ||
537 | return -1; | ||
538 | } | ||
539 | |||
540 | return 0; | ||
541 | } | ||
542 | |||
543 | static int delete_image(struct ipod_t* ipod, char* name) | ||
544 | { | ||
545 | int n; | ||
546 | int x; | ||
547 | int found; | ||
548 | int i; | ||
549 | unsigned char* p; | ||
550 | |||
551 | /* diroffset may not be sector-aligned */ | ||
552 | x = ipod->diroffset % ipod->sector_size; | ||
553 | |||
554 | /* Read directory */ | ||
555 | if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { | ||
556 | fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset); | ||
557 | return -1; | ||
558 | } | ||
559 | |||
560 | n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size); | ||
561 | if (n < 0) { | ||
562 | fprintf(stderr,"[ERR] Read of directory failed.\n"); | ||
563 | return -1; | ||
564 | } | ||
565 | |||
566 | p = ipod_sectorbuf + x; | ||
567 | |||
568 | /* A hack to detect 2nd gen Nanos - maybe there is a better way? */ | ||
569 | if (p[0] == 0) | ||
570 | { | ||
571 | /* Adjust diroffset */ | ||
572 | ipod->diroffset += ipod->sector_size - x; | ||
573 | |||
574 | n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size); | ||
575 | if (n < 0) { | ||
576 | fprintf(stderr,"[ERR] Read of directory failed.\n"); | ||
577 | return -1; | ||
578 | } | ||
579 | p = ipod_sectorbuf; | ||
580 | } | ||
581 | |||
582 | found = 0; | ||
583 | for (i=0 ; !found && i < MAX_IMAGES; i++) { | ||
584 | if (memcmp(p + 4, name, 4) == 0) { | ||
585 | memset(p, 0, 40); /* Delete directory entry */ | ||
586 | found = 1; | ||
587 | } | ||
588 | p += 40; | ||
589 | } | ||
590 | |||
591 | if (!found) { | ||
592 | fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", name); | ||
593 | return -1; | ||
594 | } | ||
595 | |||
596 | /* Write directory back to disk */ | ||
597 | if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { | ||
598 | fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset); | ||
599 | return -1; | ||
600 | } | ||
601 | |||
602 | n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size); | ||
603 | if (n < 0) { | ||
604 | fprintf(stderr,"[ERR] Write of directory failed in delete_image.\n"); | ||
605 | return -1; | ||
606 | } | ||
607 | |||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | int add_new_image(struct ipod_t* ipod, char* imagename, char* filename, int type) | ||
612 | { | ||
613 | int length; | ||
614 | int found; | ||
615 | int i; | ||
616 | int x; | ||
617 | int n; | ||
618 | int infile; | ||
619 | int newsize; | ||
620 | unsigned long chksum=0; | ||
621 | unsigned long filechksum=0; | ||
622 | unsigned long offset; | ||
623 | unsigned char header[8]; /* Header for .ipod file */ | ||
624 | unsigned char* p; | ||
625 | |||
626 | #ifdef WITH_BOOTOBJS | ||
627 | if (type == FILETYPE_INTERNAL) { | ||
628 | fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len); | ||
629 | length = ipod->bootloader_len; | ||
630 | infile = -1; | ||
631 | } | ||
632 | else | ||
633 | #endif | ||
634 | { | ||
635 | /* First check that the input file is the correct type for this ipod. */ | ||
636 | infile=open(filename,O_RDONLY); | ||
637 | if (infile < 0) { | ||
638 | fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename); | ||
639 | return -1; | ||
640 | } | ||
641 | |||
642 | if (type==FILETYPE_DOT_IPOD) { | ||
643 | n = read(infile,header,8); | ||
644 | if (n < 8) { | ||
645 | fprintf(stderr,"[ERR] Failed to read header from %s\n",filename); | ||
646 | close(infile); | ||
647 | return -1; | ||
648 | } | ||
649 | |||
650 | if (memcmp(header+4, ipod->modelname,4)!=0) { | ||
651 | fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n", | ||
652 | header[4],header[5],header[6],header[7], ipod->modelname); | ||
653 | close(infile); | ||
654 | return -1; | ||
655 | } | ||
656 | |||
657 | filechksum = be2int(header); | ||
658 | |||
659 | length = filesize(infile)-8; | ||
660 | } else { | ||
661 | length = filesize(infile); | ||
662 | } | ||
663 | } | ||
664 | |||
665 | newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1); | ||
666 | |||
667 | fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n", | ||
668 | length,newsize); | ||
669 | |||
670 | if (newsize > BUFFER_SIZE) { | ||
671 | fprintf(stderr,"[ERR] Input file too big for buffer\n"); | ||
672 | if (infile >= 0) close(infile); | ||
673 | return -1; | ||
674 | } | ||
675 | |||
676 | /* TODO: Check if we have enough space in the partition for the new image */ | ||
677 | |||
678 | #ifdef WITH_BOOTOBJS | ||
679 | if (type == FILETYPE_INTERNAL) { | ||
680 | memcpy(ipod_sectorbuf,ipod->bootloader,ipod->bootloader_len); | ||
681 | } | ||
682 | else | ||
683 | #endif | ||
684 | { | ||
685 | fprintf(stderr,"[INFO] Reading input file...\n"); | ||
686 | |||
687 | n = read(infile,ipod_sectorbuf,length); | ||
688 | if (n < 0) { | ||
689 | fprintf(stderr,"[ERR] Couldn't read input file\n"); | ||
690 | close(infile); | ||
691 | return -1; | ||
692 | } | ||
693 | close(infile); | ||
694 | } | ||
695 | |||
696 | /* Pad the data with zeros */ | ||
697 | memset(ipod_sectorbuf+length,0,newsize-length); | ||
698 | |||
699 | if (type==FILETYPE_DOT_IPOD) { | ||
700 | chksum = ipod->modelnum; | ||
701 | for (i = 0; i < length; i++) { | ||
702 | /* add 8 unsigned bits but keep a 32 bit sum */ | ||
703 | chksum += ipod_sectorbuf[i]; | ||
704 | } | ||
705 | |||
706 | if (chksum == filechksum) { | ||
707 | fprintf(stderr,"[INFO] Checksum OK in %s\n",filename); | ||
708 | } else { | ||
709 | fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename); | ||
710 | return -1; | ||
711 | } | ||
712 | } | ||
713 | |||
714 | |||
715 | offset = ipod->fwoffset + ipod->ipod_directory[ipod->nimages - 1].devOffset + | ||
716 | ipod->ipod_directory[ipod->nimages - 1].len + ipod->sector_size; | ||
717 | |||
718 | /* 2nd Gen Nano has encrypted firmware, and the sector | ||
719 | preceeding the firmware contains hashes that need to be | ||
720 | preserved. Nano 2G images include these extra 2048 (0x800) | ||
721 | bytes | ||
722 | */ | ||
723 | if (ipod_seek(ipod, offset - (ipod->modelnum == 62 ? 0x800 : 0)) < 0) { | ||
724 | fprintf(stderr,"[ERR] Seek failed\n"); | ||
725 | return -1; | ||
726 | } | ||
727 | |||
728 | if ((n = ipod_write(ipod,ipod_sectorbuf,newsize)) < 0) { | ||
729 | perror("[ERR] Write failed\n"); | ||
730 | return -1; | ||
731 | } | ||
732 | |||
733 | if (n < newsize) { | ||
734 | fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n" | ||
735 | ,newsize,n); | ||
736 | return -1; | ||
737 | } | ||
738 | fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n); | ||
739 | |||
740 | /* Now we need to create a new directory entry | ||
741 | |||
742 | NOTE: On the Nano 2G, the checksum is the checksum of the | ||
743 | unencrypted firmware. But this isn't checked by the NOR | ||
744 | bootloader (there are cryptographic hashes in the | ||
745 | firmware itself), so it doesn't matter that this is | ||
746 | wrong. | ||
747 | */ | ||
748 | chksum = 0; | ||
749 | for (i = 0; i < length; i++) { | ||
750 | /* add 8 unsigned bits but keep a 32 bit sum */ | ||
751 | chksum += ipod_sectorbuf[i]; | ||
752 | } | ||
753 | |||
754 | x = ipod->diroffset % ipod->sector_size; | ||
755 | |||
756 | /* Read directory */ | ||
757 | if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } | ||
758 | |||
759 | n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size); | ||
760 | if (n < 0) { return -1; } | ||
761 | |||
762 | /* Create a new directory entry */ | ||
763 | |||
764 | /* Copy OSOS or OSBK details - we assume one of them exists */ | ||
765 | p = ipod_sectorbuf + x; | ||
766 | found = 0; | ||
767 | for (i = 0; !found && i < ipod->nimages; i++) { | ||
768 | if ((memcmp(p + 4, "soso", 4)==0) || (memcmp(p + 4, "kbso", 4)==0)) { | ||
769 | found = 1; | ||
770 | } else { | ||
771 | p += 40; | ||
772 | } | ||
773 | } | ||
774 | |||
775 | if (!found) { | ||
776 | fprintf(stderr,"[ERR] No OSOS or OSBK image to copy directory from\n"); | ||
777 | return -1; | ||
778 | } | ||
779 | |||
780 | /* Copy directory image */ | ||
781 | memcpy(ipod_sectorbuf + x + (ipod->nimages * 40), p, 40); | ||
782 | p = ipod_sectorbuf + x + (ipod->nimages * 40); | ||
783 | |||
784 | /* Modify directory. */ | ||
785 | memcpy(p + 4, imagename, 4); | ||
786 | int2le(offset - ipod->fwoffset, p + 12); /* devOffset */ | ||
787 | int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16); /* len */ | ||
788 | int2le(chksum, p + 28); /* checksum */ | ||
789 | |||
790 | /* Write directory */ | ||
791 | if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } | ||
792 | n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size); | ||
793 | if (n < 0) { return -1; } | ||
794 | |||
795 | return 0; | ||
796 | } | ||
797 | |||
798 | |||
799 | /* | ||
800 | Bootloader installation on the Nano2G consists of renaming the | ||
801 | OSOS image to OSBK and then writing the Rockbox bootloader as a | ||
802 | new OSOS image. | ||
803 | |||
804 | Maybe this approach can/should be adapted for other ipods, as it | ||
805 | prevents the Apple bootloader loading the original firmware into | ||
806 | RAM along with the Rockbox bootloader (and hence will give a | ||
807 | faster boot when the user just wants to start Rockbox). | ||
808 | |||
809 | */ | ||
810 | |||
811 | static int add_bootloader_nano2g(struct ipod_t* ipod, char* filename, int type) | ||
812 | { | ||
813 | int i; | ||
814 | int has_osbk = 0; | ||
815 | |||
816 | /* Check if we already have an OSBK image */ | ||
817 | for (i = 0; i < ipod->nimages; i++) { | ||
818 | if (ipod->ipod_directory[i].ftype==FTYPE_OSBK) { | ||
819 | has_osbk = 1; | ||
820 | } | ||
821 | } | ||
822 | |||
823 | if (has_osbk == 0) { | ||
824 | /* First-time install - rename OSOS to OSBK and create new OSOS for bootloader */ | ||
825 | fprintf(stderr,"[INFO] Creating OSBK backup image of original firmware\n"); | ||
826 | |||
827 | if (rename_image(ipod, "soso", "kbso") < 0) { | ||
828 | fprintf(stderr,"[ERR] Could not rename OSOS image\n"); | ||
829 | return -1; | ||
830 | } | ||
831 | |||
832 | /* Add our bootloader as a brand new image */ | ||
833 | return add_new_image(ipod, "soso", filename, type); | ||
834 | } else { | ||
835 | /* This is an update, just replace OSOS with our bootloader */ | ||
836 | |||
837 | return write_firmware(ipod, filename, type); | ||
838 | } | ||
839 | } | ||
840 | |||
841 | |||
842 | static int delete_bootloader_nano2g(struct ipod_t* ipod) | ||
843 | { | ||
844 | int i; | ||
845 | int has_osbk = 0; | ||
846 | |||
847 | /* Check if we have an OSBK image */ | ||
848 | for (i = 0; i < ipod->nimages; i++) { | ||
849 | if (ipod->ipod_directory[i].ftype==FTYPE_OSBK) { | ||
850 | has_osbk = 1; | ||
851 | } | ||
852 | } | ||
853 | |||
854 | if (has_osbk == 0) { | ||
855 | fprintf(stderr,"[ERR] No OSBK image found - nothing to uninstall\n"); | ||
856 | return -1; | ||
857 | } else { | ||
858 | /* Delete our bootloader image */ | ||
859 | if (delete_image(ipod, "soso") < 0) { | ||
860 | fprintf(stderr,"[WARN] Could not delete OSOS image\n"); | ||
861 | } else { | ||
862 | fprintf(stderr,"[INFO] OSOS image deleted\n"); | ||
863 | } | ||
864 | |||
865 | if (rename_image(ipod, "kbso", "soso") < 0) { | ||
866 | fprintf(stderr,"[ERR] Could not rename OSBK image\n"); | ||
867 | return -1; | ||
868 | } | ||
869 | |||
870 | |||
871 | fprintf(stderr,"[INFO] OSBK image renamed to OSOS - bootloader uninstalled.\n"); | ||
872 | return 0; | ||
873 | } | ||
874 | } | ||
875 | |||
876 | |||
473 | int add_bootloader(struct ipod_t* ipod, char* filename, int type) | 877 | int add_bootloader(struct ipod_t* ipod, char* filename, int type) |
474 | { | 878 | { |
475 | int length; | 879 | int length; |
@@ -485,6 +889,11 @@ int add_bootloader(struct ipod_t* ipod, char* filename, int type) | |||
485 | unsigned char header[8]; /* Header for .ipod file */ | 889 | unsigned char header[8]; /* Header for .ipod file */ |
486 | unsigned char* bootloader_buf; | 890 | unsigned char* bootloader_buf; |
487 | 891 | ||
892 | /* The 2nd gen Nano is installed differently */ | ||
893 | if (ipod->modelnum == 62) { | ||
894 | return add_bootloader_nano2g(ipod, filename, type); | ||
895 | } | ||
896 | |||
488 | /* Calculate the position in the OSOS image where our bootloader will go. */ | 897 | /* Calculate the position in the OSOS image where our bootloader will go. */ |
489 | if (ipod->ipod_directory[0].entryOffset>0) { | 898 | if (ipod->ipod_directory[0].entryOffset>0) { |
490 | /* Keep the same entryOffset */ | 899 | /* Keep the same entryOffset */ |
@@ -698,6 +1107,11 @@ int delete_bootloader(struct ipod_t* ipod) | |||
698 | int n; | 1107 | int n; |
699 | unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/ | 1108 | unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/ |
700 | 1109 | ||
1110 | /* The 2nd gen Nano is installed differently */ | ||
1111 | if (ipod->modelnum == 62) { | ||
1112 | return delete_bootloader_nano2g(ipod); | ||
1113 | } | ||
1114 | |||
701 | /* Removing the bootloader involves adjusting the "length", | 1115 | /* Removing the bootloader involves adjusting the "length", |
702 | "chksum" and "entryOffset" values in the osos image's directory | 1116 | "chksum" and "entryOffset" values in the osos image's directory |
703 | entry. */ | 1117 | entry. */ |
@@ -774,7 +1188,9 @@ int write_firmware(struct ipod_t* ipod, char* filename, int type) | |||
774 | int bytesavailable; | 1188 | int bytesavailable; |
775 | unsigned long chksum=0; | 1189 | unsigned long chksum=0; |
776 | unsigned long filechksum=0; | 1190 | unsigned long filechksum=0; |
1191 | unsigned long offset; | ||
777 | unsigned char header[8]; /* Header for .ipod file */ | 1192 | unsigned char header[8]; /* Header for .ipod file */ |
1193 | unsigned char* p; | ||
778 | 1194 | ||
779 | #ifdef WITH_BOOTOBJS | 1195 | #ifdef WITH_BOOTOBJS |
780 | if (type == FILETYPE_INTERNAL) { | 1196 | if (type == FILETYPE_INTERNAL) { |
@@ -876,7 +1292,23 @@ int write_firmware(struct ipod_t* ipod, char* filename, int type) | |||
876 | } | 1292 | } |
877 | } | 1293 | } |
878 | 1294 | ||
879 | if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) { | 1295 | |
1296 | offset = ipod->fwoffset+ipod->ipod_directory[ipod->ososimage].devOffset; | ||
1297 | |||
1298 | if (ipod->modelnum==62) { | ||
1299 | |||
1300 | /* 2nd Gen Nano has encrypted firmware, and the sector | ||
1301 | preceeding the firmware contains hashes that need to be | ||
1302 | preserved. Nano 2G images include these extra 2048 (0x800) | ||
1303 | bytes | ||
1304 | */ | ||
1305 | |||
1306 | offset -= 0x800; | ||
1307 | |||
1308 | /* TODO: The above checks need to take into account this 0x800 bytes */ | ||
1309 | } | ||
1310 | |||
1311 | if (ipod_seek(ipod, offset) < 0) { | ||
880 | fprintf(stderr,"[ERR] Seek failed\n"); | 1312 | fprintf(stderr,"[ERR] Seek failed\n"); |
881 | return -1; | 1313 | return -1; |
882 | } | 1314 | } |
@@ -893,7 +1325,14 @@ int write_firmware(struct ipod_t* ipod, char* filename, int type) | |||
893 | } | 1325 | } |
894 | fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n); | 1326 | fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n); |
895 | 1327 | ||
896 | /* Now we need to update the "len", "entryOffset" and "chksum" fields */ | 1328 | /* Now we need to update the "len", "entryOffset" and "chksum" fields |
1329 | |||
1330 | NOTE: On the Nano 2G, the checksum is the checksum of the | ||
1331 | unencrypted firmware. But this isn't checked by the NOR | ||
1332 | bootloader (there are cryptographic hashes in the | ||
1333 | firmware itself), so it doesn't matter that this is | ||
1334 | wrong. | ||
1335 | */ | ||
897 | chksum = 0; | 1336 | chksum = 0; |
898 | for (i = 0; i < length; i++) { | 1337 | for (i = 0; i < length; i++) { |
899 | /* add 8 unsigned bits but keep a 32 bit sum */ | 1338 | /* 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) | |||
908 | n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size); | 1347 | n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size); |
909 | if (n < 0) { return -1; } | 1348 | if (n < 0) { return -1; } |
910 | 1349 | ||
911 | /* Update entries for image 0 */ | 1350 | /* Update entries for image */ |
912 | int2le(length,ipod_sectorbuf+x+16); | 1351 | p = ipod_sectorbuf + x + (ipod->ososimage * 40); |
913 | int2le(0,ipod_sectorbuf+x+24); | 1352 | int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16); |
914 | int2le(chksum,ipod_sectorbuf+x+28); | 1353 | int2le(0, p + 24); |
1354 | int2le(chksum, p + 28); | ||
915 | 1355 | ||
916 | /* Write directory */ | 1356 | /* Write directory */ |
917 | if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } | 1357 | 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) | |||
927 | int i; | 1367 | int i; |
928 | int outfile; | 1368 | int outfile; |
929 | int n; | 1369 | int n; |
1370 | unsigned long offset; | ||
930 | unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/ | 1371 | unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/ |
931 | unsigned char header[8]; /* Header for .ipod file */ | 1372 | unsigned char header[8]; /* Header for .ipod file */ |
932 | 1373 | ||
933 | if (ipod->ipod_directory[0].entryOffset != 0) { | 1374 | if (ipod->ipod_directory[ipod->ososimage].entryOffset != 0) { |
934 | /* We have a bootloader... */ | 1375 | /* We have a bootloader... */ |
935 | length = ipod->ipod_directory[0].entryOffset; | 1376 | length = ipod->ipod_directory[ipod->ososimage].entryOffset; |
936 | } else { | 1377 | } else { |
937 | length = ipod->ipod_directory[0].len; | 1378 | length = ipod->ipod_directory[ipod->ososimage].len; |
938 | } | 1379 | } |
939 | 1380 | ||
940 | fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length); | 1381 | fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length); |
941 | 1382 | ||
942 | if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) { | 1383 | offset = ipod->fwoffset + ipod->ipod_directory[ipod->ososimage].devOffset; |
943 | return -1; | ||
944 | } | ||
945 | |||
946 | i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1); | 1384 | i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1); |
947 | fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n", | 1385 | fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n", |
948 | length,i); | 1386 | length,i); |
949 | 1387 | ||
1388 | if (ipod->modelnum==62) { | ||
1389 | /* 2nd Gen Nano has encrypted firmware, and we need to dump the | ||
1390 | sector preceeding the image - it contains hashes */ | ||
1391 | offset -= 0x800; | ||
1392 | length += 0x800; | ||
1393 | i += 0x800; | ||
1394 | } | ||
1395 | |||
1396 | if (ipod_seek(ipod, offset)) { | ||
1397 | return -1; | ||
1398 | } | ||
1399 | |||
950 | if ((n = ipod_read(ipod,ipod_sectorbuf,i)) < 0) { | 1400 | if ((n = ipod_read(ipod,ipod_sectorbuf,i)) < 0) { |
951 | return -1; | 1401 | return -1; |
952 | } | 1402 | } |
@@ -1049,6 +1499,9 @@ int read_directory(struct ipod_t* ipod) | |||
1049 | /* A hack to detect 2nd gen Nanos - maybe there is a better way? */ | 1499 | /* A hack to detect 2nd gen Nanos - maybe there is a better way? */ |
1050 | if (p[0] == 0) | 1500 | if (p[0] == 0) |
1051 | { | 1501 | { |
1502 | /* Adjust diroffset */ | ||
1503 | ipod->diroffset += ipod->sector_size - x; | ||
1504 | |||
1052 | n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size); | 1505 | n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size); |
1053 | if (n < 0) { | 1506 | if (n < 0) { |
1054 | fprintf(stderr,"[ERR] Read of directory failed.\n"); | 1507 | fprintf(stderr,"[ERR] Read of directory failed.\n"); |
@@ -1057,15 +1510,19 @@ int read_directory(struct ipod_t* ipod) | |||
1057 | p = ipod_sectorbuf; | 1510 | p = ipod_sectorbuf; |
1058 | } | 1511 | } |
1059 | 1512 | ||
1513 | ipod->ososimage = -1; | ||
1060 | while ((ipod->nimages < MAX_IMAGES) && (p < (ipod_sectorbuf + x + 400)) && | 1514 | while ((ipod->nimages < MAX_IMAGES) && (p < (ipod_sectorbuf + x + 400)) && |
1061 | ((memcmp(p,"!ATA",4)==0) || (memcmp(p,"DNAN",4)==0))) { | 1515 | ((memcmp(p,"!ATA",4)==0) || (memcmp(p,"DNAN",4)==0))) { |
1062 | p+=4; | 1516 | p+=4; |
1063 | if (memcmp(p,"soso",4)==0) { | 1517 | if (memcmp(p,"soso",4)==0) { |
1064 | ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS; | 1518 | ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS; |
1519 | ipod->ososimage = ipod->nimages; | ||
1065 | } else if (memcmp(p,"crsr",4)==0) { | 1520 | } else if (memcmp(p,"crsr",4)==0) { |
1066 | ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC; | 1521 | ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC; |
1067 | } else if (memcmp(p,"dpua",4)==0) { | 1522 | } else if (memcmp(p,"dpua",4)==0) { |
1068 | ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD; | 1523 | ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD; |
1524 | } else if (memcmp(p,"kbso",4)==0) { | ||
1525 | ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSBK; | ||
1069 | } else if (memcmp(p,"ebih",4)==0) { | 1526 | } else if (memcmp(p,"ebih",4)==0) { |
1070 | ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE; | 1527 | ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE; |
1071 | } else { | 1528 | } else { |
@@ -1092,12 +1549,17 @@ int read_directory(struct ipod_t* ipod) | |||
1092 | ipod->nimages++; | 1549 | ipod->nimages++; |
1093 | } | 1550 | } |
1094 | 1551 | ||
1552 | if (ipod->ososimage < 0) { | ||
1553 | fprintf(stderr,"[ERR] No OSOS image found.\n"); | ||
1554 | return -1; | ||
1555 | } | ||
1556 | |||
1095 | if ((ipod->nimages > 1) && (version==2)) { | 1557 | if ((ipod->nimages > 1) && (version==2)) { |
1096 | /* The 3g firmware image doesn't appear to have a version, so | 1558 | /* The 3g firmware image doesn't appear to have a version, so |
1097 | let's make one up... Note that this is never written back to the | 1559 | let's make one up... Note that this is never written back to the |
1098 | ipod, so it's OK to do. */ | 1560 | ipod, so it's OK to do. */ |
1099 | 1561 | ||
1100 | if (ipod->ipod_directory[0].vers == 0) { ipod->ipod_directory[0].vers = 3; } | 1562 | if (ipod->ipod_directory[ipod->ososimage].vers == 0) { ipod->ipod_directory[ipod->ososimage].vers = 3; } |
1101 | 1563 | ||
1102 | ipod->fwoffset = ipod->start; | 1564 | ipod->fwoffset = ipod->start; |
1103 | } else { | 1565 | } else { |
@@ -1247,11 +1709,12 @@ int getmodel(struct ipod_t* ipod, int ipod_version) | |||
1247 | break; | 1709 | break; |
1248 | case 0x100: | 1710 | case 0x100: |
1249 | ipod->modelstr="2nd Generation Nano"; | 1711 | ipod->modelstr="2nd Generation Nano"; |
1250 | ipod->modelnum = 0; | 1712 | ipod->modelnum = 62; |
1251 | ipod->targetname = NULL; | 1713 | ipod->modelname = "nn2x"; |
1714 | ipod->targetname = "ipodnano2g"; | ||
1252 | #ifdef WITH_BOOTOBJS | 1715 | #ifdef WITH_BOOTOBJS |
1253 | ipod->bootloader = NULL; | 1716 | ipod->bootloader = ipodnano2g; |
1254 | ipod->bootloader_len = 0; | 1717 | ipod->bootloader_len = LEN_ipodnano2g; |
1255 | #endif | 1718 | #endif |
1256 | break; | 1719 | break; |
1257 | default: | 1720 | default: |
@@ -1316,7 +1779,7 @@ int ipod_scan(struct ipod_t* ipod) | |||
1316 | continue; | 1779 | continue; |
1317 | } | 1780 | } |
1318 | 1781 | ||
1319 | ipod_version=(ipod->ipod_directory[0].vers>>8); | 1782 | ipod_version=(ipod->ipod_directory[ipod->ososimage].vers>>8); |
1320 | /* Windows requires the ipod in R/W mode for SCSI Inquiry */ | 1783 | /* Windows requires the ipod in R/W mode for SCSI Inquiry */ |
1321 | ipod->ramsize = 0; | 1784 | ipod->ramsize = 0; |
1322 | ipod_reopen_rw(ipod); | 1785 | ipod_reopen_rw(ipod); |
diff --git a/rbutil/ipodpatcher/main.c b/rbutil/ipodpatcher/main.c index 1dcb916240..e1002b23c9 100644 --- a/rbutil/ipodpatcher/main.c +++ b/rbutil/ipodpatcher/main.c | |||
@@ -31,7 +31,11 @@ | |||
31 | #include "ipodpatcher.h" | 31 | #include "ipodpatcher.h" |
32 | #include "ipodio.h" | 32 | #include "ipodio.h" |
33 | 33 | ||
34 | #define VERSION "3.0 with v3.0 bootloaders" | 34 | #ifdef RELEASE |
35 | #undef VERSION | ||
36 | #define VERSION "4.0 with v3.0 bootloaders (v1.0 for 2nd Gen Nano)" | ||
37 | #endif | ||
38 | |||
35 | 39 | ||
36 | enum { | 40 | enum { |
37 | NONE, | 41 | NONE, |
@@ -80,14 +84,14 @@ void print_usage(void) | |||
80 | fprintf(stderr," -l, --list\n"); | 84 | fprintf(stderr," -l, --list\n"); |
81 | fprintf(stderr," -r, --read-partition bootpartition.bin\n"); | 85 | fprintf(stderr," -r, --read-partition bootpartition.bin\n"); |
82 | fprintf(stderr," -w, --write-partition bootpartition.bin\n"); | 86 | fprintf(stderr," -w, --write-partition bootpartition.bin\n"); |
83 | fprintf(stderr," -rf, --read-firmware filename.ipod\n"); | 87 | fprintf(stderr," -rf, --read-firmware filename.ipod[x]\n"); |
84 | fprintf(stderr," -rfb, --read-firmware-bin filename.bin\n"); | 88 | fprintf(stderr," -rfb, --read-firmware-bin filename.bin\n"); |
85 | fprintf(stderr," -wf, --write-firmware filename.ipod\n"); | 89 | fprintf(stderr," -wf, --write-firmware filename.ipod[x]\n"); |
86 | fprintf(stderr," -wfb, --write-firmware-bin filename.bin\n"); | 90 | fprintf(stderr," -wfb, --write-firmware-bin filename.bin\n"); |
87 | #ifdef WITH_BOOTOBJS | 91 | #ifdef WITH_BOOTOBJS |
88 | fprintf(stderr," -we, --write-embedded\n"); | 92 | fprintf(stderr," -we, --write-embedded\n"); |
89 | #endif | 93 | #endif |
90 | fprintf(stderr," -a, --add-bootloader filename.ipod\n"); | 94 | fprintf(stderr," -a, --add-bootloader filename.ipod[x]\n"); |
91 | fprintf(stderr," -ab, --add-bootloader-bin filename.bin\n"); | 95 | fprintf(stderr," -ab, --add-bootloader-bin filename.bin\n"); |
92 | fprintf(stderr," -d, --delete-bootloader\n"); | 96 | fprintf(stderr," -d, --delete-bootloader\n"); |
93 | fprintf(stderr," -f, --format\n"); | 97 | fprintf(stderr," -f, --format\n"); |
@@ -97,6 +101,8 @@ void print_usage(void) | |||
97 | fprintf(stderr," -x --dump-xml filename.xml\n"); | 101 | fprintf(stderr," -x --dump-xml filename.xml\n"); |
98 | fprintf(stderr,"\n"); | 102 | fprintf(stderr,"\n"); |
99 | 103 | ||
104 | fprintf(stderr,"The .ipodx extension is used for encrypted images for the 2nd Gen Nano.\n\n"); | ||
105 | |||
100 | #ifdef __WIN32__ | 106 | #ifdef __WIN32__ |
101 | fprintf(stderr,"DISKNO is the number (e.g. 2) Windows has assigned to your ipod's hard disk.\n"); | 107 | fprintf(stderr,"DISKNO is the number (e.g. 2) Windows has assigned to your ipod's hard disk.\n"); |
102 | fprintf(stderr,"The first hard disk in your computer (i.e. C:\\) will be disk 0, the next disk\n"); | 108 | 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[]) | |||
148 | int type; | 154 | int type; |
149 | struct ipod_t ipod; | 155 | struct ipod_t ipod; |
150 | 156 | ||
151 | fprintf(stderr,"ipodpatcher v" VERSION " - (C) Dave Chapman 2006-2007\n"); | 157 | fprintf(stderr,"ipodpatcher " VERSION "\n"); |
158 | fprintf(stderr,"(C) Dave Chapman 2006-2009\n"); | ||
152 | fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n"); | 159 | fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n"); |
153 | fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); | 160 | fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); |
154 | 161 | ||
@@ -364,9 +371,9 @@ int main(int argc, char* argv[]) | |||
364 | return 1; | 371 | return 1; |
365 | } | 372 | } |
366 | 373 | ||
367 | if (getmodel(&ipod,(ipod.ipod_directory[0].vers>>8)) < 0) { | 374 | if (getmodel(&ipod,(ipod.ipod_directory[ipod.ososimage].vers>>8)) < 0) { |
368 | fprintf(stderr,"[ERR] Unknown version number in firmware (%08x)\n", | 375 | fprintf(stderr,"[ERR] Unknown version number in firmware (%08x)\n", |
369 | ipod.ipod_directory[0].vers); | 376 | ipod.ipod_directory[ipod.ososimage].vers); |
370 | return -1; | 377 | return -1; |
371 | } | 378 | } |
372 | 379 | ||
@@ -391,7 +398,7 @@ int main(int argc, char* argv[]) | |||
391 | if (ipod.ramsize > 0) { printf("(%dMB RAM) ",ipod.ramsize); } | 398 | if (ipod.ramsize > 0) { printf("(%dMB RAM) ",ipod.ramsize); } |
392 | printf("(\"%s\")\n",ipod.macpod ? "macpod" : "winpod"); | 399 | printf("(\"%s\")\n",ipod.macpod ? "macpod" : "winpod"); |
393 | 400 | ||
394 | if (ipod.ipod_directory[0].vers == 0x10000) { | 401 | if (ipod.ipod_directory[ipod.ososimage].vers == 0x10000) { |
395 | fprintf(stderr,"[ERR] *** ipodpatcher does not support the 2nd Generation Nano! ***\n"); | 402 | fprintf(stderr,"[ERR] *** ipodpatcher does not support the 2nd Generation Nano! ***\n"); |
396 | #ifdef WITH_BOOTOBJS | 403 | #ifdef WITH_BOOTOBJS |
397 | printf("Press ENTER to exit ipodpatcher :"); | 404 | printf("Press ENTER to exit ipodpatcher :"); |
diff --git a/rbutil/rbutilqt/rbutil.ini b/rbutil/rbutilqt/rbutil.ini index 987061be01..29db74c946 100644 --- a/rbutil/rbutilqt/rbutil.ini +++ b/rbutil/rbutilqt/rbutil.ini | |||
@@ -39,6 +39,7 @@ platform25=ipodvideo64mb | |||
39 | platform26=ipodmini1g | 39 | platform26=ipodmini1g |
40 | platform27=ipodmini2g | 40 | platform27=ipodmini2g |
41 | platform28=ipodnano | 41 | platform28=ipodnano |
42 | platform29=ipodnano2g | ||
42 | platform30=iaudiox5 | 43 | platform30=iaudiox5 |
43 | platform31=iaudiom5 | 44 | platform31=iaudiom5 |
44 | platform32=iaudiox5v | 45 | platform32=iaudiox5v |
@@ -242,6 +243,16 @@ brand=Apple | |||
242 | configure_modelname=ipodnano | 243 | configure_modelname=ipodnano |
243 | encoder=rbspeex | 244 | encoder=rbspeex |
244 | 245 | ||
246 | [ipodnano2g] | ||
247 | name="Ipod Nano (2nd gen)" | ||
248 | buildserver_modelname=ipodnano2g | ||
249 | bootloadermethod=ipod | ||
250 | bootloadername=/ipod/bootloader-ipodnano2g.ipodx | ||
251 | manualname= | ||
252 | brand=Apple | ||
253 | configure_modelname=ipodnano2g | ||
254 | encoder=rbspeex | ||
255 | |||
245 | [ipod4gray] | 256 | [ipod4gray] |
246 | name="Ipod (4th gen, greyscale)" | 257 | name="Ipod (4th gen, greyscale)" |
247 | buildserver_modelname=ipod4gray | 258 | buildserver_modelname=ipod4gray |
@@ -527,9 +538,6 @@ usbid=0x04e85024 | |||
527 | configure_modelname=yh925 | 538 | configure_modelname=yh925 |
528 | encoder=rbspeex | 539 | encoder=rbspeex |
529 | 540 | ||
530 | [05ac1260] | ||
531 | name="Apple Ipod Nano (Second Generation)" | ||
532 | |||
533 | [05ac1240] | 541 | [05ac1240] |
534 | name="Apple Ipod Nano (Second Generation, DFU Mode)" | 542 | name="Apple Ipod Nano (Second Generation, DFU Mode)" |
535 | 543 | ||