diff options
-rw-r--r-- | rbutil/ipodpatcher/Makefile | 4 | ||||
-rw-r--r-- | rbutil/ipodpatcher/ipodio-posix.c | 63 | ||||
-rw-r--r-- | rbutil/ipodpatcher/ipodio-win32-scsi.c | 118 | ||||
-rw-r--r-- | rbutil/ipodpatcher/ipodio-win32.c | 4 | ||||
-rw-r--r-- | rbutil/ipodpatcher/ipodio.h | 5 | ||||
-rw-r--r-- | rbutil/ipodpatcher/ipodpatcher.c | 80 | ||||
-rw-r--r-- | rbutil/ipodpatcher/ipodpatcher.h | 2 | ||||
-rw-r--r-- | rbutil/ipodpatcher/main.c | 50 |
8 files changed, 319 insertions, 7 deletions
diff --git a/rbutil/ipodpatcher/Makefile b/rbutil/ipodpatcher/Makefile index 263d64ed01..9c32587fa1 100644 --- a/rbutil/ipodpatcher/Makefile +++ b/rbutil/ipodpatcher/Makefile @@ -36,8 +36,8 @@ ipodpatcher: $(SRC) ipodio-posix.c $(BOOTSRC) gcc $(CFLAGS) -o ipodpatcher $(SRC) ipodio-posix.c $(BOOTSRC) strip ipodpatcher -ipodpatcher.exe: $(SRC) ipodio-win32.c ipodpatcher-rc.o $(BOOTSRC) - $(CC) $(CFLAGS) -o ipodpatcher.exe $(SRC) ipodio-win32.c ipodpatcher-rc.o $(BOOTSRC) +ipodpatcher.exe: $(SRC) ipodio-win32.c ipodio-win32-scsi.c ipodpatcher-rc.o $(BOOTSRC) + $(CC) $(CFLAGS) -o ipodpatcher.exe $(SRC) ipodio-win32.c ipodio-win32-scsi.c ipodpatcher-rc.o $(BOOTSRC) $(CROSS)strip ipodpatcher.exe ipodpatcher-rc.o: ipodpatcher.rc ipodpatcher.manifest diff --git a/rbutil/ipodpatcher/ipodio-posix.c b/rbutil/ipodpatcher/ipodio-posix.c index 6dfb09ed33..be048fc986 100644 --- a/rbutil/ipodpatcher/ipodio-posix.c +++ b/rbutil/ipodpatcher/ipodio-posix.c @@ -34,6 +34,9 @@ #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) @@ -50,6 +53,51 @@ static void get_geometry(struct ipod_t* ipod) } } +/* 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> @@ -63,6 +111,13 @@ static void get_geometry(struct ipod_t* ipod) 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 */ + return -1; +} + #elif defined(__APPLE__) && defined(__MACH__) #include <sys/disk.h> #define IPOD_SECTORSIZE_IOCTL DKIOCGETBLOCKSIZE @@ -75,6 +130,13 @@ static void get_geometry(struct ipod_t* ipod) ipod->sectors_per_track = 63; } +int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code, + unsigned char* buf, int bufsize) +{ + /* TODO: Implement for OS X */ + return -1; +} + #else #error No sector-size detection implemented for this platform #endif @@ -180,3 +242,4 @@ ssize_t ipod_write(struct ipod_t* ipod, unsigned char* buf, int nbytes) { return write(ipod->dh, buf, nbytes); } + diff --git a/rbutil/ipodpatcher/ipodio-win32-scsi.c b/rbutil/ipodpatcher/ipodio-win32-scsi.c new file mode 100644 index 0000000000..5843ce5d2f --- /dev/null +++ b/rbutil/ipodpatcher/ipodio-win32-scsi.c @@ -0,0 +1,118 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: ipodio-win32.c 17847 2008-06-28 18:10:04Z bagder $ + * + * 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. + * + ****************************************************************************/ + +#include <windows.h> +#include <stddef.h> +#include <stdio.h> +#include <ddk/ntddscsi.h> + +#include "ipodio.h" + +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) { + memcpy(buf, sptwb.DataBuf, returned); + return 0; + } else { + return -1; + } +} diff --git a/rbutil/ipodpatcher/ipodio-win32.c b/rbutil/ipodpatcher/ipodio-win32.c index ceec4a3d6c..5125c070f8 100644 --- a/rbutil/ipodpatcher/ipodio-win32.c +++ b/rbutil/ipodpatcher/ipodio-win32.c @@ -32,10 +32,9 @@ #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> -#ifdef __WIN32__ #include <windows.h> +#include <stddef.h> #include <winioctl.h> -#endif #include "ipodio.h" @@ -201,3 +200,4 @@ ssize_t ipod_write(struct ipod_t* ipod, unsigned char* buf, int nbytes) return count; } + diff --git a/rbutil/ipodpatcher/ipodio.h b/rbutil/ipodpatcher/ipodio.h index dbd3d5e1ff..e0692ca6d9 100644 --- a/rbutil/ipodpatcher/ipodio.h +++ b/rbutil/ipodpatcher/ipodio.h @@ -80,6 +80,9 @@ struct ipod_t { 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; @@ -91,6 +94,8 @@ 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, unsigned char* buf, int nbytes); ssize_t ipod_write(struct ipod_t* ipod, unsigned char* buf, int nbytes); int ipod_alloc_buffer(unsigned char** sectorbuf, int bufsize); diff --git a/rbutil/ipodpatcher/ipodpatcher.c b/rbutil/ipodpatcher/ipodpatcher.c index dd650506a1..1a5268bb6d 100644 --- a/rbutil/ipodpatcher/ipodpatcher.c +++ b/rbutil/ipodpatcher/ipodpatcher.c @@ -1401,6 +1401,86 @@ int write_dos_partition_table(struct ipod_t* ipod) return 0; } +/* Get the XML Device Information, as documented here: + + http://www.ipodlinux.org/wiki/Device_Information +*/ + +int ipod_get_xmlinfo(struct ipod_t* ipod) +{ + unsigned char hdr[255]; + unsigned char buf[255]; + char* p; + int psize; + int npages; + int i; + + if (ipod_scsi_inquiry(ipod, 0xc0, buf, sizeof(buf)) < 0) + { + fprintf(stderr,"[ERR] Sending SCSI Command failed.\n"); + return -1; + } + + /* Reading directly into hdr[] causes problems (for an unknown reason) on + win32 */ + memcpy(hdr, buf, sizeof(hdr)); + + npages = hdr[3]; + + psize = npages * 0xf8; /* Hopefully this is enough. */ + + ipod->xmlinfo = malloc(psize); + ipod->xmlinfo_len = 0; + + if (ipod->xmlinfo == NULL) { + fprintf(stderr,"[ERR] Could not allocate RAM for xmlinfo\n"); + return -1; + } + + p = ipod->xmlinfo; + + for (i=0; i < npages; i++) { + if (ipod_scsi_inquiry(ipod, hdr[i+4], buf, sizeof(buf)) < 0) { + fprintf(stderr,"[ERR] Sending SCSI Command failed.\n"); + return -1; + } + + if ((buf[3] + ipod->xmlinfo_len) > psize) { + fprintf(stderr,"[ERR] Ran out of memory reading xmlinfo\n"); + free(ipod->xmlinfo); + ipod->xmlinfo = NULL; + ipod->xmlinfo_len = 0; + return -1; + } + + memcpy(p, buf + 4, buf[3]); + p += buf[3]; + ipod->xmlinfo_len += buf[3]; + } + + /* NULL-terminate the XML info */ + *p = 0; + + fprintf(stderr,"[INFO] Read XML info (%d bytes)\n",ipod->xmlinfo_len); + + return 0; +} + +void ipod_get_ramsize(struct ipod_t* ipod) +{ + const char needle[] = "<key>RAM</key>\n<integer>"; + char* p; + + if (ipod->xmlinfo == NULL) + return; + + p = strstr(ipod->xmlinfo, needle); + + if (p) { + ipod->ramsize = atoi(p + sizeof(needle) - 1); + } +} + #ifndef RBUTIL static inline uint32_t getuint32le(unsigned char* buf) diff --git a/rbutil/ipodpatcher/ipodpatcher.h b/rbutil/ipodpatcher/ipodpatcher.h index bb80ba3758..3fbb83ca9e 100644 --- a/rbutil/ipodpatcher/ipodpatcher.h +++ b/rbutil/ipodpatcher/ipodpatcher.h @@ -54,6 +54,8 @@ 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); diff --git a/rbutil/ipodpatcher/main.c b/rbutil/ipodpatcher/main.c index 88ac3a60e1..1dcb916240 100644 --- a/rbutil/ipodpatcher/main.c +++ b/rbutil/ipodpatcher/main.c @@ -50,6 +50,7 @@ enum { READ_PARTITION, WRITE_PARTITION, FORMAT_PARTITION, + DUMP_XML, CONVERT_TO_FAT32 }; @@ -93,6 +94,7 @@ void print_usage(void) 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"); #ifdef __WIN32__ @@ -315,6 +317,13 @@ int main(int argc, char* argv[]) if (i == argc) { print_usage(); return 1; } 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 1; } + filename=argv[i]; + i++; } else if ((strcmp(argv[i],"-c")==0) || (strcmp(argv[i],"--convert")==0)) { action = CONVERT_TO_FAT32; @@ -361,8 +370,26 @@ int main(int argc, char* argv[]) return -1; } - printf("[INFO] Ipod model: %s (\"%s\")\n",ipod.modelstr, - ipod.macpod ? "macpod" : "winpod"); +#ifdef __WIN32__ + /* Windows requires the ipod in R/W mode for SCSI Inquiry */ + if (ipod_reopen_rw(&ipod) < 0) { + return 5; + } +#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.ipod_directory[0].vers == 0x10000) { fprintf(stderr,"[ERR] *** ipodpatcher does not support the 2nd Generation Nano! ***\n"); @@ -476,6 +503,24 @@ int main(int argc, char* argv[]) } 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 1; + } + + outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE); + if (outfile < 0) { + perror(filename); + return 4; + } + + 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) { @@ -571,6 +616,5 @@ int main(int argc, char* argv[]) } #endif - return 0; } |