Subversion Repositories freemyipod

Rev

Rev 975 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 975 Rev 976
Line 19... Line 19...
19
//    You should have received a copy of the GNU General Public License along
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/>.
20
//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
21
//
21
//
22
//
22
//
23
 
23
 
-
 
24
// This is a linux-based implementation of ipodscsi, originally
-
 
25
// implemented by TheSeven for Microsoft Windows.
-
 
26
//
-
 
27
// Currently, this only works for iPod 6g/Classic, but it should also
-
 
28
// work with minor modifications for, e.g., Nano 4g, which uses a
-
 
29
// similar firmware update mechanism.
-
 
30
 
24
#include <string.h>
31
#include <string.h>
25
#include <errno.h>
32
#include <errno.h>
26
#include <unistd.h>
33
#include <unistd.h>
27
#include <fcntl.h>
34
#include <fcntl.h>
28
#include <stdio.h>
35
#include <stdio.h>
29
#include <sys/ioctl.h>
36
#include <sys/ioctl.h>
30
#include <scsi/sg.h>
37
#include <scsi/sg.h>
31
#include <stdlib.h>
38
#include <stdlib.h>
32
 
39
 
33
#include "version.h"
40
#include "build/version.h"
34
 
41
 
35
#define APPLE_PREFIX 0xc6
42
#define APPLE_PREFIX 0xc6
36
#define CMD_PARTITION 0x94
-
 
37
#define CMD_INIT_FIRMWARE 0x90
43
#define CMD_INIT_FIRMWARE 0x90
38
#define CMD_SEND_FIRMWARE 0x91
44
#define CMD_SEND_FIRMWARE 0x91
-
 
45
#define CMD_PARTITION 0x94
39
 
46
 
40
/* Return a file descriptor for the SCSI device, after checking if it
47
// Return a file descriptor for the SCSI device, after checking if it
41
   is really a SCSI-generic device. */
48
// is really a SCSI-generic device.
42
int open_scsi(const char * scsi_device) {
49
int open_scsi(const char * scsi_device) {
43
  int version;
50
  int version;
44
  int sg_fd;
51
  int sg_fd;
45
  
52
  
46
  /* Open SCSI device */
53
  // Open SCSI device 
47
  if ((sg_fd = open(scsi_device, O_RDWR)) < 0) {
54
  if ((sg_fd = open(scsi_device, O_RDWR)) < 0) 
-
 
55
  {
48
    perror("error opening given file name");
56
    perror("error opening given file name");
49
    exit(EXIT_FAILURE);
57
    exit(EXIT_FAILURE);
50
  }
58
  }
51
 
59
 
52
  /* Request a very simple scsi-generic ioctl(). If this fails, this
60
  // Request a very simple scsi-generic ioctl(). If this fails, this
53
     is not a scsi-generic device. */
61
  // is not a scsi-generic device.
54
  if (ioctl(sg_fd, SG_GET_VERSION_NUM, &version) < 0) {
62
  if (ioctl(sg_fd, SG_GET_VERSION_NUM, &version) < 0) 
-
 
63
  {
55
    printf("%s is not a SCSI-generic device.\n", scsi_device);
64
    printf("%s is not a SCSI-generic device.\n", scsi_device);
56
    exit(EXIT_FAILURE);
65
    exit(EXIT_FAILURE);
57
  }
66
  }
58
 
67
 
59
  return sg_fd;
68
  return sg_fd;
Line 69... Line 78...
69
	   "  scsi_device is the path to a device managed by the\n"
78
	   "  scsi_device is the path to a device managed by the\n"
70
	   "  'scsi-generic' driver. Those are usually /dev/sgN,\n"
79
	   "  'scsi-generic' driver. Those are usually /dev/sgN,\n"
71
	   "  where N is the device number.\n"
80
	   "  where N is the device number.\n"
72
           "\n"
81
           "\n"
73
           "Commands:\n"
82
           "Commands:\n"
74
           "  writefirmware [-p] <firmware.mse>\n"
83
           "  writefirmware [-p] [-r] <firmware.mse>\n"
75
           "    -r: Reboot device\n"
84
           "    -r: Reboot device\n"
76
           "    -p: Repartition device\n", argv[0]);
85
           "    -p: Repartition device\n", argv[0]);
77
    exit(EXIT_SUCCESS);
86
    exit(EXIT_SUCCESS);
78
}
87
}
79
 
88
 
80
int main(int argc, char const* const* argv)
89
int main(int argc, char const* const* argv)
81
{
90
{
82
    unsigned char sense_buffer[32];
-
 
83
    int arg = 1;
91
    int arg = 3;
84
    char const* mse_filename = NULL;
92
    char const* mse_filename = NULL;
85
    char const* scsi_device = NULL;
93
    char const* scsi_device = NULL;
86
    int repartition = 0;
94
    int repartition = 0;
87
    int reboot = 0;
95
    int reboot = 0;
88
    int identify = 0;
-
 
89
 
96
 
90
    int f; /* Firmware file descriptor */
97
    int f; // Firmware file descriptor
91
    unsigned long bytes;
98
    unsigned long bytes;
92
 
99
 
93
    printf("iPodSCSI v. " VERSION " r" VERSION_SVN " - Copyright 2011 by Michael Sparmann (TheSeven)\n"
100
    printf("iPodSCSI for linux v. " VERSION " r" VERSION_SVN " - Copyright 2012 by Nuno J. Silva (njsg)\n"
-
 
101
	   "Based on the original iPodSCSI Windows code by Michael Sparmann (TheSeven)\n"
94
           "This is free software; see the source for copying conditions.  There is NO\n"
102
           "This is free software; see the source for copying conditions.  There is NO\n"
95
           "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
103
           "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
96
           "\n");
104
           "\n");
97
 
105
 
98
    if (argc < 4) return usage("Not enough arguments specified", NULL, argc, argv);
106
    if (argc < 3) return usage("Not enough arguments specified", NULL, argc, argv);
-
 
107
 
-
 
108
    if (strcmp(argv[2], "writefirmware") != 0)
-
 
109
    {
-
 
110
      usage("Unknown command: %s", argv[2], argc, argv);
-
 
111
    }
-
 
112
 
-
 
113
    scsi_device = argv[1];
-
 
114
    
99
 
115
 
100
    while (arg < argc)
116
    while (arg < argc)
101
    {
117
    {
102
        if (argv[arg][0] == '-')
118
        if (argv[arg][0] == '-')
103
        {
119
        {
104
            if (!strcmp(argv[arg], "-p")) repartition = 1;
120
            if (!strcmp(argv[arg], "-p")) repartition = 1;
105
            else if (!strcmp(argv[arg], "-r")) reboot = 1;
121
            else if (!strcmp(argv[arg], "-r")) reboot = 1;
106
            else if (!strcmp(argv[arg], "-i")) identify = 1;
-
 
107
            else return usage("Unknown option: %s", argv[arg], argc, argv);
122
            else return usage("Unknown option: %s", argv[arg], argc, argv);
108
        }
123
        }
109
        else {
-
 
110
	  if (scsi_device) {
-
 
111
	    if (!mse_filename) {
-
 
112
	      mse_filename = argv[arg];
-
 
113
	    } else {
-
 
114
	      return usage("Excessive argument: %s", argv[arg], argc, argv);
124
        else if (mse_filename) return usage("Excessive argument: %s", argv[arg], argc, argv);
115
	    }
-
 
116
	  } else {
-
 
117
	    scsi_device = argv[arg];
125
        else mse_filename = argv[arg];
118
	  }
-
 
119
	}
-
 
120
        arg++;
126
        arg++;
121
    }
127
    }
122
 
128
 
123
    int sg_fd = open_scsi (scsi_device);
129
    int sg_fd = open_scsi (scsi_device);
124
 
130
 
Line 133... Line 139...
133
      exit(EXIT_FAILURE);
139
      exit(EXIT_FAILURE);
134
    }
140
    }
135
 
141
 
136
 
142
 
137
    {
143
    {
138
      /* Get MSE file size */
144
      // Get MSE file size 
139
      struct stat *f_stat = malloc (sizeof (struct stat));
145
      struct stat *f_stat = malloc (sizeof (struct stat));
140
      unsigned long size;
146
      unsigned long size;
141
 
147
 
142
      if (fstat (f, f_stat) == -1) {
148
      if (fstat (f, f_stat) == -1) 
-
 
149
      {
143
	perror("Error while getting MSE file size");
150
	perror("Error while getting MSE file size");
144
	exit(EXIT_FAILURE);
151
	exit(EXIT_FAILURE);
145
      }
152
      }
146
 
153
 
147
      bytes = f_stat->st_size;
154
      bytes = f_stat->st_size;
148
 
155
 
149
      if (bytes & 0xfff) {
156
      if (bytes & 0xfff) 
-
 
157
      {
150
	fprintf(stderr, "MSE file size must be a multiple of 4096\n");
158
	fprintf(stderr, "MSE file size must be a multiple of 4096\n");
151
	exit (EXIT_FAILURE);
159
	exit (EXIT_FAILURE);
152
      }
160
      }
153
    }
161
    }
154
 
162
 
155
    int sectors = bytes >> 12;
163
    int sectors = bytes >> 12;
156
 
164
 
157
    /* Most commands will have the same prefix. */
165
    // Most commands will have the same prefix.
158
    unsigned char cmdBlk[] = {APPLE_PREFIX, 0, 0, 0, 0, 0};
166
    unsigned char cmdBlk[] = {APPLE_PREFIX, 0, 0, 0, 0, 0};
159
 
167
 
-
 
168
 
-
 
169
    // Prepare a SCSI command structure, which will be changed as
-
 
170
    // needed later.
160
    sg_io_hdr_t io_hdr;
171
    sg_io_hdr_t io_hdr;
161
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
172
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
162
    io_hdr.interface_id = 'S';
173
    io_hdr.interface_id = 'S';
163
    io_hdr.dxfer_direction = SG_DXFER_NONE;
174
    io_hdr.dxfer_direction = SG_DXFER_NONE;
164
    io_hdr.dxfer_len = 0;
175
    io_hdr.dxfer_len = 0;
Line 167... Line 178...
167
    io_hdr.cmd_len = sizeof(cmdBlk);
178
    io_hdr.cmd_len = sizeof(cmdBlk);
168
    io_hdr.mx_sb_len = 0;
179
    io_hdr.mx_sb_len = 0;
169
    io_hdr.sbp = NULL;
180
    io_hdr.sbp = NULL;
170
 
181
 
171
    if (repartition)
182
    if (repartition)
-
 
183
    {
-
 
184
      printf("Repartitioning...");
-
 
185
      int partsize = sectors << 2;
-
 
186
      cmdBlk[1] = CMD_PARTITION;
-
 
187
      cmdBlk[2] = (partsize >> 24) & 0xff;
-
 
188
      cmdBlk[3] = (partsize >> 16) & 0xff;
-
 
189
      cmdBlk[4] = (partsize >> 8) & 0xff;
-
 
190
      cmdBlk[5] = (partsize) & 0xff;
-
 
191
 
-
 
192
      io_hdr.timeout = 60000;     
-
 
193
      
-
 
194
      if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) 
172
      {
195
      {
173
        printf("Repartitioning...");
-
 
174
        int partsize = sectors << 2;
-
 
175
	cmdBlk[1] = CMD_PARTITION;
-
 
176
	cmdBlk[2] = (partsize >> 24) & 0xff,
-
 
177
	cmdBlk[3] = (partsize >> 16) & 0xff,
-
 
178
	cmdBlk[4] = (partsize >> 8) & 0xff,
-
 
179
	cmdBlk[5] = (partsize) & 0xff ;
-
 
180
 
-
 
181
	io_hdr.timeout = 60000;     
-
 
182
 
-
 
183
	if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
-
 
184
	  perror("iPod repartitioning SG_IO ioctl error");
196
	perror("iPod repartitioning SG_IO ioctl error");
185
	  exit(EXIT_FAILURE);
197
	exit(EXIT_FAILURE);
186
	}
-
 
187
	printf(" done\n");
-
 
188
      }
198
      }
-
 
199
      printf(" done\n");
-
 
200
    }
-
 
201
    
-
 
202
 
-
 
203
    printf("Initiating firmware transfer...");
189
 
204
 
190
    cmdBlk[1] = CMD_INIT_FIRMWARE;
205
    cmdBlk[1] = CMD_INIT_FIRMWARE;
191
    cmdBlk[2] = 0;
206
    cmdBlk[2] = 0;
192
    cmdBlk[3] = 0;
207
    cmdBlk[3] = 0;
193
    cmdBlk[4] = 0;
208
    cmdBlk[4] = 0;
194
    cmdBlk[5] = 0;
209
    cmdBlk[5] = 0;
195
 
210
 
196
    io_hdr.timeout = 1000;     
211
    io_hdr.timeout = 1000;     
197
	
212
	
198
    printf("Initiating firmware transfer...");
-
 
199
 
213
 
-
 
214
 
200
    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
215
    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) 
-
 
216
    {
201
      perror("iPod firmware transfer init SG_IO ioctl error");
217
      perror("iPod firmware transfer init SG_IO ioctl error");
202
      exit(EXIT_FAILURE);
218
      exit(EXIT_FAILURE);
203
    }
219
    }
204
    printf(" done\n");
220
    printf(" done\n");
205
 
221
 
206
    printf("Writing firmware...");
-
 
207
 
222
 
208
 
223
 
-
 
224
    printf("Writing firmware...");
-
 
225
 
209
    cmdBlk[1] = CMD_SEND_FIRMWARE;
226
    cmdBlk[1] = CMD_SEND_FIRMWARE;
210
 
227
 
211
    while (sectors)
228
    while (sectors)
212
      {
229
    {
213
        int tsize = sectors > 0x10 ? 0x10 : sectors;
230
      int tsize = sectors > 0x10 ? 0x10 : sectors;
214
        int got = 0;
231
      int got = 0;
215
	
232
	
216
	char * buf = malloc((tsize << 12) * sizeof(char));
233
      char * buf = malloc((tsize << 12) * sizeof(char));
217
 
234
 
218
        while (got < (tsize << 12))
235
      while (got < (tsize << 12))
219
	  {
236
      {
220
	    int b = read(f, buf + got, (tsize << 12) - got);
237
	int b = read(f, buf + got, (tsize << 12) - got);
221
	    if (b == -1) {
238
	if (b == -1) 
-
 
239
	{
222
	      perror("Error reading from MSE file");
240
	  perror("Error reading from MSE file");
223
	      exit(EXIT_FAILURE);
241
	  exit(EXIT_FAILURE);
224
	    }
242
	}
225
	    got += b;
243
	got += b;
226
        }
244
      }
227
		
245
		
228
	cmdBlk[3] = tsize;
246
      cmdBlk[3] = tsize;
229
	
247
	
230
	io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
248
      io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
231
	io_hdr.dxfer_len = tsize << 12;
249
      io_hdr.dxfer_len = tsize << 12;
232
	io_hdr.dxferp = buf;
250
      io_hdr.dxferp = buf;
233
	io_hdr.timeout = 5000; 
251
      io_hdr.timeout = 5000; 
234
 
252
 
235
	if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
253
      if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) 
-
 
254
      {
236
	  perror("iPod firmware transfer SG_IO ioctl error");
255
	perror("iPod firmware transfer SG_IO ioctl error");
237
	  exit(EXIT_FAILURE);
256
	exit(EXIT_FAILURE);
238
	}
257
      }
239
 
258
 
240
        sectors -= tsize;
259
      sectors -= tsize;
241
        printf(".");
260
      printf(".");
242
	fflush(stdout);
261
      fflush(stdout);
243
    }
262
    }
244
    printf(" done\n");
263
    printf(" done\n");
245
 
264
 
246
 
265
 
247
    if (reboot)
266
    if (reboot)
Line 258... Line 277...
258
	io_hdr.dxfer_direction = SG_DXFER_NONE;
277
	io_hdr.dxfer_direction = SG_DXFER_NONE;
259
	io_hdr.dxfer_len = 0;
278
	io_hdr.dxfer_len = 0;
260
	io_hdr.dxferp = NULL;
279
	io_hdr.dxferp = NULL;
261
	io_hdr.timeout = 10000;     
280
	io_hdr.timeout = 10000;     
262
 
281
 
263
	if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
282
	if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) 
-
 
283
	{
264
	  perror("iPod reboot SG_IO ioctl error");
284
	  perror("iPod reboot SG_IO ioctl error");
265
	  exit(EXIT_FAILURE);
285
	  exit(EXIT_FAILURE);
266
	}
286
	}
267
 
287
 
268
        printf(" done\n");
288
        printf(" done\n");