/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id:$ * * Copyright (C) 2015 by Cástor Muñoz * * 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. * ****************************************************************************/ #include #include #include #include #include #include #include #include "mks5lboot.h" /* Win32 compatibility */ #ifndef O_BINARY #define O_BINARY 0 #endif #ifdef WIN32 #include #define sleep_ms(ms) Sleep(ms) #else #include static void sleep_ms(unsigned int ms) { struct timespec req; req.tv_sec = ms / 1000; req.tv_nsec = (ms % 1000) * 1000000; nanosleep(&req, NULL); } #endif #define DEFAULT_LOOP_PERIOD 1 /* seconds */ #define _ERR(format, ...) \ do { \ snprintf(errstr, errstrsize, "[ERR] "format, __VA_ARGS__); \ goto error; \ } while(0) static int write_file(char *outfile, unsigned char* buf, int bufsize, char* errstr, int errstrsize) { int fd = open(outfile, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666); if (fd < 0) _ERR("Could not open %s for writing", outfile); if (write(fd, buf, bufsize) != bufsize) _ERR("Could not write file %s", outfile); return 1; error: return 0; } static unsigned char *read_file(char *infile, int *bufsize, char* errstr, int errstrsize) { unsigned char *buf; int fd; struct stat s; fd = open(infile, O_RDONLY|O_BINARY); if (fd < 0) _ERR("Could not open %s for reading", infile); if (fstat(fd, &s) < 0) _ERR("Checking size of input file %s", infile); *bufsize = s.st_size; buf = malloc(*bufsize); if (buf == NULL) _ERR("Could not allocate memory for %s", infile); if (read(fd, buf, *bufsize) != *bufsize) _ERR("Could not read file %s", infile); return buf; error: return NULL; } static void usage(void) { fprintf(stderr, "Usage:\n" " mks5lboot --bl-inst [-p ] [--single]\n" " --bl-uninst [-p ]\n" " --dfuscan [--loop []] [-p ]\n" " --dfusend [-p ]\n" " --dfureset [--loop []] [-p ]\n" " --mkdfu-inst [--single]\n" " --mkdfu-uninst \n" " --mkdfu-raw \n" "\n" "Commands:\n" " --bl-inst Install file into an iPod device\n" " (same as --mkdfu-inst and --dfusend).\n" " --bl-uninst Remove a bootloader from an iPod device (same as\n" " --mkdfu-uninst and --dfusend).\n" "\n" " --dfuscan scan for DFU USB devices and outputs the status.\n" " --dfusend send DFU image to the device.\n" " --dfureset reset DFU USB device bus.\n" "\n" " --mkdfu-inst Build a DFU image containing an installer for\n" " , save it as .\n" " --mkdfu-uninst Build a DFU image containing an uninstaler for\n" " devices, save it as .\n" " --mkdfu-raw Build a DFU image containing raw executable\n" " code, save it ass . \n" " is the code you want to run, it is loaded at\n" " address 0x%08x and executed.\n" "\n" " is the rockbox bootloader that you want to\n" " install (previously scrambled with tools/scramble utility).\n" "\n" " is the name of the platform (type of device) for\n" " which the DFU uninstaller will be built. Currently supported\n" " platform names are:\n" " ipod6g: iPod Classic 6G\n" "\n" "Options:\n" " -p, --pid Use a specific (Product Id) USB device,\n" " if this option is ommited then it uses the\n" " first USB DFU device found.\n" " -l, --loop Run the command every seconds, default\n" " period ( ommited) is %d seconds.\n" " -S, --single Be careful using this option. The bootloader\n" " is installed for single boot, the original\n" " Apple NOR boot is destroyed (if it exists),\n" " and only Rockbox can be used.\n" , DFU_LOADADDR + BIN_OFFSET , DEFAULT_LOOP_PERIOD); exit(1); } int main(int argc, char* argv[]) { char *dfuoutfile = NULL; char *dfuinfile = NULL; char *dfu_arg = NULL; int dfu_type = DFU_NONE; int n_cmds = 0; int scan = 0; int pid = 0; int reset = 0; int loop = 0; int single = 0; char errstr[200]; unsigned char *dfubuf; int dfusize; fprintf(stderr, #if defined(WIN32) && defined(USE_LIBUSBAPI) "mks5lboot Version " VERSION " (libusb)\n" #else "mks5lboot Version " VERSION "\n" #endif "This is free software; see the source for copying conditions. There is NO\n" "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" "\n"); fflush(stderr); while (--argc) { argv++; if (!memcmp(*argv, "--bl", 4)) { if (!strcmp(*argv+4, "-inst")) dfu_type = DFU_INST; else if (!strcmp(*argv+4, "-uninst")) dfu_type = DFU_UNINST; else usage(); if (!--argc) usage(); dfu_arg = *++argv; n_cmds++; } else if (!memcmp(*argv, "--mkdfu", 7)) { if (!strcmp(*argv+7, "-inst")) dfu_type = DFU_INST; else if (!strcmp(*argv+7, "-uninst")) dfu_type = DFU_UNINST; else if (!strcmp(*argv+7, "-raw")) dfu_type = DFU_RAW; else usage(); if (!--argc) usage(); dfu_arg = *++argv; if (!--argc) usage(); dfuoutfile = *++argv; n_cmds++; } else if (!strcmp(*argv, "--dfusend")) { if (!--argc) usage(); dfuinfile = *++argv; n_cmds++; } else if (!strcmp(*argv, "--dfuscan")) { scan = 1; n_cmds++; } else if (!strcmp(*argv, "--dfureset")) { scan = 1; reset = 1; n_cmds++; } else if (!strcmp(*argv, "--pid") || !strcmp(*argv, "-p")) { if (!--argc) usage(); if (sscanf(*++argv, "%x", &pid) != 1) usage(); } else if (!strcmp(*argv, "--loop") || !strcmp (*argv, "-l")) { if (!(argc-1) || *(argv+1)[0] == '-') { loop = DEFAULT_LOOP_PERIOD; } else { if ((sscanf(*++argv, "%d", &loop) != 1) || !loop) usage(); argc--; } } else if (!strcmp(*argv, "--single") || !strcmp(*argv, "-S")) { single = 1; } else if (!strcmp(*argv, "--debug")) { ipoddfu_debug(1); } else usage(); } if (n_cmds != 1) usage(); if ((dfu_type == DFU_INST) && single) dfu_type = DFU_INST_SINGLE; if (scan) { int cnt = 0; while (1) { int state, res; if (loop) printf("[%d] ", cnt); else printf("[INFO] "); printf("DFU %s:\n", reset ? "reset":"scan"); res = ipoddfu_scan(pid, &state, reset, errstr, sizeof(errstr)); if (res == 0) printf("%s\n", errstr); else printf("[INFO] DFU device state: %d\n", state); if (!loop) exit(!res); fflush(stdout); sleep_ms(loop*1000); cnt += loop; } } if (dfuinfile) dfubuf = read_file(dfuinfile, &dfusize, errstr, sizeof(errstr)); else dfubuf = mkdfu(dfu_type, dfu_arg, &dfusize, errstr, sizeof(errstr)); if (!dfubuf) goto error; if (dfuoutfile) { if (write_file(dfuoutfile, dfubuf, dfusize, errstr, sizeof(errstr))) { printf("[INFO] Created file %s (%d bytes)\n", dfuoutfile, dfusize); exit(0); } } else { if (ipoddfu_send(pid, dfubuf, dfusize, errstr, sizeof(errstr))) { printf("[INFO] DFU image sent successfully (%d bytes)\n", dfusize); exit(0); } } error: printf("%s\n", errstr); exit(1); }