mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-08 12:45:26 -05:00
mks5lboot: updates
- fix Makefile to allow cross compilation - Windows: use Sleep() instead of nanosleep() - Windows: libusb now is optional - OS X: use IOKit instead of libusb - small rework on the DFU API Change-Id: Ia4b07012c098ad608594e15f6effe9c9d2164b9b
This commit is contained in:
parent
cf168d4636
commit
fbbba9292b
6 changed files with 492 additions and 267 deletions
3
rbutil/mks5lboot/.gitignore
vendored
3
rbutil/mks5lboot/.gitignore
vendored
|
|
@ -1,2 +1,5 @@
|
||||||
buildposix/
|
buildposix/
|
||||||
|
buildmingw/
|
||||||
|
builddarwin/
|
||||||
mks5lboot
|
mks5lboot
|
||||||
|
mks5lboot.exe
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
# \/ \/ \/ \/ \/
|
# \/ \/ \/ \/ \/
|
||||||
|
CC := gcc
|
||||||
CFLAGS += -Wall -Wextra
|
CFLAGS += -Wall -Wextra
|
||||||
|
|
||||||
OUTPUT = mks5lboot
|
OUTPUT = mks5lboot
|
||||||
|
|
@ -15,18 +16,25 @@ SOURCES := $(LIBSOURCES) main.c
|
||||||
# dependencies for binary
|
# dependencies for binary
|
||||||
EXTRADEPS :=
|
EXTRADEPS :=
|
||||||
|
|
||||||
ifeq ($(findstring MINGW,$(shell uname)),MINGW)
|
CPPDEFINES := $(shell echo foo | $(CROSS)$(CC) -dM -E -)
|
||||||
|
|
||||||
|
ifeq ($(findstring WIN32,$(CPPDEFINES)),WIN32)
|
||||||
LDOPTS += -lsetupapi
|
LDOPTS += -lsetupapi
|
||||||
# optional libusb support on Windows
|
# optional libusb support (needed for WinUSB and libusbK drivers)
|
||||||
ifdef DISABLE_LIBUSBAPI
|
ifeq ($(findstring MINGW,$(CPPDEFINES)),MINGW)
|
||||||
CFLAGS += -DNO_LIBUSBAPI
|
ifeq ($(USE_LIBUSBAPI),1)
|
||||||
else
|
CFLAGS += -DUSE_LIBUSBAPI
|
||||||
LDOPTS += -Wl,-Bstatic -lusb-1.0
|
LDOPTS += -Wl,-Bstatic -lusb-1.0
|
||||||
endif
|
endif
|
||||||
|
endif
|
||||||
else
|
else
|
||||||
# Linux, OS X
|
ifeq ($(findstring APPLE,$(CPPDEFINES)),APPLE)
|
||||||
|
LDOPTS += -L/usr/local/lib -framework IOKit -framework CoreFoundation
|
||||||
|
else # Linux
|
||||||
|
CFLAGS += -DUSE_LIBUSBAPI
|
||||||
LDOPTS += -lusb-1.0
|
LDOPTS += -lusb-1.0
|
||||||
endif
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
include ../libtools.make
|
include ../libtools.make
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ A tool to install/uninstall a dual bootloader into a s5l8702 based
|
||||||
device:
|
device:
|
||||||
|
|
||||||
- iPod Classic 6G
|
- iPod Classic 6G
|
||||||
- iPod Nano 3G (TODO)
|
- iPod Nano 3G (WIP)
|
||||||
|
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
|
|
@ -97,32 +97,40 @@ Prerequisites:
|
||||||
[INFO] DFU device state: 2
|
[INFO] DFU device state: 2
|
||||||
. When the device is found but there is no driver installed:
|
. When the device is found but there is no driver installed:
|
||||||
[ERR] Could not open USB device: LIBUSB_ERROR_NOT_SUPPORTED
|
[ERR] Could not open USB device: LIBUSB_ERROR_NOT_SUPPORTED
|
||||||
. Then the device is found but driver is not valid (probably a
|
. When the device is found but driver is not valid (probably a
|
||||||
libusb-win32 driver is installed):
|
libusb-win32 driver is installed):
|
||||||
[ERR] Could not set USB configuration: LIBUSB_ERROR_NOT_FOUND
|
[ERR] Could not set USB configuration: LIBUSB_ERROR_NOT_FOUND
|
||||||
. If there is no valid DFU driver installed, try one of these:
|
. If there is no valid DFU driver installed, try one of these:
|
||||||
a) Use Zadig (http://zadig.akeo.ie/) to build and install a WinUSB
|
a) Use Zadig (http://zadig.akeo.ie/) to build and install a WinUSB
|
||||||
(libusb.info) or libusbK driver for your device. Note that
|
(libusb.info) or libusbK driver for your device. Note that
|
||||||
libusb-win32 (libusb0) drivers are not valid for mks5lboot.
|
libusb-win32 (libusb0) drivers are not valid for mks5lboot.
|
||||||
b) Use Apple Mobile Device USB driver (included with iTunes).
|
b) Use Apple Mobile Device USB driver (included with iTunes). To
|
||||||
|
install this driver without iTunes see https://www.freemyipod.org
|
||||||
|
/wiki/EmCORE_Installation/iPodClassic/InstalliTunesDrivers
|
||||||
|
|
||||||
Command line install:
|
Command line install:
|
||||||
|
|
||||||
- If you are using iTunes on Windows, close iTunes and kill (or pause)
|
- If you are using iTunes on Windows, close iTunes and kill (or pause)
|
||||||
iTunesHelper.exe before entering DFU mode.
|
iTunesHelper.exe before entering DFU mode.
|
||||||
|
|
||||||
|
- If you are using iTunes on Mac, quit iTunes and kill (or pause) the
|
||||||
|
iTunesHelper process before entering DFU mode.
|
||||||
|
You can use "ps x | grep iTunesHelper" to locate the process <PID>,
|
||||||
|
use "kill -STOP <PID>" to suspend the process and "kill -CONT <PID>"
|
||||||
|
to resume it once the bootloader is installed.
|
||||||
|
|
||||||
- Put you device on DFU mode by pressing and holding SELECT+MENU buttons
|
- Put you device on DFU mode by pressing and holding SELECT+MENU buttons
|
||||||
for about 12 seconds.
|
for about 12 seconds.
|
||||||
|
|
||||||
You can notice when the device enters DFU mode running the next command
|
You can notice when the device enters DFU mode running the next command
|
||||||
to scan the USB bus every second (press Ctrl-C to abort the scan):
|
to scan the USB bus every second (press Ctrl-C to abort the scan):
|
||||||
mks5lboot --dfuscan --loop
|
./mks5lboot --dfuscan --loop
|
||||||
|
|
||||||
- To install or update a bootloader, build the DFU installer and send it
|
- To install or update a bootloader, build the DFU installer and send it
|
||||||
to the device:
|
to the device:
|
||||||
mks5lboot --bl-inst /path/to/bootloader-ipod6g.ipod
|
./mks5lboot --bl-inst path/to/bootloader-ipod6g.ipod
|
||||||
|
|
||||||
When the DFU imagen is loaded and executed, the device emits an 'alive'
|
When the DFU image is loaded and executed, the device emits an 'alive'
|
||||||
tone (2000Hz/100ms). When the bootloader is successfully installed then
|
tone (2000Hz/100ms). When the bootloader is successfully installed then
|
||||||
a dual tone beep sounds (1000Hz/100ms+2000Hz/150ms) and the device
|
a dual tone beep sounds (1000Hz/100ms+2000Hz/150ms) and the device
|
||||||
reboots. If something went bad then 330Hz/500ms tone is emited and the
|
reboots. If something went bad then 330Hz/500ms tone is emited and the
|
||||||
|
|
@ -132,10 +140,15 @@ Command line install:
|
||||||
|
|
||||||
- To remove a previously installed bootloader, build the DFU uninstaler
|
- To remove a previously installed bootloader, build the DFU uninstaler
|
||||||
and send it to the device:
|
and send it to the device:
|
||||||
mks5lboot --bl-uninst ipod6g
|
./mks5lboot --bl-uninst ipod6g
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- If USB access is denied, try to run the mks5lboot tool using a privileged
|
||||||
|
user (i.e. Administrator or root).
|
||||||
|
|
||||||
|
- On Windows, use 'mks5lboot' or 'mks5lboot.exe' instead of './mks5lboot'.
|
||||||
|
|
||||||
If USB access is denied, try to run the mks5lboot tool using a privileged
|
|
||||||
user (i.e. Administrator or root).
|
|
||||||
|
|
||||||
|
|
||||||
Dual-Boot
|
Dual-Boot
|
||||||
|
|
@ -192,14 +205,20 @@ To build the DFU single-boot installer and send it to the device:
|
||||||
mks5lboot --bl-inst --single /path/to/bootloader-ipod6g.ipod
|
mks5lboot --bl-inst --single /path/to/bootloader-ipod6g.ipod
|
||||||
|
|
||||||
|
|
||||||
Compilation
|
Build
|
||||||
-----------
|
-----
|
||||||
|
|
||||||
Needs libusb > 1.0 installed, tested on:
|
To build type 'make'.
|
||||||
|
|
||||||
Linux: gcc-4.9.2 + libusb-1.0.19
|
Linux needs libusb >= 1.0, use your package manager to install libusb.
|
||||||
Windows XP: mingw32-gcc-4.8.1 + libusbx-1.0.15
|
|
||||||
OS X 10.11: clang-7.3.0 + libusb-1.0.20
|
For Windows, to build with libusb support type 'make USE_LIBUSBAPI=1'.
|
||||||
|
|
||||||
|
Tested on:
|
||||||
|
Linux: gcc-4.9.2 + libusb-1.0.19
|
||||||
|
Windows XP: mingw32-gcc-4.8.1 + libusbx-1.0.15
|
||||||
|
OS X 10.11: clang-7.3.0 + libusb-1.0.20
|
||||||
|
MXE: i686-w64-mingw32.static-gcc 5.4.0 + libusb-1.0.21
|
||||||
|
|
||||||
|
|
||||||
Hacking
|
Hacking
|
||||||
|
|
|
||||||
|
|
@ -22,28 +22,32 @@
|
||||||
* KIND, either express or implied.
|
* KIND, either express or implied.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#ifndef NO_LIBUSBAPI
|
|
||||||
#define USE_LIBUSBAPI
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <setupapi.h>
|
#include <setupapi.h>
|
||||||
#include <stdbool.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_LIBUSBAPI
|
#ifdef USE_LIBUSBAPI
|
||||||
#include <libusb-1.0/libusb.h>
|
#include <libusb-1.0/libusb.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
#include <IOKit/IOCFPlugIn.h>
|
||||||
|
#include <IOKit/usb/IOUSBLib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "mks5lboot.h"
|
#include "mks5lboot.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define sleep_ms(ms) Sleep(ms)
|
||||||
|
#else
|
||||||
|
#include <time.h>
|
||||||
static void sleep_ms(unsigned int ms)
|
static void sleep_ms(unsigned int ms)
|
||||||
{
|
{
|
||||||
struct timespec req;
|
struct timespec req;
|
||||||
|
|
@ -51,36 +55,36 @@ static void sleep_ms(unsigned int ms)
|
||||||
req.tv_nsec = (ms % 1000) * 1000000;
|
req.tv_nsec = (ms % 1000) * 1000000;
|
||||||
nanosleep(&req, NULL);
|
nanosleep(&req, NULL);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void put_uint32le(unsigned char* p, uint32_t x)
|
||||||
|
{
|
||||||
|
p[0] = x & 0xff;
|
||||||
|
p[1] = (x >> 8) & 0xff;
|
||||||
|
p[2] = (x >> 16) & 0xff;
|
||||||
|
p[3] = (x >> 24) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CRC32 functions
|
* CRC32 functions
|
||||||
* Based on public domain implementation by Finn Yannick Jacobs.
|
* Based on public domain implementation by Finn Yannick Jacobs.
|
||||||
*/
|
*
|
||||||
|
* Written and copyright 1999 by Finn Yannick Jacobs
|
||||||
/* Written and copyright 1999 by Finn Yannick Jacobs
|
|
||||||
* No rights were reserved to this, so feel free to
|
* No rights were reserved to this, so feel free to
|
||||||
* manipulate or do with it, what you want or desire :)
|
* manipulate or do with it, what you want or desire :)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CRC32_DEFAULT_SEED 0xffffffff
|
|
||||||
|
|
||||||
/* crc32table[] built by crc32_init() */
|
/* crc32table[] built by crc32_init() */
|
||||||
static unsigned long crc32table[256];
|
static uint32_t crc32table[256];
|
||||||
|
|
||||||
/* Calculate crc32. Little endian.
|
/* Calculate crc32 */
|
||||||
* Standard seed is 0xffffffff or 0.
|
static uint32_t crc32(void *data, unsigned int len, uint32_t previousCrc32)
|
||||||
* Some implementations xor result with 0xffffffff after calculation.
|
|
||||||
*/
|
|
||||||
static uint32_t crc32(void *data, unsigned int len, uint32_t seed)
|
|
||||||
{
|
{
|
||||||
uint8_t *d = data;
|
uint32_t crc = ~previousCrc32;
|
||||||
|
unsigned char *d = (unsigned char*) data;
|
||||||
while (len--)
|
while (len--)
|
||||||
{
|
crc = (crc >> 8) ^ crc32table[(crc & 0xFF) ^ *d++];
|
||||||
seed = ((seed >> 8) & 0x00FFFFFF) ^ crc32table [(seed ^ *d++) & 0xFF];
|
return ~crc;
|
||||||
}
|
|
||||||
|
|
||||||
return seed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate crc32table */
|
/* Calculate crc32table */
|
||||||
|
|
@ -89,55 +93,49 @@ static void crc32_init()
|
||||||
uint32_t poly = 0xEDB88320L;
|
uint32_t poly = 0xEDB88320L;
|
||||||
uint32_t crc;
|
uint32_t crc;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
for (i = 0; i < 256; ++i)
|
for (i = 0; i < 256; ++i)
|
||||||
{
|
{
|
||||||
crc = i;
|
crc = i;
|
||||||
|
for (j = 0; j < 8; ++j)
|
||||||
for (j = 8; j > 0; --j)
|
|
||||||
{
|
|
||||||
crc = (crc >> 1) ^ ((crc & 1) ? poly : 0);
|
crc = (crc >> 1) ^ ((crc & 1) ? poly : 0);
|
||||||
}
|
|
||||||
|
|
||||||
crc32table[i] = crc;
|
crc32table[i] = crc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* USB */
|
||||||
/*
|
|
||||||
* DFU
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* must be pow2 <= wTransferSize (2048) */
|
|
||||||
#define DFU_PKT_SZ 2048
|
|
||||||
|
|
||||||
#define APPLE_VID 0x05AC
|
#define APPLE_VID 0x05AC
|
||||||
|
|
||||||
static int KNOWN_PIDS[] =
|
struct pid_info {
|
||||||
|
int pid;
|
||||||
|
int mode; /* 0->DFU, 1->WTF */
|
||||||
|
char *desc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pid_info known_pids[] =
|
||||||
{
|
{
|
||||||
/* DFU */
|
/* DFU */
|
||||||
0x1220, /* Nano 2G */
|
{ 0x1220, 0, "Nano 2G" },
|
||||||
0x1223, /* Nano 3G and Classic 1G/2G/3G/4G */
|
{ 0x1223, 0, "Nano 3G / Classic" },
|
||||||
0x1224, /* Shuffle 3G */
|
{ 0x1224, 0, "Shuffle 3G" },
|
||||||
0x1225, /* Nano 4G */
|
{ 0x1225, 0, "Nano 4G" },
|
||||||
0x1231, /* Nano 5G */
|
{ 0x1231, 0, "Nano 5G" },
|
||||||
0x1232, /* Nano 6G */
|
{ 0x1232, 0, "Nano 6G" },
|
||||||
0x1233, /* Shuffle 4G */
|
{ 0x1233, 0, "Shuffle 4G" },
|
||||||
0x1234, /* Nano 7G */
|
{ 0x1234, 0, "Nano 7G" },
|
||||||
/* WTF */
|
/* WTF */
|
||||||
0x1240, /* Nano 2G */
|
{ 0x1240, 1, "Nano 2G" },
|
||||||
0x1241, /* Classic 1G */
|
{ 0x1241, 1, "Classic 1G" },
|
||||||
0x1242, /* Nano 3G */
|
{ 0x1242, 1, "Nano 3G" },
|
||||||
0x1243, /* Nano 4G */
|
{ 0x1243, 1, "Nano 4G" },
|
||||||
0x1245, /* Classic 2G */
|
{ 0x1245, 1, "Classic 2G" },
|
||||||
0x1246, /* Nano 5G */
|
{ 0x1246, 1, "Nano 5G" },
|
||||||
0x1247, /* Classic 3G */
|
{ 0x1247, 1, "Classic 3G" },
|
||||||
0x1248, /* Nano 6G */
|
{ 0x1248, 1, "Nano 6G" },
|
||||||
0x1249, /* Nano 7G */
|
{ 0x1249, 1, "Nano 7G" },
|
||||||
0x124a, /* Nano 7G */
|
{ 0x124a, 1, "Nano 7G" },
|
||||||
0x1250, /* Classic 4G */
|
{ 0x1250, 1, "Classic 4G" },
|
||||||
0
|
|
||||||
};
|
};
|
||||||
|
#define N_KNOWN_PIDS (sizeof(known_pids)/sizeof(struct pid_info))
|
||||||
|
|
||||||
struct usbControlSetup {
|
struct usbControlSetup {
|
||||||
uint8_t bmRequestType;
|
uint8_t bmRequestType;
|
||||||
|
|
@ -157,8 +155,14 @@ struct usbStatusData {
|
||||||
uint8_t iString;
|
uint8_t iString;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DFU API
|
||||||
|
*/
|
||||||
|
#define DFU_PKT_SZ 2048 /* must be pow2 <= wTransferSize (2048) */
|
||||||
|
|
||||||
/* DFU 1.1 specs */
|
/* DFU 1.1 specs */
|
||||||
typedef enum DFUState {
|
typedef enum {
|
||||||
appIDLE = 0,
|
appIDLE = 0,
|
||||||
appDETACH = 1,
|
appDETACH = 1,
|
||||||
dfuIDLE = 2,
|
dfuIDLE = 2,
|
||||||
|
|
@ -172,7 +176,7 @@ typedef enum DFUState {
|
||||||
dfuERROR = 10
|
dfuERROR = 10
|
||||||
} DFUState;
|
} DFUState;
|
||||||
|
|
||||||
typedef enum DFUStatus {
|
typedef enum {
|
||||||
errNONE = 0,
|
errNONE = 0,
|
||||||
errTARGET = 1,
|
errTARGET = 1,
|
||||||
errFILE = 2,
|
errFILE = 2,
|
||||||
|
|
@ -191,7 +195,7 @@ typedef enum DFUStatus {
|
||||||
errSTALLEDPKT = 15
|
errSTALLEDPKT = 15
|
||||||
} DFUStatus;
|
} DFUStatus;
|
||||||
|
|
||||||
typedef enum DFURequest {
|
typedef enum {
|
||||||
DFU_DETACH = 0,
|
DFU_DETACH = 0,
|
||||||
DFU_DNLOAD = 1,
|
DFU_DNLOAD = 1,
|
||||||
DFU_UPLOAD = 2,
|
DFU_UPLOAD = 2,
|
||||||
|
|
@ -201,12 +205,17 @@ typedef enum DFURequest {
|
||||||
DFU_ABORT = 6
|
DFU_ABORT = 6
|
||||||
} DFURequest;
|
} DFURequest;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DFUAPIFail = 0,
|
||||||
|
DFUAPISuccess,
|
||||||
|
} dfuAPIResult;
|
||||||
|
|
||||||
struct dfuDev {
|
struct dfuDev {
|
||||||
struct dfuAPI *api;
|
struct dfuAPI *api;
|
||||||
int found_pid;
|
int found_pid;
|
||||||
int detached;
|
int detached;
|
||||||
char descr[256];
|
char descr[256];
|
||||||
int res; /* API result: 1->ok, 0->failure */
|
dfuAPIResult res;
|
||||||
char err[256];
|
char err[256];
|
||||||
/* API private */
|
/* API private */
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
|
@ -219,21 +228,25 @@ struct dfuDev {
|
||||||
libusb_device_handle* devh;
|
libusb_device_handle* devh;
|
||||||
int rc; /* libusb return code */
|
int rc; /* libusb return code */
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef __APPLE__
|
||||||
|
IOUSBDeviceInterface** dev;
|
||||||
|
kern_return_t kr;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dfuAPI {
|
struct dfuAPI {
|
||||||
char *name;
|
char *name;
|
||||||
int (*open_fn)(struct dfuDev*, int*);
|
dfuAPIResult (*open_fn)(struct dfuDev*, int*);
|
||||||
int (*dfureq_fn)(struct dfuDev*, struct usbControlSetup*, void*);
|
dfuAPIResult (*dfureq_fn)(struct dfuDev*, struct usbControlSetup*, void*);
|
||||||
int (*reset_fn)(struct dfuDev*);
|
dfuAPIResult (*reset_fn)(struct dfuDev*);
|
||||||
void (*close_fn)(struct dfuDev*);
|
void (*close_fn)(struct dfuDev*);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* low-level (API specific) functions
|
* DFU API low-level (specific) functions
|
||||||
*/
|
*/
|
||||||
static int dfu_check_id(int vid, int pid, int *pid_list)
|
static bool dfu_check_id(int vid, int pid, int *pid_list)
|
||||||
{
|
{
|
||||||
int *p;
|
int *p;
|
||||||
if (vid != APPLE_VID)
|
if (vid != APPLE_VID)
|
||||||
|
|
@ -253,17 +266,17 @@ static void dfu_add_reqerrstr(struct dfuDev *dfuh, struct usbControlSetup *cs)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
static int dfu_winapi_chkrc(struct dfuDev *dfuh, char *str, bool success)
|
static bool dfu_winapi_chkrc(struct dfuDev *dfuh, char *str, bool success)
|
||||||
{
|
{
|
||||||
dfuh->res = (int)success;
|
dfuh->res = (success) ? DFUAPISuccess : DFUAPIFail;
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dfuh->ec = GetLastError();
|
dfuh->ec = GetLastError();
|
||||||
snprintf(dfuh->err, sizeof(dfuh->err), "%s error %ld", str, dfuh->ec);
|
snprintf(dfuh->err, sizeof(dfuh->err), "%s error %ld", str, dfuh->ec);
|
||||||
}
|
}
|
||||||
return dfuh->res;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dfu_winapi_request(struct dfuDev *dfuh,
|
static dfuAPIResult dfu_winapi_request(struct dfuDev *dfuh,
|
||||||
struct usbControlSetup* cs, void* data)
|
struct usbControlSetup* cs, void* data)
|
||||||
{
|
{
|
||||||
unsigned char buf[USB_CS_SZ + DFU_PKT_SZ];
|
unsigned char buf[USB_CS_SZ + DFU_PKT_SZ];
|
||||||
|
|
@ -284,19 +297,20 @@ static int dfu_winapi_request(struct dfuDev *dfuh,
|
||||||
rc = WriteFile(dfuh->ph, buf, USB_CS_SZ + cs->wLength, &rdwr, NULL);
|
rc = WriteFile(dfuh->ph, buf, USB_CS_SZ + cs->wLength, &rdwr, NULL);
|
||||||
dfu_winapi_chkrc(dfuh, "DFU request failed: WriteFile()", rc);
|
dfu_winapi_chkrc(dfuh, "DFU request failed: WriteFile()", rc);
|
||||||
}
|
}
|
||||||
|
if (!rc)
|
||||||
if (!dfuh->res)
|
|
||||||
dfu_add_reqerrstr(dfuh, cs);
|
dfu_add_reqerrstr(dfuh, cs);
|
||||||
|
|
||||||
return dfuh->res;
|
return dfuh->res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dfu_winapi_reset(struct dfuDev *dfuh)
|
static dfuAPIResult dfu_winapi_reset(struct dfuDev *dfuh)
|
||||||
{
|
{
|
||||||
DWORD bytesReturned;
|
DWORD bytesReturned;
|
||||||
bool rc = DeviceIoControl(dfuh->fh, 0x22000c,
|
bool rc = DeviceIoControl(dfuh->fh,
|
||||||
NULL, 0, NULL, 0, &bytesReturned, NULL);
|
0x22000c, NULL, 0, NULL, 0, &bytesReturned, NULL);
|
||||||
return dfu_winapi_chkrc(dfuh,
|
dfu_winapi_chkrc(dfuh,
|
||||||
"Could not reset USB device: DeviceIoControl()", rc);
|
"Could not reset USB device: DeviceIoControl()", rc);
|
||||||
|
return dfuh->res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dfu_winapi_close(struct dfuDev *dfuh)
|
static void dfu_winapi_close(struct dfuDev *dfuh)
|
||||||
|
|
@ -314,7 +328,7 @@ static void dfu_winapi_close(struct dfuDev *dfuh)
|
||||||
static const GUID GUID_AAPLDFU =
|
static const GUID GUID_AAPLDFU =
|
||||||
{ 0xB8085869L, 0xFEB9, 0x404B, {0x8C, 0xB1, 0x1E, 0x5C, 0x14, 0xFA, 0x8C, 0x54}};
|
{ 0xB8085869L, 0xFEB9, 0x404B, {0x8C, 0xB1, 0x1E, 0x5C, 0x14, 0xFA, 0x8C, 0x54}};
|
||||||
|
|
||||||
static int dfu_winapi_open(struct dfuDev *dfuh, int *pid_list)
|
static dfuAPIResult dfu_winapi_open(struct dfuDev *dfuh, int *pid_list)
|
||||||
{
|
{
|
||||||
const GUID *guid = &GUID_AAPLDFU;
|
const GUID *guid = &GUID_AAPLDFU;
|
||||||
HDEVINFO devinfo = NULL;
|
HDEVINFO devinfo = NULL;
|
||||||
|
|
@ -327,7 +341,7 @@ static int dfu_winapi_open(struct dfuDev *dfuh, int *pid_list)
|
||||||
dfuh->fh =
|
dfuh->fh =
|
||||||
dfuh->ph = INVALID_HANDLE_VALUE;
|
dfuh->ph = INVALID_HANDLE_VALUE;
|
||||||
dfuh->found_pid = 0;
|
dfuh->found_pid = 0;
|
||||||
dfuh->res = 1; /* ok */
|
dfuh->res = DFUAPISuccess;
|
||||||
dfuh->ec = 0;
|
dfuh->ec = 0;
|
||||||
|
|
||||||
/* Get DFU path */
|
/* Get DFU path */
|
||||||
|
|
@ -398,16 +412,16 @@ error:
|
||||||
#endif /* WIN32 */
|
#endif /* WIN32 */
|
||||||
|
|
||||||
#ifdef USE_LIBUSBAPI
|
#ifdef USE_LIBUSBAPI
|
||||||
static int dfu_libusb_chkrc(struct dfuDev *dfuh, char *str)
|
static bool dfu_libusb_chkrc(struct dfuDev *dfuh, char *str)
|
||||||
{
|
{
|
||||||
dfuh->res = (dfuh->rc < LIBUSB_SUCCESS) ? 0 : 1;
|
dfuh->res = (dfuh->rc < LIBUSB_SUCCESS) ? DFUAPIFail : DFUAPISuccess;
|
||||||
if (dfuh->res == 0)
|
if (dfuh->res == DFUAPIFail)
|
||||||
snprintf(dfuh->err, sizeof(dfuh->err),
|
snprintf(dfuh->err, sizeof(dfuh->err),
|
||||||
"%s: %s", str, libusb_error_name(dfuh->rc));
|
"%s: %s", str, libusb_error_name(dfuh->rc));
|
||||||
return dfuh->res;
|
return (dfuh->res == DFUAPISuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dfu_libusb_request(struct dfuDev *dfuh,
|
static dfuAPIResult dfu_libusb_request(struct dfuDev *dfuh,
|
||||||
struct usbControlSetup *cs, void *data)
|
struct usbControlSetup *cs, void *data)
|
||||||
{
|
{
|
||||||
dfuh->rc = libusb_control_transfer(dfuh->devh, cs->bmRequestType,
|
dfuh->rc = libusb_control_transfer(dfuh->devh, cs->bmRequestType,
|
||||||
|
|
@ -417,10 +431,11 @@ static int dfu_libusb_request(struct dfuDev *dfuh,
|
||||||
return dfuh->res;
|
return dfuh->res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dfu_libusb_reset(struct dfuDev *dfuh)
|
static dfuAPIResult dfu_libusb_reset(struct dfuDev *dfuh)
|
||||||
{
|
{
|
||||||
dfuh->rc = libusb_reset_device(dfuh->devh);
|
dfuh->rc = libusb_reset_device(dfuh->devh);
|
||||||
return dfu_libusb_chkrc(dfuh, "Could not reset USB device");
|
dfu_libusb_chkrc(dfuh, "Could not reset USB device");
|
||||||
|
return dfuh->res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dfu_libusb_close(struct dfuDev *dfuh)
|
static void dfu_libusb_close(struct dfuDev *dfuh)
|
||||||
|
|
@ -438,7 +453,7 @@ static void dfu_libusb_close(struct dfuDev *dfuh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dfu_libusb_open(struct dfuDev *dfuh, int *pid_list)
|
static dfuAPIResult dfu_libusb_open(struct dfuDev *dfuh, int *pid_list)
|
||||||
{
|
{
|
||||||
struct libusb_device_descriptor desc;
|
struct libusb_device_descriptor desc;
|
||||||
libusb_device **devs = NULL, *dev;
|
libusb_device **devs = NULL, *dev;
|
||||||
|
|
@ -447,7 +462,7 @@ static int dfu_libusb_open(struct dfuDev *dfuh, int *pid_list)
|
||||||
dfuh->devh = NULL;
|
dfuh->devh = NULL;
|
||||||
dfuh->found_pid = 0;
|
dfuh->found_pid = 0;
|
||||||
dfuh->detached = 0;
|
dfuh->detached = 0;
|
||||||
dfuh->res = 1; /* ok */
|
dfuh->res = DFUAPISuccess;
|
||||||
|
|
||||||
dfuh->rc = libusb_init(&(dfuh->ctx));
|
dfuh->rc = libusb_init(&(dfuh->ctx));
|
||||||
if (!dfu_libusb_chkrc(dfuh, "Could not init USB library")) {
|
if (!dfu_libusb_chkrc(dfuh, "Could not init USB library")) {
|
||||||
|
|
@ -517,10 +532,138 @@ error:
|
||||||
}
|
}
|
||||||
#endif /* USE_LIBUSBAPI */
|
#endif /* USE_LIBUSBAPI */
|
||||||
|
|
||||||
/* list of suported APIs:
|
#ifdef __APPLE__
|
||||||
* Windows: winapi and libusb (optional)
|
static bool dfu_iokit_chkrc(struct dfuDev *dfuh, char *str)
|
||||||
* Linux and OSX: libusb
|
{
|
||||||
*/
|
dfuh->res = (dfuh->kr == kIOReturnSuccess) ? DFUAPISuccess : DFUAPIFail;
|
||||||
|
if (dfuh->res == DFUAPIFail)
|
||||||
|
snprintf(dfuh->err, sizeof(dfuh->err),
|
||||||
|
"%s: error %08x", str, dfuh->kr);
|
||||||
|
return (dfuh->res == DFUAPISuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dfuAPIResult dfu_iokit_request(struct dfuDev *dfuh,
|
||||||
|
struct usbControlSetup *cs, void *data)
|
||||||
|
{
|
||||||
|
IOUSBDevRequest req;
|
||||||
|
req.bmRequestType = cs->bmRequestType;
|
||||||
|
req.bRequest = cs->bRequest;
|
||||||
|
req.wValue = cs->wValue;
|
||||||
|
req.wIndex = cs->wIndex;
|
||||||
|
req.wLength = cs->wLength;
|
||||||
|
req.pData = data;
|
||||||
|
|
||||||
|
dfuh->kr = (*(dfuh->dev))->DeviceRequest(dfuh->dev, &req);
|
||||||
|
if (!dfu_iokit_chkrc(dfuh, "DFU request failed"))
|
||||||
|
dfu_add_reqerrstr(dfuh, cs);
|
||||||
|
|
||||||
|
return dfuh->res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static dfuAPIResult dfu_iokit_reset(struct dfuDev *dfuh)
|
||||||
|
{
|
||||||
|
dfuh->kr = (*(dfuh->dev))->ResetDevice(dfuh->dev);
|
||||||
|
#if 0
|
||||||
|
/* On 10.11+ ResetDevice() returns no error but does not perform
|
||||||
|
* any reset, just a kernel log message.
|
||||||
|
* USBDeviceReEnumerate() could be used as a workaround.
|
||||||
|
*/
|
||||||
|
dfuh->kr = (*(dfuh->dev))->USBDeviceReEnumerate(dfuh->dev, 0);
|
||||||
|
#endif
|
||||||
|
dfu_iokit_chkrc(dfuh, "Could not reset USB device");
|
||||||
|
return dfuh->res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dfu_iokit_close(struct dfuDev *dfuh)
|
||||||
|
{
|
||||||
|
if (dfuh->dev) {
|
||||||
|
(*(dfuh->dev))->USBDeviceClose(dfuh->dev);
|
||||||
|
(*(dfuh->dev))->Release(dfuh->dev);
|
||||||
|
dfuh->dev = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static dfuAPIResult dfu_iokit_open(struct dfuDev *dfuh, int *pid_list)
|
||||||
|
{
|
||||||
|
kern_return_t kr;
|
||||||
|
CFMutableDictionaryRef usb_matching_dict = 0;
|
||||||
|
io_object_t usbDevice;
|
||||||
|
io_iterator_t usb_iterator = IO_OBJECT_NULL;
|
||||||
|
IOCFPlugInInterface **plugInInterface = NULL;
|
||||||
|
IOUSBDeviceInterface **dev = NULL;
|
||||||
|
HRESULT result;
|
||||||
|
SInt32 score;
|
||||||
|
UInt16 vendor;
|
||||||
|
UInt16 product;
|
||||||
|
UInt16 release;
|
||||||
|
|
||||||
|
dfuh->dev = NULL;
|
||||||
|
dfuh->found_pid = 0;
|
||||||
|
dfuh->res = DFUAPISuccess;
|
||||||
|
|
||||||
|
usb_matching_dict = IOServiceMatching(kIOUSBDeviceClassName);
|
||||||
|
dfuh->kr = IOServiceGetMatchingServices(
|
||||||
|
kIOMasterPortDefault, usb_matching_dict, &usb_iterator);
|
||||||
|
if (!dfu_iokit_chkrc(dfuh, "Could not get matching services"))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
while ((usbDevice = IOIteratorNext(usb_iterator)))
|
||||||
|
{
|
||||||
|
/* Create an intermediate plug-in */
|
||||||
|
kr = IOCreatePlugInInterfaceForService(usbDevice,
|
||||||
|
kIOUSBDeviceUserClientTypeID,
|
||||||
|
kIOCFPlugInInterfaceID,
|
||||||
|
&plugInInterface,
|
||||||
|
&score);
|
||||||
|
IOObjectRelease(usbDevice);
|
||||||
|
|
||||||
|
if ((kIOReturnSuccess != kr) || !plugInInterface)
|
||||||
|
continue; /* Unable to create a plugin */
|
||||||
|
|
||||||
|
/* Now create the device interface */
|
||||||
|
result = (*plugInInterface)->QueryInterface(plugInInterface,
|
||||||
|
CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
|
||||||
|
(LPVOID*)&dev);
|
||||||
|
(*plugInInterface)->Release(plugInInterface);
|
||||||
|
|
||||||
|
if (result || !dev)
|
||||||
|
continue; /* Couldn't create a device interface */
|
||||||
|
|
||||||
|
kr = (*dev)->GetDeviceVendor(dev, &vendor);
|
||||||
|
kr = (*dev)->GetDeviceProduct(dev, &product);
|
||||||
|
kr = (*dev)->GetDeviceReleaseNumber(dev, &release);
|
||||||
|
|
||||||
|
if (!dfu_check_id(vendor, product, pid_list)) {
|
||||||
|
(*dev)->Release(dev);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Device found, open it */
|
||||||
|
dfuh->kr = (*dev)->USBDeviceOpen(dev);
|
||||||
|
if (!dfu_iokit_chkrc(dfuh, "Could not open USB device")) {
|
||||||
|
(*dev)->Release(dev);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ok */
|
||||||
|
dfuh->found_pid = product;
|
||||||
|
dfuh->dev = dev;
|
||||||
|
snprintf(dfuh->descr, sizeof(dfuh->descr),
|
||||||
|
"[%04x:%04x] release: %d", vendor, product, release);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bye:
|
||||||
|
if (usb_iterator != IO_OBJECT_NULL)
|
||||||
|
IOObjectRelease(usb_iterator);
|
||||||
|
return dfuh->res;
|
||||||
|
|
||||||
|
error:
|
||||||
|
goto bye;
|
||||||
|
}
|
||||||
|
#endif /* __APPLE__ */
|
||||||
|
|
||||||
|
/* list of suported APIs */
|
||||||
static struct dfuAPI api_list[] =
|
static struct dfuAPI api_list[] =
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
|
@ -538,22 +681,22 @@ static struct dfuAPI api_list[] =
|
||||||
dfu_libusb_close },
|
dfu_libusb_close },
|
||||||
#endif
|
#endif
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
/* TODO: implement API for OS X < 10.6 ??? */
|
{ "IOKit",
|
||||||
|
dfu_iokit_open,
|
||||||
|
dfu_iokit_request,
|
||||||
|
dfu_iokit_reset,
|
||||||
|
dfu_iokit_close },
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
#define DFU_N_APIS (sizeof(api_list)/sizeof(struct dfuAPI))
|
#define N_DFU_APIS (sizeof(api_list)/sizeof(struct dfuAPI))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mid-layer (common) functions
|
* DFU API common functions
|
||||||
*/
|
*/
|
||||||
static void dfu_set_errstr(struct dfuDev *dfuh, char *str)
|
|
||||||
{
|
|
||||||
strncpy(dfuh->err, str, sizeof(dfuh->err));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int DEBUG_DFUREQ = 0;
|
static int DEBUG_DFUREQ = 0;
|
||||||
|
|
||||||
static int dfu_request(struct dfuDev *dfuh,
|
static dfuAPIResult dfuapi_request(struct dfuDev *dfuh,
|
||||||
struct usbControlSetup *cs, void *data)
|
struct usbControlSetup *cs, void *data)
|
||||||
{
|
{
|
||||||
if (!DEBUG_DFUREQ)
|
if (!DEBUG_DFUREQ)
|
||||||
|
|
@ -564,16 +707,17 @@ static int dfu_request(struct dfuDev *dfuh,
|
||||||
/* previous state */
|
/* previous state */
|
||||||
unsigned char ste = 0;
|
unsigned char ste = 0;
|
||||||
struct usbControlSetup css = { 0xA1, DFU_GETSTATE, 0, 0, sizeof(ste) };
|
struct usbControlSetup css = { 0xA1, DFU_GETSTATE, 0, 0, sizeof(ste) };
|
||||||
if (!dfuh->api->dfureq_fn(dfuh, &css, &ste)) {
|
if (dfuh->api->dfureq_fn(dfuh, &css, &ste) != DFUAPISuccess) {
|
||||||
snprintf(dfuh->err + strlen(dfuh->err), sizeof(dfuh->err) -
|
snprintf(dfuh->err + strlen(dfuh->err), sizeof(dfuh->err) -
|
||||||
strlen(dfuh->err), " [DEBUG_DFUREQ ERROR: state=%d]", ste);
|
strlen(dfuh->err), " [DEBUG_DFUREQ ERROR: state=%d]", ste);
|
||||||
return 0;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = dfuh->api->dfureq_fn(dfuh, cs, data);
|
dfuh->api->dfureq_fn(dfuh, cs, data);
|
||||||
fprintf(stderr, "[DEBUG]: REQ: ste=%d, cs=%2x/%d/%d/%d/%d -> %s",
|
fprintf(stderr, "[DEBUG]: REQ: ste=%d, cs=%2x/%d/%d/%d/%d -> %s",
|
||||||
ste, cs->bmRequestType, cs->bRequest, cs->wValue,
|
ste, cs->bmRequestType, cs->bRequest, cs->wValue,
|
||||||
cs->wIndex, cs->wLength, ret ? "ok" : "ERROR");
|
cs->wIndex, cs->wLength,
|
||||||
|
(dfuh->res == DFUAPISuccess) ? "ok" : "ERROR");
|
||||||
if (cs->bRequest == DFU_GETSTATE)
|
if (cs->bRequest == DFU_GETSTATE)
|
||||||
fprintf(stderr, " (state=%d)", *((unsigned char*)(data)));
|
fprintf(stderr, " (state=%d)", *((unsigned char*)(data)));
|
||||||
if (cs->bRequest == DFU_GETSTATUS) {
|
if (cs->bRequest == DFU_GETSTATUS) {
|
||||||
|
|
@ -584,106 +728,189 @@ static int dfu_request(struct dfuDev *dfuh,
|
||||||
}
|
}
|
||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
return ret;
|
|
||||||
|
bye:
|
||||||
|
return dfuh->res;
|
||||||
|
error:
|
||||||
|
goto bye;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dfureq_getstatus(struct dfuDev *dfuh, int *status,
|
static dfuAPIResult dfuapi_req_getstatus(struct dfuDev *dfuh,
|
||||||
int *poll_tmo /*ms*/, int *state)
|
DFUStatus *status, int *poll_tmo /*ms*/,
|
||||||
|
DFUState *state)
|
||||||
{
|
{
|
||||||
struct usbStatusData sd = { 0, 0, 0, 0, 0, 0 };
|
struct usbStatusData sd = { 0, 0, 0, 0, 0, 0 };
|
||||||
struct usbControlSetup cs = { 0xA1, DFU_GETSTATUS, 0, 0, sizeof(sd) };
|
struct usbControlSetup cs = { 0xA1, DFU_GETSTATUS, 0, 0, sizeof(sd) };
|
||||||
int ret = dfu_request(dfuh, &cs, &sd);
|
dfuapi_request(dfuh, &cs, &sd);
|
||||||
if (status) *status = sd.bStatus;
|
if (status) *status = sd.bStatus;
|
||||||
if (state) *state = sd.bState;
|
if (state) *state = sd.bState;
|
||||||
if (poll_tmo) *poll_tmo = (sd.bwPollTimeout2 << 16) |
|
if (poll_tmo) *poll_tmo = (sd.bwPollTimeout2 << 16) |
|
||||||
(sd.bwPollTimeout1 << 8) | (sd.bwPollTimeout0);
|
(sd.bwPollTimeout1 << 8) | (sd.bwPollTimeout0);
|
||||||
return ret;
|
return dfuh->res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dfureq_getstate(struct dfuDev *dfuh, int *state)
|
static dfuAPIResult dfuapi_req_getstate(struct dfuDev *dfuh, DFUState *state)
|
||||||
{
|
{
|
||||||
if (!state)
|
|
||||||
return 1; /* nothing to do */
|
|
||||||
unsigned char sts = 0;
|
unsigned char sts = 0;
|
||||||
struct usbControlSetup cs = { 0xA1, DFU_GETSTATE, 0, 0, sizeof(sts) };
|
struct usbControlSetup cs = { 0xA1, DFU_GETSTATE, 0, 0, sizeof(sts) };
|
||||||
int ret = dfu_request(dfuh, &cs, &sts);
|
dfuapi_request(dfuh, &cs, &sts);
|
||||||
*state = sts;
|
if (state) *state = sts;
|
||||||
return ret;
|
return dfuh->res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dfureq_dnload(struct dfuDev* dfuh, uint16_t blknum,
|
static dfuAPIResult dfuapi_req_dnload(struct dfuDev* dfuh, uint16_t blknum,
|
||||||
uint16_t len, unsigned char *data)
|
uint16_t len, unsigned char *data)
|
||||||
{
|
{
|
||||||
struct usbControlSetup cs = { 0x21, DFU_DNLOAD, blknum, 0, len };
|
struct usbControlSetup cs = { 0x21, DFU_DNLOAD, blknum, 0, len };
|
||||||
return dfu_request(dfuh, &cs, data);
|
return dfuapi_request(dfuh, &cs, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* not used */
|
/* not used */
|
||||||
#if 0
|
#if 0
|
||||||
static int dfureq_upload(struct dfuDev* dfuh,
|
static dfuAPIResult dfuapi_req_upload(struct dfuDev* dfuh,
|
||||||
uint16_t blknum, uint16_t len, unsigned char *data)
|
uint16_t blknum, uint16_t len, unsigned char *data)
|
||||||
{
|
{
|
||||||
struct usbControlSetup cs = { 0xA1, DFU_UPLOAD, blknum, 0, len };
|
struct usbControlSetup cs = { 0xA1, DFU_UPLOAD, blknum, 0, len };
|
||||||
return dfu_request(dfuh, &cs, data);
|
return dfuapi_request(dfuh, &cs, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dfureq_clrstatus(struct dfuDev* dfuh)
|
static dfuAPIResult dfuapi_req_clrstatus(struct dfuDev* dfuh)
|
||||||
{
|
{
|
||||||
struct usbControlSetup cs = { 0x21, DFU_CLRSTATUS, 0, 0, 0 };
|
struct usbControlSetup cs = { 0x21, DFU_CLRSTATUS, 0, 0, 0 };
|
||||||
return dfu_request(dfuh, &cs, NULL);
|
return dfuapi_request(dfuh, &cs, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dfureq_abort(struct dfuDev* dfuh)
|
static dfuAPIResult dfuapi_req_abort(struct dfuDev* dfuh)
|
||||||
{
|
{
|
||||||
struct usbControlSetup cs = { 0x21, DFU_ABORT, 0, 0, 0 };
|
struct usbControlSetup cs = { 0x21, DFU_ABORT, 0, 0, 0 };
|
||||||
return dfu_request(dfuh, &cs, NULL);
|
return dfuapi_request(dfuh, &cs, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* not implemented on DFU8702 */
|
/* not implemented on DFU8702 */
|
||||||
static int dfureq_detach(struct dfuDev* dfuh, int tmo)
|
static dfuAPIResult dfuapi_req_detach(struct dfuDev* dfuh, int tmo)
|
||||||
{
|
{
|
||||||
struct usbControlSetup cs = { 0x21, DFU_DETACH, tmo, 0, 0 };
|
struct usbControlSetup cs = { 0x21, DFU_DETACH, tmo, 0, 0 };
|
||||||
return dfu_request(dfuh, &cs, NULL);
|
return dfuapi_request(dfuh, &cs, NULL);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int dfu_send_packet(struct dfuDev* dfuh, uint16_t blknum,
|
static dfuAPIResult dfuapi_reset(struct dfuDev *dfuh)
|
||||||
uint16_t len, unsigned char *data, int *status,
|
|
||||||
int *poll_tmo, int *state, int *pre_state)
|
|
||||||
{
|
{
|
||||||
if (!dfureq_dnload(dfuh, blknum, len, data))
|
return dfuh->api->reset_fn(dfuh);
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
|
static dfuAPIResult dfuapi_send_packet(struct dfuDev* dfuh, uint16_t blknum,
|
||||||
|
uint16_t len, unsigned char *data, DFUStatus *status,
|
||||||
|
int *poll_tmo, DFUState *state, DFUState *pre_state)
|
||||||
|
{
|
||||||
|
if (dfuapi_req_dnload(dfuh, blknum, len, data) != DFUAPISuccess)
|
||||||
|
goto error;
|
||||||
|
|
||||||
/* device is in dfuDLSYNC state, waiting for a GETSTATUS request
|
/* device is in dfuDLSYNC state, waiting for a GETSTATUS request
|
||||||
to enter the next state, if she respond with dfuDLBUSY then
|
* to enter the next state, if she respond with dfuDLBUSY then
|
||||||
we must wait to resend the GETSTATUS request */
|
* we must wait to resend the GETSTATUS request */
|
||||||
|
|
||||||
if (!dfureq_getstatus(dfuh, status, poll_tmo, state))
|
if (dfuapi_req_getstatus(dfuh, status, poll_tmo, state) != DFUAPISuccess)
|
||||||
return 0;
|
goto error;
|
||||||
|
|
||||||
if (*state == dfuDNBUSY) {
|
if (*state == dfuDNBUSY) {
|
||||||
if (*poll_tmo)
|
if (*poll_tmo)
|
||||||
sleep_ms(*poll_tmo);
|
sleep_ms(*poll_tmo);
|
||||||
if (!dfureq_getstate(dfuh, pre_state))
|
if (pre_state)
|
||||||
return 0;
|
if (dfuapi_req_getstate(dfuh, pre_state) != DFUAPISuccess)
|
||||||
if (!dfureq_getstatus(dfuh, status, poll_tmo, state))
|
goto error;
|
||||||
return 0;
|
if (dfuapi_req_getstatus(dfuh, status, poll_tmo, state) != DFUAPISuccess)
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
bye:
|
||||||
|
return dfuh->res;
|
||||||
|
error:
|
||||||
|
goto bye;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dfu_download_file(struct dfuDev* dfuh,
|
static void dfuapi_set_err(struct dfuDev *dfuh, char *str)
|
||||||
|
{
|
||||||
|
dfuh->res = DFUAPIFail;
|
||||||
|
strncpy(dfuh->err, str, sizeof(dfuh->err));
|
||||||
|
}
|
||||||
|
|
||||||
|
static dfuAPIResult dfuapi_open(struct dfuDev *dfuh, int pid)
|
||||||
|
{
|
||||||
|
int pid_l[N_KNOWN_PIDS+1] = { 0 };
|
||||||
|
struct dfuAPI *api;
|
||||||
|
unsigned i, p;
|
||||||
|
|
||||||
|
/* fill pid list */
|
||||||
|
if (pid)
|
||||||
|
pid_l[0] = pid;
|
||||||
|
else
|
||||||
|
for (p = 0; p < N_KNOWN_PIDS; p++)
|
||||||
|
pid_l[p] = known_pids[p].pid;
|
||||||
|
|
||||||
|
for (i = 0; i < N_DFU_APIS; i++)
|
||||||
|
{
|
||||||
|
api = &api_list[i];
|
||||||
|
if (api->open_fn(dfuh, pid_l) != DFUAPISuccess)
|
||||||
|
goto error;
|
||||||
|
if (dfuh->found_pid) {
|
||||||
|
/* ok */
|
||||||
|
dfuh->api = api;
|
||||||
|
printf("[INFO] %s: found %s\n", api->name, dfuh->descr);
|
||||||
|
for (p = 0; p < N_KNOWN_PIDS; p++) {
|
||||||
|
if (known_pids[p].pid == dfuh->found_pid) {
|
||||||
|
printf("[INFO] iPod %s, mode: %s\n", known_pids[p].desc,
|
||||||
|
known_pids[p].mode ? "WTF" : "DFU");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
goto bye;
|
||||||
|
}
|
||||||
|
printf("[INFO] %s: no DFU devices found\n", api->name);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* error */
|
||||||
|
dfuapi_set_err(dfuh, "DFU device not found");
|
||||||
|
|
||||||
|
bye:
|
||||||
|
return dfuh->res;
|
||||||
|
error:
|
||||||
|
goto bye;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dfuapi_destroy(struct dfuDev *dfuh)
|
||||||
|
{
|
||||||
|
if (dfuh) {
|
||||||
|
if (dfuh->api)
|
||||||
|
dfuh->api->close_fn(dfuh);
|
||||||
|
free(dfuh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dfuDev *dfuapi_create(void)
|
||||||
|
{
|
||||||
|
return calloc(sizeof(struct dfuDev), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* app level functions
|
||||||
|
*/
|
||||||
|
static int ipoddfu_download_file(struct dfuDev* dfuh,
|
||||||
unsigned char *data, unsigned long size)
|
unsigned char *data, unsigned long size)
|
||||||
{
|
{
|
||||||
unsigned int blknum, len, remaining;
|
unsigned int blknum, len, remaining;
|
||||||
int status, poll_tmo, state;
|
int poll_tmo;
|
||||||
|
DFUStatus status;
|
||||||
|
DFUState state;
|
||||||
|
|
||||||
if (!dfureq_getstate(dfuh, &state))
|
if (dfuapi_req_getstate(dfuh, &state) != DFUAPISuccess)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (state != dfuIDLE) {
|
if (state != dfuIDLE) {
|
||||||
dfu_set_errstr(dfuh, "Could not start DFU download: not idle");
|
dfuapi_set_err(dfuh, "Could not start DFU download: not idle");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -693,12 +920,12 @@ static int dfu_download_file(struct dfuDev* dfuh,
|
||||||
{
|
{
|
||||||
len = (remaining < DFU_PKT_SZ) ? remaining : DFU_PKT_SZ;
|
len = (remaining < DFU_PKT_SZ) ? remaining : DFU_PKT_SZ;
|
||||||
|
|
||||||
if (!dfu_send_packet(dfuh, blknum, len, data +
|
if (dfuapi_send_packet(dfuh, blknum, len, data + blknum*DFU_PKT_SZ,
|
||||||
blknum*DFU_PKT_SZ, &status, &poll_tmo, &state, NULL))
|
&status, &poll_tmo, &state, NULL) != DFUAPISuccess)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (state != dfuDNLOAD_IDLE) {
|
if (state != dfuDNLOAD_IDLE) {
|
||||||
dfu_set_errstr(dfuh, "DFU download aborted: unexpected state");
|
dfuapi_set_err(dfuh, "DFU download aborted: unexpected state");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -707,9 +934,9 @@ static int dfu_download_file(struct dfuDev* dfuh,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send ZLP */
|
/* send ZLP */
|
||||||
int pre_state = 0;
|
DFUState pre_state = appIDLE; /* dummy state */
|
||||||
if (!dfu_send_packet(dfuh, blknum, 0, NULL,
|
if (dfuapi_send_packet(dfuh, blknum, 0, NULL,
|
||||||
&status, &poll_tmo, &state, &pre_state)) {
|
&status, &poll_tmo, &state, &pre_state) != DFUAPISuccess) {
|
||||||
if (pre_state == dfuMANIFEST_SYNC)
|
if (pre_state == dfuMANIFEST_SYNC)
|
||||||
goto ok; /* pwnaged .dfu file */
|
goto ok; /* pwnaged .dfu file */
|
||||||
goto error;
|
goto error;
|
||||||
|
|
@ -717,9 +944,9 @@ static int dfu_download_file(struct dfuDev* dfuh,
|
||||||
|
|
||||||
if (state != dfuMANIFEST) {
|
if (state != dfuMANIFEST) {
|
||||||
if (status == errFIRMWARE)
|
if (status == errFIRMWARE)
|
||||||
dfu_set_errstr(dfuh, "DFU download failed: corrupt firmware");
|
dfuapi_set_err(dfuh, "DFU download failed: corrupt firmware");
|
||||||
else
|
else
|
||||||
dfu_set_errstr(dfuh, "DFU download failed: unexpected state");
|
dfuapi_set_err(dfuh, "DFU download failed: unexpected state");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -727,21 +954,20 @@ static int dfu_download_file(struct dfuDev* dfuh,
|
||||||
if (poll_tmo)
|
if (poll_tmo)
|
||||||
sleep_ms(poll_tmo);
|
sleep_ms(poll_tmo);
|
||||||
|
|
||||||
if (!dfureq_getstatus(dfuh, &status, NULL, &state))
|
if (dfuapi_req_getstatus(dfuh, &status, NULL, &state) != DFUAPISuccess)
|
||||||
goto ok; /* 1223 .dfu file */
|
goto ok; /* 1223 .dfu file */
|
||||||
|
|
||||||
|
/* XXX: next code never tested */
|
||||||
/* TODO: next code never tested */
|
|
||||||
|
|
||||||
if (state != dfuMANIFEST_WAIT_RESET) {
|
if (state != dfuMANIFEST_WAIT_RESET) {
|
||||||
if (status == errVERIFY)
|
if (status == errVERIFY)
|
||||||
dfu_set_errstr(dfuh, "DFU manifest failed: wrong FW verification");
|
dfuapi_set_err(dfuh, "DFU manifest failed: wrong FW verification");
|
||||||
else
|
else
|
||||||
dfu_set_errstr(dfuh, "DFU manifest failed: unexpected state");
|
dfuapi_set_err(dfuh, "DFU manifest failed: unexpected state");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dfuh->api->reset_fn(dfuh))
|
if (dfuapi_reset(dfuh) != DFUAPISuccess)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
ok:
|
ok:
|
||||||
|
|
@ -750,86 +976,42 @@ error:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dfu_open(struct dfuDev *dfuh, int pid)
|
/* exported functions */
|
||||||
{
|
|
||||||
int pid_l[2] = {0};
|
|
||||||
struct dfuAPI *api;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
pid_l[0] = pid;
|
|
||||||
|
|
||||||
for (i = 0; i < DFU_N_APIS; i++)
|
|
||||||
{
|
|
||||||
api = &api_list[i];
|
|
||||||
if (!(api->open_fn(dfuh, pid ? pid_l : KNOWN_PIDS)))
|
|
||||||
return 0; /* error */
|
|
||||||
if (dfuh->found_pid) {
|
|
||||||
dfuh->api = api;
|
|
||||||
printf("[INFO] %s: found %s\n", api->name, dfuh->descr);
|
|
||||||
fflush(stdout);
|
|
||||||
return 1; /* ok */
|
|
||||||
}
|
|
||||||
printf("[INFO] %s: no DFU devices found\n", api->name);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
dfu_set_errstr(dfuh, "DFU device not found");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dfu_destroy(struct dfuDev *dfuh)
|
|
||||||
{
|
|
||||||
if (dfuh) {
|
|
||||||
if (dfuh->api)
|
|
||||||
dfuh->api->close_fn(dfuh);
|
|
||||||
free(dfuh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct dfuDev *dfu_create()
|
|
||||||
{
|
|
||||||
return calloc(sizeof(struct dfuDev), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* exported functions
|
|
||||||
*/
|
|
||||||
int ipoddfu_send(int pid, unsigned char *data, int size,
|
int ipoddfu_send(int pid, unsigned char *data, int size,
|
||||||
char* errstr, int errstrsize)
|
char* errstr, int errstrsize)
|
||||||
{
|
{
|
||||||
struct dfuDev *dfuh;
|
struct dfuDev *dfuh;
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
unsigned int checksum;
|
uint32_t checksum;
|
||||||
int ret = 1; /* ok */
|
int ret = 1; /* ok */
|
||||||
|
|
||||||
dfuh = dfu_create();
|
dfuh = dfuapi_create();
|
||||||
|
|
||||||
buf = malloc(size+4);
|
buf = malloc(size+4);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
dfu_set_errstr(dfuh, "Could not allocate memory for DFU buffer");
|
dfuapi_set_err(dfuh, "Could not allocate memory for DFU buffer");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(data, IM3_IDENT, 4)) {
|
if (memcmp(data, IM3_IDENT, 4)) {
|
||||||
dfu_set_errstr(dfuh, "Bad DFU image data");
|
dfuapi_set_err(dfuh, "Bad DFU image data");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: big endian */
|
|
||||||
crc32_init();
|
crc32_init();
|
||||||
checksum = crc32(data, size, CRC32_DEFAULT_SEED);
|
checksum = crc32(data, size, 0);
|
||||||
memcpy(buf, data, size);
|
memcpy(buf, data, size);
|
||||||
memcpy(buf+size, &checksum, 4);
|
put_uint32le(buf+size, ~checksum);
|
||||||
|
|
||||||
if (!dfu_open(dfuh, pid))
|
if (dfuapi_open(dfuh, pid) != DFUAPISuccess)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!dfu_download_file(dfuh, buf, size+4))
|
if (!ipoddfu_download_file(dfuh, buf, size+4))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
bye:
|
bye:
|
||||||
if (buf) free(buf);
|
if (buf) free(buf);
|
||||||
dfu_destroy(dfuh);
|
dfuapi_destroy(dfuh);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
|
@ -846,20 +1028,24 @@ int ipoddfu_scan(int pid, int *state, int reset,
|
||||||
struct dfuDev *dfuh;
|
struct dfuDev *dfuh;
|
||||||
int ret = 1; /* ok */
|
int ret = 1; /* ok */
|
||||||
|
|
||||||
dfuh = dfu_create();
|
dfuh = dfuapi_create();
|
||||||
|
|
||||||
if (!dfu_open(dfuh, pid))
|
if (dfuapi_open(dfuh, pid) != DFUAPISuccess)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (reset)
|
if (reset)
|
||||||
if (!dfuh->api->reset_fn(dfuh))
|
if (dfuapi_reset(dfuh) != DFUAPISuccess)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!dfureq_getstate(dfuh, state))
|
if (state) {
|
||||||
goto error;
|
DFUState sts;
|
||||||
|
if (dfuapi_req_getstate(dfuh, &sts) != DFUAPISuccess)
|
||||||
|
goto error;
|
||||||
|
*state = (int)sts;
|
||||||
|
}
|
||||||
|
|
||||||
bye:
|
bye:
|
||||||
dfu_destroy(dfuh);
|
dfuapi_destroy(dfuh);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <time.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
|
@ -35,9 +34,23 @@
|
||||||
#define O_BINARY 0
|
#define O_BINARY 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#define sleep_ms(ms) Sleep(ms)
|
||||||
|
#else
|
||||||
|
#include <time.h>
|
||||||
|
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 DEFAULT_LOOP_PERIOD 1 /* seconds */
|
||||||
|
|
||||||
#define ERROR(format, ...) \
|
#define _ERR(format, ...) \
|
||||||
do { \
|
do { \
|
||||||
snprintf(errstr, errstrsize, "[ERR] "format, __VA_ARGS__); \
|
snprintf(errstr, errstrsize, "[ERR] "format, __VA_ARGS__); \
|
||||||
goto error; \
|
goto error; \
|
||||||
|
|
@ -48,10 +61,10 @@ static int write_file(char *outfile, unsigned char* buf,
|
||||||
{
|
{
|
||||||
int fd = open(outfile, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666);
|
int fd = open(outfile, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
ERROR("Could not open %s for writing", outfile);
|
_ERR("Could not open %s for writing", outfile);
|
||||||
|
|
||||||
if (write(fd, buf, bufsize) != bufsize)
|
if (write(fd, buf, bufsize) != bufsize)
|
||||||
ERROR("Could not write file %s", outfile);
|
_ERR("Could not write file %s", outfile);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
|
@ -68,19 +81,19 @@ static unsigned char *read_file(char *infile, int *bufsize,
|
||||||
|
|
||||||
fd = open(infile, O_RDONLY|O_BINARY);
|
fd = open(infile, O_RDONLY|O_BINARY);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
ERROR("Could not open %s for reading", infile);
|
_ERR("Could not open %s for reading", infile);
|
||||||
|
|
||||||
if (fstat(fd, &s) < 0)
|
if (fstat(fd, &s) < 0)
|
||||||
ERROR("Checking size of input file %s", infile);
|
_ERR("Checking size of input file %s", infile);
|
||||||
|
|
||||||
*bufsize = s.st_size;
|
*bufsize = s.st_size;
|
||||||
|
|
||||||
buf = malloc(*bufsize);
|
buf = malloc(*bufsize);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
ERROR("Could not allocate memory for %s", infile);
|
_ERR("Could not allocate memory for %s", infile);
|
||||||
|
|
||||||
if (read(fd, buf, *bufsize) != *bufsize)
|
if (read(fd, buf, *bufsize) != *bufsize)
|
||||||
ERROR("Could not read file %s", infile);
|
_ERR("Could not read file %s", infile);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
|
|
||||||
|
|
@ -88,14 +101,6 @@ error:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sleep_ms(unsigned int ms)
|
|
||||||
{
|
|
||||||
struct timespec req;
|
|
||||||
req.tv_sec = ms / 1000;
|
|
||||||
req.tv_nsec = (ms % 1000) * 1000000;
|
|
||||||
nanosleep(&req, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usage(void)
|
static void usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
|
@ -169,7 +174,11 @@ int main(int argc, char* argv[])
|
||||||
int dfusize;
|
int dfusize;
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
#if defined(WIN32) && defined(USE_LIBUSBAPI)
|
||||||
|
"mks5lboot Version " VERSION " (libusb)\n"
|
||||||
|
#else
|
||||||
"mks5lboot Version " VERSION "\n"
|
"mks5lboot Version " VERSION "\n"
|
||||||
|
#endif
|
||||||
"This is free software; see the source for copying conditions. There is NO\n"
|
"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"
|
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
|
||||||
"\n");
|
"\n");
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ static void put_uint32le(unsigned char* p, uint32_t x)
|
||||||
p[3] = (x >> 24) & 0xff;
|
p[3] = (x >> 24) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ERROR(format, ...) \
|
#define _ERR(format, ...) \
|
||||||
do { \
|
do { \
|
||||||
snprintf(errstr, errstrsize, "[ERR] "format, __VA_ARGS__); \
|
snprintf(errstr, errstrsize, "[ERR] "format, __VA_ARGS__); \
|
||||||
goto error; \
|
goto error; \
|
||||||
|
|
@ -135,16 +135,16 @@ static unsigned char *load_file(char *filename, int *bufsize,
|
||||||
|
|
||||||
fd = open(filename, O_RDONLY|O_BINARY);
|
fd = open(filename, O_RDONLY|O_BINARY);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
ERROR("Could not open %s for reading", filename);
|
_ERR("Could not open %s for reading", filename);
|
||||||
|
|
||||||
if (fstat(fd, &s) < 0)
|
if (fstat(fd, &s) < 0)
|
||||||
ERROR("Checking filesize of input file %s", filename);
|
_ERR("Checking filesize of input file %s", filename);
|
||||||
*bufsize = s.st_size;
|
*bufsize = s.st_size;
|
||||||
|
|
||||||
if (is_rbbl) {
|
if (is_rbbl) {
|
||||||
/* Read Rockbox header */
|
/* Read Rockbox header */
|
||||||
if (read(fd, header, sizeof(header)) != sizeof(header))
|
if (read(fd, header, sizeof(header)) != sizeof(header))
|
||||||
ERROR("Could not read file %s", filename);
|
_ERR("Could not read file %s", filename);
|
||||||
*bufsize -= sizeof(header);
|
*bufsize -= sizeof(header);
|
||||||
|
|
||||||
for (i = 0; i < NUM_MODELS; i++)
|
for (i = 0; i < NUM_MODELS; i++)
|
||||||
|
|
@ -152,7 +152,7 @@ static unsigned char *load_file(char *filename, int *bufsize,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (i == NUM_MODELS)
|
if (i == NUM_MODELS)
|
||||||
ERROR("Model name \"%4.4s\" unknown. "
|
_ERR("Model name \"%4.4s\" unknown. "
|
||||||
"Is this really a rockbox bootloader?", header + 4);
|
"Is this really a rockbox bootloader?", header + 4);
|
||||||
|
|
||||||
*model = &ipod_identity[i];
|
*model = &ipod_identity[i];
|
||||||
|
|
@ -160,10 +160,10 @@ static unsigned char *load_file(char *filename, int *bufsize,
|
||||||
|
|
||||||
buf = malloc(*bufsize);
|
buf = malloc(*bufsize);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
ERROR("Could not allocate memory for %s", filename);
|
_ERR("Could not allocate memory for %s", filename);
|
||||||
|
|
||||||
if (read(fd, buf, *bufsize) != *bufsize)
|
if (read(fd, buf, *bufsize) != *bufsize)
|
||||||
ERROR("Could not read file %s", filename);
|
_ERR("Could not read file %s", filename);
|
||||||
|
|
||||||
if (is_rbbl) {
|
if (is_rbbl) {
|
||||||
/* Check checksum */
|
/* Check checksum */
|
||||||
|
|
@ -173,7 +173,7 @@ static unsigned char *load_file(char *filename, int *bufsize,
|
||||||
sum += buf[i];
|
sum += buf[i];
|
||||||
}
|
}
|
||||||
if (sum != get_uint32be(header))
|
if (sum != get_uint32be(header))
|
||||||
ERROR("Checksum mismatch in %s", filename);
|
_ERR("Checksum mismatch in %s", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
@ -223,7 +223,7 @@ unsigned char *mkdfu(int dfu_type, char *dfu_arg, int* dfu_size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!model)
|
if (!model)
|
||||||
ERROR("Platform name \"%s\" unknown", dfu_arg);
|
_ERR("Platform name \"%s\" unknown", dfu_arg);
|
||||||
|
|
||||||
*dfu_size = BIN_OFFSET + model->dualboot_uninstall_size;
|
*dfu_size = BIN_OFFSET + model->dualboot_uninstall_size;
|
||||||
dfu_desc = "BL uninstaller";
|
dfu_desc = "BL uninstaller";
|
||||||
|
|
@ -255,11 +255,11 @@ unsigned char *mkdfu(int dfu_type, char *dfu_arg, int* dfu_size,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*dfu_size > DFU_MAXSIZE)
|
if (*dfu_size > DFU_MAXSIZE)
|
||||||
ERROR("DFU image (%d bytes) too big", *dfu_size);
|
_ERR("DFU image (%d bytes) too big", *dfu_size);
|
||||||
|
|
||||||
dfu_buf = calloc(*dfu_size, 1);
|
dfu_buf = calloc(*dfu_size, 1);
|
||||||
if (!dfu_buf)
|
if (!dfu_buf)
|
||||||
ERROR("Could not allocate %d bytes for DFU image", *dfu_size);
|
_ERR("Could not allocate %d bytes for DFU image", *dfu_size);
|
||||||
|
|
||||||
cert_off = get_uint32le(s5l8702hdr.u.enc34.cert_off);
|
cert_off = get_uint32le(s5l8702hdr.u.enc34.cert_off);
|
||||||
cert_sz = get_uint32le(s5l8702hdr.u.enc34.cert_sz);
|
cert_sz = get_uint32le(s5l8702hdr.u.enc34.cert_sz);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue