| Index: tools/ipodscsi_linux/main.c | 
| — | — | @@ -0,0 +1,273 @@ | 
|  | 2 | +// | 
|  | 3 | +// | 
|  | 4 | +//    Copyright 2011 TheSeven | 
|  | 5 | +//    Copyright 2012 njsg | 
|  | 6 | +// | 
|  | 7 | +// | 
|  | 8 | +//    This file is part of emCORE. | 
|  | 9 | +// | 
|  | 10 | +//    emCORE is free software: you can redistribute it and/or | 
|  | 11 | +//    modify it under the terms of the GNU General Public License as | 
|  | 12 | +//    published by the Free Software Foundation, either version 2 of the | 
|  | 13 | +//    License, or (at your option) any later version. | 
|  | 14 | +// | 
|  | 15 | +//    emCORE is distributed in the hope that it will be useful, | 
|  | 16 | +//    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 17 | +//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 
|  | 18 | +//    See the GNU General Public License for more details. | 
|  | 19 | +// | 
|  | 20 | +//    You should have received a copy of the GNU General Public License along | 
|  | 21 | +//    with emCORE.  If not, see <http://www.gnu.org/licenses/>. | 
|  | 22 | +// | 
|  | 23 | +// | 
|  | 24 | + | 
|  | 25 | +#include <string.h> | 
|  | 26 | +#include <errno.h> | 
|  | 27 | +#include <unistd.h> | 
|  | 28 | +#include <fcntl.h> | 
|  | 29 | +#include <stdio.h> | 
|  | 30 | +#include <sys/ioctl.h> | 
|  | 31 | +#include <scsi/sg.h> | 
|  | 32 | +#include <stdlib.h> | 
|  | 33 | + | 
|  | 34 | +#include "version.h" | 
|  | 35 | + | 
|  | 36 | +#define APPLE_PREFIX 0xc6 | 
|  | 37 | +#define CMD_PARTITION 0x94 | 
|  | 38 | +#define CMD_INIT_FIRMWARE 0x90 | 
|  | 39 | +#define CMD_SEND_FIRMWARE 0x91 | 
|  | 40 | + | 
|  | 41 | +/* Return a file descriptor for the SCSI device, after checking if it | 
|  | 42 | +   is really a SCSI-generic device. */ | 
|  | 43 | +int open_scsi(const char * scsi_device) { | 
|  | 44 | +  int version; | 
|  | 45 | +  int sg_fd; | 
|  | 46 | + | 
|  | 47 | +  /* Open SCSI device */ | 
|  | 48 | +  if ((sg_fd = open(scsi_device, O_RDWR)) < 0) { | 
|  | 49 | +    perror("error opening given file name"); | 
|  | 50 | +    exit(EXIT_FAILURE); | 
|  | 51 | +  } | 
|  | 52 | + | 
|  | 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) { | 
|  | 56 | +    printf("%s is not a SCSI-generic device.\n", scsi_device); | 
|  | 57 | +    exit(EXIT_FAILURE); | 
|  | 58 | +  } | 
|  | 59 | + | 
|  | 60 | +  return sg_fd; | 
|  | 61 | +} | 
|  | 62 | + | 
|  | 63 | +int usage(char const* msg, char const* msgarg, int argc, char const* const* argv) | 
|  | 64 | +{ | 
|  | 65 | +    printf(msg, msgarg); | 
|  | 66 | +    printf("\n" | 
|  | 67 | +           "\n" | 
|  | 68 | +           "Usage: %s <scsi_device> <command> [options...]\n" | 
|  | 69 | +           "\n" | 
|  | 70 | +	   "  scsi_device is the path to a device managed by the\n" | 
|  | 71 | +	   "  'scsi-generic' driver. Those are usually /dev/sgN,\n" | 
|  | 72 | +	   "  where N is the device number.\n" | 
|  | 73 | +           "\n" | 
|  | 74 | +           "Commands:\n" | 
|  | 75 | +           "  writefirmware [-p] <firmware.mse>\n" | 
|  | 76 | +           "    -r: Reboot device\n" | 
|  | 77 | +           "    -p: Repartition device\n", argv[0]); | 
|  | 78 | +    exit(EXIT_SUCCESS); | 
|  | 79 | +} | 
|  | 80 | + | 
|  | 81 | +int main(int argc, char const* const* argv) | 
|  | 82 | +{ | 
|  | 83 | +    unsigned char sense_buffer[32]; | 
|  | 84 | +    int arg = 1; | 
|  | 85 | +    char const* mse_filename = NULL; | 
|  | 86 | +    char const* scsi_device = NULL; | 
|  | 87 | +    int repartition = 0; | 
|  | 88 | +    int reboot = 0; | 
|  | 89 | +    int identify = 0; | 
|  | 90 | + | 
|  | 91 | +    int f; /* Firmware file descriptor */ | 
|  | 92 | +    unsigned long bytes; | 
|  | 93 | + | 
|  | 94 | +    printf("iPodSCSI v. " VERSION " r" VERSION_SVN " - Copyright 2011 by Michael Sparmann (TheSeven)\n" | 
|  | 95 | +           "This is free software; see the source for copying conditions.  There is NO\n" | 
|  | 96 | +           "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" | 
|  | 97 | +           "\n"); | 
|  | 98 | + | 
|  | 99 | +    if (argc < 4) return usage("Not enough arguments specified", NULL, argc, argv); | 
|  | 100 | + | 
|  | 101 | +    while (arg < argc) | 
|  | 102 | +    { | 
|  | 103 | +        if (argv[arg][0] == '-') | 
|  | 104 | +        { | 
|  | 105 | +            if (!strcmp(argv[arg], "-p")) repartition = 1; | 
|  | 106 | +            else if (!strcmp(argv[arg], "-r")) reboot = 1; | 
|  | 107 | +            else if (!strcmp(argv[arg], "-i")) identify = 1; | 
|  | 108 | +            else return usage("Unknown option: %s", argv[arg], argc, argv); | 
|  | 109 | +        } | 
|  | 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 | +	} | 
|  | 121 | +        arg++; | 
|  | 122 | +    } | 
|  | 123 | + | 
|  | 124 | +    int sg_fd = open_scsi (scsi_device); | 
|  | 125 | + | 
|  | 126 | +    if (!mse_filename) return usage("No MSE file name specified", NULL, argc, argv); | 
|  | 127 | + | 
|  | 128 | + | 
|  | 129 | +    f = open(mse_filename, O_RDONLY); | 
|  | 130 | + | 
|  | 131 | +    if (f == -1) | 
|  | 132 | +    { | 
|  | 133 | +      perror("Error while opening MSE file"); | 
|  | 134 | +      exit(EXIT_FAILURE); | 
|  | 135 | +    } | 
|  | 136 | + | 
|  | 137 | + | 
|  | 138 | +    { | 
|  | 139 | +      /* Get MSE file size */ | 
|  | 140 | +      struct stat *f_stat = malloc (sizeof (struct stat)); | 
|  | 141 | +      unsigned long size; | 
|  | 142 | + | 
|  | 143 | +      if (fstat (f, f_stat) == -1) { | 
|  | 144 | +	perror("Error while getting MSE file size"); | 
|  | 145 | +	exit(EXIT_FAILURE); | 
|  | 146 | +      } | 
|  | 147 | + | 
|  | 148 | +      bytes = f_stat->st_size; | 
|  | 149 | + | 
|  | 150 | +      if (bytes & 0xfff) { | 
|  | 151 | +	fprintf(stderr, "MSE file size must be a multiple of 4096\n"); | 
|  | 152 | +	exit (EXIT_FAILURE); | 
|  | 153 | +      } | 
|  | 154 | +    } | 
|  | 155 | + | 
|  | 156 | +    int sectors = bytes >> 12; | 
|  | 157 | + | 
|  | 158 | +    /* Most commands will have the same prefix. */ | 
|  | 159 | +    unsigned char cmdBlk[] = {APPLE_PREFIX, 0, 0, 0, 0, 0}; | 
|  | 160 | + | 
|  | 161 | +    sg_io_hdr_t io_hdr; | 
|  | 162 | +    memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); | 
|  | 163 | +    io_hdr.interface_id = 'S'; | 
|  | 164 | +    io_hdr.dxfer_direction = SG_DXFER_NONE; | 
|  | 165 | +    io_hdr.dxfer_len = 0; | 
|  | 166 | +    io_hdr.dxferp = NULL; | 
|  | 167 | +    io_hdr.cmdp = cmdBlk; | 
|  | 168 | +    io_hdr.cmd_len = sizeof(cmdBlk); | 
|  | 169 | +    io_hdr.mx_sb_len = 0; | 
|  | 170 | +    io_hdr.sbp = NULL; | 
|  | 171 | + | 
|  | 172 | +    if (repartition) | 
|  | 173 | +      { | 
|  | 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 ; | 
|  | 181 | + | 
|  | 182 | +	io_hdr.timeout = 60000; | 
|  | 183 | + | 
|  | 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 | +    cmdBlk[1] = CMD_INIT_FIRMWARE; | 
|  | 192 | +    cmdBlk[2] = 0; | 
|  | 193 | +    cmdBlk[3] = 0; | 
|  | 194 | +    cmdBlk[4] = 0; | 
|  | 195 | +    cmdBlk[5] = 0; | 
|  | 196 | + | 
|  | 197 | +    io_hdr.timeout = 1000; | 
|  | 198 | + | 
|  | 199 | +    printf("Initiating firmware transfer..."); | 
|  | 200 | + | 
|  | 201 | +    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { | 
|  | 202 | +      perror("iPod firmware transfer init SG_IO ioctl error"); | 
|  | 203 | +      exit(EXIT_FAILURE); | 
|  | 204 | +    } | 
|  | 205 | +    printf(" done\n"); | 
|  | 206 | + | 
|  | 207 | +    printf("Writing firmware..."); | 
|  | 208 | + | 
|  | 209 | + | 
|  | 210 | +    cmdBlk[1] = CMD_SEND_FIRMWARE; | 
|  | 211 | + | 
|  | 212 | +    while (sectors) | 
|  | 213 | +      { | 
|  | 214 | +        int tsize = sectors > 0x10 ? 0x10 : sectors; | 
|  | 215 | +        int got = 0; | 
|  | 216 | + | 
|  | 217 | +	char * buf = malloc((tsize << 12) * sizeof(char)); | 
|  | 218 | + | 
|  | 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 | +        } | 
|  | 228 | + | 
|  | 229 | +	cmdBlk[3] = tsize; | 
|  | 230 | + | 
|  | 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; | 
|  | 235 | + | 
|  | 236 | +	if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { | 
|  | 237 | +	  perror("iPod firmware transfer SG_IO ioctl error"); | 
|  | 238 | +	  exit(EXIT_FAILURE); | 
|  | 239 | +	} | 
|  | 240 | + | 
|  | 241 | +        sectors -= tsize; | 
|  | 242 | +        printf("."); | 
|  | 243 | +	fflush(stdout); | 
|  | 244 | +    } | 
|  | 245 | +    printf(" done\n"); | 
|  | 246 | + | 
|  | 247 | + | 
|  | 248 | +    if (reboot) | 
|  | 249 | +    { | 
|  | 250 | +        printf("Rebooting device..."); | 
|  | 251 | + | 
|  | 252 | +	cmdBlk[0] = 0x1b; | 
|  | 253 | +	cmdBlk[1] = 0; | 
|  | 254 | +	cmdBlk[2] = 0; | 
|  | 255 | +	cmdBlk[3] = 0; | 
|  | 256 | +	cmdBlk[4] = 0x02; | 
|  | 257 | +	cmdBlk[5] = 0; | 
|  | 258 | + | 
|  | 259 | +	io_hdr.dxfer_direction = SG_DXFER_NONE; | 
|  | 260 | +	io_hdr.dxfer_len = 0; | 
|  | 261 | +	io_hdr.dxferp = NULL; | 
|  | 262 | +	io_hdr.timeout = 10000; | 
|  | 263 | + | 
|  | 264 | +	if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { | 
|  | 265 | +	  perror("iPod reboot SG_IO ioctl error"); | 
|  | 266 | +	  exit(EXIT_FAILURE); | 
|  | 267 | +	} | 
|  | 268 | + | 
|  | 269 | +        printf(" done\n"); | 
|  | 270 | +    } | 
|  | 271 | + | 
|  | 272 | +    close(sg_fd); | 
|  | 273 | +    exit(EXIT_SUCCESS); | 
|  | 274 | +} |