summaryrefslogtreecommitdiff
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 @@
22 * KIND, either express or implied. 22 * KIND, either express or implied.
23 * 23 *
24 ****************************************************************************/ 24 ****************************************************************************/
25#ifndef NO_LIBUSBAPI
26#define USE_LIBUSBAPI
27#endif
28 25
29#include <stdio.h> 26#include <stdio.h>
30#include <stdlib.h> 27#include <stdlib.h>
31#include <unistd.h> 28#include <unistd.h>
29#include <stdbool.h>
32#include <string.h> 30#include <string.h>
33#include <time.h>
34#ifdef WIN32 31#ifdef WIN32
35#include <windows.h> 32#include <windows.h>
36#include <setupapi.h> 33#include <setupapi.h>
37#include <stdbool.h>
38#endif 34#endif
39
40#ifdef USE_LIBUSBAPI 35#ifdef USE_LIBUSBAPI
41#include <libusb-1.0/libusb.h> 36#include <libusb-1.0/libusb.h>
42#endif 37#endif
38#ifdef __APPLE__
39#include <CoreFoundation/CoreFoundation.h>
40#include <IOKit/IOCFPlugIn.h>
41#include <IOKit/usb/IOUSBLib.h>
42#endif
43 43
44#include "mks5lboot.h" 44#include "mks5lboot.h"
45 45
46 46
47#ifdef WIN32
48#define sleep_ms(ms) Sleep(ms)
49#else
50#include <time.h>
47static void sleep_ms(unsigned int ms) 51static void sleep_ms(unsigned int ms)
48{ 52{
49 struct timespec req; 53 struct timespec req;
@@ -51,36 +55,36 @@ static void sleep_ms(unsigned int ms)
51 req.tv_nsec = (ms % 1000) * 1000000; 55 req.tv_nsec = (ms % 1000) * 1000000;
52 nanosleep(&req, NULL); 56 nanosleep(&req, NULL);
53} 57}
58#endif
59
60static void put_uint32le(unsigned char* p, uint32_t x)
61{
62 p[0] = x & 0xff;
63 p[1] = (x >> 8) & 0xff;
64 p[2] = (x >> 16) & 0xff;
65 p[3] = (x >> 24) & 0xff;
66}
54 67
55/* 68/*
56 * CRC32 functions 69 * CRC32 functions
57 * Based on public domain implementation by Finn Yannick Jacobs. 70 * Based on public domain implementation by Finn Yannick Jacobs.
58 */ 71 *
59 72 * Written and copyright 1999 by Finn Yannick Jacobs
60/* Written and copyright 1999 by Finn Yannick Jacobs
61 * No rights were reserved to this, so feel free to 73 * No rights were reserved to this, so feel free to
62 * manipulate or do with it, what you want or desire :) 74 * manipulate or do with it, what you want or desire :)
63 */ 75 */
64 76
65#define CRC32_DEFAULT_SEED 0xffffffff
66
67/* crc32table[] built by crc32_init() */ 77/* crc32table[] built by crc32_init() */
68static unsigned long crc32table[256]; 78static uint32_t crc32table[256];
69 79
70/* Calculate crc32. Little endian. 80/* Calculate crc32 */
71 * Standard seed is 0xffffffff or 0. 81static uint32_t crc32(void *data, unsigned int len, uint32_t previousCrc32)
72 * Some implementations xor result with 0xffffffff after calculation.
73 */
74static uint32_t crc32(void *data, unsigned int len, uint32_t seed)
75{ 82{
76 uint8_t *d = data; 83 uint32_t crc = ~previousCrc32;
77 84 unsigned char *d = (unsigned char*) data;
78 while (len--) 85 while (len--)
79 { 86 crc = (crc >> 8) ^ crc32table[(crc & 0xFF) ^ *d++];
80 seed = ((seed >> 8) & 0x00FFFFFF) ^ crc32table [(seed ^ *d++) & 0xFF]; 87 return ~crc;
81 }
82
83 return seed;
84} 88}
85 89
86/* Calculate crc32table */ 90/* Calculate crc32table */
@@ -89,55 +93,49 @@ static void crc32_init()
89 uint32_t poly = 0xEDB88320L; 93 uint32_t poly = 0xEDB88320L;
90 uint32_t crc; 94 uint32_t crc;
91 int i, j; 95 int i, j;
92
93 for (i = 0; i < 256; ++i) 96 for (i = 0; i < 256; ++i)
94 { 97 {
95 crc = i; 98 crc = i;
96 99 for (j = 0; j < 8; ++j)
97 for (j = 8; j > 0; --j)
98 {
99 crc = (crc >> 1) ^ ((crc & 1) ? poly : 0); 100 crc = (crc >> 1) ^ ((crc & 1) ? poly : 0);
100 }
101
102 crc32table[i] = crc; 101 crc32table[i] = crc;
103 } 102 }
104} 103}
105 104
106 105/* USB */
107/*
108 * DFU
109 */
110
111/* must be pow2 <= wTransferSize (2048) */
112#define DFU_PKT_SZ 2048
113
114#define APPLE_VID 0x05AC 106#define APPLE_VID 0x05AC
115 107
116static int KNOWN_PIDS[] = 108struct pid_info {
109 int pid;
110 int mode; /* 0->DFU, 1->WTF */
111 char *desc;
112};
113
114struct pid_info known_pids[] =
117{ 115{
118 /* DFU */ 116 /* DFU */
119 0x1220, /* Nano 2G */ 117 { 0x1220, 0, "Nano 2G" },
120 0x1223, /* Nano 3G and Classic 1G/2G/3G/4G */ 118 { 0x1223, 0, "Nano 3G / Classic" },
121 0x1224, /* Shuffle 3G */ 119 { 0x1224, 0, "Shuffle 3G" },
122 0x1225, /* Nano 4G */ 120 { 0x1225, 0, "Nano 4G" },
123 0x1231, /* Nano 5G */ 121 { 0x1231, 0, "Nano 5G" },
124 0x1232, /* Nano 6G */ 122 { 0x1232, 0, "Nano 6G" },
125 0x1233, /* Shuffle 4G */ 123 { 0x1233, 0, "Shuffle 4G" },
126 0x1234, /* Nano 7G */ 124 { 0x1234, 0, "Nano 7G" },
127 /* WTF */ 125 /* WTF */
128 0x1240, /* Nano 2G */ 126 { 0x1240, 1, "Nano 2G" },
129 0x1241, /* Classic 1G */ 127 { 0x1241, 1, "Classic 1G" },
130 0x1242, /* Nano 3G */ 128 { 0x1242, 1, "Nano 3G" },
131 0x1243, /* Nano 4G */ 129 { 0x1243, 1, "Nano 4G" },
132 0x1245, /* Classic 2G */ 130 { 0x1245, 1, "Classic 2G" },
133 0x1246, /* Nano 5G */ 131 { 0x1246, 1, "Nano 5G" },
134 0x1247, /* Classic 3G */ 132 { 0x1247, 1, "Classic 3G" },
135 0x1248, /* Nano 6G */ 133 { 0x1248, 1, "Nano 6G" },
136 0x1249, /* Nano 7G */ 134 { 0x1249, 1, "Nano 7G" },
137 0x124a, /* Nano 7G */ 135 { 0x124a, 1, "Nano 7G" },
138 0x1250, /* Classic 4G */ 136 { 0x1250, 1, "Classic 4G" },
139 0
140}; 137};
138#define N_KNOWN_PIDS (sizeof(known_pids)/sizeof(struct pid_info))
141 139
142struct usbControlSetup { 140struct usbControlSetup {
143 uint8_t bmRequestType; 141 uint8_t bmRequestType;
@@ -157,8 +155,14 @@ struct usbStatusData {
157 uint8_t iString; 155 uint8_t iString;
158} __attribute__ ((packed)); 156} __attribute__ ((packed));
159 157
158
159/*
160 * DFU API
161 */
162#define DFU_PKT_SZ 2048 /* must be pow2 <= wTransferSize (2048) */
163
160/* DFU 1.1 specs */ 164/* DFU 1.1 specs */
161typedef enum DFUState { 165typedef enum {
162 appIDLE = 0, 166 appIDLE = 0,
163 appDETACH = 1, 167 appDETACH = 1,
164 dfuIDLE = 2, 168 dfuIDLE = 2,
@@ -172,7 +176,7 @@ typedef enum DFUState {
172 dfuERROR = 10 176 dfuERROR = 10
173} DFUState; 177} DFUState;
174 178
175typedef enum DFUStatus { 179typedef enum {
176 errNONE = 0, 180 errNONE = 0,
177 errTARGET = 1, 181 errTARGET = 1,
178 errFILE = 2, 182 errFILE = 2,
@@ -191,7 +195,7 @@ typedef enum DFUStatus {
191 errSTALLEDPKT = 15 195 errSTALLEDPKT = 15
192} DFUStatus; 196} DFUStatus;
193 197
194typedef enum DFURequest { 198typedef enum {
195 DFU_DETACH = 0, 199 DFU_DETACH = 0,
196 DFU_DNLOAD = 1, 200 DFU_DNLOAD = 1,
197 DFU_UPLOAD = 2, 201 DFU_UPLOAD = 2,
@@ -201,12 +205,17 @@ typedef enum DFURequest {
201 DFU_ABORT = 6 205 DFU_ABORT = 6
202} DFURequest; 206} DFURequest;
203 207
208typedef enum {
209 DFUAPIFail = 0,
210 DFUAPISuccess,
211} dfuAPIResult;
212
204struct dfuDev { 213struct dfuDev {
205 struct dfuAPI *api; 214 struct dfuAPI *api;
206 int found_pid; 215 int found_pid;
207 int detached; 216 int detached;
208 char descr[256]; 217 char descr[256];
209 int res; /* API result: 1->ok, 0->failure */ 218 dfuAPIResult res;
210 char err[256]; 219 char err[256];
211 /* API private */ 220 /* API private */
212#ifdef WIN32 221#ifdef WIN32
@@ -219,21 +228,25 @@ struct dfuDev {
219 libusb_device_handle* devh; 228 libusb_device_handle* devh;
220 int rc; /* libusb return code */ 229 int rc; /* libusb return code */
221#endif 230#endif
231#ifdef __APPLE__
232 IOUSBDeviceInterface** dev;
233 kern_return_t kr;
234#endif
222}; 235};
223 236
224struct dfuAPI { 237struct dfuAPI {
225 char *name; 238 char *name;
226 int (*open_fn)(struct dfuDev*, int*); 239 dfuAPIResult (*open_fn)(struct dfuDev*, int*);
227 int (*dfureq_fn)(struct dfuDev*, struct usbControlSetup*, void*); 240 dfuAPIResult (*dfureq_fn)(struct dfuDev*, struct usbControlSetup*, void*);
228 int (*reset_fn)(struct dfuDev*); 241 dfuAPIResult (*reset_fn)(struct dfuDev*);
229 void (*close_fn)(struct dfuDev*); 242 void (*close_fn)(struct dfuDev*);
230}; 243};
231 244
232 245
233/* 246/*
234 * low-level (API specific) functions 247 * DFU API low-level (specific) functions
235 */ 248 */
236static int dfu_check_id(int vid, int pid, int *pid_list) 249static bool dfu_check_id(int vid, int pid, int *pid_list)
237{ 250{
238 int *p; 251 int *p;
239 if (vid != APPLE_VID) 252 if (vid != APPLE_VID)
@@ -253,17 +266,17 @@ static void dfu_add_reqerrstr(struct dfuDev *dfuh, struct usbControlSetup *cs)
253} 266}
254 267
255#ifdef WIN32 268#ifdef WIN32
256static int dfu_winapi_chkrc(struct dfuDev *dfuh, char *str, bool success) 269static bool dfu_winapi_chkrc(struct dfuDev *dfuh, char *str, bool success)
257{ 270{
258 dfuh->res = (int)success; 271 dfuh->res = (success) ? DFUAPISuccess : DFUAPIFail;
259 if (!success) { 272 if (!success) {
260 dfuh->ec = GetLastError(); 273 dfuh->ec = GetLastError();
261 snprintf(dfuh->err, sizeof(dfuh->err), "%s error %ld", str, dfuh->ec); 274 snprintf(dfuh->err, sizeof(dfuh->err), "%s error %ld", str, dfuh->ec);
262 } 275 }
263 return dfuh->res; 276 return success;
264} 277}
265 278
266static int dfu_winapi_request(struct dfuDev *dfuh, 279static dfuAPIResult dfu_winapi_request(struct dfuDev *dfuh,
267 struct usbControlSetup* cs, void* data) 280 struct usbControlSetup* cs, void* data)
268{ 281{
269 unsigned char buf[USB_CS_SZ + DFU_PKT_SZ]; 282 unsigned char buf[USB_CS_SZ + DFU_PKT_SZ];
@@ -284,19 +297,20 @@ static int dfu_winapi_request(struct dfuDev *dfuh,
284 rc = WriteFile(dfuh->ph, buf, USB_CS_SZ + cs->wLength, &rdwr, NULL); 297 rc = WriteFile(dfuh->ph, buf, USB_CS_SZ + cs->wLength, &rdwr, NULL);
285 dfu_winapi_chkrc(dfuh, "DFU request failed: WriteFile()", rc); 298 dfu_winapi_chkrc(dfuh, "DFU request failed: WriteFile()", rc);
286 } 299 }
287 300 if (!rc)
288 if (!dfuh->res)
289 dfu_add_reqerrstr(dfuh, cs); 301 dfu_add_reqerrstr(dfuh, cs);
302
290 return dfuh->res; 303 return dfuh->res;
291} 304}
292 305
293static int dfu_winapi_reset(struct dfuDev *dfuh) 306static dfuAPIResult dfu_winapi_reset(struct dfuDev *dfuh)
294{ 307{
295 DWORD bytesReturned; 308 DWORD bytesReturned;
296 bool rc = DeviceIoControl(dfuh->fh, 0x22000c, 309 bool rc = DeviceIoControl(dfuh->fh,
297 NULL, 0, NULL, 0, &bytesReturned, NULL); 310 0x22000c, NULL, 0, NULL, 0, &bytesReturned, NULL);
298 return dfu_winapi_chkrc(dfuh, 311 dfu_winapi_chkrc(dfuh,
299 "Could not reset USB device: DeviceIoControl()", rc); 312 "Could not reset USB device: DeviceIoControl()", rc);
313 return dfuh->res;
300} 314}
301 315
302static void dfu_winapi_close(struct dfuDev *dfuh) 316static void dfu_winapi_close(struct dfuDev *dfuh)
@@ -314,7 +328,7 @@ static void dfu_winapi_close(struct dfuDev *dfuh)
314static const GUID GUID_AAPLDFU = 328static const GUID GUID_AAPLDFU =
315 { 0xB8085869L, 0xFEB9, 0x404B, {0x8C, 0xB1, 0x1E, 0x5C, 0x14, 0xFA, 0x8C, 0x54}}; 329 { 0xB8085869L, 0xFEB9, 0x404B, {0x8C, 0xB1, 0x1E, 0x5C, 0x14, 0xFA, 0x8C, 0x54}};
316 330
317static int dfu_winapi_open(struct dfuDev *dfuh, int *pid_list) 331static dfuAPIResult dfu_winapi_open(struct dfuDev *dfuh, int *pid_list)
318{ 332{
319 const GUID *guid = &GUID_AAPLDFU; 333 const GUID *guid = &GUID_AAPLDFU;
320 HDEVINFO devinfo = NULL; 334 HDEVINFO devinfo = NULL;
@@ -327,7 +341,7 @@ static int dfu_winapi_open(struct dfuDev *dfuh, int *pid_list)
327 dfuh->fh = 341 dfuh->fh =
328 dfuh->ph = INVALID_HANDLE_VALUE; 342 dfuh->ph = INVALID_HANDLE_VALUE;
329 dfuh->found_pid = 0; 343 dfuh->found_pid = 0;
330 dfuh->res = 1; /* ok */ 344 dfuh->res = DFUAPISuccess;
331 dfuh->ec = 0; 345 dfuh->ec = 0;
332 346
333 /* Get DFU path */ 347 /* Get DFU path */
@@ -398,16 +412,16 @@ error:
398#endif /* WIN32 */ 412#endif /* WIN32 */
399 413
400#ifdef USE_LIBUSBAPI 414#ifdef USE_LIBUSBAPI
401static int dfu_libusb_chkrc(struct dfuDev *dfuh, char *str) 415static bool dfu_libusb_chkrc(struct dfuDev *dfuh, char *str)
402{ 416{
403 dfuh->res = (dfuh->rc < LIBUSB_SUCCESS) ? 0 : 1; 417 dfuh->res = (dfuh->rc < LIBUSB_SUCCESS) ? DFUAPIFail : DFUAPISuccess;
404 if (dfuh->res == 0) 418 if (dfuh->res == DFUAPIFail)
405 snprintf(dfuh->err, sizeof(dfuh->err), 419 snprintf(dfuh->err, sizeof(dfuh->err),
406 "%s: %s", str, libusb_error_name(dfuh->rc)); 420 "%s: %s", str, libusb_error_name(dfuh->rc));
407 return dfuh->res; 421 return (dfuh->res == DFUAPISuccess);
408} 422}
409 423
410static int dfu_libusb_request(struct dfuDev *dfuh, 424static dfuAPIResult dfu_libusb_request(struct dfuDev *dfuh,
411 struct usbControlSetup *cs, void *data) 425 struct usbControlSetup *cs, void *data)
412{ 426{
413 dfuh->rc = libusb_control_transfer(dfuh->devh, cs->bmRequestType, 427 dfuh->rc = libusb_control_transfer(dfuh->devh, cs->bmRequestType,
@@ -417,10 +431,11 @@ static int dfu_libusb_request(struct dfuDev *dfuh,
417 return dfuh->res; 431 return dfuh->res;
418} 432}
419 433
420static int dfu_libusb_reset(struct dfuDev *dfuh) 434static dfuAPIResult dfu_libusb_reset(struct dfuDev *dfuh)
421{ 435{
422 dfuh->rc = libusb_reset_device(dfuh->devh); 436 dfuh->rc = libusb_reset_device(dfuh->devh);
423 return dfu_libusb_chkrc(dfuh, "Could not reset USB device"); 437 dfu_libusb_chkrc(dfuh, "Could not reset USB device");
438 return dfuh->res;
424} 439}
425 440
426static void dfu_libusb_close(struct dfuDev *dfuh) 441static void dfu_libusb_close(struct dfuDev *dfuh)
@@ -438,7 +453,7 @@ static void dfu_libusb_close(struct dfuDev *dfuh)
438 } 453 }
439} 454}
440 455
441static int dfu_libusb_open(struct dfuDev *dfuh, int *pid_list) 456static dfuAPIResult dfu_libusb_open(struct dfuDev *dfuh, int *pid_list)
442{ 457{
443 struct libusb_device_descriptor desc; 458 struct libusb_device_descriptor desc;
444 libusb_device **devs = NULL, *dev; 459 libusb_device **devs = NULL, *dev;
@@ -447,7 +462,7 @@ static int dfu_libusb_open(struct dfuDev *dfuh, int *pid_list)
447 dfuh->devh = NULL; 462 dfuh->devh = NULL;
448 dfuh->found_pid = 0; 463 dfuh->found_pid = 0;
449 dfuh->detached = 0; 464 dfuh->detached = 0;
450 dfuh->res = 1; /* ok */ 465 dfuh->res = DFUAPISuccess;
451 466
452 dfuh->rc = libusb_init(&(dfuh->ctx)); 467 dfuh->rc = libusb_init(&(dfuh->ctx));
453 if (!dfu_libusb_chkrc(dfuh, "Could not init USB library")) { 468 if (!dfu_libusb_chkrc(dfuh, "Could not init USB library")) {
@@ -517,10 +532,138 @@ error:
517} 532}
518#endif /* USE_LIBUSBAPI */ 533#endif /* USE_LIBUSBAPI */
519 534
520/* list of suported APIs: 535#ifdef __APPLE__
521 * Windows: winapi and libusb (optional) 536static bool dfu_iokit_chkrc(struct dfuDev *dfuh, char *str)
522 * Linux and OSX: libusb 537{
523 */ 538 dfuh->res = (dfuh->kr == kIOReturnSuccess) ? DFUAPISuccess : DFUAPIFail;
539 if (dfuh->res == DFUAPIFail)
540 snprintf(dfuh->err, sizeof(dfuh->err),
541 "%s: error %08x", str, dfuh->kr);
542 return (dfuh->res == DFUAPISuccess);
543}
544
545static dfuAPIResult dfu_iokit_request(struct dfuDev *dfuh,
546 struct usbControlSetup *cs, void *data)
547{
548 IOUSBDevRequest req;
549 req.bmRequestType = cs->bmRequestType;
550 req.bRequest = cs->bRequest;
551 req.wValue = cs->wValue;
552 req.wIndex = cs->wIndex;
553 req.wLength = cs->wLength;
554 req.pData = data;
555
556 dfuh->kr = (*(dfuh->dev))->DeviceRequest(dfuh->dev, &req);
557 if (!dfu_iokit_chkrc(dfuh, "DFU request failed"))
558 dfu_add_reqerrstr(dfuh, cs);
559
560 return dfuh->res;
561}
562
563static dfuAPIResult dfu_iokit_reset(struct dfuDev *dfuh)
564{
565 dfuh->kr = (*(dfuh->dev))->ResetDevice(dfuh->dev);
566#if 0
567 /* On 10.11+ ResetDevice() returns no error but does not perform
568 * any reset, just a kernel log message.
569 * USBDeviceReEnumerate() could be used as a workaround.
570 */
571 dfuh->kr = (*(dfuh->dev))->USBDeviceReEnumerate(dfuh->dev, 0);
572#endif
573 dfu_iokit_chkrc(dfuh, "Could not reset USB device");
574 return dfuh->res;
575}
576
577static void dfu_iokit_close(struct dfuDev *dfuh)
578{
579 if (dfuh->dev) {
580 (*(dfuh->dev))->USBDeviceClose(dfuh->dev);
581 (*(dfuh->dev))->Release(dfuh->dev);
582 dfuh->dev = NULL;
583 }
584}
585
586static dfuAPIResult dfu_iokit_open(struct dfuDev *dfuh, int *pid_list)
587{
588 kern_return_t kr;
589 CFMutableDictionaryRef usb_matching_dict = 0;
590 io_object_t usbDevice;
591 io_iterator_t usb_iterator = IO_OBJECT_NULL;
592 IOCFPlugInInterface **plugInInterface = NULL;
593 IOUSBDeviceInterface **dev = NULL;
594 HRESULT result;
595 SInt32 score;
596 UInt16 vendor;
597 UInt16 product;
598 UInt16 release;
599
600 dfuh->dev = NULL;
601 dfuh->found_pid = 0;
602 dfuh->res = DFUAPISuccess;
603
604 usb_matching_dict = IOServiceMatching(kIOUSBDeviceClassName);
605 dfuh->kr = IOServiceGetMatchingServices(
606 kIOMasterPortDefault, usb_matching_dict, &usb_iterator);
607 if (!dfu_iokit_chkrc(dfuh, "Could not get matching services"))
608 goto error;
609
610 while ((usbDevice = IOIteratorNext(usb_iterator)))
611 {
612 /* Create an intermediate plug-in */
613 kr = IOCreatePlugInInterfaceForService(usbDevice,
614 kIOUSBDeviceUserClientTypeID,
615 kIOCFPlugInInterfaceID,
616 &plugInInterface,
617 &score);
618 IOObjectRelease(usbDevice);
619
620 if ((kIOReturnSuccess != kr) || !plugInInterface)
621 continue; /* Unable to create a plugin */
622
623 /* Now create the device interface */
624 result = (*plugInInterface)->QueryInterface(plugInInterface,
625 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
626 (LPVOID*)&dev);
627 (*plugInInterface)->Release(plugInInterface);
628
629 if (result || !dev)
630 continue; /* Couldn't create a device interface */
631
632 kr = (*dev)->GetDeviceVendor(dev, &vendor);
633 kr = (*dev)->GetDeviceProduct(dev, &product);
634 kr = (*dev)->GetDeviceReleaseNumber(dev, &release);
635
636 if (!dfu_check_id(vendor, product, pid_list)) {
637 (*dev)->Release(dev);
638 continue;
639 }
640
641 /* Device found, open it */
642 dfuh->kr = (*dev)->USBDeviceOpen(dev);
643 if (!dfu_iokit_chkrc(dfuh, "Could not open USB device")) {
644 (*dev)->Release(dev);
645 goto error;
646 }
647
648 /* ok */
649 dfuh->found_pid = product;
650 dfuh->dev = dev;
651 snprintf(dfuh->descr, sizeof(dfuh->descr),
652 "[%04x:%04x] release: %d", vendor, product, release);
653 break;
654 }
655
656bye:
657 if (usb_iterator != IO_OBJECT_NULL)
658 IOObjectRelease(usb_iterator);
659 return dfuh->res;
660
661error:
662 goto bye;
663}
664#endif /* __APPLE__ */
665
666/* list of suported APIs */
524static struct dfuAPI api_list[] = 667static struct dfuAPI api_list[] =
525{ 668{
526#ifdef WIN32 669#ifdef WIN32
@@ -538,22 +681,22 @@ static struct dfuAPI api_list[] =
538 dfu_libusb_close }, 681 dfu_libusb_close },
539#endif 682#endif
540#ifdef __APPLE__ 683#ifdef __APPLE__
541 /* TODO: implement API for OS X < 10.6 ??? */ 684 { "IOKit",
685 dfu_iokit_open,
686 dfu_iokit_request,
687 dfu_iokit_reset,
688 dfu_iokit_close },
542#endif 689#endif
543}; 690};
544#define DFU_N_APIS (sizeof(api_list)/sizeof(struct dfuAPI)) 691#define N_DFU_APIS (sizeof(api_list)/sizeof(struct dfuAPI))
692
545 693
546/* 694/*
547 * mid-layer (common) functions 695 * DFU API common functions
548 */ 696 */
549static void dfu_set_errstr(struct dfuDev *dfuh, char *str)
550{
551 strncpy(dfuh->err, str, sizeof(dfuh->err));
552}
553
554static int DEBUG_DFUREQ = 0; 697static int DEBUG_DFUREQ = 0;
555 698
556static int dfu_request(struct dfuDev *dfuh, 699static dfuAPIResult dfuapi_request(struct dfuDev *dfuh,
557 struct usbControlSetup *cs, void *data) 700 struct usbControlSetup *cs, void *data)
558{ 701{
559 if (!DEBUG_DFUREQ) 702 if (!DEBUG_DFUREQ)
@@ -564,16 +707,17 @@ static int dfu_request(struct dfuDev *dfuh,
564 /* previous state */ 707 /* previous state */
565 unsigned char ste = 0; 708 unsigned char ste = 0;
566 struct usbControlSetup css = { 0xA1, DFU_GETSTATE, 0, 0, sizeof(ste) }; 709 struct usbControlSetup css = { 0xA1, DFU_GETSTATE, 0, 0, sizeof(ste) };
567 if (!dfuh->api->dfureq_fn(dfuh, &css, &ste)) { 710 if (dfuh->api->dfureq_fn(dfuh, &css, &ste) != DFUAPISuccess) {
568 snprintf(dfuh->err + strlen(dfuh->err), sizeof(dfuh->err) - 711 snprintf(dfuh->err + strlen(dfuh->err), sizeof(dfuh->err) -
569 strlen(dfuh->err), " [DEBUG_DFUREQ ERROR: state=%d]", ste); 712 strlen(dfuh->err), " [DEBUG_DFUREQ ERROR: state=%d]", ste);
570 return 0; 713 goto error;
571 } 714 }
572 715
573 int ret = dfuh->api->dfureq_fn(dfuh, cs, data); 716 dfuh->api->dfureq_fn(dfuh, cs, data);
574 fprintf(stderr, "[DEBUG]: REQ: ste=%d, cs=%2x/%d/%d/%d/%d -> %s", 717 fprintf(stderr, "[DEBUG]: REQ: ste=%d, cs=%2x/%d/%d/%d/%d -> %s",
575 ste, cs->bmRequestType, cs->bRequest, cs->wValue, 718 ste, cs->bmRequestType, cs->bRequest, cs->wValue,
576 cs->wIndex, cs->wLength, ret ? "ok" : "ERROR"); 719 cs->wIndex, cs->wLength,
720 (dfuh->res == DFUAPISuccess) ? "ok" : "ERROR");
577 if (cs->bRequest == DFU_GETSTATE) 721 if (cs->bRequest == DFU_GETSTATE)
578 fprintf(stderr, " (state=%d)", *((unsigned char*)(data))); 722 fprintf(stderr, " (state=%d)", *((unsigned char*)(data)));
579 if (cs->bRequest == DFU_GETSTATUS) { 723 if (cs->bRequest == DFU_GETSTATUS) {
@@ -584,106 +728,189 @@ static int dfu_request(struct dfuDev *dfuh,
584 } 728 }
585 fputc('\n', stderr); 729 fputc('\n', stderr);
586 fflush(stderr); 730 fflush(stderr);
587 return ret; 731
732bye:
733 return dfuh->res;
734error:
735 goto bye;
588} 736}
589 737
590static int dfureq_getstatus(struct dfuDev *dfuh, int *status, 738static dfuAPIResult dfuapi_req_getstatus(struct dfuDev *dfuh,
591 int *poll_tmo /*ms*/, int *state) 739 DFUStatus *status, int *poll_tmo /*ms*/,
740 DFUState *state)
592{ 741{
593 struct usbStatusData sd = { 0, 0, 0, 0, 0, 0 }; 742 struct usbStatusData sd = { 0, 0, 0, 0, 0, 0 };
594 struct usbControlSetup cs = { 0xA1, DFU_GETSTATUS, 0, 0, sizeof(sd) }; 743 struct usbControlSetup cs = { 0xA1, DFU_GETSTATUS, 0, 0, sizeof(sd) };
595 int ret = dfu_request(dfuh, &cs, &sd); 744 dfuapi_request(dfuh, &cs, &sd);
596 if (status) *status = sd.bStatus; 745 if (status) *status = sd.bStatus;
597 if (state) *state = sd.bState; 746 if (state) *state = sd.bState;
598 if (poll_tmo) *poll_tmo = (sd.bwPollTimeout2 << 16) | 747 if (poll_tmo) *poll_tmo = (sd.bwPollTimeout2 << 16) |
599 (sd.bwPollTimeout1 << 8) | (sd.bwPollTimeout0); 748 (sd.bwPollTimeout1 << 8) | (sd.bwPollTimeout0);
600 return ret; 749 return dfuh->res;
601} 750}
602 751
603static int dfureq_getstate(struct dfuDev *dfuh, int *state) 752static dfuAPIResult dfuapi_req_getstate(struct dfuDev *dfuh, DFUState *state)
604{ 753{
605 if (!state)
606 return 1; /* nothing to do */
607 unsigned char sts = 0; 754 unsigned char sts = 0;
608 struct usbControlSetup cs = { 0xA1, DFU_GETSTATE, 0, 0, sizeof(sts) }; 755 struct usbControlSetup cs = { 0xA1, DFU_GETSTATE, 0, 0, sizeof(sts) };
609 int ret = dfu_request(dfuh, &cs, &sts); 756 dfuapi_request(dfuh, &cs, &sts);
610 *state = sts; 757 if (state) *state = sts;
611 return ret; 758 return dfuh->res;
612} 759}
613 760
614static int dfureq_dnload(struct dfuDev* dfuh, uint16_t blknum, 761static dfuAPIResult dfuapi_req_dnload(struct dfuDev* dfuh, uint16_t blknum,
615 uint16_t len, unsigned char *data) 762 uint16_t len, unsigned char *data)
616{ 763{
617 struct usbControlSetup cs = { 0x21, DFU_DNLOAD, blknum, 0, len }; 764 struct usbControlSetup cs = { 0x21, DFU_DNLOAD, blknum, 0, len };
618 return dfu_request(dfuh, &cs, data); 765 return dfuapi_request(dfuh, &cs, data);
619} 766}
620 767
621/* not used */ 768/* not used */
622#if 0 769#if 0
623static int dfureq_upload(struct dfuDev* dfuh, 770static dfuAPIResult dfuapi_req_upload(struct dfuDev* dfuh,
624 uint16_t blknum, uint16_t len, unsigned char *data) 771 uint16_t blknum, uint16_t len, unsigned char *data)
625{ 772{
626 struct usbControlSetup cs = { 0xA1, DFU_UPLOAD, blknum, 0, len }; 773 struct usbControlSetup cs = { 0xA1, DFU_UPLOAD, blknum, 0, len };
627 return dfu_request(dfuh, &cs, data); 774 return dfuapi_request(dfuh, &cs, data);
628} 775}
629 776
630static int dfureq_clrstatus(struct dfuDev* dfuh) 777static dfuAPIResult dfuapi_req_clrstatus(struct dfuDev* dfuh)
631{ 778{
632 struct usbControlSetup cs = { 0x21, DFU_CLRSTATUS, 0, 0, 0 }; 779 struct usbControlSetup cs = { 0x21, DFU_CLRSTATUS, 0, 0, 0 };
633 return dfu_request(dfuh, &cs, NULL); 780 return dfuapi_request(dfuh, &cs, NULL);
634} 781}
635 782
636static int dfureq_abort(struct dfuDev* dfuh) 783static dfuAPIResult dfuapi_req_abort(struct dfuDev* dfuh)
637{ 784{
638 struct usbControlSetup cs = { 0x21, DFU_ABORT, 0, 0, 0 }; 785 struct usbControlSetup cs = { 0x21, DFU_ABORT, 0, 0, 0 };
639 return dfu_request(dfuh, &cs, NULL); 786 return dfuapi_request(dfuh, &cs, NULL);
640} 787}
641 788
642/* not implemented on DFU8702 */ 789/* not implemented on DFU8702 */
643static int dfureq_detach(struct dfuDev* dfuh, int tmo) 790static dfuAPIResult dfuapi_req_detach(struct dfuDev* dfuh, int tmo)
644{ 791{
645 struct usbControlSetup cs = { 0x21, DFU_DETACH, tmo, 0, 0 }; 792 struct usbControlSetup cs = { 0x21, DFU_DETACH, tmo, 0, 0 };
646 return dfu_request(dfuh, &cs, NULL); 793 return dfuapi_request(dfuh, &cs, NULL);
647} 794}
648#endif 795#endif
649 796
650static int dfu_send_packet(struct dfuDev* dfuh, uint16_t blknum, 797static dfuAPIResult dfuapi_reset(struct dfuDev *dfuh)
651 uint16_t len, unsigned char *data, int *status,
652 int *poll_tmo, int *state, int *pre_state)
653{ 798{
654 if (!dfureq_dnload(dfuh, blknum, len, data)) 799 return dfuh->api->reset_fn(dfuh);
655 return 0; 800}
801
802static dfuAPIResult dfuapi_send_packet(struct dfuDev* dfuh, uint16_t blknum,
803 uint16_t len, unsigned char *data, DFUStatus *status,
804 int *poll_tmo, DFUState *state, DFUState *pre_state)
805{
806 if (dfuapi_req_dnload(dfuh, blknum, len, data) != DFUAPISuccess)
807 goto error;
656 808
657 /* device is in dfuDLSYNC state, waiting for a GETSTATUS request 809 /* device is in dfuDLSYNC state, waiting for a GETSTATUS request
658 to enter the next state, if she respond with dfuDLBUSY then 810 * to enter the next state, if she respond with dfuDLBUSY then
659 we must wait to resend the GETSTATUS request */ 811 * we must wait to resend the GETSTATUS request */
660 812
661 if (!dfureq_getstatus(dfuh, status, poll_tmo, state)) 813 if (dfuapi_req_getstatus(dfuh, status, poll_tmo, state) != DFUAPISuccess)
662 return 0; 814 goto error;
663 815
664 if (*state == dfuDNBUSY) { 816 if (*state == dfuDNBUSY) {
665 if (*poll_tmo) 817 if (*poll_tmo)
666 sleep_ms(*poll_tmo); 818 sleep_ms(*poll_tmo);
667 if (!dfureq_getstate(dfuh, pre_state)) 819 if (pre_state)
668 return 0; 820 if (dfuapi_req_getstate(dfuh, pre_state) != DFUAPISuccess)
669 if (!dfureq_getstatus(dfuh, status, poll_tmo, state)) 821 goto error;
670 return 0; 822 if (dfuapi_req_getstatus(dfuh, status, poll_tmo, state) != DFUAPISuccess)
823 goto error;
671 } 824 }
672 825
673 return 1; 826bye:
827 return dfuh->res;
828error:
829 goto bye;
830}
831
832static void dfuapi_set_err(struct dfuDev *dfuh, char *str)
833{
834 dfuh->res = DFUAPIFail;
835 strncpy(dfuh->err, str, sizeof(dfuh->err));
836}
837
838static dfuAPIResult dfuapi_open(struct dfuDev *dfuh, int pid)
839{
840 int pid_l[N_KNOWN_PIDS+1] = { 0 };
841 struct dfuAPI *api;
842 unsigned i, p;
843
844 /* fill pid list */
845 if (pid)
846 pid_l[0] = pid;
847 else
848 for (p = 0; p < N_KNOWN_PIDS; p++)
849 pid_l[p] = known_pids[p].pid;
850
851 for (i = 0; i < N_DFU_APIS; i++)
852 {
853 api = &api_list[i];
854 if (api->open_fn(dfuh, pid_l) != DFUAPISuccess)
855 goto error;
856 if (dfuh->found_pid) {
857 /* ok */
858 dfuh->api = api;
859 printf("[INFO] %s: found %s\n", api->name, dfuh->descr);
860 for (p = 0; p < N_KNOWN_PIDS; p++) {
861 if (known_pids[p].pid == dfuh->found_pid) {
862 printf("[INFO] iPod %s, mode: %s\n", known_pids[p].desc,
863 known_pids[p].mode ? "WTF" : "DFU");
864 break;
865 }
866 }
867 fflush(stdout);
868 goto bye;
869 }
870 printf("[INFO] %s: no DFU devices found\n", api->name);
871 fflush(stdout);
872 }
873
874 /* error */
875 dfuapi_set_err(dfuh, "DFU device not found");
876
877bye:
878 return dfuh->res;
879error:
880 goto bye;
674} 881}
675 882
676static int dfu_download_file(struct dfuDev* dfuh, 883static void dfuapi_destroy(struct dfuDev *dfuh)
884{
885 if (dfuh) {
886 if (dfuh->api)
887 dfuh->api->close_fn(dfuh);
888 free(dfuh);
889 }
890}
891
892static struct dfuDev *dfuapi_create(void)
893{
894 return calloc(sizeof(struct dfuDev), 1);
895}
896
897
898/*
899 * app level functions
900 */
901static int ipoddfu_download_file(struct dfuDev* dfuh,
677 unsigned char *data, unsigned long size) 902 unsigned char *data, unsigned long size)
678{ 903{
679 unsigned int blknum, len, remaining; 904 unsigned int blknum, len, remaining;
680 int status, poll_tmo, state; 905 int poll_tmo;
906 DFUStatus status;
907 DFUState state;
681 908
682 if (!dfureq_getstate(dfuh, &state)) 909 if (dfuapi_req_getstate(dfuh, &state) != DFUAPISuccess)
683 goto error; 910 goto error;
684 911
685 if (state != dfuIDLE) { 912 if (state != dfuIDLE) {
686 dfu_set_errstr(dfuh, "Could not start DFU download: not idle"); 913 dfuapi_set_err(dfuh, "Could not start DFU download: not idle");
687 goto error; 914 goto error;
688 } 915 }
689 916
@@ -693,12 +920,12 @@ static int dfu_download_file(struct dfuDev* dfuh,
693 { 920 {
694 len = (remaining < DFU_PKT_SZ) ? remaining : DFU_PKT_SZ; 921 len = (remaining < DFU_PKT_SZ) ? remaining : DFU_PKT_SZ;
695 922
696 if (!dfu_send_packet(dfuh, blknum, len, data + 923 if (dfuapi_send_packet(dfuh, blknum, len, data + blknum*DFU_PKT_SZ,
697 blknum*DFU_PKT_SZ, &status, &poll_tmo, &state, NULL)) 924 &status, &poll_tmo, &state, NULL) != DFUAPISuccess)
698 goto error; 925 goto error;
699 926
700 if (state != dfuDNLOAD_IDLE) { 927 if (state != dfuDNLOAD_IDLE) {
701 dfu_set_errstr(dfuh, "DFU download aborted: unexpected state"); 928 dfuapi_set_err(dfuh, "DFU download aborted: unexpected state");
702 goto error; 929 goto error;
703 } 930 }
704 931
@@ -707,9 +934,9 @@ static int dfu_download_file(struct dfuDev* dfuh,
707 } 934 }
708 935
709 /* send ZLP */ 936 /* send ZLP */
710 int pre_state = 0; 937 DFUState pre_state = appIDLE; /* dummy state */
711 if (!dfu_send_packet(dfuh, blknum, 0, NULL, 938 if (dfuapi_send_packet(dfuh, blknum, 0, NULL,
712 &status, &poll_tmo, &state, &pre_state)) { 939 &status, &poll_tmo, &state, &pre_state) != DFUAPISuccess) {
713 if (pre_state == dfuMANIFEST_SYNC) 940 if (pre_state == dfuMANIFEST_SYNC)
714 goto ok; /* pwnaged .dfu file */ 941 goto ok; /* pwnaged .dfu file */
715 goto error; 942 goto error;
@@ -717,9 +944,9 @@ static int dfu_download_file(struct dfuDev* dfuh,
717 944
718 if (state != dfuMANIFEST) { 945 if (state != dfuMANIFEST) {
719 if (status == errFIRMWARE) 946 if (status == errFIRMWARE)
720 dfu_set_errstr(dfuh, "DFU download failed: corrupt firmware"); 947 dfuapi_set_err(dfuh, "DFU download failed: corrupt firmware");
721 else 948 else
722 dfu_set_errstr(dfuh, "DFU download failed: unexpected state"); 949 dfuapi_set_err(dfuh, "DFU download failed: unexpected state");
723 goto error; 950 goto error;
724 } 951 }
725 952
@@ -727,21 +954,20 @@ static int dfu_download_file(struct dfuDev* dfuh,
727 if (poll_tmo) 954 if (poll_tmo)
728 sleep_ms(poll_tmo); 955 sleep_ms(poll_tmo);
729 956
730 if (!dfureq_getstatus(dfuh, &status, NULL, &state)) 957 if (dfuapi_req_getstatus(dfuh, &status, NULL, &state) != DFUAPISuccess)
731 goto ok; /* 1223 .dfu file */ 958 goto ok; /* 1223 .dfu file */
732 959
733 960 /* XXX: next code never tested */
734 /* TODO: next code never tested */
735 961
736 if (state != dfuMANIFEST_WAIT_RESET) { 962 if (state != dfuMANIFEST_WAIT_RESET) {
737 if (status == errVERIFY) 963 if (status == errVERIFY)
738 dfu_set_errstr(dfuh, "DFU manifest failed: wrong FW verification"); 964 dfuapi_set_err(dfuh, "DFU manifest failed: wrong FW verification");
739 else 965 else
740 dfu_set_errstr(dfuh, "DFU manifest failed: unexpected state"); 966 dfuapi_set_err(dfuh, "DFU manifest failed: unexpected state");
741 goto error; 967 goto error;
742 } 968 }
743 969
744 if (!dfuh->api->reset_fn(dfuh)) 970 if (dfuapi_reset(dfuh) != DFUAPISuccess)
745 goto error; 971 goto error;
746 972
747ok: 973ok:
@@ -750,86 +976,42 @@ error:
750 return 0; 976 return 0;
751} 977}
752 978
753static int dfu_open(struct dfuDev *dfuh, int pid) 979/* exported functions */
754{
755 int pid_l[2] = {0};
756 struct dfuAPI *api;
757 unsigned i;
758
759 pid_l[0] = pid;
760
761 for (i = 0; i < DFU_N_APIS; i++)
762 {
763 api = &api_list[i];
764 if (!(api->open_fn(dfuh, pid ? pid_l : KNOWN_PIDS)))
765 return 0; /* error */
766 if (dfuh->found_pid) {
767 dfuh->api = api;
768 printf("[INFO] %s: found %s\n", api->name, dfuh->descr);
769 fflush(stdout);
770 return 1; /* ok */
771 }
772 printf("[INFO] %s: no DFU devices found\n", api->name);
773 fflush(stdout);
774 }
775
776 dfu_set_errstr(dfuh, "DFU device not found");
777 return 0;
778}
779
780static void dfu_destroy(struct dfuDev *dfuh)
781{
782 if (dfuh) {
783 if (dfuh->api)
784 dfuh->api->close_fn(dfuh);
785 free(dfuh);
786 }
787}
788
789static struct dfuDev *dfu_create()
790{
791 return calloc(sizeof(struct dfuDev), 1);
792}
793
794/*
795 * exported functions
796 */
797int ipoddfu_send(int pid, unsigned char *data, int size, 980int ipoddfu_send(int pid, unsigned char *data, int size,
798 char* errstr, int errstrsize) 981 char* errstr, int errstrsize)
799{ 982{
800 struct dfuDev *dfuh; 983 struct dfuDev *dfuh;
801 unsigned char *buf; 984 unsigned char *buf;
802 unsigned int checksum; 985 uint32_t checksum;
803 int ret = 1; /* ok */ 986 int ret = 1; /* ok */
804 987
805 dfuh = dfu_create(); 988 dfuh = dfuapi_create();
806 989
807 buf = malloc(size+4); 990 buf = malloc(size+4);
808 if (!buf) { 991 if (!buf) {
809 dfu_set_errstr(dfuh, "Could not allocate memory for DFU buffer"); 992 dfuapi_set_err(dfuh, "Could not allocate memory for DFU buffer");
810 goto error; 993 goto error;
811 } 994 }
812 995
813 if (memcmp(data, IM3_IDENT, 4)) { 996 if (memcmp(data, IM3_IDENT, 4)) {
814 dfu_set_errstr(dfuh, "Bad DFU image data"); 997 dfuapi_set_err(dfuh, "Bad DFU image data");
815 goto error; 998 goto error;
816 } 999 }
817 1000
818 /* FIXME: big endian */
819 crc32_init(); 1001 crc32_init();
820 checksum = crc32(data, size, CRC32_DEFAULT_SEED); 1002 checksum = crc32(data, size, 0);
821 memcpy(buf, data, size); 1003 memcpy(buf, data, size);
822 memcpy(buf+size, &checksum, 4); 1004 put_uint32le(buf+size, ~checksum);
823 1005
824 if (!dfu_open(dfuh, pid)) 1006 if (dfuapi_open(dfuh, pid) != DFUAPISuccess)
825 goto error; 1007 goto error;
826 1008
827 if (!dfu_download_file(dfuh, buf, size+4)) 1009 if (!ipoddfu_download_file(dfuh, buf, size+4))
828 goto error; 1010 goto error;
829 1011
830bye: 1012bye:
831 if (buf) free(buf); 1013 if (buf) free(buf);
832 dfu_destroy(dfuh); 1014 dfuapi_destroy(dfuh);
833 return ret; 1015 return ret;
834 1016
835error: 1017error:
@@ -846,20 +1028,24 @@ int ipoddfu_scan(int pid, int *state, int reset,
846 struct dfuDev *dfuh; 1028 struct dfuDev *dfuh;
847 int ret = 1; /* ok */ 1029 int ret = 1; /* ok */
848 1030
849 dfuh = dfu_create(); 1031 dfuh = dfuapi_create();
850 1032
851 if (!dfu_open(dfuh, pid)) 1033 if (dfuapi_open(dfuh, pid) != DFUAPISuccess)
852 goto error; 1034 goto error;
853 1035
854 if (reset) 1036 if (reset)
855 if (!dfuh->api->reset_fn(dfuh)) 1037 if (dfuapi_reset(dfuh) != DFUAPISuccess)
856 goto error; 1038 goto error;
857 1039
858 if (!dfureq_getstate(dfuh, state)) 1040 if (state) {
859 goto error; 1041 DFUState sts;
1042 if (dfuapi_req_getstate(dfuh, &sts) != DFUAPISuccess)
1043 goto error;
1044 *state = (int)sts;
1045 }
860 1046
861bye: 1047bye:
862 dfu_destroy(dfuh); 1048 dfuapi_destroy(dfuh);
863 return ret; 1049 return ret;
864 1050
865error: 1051error: