Subversion Repositories freemyipod

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
975 user890104 1
//
2
//
3
//    Copyright 2011 TheSeven
4
//    Copyright 2012 njsg
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
#include <string.h>
25
#include <errno.h>
26
#include <unistd.h>
27
#include <fcntl.h>
28
#include <stdio.h>
29
#include <sys/ioctl.h>
30
#include <scsi/sg.h>
31
#include <stdlib.h>
32
 
33
#include "version.h"
34
 
35
#define APPLE_PREFIX 0xc6
36
#define CMD_PARTITION 0x94
37
#define CMD_INIT_FIRMWARE 0x90
38
#define CMD_SEND_FIRMWARE 0x91
39
 
40
/* Return a file descriptor for the SCSI device, after checking if it
41
   is really a SCSI-generic device. */
42
int open_scsi(const char * scsi_device) {
43
  int version;
44
  int sg_fd;
45
 
46
  /* Open SCSI device */
47
  if ((sg_fd = open(scsi_device, O_RDWR)) < 0) {
48
    perror("error opening given file name");
49
    exit(EXIT_FAILURE);
50
  }
51
 
52
  /* Request a very simple scsi-generic ioctl(). If this fails, this
53
     is not a scsi-generic device. */
54
  if (ioctl(sg_fd, SG_GET_VERSION_NUM, &version) < 0) {
55
    printf("%s is not a SCSI-generic device.\n", scsi_device);
56
    exit(EXIT_FAILURE);
57
  }
58
 
59
  return sg_fd;
60
}
61
 
62
int usage(char const* msg, char const* msgarg, int argc, char const* const* argv)
63
{
64
    printf(msg, msgarg);
65
    printf("\n"
66
           "\n"
67
           "Usage: %s <scsi_device> <command> [options...]\n"
68
           "\n"
69
	   "  scsi_device is the path to a device managed by the\n"
70
	   "  'scsi-generic' driver. Those are usually /dev/sgN,\n"
71
	   "  where N is the device number.\n"
72
           "\n"
73
           "Commands:\n"
74
           "  writefirmware [-p] <firmware.mse>\n"
75
           "    -r: Reboot device\n"
76
           "    -p: Repartition device\n", argv[0]);
77
    exit(EXIT_SUCCESS);
78
}
79
 
80
int main(int argc, char const* const* argv)
81
{
82
    unsigned char sense_buffer[32];
83
    int arg = 1;
84
    char const* mse_filename = NULL;
85
    char const* scsi_device = NULL;
86
    int repartition = 0;
87
    int reboot = 0;
88
    int identify = 0;
89
 
90
    int f; /* Firmware file descriptor */
91
    unsigned long bytes;
92
 
93
    printf("iPodSCSI v. " VERSION " r" VERSION_SVN " - Copyright 2011 by Michael Sparmann (TheSeven)\n"
94
           "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"
96
           "\n");
97
 
98
    if (argc < 4) return usage("Not enough arguments specified", NULL, argc, argv);
99
 
100
    while (arg < argc)
101
    {
102
        if (argv[arg][0] == '-')
103
        {
104
            if (!strcmp(argv[arg], "-p")) repartition = 1;
105
            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);
108
        }
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);
115
	    }
116
	  } else {
117
	    scsi_device = argv[arg];
118
	  }
119
	}
120
        arg++;
121
    }
122
 
123
    int sg_fd = open_scsi (scsi_device);
124
 
125
    if (!mse_filename) return usage("No MSE file name specified", NULL, argc, argv);
126
 
127
 
128
    f = open(mse_filename, O_RDONLY);
129
 
130
    if (f == -1)
131
    {
132
      perror("Error while opening MSE file");
133
      exit(EXIT_FAILURE);
134
    }
135
 
136
 
137
    {
138
      /* Get MSE file size */
139
      struct stat *f_stat = malloc (sizeof (struct stat));
140
      unsigned long size;
141
 
142
      if (fstat (f, f_stat) == -1) {
143
	perror("Error while getting MSE file size");
144
	exit(EXIT_FAILURE);
145
      }
146
 
147
      bytes = f_stat->st_size;
148
 
149
      if (bytes & 0xfff) {
150
	fprintf(stderr, "MSE file size must be a multiple of 4096\n");
151
	exit (EXIT_FAILURE);
152
      }
153
    }
154
 
155
    int sectors = bytes >> 12;
156
 
157
    /* Most commands will have the same prefix. */
158
    unsigned char cmdBlk[] = {APPLE_PREFIX, 0, 0, 0, 0, 0};
159
 
160
    sg_io_hdr_t io_hdr;
161
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
162
    io_hdr.interface_id = 'S';
163
    io_hdr.dxfer_direction = SG_DXFER_NONE;
164
    io_hdr.dxfer_len = 0;
165
    io_hdr.dxferp = NULL;
166
    io_hdr.cmdp = cmdBlk;
167
    io_hdr.cmd_len = sizeof(cmdBlk);
168
    io_hdr.mx_sb_len = 0;
169
    io_hdr.sbp = NULL;
170
 
171
    if (repartition)
172
      {
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");
185
	  exit(EXIT_FAILURE);
186
	}
187
	printf(" done\n");
188
      }
189
 
190
    cmdBlk[1] = CMD_INIT_FIRMWARE;
191
    cmdBlk[2] = 0;
192
    cmdBlk[3] = 0;
193
    cmdBlk[4] = 0;
194
    cmdBlk[5] = 0;
195
 
196
    io_hdr.timeout = 1000;     
197
 
198
    printf("Initiating firmware transfer...");
199
 
200
    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
201
      perror("iPod firmware transfer init SG_IO ioctl error");
202
      exit(EXIT_FAILURE);
203
    }
204
    printf(" done\n");
205
 
206
    printf("Writing firmware...");
207
 
208
 
209
    cmdBlk[1] = CMD_SEND_FIRMWARE;
210
 
211
    while (sectors)
212
      {
213
        int tsize = sectors > 0x10 ? 0x10 : sectors;
214
        int got = 0;
215
 
216
	char * buf = malloc((tsize << 12) * sizeof(char));
217
 
218
        while (got < (tsize << 12))
219
	  {
220
	    int b = read(f, buf + got, (tsize << 12) - got);
221
	    if (b == -1) {
222
	      perror("Error reading from MSE file");
223
	      exit(EXIT_FAILURE);
224
	    }
225
	    got += b;
226
        }
227
 
228
	cmdBlk[3] = tsize;
229
 
230
	io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
231
	io_hdr.dxfer_len = tsize << 12;
232
	io_hdr.dxferp = buf;
233
	io_hdr.timeout = 5000; 
234
 
235
	if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
236
	  perror("iPod firmware transfer SG_IO ioctl error");
237
	  exit(EXIT_FAILURE);
238
	}
239
 
240
        sectors -= tsize;
241
        printf(".");
242
	fflush(stdout);
243
    }
244
    printf(" done\n");
245
 
246
 
247
    if (reboot)
248
    {
249
        printf("Rebooting device...");
250
 
251
	cmdBlk[0] = 0x1b;
252
	cmdBlk[1] = 0;
253
	cmdBlk[2] = 0;
254
	cmdBlk[3] = 0;
255
	cmdBlk[4] = 0x02;
256
	cmdBlk[5] = 0;
257
 
258
	io_hdr.dxfer_direction = SG_DXFER_NONE;
259
	io_hdr.dxfer_len = 0;
260
	io_hdr.dxferp = NULL;
261
	io_hdr.timeout = 10000;     
262
 
263
	if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
264
	  perror("iPod reboot SG_IO ioctl error");
265
	  exit(EXIT_FAILURE);
266
	}
267
 
268
        printf(" done\n");
269
    }
270
 
271
    close(sg_fd);
272
    exit(EXIT_SUCCESS);
273
}