summaryrefslogtreecommitdiffstats
path: root/rbutil/mks5lboot/ipoddfu.c
diff options
context:
space:
mode:
Diffstat (limited to 'rbutil/mks5lboot/ipoddfu.c')
-rw-r--r--rbutil/mks5lboot/ipoddfu.c624
1 files changed, 405 insertions, 219 deletions
diff --git a/rbutil/mks5lboot/ipoddfu.c b/rbutil/mks5lboot/ipoddfu.c
index 6d303d6603..5e2914af4b 100644
--- a/rbutil/mks5lboot/ipoddfu.c
+++ b/rbutil/mks5lboot/ipoddfu.c
@@ -22,28 +22,32 @@
* KIND, either express or implied.
*
****************************************************************************/
-#ifndef NO_LIBUSBAPI
-#define USE_LIBUSBAPI
-#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <stdbool.h>
#include <string.h>
-#include <time.h>
#ifdef WIN32
#include <windows.h>
#include <setupapi.h>
-#include <stdbool.h>
#endif
-
#ifdef USE_LIBUSBAPI
#include <libusb-1.0/libusb.h>
#endif
+#ifdef __APPLE__
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/usb/IOUSBLib.h>
+#endif
#include "mks5lboot.h"
+#ifdef WIN32
+#define sleep_ms(ms) Sleep(ms)
+#else
+#include <time.h>
static void sleep_ms(unsigned int ms)
{
struct timespec req;
@@ -51,36 +55,36 @@ static void sleep_ms(unsigned int ms)
req.tv_nsec = (ms % 1000) * 1000000;
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
* 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
* manipulate or do with it, what you want or desire :)
*/
-#define CRC32_DEFAULT_SEED 0xffffffff
-
/* crc32table[] built by crc32_init() */
-static unsigned long crc32table[256];
+static uint32_t crc32table[256];
-/* Calculate crc32. Little endian.
- * Standard seed is 0xffffffff or 0.
- * Some implementations xor result with 0xffffffff after calculation.
- */
-static uint32_t crc32(void *data, unsigned int len, uint32_t seed)
+/* Calculate crc32 */
+static uint32_t crc32(void *data, unsigned int len, uint32_t previousCrc32)
{
- uint8_t *d = data;
-
+ uint32_t crc = ~previousCrc32;
+ unsigned char *d = (unsigned char*) data;
while (len--)
- {
- seed = ((seed >> 8) & 0x00FFFFFF) ^ crc32table [(seed ^ *d++) & 0xFF];
- }
-
- return seed;
+ crc = (crc >> 8) ^ crc32table[(crc & 0xFF) ^ *d++];
+ return ~crc;
}
/* Calculate crc32table */
@@ -89,55 +93,49 @@ static void crc32_init()
uint32_t poly = 0xEDB88320L;
uint32_t crc;
int i, j;
-
for (i = 0; i < 256; ++i)
{
crc = i;
-
- for (j = 8; j > 0; --j)
- {
+ for (j = 0; j < 8; ++j)
crc = (crc >> 1) ^ ((crc & 1) ? poly : 0);
- }
-
crc32table[i] = crc;
}
}
-
-/*
- * DFU
- */
-
-/* must be pow2 <= wTransferSize (2048) */
-#define DFU_PKT_SZ 2048
-
+/* USB */
#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 */
- 0x1220, /* Nano 2G */
- 0x1223, /* Nano 3G and Classic 1G/2G/3G/4G */
- 0x1224, /* Shuffle 3G */
- 0x1225, /* Nano 4G */
- 0x1231, /* Nano 5G */
- 0x1232, /* Nano 6G */
- 0x1233, /* Shuffle 4G */
- 0x1234, /* Nano 7G */
+ { 0x1220, 0, "Nano 2G" },
+ { 0x1223, 0, "Nano 3G / Classic" },
+ { 0x1224, 0, "Shuffle 3G" },
+ { 0x1225, 0, "Nano 4G" },
+ { 0x1231, 0, "Nano 5G" },
+ { 0x1232, 0, "Nano 6G" },
+ { 0x1233, 0, "Shuffle 4G" },
+ { 0x1234, 0, "Nano 7G" },
/* WTF */
- 0x1240, /* Nano 2G */
- 0x1241, /* Classic 1G */
- 0x1242, /* Nano 3G */
- 0x1243, /* Nano 4G */
- 0x1245, /* Classic 2G */
- 0x1246, /* Nano 5G */
- 0x1247, /* Classic 3G */
- 0x1248, /* Nano 6G */
- 0x1249, /* Nano 7G */
- 0x124a, /* Nano 7G */
- 0x1250, /* Classic 4G */
- 0
+ { 0x1240, 1, "Nano 2G" },
+ { 0x1241, 1, "Classic 1G" },
+ { 0x1242, 1, "Nano 3G" },
+ { 0x1243, 1, "Nano 4G" },
+ { 0x1245, 1, "Classic 2G" },
+ { 0x1246, 1, "Nano 5G" },
+ { 0x1247, 1, "Classic 3G" },
+ { 0x1248, 1, "Nano 6G" },
+ { 0x1249, 1, "Nano 7G" },
+ { 0x124a, 1, "Nano 7G" },
+ { 0x1250, 1, "Classic 4G" },
};
+#define N_KNOWN_PIDS (sizeof(known_pids)/sizeof(struct pid_info))
struct usbControlSetup {
uint8_t bmRequestType;
@@ -157,8 +155,14 @@ struct usbStatusData {
uint8_t iString;
} __attribute__ ((packed));
+
+/*
+ * DFU API
+ */
+#define DFU_PKT_SZ 2048 /* must be pow2 <= wTransferSize (2048) */
+
/* DFU 1.1 specs */
-typedef enum DFUState {
+typedef enum {
appIDLE = 0,
appDETACH = 1,
dfuIDLE = 2,
@@ -172,7 +176,7 @@ typedef enum DFUState {
dfuERROR = 10
} DFUState;
-typedef enum DFUStatus {
+typedef enum {
errNONE = 0,
errTARGET = 1,
errFILE = 2,
@@ -191,7 +195,7 @@ typedef enum DFUStatus {
errSTALLEDPKT = 15
} DFUStatus;
-typedef enum DFURequest {
+typedef enum {
DFU_DETACH = 0,
DFU_DNLOAD = 1,
DFU_UPLOAD = 2,
@@ -201,12 +205,17 @@ typedef enum DFURequest {
DFU_ABORT = 6
} DFURequest;
+typedef enum {
+ DFUAPIFail = 0,
+ DFUAPISuccess,
+} dfuAPIResult;
+
struct dfuDev {
struct dfuAPI *api;
int found_pid;
int detached;
char descr[256];
- int res; /* API result: 1->ok, 0->failure */
+ dfuAPIResult res;
char err[256];
/* API private */
#ifdef WIN32
@@ -219,21 +228,25 @@ struct dfuDev {
libusb_device_handle* devh;
int rc; /* libusb return code */
#endif
+#ifdef __APPLE__
+ IOUSBDeviceInterface** dev;
+ kern_return_t kr;
+#endif
};
struct dfuAPI {
char *name;
- int (*open_fn)(struct dfuDev*, int*);
- int (*dfureq_fn)(struct dfuDev*, struct usbControlSetup*, void*);
- int (*reset_fn)(struct dfuDev*);
+ dfuAPIResult (*open_fn)(struct dfuDev*, int*);
+ dfuAPIResult (*dfureq_fn)(struct dfuDev*, struct usbControlSetup*, void*);
+ dfuAPIResult (*reset_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;
if (vid != APPLE_VID)
@@ -253,17 +266,17 @@ static void dfu_add_reqerrstr(struct dfuDev *dfuh, struct usbControlSetup *cs)
}
#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) {
dfuh->ec = GetLastError();
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)
{
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);
dfu_winapi_chkrc(dfuh, "DFU request failed: WriteFile()", rc);
}
-
- if (!dfuh->res)
+ if (!rc)
dfu_add_reqerrstr(dfuh, cs);
+
return dfuh->res;
}
-static int dfu_winapi_reset(struct dfuDev *dfuh)
+static dfuAPIResult dfu_winapi_reset(struct dfuDev *dfuh)
{
DWORD bytesReturned;
- bool rc = DeviceIoControl(dfuh->fh, 0x22000c,
- NULL, 0, NULL, 0, &bytesReturned, NULL);
- return dfu_winapi_chkrc(dfuh,
+ bool rc = DeviceIoControl(dfuh->fh,
+ 0x22000c, NULL, 0, NULL, 0, &bytesReturned, NULL);
+ dfu_winapi_chkrc(dfuh,
"Could not reset USB device: DeviceIoControl()", rc);
+ return dfuh->res;
}
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 =
{ 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;
HDEVINFO devinfo = NULL;
@@ -327,7 +341,7 @@ static int dfu_winapi_open(struct dfuDev *dfuh, int *pid_list)
dfuh->fh =
dfuh->ph = INVALID_HANDLE_VALUE;
dfuh->found_pid = 0;
- dfuh->res = 1; /* ok */
+ dfuh->res = DFUAPISuccess;
dfuh->ec = 0;
/* Get DFU path */
@@ -398,16 +412,16 @@ error:
#endif /* WIN32 */
#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;
- if (dfuh->res == 0)
+ dfuh->res = (dfuh->rc < LIBUSB_SUCCESS) ? DFUAPIFail : DFUAPISuccess;
+ if (dfuh->res == DFUAPIFail)
snprintf(dfuh->err, sizeof(dfuh->err),
"%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)
{
dfuh->rc = libusb_control_transfer(dfuh->devh, cs->bmRequestType,
@@ -417,10 +431,11 @@ static int dfu_libusb_request(struct dfuDev *dfuh,
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);
- 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)
@@ -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;
libusb_device **devs = NULL, *dev;
@@ -447,7 +462,7 @@ static int dfu_libusb_open(struct dfuDev *dfuh, int *pid_list)
dfuh->devh = NULL;
dfuh->found_pid = 0;
dfuh->detached = 0;
- dfuh->res = 1; /* ok */
+ dfuh->res = DFUAPISuccess;
dfuh->rc = libusb_init(&(dfuh->ctx));
if (!dfu_libusb_chkrc(dfuh, "Could not init USB library")) {
@@ -517,10 +532,138 @@ error:
}
#endif /* USE_LIBUSBAPI */
-/* list of suported APIs:
- * Windows: winapi and libusb (optional)
- * Linux and OSX: libusb
- */
+#ifdef __APPLE__
+static bool dfu_iokit_chkrc(struct dfuDev *dfuh, char *str)
+{
+ 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[] =
{
#ifdef WIN32
@@ -538,22 +681,22 @@ static struct dfuAPI api_list[] =
dfu_libusb_close },
#endif
#ifdef __APPLE__
- /* TODO: implement API for OS X < 10.6 ??? */
+ { "IOKit",
+ dfu_iokit_open,
+ dfu_iokit_request,
+ dfu_iokit_reset,
+ dfu_iokit_close },
#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 dfu_request(struct dfuDev *dfuh,
+static dfuAPIResult dfuapi_request(struct dfuDev *dfuh,
struct usbControlSetup *cs, void *data)
{
if (!DEBUG_DFUREQ)
@@ -564,16 +707,17 @@ static int dfu_request(struct dfuDev *dfuh,
/* previous state */
unsigned char ste = 0;
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) -
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",
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)
fprintf(stderr, " (state=%d)", *((unsigned char*)(data)));
if (cs->bRequest == DFU_GETSTATUS) {
@@ -584,106 +728,189 @@ static int dfu_request(struct dfuDev *dfuh,
}
fputc('\n', stderr);
fflush(stderr);
- return ret;
+
+bye:
+ return dfuh->res;
+error:
+ goto bye;
}
-static int dfureq_getstatus(struct dfuDev *dfuh, int *status,
- int *poll_tmo /*ms*/, int *state)
+static dfuAPIResult dfuapi_req_getstatus(struct dfuDev *dfuh,
+ DFUStatus *status, int *poll_tmo /*ms*/,
+ DFUState *state)
{
struct usbStatusData sd = { 0, 0, 0, 0, 0, 0 };
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 (state) *state = sd.bState;
if (poll_tmo) *poll_tmo = (sd.bwPollTimeout2 << 16) |
(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;
struct usbControlSetup cs = { 0xA1, DFU_GETSTATE, 0, 0, sizeof(sts) };
- int ret = dfu_request(dfuh, &cs, &sts);
- *state = sts;
- return ret;
+ dfuapi_request(dfuh, &cs, &sts);
+ if (state) *state = sts;
+ 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)
{
struct usbControlSetup cs = { 0x21, DFU_DNLOAD, blknum, 0, len };
- return dfu_request(dfuh, &cs, data);
+ return dfuapi_request(dfuh, &cs, data);
}
/* not used */
#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)
{
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 };
- 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 };
- return dfu_request(dfuh, &cs, NULL);
+ return dfuapi_request(dfuh, &cs, NULL);
}
/* 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 };
- return dfu_request(dfuh, &cs, NULL);
+ return dfuapi_request(dfuh, &cs, NULL);
}
#endif
-static int dfu_send_packet(struct dfuDev* dfuh, uint16_t blknum,
- uint16_t len, unsigned char *data, int *status,
- int *poll_tmo, int *state, int *pre_state)
+static dfuAPIResult dfuapi_reset(struct dfuDev *dfuh)
{
- if (!dfureq_dnload(dfuh, blknum, len, data))
- return 0;
+ return dfuh->api->reset_fn(dfuh);
+}
+
+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
- to enter the next state, if she respond with dfuDLBUSY then
- we must wait to resend the GETSTATUS request */
+ * to enter the next state, if she respond with dfuDLBUSY then
+ * we must wait to resend the GETSTATUS request */
- if (!dfureq_getstatus(dfuh, status, poll_tmo, state))
- return 0;
+ if (dfuapi_req_getstatus(dfuh, status, poll_tmo, state) != DFUAPISuccess)
+ goto error;
if (*state == dfuDNBUSY) {
if (*poll_tmo)
sleep_ms(*poll_tmo);
- if (!dfureq_getstate(dfuh, pre_state))
- return 0;
- if (!dfureq_getstatus(dfuh, status, poll_tmo, state))
- return 0;
+ if (pre_state)
+ if (dfuapi_req_getstate(dfuh, pre_state) != DFUAPISuccess)
+ goto error;
+ if (dfuapi_req_getstatus(dfuh, status, poll_tmo, state) != DFUAPISuccess)
+ goto error;
}
- return 1;
+bye:
+ return dfuh->res;
+error:
+ goto bye;
+}
+
+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 int dfu_download_file(struct dfuDev* dfuh,
+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 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;
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;
}
@@ -693,12 +920,12 @@ static int dfu_download_file(struct dfuDev* dfuh,
{
len = (remaining < DFU_PKT_SZ) ? remaining : DFU_PKT_SZ;
- if (!dfu_send_packet(dfuh, blknum, len, data +
- blknum*DFU_PKT_SZ, &status, &poll_tmo, &state, NULL))
+ if (dfuapi_send_packet(dfuh, blknum, len, data + blknum*DFU_PKT_SZ,
+ &status, &poll_tmo, &state, NULL) != DFUAPISuccess)
goto error;
if (state != dfuDNLOAD_IDLE) {
- dfu_set_errstr(dfuh, "DFU download aborted: unexpected state");
+ dfuapi_set_err(dfuh, "DFU download aborted: unexpected state");
goto error;
}
@@ -707,9 +934,9 @@ static int dfu_download_file(struct dfuDev* dfuh,
}
/* send ZLP */
- int pre_state = 0;
- if (!dfu_send_packet(dfuh, blknum, 0, NULL,
- &status, &poll_tmo, &state, &pre_state)) {
+ DFUState pre_state = appIDLE; /* dummy state */
+ if (dfuapi_send_packet(dfuh, blknum, 0, NULL,
+ &status, &poll_tmo, &state, &pre_state) != DFUAPISuccess) {
if (pre_state == dfuMANIFEST_SYNC)
goto ok; /* pwnaged .dfu file */
goto error;
@@ -717,9 +944,9 @@ static int dfu_download_file(struct dfuDev* dfuh,
if (state != dfuMANIFEST) {
if (status == errFIRMWARE)
- dfu_set_errstr(dfuh, "DFU download failed: corrupt firmware");
+ dfuapi_set_err(dfuh, "DFU download failed: corrupt firmware");
else
- dfu_set_errstr(dfuh, "DFU download failed: unexpected state");
+ dfuapi_set_err(dfuh, "DFU download failed: unexpected state");
goto error;
}
@@ -727,21 +954,20 @@ static int dfu_download_file(struct dfuDev* dfuh,
if (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 */
-
- /* TODO: next code never tested */
+ /* XXX: next code never tested */
if (state != dfuMANIFEST_WAIT_RESET) {
if (status == errVERIFY)
- dfu_set_errstr(dfuh, "DFU manifest failed: wrong FW verification");
+ dfuapi_set_err(dfuh, "DFU manifest failed: wrong FW verification");
else
- dfu_set_errstr(dfuh, "DFU manifest failed: unexpected state");
+ dfuapi_set_err(dfuh, "DFU manifest failed: unexpected state");
goto error;
}
- if (!dfuh->api->reset_fn(dfuh))
+ if (dfuapi_reset(dfuh) != DFUAPISuccess)
goto error;
ok:
@@ -750,86 +976,42 @@ error:
return 0;
}
-static int dfu_open(struct dfuDev *dfuh, int pid)
-{
- 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
- */
+/* exported functions */
int ipoddfu_send(int pid, unsigned char *data, int size,
char* errstr, int errstrsize)
{
struct dfuDev *dfuh;
unsigned char *buf;
- unsigned int checksum;
+ uint32_t checksum;
int ret = 1; /* ok */
- dfuh = dfu_create();
+ dfuh = dfuapi_create();
buf = malloc(size+4);
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;
}
if (memcmp(data, IM3_IDENT, 4)) {
- dfu_set_errstr(dfuh, "Bad DFU image data");
+ dfuapi_set_err(dfuh, "Bad DFU image data");
goto error;
}
- /* FIXME: big endian */
crc32_init();
- checksum = crc32(data, size, CRC32_DEFAULT_SEED);
+ checksum = crc32(data, size, 0);
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;
- if (!dfu_download_file(dfuh, buf, size+4))
+ if (!ipoddfu_download_file(dfuh, buf, size+4))
goto error;
bye:
if (buf) free(buf);
- dfu_destroy(dfuh);
+ dfuapi_destroy(dfuh);
return ret;
error:
@@ -846,20 +1028,24 @@ int ipoddfu_scan(int pid, int *state, int reset,
struct dfuDev *dfuh;
int ret = 1; /* ok */
- dfuh = dfu_create();
+ dfuh = dfuapi_create();
- if (!dfu_open(dfuh, pid))
+ if (dfuapi_open(dfuh, pid) != DFUAPISuccess)
goto error;
if (reset)
- if (!dfuh->api->reset_fn(dfuh))
+ if (dfuapi_reset(dfuh) != DFUAPISuccess)
goto error;
- if (!dfureq_getstate(dfuh, state))
- goto error;
+ if (state) {
+ DFUState sts;
+ if (dfuapi_req_getstate(dfuh, &sts) != DFUAPISuccess)
+ goto error;
+ *state = (int)sts;
+ }
bye:
- dfu_destroy(dfuh);
+ dfuapi_destroy(dfuh);
return ret;
error: