summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--rbutil/ipodpatcher/Makefile4
-rw-r--r--rbutil/ipodpatcher/ipodio-posix.c63
-rw-r--r--rbutil/ipodpatcher/ipodio-win32-scsi.c118
-rw-r--r--rbutil/ipodpatcher/ipodio-win32.c4
-rw-r--r--rbutil/ipodpatcher/ipodio.h5
-rw-r--r--rbutil/ipodpatcher/ipodpatcher.c80
-rw-r--r--rbutil/ipodpatcher/ipodpatcher.h2
-rw-r--r--rbutil/ipodpatcher/main.c50
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;
}