Index: tools/ipodscsi_linux/Makefile |
— | — | @@ -0,0 +1,94 @@ |
| 2 | +NAME := ipodscsi |
| 3 | + |
| 4 | +ifeq ($(shell uname),WindowsNT) |
| 5 | +CCACHE := |
| 6 | +else |
| 7 | +CCACHE := $(shell which ccache) |
| 8 | +endif |
| 9 | + |
| 10 | +CC := $(CCACHE) gcc |
| 11 | +LD := $(CCACHE) gcc |
| 12 | + |
| 13 | +CFLAGS += -Os -fomit-frame-pointer "-DDFUIMAGE=\"$(DFUIMAGE)\"" |
| 14 | +LDFLAGS += -Wl,-s |
| 15 | + |
| 16 | +preprocess = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#") |
| 17 | +preprocesspaths = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#" | sed -e "s:^..*:$(dir $(1))&:" | sed -e "s:^\\./::") |
| 18 | + |
| 19 | +REVISION := $(shell svnversion .) |
| 20 | +REVISIONINT := $(shell echo $(REVISION) | sed -e "s/[^0-9].*$$//") |
| 21 | + |
| 22 | +SRC := $(call preprocesspaths,SOURCES,-I. -I..) |
| 23 | +OBJ := $(SRC:%.c=build/%.o) |
| 24 | +OBJ := $(OBJ:%.S=build/%.o) |
| 25 | +OBJ := $(OBJ:%.rc=build/%.o) |
| 26 | + |
| 27 | +all: $(NAME) |
| 28 | + |
| 29 | +-include $(OBJ:%=%.dep) |
| 30 | + |
| 31 | +ipodscsi.rc: ipodscsi.exe.manifest |
| 32 | + |
| 33 | +$(NAME): build/$(NAME).exe |
| 34 | + |
| 35 | +build/$(NAME).exe: $(OBJ) |
| 36 | + @echo [LD] $@ |
| 37 | + @$(LD) -o $@ $(OBJ) $(LDFLAGS) |
| 38 | + |
| 39 | +build/%.o: %.c build/version.h |
| 40 | + @echo [CC] $< |
| 41 | +ifeq ($(shell uname),WindowsNT) |
| 42 | + @-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@)) |
| 43 | +else |
| 44 | + @-mkdir -p $(dir $@) |
| 45 | +endif |
| 46 | + @$(CC) -c $(CFLAGS) -o $@ $< |
| 47 | + @$(CC) -MM $(CFLAGS) $< > $@.dep.tmp |
| 48 | + @sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep |
| 49 | +ifeq ($(shell uname),WindowsNT) |
| 50 | + @sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep |
| 51 | +else |
| 52 | + @sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep |
| 53 | +endif |
| 54 | + @rm -f $@.dep.tmp |
| 55 | + |
| 56 | +build/%.o: %.S build/version.h |
| 57 | + @echo [CC] $< |
| 58 | +ifeq ($(shell uname),WindowsNT) |
| 59 | + @-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@)) |
| 60 | +else |
| 61 | + @-mkdir -p $(dir $@) |
| 62 | +endif |
| 63 | + @$(CC) -c $(CFLAGS) -o $@ $< |
| 64 | + @$(CC) -MM $(CFLAGS) $< > $@.dep.tmp |
| 65 | + @sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep |
| 66 | +ifeq ($(shell uname),WindowsNT) |
| 67 | + @sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep |
| 68 | +else |
| 69 | + @sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep |
| 70 | +endif |
| 71 | + @rm -f $@.dep.tmp |
| 72 | + |
| 73 | +build/%.o: %.rc |
| 74 | + @echo [WINRES] $< |
| 75 | +ifeq ($(shell uname),WindowsNT) |
| 76 | + @-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@)) |
| 77 | +else |
| 78 | + @-mkdir -p $(dir $@) |
| 79 | +endif |
| 80 | + @windres -i $< -o $@ |
| 81 | + |
| 82 | +build/version.h: version.h ../../.svn/entries |
| 83 | + @echo [PP] $< |
| 84 | +ifeq ($(shell uname),WindowsNT) |
| 85 | + @-if not exist build md build |
| 86 | + @sed -e "s/\$$REVISION\$$/$(REVISION)/" -e "s/\$$REVISIONINT\$$/$(REVISIONINT)/" < $< > $@ |
| 87 | +else |
| 88 | + @-mkdir -p build |
| 89 | + @sed -e 's/\$$REVISION\$$/$(REVISION)/' -e 's/\$$REVISIONINT\$$/$(REVISIONINT)/' < $< > $@ |
| 90 | +endif |
| 91 | + |
| 92 | +clean: |
| 93 | + @rm -rf build |
| 94 | + |
| 95 | +.PHONY: all clean $(NAME) |
Index: tools/ipodscsi_linux/SOURCES |
— | — | @@ -0,0 +1 @@ |
| 2 | +main.c
|
Index: tools/ipodscsi_linux/main.c |
— | — | @@ -21,6 +21,13 @@ |
22 | 22 | // |
23 | 23 | // |
24 | 24 | |
| 25 | +// This is a linux-based implementation of ipodscsi, originally |
| 26 | +// implemented by TheSeven for Microsoft Windows. |
| 27 | +// |
| 28 | +// Currently, this only works for iPod 6g/Classic, but it should also |
| 29 | +// work with minor modifications for, e.g., Nano 4g, which uses a |
| 30 | +// similar firmware update mechanism. |
| 31 | + |
25 | 32 | #include <string.h> |
26 | 33 | #include <errno.h> |
27 | 34 | #include <unistd.h> |
— | — | @@ -30,28 +37,30 @@ |
31 | 38 | #include <scsi/sg.h> |
32 | 39 | #include <stdlib.h> |
33 | 40 | |
34 | | -#include "version.h" |
| 41 | +#include "build/version.h" |
35 | 42 | |
36 | 43 | #define APPLE_PREFIX 0xc6 |
37 | | -#define CMD_PARTITION 0x94 |
38 | 44 | #define CMD_INIT_FIRMWARE 0x90 |
39 | 45 | #define CMD_SEND_FIRMWARE 0x91 |
| 46 | +#define CMD_PARTITION 0x94 |
40 | 47 | |
41 | | -/* Return a file descriptor for the SCSI device, after checking if it |
42 | | - is really a SCSI-generic device. */ |
| 48 | +// Return a file descriptor for the SCSI device, after checking if it |
| 49 | +// is really a SCSI-generic device. |
43 | 50 | int open_scsi(const char * scsi_device) { |
44 | 51 | int version; |
45 | 52 | int sg_fd; |
46 | 53 | |
47 | | - /* Open SCSI device */ |
48 | | - if ((sg_fd = open(scsi_device, O_RDWR)) < 0) { |
| 54 | + // Open SCSI device |
| 55 | + if ((sg_fd = open(scsi_device, O_RDWR)) < 0) |
| 56 | + { |
49 | 57 | perror("error opening given file name"); |
50 | 58 | exit(EXIT_FAILURE); |
51 | 59 | } |
52 | 60 | |
53 | | - /* Request a very simple scsi-generic ioctl(). If this fails, this |
54 | | - is not a scsi-generic device. */ |
55 | | - if (ioctl(sg_fd, SG_GET_VERSION_NUM, &version) < 0) { |
| 61 | + // Request a very simple scsi-generic ioctl(). If this fails, this |
| 62 | + // is not a scsi-generic device. |
| 63 | + if (ioctl(sg_fd, SG_GET_VERSION_NUM, &version) < 0) |
| 64 | + { |
56 | 65 | printf("%s is not a SCSI-generic device.\n", scsi_device); |
57 | 66 | exit(EXIT_FAILURE); |
58 | 67 | } |
— | — | @@ -71,7 +80,7 @@ |
72 | 81 | " where N is the device number.\n" |
73 | 82 | "\n" |
74 | 83 | "Commands:\n" |
75 | | - " writefirmware [-p] <firmware.mse>\n" |
| 84 | + " writefirmware [-p] [-r] <firmware.mse>\n" |
76 | 85 | " -r: Reboot device\n" |
77 | 86 | " -p: Repartition device\n", argv[0]); |
78 | 87 | exit(EXIT_SUCCESS); |
— | — | @@ -79,24 +88,31 @@ |
80 | 89 | |
81 | 90 | int main(int argc, char const* const* argv) |
82 | 91 | { |
83 | | - unsigned char sense_buffer[32]; |
84 | | - int arg = 1; |
| 92 | + int arg = 3; |
85 | 93 | char const* mse_filename = NULL; |
86 | 94 | char const* scsi_device = NULL; |
87 | 95 | int repartition = 0; |
88 | 96 | int reboot = 0; |
89 | | - int identify = 0; |
90 | 97 | |
91 | | - int f; /* Firmware file descriptor */ |
| 98 | + int f; // Firmware file descriptor |
92 | 99 | unsigned long bytes; |
93 | 100 | |
94 | | - printf("iPodSCSI v. " VERSION " r" VERSION_SVN " - Copyright 2011 by Michael Sparmann (TheSeven)\n" |
| 101 | + printf("iPodSCSI for linux v. " VERSION " r" VERSION_SVN " - Copyright 2012 by Nuno J. Silva (njsg)\n" |
| 102 | + "Based on the original iPodSCSI Windows code by Michael Sparmann (TheSeven)\n" |
95 | 103 | "This is free software; see the source for copying conditions. There is NO\n" |
96 | 104 | "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" |
97 | 105 | "\n"); |
98 | 106 | |
99 | | - if (argc < 4) return usage("Not enough arguments specified", NULL, argc, argv); |
| 107 | + if (argc < 3) return usage("Not enough arguments specified", NULL, argc, argv); |
100 | 108 | |
| 109 | + if (strcmp(argv[2], "writefirmware") != 0) |
| 110 | + { |
| 111 | + usage("Unknown command: %s", argv[2], argc, argv); |
| 112 | + } |
| 113 | + |
| 114 | + scsi_device = argv[1]; |
| 115 | + |
| 116 | + |
101 | 117 | while (arg < argc) |
102 | 118 | { |
103 | 119 | if (argv[arg][0] == '-') |
— | — | @@ -103,20 +119,10 @@ |
104 | 120 | { |
105 | 121 | if (!strcmp(argv[arg], "-p")) repartition = 1; |
106 | 122 | else if (!strcmp(argv[arg], "-r")) reboot = 1; |
107 | | - else if (!strcmp(argv[arg], "-i")) identify = 1; |
108 | 123 | else return usage("Unknown option: %s", argv[arg], argc, argv); |
109 | 124 | } |
110 | | - else { |
111 | | - if (scsi_device) { |
112 | | - if (!mse_filename) { |
113 | | - mse_filename = argv[arg]; |
114 | | - } else { |
115 | | - return usage("Excessive argument: %s", argv[arg], argc, argv); |
116 | | - } |
117 | | - } else { |
118 | | - scsi_device = argv[arg]; |
119 | | - } |
120 | | - } |
| 125 | + else if (mse_filename) return usage("Excessive argument: %s", argv[arg], argc, argv); |
| 126 | + else mse_filename = argv[arg]; |
121 | 127 | arg++; |
122 | 128 | } |
123 | 129 | |
— | — | @@ -135,11 +141,12 @@ |
136 | 142 | |
137 | 143 | |
138 | 144 | { |
139 | | - /* Get MSE file size */ |
| 145 | + // Get MSE file size |
140 | 146 | struct stat *f_stat = malloc (sizeof (struct stat)); |
141 | 147 | unsigned long size; |
142 | 148 | |
143 | | - if (fstat (f, f_stat) == -1) { |
| 149 | + if (fstat (f, f_stat) == -1) |
| 150 | + { |
144 | 151 | perror("Error while getting MSE file size"); |
145 | 152 | exit(EXIT_FAILURE); |
146 | 153 | } |
— | — | @@ -146,7 +153,8 @@ |
147 | 154 | |
148 | 155 | bytes = f_stat->st_size; |
149 | 156 | |
150 | | - if (bytes & 0xfff) { |
| 157 | + if (bytes & 0xfff) |
| 158 | + { |
151 | 159 | fprintf(stderr, "MSE file size must be a multiple of 4096\n"); |
152 | 160 | exit (EXIT_FAILURE); |
153 | 161 | } |
— | — | @@ -154,9 +162,12 @@ |
155 | 163 | |
156 | 164 | int sectors = bytes >> 12; |
157 | 165 | |
158 | | - /* Most commands will have the same prefix. */ |
| 166 | + // Most commands will have the same prefix. |
159 | 167 | unsigned char cmdBlk[] = {APPLE_PREFIX, 0, 0, 0, 0, 0}; |
160 | 168 | |
| 169 | + |
| 170 | + // Prepare a SCSI command structure, which will be changed as |
| 171 | + // needed later. |
161 | 172 | sg_io_hdr_t io_hdr; |
162 | 173 | memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); |
163 | 174 | io_hdr.interface_id = 'S'; |
— | — | @@ -169,24 +180,28 @@ |
170 | 181 | io_hdr.sbp = NULL; |
171 | 182 | |
172 | 183 | if (repartition) |
| 184 | + { |
| 185 | + printf("Repartitioning..."); |
| 186 | + int partsize = sectors << 2; |
| 187 | + cmdBlk[1] = CMD_PARTITION; |
| 188 | + cmdBlk[2] = (partsize >> 24) & 0xff; |
| 189 | + cmdBlk[3] = (partsize >> 16) & 0xff; |
| 190 | + cmdBlk[4] = (partsize >> 8) & 0xff; |
| 191 | + cmdBlk[5] = (partsize) & 0xff; |
| 192 | + |
| 193 | + io_hdr.timeout = 60000; |
| 194 | + |
| 195 | + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) |
173 | 196 | { |
174 | | - printf("Repartitioning..."); |
175 | | - int partsize = sectors << 2; |
176 | | - cmdBlk[1] = CMD_PARTITION; |
177 | | - cmdBlk[2] = (partsize >> 24) & 0xff, |
178 | | - cmdBlk[3] = (partsize >> 16) & 0xff, |
179 | | - cmdBlk[4] = (partsize >> 8) & 0xff, |
180 | | - cmdBlk[5] = (partsize) & 0xff ; |
| 197 | + perror("iPod repartitioning SG_IO ioctl error"); |
| 198 | + exit(EXIT_FAILURE); |
| 199 | + } |
| 200 | + printf(" done\n"); |
| 201 | + } |
| 202 | + |
181 | 203 | |
182 | | - io_hdr.timeout = 60000; |
| 204 | + printf("Initiating firmware transfer..."); |
183 | 205 | |
184 | | - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { |
185 | | - perror("iPod repartitioning SG_IO ioctl error"); |
186 | | - exit(EXIT_FAILURE); |
187 | | - } |
188 | | - printf(" done\n"); |
189 | | - } |
190 | | - |
191 | 206 | cmdBlk[1] = CMD_INIT_FIRMWARE; |
192 | 207 | cmdBlk[2] = 0; |
193 | 208 | cmdBlk[3] = 0; |
— | — | @@ -195,51 +210,55 @@ |
196 | 211 | |
197 | 212 | io_hdr.timeout = 1000; |
198 | 213 | |
199 | | - printf("Initiating firmware transfer..."); |
200 | 214 | |
201 | | - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { |
| 215 | + |
| 216 | + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) |
| 217 | + { |
202 | 218 | perror("iPod firmware transfer init SG_IO ioctl error"); |
203 | 219 | exit(EXIT_FAILURE); |
204 | 220 | } |
205 | 221 | printf(" done\n"); |
206 | 222 | |
| 223 | + |
| 224 | + |
207 | 225 | printf("Writing firmware..."); |
208 | 226 | |
209 | | - |
210 | 227 | cmdBlk[1] = CMD_SEND_FIRMWARE; |
211 | 228 | |
212 | 229 | while (sectors) |
213 | | - { |
214 | | - int tsize = sectors > 0x10 ? 0x10 : sectors; |
215 | | - int got = 0; |
| 230 | + { |
| 231 | + int tsize = sectors > 0x10 ? 0x10 : sectors; |
| 232 | + int got = 0; |
216 | 233 | |
217 | | - char * buf = malloc((tsize << 12) * sizeof(char)); |
| 234 | + char * buf = malloc((tsize << 12) * sizeof(char)); |
218 | 235 | |
219 | | - while (got < (tsize << 12)) |
220 | | - { |
221 | | - int b = read(f, buf + got, (tsize << 12) - got); |
222 | | - if (b == -1) { |
223 | | - perror("Error reading from MSE file"); |
224 | | - exit(EXIT_FAILURE); |
225 | | - } |
226 | | - got += b; |
227 | | - } |
| 236 | + while (got < (tsize << 12)) |
| 237 | + { |
| 238 | + int b = read(f, buf + got, (tsize << 12) - got); |
| 239 | + if (b == -1) |
| 240 | + { |
| 241 | + perror("Error reading from MSE file"); |
| 242 | + exit(EXIT_FAILURE); |
| 243 | + } |
| 244 | + got += b; |
| 245 | + } |
228 | 246 | |
229 | | - cmdBlk[3] = tsize; |
| 247 | + cmdBlk[3] = tsize; |
230 | 248 | |
231 | | - io_hdr.dxfer_direction = SG_DXFER_TO_DEV; |
232 | | - io_hdr.dxfer_len = tsize << 12; |
233 | | - io_hdr.dxferp = buf; |
234 | | - io_hdr.timeout = 5000; |
| 249 | + io_hdr.dxfer_direction = SG_DXFER_TO_DEV; |
| 250 | + io_hdr.dxfer_len = tsize << 12; |
| 251 | + io_hdr.dxferp = buf; |
| 252 | + io_hdr.timeout = 5000; |
235 | 253 | |
236 | | - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { |
237 | | - perror("iPod firmware transfer SG_IO ioctl error"); |
238 | | - exit(EXIT_FAILURE); |
239 | | - } |
| 254 | + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) |
| 255 | + { |
| 256 | + perror("iPod firmware transfer SG_IO ioctl error"); |
| 257 | + exit(EXIT_FAILURE); |
| 258 | + } |
240 | 259 | |
241 | | - sectors -= tsize; |
242 | | - printf("."); |
243 | | - fflush(stdout); |
| 260 | + sectors -= tsize; |
| 261 | + printf("."); |
| 262 | + fflush(stdout); |
244 | 263 | } |
245 | 264 | printf(" done\n"); |
246 | 265 | |
— | — | @@ -260,7 +279,8 @@ |
261 | 280 | io_hdr.dxferp = NULL; |
262 | 281 | io_hdr.timeout = 10000; |
263 | 282 | |
264 | | - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { |
| 283 | + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) |
| 284 | + { |
265 | 285 | perror("iPod reboot SG_IO ioctl error"); |
266 | 286 | exit(EXIT_FAILURE); |
267 | 287 | } |
Index: tools/ipodscsi_linux/version.h |
— | — | @@ -0,0 +1,36 @@ |
| 2 | +//
|
| 3 | +//
|
| 4 | +// Copyright 2011 TheSeven
|
| 5 | +//
|
| 6 | +//
|
| 7 | +// This file is part of emCORE.
|
| 8 | +//
|
| 9 | +// emCORE is free software: you can redistribute it and/or
|
| 10 | +// modify it under the terms of the GNU General Public License as
|
| 11 | +// published by the Free Software Foundation, either version 2 of the
|
| 12 | +// License, or (at your option) any later version.
|
| 13 | +//
|
| 14 | +// emCORE is distributed in the hope that it will be useful,
|
| 15 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 16 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
| 17 | +// See the GNU General Public License for more details.
|
| 18 | +//
|
| 19 | +// You should have received a copy of the GNU General Public License along
|
| 20 | +// with emCORE. If not, see <http://www.gnu.org/licenses/>.
|
| 21 | +//
|
| 22 | +//
|
| 23 | +
|
| 24 | +
|
| 25 | +#ifndef __VERSION_H__
|
| 26 | +#define __VERSION_H__
|
| 27 | +
|
| 28 | +
|
| 29 | +#define VERSION "0.1.0"
|
| 30 | +#define VERSION_MAJOR 0
|
| 31 | +#define VERSION_MINOR 1
|
| 32 | +#define VERSION_PATCH 0
|
| 33 | +#define VERSION_SVN "$REVISION$"
|
| 34 | +#define VERSION_SVN_INT $REVISIONINT$
|
| 35 | +
|
| 36 | +
|
| 37 | +#endif
|