summaryrefslogtreecommitdiff
path: root/rbutil
diff options
context:
space:
mode:
Diffstat (limited to 'rbutil')
-rw-r--r--rbutil/mks5lboot/.gitignore3
-rw-r--r--rbutil/mks5lboot/Makefile20
-rw-r--r--rbutil/mks5lboot/README49
-rw-r--r--rbutil/mks5lboot/ipoddfu.c624
-rw-r--r--rbutil/mks5lboot/main.c41
-rw-r--r--rbutil/mks5lboot/mkdfu.c22
6 files changed, 492 insertions, 267 deletions
diff --git a/rbutil/mks5lboot/.gitignore b/rbutil/mks5lboot/.gitignore
index 9078451a7a..9b9b1de6ab 100644
--- a/rbutil/mks5lboot/.gitignore
+++ b/rbutil/mks5lboot/.gitignore
@@ -1,2 +1,5 @@
1buildposix/ 1buildposix/
2buildmingw/
3builddarwin/
2mks5lboot 4mks5lboot
5mks5lboot.exe
diff --git a/rbutil/mks5lboot/Makefile b/rbutil/mks5lboot/Makefile
index ba118eefd0..72ea521d5f 100644
--- a/rbutil/mks5lboot/Makefile
+++ b/rbutil/mks5lboot/Makefile
@@ -4,6 +4,7 @@
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/ 6# \/ \/ \/ \/ \/
7CC := gcc
7CFLAGS += -Wall -Wextra 8CFLAGS += -Wall -Wextra
8 9
9OUTPUT = mks5lboot 10OUTPUT = mks5lboot
@@ -15,18 +16,25 @@ SOURCES := $(LIBSOURCES) main.c
15# dependencies for binary 16# dependencies for binary
16EXTRADEPS := 17EXTRADEPS :=
17 18
18ifeq ($(findstring MINGW,$(shell uname)),MINGW) 19CPPDEFINES := $(shell echo foo | $(CROSS)$(CC) -dM -E -)
20
21ifeq ($(findstring WIN32,$(CPPDEFINES)),WIN32)
19LDOPTS += -lsetupapi 22LDOPTS += -lsetupapi
20# optional libusb support on Windows 23# optional libusb support (needed for WinUSB and libusbK drivers)
21ifdef DISABLE_LIBUSBAPI 24ifeq ($(findstring MINGW,$(CPPDEFINES)),MINGW)
22CFLAGS += -DNO_LIBUSBAPI 25ifeq ($(USE_LIBUSBAPI),1)
23else 26CFLAGS += -DUSE_LIBUSBAPI
24LDOPTS += -Wl,-Bstatic -lusb-1.0 27LDOPTS += -Wl,-Bstatic -lusb-1.0
25endif 28endif
29endif
26else 30else
27# Linux, OS X 31ifeq ($(findstring APPLE,$(CPPDEFINES)),APPLE)
32LDOPTS += -L/usr/local/lib -framework IOKit -framework CoreFoundation
33else # Linux
34CFLAGS += -DUSE_LIBUSBAPI
28LDOPTS += -lusb-1.0 35LDOPTS += -lusb-1.0
29endif 36endif
37endif
30 38
31include ../libtools.make 39include ../libtools.make
32 40
diff --git a/rbutil/mks5lboot/README b/rbutil/mks5lboot/README
index c2df299867..c424f7e617 100644
--- a/rbutil/mks5lboot/README
+++ b/rbutil/mks5lboot/README
@@ -5,7 +5,7 @@ A tool to install/uninstall a dual bootloader into a s5l8702 based
5device: 5device:
6 6
7 - iPod Classic 6G 7 - iPod Classic 6G
8 - iPod Nano 3G (TODO) 8 - iPod Nano 3G (WIP)
9 9
10 10
11Usage 11Usage
@@ -97,32 +97,40 @@ Prerequisites:
97 [INFO] DFU device state: 2 97 [INFO] DFU device state: 2
98 . When the device is found but there is no driver installed: 98 . When the device is found but there is no driver installed:
99 [ERR] Could not open USB device: LIBUSB_ERROR_NOT_SUPPORTED 99 [ERR] Could not open USB device: LIBUSB_ERROR_NOT_SUPPORTED
100 . Then the device is found but driver is not valid (probably a 100 . When the device is found but driver is not valid (probably a
101 libusb-win32 driver is installed): 101 libusb-win32 driver is installed):
102 [ERR] Could not set USB configuration: LIBUSB_ERROR_NOT_FOUND 102 [ERR] Could not set USB configuration: LIBUSB_ERROR_NOT_FOUND
103 . If there is no valid DFU driver installed, try one of these: 103 . If there is no valid DFU driver installed, try one of these:
104 a) Use Zadig (http://zadig.akeo.ie/) to build and install a WinUSB 104 a) Use Zadig (http://zadig.akeo.ie/) to build and install a WinUSB
105 (libusb.info) or libusbK driver for your device. Note that 105 (libusb.info) or libusbK driver for your device. Note that
106 libusb-win32 (libusb0) drivers are not valid for mks5lboot. 106 libusb-win32 (libusb0) drivers are not valid for mks5lboot.
107 b) Use Apple Mobile Device USB driver (included with iTunes). 107 b) Use Apple Mobile Device USB driver (included with iTunes). To
108 install this driver without iTunes see https://www.freemyipod.org
109 /wiki/EmCORE_Installation/iPodClassic/InstalliTunesDrivers
108 110
109Command line install: 111Command line install:
110 112
111 - If you are using iTunes on Windows, close iTunes and kill (or pause) 113 - If you are using iTunes on Windows, close iTunes and kill (or pause)
112 iTunesHelper.exe before entering DFU mode. 114 iTunesHelper.exe before entering DFU mode.
113 115
116 - If you are using iTunes on Mac, quit iTunes and kill (or pause) the
117 iTunesHelper process before entering DFU mode.
118 You can use "ps x | grep iTunesHelper" to locate the process <PID>,
119 use "kill -STOP <PID>" to suspend the process and "kill -CONT <PID>"
120 to resume it once the bootloader is installed.
121
114 - Put you device on DFU mode by pressing and holding SELECT+MENU buttons 122 - Put you device on DFU mode by pressing and holding SELECT+MENU buttons
115 for about 12 seconds. 123 for about 12 seconds.
116 124
117 You can notice when the device enters DFU mode running the next command 125 You can notice when the device enters DFU mode running the next command
118 to scan the USB bus every second (press Ctrl-C to abort the scan): 126 to scan the USB bus every second (press Ctrl-C to abort the scan):
119 mks5lboot --dfuscan --loop 127 ./mks5lboot --dfuscan --loop
120 128
121 - To install or update a bootloader, build the DFU installer and send it 129 - To install or update a bootloader, build the DFU installer and send it
122 to the device: 130 to the device:
123 mks5lboot --bl-inst /path/to/bootloader-ipod6g.ipod 131 ./mks5lboot --bl-inst path/to/bootloader-ipod6g.ipod
124 132
125 When the DFU imagen is loaded and executed, the device emits an 'alive' 133 When the DFU image is loaded and executed, the device emits an 'alive'
126 tone (2000Hz/100ms). When the bootloader is successfully installed then 134 tone (2000Hz/100ms). When the bootloader is successfully installed then
127 a dual tone beep sounds (1000Hz/100ms+2000Hz/150ms) and the device 135 a dual tone beep sounds (1000Hz/100ms+2000Hz/150ms) and the device
128 reboots. If something went bad then 330Hz/500ms tone is emited and the 136 reboots. If something went bad then 330Hz/500ms tone is emited and the
@@ -132,10 +140,15 @@ Command line install:
132 140
133 - To remove a previously installed bootloader, build the DFU uninstaler 141 - To remove a previously installed bootloader, build the DFU uninstaler
134 and send it to the device: 142 and send it to the device:
135 mks5lboot --bl-uninst ipod6g 143 ./mks5lboot --bl-uninst ipod6g
144
145 Notes:
146
147 - If USB access is denied, try to run the mks5lboot tool using a privileged
148 user (i.e. Administrator or root).
149
150 - On Windows, use 'mks5lboot' or 'mks5lboot.exe' instead of './mks5lboot'.
136 151
137 If USB access is denied, try to run the mks5lboot tool using a privileged
138 user (i.e. Administrator or root).
139 152
140 153
141Dual-Boot 154Dual-Boot
@@ -192,14 +205,20 @@ To build the DFU single-boot installer and send it to the device:
192 mks5lboot --bl-inst --single /path/to/bootloader-ipod6g.ipod 205 mks5lboot --bl-inst --single /path/to/bootloader-ipod6g.ipod
193 206
194 207
195Compilation 208Build
196----------- 209-----
210
211To build type 'make'.
212
213Linux needs libusb >= 1.0, use your package manager to install libusb.
197 214
198Needs libusb > 1.0 installed, tested on: 215For Windows, to build with libusb support type 'make USE_LIBUSBAPI=1'.
199 216
200Linux: gcc-4.9.2 + libusb-1.0.19 217Tested on:
201Windows XP: mingw32-gcc-4.8.1 + libusbx-1.0.15 218 Linux: gcc-4.9.2 + libusb-1.0.19
202OS X 10.11: clang-7.3.0 + libusb-1.0.20 219 Windows XP: mingw32-gcc-4.8.1 + libusbx-1.0.15
220 OS X 10.11: clang-7.3.0 + libusb-1.0.20
221 MXE: i686-w64-mingw32.static-gcc 5.4.0 + libusb-1.0.21
203 222
204 223
205Hacking 224Hacking
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:
diff --git a/rbutil/mks5lboot/main.c b/rbutil/mks5lboot/main.c
index 98c85b9bb7..31e16eca82 100644
--- a/rbutil/mks5lboot/main.c
+++ b/rbutil/mks5lboot/main.c
@@ -24,7 +24,6 @@
24#include <string.h> 24#include <string.h>
25#include <unistd.h> 25#include <unistd.h>
26#include <fcntl.h> 26#include <fcntl.h>
27#include <time.h>
28#include <sys/types.h> 27#include <sys/types.h>
29#include <sys/stat.h> 28#include <sys/stat.h>
30 29
@@ -35,9 +34,23 @@
35#define O_BINARY 0 34#define O_BINARY 0
36#endif 35#endif
37 36
37#ifdef WIN32
38#include <windows.h>
39#define sleep_ms(ms) Sleep(ms)
40#else
41#include <time.h>
42static void sleep_ms(unsigned int ms)
43{
44 struct timespec req;
45 req.tv_sec = ms / 1000;
46 req.tv_nsec = (ms % 1000) * 1000000;
47 nanosleep(&req, NULL);
48}
49#endif
50
38#define DEFAULT_LOOP_PERIOD 1 /* seconds */ 51#define DEFAULT_LOOP_PERIOD 1 /* seconds */
39 52
40#define ERROR(format, ...) \ 53#define _ERR(format, ...) \
41 do { \ 54 do { \
42 snprintf(errstr, errstrsize, "[ERR] "format, __VA_ARGS__); \ 55 snprintf(errstr, errstrsize, "[ERR] "format, __VA_ARGS__); \
43 goto error; \ 56 goto error; \
@@ -48,10 +61,10 @@ static int write_file(char *outfile, unsigned char* buf,
48{ 61{
49 int fd = open(outfile, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666); 62 int fd = open(outfile, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666);
50 if (fd < 0) 63 if (fd < 0)
51 ERROR("Could not open %s for writing", outfile); 64 _ERR("Could not open %s for writing", outfile);
52 65
53 if (write(fd, buf, bufsize) != bufsize) 66 if (write(fd, buf, bufsize) != bufsize)
54 ERROR("Could not write file %s", outfile); 67 _ERR("Could not write file %s", outfile);
55 68
56 return 1; 69 return 1;
57 70
@@ -68,19 +81,19 @@ static unsigned char *read_file(char *infile, int *bufsize,
68 81
69 fd = open(infile, O_RDONLY|O_BINARY); 82 fd = open(infile, O_RDONLY|O_BINARY);
70 if (fd < 0) 83 if (fd < 0)
71 ERROR("Could not open %s for reading", infile); 84 _ERR("Could not open %s for reading", infile);
72 85
73 if (fstat(fd, &s) < 0) 86 if (fstat(fd, &s) < 0)
74 ERROR("Checking size of input file %s", infile); 87 _ERR("Checking size of input file %s", infile);
75 88
76 *bufsize = s.st_size; 89 *bufsize = s.st_size;
77 90
78 buf = malloc(*bufsize); 91 buf = malloc(*bufsize);
79 if (buf == NULL) 92 if (buf == NULL)
80 ERROR("Could not allocate memory for %s", infile); 93 _ERR("Could not allocate memory for %s", infile);
81 94
82 if (read(fd, buf, *bufsize) != *bufsize) 95 if (read(fd, buf, *bufsize) != *bufsize)
83 ERROR("Could not read file %s", infile); 96 _ERR("Could not read file %s", infile);
84 97
85 return buf; 98 return buf;
86 99
@@ -88,14 +101,6 @@ error:
88 return NULL; 101 return NULL;
89} 102}
90 103
91static void sleep_ms(unsigned int ms)
92{
93 struct timespec req;
94 req.tv_sec = ms / 1000;
95 req.tv_nsec = (ms % 1000) * 1000000;
96 nanosleep(&req, NULL);
97}
98
99static void usage(void) 104static void usage(void)
100{ 105{
101 fprintf(stderr, 106 fprintf(stderr,
@@ -169,7 +174,11 @@ int main(int argc, char* argv[])
169 int dfusize; 174 int dfusize;
170 175
171 fprintf(stderr, 176 fprintf(stderr,
177#if defined(WIN32) && defined(USE_LIBUSBAPI)
178 "mks5lboot Version " VERSION " (libusb)\n"
179#else
172 "mks5lboot Version " VERSION "\n" 180 "mks5lboot Version " VERSION "\n"
181#endif
173 "This is free software; see the source for copying conditions. There is NO\n" 182 "This is free software; see the source for copying conditions. There is NO\n"
174 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" 183 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
175 "\n"); 184 "\n");
diff --git a/rbutil/mks5lboot/mkdfu.c b/rbutil/mks5lboot/mkdfu.c
index 6ac0daf1ac..bb1929bffd 100644
--- a/rbutil/mks5lboot/mkdfu.c
+++ b/rbutil/mks5lboot/mkdfu.c
@@ -117,7 +117,7 @@ static void put_uint32le(unsigned char* p, uint32_t x)
117 p[3] = (x >> 24) & 0xff; 117 p[3] = (x >> 24) & 0xff;
118} 118}
119 119
120#define ERROR(format, ...) \ 120#define _ERR(format, ...) \
121 do { \ 121 do { \
122 snprintf(errstr, errstrsize, "[ERR] "format, __VA_ARGS__); \ 122 snprintf(errstr, errstrsize, "[ERR] "format, __VA_ARGS__); \
123 goto error; \ 123 goto error; \
@@ -135,16 +135,16 @@ static unsigned char *load_file(char *filename, int *bufsize,
135 135
136 fd = open(filename, O_RDONLY|O_BINARY); 136 fd = open(filename, O_RDONLY|O_BINARY);
137 if (fd < 0) 137 if (fd < 0)
138 ERROR("Could not open %s for reading", filename); 138 _ERR("Could not open %s for reading", filename);
139 139
140 if (fstat(fd, &s) < 0) 140 if (fstat(fd, &s) < 0)
141 ERROR("Checking filesize of input file %s", filename); 141 _ERR("Checking filesize of input file %s", filename);
142 *bufsize = s.st_size; 142 *bufsize = s.st_size;
143 143
144 if (is_rbbl) { 144 if (is_rbbl) {
145 /* Read Rockbox header */ 145 /* Read Rockbox header */
146 if (read(fd, header, sizeof(header)) != sizeof(header)) 146 if (read(fd, header, sizeof(header)) != sizeof(header))
147 ERROR("Could not read file %s", filename); 147 _ERR("Could not read file %s", filename);
148 *bufsize -= sizeof(header); 148 *bufsize -= sizeof(header);
149 149
150 for (i = 0; i < NUM_MODELS; i++) 150 for (i = 0; i < NUM_MODELS; i++)
@@ -152,7 +152,7 @@ static unsigned char *load_file(char *filename, int *bufsize,
152 break; 152 break;
153 153
154 if (i == NUM_MODELS) 154 if (i == NUM_MODELS)
155 ERROR("Model name \"%4.4s\" unknown. " 155 _ERR("Model name \"%4.4s\" unknown. "
156 "Is this really a rockbox bootloader?", header + 4); 156 "Is this really a rockbox bootloader?", header + 4);
157 157
158 *model = &ipod_identity[i]; 158 *model = &ipod_identity[i];
@@ -160,10 +160,10 @@ static unsigned char *load_file(char *filename, int *bufsize,
160 160
161 buf = malloc(*bufsize); 161 buf = malloc(*bufsize);
162 if (buf == NULL) 162 if (buf == NULL)
163 ERROR("Could not allocate memory for %s", filename); 163 _ERR("Could not allocate memory for %s", filename);
164 164
165 if (read(fd, buf, *bufsize) != *bufsize) 165 if (read(fd, buf, *bufsize) != *bufsize)
166 ERROR("Could not read file %s", filename); 166 _ERR("Could not read file %s", filename);
167 167
168 if (is_rbbl) { 168 if (is_rbbl) {
169 /* Check checksum */ 169 /* Check checksum */
@@ -173,7 +173,7 @@ static unsigned char *load_file(char *filename, int *bufsize,
173 sum += buf[i]; 173 sum += buf[i];
174 } 174 }
175 if (sum != get_uint32be(header)) 175 if (sum != get_uint32be(header))
176 ERROR("Checksum mismatch in %s", filename); 176 _ERR("Checksum mismatch in %s", filename);
177 } 177 }
178 178
179 close(fd); 179 close(fd);
@@ -223,7 +223,7 @@ unsigned char *mkdfu(int dfu_type, char *dfu_arg, int* dfu_size,
223 } 223 }
224 } 224 }
225 if (!model) 225 if (!model)
226 ERROR("Platform name \"%s\" unknown", dfu_arg); 226 _ERR("Platform name \"%s\" unknown", dfu_arg);
227 227
228 *dfu_size = BIN_OFFSET + model->dualboot_uninstall_size; 228 *dfu_size = BIN_OFFSET + model->dualboot_uninstall_size;
229 dfu_desc = "BL uninstaller"; 229 dfu_desc = "BL uninstaller";
@@ -255,11 +255,11 @@ unsigned char *mkdfu(int dfu_type, char *dfu_arg, int* dfu_size,
255 } 255 }
256 256
257 if (*dfu_size > DFU_MAXSIZE) 257 if (*dfu_size > DFU_MAXSIZE)
258 ERROR("DFU image (%d bytes) too big", *dfu_size); 258 _ERR("DFU image (%d bytes) too big", *dfu_size);
259 259
260 dfu_buf = calloc(*dfu_size, 1); 260 dfu_buf = calloc(*dfu_size, 1);
261 if (!dfu_buf) 261 if (!dfu_buf)
262 ERROR("Could not allocate %d bytes for DFU image", *dfu_size); 262 _ERR("Could not allocate %d bytes for DFU image", *dfu_size);
263 263
264 cert_off = get_uint32le(s5l8702hdr.u.enc34.cert_off); 264 cert_off = get_uint32le(s5l8702hdr.u.enc34.cert_off);
265 cert_sz = get_uint32le(s5l8702hdr.u.enc34.cert_sz); 265 cert_sz = get_uint32le(s5l8702hdr.u.enc34.cert_sz);