diff options
Diffstat (limited to 'rbutil/mks5lboot/ipoddfu.c')
-rw-r--r-- | rbutil/mks5lboot/ipoddfu.c | 624 |
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> | ||
47 | static void sleep_ms(unsigned int ms) | 51 | static 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 | |||
60 | static 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() */ |
68 | static unsigned long crc32table[256]; | 78 | static uint32_t crc32table[256]; |
69 | 79 | ||
70 | /* Calculate crc32. Little endian. | 80 | /* Calculate crc32 */ |
71 | * Standard seed is 0xffffffff or 0. | 81 | static uint32_t crc32(void *data, unsigned int len, uint32_t previousCrc32) |
72 | * Some implementations xor result with 0xffffffff after calculation. | ||
73 | */ | ||
74 | static 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 | ||
116 | static int KNOWN_PIDS[] = | 108 | struct pid_info { |
109 | int pid; | ||
110 | int mode; /* 0->DFU, 1->WTF */ | ||
111 | char *desc; | ||
112 | }; | ||
113 | |||
114 | struct 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 | ||
142 | struct usbControlSetup { | 140 | struct 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 */ |
161 | typedef enum DFUState { | 165 | typedef 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 | ||
175 | typedef enum DFUStatus { | 179 | typedef 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 | ||
194 | typedef enum DFURequest { | 198 | typedef 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 | ||
208 | typedef enum { | ||
209 | DFUAPIFail = 0, | ||
210 | DFUAPISuccess, | ||
211 | } dfuAPIResult; | ||
212 | |||
204 | struct dfuDev { | 213 | struct 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 | ||
224 | struct dfuAPI { | 237 | struct 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 | */ |
236 | static int dfu_check_id(int vid, int pid, int *pid_list) | 249 | static 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 |
256 | static int dfu_winapi_chkrc(struct dfuDev *dfuh, char *str, bool success) | 269 | static 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 | ||
266 | static int dfu_winapi_request(struct dfuDev *dfuh, | 279 | static 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 | ||
293 | static int dfu_winapi_reset(struct dfuDev *dfuh) | 306 | static 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 | ||
302 | static void dfu_winapi_close(struct dfuDev *dfuh) | 316 | static void dfu_winapi_close(struct dfuDev *dfuh) |
@@ -314,7 +328,7 @@ static void dfu_winapi_close(struct dfuDev *dfuh) | |||
314 | static const GUID GUID_AAPLDFU = | 328 | static 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 | ||
317 | static int dfu_winapi_open(struct dfuDev *dfuh, int *pid_list) | 331 | static 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 |
401 | static int dfu_libusb_chkrc(struct dfuDev *dfuh, char *str) | 415 | static 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 | ||
410 | static int dfu_libusb_request(struct dfuDev *dfuh, | 424 | static 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 | ||
420 | static int dfu_libusb_reset(struct dfuDev *dfuh) | 434 | static 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 | ||
426 | static void dfu_libusb_close(struct dfuDev *dfuh) | 441 | static 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 | ||
441 | static int dfu_libusb_open(struct dfuDev *dfuh, int *pid_list) | 456 | static 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) | 536 | static 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 | |||
545 | static 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 | |||
563 | static 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 | |||
577 | static 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 | |||
586 | static 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 | |||
656 | bye: | ||
657 | if (usb_iterator != IO_OBJECT_NULL) | ||
658 | IOObjectRelease(usb_iterator); | ||
659 | return dfuh->res; | ||
660 | |||
661 | error: | ||
662 | goto bye; | ||
663 | } | ||
664 | #endif /* __APPLE__ */ | ||
665 | |||
666 | /* list of suported APIs */ | ||
524 | static struct dfuAPI api_list[] = | 667 | static 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 | */ |
549 | static void dfu_set_errstr(struct dfuDev *dfuh, char *str) | ||
550 | { | ||
551 | strncpy(dfuh->err, str, sizeof(dfuh->err)); | ||
552 | } | ||
553 | |||
554 | static int DEBUG_DFUREQ = 0; | 697 | static int DEBUG_DFUREQ = 0; |
555 | 698 | ||
556 | static int dfu_request(struct dfuDev *dfuh, | 699 | static 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 | |
732 | bye: | ||
733 | return dfuh->res; | ||
734 | error: | ||
735 | goto bye; | ||
588 | } | 736 | } |
589 | 737 | ||
590 | static int dfureq_getstatus(struct dfuDev *dfuh, int *status, | 738 | static 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 | ||
603 | static int dfureq_getstate(struct dfuDev *dfuh, int *state) | 752 | static 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 | ||
614 | static int dfureq_dnload(struct dfuDev* dfuh, uint16_t blknum, | 761 | static 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 |
623 | static int dfureq_upload(struct dfuDev* dfuh, | 770 | static 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 | ||
630 | static int dfureq_clrstatus(struct dfuDev* dfuh) | 777 | static 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 | ||
636 | static int dfureq_abort(struct dfuDev* dfuh) | 783 | static 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 */ |
643 | static int dfureq_detach(struct dfuDev* dfuh, int tmo) | 790 | static 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 | ||
650 | static int dfu_send_packet(struct dfuDev* dfuh, uint16_t blknum, | 797 | static 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 | |||
802 | static 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; | 826 | bye: |
827 | return dfuh->res; | ||
828 | error: | ||
829 | goto bye; | ||
830 | } | ||
831 | |||
832 | static void dfuapi_set_err(struct dfuDev *dfuh, char *str) | ||
833 | { | ||
834 | dfuh->res = DFUAPIFail; | ||
835 | strncpy(dfuh->err, str, sizeof(dfuh->err)); | ||
836 | } | ||
837 | |||
838 | static 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 | |||
877 | bye: | ||
878 | return dfuh->res; | ||
879 | error: | ||
880 | goto bye; | ||
674 | } | 881 | } |
675 | 882 | ||
676 | static int dfu_download_file(struct dfuDev* dfuh, | 883 | static 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 | |||
892 | static struct dfuDev *dfuapi_create(void) | ||
893 | { | ||
894 | return calloc(sizeof(struct dfuDev), 1); | ||
895 | } | ||
896 | |||
897 | |||
898 | /* | ||
899 | * app level functions | ||
900 | */ | ||
901 | static 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 | ||
747 | ok: | 973 | ok: |
@@ -750,86 +976,42 @@ error: | |||
750 | return 0; | 976 | return 0; |
751 | } | 977 | } |
752 | 978 | ||
753 | static 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 | |||
780 | static 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 | |||
789 | static struct dfuDev *dfu_create() | ||
790 | { | ||
791 | return calloc(sizeof(struct dfuDev), 1); | ||
792 | } | ||
793 | |||
794 | /* | ||
795 | * exported functions | ||
796 | */ | ||
797 | int ipoddfu_send(int pid, unsigned char *data, int size, | 980 | int 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 | ||
830 | bye: | 1012 | bye: |
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 | ||
835 | error: | 1017 | error: |
@@ -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 | ||
861 | bye: | 1047 | bye: |
862 | dfu_destroy(dfuh); | 1048 | dfuapi_destroy(dfuh); |
863 | return ret; | 1049 | return ret; |
864 | 1050 | ||
865 | error: | 1051 | error: |