summaryrefslogtreecommitdiffstats
path: root/src/libirecovery.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libirecovery.c')
-rw-r--r--src/libirecovery.c3828
1 files changed, 3573 insertions, 255 deletions
diff --git a/src/libirecovery.c b/src/libirecovery.c
index 38e0fc3..6b110f1 100644
--- a/src/libirecovery.c
+++ b/src/libirecovery.c
@@ -1,117 +1,1905 @@
1/** 1/*
2 * iRecovery - Utility for DFU 2.0, WTF and Recovery Mode 2 * libirecovery.c
3 * Copyright (C) 2008 - 2009 westbaer 3 * Communication to iBoot/iBSS on Apple iOS devices via USB
4 * 4 *
5 * This program is free software: you can redistribute it and/or modify 5 * Copyright (c) 2011-2023 Nikias Bassen <nikias@gmx.li>
6 * it under the terms of the GNU General Public License as published by 6 * Copyright (c) 2012-2020 Martin Szulecki <martin.szulecki@libimobiledevice.org>
7 * the Free Software Foundation, either version 3 of the License, or 7 * Copyright (c) 2010 Chronic-Dev Team
8 * (at your option) any later version. 8 * Copyright (c) 2010 Joshua Hill
9 * Copyright (c) 2008-2011 Nicolas Haunold
9 * 10 *
10 * This program is distributed in the hope that it will be useful, 11 * All rights reserved. This program and the accompanying materials
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * are made available under the terms of the GNU Lesser General Public License
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * (LGPL) version 2.1 which accompanies this distribution, and is available at
13 * GNU General Public License for more details. 14 * http://www.gnu.org/licenses/lgpl-2.1.html
14 * 15 *
15 * You should have received a copy of the GNU General Public License 16 * This library is distributed in the hope that it will be useful,
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **/ 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 */
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
18 25
19#include <stdio.h> 26#include <stdio.h>
27#include <stdint.h>
20#include <stdlib.h> 28#include <stdlib.h>
21#include <string.h> 29#include <string.h>
30#include <inttypes.h>
31#include <ctype.h>
22#include <unistd.h> 32#include <unistd.h>
23#include <libusb-1.0/libusb.h> 33#include <sys/stat.h>
34
35#include <libimobiledevice-glue/collection.h>
36#include <libimobiledevice-glue/thread.h>
37
38#ifndef USE_DUMMY
39#ifndef WIN32
40#ifndef HAVE_IOKIT
41#include <libusb.h>
42#if (defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000102)) || (defined(LIBUSBX_API_VERSION) && (LIBUSBX_API_VERSION >= 0x01000102))
43#define HAVE_LIBUSB_HOTPLUG_API 1
44#endif
45#else
46#include <CoreFoundation/CoreFoundation.h>
47#include <IOKit/usb/IOUSBLib.h>
48#include <IOKit/IOCFPlugIn.h>
49#endif
50#else
51#define WIN32_LEAN_AND_MEAN
52#include <windows.h>
53#include <setupapi.h>
54#ifndef sleep
55#define sleep(n) Sleep(1000 * n)
56#endif
57#endif
58#endif
59
60#ifdef IRECV_STATIC
61 #define IRECV_API
62#elif defined(_WIN32)
63 #define IRECV_API __declspec( dllexport )
64#else
65 #if __GNUC__ >= 4
66 #define IRECV_API __attribute__((visibility("default")))
67 #else
68 #define IRECV_API
69 #endif
70#endif
24 71
25#include "libirecovery.h" 72#include "libirecovery.h"
26 73
74struct irecv_client_private {
75 int debug;
76 int usb_config;
77 int usb_interface;
78 int usb_alt_interface;
79 unsigned int mode;
80 int isKIS;
81 struct irecv_device_info device_info;
82#ifndef USE_DUMMY
83#ifndef WIN32
84#ifndef HAVE_IOKIT
85 libusb_device_handle* handle;
86#else
87 IOUSBDeviceInterface320 **handle;
88 IOUSBInterfaceInterface300 **usbInterface;
89#endif
90#else
91 HANDLE handle;
92#endif
93 irecv_event_cb_t progress_callback;
94 irecv_event_cb_t received_callback;
95 irecv_event_cb_t connected_callback;
96 irecv_event_cb_t precommand_callback;
97 irecv_event_cb_t postcommand_callback;
98 irecv_event_cb_t disconnected_callback;
99#endif
100};
101
102#define USB_TIMEOUT 10000
103#define APPLE_VENDOR_ID 0x05AC
104
105// KIS
106#define KIS_PRODUCT_ID 0x1881
107
108#define KIS_PORTAL_CONFIG 0x01
109#define KIS_PORTAL_RSM 0x10
110
111#define KIS_INDEX_UPLOAD 0x0D
112#define KIS_INDEX_ENABLE_A 0x0A // macOS writes to this
113#define KIS_INDEX_ENABLE_B 0x14 // macOS writes to this
114#define KIS_INDEX_GET_INFO 0x100
115#define KIS_INDEX_BOOT_IMG 0x103
116
117#define KIS_ENABLE_A_VAL 0x21 // Value to write to KIS_INDEX_ENABLE_A
118#define KIS_ENABLE_B_VAL 0x01 // Value to write to KIS_INDEX_ENABLE_B
119
27#define BUFFER_SIZE 0x1000 120#define BUFFER_SIZE 0x1000
28#define debug(...) if(libirecovery_debug) fprintf(stderr, __VA_ARGS__) 121#define debug(...) if (libirecovery_debug) fprintf(stderr, __VA_ARGS__)
29 122
30static int libirecovery_debug = 0; 123static int libirecovery_debug = 0;
124#ifndef USE_DUMMY
125#ifndef WIN32
126#ifndef HAVE_IOKIT
31static libusb_context* libirecovery_context = NULL; 127static libusb_context* libirecovery_context = NULL;
128#endif
129#endif
130#endif
131
132static struct irecv_device irecv_devices[] = {
133 /* iPhone */
134 { "iPhone1,1", "m68ap", 0x00, 0x8900, "iPhone 2G" },
135 { "iPhone1,2", "n82ap", 0x04, 0x8900, "iPhone 3G" },
136 { "iPhone2,1", "n88ap", 0x00, 0x8920, "iPhone 3Gs" },
137 { "iPhone3,1", "n90ap", 0x00, 0x8930, "iPhone 4 (GSM)" },
138 { "iPhone3,2", "n90bap", 0x04, 0x8930, "iPhone 4 (GSM) R2 2012" },
139 { "iPhone3,3", "n92ap", 0x06, 0x8930, "iPhone 4 (CDMA)" },
140 { "iPhone4,1", "n94ap", 0x08, 0x8940, "iPhone 4s" },
141 { "iPhone5,1", "n41ap", 0x00, 0x8950, "iPhone 5 (GSM)" },
142 { "iPhone5,2", "n42ap", 0x02, 0x8950, "iPhone 5 (Global)" },
143 { "iPhone5,3", "n48ap", 0x0a, 0x8950, "iPhone 5c (GSM)" },
144 { "iPhone5,4", "n49ap", 0x0e, 0x8950, "iPhone 5c (Global)" },
145 { "iPhone6,1", "n51ap", 0x00, 0x8960, "iPhone 5s (GSM)" },
146 { "iPhone6,2", "n53ap", 0x02, 0x8960, "iPhone 5s (Global)" },
147 { "iPhone7,1", "n56ap", 0x04, 0x7000, "iPhone 6 Plus" },
148 { "iPhone7,2", "n61ap", 0x06, 0x7000, "iPhone 6" },
149 { "iPhone8,1", "n71ap", 0x04, 0x8000, "iPhone 6s" },
150 { "iPhone8,1", "n71map", 0x04, 0x8003, "iPhone 6s" },
151 { "iPhone8,2", "n66ap", 0x06, 0x8000, "iPhone 6s Plus" },
152 { "iPhone8,2", "n66map", 0x06, 0x8003, "iPhone 6s Plus" },
153 { "iPhone8,4", "n69ap", 0x02, 0x8003, "iPhone SE (1st gen)" },
154 { "iPhone8,4", "n69uap", 0x02, 0x8000, "iPhone SE (1st gen)" },
155 { "iPhone9,1", "d10ap", 0x08, 0x8010, "iPhone 7 (Global)" },
156 { "iPhone9,2", "d11ap", 0x0a, 0x8010, "iPhone 7 Plus (Global)" },
157 { "iPhone9,3", "d101ap", 0x0c, 0x8010, "iPhone 7 (GSM)" },
158 { "iPhone9,4", "d111ap", 0x0e, 0x8010, "iPhone 7 Plus (GSM)" },
159 { "iPhone10,1", "d20ap", 0x02, 0x8015, "iPhone 8 (Global)" },
160 { "iPhone10,2", "d21ap", 0x04, 0x8015, "iPhone 8 Plus (Global)" },
161 { "iPhone10,3", "d22ap", 0x06, 0x8015, "iPhone X (Global)" },
162 { "iPhone10,4", "d201ap", 0x0a, 0x8015, "iPhone 8 (GSM)" },
163 { "iPhone10,5", "d211ap", 0x0c, 0x8015, "iPhone 8 Plus (GSM)" },
164 { "iPhone10,6", "d221ap", 0x0e, 0x8015, "iPhone X (GSM)" },
165 { "iPhone11,2", "d321ap", 0x0e, 0x8020, "iPhone XS" },
166 { "iPhone11,4", "d331ap", 0x0a, 0x8020, "iPhone XS Max (China)" },
167 { "iPhone11,6", "d331pap", 0x1a, 0x8020, "iPhone XS Max" },
168 { "iPhone11,8", "n841ap", 0x0c, 0x8020, "iPhone XR" },
169 { "iPhone12,1", "n104ap", 0x04, 0x8030, "iPhone 11" },
170 { "iPhone12,3", "d421ap", 0x06, 0x8030, "iPhone 11 Pro" },
171 { "iPhone12,5", "d431ap", 0x02, 0x8030, "iPhone 11 Pro Max" },
172 { "iPhone12,8", "d79ap", 0x10, 0x8030, "iPhone SE (2nd gen)" },
173 { "iPhone13,1", "d52gap", 0x0A, 0x8101, "iPhone 12 mini" },
174 { "iPhone13,2", "d53gap", 0x0C, 0x8101, "iPhone 12" },
175 { "iPhone13,3", "d53pap", 0x0E, 0x8101, "iPhone 12 Pro" },
176 { "iPhone13,4", "d54pap", 0x08, 0x8101, "iPhone 12 Pro Max" },
177 { "iPhone14,2", "d63ap", 0x0C, 0x8110, "iPhone 13 Pro" },
178 { "iPhone14,3", "d64ap", 0x0E, 0x8110, "iPhone 13 Pro Max" },
179 { "iPhone14,4", "d16ap", 0x08, 0x8110, "iPhone 13 mini" },
180 { "iPhone14,5", "d17ap", 0x0A, 0x8110, "iPhone 13" },
181 { "iPhone14,6", "d49ap", 0x10, 0x8110, "iPhone SE (3rd gen)" },
182 { "iPhone14,7", "d27ap", 0x18, 0x8110, "iPhone 14" },
183 { "iPhone14,8", "d28ap", 0x1A, 0x8110, "iPhone 14 Plus" },
184 { "iPhone15,2", "d73ap", 0x0C, 0x8120, "iPhone 14 Pro" },
185 { "iPhone15,3", "d74ap", 0x0E, 0x8120, "iPhone 14 Pro Max" },
186 { "iPhone15,4", "d37ap", 0x08, 0x8120, "iPhone 15" },
187 { "iPhone15,5", "d38ap", 0x0A, 0x8120, "iPhone 15 Plus" },
188 { "iPhone16,1", "d83ap", 0x04, 0x8130, "iPhone 15 Pro" },
189 { "iPhone16,2", "d84ap", 0x06, 0x8130, "iPhone 15 Pro Max" },
190 /* iPod */
191 { "iPod1,1", "n45ap", 0x02, 0x8900, "iPod Touch (1st gen)" },
192 { "iPod2,1", "n72ap", 0x00, 0x8720, "iPod Touch (2nd gen)" },
193 { "iPod3,1", "n18ap", 0x02, 0x8922, "iPod Touch (3rd gen)" },
194 { "iPod4,1", "n81ap", 0x08, 0x8930, "iPod Touch (4th gen)" },
195 { "iPod5,1", "n78ap", 0x00, 0x8942, "iPod Touch (5th gen)" },
196 { "iPod7,1", "n102ap", 0x10, 0x7000, "iPod Touch (6th gen)" },
197 { "iPod9,1", "n112ap", 0x16, 0x8010, "iPod Touch (7th gen)" },
198 /* iPad */
199 { "iPad1,1", "k48ap", 0x02, 0x8930, "iPad" },
200 { "iPad2,1", "k93ap", 0x04, 0x8940, "iPad 2 (WiFi)" },
201 { "iPad2,2", "k94ap", 0x06, 0x8940, "iPad 2 (GSM)" },
202 { "iPad2,3", "k95ap", 0x02, 0x8940, "iPad 2 (CDMA)" },
203 { "iPad2,4", "k93aap", 0x06, 0x8942, "iPad 2 (WiFi) R2 2012" },
204 { "iPad2,5", "p105ap", 0x0a, 0x8942, "iPad mini (WiFi)" },
205 { "iPad2,6", "p106ap", 0x0c, 0x8942, "iPad mini (GSM)" },
206 { "iPad2,7", "p107ap", 0x0e, 0x8942, "iPad mini (Global)" },
207 { "iPad3,1", "j1ap", 0x00, 0x8945, "iPad (3rd gen, WiFi)" },
208 { "iPad3,2", "j2ap", 0x02, 0x8945, "iPad (3rd gen, CDMA)" },
209 { "iPad3,3", "j2aap", 0x04, 0x8945, "iPad (3rd gen, GSM)" },
210 { "iPad3,4", "p101ap", 0x00, 0x8955, "iPad (4th gen, WiFi)" },
211 { "iPad3,5", "p102ap", 0x02, 0x8955, "iPad (4th gen, GSM)" },
212 { "iPad3,6", "p103ap", 0x04, 0x8955, "iPad (4th gen, Global)" },
213 { "iPad4,1", "j71ap", 0x10, 0x8960, "iPad Air (WiFi)" },
214 { "iPad4,2", "j72ap", 0x12, 0x8960, "iPad Air (Cellular)" },
215 { "iPad4,3", "j73ap", 0x14, 0x8960, "iPad Air (China)" },
216 { "iPad4,4", "j85ap", 0x0a, 0x8960, "iPad mini 2 (WiFi)" },
217 { "iPad4,5", "j86ap", 0x0c, 0x8960, "iPad mini 2 (Cellular)" },
218 { "iPad4,6", "j87ap", 0x0e, 0x8960, "iPad mini 2 (China)" },
219 { "iPad4,7", "j85map", 0x32, 0x8960, "iPad mini 3 (WiFi)" },
220 { "iPad4,8", "j86map", 0x34, 0x8960, "iPad mini 3 (Cellular)" },
221 { "iPad4,9", "j87map", 0x36, 0x8960, "iPad mini 3 (China)" },
222 { "iPad5,1", "j96ap", 0x08, 0x7000, "iPad mini 4 (WiFi)" },
223 { "iPad5,2", "j97ap", 0x0A, 0x7000, "iPad mini 4 (Cellular)" },
224 { "iPad5,3", "j81ap", 0x06, 0x7001, "iPad Air 2 (WiFi)" },
225 { "iPad5,4", "j82ap", 0x02, 0x7001, "iPad Air 2 (Cellular)" },
226 { "iPad6,3", "j127ap", 0x08, 0x8001, "iPad Pro 9.7-inch (WiFi)" },
227 { "iPad6,4", "j128ap", 0x0a, 0x8001, "iPad Pro 9.7-inch (Cellular)" },
228 { "iPad6,7", "j98aap", 0x10, 0x8001, "iPad Pro 12.9-inch (1st gen, WiFi)" },
229 { "iPad6,8", "j99aap", 0x12, 0x8001, "iPad Pro 12.9-inch (1st gen, Cellular)" },
230 { "iPad6,11", "j71sap", 0x10, 0x8000, "iPad (5th gen, WiFi)" },
231 { "iPad6,11", "j71tap", 0x10, 0x8003, "iPad (5th gen, WiFi)" },
232 { "iPad6,12", "j72sap", 0x12, 0x8000, "iPad (5th gen, Cellular)" },
233 { "iPad6,12", "j72tap", 0x12, 0x8003, "iPad (5th gen, Cellular)" },
234 { "iPad7,1", "j120ap", 0x0C, 0x8011, "iPad Pro 12.9-inch (2nd gen, WiFi)" },
235 { "iPad7,2", "j121ap", 0x0E, 0x8011, "iPad Pro 12.9-inch (2nd gen, Cellular)" },
236 { "iPad7,3", "j207ap", 0x04, 0x8011, "iPad Pro 10.5-inch (WiFi)" },
237 { "iPad7,4", "j208ap", 0x06, 0x8011, "iPad Pro 10.5-inch (Cellular)" },
238 { "iPad7,5", "j71bap", 0x18, 0x8010, "iPad (6th gen, WiFi)" },
239 { "iPad7,6", "j72bap", 0x1A, 0x8010, "iPad (6th gen, Cellular)" },
240 { "iPad7,11", "j171ap", 0x1C, 0x8010, "iPad (7th gen, WiFi)" },
241 { "iPad7,12", "j172ap", 0x1E, 0x8010, "iPad (7th gen, Cellular)" },
242 { "iPad8,1", "j317ap", 0x0C, 0x8027, "iPad Pro 11-inch (1st gen, WiFi)" },
243 { "iPad8,2", "j317xap", 0x1C, 0x8027, "iPad Pro 11-inch (1st gen, WiFi, 1TB)" },
244 { "iPad8,3", "j318ap", 0x0E, 0x8027, "iPad Pro 11-inch (1st gen, Cellular)" },
245 { "iPad8,4", "j318xap", 0x1E, 0x8027, "iPad Pro 11-inch (1st gen, Cellular, 1TB)" },
246 { "iPad8,5", "j320ap", 0x08, 0x8027, "iPad Pro 12.9-inch (3rd gen, WiFi)" },
247 { "iPad8,6", "j320xap", 0x18, 0x8027, "iPad Pro 12.9-inch (3rd gen, WiFi, 1TB)" },
248 { "iPad8,7", "j321ap", 0x0A, 0x8027, "iPad Pro 12.9-inch (3rd gen, Cellular)" },
249 { "iPad8,8", "j321xap", 0x1A, 0x8027, "iPad Pro 12.9-inch (3rd gen, Cellular, 1TB)" },
250 { "iPad8,9", "j417ap", 0x3C, 0x8027, "iPad Pro 11-inch (2nd gen, WiFi)" },
251 { "iPad8,10", "j418ap", 0x3E, 0x8027, "iPad Pro 11-inch (2nd gen, Cellular)" },
252 { "iPad8,11", "j420ap", 0x38, 0x8027, "iPad Pro 12.9-inch (4th gen, WiFi)" },
253 { "iPad8,12", "j421ap", 0x3A, 0x8027, "iPad Pro 12.9-inch (4th gen, Cellular)" },
254 { "iPad11,1", "j210ap", 0x14, 0x8020, "iPad mini (5th gen, WiFi)" },
255 { "iPad11,2", "j211ap", 0x16, 0x8020, "iPad mini (5th gen, Cellular)" },
256 { "iPad11,3", "j217ap", 0x1C, 0x8020, "iPad Air (3rd gen, WiFi)" },
257 { "iPad11,4", "j218ap", 0x1E, 0x8020, "iPad Air (3rd gen, Cellular)" },
258 { "iPad11,6", "j171aap", 0x24, 0x8020, "iPad (8th gen, WiFi)" },
259 { "iPad11,7", "j172aap", 0x26, 0x8020, "iPad (8th gen, Cellular)" },
260 { "iPad12,1", "j181ap", 0x18, 0x8030, "iPad (9th gen, WiFi)" },
261 { "iPad12,2", "j182ap", 0x1A, 0x8030, "iPad (9th gen, Cellular)" },
262 { "iPad13,1", "j307ap", 0x04, 0x8101, "iPad Air (4th gen, WiFi)" },
263 { "iPad13,2", "j308ap", 0x06, 0x8101, "iPad Air (4th gen, Cellular)" },
264 { "iPad13,4", "j517ap", 0x08, 0x8103, "iPad Pro 11-inch (3rd gen, WiFi)" },
265 { "iPad13,5", "j517xap", 0x0A, 0x8103, "iPad Pro 11-inch (3rd gen, WiFi, 2TB)" },
266 { "iPad13,6", "j518ap", 0x0C, 0x8103, "iPad Pro 11-inch (3rd gen, Cellular)" },
267 { "iPad13,7", "j518xap", 0x0E, 0x8103, "iPad Pro 11-inch (3rd gen, Cellular, 2TB)" },
268 { "iPad13,8", "j522ap", 0x18, 0x8103, "iPad Pro 12.9-inch (5th gen, WiFi)" },
269 { "iPad13,9", "j522xap", 0x1A, 0x8103, "iPad Pro 12.9-inch (5th gen, WiFi, 2TB)" },
270 { "iPad13,10", "j523ap", 0x1C, 0x8103, "iPad Pro 12.9-inch (5th gen, Cellular)" },
271 { "iPad13,11", "j523xap", 0x1E, 0x8103, "iPad Pro 12.9-inch (5th gen, Cellular, 2TB)" },
272 { "iPad13,16", "j407ap", 0x10, 0x8103, "iPad Air (5th gen, WiFi)" },
273 { "iPad13,17", "j408ap", 0x12, 0x8103, "iPad Air (5th gen, Cellular)" },
274 { "iPad13,18", "j271ap", 0x14, 0x8101, "iPad (10th gen, WiFi)" },
275 { "iPad13,19", "j272ap", 0x16, 0x8101, "iPad (10th gen, Cellular)" },
276 { "iPad14,1", "j310ap", 0x04, 0x8110, "iPad mini (6th gen, WiFi)" },
277 { "iPad14,2", "j311ap", 0x06, 0x8110, "iPad mini (6th gen, Cellular)" },
278 { "iPad14,3", "j617ap", 0x08, 0x8112, "iPad Pro 11-inch (4th gen, WiFi)" },
279 { "iPad14,4", "j618ap", 0x0A, 0x8112, "iPad Pro 11-inch (4th gen, Cellular)" },
280 { "iPad14,5", "j620ap", 0x0C, 0x8112, "iPad Pro 12.9-inch (6th gen, WiFi)" },
281 { "iPad14,6", "j621ap", 0x0E, 0x8112, "iPad Pro 12.9-inch (6th gen, Cellular)" },
282 { "iPad14,8", "j507ap", 0x10, 0x8112, "iPad Air 11-inch (M2, WiFi)" },
283 { "iPad14,9", "j508ap", 0x12, 0x8112, "iPad Air 11-inch (M2, Cellular)" },
284 { "iPad14,10", "j537ap", 0x14, 0x8112, "iPad Air 13-inch (M2, WiFi)" },
285 { "iPad14,11", "j538ap", 0x16, 0x8112, "iPad Air 13-inch (M2, Cellular)" },
286 { "iPad16,3", "j717ap", 0x08, 0x8132, "iPad Pro 11-inch (M4, WiFi)" },
287 { "iPad16,4", "j718ap", 0x0A, 0x8132, "iPad Pro 11-inch (M4, Cellular)" },
288 { "iPad16,5", "j720ap", 0x0C, 0x8132, "iPad Pro 13-inch (M4, WiFi)" },
289 { "iPad16,6", "j721ap", 0x0E, 0x8132, "iPad Pro 13-inch (M4, Cellular)" },
290 /* Apple TV */
291 { "AppleTV2,1", "k66ap", 0x10, 0x8930, "Apple TV 2" },
292 { "AppleTV3,1", "j33ap", 0x08, 0x8942, "Apple TV 3" },
293 { "AppleTV3,2", "j33iap", 0x00, 0x8947, "Apple TV 3 (2013)" },
294 { "AppleTV5,3", "j42dap", 0x34, 0x7000, "Apple TV 4" },
295 { "AppleTV6,2", "j105aap", 0x02, 0x8011, "Apple TV 4K" },
296 { "AppleTV11,1", "j305ap", 0x08, 0x8020, "Apple TV 4K (2nd gen)" },
297 { "AppleTV14,1", "j255ap", 0x02, 0x8110, "Apple TV 4K (3rd gen)" },
298 /* HomePod */
299 { "AudioAccessory1,1", "b238aap", 0x38, 0x7000, "HomePod (1st gen)" },
300 { "AudioAccessory1,2", "b238ap", 0x1A, 0x7000, "HomePod (1st gen)" },
301 { "AudioAccessory5,1", "b520ap", 0x22, 0x8006, "HomePod mini" },
302 { "AudioAccessory6,1", "b620ap", 0x18, 0x8301, "HomePod (2nd gen)" },
303 /* Apple Watch */
304 { "Watch1,1", "n27aap", 0x02, 0x7002, "Apple Watch 38mm (1st gen)" },
305 { "Watch1,2", "n28aap", 0x04, 0x7002, "Apple Watch 42mm (1st gen)" },
306 { "Watch2,6", "n27dap", 0x02, 0x8002, "Apple Watch Series 1 (38mm)" },
307 { "Watch2,7", "n28dap", 0x04, 0x8002, "Apple Watch Series 1 (42mm)" },
308 { "Watch2,3", "n74ap", 0x0C, 0x8002, "Apple Watch Series 2 (38mm)" },
309 { "Watch2,4", "n75ap", 0x0E, 0x8002, "Apple Watch Series 2 (42mm)" },
310 { "Watch3,1", "n111sap", 0x1C, 0x8004, "Apple Watch Series 3 (38mm Cellular)" },
311 { "Watch3,2", "n111bap", 0x1E, 0x8004, "Apple Watch Series 3 (42mm Cellular)" },
312 { "Watch3,3", "n121sap", 0x18, 0x8004, "Apple Watch Series 3 (38mm)" },
313 { "Watch3,4", "n121bap", 0x1A, 0x8004, "Apple Watch Series 3 (42mm)" },
314 { "Watch4,1", "n131sap", 0x08, 0x8006, "Apple Watch Series 4 (40mm)" },
315 { "Watch4,2", "n131bap", 0x0A, 0x8006, "Apple Watch Series 4 (44mm)" },
316 { "Watch4,3", "n141sap", 0x0C, 0x8006, "Apple Watch Series 4 (40mm Cellular)" },
317 { "Watch4,4", "n141bap", 0x0E, 0x8006, "Apple Watch Series 4 (44mm Cellular)" },
318 { "Watch5,1", "n144sap", 0x10, 0x8006, "Apple Watch Series 5 (40mm)" },
319 { "Watch5,2", "n144bap", 0x12, 0x8006, "Apple Watch Series 5 (44mm)" },
320 { "Watch5,3", "n146sap", 0x14, 0x8006, "Apple Watch Series 5 (40mm Cellular)" },
321 { "Watch5,4", "n146bap", 0x16, 0x8006, "Apple Watch Series 5 (44mm Cellular)" },
322 { "Watch5,9", "n140sap", 0x28, 0x8006, "Apple Watch SE (40mm)" },
323 { "Watch5,10", "n140bap", 0x2A, 0x8006, "Apple Watch SE (44mm)" },
324 { "Watch5,11", "n142sap", 0x2C, 0x8006, "Apple Watch SE (40mm Cellular)" },
325 { "Watch5,12", "n142bap", 0x2E, 0x8006, "Apple Watch SE (44mm Cellular)" },
326 { "Watch6,1", "n157sap", 0x08, 0x8301, "Apple Watch Series 6 (40mm)" },
327 { "Watch6,2", "n157bap", 0x0A, 0x8301, "Apple Watch Series 6 (44mm)" },
328 { "Watch6,3", "n158sap", 0x0C, 0x8301, "Apple Watch Series 6 (40mm Cellular)" },
329 { "Watch6,4", "n158bap", 0x0E, 0x8301, "Apple Watch Series 6 (44mm Cellular)" },
330 { "Watch6,6", "n187sap", 0x10, 0x8301, "Apple Watch Series 7 (41mm)" },
331 { "Watch6,7", "n187bap", 0x12, 0x8301, "Apple Watch Series 7 (45mm)" },
332 { "Watch6,8", "n188sap", 0x14, 0x8301, "Apple Watch Series 7 (41mm Cellular)" },
333 { "Watch6,9", "n188bap", 0x16, 0x8301, "Apple Watch Series 7 (45mm Cellular)" },
334 { "Watch6,10", "n143sap", 0x28, 0x8301, "Apple Watch SE 2 (40mm)" },
335 { "Watch6,11", "n143bap", 0x2A, 0x8301, "Apple Watch SE 2 (44mm)" },
336 { "Watch6,12", "n149sap", 0x2C, 0x8301, "Apple Watch SE 2 (40mm Cellular)" },
337 { "Watch6,13", "n149bap", 0x2E, 0x8301, "Apple Watch SE 2 (44mm Cellular)" },
338 { "Watch6,14", "n197sap", 0x30, 0x8301, "Apple Watch Series 8 (41mm)" },
339 { "Watch6,15", "n197bap", 0x32, 0x8301, "Apple Watch Series 8 (45mm)" },
340 { "Watch6,16", "n198sap", 0x34, 0x8301, "Apple Watch Series 8 (41mm Cellular)" },
341 { "Watch6,17", "n198bap", 0x36, 0x8301, "Apple Watch Series 8 (45mm Cellular)" },
342 { "Watch6,18", "n199ap", 0x26, 0x8301, "Apple Watch Ultra" },
343 { "Watch7,1", "n207sap", 0x08, 0x8310, "Apple Watch Series 9 (41mm)" },
344 { "Watch7,2", "n207bap", 0x0A, 0x8310, "Apple Watch Series 9 (45mm)" },
345 { "Watch7,3", "n208sap", 0x0C, 0x8310, "Apple Watch Series 9 (41mm Cellular)" },
346 { "Watch7,4", "n208bap", 0x0E, 0x8310, "Apple Watch Series 9 (45mm Cellular)" },
347 { "Watch7,5", "n210ap", 0x02, 0x8310, "Apple Watch Ultra 2" },
348 /* Apple Silicon Macs */
349 { "ADP3,2", "j273aap", 0x42, 0x8027, "Developer Transition Kit (2020)" },
350 { "Macmini9,1", "j274ap", 0x22, 0x8103, "Mac mini (M1, 2020)" },
351 { "MacBookPro17,1", "j293ap", 0x24, 0x8103, "MacBook Pro (M1, 13-inch, 2020)" },
352 { "MacBookPro18,1", "j316sap", 0x0A, 0x6000, "MacBook Pro (M1 Pro, 16-inch, 2021)" },
353 { "MacBookPro18,2", "j316cap", 0x0A, 0x6001, "MacBook Pro (M1 Max, 16-inch, 2021)" },
354 { "MacBookPro18,3", "j314sap", 0x08, 0x6000, "MacBook Pro (M1 Pro, 14-inch, 2021)" },
355 { "MacBookPro18,4", "j314cap", 0x08, 0x6001, "MacBook Pro (M1 Max, 14-inch, 2021)" },
356 { "MacBookAir10,1", "j313ap", 0x26, 0x8103, "MacBook Air (M1, 2020)" },
357 { "iMac21,1", "j456ap", 0x28, 0x8103, "iMac 24-inch (M1, Two Ports, 2021)" },
358 { "iMac21,2", "j457ap", 0x2A, 0x8103, "iMac 24-inch (M1, Four Ports, 2021)" },
359 { "Mac13,1", "j375cap", 0x04, 0x6001, "Mac Studio (M1 Max, 2022)" },
360 { "Mac13,2", "j375dap", 0x0C, 0x6002, "Mac Studio (M1 Ultra, 2022)" },
361 { "Mac14,2", "j413ap", 0x28, 0x8112, "MacBook Air (M2, 2022)" },
362 { "Mac14,7", "j493ap", 0x2A, 0x8112, "MacBook Pro (M2, 13-inch, 2022)" },
363 { "Mac14,3", "j473ap", 0x24, 0x8112, "Mac mini (M2, 2023)" },
364 { "Mac14,5", "j414cap", 0x04, 0x6021, "MacBook Pro (14-inch, M2 Max, 2023)" },
365 { "Mac14,6", "j416cap", 0x06, 0x6021, "MacBook Pro (16-inch, M2 Max, 2023)" },
366 { "Mac14,8", "j180dap", 0x08, 0x6022, "Mac Pro (2023)" },
367 { "Mac14,9", "j414sap", 0x04, 0x6020, "MacBook Pro (14-inch, M2 Pro, 2023)" },
368 { "Mac14,10", "j416sap", 0x06, 0x6020, "MacBook Pro (16-inch, M2 Pro, 2023)" },
369 { "Mac14,12", "j474sap", 0x02, 0x6020, "Mac mini (M2 Pro, 2023)" },
370 { "Mac14,13", "j475cap", 0x0A, 0x6021, "Mac Studio (M2 Max, 2023)" },
371 { "Mac14,14", "j475dap", 0x0A, 0x6022, "Mac Studio (M2 Ultra, 2023)" },
372 { "Mac14,15", "j415ap", 0x2E, 0x8112, "MacBook Air (M2, 15-inch, 2023)" },
373 { "Mac15,3", "j504ap", 0x22, 0x8122, "MacBook Pro (14-inch, M3, Nov 2023)" },
374 { "Mac15,4", "j433ap", 0x28, 0x8122, "iMac 24-inch (M3, Two Ports, 2023)" },
375 { "Mac15,5", "j434ap", 0x2A, 0x8122, "iMac 24-inch (M3, Four Ports, 2023)" },
376 { "Mac15,6", "j514sap", 0x04, 0x6030, "MacBook Pro (14-inch, M3 Pro, Nov 2023)" },
377 { "Mac15,7", "j516sap", 0x06, 0x6030, "MacBook Pro (16-inch, M3 Pro, Nov 2023)" },
378 { "Mac15,8", "j514cap", 0x44, 0x6031, "MacBook Pro (14-inch, M3 Max, Nov 2023)" },
379 { "Mac15,9", "j516cap", 0x46, 0x6031, "MacBook Pro (16-inch, M3 Max, Nov 2023)" },
380 { "Mac15,10", "j514map", 0x44, 0x6034, "MacBook Pro (14-inch, M3 Max, Nov 2023)" },
381 { "Mac15,11", "j516map", 0x46, 0x6034, "MacBook Pro (16-inch, M3 Max, Nov 2023)" },
382 { "Mac15,12", "j613ap", 0x30, 0x8122, "MacBook Air (13-inch, M3, 2024)" },
383 { "Mac15,13", "j615ap", 0x32, 0x8122, "MacBook Air (15-inch, M3, 2024)" },
384 /* Apple Silicon VMs (supported by Virtualization.framework on macOS 12) */
385 { "VirtualMac2,1", "vma2macosap", 0x20, 0xFE00, "Apple Virtual Machine 1" },
386 /* Apple T2 Coprocessor */
387 { "iBridge2,1", "j137ap", 0x0A, 0x8012, "Apple T2 iMacPro1,1 (j137)" },
388 { "iBridge2,3", "j680ap", 0x0B, 0x8012, "Apple T2 MacBookPro15,1 (j680)" },
389 { "iBridge2,4", "j132ap", 0x0C, 0x8012, "Apple T2 MacBookPro15,2 (j132)" },
390 { "iBridge2,5", "j174ap", 0x0E, 0x8012, "Apple T2 Macmini8,1 (j174)" },
391 { "iBridge2,6", "j160ap", 0x0F, 0x8012, "Apple T2 MacPro7,1 (j160)" },
392 { "iBridge2,7", "j780ap", 0x07, 0x8012, "Apple T2 MacBookPro15,3 (j780)" },
393 { "iBridge2,8", "j140kap", 0x17, 0x8012, "Apple T2 MacBookAir8,1 (j140k)" },
394 { "iBridge2,10", "j213ap", 0x18, 0x8012, "Apple T2 MacBookPro15,4 (j213)" },
395 { "iBridge2,12", "j140aap", 0x37, 0x8012, "Apple T2 MacBookAir8,2 (j140a)" },
396 { "iBridge2,14", "j152fap", 0x3A, 0x8012, "Apple T2 MacBookPro16,1 (j152f)" },
397 { "iBridge2,15", "j230kap", 0x3F, 0x8012, "Apple T2 MacBookAir9,1 (j230k)" },
398 { "iBridge2,16", "j214kap", 0x3E, 0x8012, "Apple T2 MacBookPro16,2 (j214k)" },
399 { "iBridge2,19", "j185ap", 0x22, 0x8012, "Apple T2 iMac20,1 (j185)" },
400 { "iBridge2,20", "j185fap", 0x23, 0x8012, "Apple T2 iMac20,2 (j185f)" },
401 { "iBridge2,21", "j223ap", 0x3B, 0x8012, "Apple T2 MacBookPro16,3 (j223)" },
402 { "iBridge2,22", "j215ap", 0x38, 0x8012, "Apple T2 MacBookPro16,4 (j215)" },
403 /* Apple Displays */
404 { "AppleDisplay2,1", "j327ap", 0x22, 0x8030, "Studio Display" },
405 /* Apple Vision Pro */
406 { "RealityDevice14,1", "n301ap", 0x42, 0x8112, "Apple Vision Pro" },
407 { NULL, NULL, -1, -1, NULL }
408};
409
410#ifndef USE_DUMMY
411static unsigned int crc32_lookup_t1[256] = {
412 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
413 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
414 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
415 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
416 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
417 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
418 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
419 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
420 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
421 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
422 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
423 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
424 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
425 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
426 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
427 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
428 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
429 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
430 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
431 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
432 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
433 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
434 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
435 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
436 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
437 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
438 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
439 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
440 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
441 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
442 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
443 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
444 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
445 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
446 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
447 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
448 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
449 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
450 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
451 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
452 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
453 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
454 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
455 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
456 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
457 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
458 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
459 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
460 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
461 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
462 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
463 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
464 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
465 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
466 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
467 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
468 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
469 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
470 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
471 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
472 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
473 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
474 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
475 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
476};
477
478#define crc32_step(a,b) \
479 a = (crc32_lookup_t1[(a & 0xFF) ^ ((unsigned char)b)] ^ (a >> 8))
480
481#ifdef WIN32
482#pragma pack(1)
483typedef struct {
484 uint16_t vid;
485 uint16_t pid;
486 uint32_t unk;
487 char nonces[255];
488 char serial[255];
489 char manufacturer[255];
490 char product[255];
491} KIS_device_info;
492
493typedef struct {
494 uint8_t data[0x4000];
495 uint32_t size;
496 uint32_t unused;
497 uint64_t address;
498} KIS_upload_chunk;
499#pragma pack()
500#else
501#pragma pack(1)
502typedef struct {
503 uint16_t sequence; // A sequence number
504 uint8_t version; // Protocol version
505 uint8_t portal; // The "portal" to connect to
506 uint8_t argCount; // Number of arguments
507 uint8_t indexLo; // An index
508 uint8_t indexHiRplSizeLo; // High 2 bits of index + low 6 bytes of reply size
509 uint8_t rplSizeHi; // Reply size high bits, number of words the device should send
510 uint32_t reqSize; // Size of the complete request, including the arguments and payload, excluding the header
511 // Followed by arguments and payload data
512} KIS_req_header;
513
514typedef struct {
515 KIS_req_header hdr;
516 uint32_t value;
517} KIS_config_wr32;
518
519typedef struct {
520 uint8_t bLength ; ///< Size of this descriptor in bytes.
521 uint8_t bDescriptorType ; ///< DEVICE Descriptor Type.
522 uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). This field identifies the release of the USB Specification with which the device and its descriptors are compliant.
523
524 uint8_t bDeviceClass ; ///< Class code (assigned by the USB-IF). \li If this field is reset to zero, each interface within a configuration specifies its own class information and the various interfaces operate independently. \li If this field is set to a value between 1 and FEH, the device supports different class specifications on different interfaces and the interfaces may not operate independently. This value identifies the class definition used for the aggregate interfaces. \li If this field is set to FFH, the device class is vendor-specific.
525 uint8_t bDeviceSubClass ; ///< Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass field. \li If the bDeviceClass field is reset to zero, this field must also be reset to zero. \li If the bDeviceClass field is not set to FFH, all values are reserved for assignment by the USB-IF.
526 uint8_t bDeviceProtocol ; ///< Protocol code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass and the bDeviceSubClass fields. If a device supports class-specific protocols on a device basis as opposed to an interface basis, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use class-specific protocols on a device basis. However, it may use classspecific protocols on an interface basis. \li If this field is set to FFH, the device uses a vendor-specific protocol on a device basis.
527 uint8_t bMaxPacketSize0 ; ///< Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid). For HS devices is fixed to 64.
528
529 uint16_t idVendor ; ///< Vendor ID (assigned by the USB-IF).
530 uint16_t idProduct ; ///< Product ID (assigned by the manufacturer).
531 uint16_t bcdDevice ; ///< Device release number in binary-coded decimal.
532 uint8_t iManufacturer ; ///< Index of string descriptor describing manufacturer.
533 uint8_t iProduct ; ///< Index of string descriptor describing product.
534 uint8_t iSerialNumber ; ///< Index of string descriptor describing the device's serial number.
535
536 uint8_t bNumConfigurations ; ///< Number of possible configurations.
537} usb_device_descriptor;
538
539typedef struct {
540 KIS_req_header hdr;
541 union {
542 struct {
543 uint32_t tag;
544 uint32_t unk1;
545 uint32_t maxUploadSize;
546 uint32_t maxDownloadSize; // maybe???
547 uint64_t rambase;
548 uint32_t nonceOffset;
549 uint32_t pad;
550 uint8_t unkpad[0x20];
551 usb_device_descriptor deviceDescriptor;
552 };
553 uint8_t deviceInfo[0x300];
554 };
555 uint32_t rspsize;
556 uint32_t statuscode;
557} KIS_device_info;
558
559typedef struct {
560 KIS_req_header hdr;
561 uint64_t address;
562 uint32_t size;
563 uint8_t data[0x4000];
564} KIS_upload_chunk;
565
566typedef struct {
567 KIS_req_header hdr;
568 uint32_t size; // Number of bytes read/written
569 uint32_t status;
570} KIS_generic_reply;
571#pragma pack()
572#endif
573
574static THREAD_T th_event_handler = THREAD_T_NULL;
575struct collection listeners;
576static mutex_t listener_mutex;
577struct collection devices;
578static mutex_t device_mutex;
579#ifndef WIN32
580#ifdef HAVE_IOKIT
581static CFRunLoopRef iokit_runloop = NULL;
582#else
583static libusb_context* irecv_hotplug_ctx = NULL;
584#endif
585#endif
586
587static void _irecv_init(void)
588{
589 char* dbglvl = getenv("LIBIRECOVERY_DEBUG_LEVEL");
590 if (dbglvl) {
591 libirecovery_debug = strtol(dbglvl, NULL, 0);
592 irecv_set_debug_level(libirecovery_debug);
593 }
594#ifndef USE_DUMMY
595#ifndef WIN32
596#ifndef HAVE_IOKIT
597 libusb_init(&libirecovery_context);
598#endif
599#endif
600 collection_init(&listeners);
601 mutex_init(&listener_mutex);
602#endif
603}
604
605static void _irecv_deinit(void)
606{
607#ifndef USE_DUMMY
608#ifndef WIN32
609#ifndef HAVE_IOKIT
610 if (libirecovery_context != NULL) {
611 libusb_exit(libirecovery_context);
612 libirecovery_context = NULL;
613 }
614#endif
615#endif
616 collection_free(&listeners);
617 mutex_destroy(&listener_mutex);
618#endif
619}
620
621static thread_once_t init_once = THREAD_ONCE_INIT;
622static thread_once_t deinit_once = THREAD_ONCE_INIT;
623
624#ifndef HAVE_ATTRIBUTE_CONSTRUCTOR
625 #if defined(__llvm__) || defined(__GNUC__)
626 #define HAVE_ATTRIBUTE_CONSTRUCTOR
627 #endif
628#endif
629
630#ifdef HAVE_ATTRIBUTE_CONSTRUCTOR
631static void __attribute__((constructor)) libirecovery_initialize(void)
632{
633 thread_once(&init_once, _irecv_init);
634}
635
636static void __attribute__((destructor)) libirecovery_deinitialize(void)
637{
638 thread_once(&deinit_once, _irecv_deinit);
639}
640#elif defined(WIN32)
641BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
642{
643 switch (dwReason) {
644 case DLL_PROCESS_ATTACH:
645 thread_once(&init_once, _irecv_init);
646 break;
647 case DLL_PROCESS_DETACH:
648 thread_once(&deinit_once, _irecv_deinit);
649 break;
650 default:
651 break;
652 }
653 return 1;
654}
655#else
656#warning No compiler support for constructor/destructor attributes, some features might not be available.
657#endif
658
659#ifdef HAVE_IOKIT
660static int iokit_get_string_descriptor_ascii(irecv_client_t client, uint8_t desc_index, unsigned char * buffer, int size)
661{
662 IOReturn result;
663 IOUSBDevRequest request;
664 unsigned char descriptor[256];
665
666 request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
667 request.bRequest = kUSBRqGetDescriptor;
668 request.wValue = (kUSBStringDesc << 8); // | desc_index;
669 request.wIndex = 0; // All languages 0x409; // language
670 request.wLength = sizeof(descriptor) - 1;
671 request.pData = descriptor;
672 request.wLenDone = 0;
673
674 result = (*client->handle)->DeviceRequest(client->handle, &request);
675 if (result == kIOReturnNoDevice)
676 return IRECV_E_NO_DEVICE;
677 if (result == kIOReturnNotOpen)
678 return IRECV_E_USB_STATUS;
679 if (result != kIOReturnSuccess)
680 return IRECV_E_UNKNOWN_ERROR;
681
682 if (descriptor[0] >= 4) { // && descriptor[2] == 0x9 && descriptor[3] == 0x4) {
683
684 request.wValue = (kUSBStringDesc << 8) | desc_index;
685 request.wIndex = descriptor[2] + (descriptor[3] << 8);
686 request.wLenDone = 0;
687 result = (*client->handle)->DeviceRequest(client->handle, &request);
688
689 if (result == kIOReturnNoDevice)
690 return IRECV_E_NO_DEVICE;
691 if (result == kIOReturnNotOpen)
692 return IRECV_E_USB_STATUS;
693 if (result != kIOReturnSuccess)
694 return IRECV_E_UNKNOWN_ERROR;
695
696 int i = 2, j = 0;
697 for ( ; i < descriptor[0]; i += 2, j += 1) {
698 buffer[j] = descriptor[i];
699 }
700 buffer[j] = 0;
701
702 return request.wLenDone;
703 }
704 return IRECV_E_UNKNOWN_ERROR;
705}
706#endif
707
708static int irecv_get_string_descriptor_ascii(irecv_client_t client, uint8_t desc_index, unsigned char * buffer, int size)
709{
710#ifndef WIN32
711#ifdef HAVE_IOKIT
712 return iokit_get_string_descriptor_ascii(client, desc_index, buffer, size);
713#else
714 return libusb_get_string_descriptor_ascii(client->handle, desc_index, buffer, size);
715#endif
716#else
717 irecv_error_t ret;
718 unsigned short langid = 0;
719 unsigned char data[256];
720 int di, si;
721 memset(data, 0, 256);
722 memset(buffer, 0, size);
723
724 ret = irecv_usb_control_transfer(client, 0x80, 0x06, (0x03 << 8) | desc_index, langid, data, 255, USB_TIMEOUT);
725
726 if (ret < 0) return ret;
727 if (data[1] != 0x03) return IRECV_E_UNKNOWN_ERROR;
728 if (data[0] > ret) return IRECV_E_UNKNOWN_ERROR;
729
730 for (di = 0, si = 2; si < data[0]; si += 2) {
731 if (di >= (size - 1)) break;
732 if (data[si + 1]) {
733 /* high byte */
734 buffer[di++] = '?';
735 } else {
736 buffer[di++] = data[si];
737 }
738 }
739 buffer[di] = 0;
740
741 return di;
742#endif
743}
744
745static void irecv_load_device_info_from_iboot_string(irecv_client_t client, const char* iboot_string)
746{
747 if (!client || !iboot_string) {
748 return;
749 }
750
751 memset(&client->device_info, '\0', sizeof(struct irecv_device_info));
752
753 client->device_info.serial_string = strdup(iboot_string);
754
755 char* ptr;
756
757 ptr = strstr(iboot_string, "CPID:");
758 if (ptr != NULL) {
759 sscanf(ptr, "CPID:%x", &client->device_info.cpid);
760 }
761
762 ptr = strstr(iboot_string, "CPRV:");
763 if (ptr != NULL) {
764 sscanf(ptr, "CPRV:%x", &client->device_info.cprv);
765 }
766
767 ptr = strstr(iboot_string, "CPFM:");
768 if (ptr != NULL) {
769 sscanf(ptr, "CPFM:%x", &client->device_info.cpfm);
770 }
771
772 ptr = strstr(iboot_string, "SCEP:");
773 if (ptr != NULL) {
774 sscanf(ptr, "SCEP:%x", &client->device_info.scep);
775 }
32 776
33int irecv_write_file(const char* filename, const void* data, size_t size); 777 ptr = strstr(iboot_string, "BDID:");
34int irecv_read_file(const char* filename, char** data, uint32_t* size); 778 if (ptr != NULL) {
779 uint64_t bdid = 0;
780 sscanf(ptr, "BDID:%" SCNx64, &bdid);
781 client->device_info.bdid = (unsigned int)bdid;
782 }
783
784 ptr = strstr(iboot_string, "ECID:");
785 if (ptr != NULL) {
786 sscanf(ptr, "ECID:%" SCNx64, &client->device_info.ecid);
787 }
788
789 ptr = strstr(iboot_string, "IBFL:");
790 if (ptr != NULL) {
791 sscanf(ptr, "IBFL:%x", &client->device_info.ibfl);
792 }
793
794 char tmp[256];
795 tmp[0] = '\0';
796 ptr = strstr(iboot_string, "SRNM:[");
797 if (ptr != NULL) {
798 sscanf(ptr, "SRNM:[%s]", tmp);
799 ptr = strrchr(tmp, ']');
800 if (ptr != NULL) {
801 *ptr = '\0';
802 }
803 client->device_info.srnm = strdup(tmp);
804 }
805
806 tmp[0] = '\0';
807 ptr = strstr(iboot_string, "IMEI:[");
808 if (ptr != NULL) {
809 sscanf(ptr, "IMEI:[%s]", tmp);
810 ptr = strrchr(tmp, ']');
811 if (ptr != NULL) {
812 *ptr = '\0';
813 }
814 client->device_info.imei = strdup(tmp);
815 }
816
817 tmp[0] = '\0';
818 ptr = strstr(iboot_string, "SRTG:[");
819 if (ptr != NULL) {
820 sscanf(ptr, "SRTG:[%s]", tmp);
821 ptr = strrchr(tmp, ']');
822 if (ptr != NULL) {
823 *ptr = '\0';
824 }
825 client->device_info.srtg = strdup(tmp);
826 }
827
828 client->device_info.pid = client->mode;
829 if (client->isKIS) {
830 client->device_info.pid = KIS_PRODUCT_ID;
831 }
832}
833
834static void irecv_copy_nonce_with_tag_from_buffer(const char* tag, unsigned char** nonce, unsigned int* nonce_size, const char *buf)
835{
836 int taglen = strlen(tag);
837 int nlen = 0;
838 const char* nonce_string = NULL;
839 const char* p = buf;
840 char* colon = NULL;
841 do {
842 colon = strchr(p, ':');
843 if (!colon)
844 break;
845 if (colon-taglen < p) {
846 break;
847 }
848 char *space = strchr(colon, ' ');
849 if (strncmp(colon-taglen, tag, taglen) == 0) {
850 p = colon+1;
851 if (!space) {
852 nlen = strlen(p);
853 } else {
854 nlen = space-p;
855 }
856 nonce_string = p;
857 nlen/=2;
858 break;
859 } else {
860 if (!space) {
861 break;
862 } else {
863 p = space+1;
864 }
865 }
866 } while (colon);
867
868 if (nlen == 0) {
869 debug("%s: WARNING: couldn't find tag %s in string %s\n", __func__, tag, buf);
870 return;
871 }
872
873 unsigned char *nn = malloc(nlen);
874 if (!nn) {
875 return;
876 }
35 877
36irecv_error_t irecv_open(irecv_client_t* pclient) {
37 int i = 0; 878 int i = 0;
38 char serial[256]; 879 for (i = 0; i < nlen; i++) {
880 int val = 0;
881 if (sscanf(nonce_string+(i*2), "%02X", &val) == 1) {
882 nn[i] = (unsigned char)val;
883 } else {
884 debug("%s: ERROR: unexpected data in nonce result (%2s)\n", __func__, nonce_string+(i*2));
885 break;
886 }
887 }
888
889 if (i != nlen) {
890 debug("%s: ERROR: unable to parse nonce\n", __func__);
891 free(nn);
892 return;
893 }
894
895 *nonce = nn;
896 *nonce_size = nlen;
897}
898
899static void irecv_copy_nonce_with_tag(irecv_client_t client, const char* tag, unsigned char** nonce, unsigned int* nonce_size)
900{
901 if (!client || !tag) {
902 return;
903 }
904
905 char buf[256];
906 int len = 0;
907
908 *nonce = NULL;
909 *nonce_size = 0;
910
911 memset(buf, 0, 256);
912 len = irecv_get_string_descriptor_ascii(client, 1, (unsigned char*) buf, 255);
913 if (len < 0) {
914 debug("%s: got length: %d\n", __func__, len);
915 return;
916 }
917
918 buf[len] = 0;
919
920 irecv_copy_nonce_with_tag_from_buffer(tag,nonce,nonce_size,buf);
921}
922
923#ifndef WIN32
924static irecv_error_t irecv_kis_request_init(KIS_req_header *hdr, uint8_t portal, uint16_t index, size_t argCount, size_t payloadSize, size_t rplWords)
925{
926 if (argCount > UINT8_MAX) {
927 return IRECV_E_INVALID_INPUT;
928 }
929
930 if (index >= (1 << 10)) {
931 return IRECV_E_INVALID_INPUT;
932 }
933
934 if (rplWords >= (1 << 14)) {
935 return IRECV_E_INVALID_INPUT;
936 }
937
938 size_t reqSize = payloadSize + (argCount << 2);
939 if (reqSize > UINT32_MAX) {
940 return IRECV_E_INVALID_INPUT;
941 }
942
943 hdr->sequence = 0; // Doesn't matter
944 hdr->version = 0xA0;
945 hdr->portal = portal;
946 hdr->argCount = (uint8_t) argCount;
947 hdr->indexLo = (uint8_t) (index & 0xFF);
948 hdr->indexHiRplSizeLo = (uint8_t) (((index >> 8) & 0x3) | ((rplWords << 2) & 0xFC));
949 hdr->rplSizeHi = (uint8_t) ((rplWords >> 6) & 0xFF);
950 hdr->reqSize = (uint32_t) reqSize;
951
952 return IRECV_E_SUCCESS;
953}
954
955static irecv_error_t irecv_kis_request(irecv_client_t client, KIS_req_header *req, size_t reqSize, KIS_req_header *rpl, size_t *rplSize)
956{
957 int endpoint = 0;
958 switch (req->portal) {
959 case KIS_PORTAL_CONFIG:
960 endpoint = 1;
961 break;
962 case KIS_PORTAL_RSM:
963 endpoint = 3;
964 break;
965 default:
966 debug("Don't know which endpoint to use for portal %d\n", req->portal);
967 return IRECV_E_INVALID_INPUT;
968 }
969
970 int sent = 0;
971 irecv_error_t err = irecv_usb_bulk_transfer(client, endpoint, (unsigned char *) req, reqSize, &sent, USB_TIMEOUT);
972 if (err != IRECV_E_SUCCESS) {
973 debug("[send] irecv_usb_bulk_transfer failed, error %d\n", err);
974 return err;
975 }
976
977 if ((size_t) sent != reqSize) {
978 debug("sent != reqSize\n");
979 return IRECV_E_USB_UPLOAD;
980 }
981
982 int rcvd = 0;
983 err = irecv_usb_bulk_transfer(client, endpoint | 0x80, (unsigned char *) rpl, *rplSize, &rcvd, USB_TIMEOUT);
984 if (err != IRECV_E_SUCCESS) {
985 debug("[rcv] irecv_usb_bulk_transfer failed, error %d\n", err);
986 return err;
987 }
988
989 *rplSize = rcvd;
990
991 return IRECV_E_SUCCESS;
992}
993
994static irecv_error_t irecv_kis_config_write32(irecv_client_t client, uint8_t portal, uint16_t index, uint32_t value)
995{
996 KIS_config_wr32 req = {};
997 KIS_generic_reply rpl = {};
998 irecv_error_t err = irecv_kis_request_init(&req.hdr, portal, index, 1, 0, 1);
999 if (err != IRECV_E_SUCCESS) {
1000 debug("Failed to init KIS request, error %d\n", err);
1001 return err;
1002 }
1003
1004 req.value = value;
1005
1006 size_t rplSize = sizeof(rpl);
1007 err = irecv_kis_request(client, &req.hdr, sizeof(req), &rpl.hdr, &rplSize);
1008 if (err != IRECV_E_SUCCESS) {
1009 debug("Failed to send KIS request, error %d\n", err);
1010 return err;
1011 }
1012
1013 if (rpl.size != 4) {
1014 debug("Failed to write config, %d bytes written, status %d\n", rpl.size, rpl.status);
1015 return err;
1016 }
1017
1018 return IRECV_E_SUCCESS;
1019}
1020
1021static int irecv_kis_read_string(KIS_device_info *di, size_t off, char *buf, size_t buf_size)
1022{
1023 off *= 4;
1024
1025 size_t inputSize = sizeof(KIS_device_info) - sizeof(KIS_req_header);
1026
1027 if ((off + 2) > inputSize)
1028 return 0;
1029
1030 uint8_t len = di->deviceInfo[off];
1031 uint8_t type = di->deviceInfo[off + 1];
1032
1033 if (len & 1)
1034 return 0;
1035
1036 if (len/2 >= buf_size)
1037 return 0;
1038
1039 if ((off + 2 + len) > inputSize)
1040 return 0;
1041
1042 if (type != 3)
1043 return 0;
1044
1045 buf[len >> 1] = 0;
1046 for (size_t i = 0; i < len; i += 2) {
1047 buf[i >> 1] = di->deviceInfo[i + off + 2];
1048 }
1049
1050 return len/2;
1051}
1052#endif
1053
1054static irecv_error_t irecv_kis_init(irecv_client_t client)
1055{
1056#ifndef WIN32
1057 irecv_error_t err = irecv_kis_config_write32(client, KIS_PORTAL_CONFIG, KIS_INDEX_ENABLE_A, KIS_ENABLE_A_VAL);
1058 if (err != IRECV_E_SUCCESS) {
1059 debug("Failed to write to KIS_INDEX_ENABLE_A, error %d\n", err);
1060 return err;
1061 }
1062
1063 err = irecv_kis_config_write32(client, KIS_PORTAL_CONFIG, KIS_INDEX_ENABLE_B, KIS_ENABLE_B_VAL);
1064 if (err != IRECV_E_SUCCESS) {
1065 debug("Failed to write to KIS_INDEX_ENABLE_B, error %d\n", err);
1066 return err;
1067 }
1068#endif
1069 client->isKIS = 1;
1070
1071 return IRECV_E_SUCCESS;
1072}
1073
1074static irecv_error_t irecv_kis_load_device_info(irecv_client_t client)
1075{
1076 debug("Loading device info in KIS mode...\n");
1077#ifdef WIN32
1078 KIS_device_info kisInfo;
1079 DWORD transferred = 0;
1080 int ret = DeviceIoControl(client->handle, 0x220004, NULL, 0, &kisInfo, sizeof(kisInfo), (PDWORD)&transferred, NULL);
1081 if (ret) {
1082 debug("Serial: %s\n", kisInfo.serial);
1083 irecv_load_device_info_from_iboot_string(client, kisInfo.serial);
1084 debug("Manufacturer: %s\n", kisInfo.manufacturer);
1085 debug("Product: %s\n", kisInfo.product);
1086 debug("Nonces: %s\n", kisInfo.nonces);
1087 irecv_copy_nonce_with_tag_from_buffer("NONC", &client->device_info.ap_nonce, &client->device_info.ap_nonce_size, kisInfo.nonces);
1088 irecv_copy_nonce_with_tag_from_buffer("SNON", &client->device_info.sep_nonce, &client->device_info.sep_nonce_size, kisInfo.nonces);
1089 debug("VID: 0x%04x\n", kisInfo.vid);
1090 debug("PID: 0x%04x\n", kisInfo.pid);
1091 }
1092 client->mode = kisInfo.pid;
1093#else
1094 KIS_req_header req = {};
1095 KIS_device_info di = {};
1096 irecv_error_t err = irecv_kis_request_init(&req, KIS_PORTAL_RSM, KIS_INDEX_GET_INFO, 0, 0, sizeof(di.deviceInfo)/4);
1097 if (err != IRECV_E_SUCCESS) {
1098 debug("Failed to init KIS request, error %d\n", err);
1099 return err;
1100 }
1101
1102 size_t rcvSize = sizeof(di);
1103 err = irecv_kis_request(client, &req, sizeof(req), &di.hdr, &rcvSize);
1104 if (err != IRECV_E_SUCCESS) {
1105 debug("Failed to send KIS request, error %d\n", err);
1106 return err;
1107 }
1108
1109 char buf[0x100];
1110 int len = 0;
1111
1112 len = irecv_kis_read_string(&di, di.deviceDescriptor.iSerialNumber, buf, sizeof(buf));
1113 if (len == 0)
1114 return IRECV_E_INVALID_INPUT;
1115 debug("Serial: %s\n", buf);
1116
1117 irecv_load_device_info_from_iboot_string(client, buf);
1118
1119 len = irecv_kis_read_string(&di, di.deviceDescriptor.iManufacturer, buf, sizeof(buf));
1120 if (len == 0)
1121 return IRECV_E_INVALID_INPUT;
1122 debug("Manufacturer: %s\n", buf);
1123
1124 len = irecv_kis_read_string(&di, di.deviceDescriptor.iProduct, buf, sizeof(buf));
1125 if (len == 0)
1126 return IRECV_E_INVALID_INPUT;
1127 debug("Product: %s\n", buf);
1128
1129 len = irecv_kis_read_string(&di, di.nonceOffset, buf, sizeof(buf));
1130 if (len == 0)
1131 return IRECV_E_INVALID_INPUT;
1132 debug("Nonces: %s\n", buf);
1133
1134 irecv_copy_nonce_with_tag_from_buffer("NONC", &client->device_info.ap_nonce, &client->device_info.ap_nonce_size, buf);
1135 irecv_copy_nonce_with_tag_from_buffer("SNON", &client->device_info.sep_nonce, &client->device_info.sep_nonce_size, buf);
1136
1137 debug("VID: 0x%04x\n", di.deviceDescriptor.idVendor);
1138 debug("PID: 0x%04x\n", di.deviceDescriptor.idProduct);
1139
1140 client->mode = di.deviceDescriptor.idProduct;
1141#endif
1142 return IRECV_E_SUCCESS;
1143}
1144
1145#ifdef WIN32
1146static const GUID GUID_DEVINTERFACE_IBOOT = {0xED82A167L, 0xD61A, 0x4AF6, {0x9A, 0xB6, 0x11, 0xE5, 0x22, 0x36, 0xC5, 0x76}};
1147static const GUID GUID_DEVINTERFACE_DFU = {0xB8085869L, 0xFEB9, 0x404B, {0x8C, 0xB1, 0x1E, 0x5C, 0x14, 0xFA, 0x8C, 0x54}};
1148static const GUID GUID_DEVINTERFACE_KIS = {0xB36F4137L, 0xF4EF, 0x4BFC, {0xA2, 0x5A, 0xC2, 0x41, 0x07, 0x68, 0xEE, 0x37}};
1149static const GUID GUID_DEVINTERFACE_PORTDFU = {0xAF633FF1L, 0x1170, 0x4CA6, {0xAE, 0x9E, 0x08, 0xD0, 0x01, 0x42, 0x1E, 0xAA}};
1150
1151typedef struct usb_control_request {
1152 uint8_t bmRequestType;
1153 uint8_t bRequest;
1154 uint16_t wValue;
1155 uint16_t wIndex;
1156 uint16_t wLength;
1157
1158 char data[];
1159} usb_control_request;
1160
1161static irecv_error_t win32_open_with_ecid(irecv_client_t* client, uint64_t ecid)
1162{
1163 int found = 0;
1164 const GUID *guids[] = { &GUID_DEVINTERFACE_KIS, &GUID_DEVINTERFACE_PORTDFU, &GUID_DEVINTERFACE_DFU, &GUID_DEVINTERFACE_IBOOT, NULL };
1165 irecv_client_t _client = (irecv_client_t) malloc(sizeof(struct irecv_client_private));
1166 memset(_client, 0, sizeof(struct irecv_client_private));
1167
1168 int k;
1169 for (k = 0; !found && guids[k]; k++) {
1170 DWORD i;
1171 SP_DEVICE_INTERFACE_DATA currentInterface;
1172 HDEVINFO usbDevices = SetupDiGetClassDevs(guids[k], NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
1173 memset(&currentInterface, '\0', sizeof(SP_DEVICE_INTERFACE_DATA));
1174 currentInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
1175 for (i = 0; usbDevices && SetupDiEnumDeviceInterfaces(usbDevices, NULL, guids[k], i, &currentInterface); i++) {
1176 _client->handle = INVALID_HANDLE_VALUE;
1177 DWORD requiredSize = 0;
1178 PSP_DEVICE_INTERFACE_DETAIL_DATA_A details;
1179 SetupDiGetDeviceInterfaceDetailA(usbDevices, &currentInterface, NULL, 0, &requiredSize, NULL);
1180 details = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A) malloc(requiredSize);
1181 details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
1182 if (!SetupDiGetDeviceInterfaceDetailA(usbDevices, &currentInterface, details, requiredSize, NULL, NULL)) {
1183 free(details);
1184 continue;
1185 }
1186
1187 unsigned int pid = 0;
1188 unsigned int vid = 0;
1189 if (sscanf(details->DevicePath, "\\\\?\\%*3s#vid_%04x&pid_%04x", &vid, &pid) != 2) {
1190 debug("%s: ERROR: failed to parse VID/PID! path: %s\n", __func__, details->DevicePath);
1191 free(details);
1192 continue;
1193 }
1194 if (vid != APPLE_VENDOR_ID) {
1195 free(details);
1196 continue;
1197 }
1198
1199 // make sure the current device is actually in the right mode for the given driver interface
1200 if ((guids[k] == &GUID_DEVINTERFACE_DFU && pid != IRECV_K_DFU_MODE && pid != IRECV_K_WTF_MODE)
1201 || (guids[k] == &GUID_DEVINTERFACE_PORTDFU && pid != IRECV_K_PORT_DFU_MODE)
1202 || (guids[k] == &GUID_DEVINTERFACE_IBOOT && (pid < IRECV_K_RECOVERY_MODE_1 || pid > IRECV_K_RECOVERY_MODE_4))
1203 || (guids[k] == &GUID_DEVINTERFACE_KIS && pid != 1)
1204 ) {
1205 free(details);
1206 continue;
1207 }
1208 if (guids[k] == &GUID_DEVINTERFACE_KIS) {
1209 pid = KIS_PRODUCT_ID;
1210 }
1211
1212 _client->handle = CreateFileA(details->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
1213 if (_client->handle == INVALID_HANDLE_VALUE) {
1214 debug("%s: Failed to open device path %s: %d\n", __func__, details->DevicePath, (int)GetLastError());
1215 free(details);
1216 continue;
1217 }
1218 _client->mode = pid;
1219
1220 if (ecid == IRECV_K_WTF_MODE) {
1221 if (_client->mode != IRECV_K_WTF_MODE) {
1222 /* special ecid case, ignore !IRECV_K_WTF_MODE */
1223 CloseHandle(_client->handle);
1224 free(details);
1225 continue;
1226 } else {
1227 ecid = 0;
1228 }
1229 }
1230
1231 if ((ecid != 0) && (_client->mode == IRECV_K_WTF_MODE)) {
1232 /* we can't get ecid in WTF mode */
1233 CloseHandle(_client->handle);
1234 free(details);
1235 continue;
1236 }
1237
1238 char serial_str[256];
1239 serial_str[0] = '\0';
1240
1241 if (_client->mode != KIS_PRODUCT_ID) {
1242 char *p = (char*)details->DevicePath;
1243 while ((p = strstr(p, "\\usb"))) {
1244 if (sscanf(p, "\\usb#vid_05ac&pid_%*04x#%s", serial_str) == 1)
1245 break;
1246 p += 4;
1247 }
1248 free(details);
1249
1250 if (serial_str[0] == '\0') {
1251 CloseHandle(_client->handle);
1252 continue;
1253 }
1254 p = strchr(serial_str, '#');
1255 if (p) {
1256 *p = '\0';
1257 }
1258
1259 unsigned int j;
1260 for (j = 0; j < strlen(serial_str); j++) {
1261 if (serial_str[j] == '_') {
1262 serial_str[j] = ' ';
1263 } else {
1264 serial_str[j] = toupper(serial_str[j]);
1265 }
1266 }
1267
1268 irecv_load_device_info_from_iboot_string(_client, serial_str);
1269 }
1270
1271 if (ecid != 0 && _client->mode != KIS_PRODUCT_ID) {
1272 if (_client->device_info.ecid != ecid) {
1273 CloseHandle(_client->handle);
1274 continue;
1275 }
1276 debug("found device with ECID %016" PRIx64 "\n", (uint64_t)ecid);
1277 }
1278 found = 1;
1279 break;
1280 }
1281 SetupDiDestroyDeviceInfoList(usbDevices);
1282 }
1283
1284 if (!found) {
1285 irecv_close(_client);
1286 return IRECV_E_UNABLE_TO_CONNECT;
1287 }
1288
1289 *client = _client;
1290
1291 return IRECV_E_SUCCESS;
1292}
1293#endif
1294
1295#ifdef HAVE_IOKIT
1296static void iokit_cfdictionary_set_short(CFMutableDictionaryRef dict, const void *key, SInt16 value)
1297{
1298 CFNumberRef numberRef;
1299
1300 numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &value);
1301 if (numberRef) {
1302 CFDictionarySetValue(dict, key, numberRef);
1303 CFRelease(numberRef);
1304 }
1305}
1306#endif
1307
1308static int check_context(irecv_client_t client)
1309{
1310 if (client == NULL || client->handle == NULL) {
1311 return IRECV_E_NO_DEVICE;
1312 }
1313
1314 return IRECV_E_SUCCESS;
1315}
1316#endif
1317
1318void irecv_init(void)
1319{
1320#ifndef USE_DUMMY
1321 thread_once(&init_once, _irecv_init);
1322#endif
1323}
1324
1325void irecv_exit(void)
1326{
1327#ifndef USE_DUMMY
1328 thread_once(&deinit_once, _irecv_deinit);
1329#endif
1330}
1331
1332#ifndef USE_DUMMY
1333#ifdef HAVE_IOKIT
1334static int iokit_usb_control_transfer(irecv_client_t client, uint8_t bm_request_type, uint8_t b_request, uint16_t w_value, uint16_t w_index, unsigned char *data, uint16_t w_length, unsigned int timeout)
1335{
1336 IOReturn result;
1337 IOUSBDevRequestTO req;
1338
1339 bzero(&req, sizeof(req));
1340 req.bmRequestType = bm_request_type;
1341 req.bRequest = b_request;
1342 req.wValue = OSSwapLittleToHostInt16(w_value);
1343 req.wIndex = OSSwapLittleToHostInt16(w_index);
1344 req.wLength = OSSwapLittleToHostInt16(w_length);
1345 req.pData = data;
1346 req.noDataTimeout = timeout;
1347 req.completionTimeout = timeout;
1348
1349 result = (*client->handle)->DeviceRequestTO(client->handle, &req);
1350 switch (result) {
1351 case kIOReturnSuccess: return req.wLenDone;
1352 case kIOReturnTimeout: return IRECV_E_TIMEOUT;
1353 case kIOUSBTransactionTimeout: return IRECV_E_TIMEOUT;
1354 case kIOReturnNotResponding: return IRECV_E_NO_DEVICE;
1355 case kIOReturnNoDevice: return IRECV_E_NO_DEVICE;
1356 default:
1357 return IRECV_E_UNKNOWN_ERROR;
1358 }
1359}
1360#else
1361#ifdef __APPLE__
1362 void dummy_callback(void) { }
1363#endif
1364#endif
1365#endif
1366
1367int irecv_usb_control_transfer(irecv_client_t client, uint8_t bm_request_type, uint8_t b_request, uint16_t w_value, uint16_t w_index, unsigned char *data, uint16_t w_length, unsigned int timeout)
1368{
1369#ifdef USE_DUMMY
1370 return IRECV_E_UNSUPPORTED;
1371#else
1372#ifndef WIN32
1373#ifdef HAVE_IOKIT
1374 return iokit_usb_control_transfer(client, bm_request_type, b_request, w_value, w_index, data, w_length, timeout);
1375#else
1376 return libusb_control_transfer(client->handle, bm_request_type, b_request, w_value, w_index, data, w_length, timeout);
1377#endif
1378#else
1379 DWORD count = 0;
1380 BOOL bRet;
1381 OVERLAPPED overlapped;
1382
1383 if (data == NULL)
1384 w_length = 0;
1385
1386 usb_control_request* packet = (usb_control_request*) malloc(sizeof(usb_control_request) + w_length);
1387 packet->bmRequestType = bm_request_type;
1388 packet->bRequest = b_request;
1389 packet->wValue = w_value;
1390 packet->wIndex = w_index;
1391 packet->wLength = w_length;
1392
1393 if (bm_request_type < 0x80 && w_length > 0) {
1394 memcpy(packet->data, data, w_length);
1395 }
1396
1397 memset(&overlapped, 0, sizeof(overlapped));
1398 overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1399 DeviceIoControl(client->handle, 0x2200A0, packet, sizeof(usb_control_request) + w_length, packet, sizeof(usb_control_request) + w_length, NULL, &overlapped);
1400 WaitForSingleObject(overlapped.hEvent, timeout);
1401 bRet = GetOverlappedResult(client->handle, &overlapped, &count, FALSE);
1402 CloseHandle(overlapped.hEvent);
1403 if (!bRet) {
1404 CancelIo(client->handle);
1405 free(packet);
1406 return -1;
1407 }
1408
1409 count -= sizeof(usb_control_request);
1410 if (count > 0) {
1411 if (bm_request_type >= 0x80) {
1412 memcpy(data, packet->data, count);
1413 }
1414 }
1415 free(packet);
1416
1417 return count;
1418#endif
1419#endif
1420}
1421
1422#ifndef USE_DUMMY
1423#ifdef HAVE_IOKIT
1424static int iokit_usb_bulk_transfer(irecv_client_t client,
1425 unsigned char endpoint,
1426 unsigned char *data,
1427 int length,
1428 int *transferred,
1429 unsigned int timeout)
1430{
1431 IOReturn result;
1432 IOUSBInterfaceInterface300 **intf = client->usbInterface;
1433 UInt32 size = length;
1434 UInt8 isUSBIn = (endpoint & kUSBbEndpointDirectionMask) != 0;
1435 UInt8 numEndpoints;
1436
1437 if (!intf) return IRECV_E_USB_INTERFACE;
1438
1439 result = (*intf)->GetNumEndpoints(intf, &numEndpoints);
1440
1441 if (result != kIOReturnSuccess)
1442 return IRECV_E_USB_INTERFACE;
1443
1444 for (UInt8 pipeRef = 0; pipeRef <= numEndpoints; pipeRef++) {
1445 UInt8 direction = 0;
1446 UInt8 number = 0;
1447 UInt8 transferType = 0;
1448 UInt16 maxPacketSize = 0;
1449 UInt8 interval = 0;
1450
1451 result = (*intf)->GetPipeProperties(intf, pipeRef, &direction, &number, &transferType, &maxPacketSize, &interval);
1452 if (result != kIOReturnSuccess)
1453 continue;
1454
1455 if (direction == 3)
1456 direction = isUSBIn;
1457
1458 if (number != (endpoint & ~kUSBbEndpointDirectionMask) || direction != isUSBIn)
1459 continue;
1460
1461 // Just because
1462 result = (*intf)->GetPipeStatus(intf, pipeRef);
1463 switch (result) {
1464 case kIOReturnSuccess: break;
1465 case kIOReturnNoDevice: return IRECV_E_NO_DEVICE;
1466 case kIOReturnNotOpen: return IRECV_E_UNABLE_TO_CONNECT;
1467 default: return IRECV_E_USB_STATUS;
1468 }
1469
1470 // Do the transfer
1471 if (isUSBIn) {
1472 result = (*intf)->ReadPipeTO(intf, pipeRef, data, &size, timeout, timeout);
1473 if (result != kIOReturnSuccess)
1474 return IRECV_E_PIPE;
1475 *transferred = size;
1476
1477 return IRECV_E_SUCCESS;
1478 }
1479 else {
1480 // IOUSBInterfaceClass::interfaceWritePipe (intf?, pipeRef==1, data, size=0x8000)
1481 result = (*intf)->WritePipeTO(intf, pipeRef, data, size, timeout, timeout);
1482 if (result != kIOReturnSuccess)
1483 return IRECV_E_PIPE;
1484 *transferred = size;
1485
1486 return IRECV_E_SUCCESS;
1487 }
1488 }
1489
1490 return IRECV_E_USB_INTERFACE;
1491}
1492#endif
1493#endif
1494
1495int irecv_usb_bulk_transfer(irecv_client_t client,
1496 unsigned char endpoint,
1497 unsigned char *data,
1498 int length,
1499 int *transferred,
1500 unsigned int timeout)
1501{
1502#ifdef USE_DUMMY
1503 return IRECV_E_UNSUPPORTED;
1504#else
1505 int ret;
1506
1507#ifndef WIN32
1508#ifdef HAVE_IOKIT
1509 return iokit_usb_bulk_transfer(client, endpoint, data, length, transferred, timeout);
1510#else
1511 ret = libusb_bulk_transfer(client->handle, endpoint, data, length, transferred, timeout);
1512 if (ret < 0) {
1513 libusb_clear_halt(client->handle, endpoint);
1514 }
1515#endif
1516#else
1517 if (endpoint==0x4) {
1518 ret = DeviceIoControl(client->handle, 0x2201B6, data, length, data, length, (PDWORD) transferred, NULL);
1519 } else {
1520 ret = 0;
1521 }
1522 ret = (ret==0) ? -1 : 0;
1523#endif
1524
1525 return ret;
1526#endif
1527}
1528
1529#ifndef USE_DUMMY
1530#ifdef HAVE_IOKIT
1531static irecv_error_t iokit_usb_open_service(irecv_client_t *pclient, io_service_t service)
1532{
1533 IOReturn result;
1534 irecv_client_t client;
1535 SInt32 score;
1536 UInt16 mode;
1537 UInt32 locationID;
1538 IOCFPlugInInterface **plug = NULL;
1539 CFStringRef serialString;
1540
1541 client = (irecv_client_t) calloc( 1, sizeof(struct irecv_client_private));
1542
1543 // Create the plug-in
1544 result = IOCreatePlugInInterfaceForService(service, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plug, &score);
1545 if (result != kIOReturnSuccess) {
1546 IOObjectRelease(service);
1547 free(client);
1548 return IRECV_E_UNKNOWN_ERROR;
1549 }
1550
1551 // Cache the serial string before discarding the service. The service object
1552 // has a cached copy, so a request to the hardware device is not required.
1553 char serial_str[256];
1554 serial_str[0] = '\0';
1555 serialString = IORegistryEntryCreateCFProperty(service, CFSTR(kUSBSerialNumberString), kCFAllocatorDefault, 0);
1556 if (serialString) {
1557 CFStringGetCString(serialString, serial_str, sizeof(serial_str), kCFStringEncodingUTF8);
1558 CFRelease(serialString);
1559 }
1560 irecv_load_device_info_from_iboot_string(client, serial_str);
1561
1562 IOObjectRelease(service);
1563
1564 // Create the device interface
1565 result = (*plug)->QueryInterface(plug, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID320), (LPVOID *)&(client->handle));
1566 IODestroyPlugInInterface(plug);
1567 if (result != kIOReturnSuccess) {
1568 free(client);
1569 return IRECV_E_UNKNOWN_ERROR;
1570 }
1571
1572 (*client->handle)->GetDeviceProduct(client->handle, &mode);
1573 (*client->handle)->GetLocationID(client->handle, &locationID);
1574 client->mode = mode;
1575 debug("opening device %04x:%04x @ %#010x...\n", kAppleVendorID, client->mode, locationID);
1576
1577 result = (*client->handle)->USBDeviceOpenSeize(client->handle);
1578 if (result != kIOReturnSuccess) {
1579 (*client->handle)->Release(client->handle);
1580 free(client);
1581 return IRECV_E_UNABLE_TO_CONNECT;
1582 }
1583
1584 *pclient = client;
1585 return IRECV_E_SUCCESS;
1586}
1587
1588static io_iterator_t iokit_usb_get_iterator_for_pid(UInt16 pid)
1589{
1590 IOReturn result;
1591 io_iterator_t iterator;
1592 CFMutableDictionaryRef matchingDict;
1593
1594 matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
1595 iokit_cfdictionary_set_short(matchingDict, CFSTR(kUSBVendorID), kAppleVendorID);
1596 iokit_cfdictionary_set_short(matchingDict, CFSTR(kUSBProductID), pid);
1597
1598 result = IOServiceGetMatchingServices(MACH_PORT_NULL, matchingDict, &iterator);
1599 if (result != kIOReturnSuccess)
1600 return IO_OBJECT_NULL;
1601
1602 return iterator;
1603}
1604
1605static irecv_error_t iokit_open_with_ecid(irecv_client_t* pclient, uint64_t ecid)
1606{
1607 io_service_t service, ret_service;
1608 io_iterator_t iterator;
1609 CFStringRef usbSerial = NULL;
1610 CFStringRef ecidString = NULL;
1611 CFRange range;
1612
1613 UInt16 wtf_pids[] = { IRECV_K_WTF_MODE, 0};
1614 UInt16 all_pids[] = { IRECV_K_WTF_MODE, IRECV_K_DFU_MODE, IRECV_K_PORT_DFU_MODE, IRECV_K_RECOVERY_MODE_1, IRECV_K_RECOVERY_MODE_2, IRECV_K_RECOVERY_MODE_3, IRECV_K_RECOVERY_MODE_4, KIS_PRODUCT_ID, 0 };
1615 UInt16 *pids = all_pids;
1616 int i;
1617
1618 if (pclient == NULL) {
1619 debug("%s: pclient parameter is null\n", __func__);
1620 return IRECV_E_INVALID_INPUT;
1621 }
1622 if (ecid == IRECV_K_WTF_MODE) {
1623 /* special ecid case, ignore !IRECV_K_WTF_MODE */
1624 pids = wtf_pids;
1625 ecid = 0;
1626 }
1627 if (ecid > 0) {
1628 ecidString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%llX"), ecid);
1629 if (ecidString == NULL) {
1630 debug("%s: failed to create ECID string\n", __func__);
1631 return IRECV_E_UNABLE_TO_CONNECT;
1632 }
1633 }
1634
1635 *pclient = NULL;
1636 ret_service = IO_OBJECT_NULL;
1637
1638 for (i = 0; (pids[i] > 0 && ret_service == IO_OBJECT_NULL) ; i++) {
1639
1640 iterator = iokit_usb_get_iterator_for_pid(pids[i]);
1641 if (iterator) {
1642 while ((service = IOIteratorNext(iterator))) {
1643
1644 if (ecid == 0) {
1645 ret_service = service;
1646 break;
1647 }
1648
1649 if (pids[i] == KIS_PRODUCT_ID) {
1650 // In KIS Mode, we have to open the device in order to get
1651 // it's ECID
1652 irecv_error_t err = iokit_usb_open_service(pclient, service);
1653 if (err != IRECV_E_SUCCESS) {
1654 debug("%s: failed to open KIS device\n", __func__);
1655 continue;
1656 }
1657
1658 if (ecidString)
1659 CFRelease(ecidString);
1660
1661 return IRECV_E_SUCCESS;
1662 }
1663
1664 usbSerial = IORegistryEntryCreateCFProperty(service, CFSTR(kUSBSerialNumberString), kCFAllocatorDefault, 0);
1665 if (usbSerial == NULL) {
1666 debug("%s: failed to create USB serial string property\n", __func__);
1667 IOObjectRelease(service);
1668 continue;
1669 }
1670
1671 range = CFStringFind(usbSerial, ecidString, kCFCompareCaseInsensitive);
1672 if (range.location == kCFNotFound) {
1673 IOObjectRelease(service);
1674 } else {
1675 ret_service = service;
1676 break;
1677 }
1678 }
1679 if (usbSerial) {
1680 CFRelease(usbSerial);
1681 usbSerial = NULL;
1682 }
1683 IOObjectRelease(iterator);
1684 }
1685 }
1686
1687 if (ecidString)
1688 CFRelease(ecidString);
1689
1690 if (ret_service == IO_OBJECT_NULL)
1691 return IRECV_E_UNABLE_TO_CONNECT;
1692
1693 return iokit_usb_open_service(pclient, ret_service);
1694}
1695#endif
1696
1697#ifndef WIN32
1698#ifndef HAVE_IOKIT
1699static irecv_error_t libusb_usb_open_handle_with_descriptor_and_ecid(irecv_client_t *pclient, struct libusb_device_handle *usb_handle, struct libusb_device_descriptor *usb_descriptor, uint64_t ecid)
1700{
1701 irecv_client_t client = (irecv_client_t) malloc(sizeof(struct irecv_client_private));
1702 if (client == NULL) {
1703 libusb_close(usb_handle);
1704 return IRECV_E_OUT_OF_MEMORY;
1705 }
1706
1707 memset(client, '\0', sizeof(struct irecv_client_private));
1708 client->usb_interface = 0;
1709 client->handle = usb_handle;
1710 client->mode = usb_descriptor->idProduct;
1711
1712 if (client->mode != KIS_PRODUCT_ID) {
1713 char serial_str[256];
1714 memset(serial_str, 0, 256);
1715 irecv_get_string_descriptor_ascii(client, usb_descriptor->iSerialNumber, (unsigned char*)serial_str, 255);
1716 irecv_load_device_info_from_iboot_string(client, serial_str);
1717 }
1718
1719 if (ecid != 0 && client->mode != KIS_PRODUCT_ID) {
1720 if (client->device_info.ecid != ecid) {
1721 irecv_close(client);
1722 return IRECV_E_NO_DEVICE; //wrong device
1723 }
1724 debug("found device with ECID %016" PRIx64 "\n", (uint64_t)ecid);
1725 }
1726
1727 *pclient = client;
1728 return IRECV_E_SUCCESS;
1729}
1730
1731static irecv_error_t libusb_open_with_ecid(irecv_client_t* pclient, uint64_t ecid)
1732{
1733 irecv_error_t ret = IRECV_E_UNABLE_TO_CONNECT;
1734 int i = 0;
39 struct libusb_device* usb_device = NULL; 1735 struct libusb_device* usb_device = NULL;
40 struct libusb_device** usb_device_list = NULL; 1736 struct libusb_device** usb_device_list = NULL;
41 struct libusb_device_handle* usb_handle = NULL;
42 struct libusb_device_descriptor usb_descriptor; 1737 struct libusb_device_descriptor usb_descriptor;
43 1738
44 *pclient = NULL; 1739 *pclient = NULL;
45 libusb_init(&libirecovery_context);
46 if(libirecovery_debug) {
47 irecv_set_debug_level(libirecovery_debug);
48 }
49
50 irecv_error_t error = IRECV_E_SUCCESS;
51 int usb_device_count = libusb_get_device_list(libirecovery_context, &usb_device_list); 1740 int usb_device_count = libusb_get_device_list(libirecovery_context, &usb_device_list);
52 for (i = 0; i < usb_device_count; i++) { 1741 for (i = 0; i < usb_device_count; i++) {
53 usb_device = usb_device_list[i]; 1742 usb_device = usb_device_list[i];
54 libusb_get_device_descriptor(usb_device, &usb_descriptor); 1743 libusb_get_device_descriptor(usb_device, &usb_descriptor);
55 if (usb_descriptor.idVendor == APPLE_VENDOR_ID) { 1744 if (usb_descriptor.idVendor == APPLE_VENDOR_ID) {
56 /* verify this device is in a mode we understand */ 1745 /* verify this device is in a mode we understand */
57 if (usb_descriptor.idProduct == kRecoveryMode1 || 1746 if (usb_descriptor.idProduct == IRECV_K_RECOVERY_MODE_1 ||
58 usb_descriptor.idProduct == kRecoveryMode2 || 1747 usb_descriptor.idProduct == IRECV_K_RECOVERY_MODE_2 ||
59 usb_descriptor.idProduct == kRecoveryMode3 || 1748 usb_descriptor.idProduct == IRECV_K_RECOVERY_MODE_3 ||
60 usb_descriptor.idProduct == kRecoveryMode4 || 1749 usb_descriptor.idProduct == IRECV_K_RECOVERY_MODE_4 ||
61 usb_descriptor.idProduct == kDfuMode) { 1750 usb_descriptor.idProduct == IRECV_K_WTF_MODE ||
1751 usb_descriptor.idProduct == IRECV_K_DFU_MODE ||
1752 usb_descriptor.idProduct == IRECV_K_PORT_DFU_MODE ||
1753 usb_descriptor.idProduct == KIS_PRODUCT_ID) {
1754
1755 if (ecid == IRECV_K_WTF_MODE) {
1756 if (usb_descriptor.idProduct != IRECV_K_WTF_MODE) {
1757 /* special ecid case, ignore !IRECV_K_WTF_MODE */
1758 continue;
1759 } else {
1760 ecid = 0;
1761 }
1762 }
1763
1764 if ((ecid != 0) && (usb_descriptor.idProduct == IRECV_K_WTF_MODE)) {
1765 /* we can't get ecid in WTF mode */
1766 continue;
1767 }
62 1768
63 debug("opening device %04x:%04x...\n", usb_descriptor.idVendor, usb_descriptor.idProduct); 1769 debug("opening device %04x:%04x...\n", usb_descriptor.idVendor, usb_descriptor.idProduct);
64 1770
65 libusb_open(usb_device, &usb_handle); 1771 struct libusb_device_handle* usb_handle = NULL;
66 if (usb_handle == NULL) { 1772 int libusb_error = libusb_open(usb_device, &usb_handle);
67 libusb_free_device_list(usb_device_list, 1); 1773 if (usb_handle == NULL || libusb_error != 0) {
1774 debug("%s: can't connect to device: %s\n", __func__, libusb_error_name(libusb_error));
1775
68 libusb_close(usb_handle); 1776 libusb_close(usb_handle);
69 libusb_exit(libirecovery_context); 1777 if (ecid != 0) {
1778 continue;
1779 }
1780 libusb_free_device_list(usb_device_list, 1);
70 return IRECV_E_UNABLE_TO_CONNECT; 1781 return IRECV_E_UNABLE_TO_CONNECT;
71 } 1782 }
72 libusb_free_device_list(usb_device_list, 1);
73 1783
74 irecv_client_t client = (irecv_client_t) malloc(sizeof(struct irecv_client)); 1784 ret = libusb_usb_open_handle_with_descriptor_and_ecid(pclient, usb_handle, &usb_descriptor, ecid);
75 if (client == NULL) { 1785 if (ret == IRECV_E_SUCCESS) {
76 libusb_close(usb_handle); 1786 break;
77 libusb_exit(libirecovery_context);
78 return IRECV_E_OUT_OF_MEMORY;
79 } 1787 }
1788 }
1789 }
1790 }
1791 libusb_free_device_list(usb_device_list, 1);
1792 return ret;
1793}
1794#endif
1795#endif
1796#endif
1797
1798irecv_error_t irecv_open_with_ecid(irecv_client_t* pclient, uint64_t ecid)
1799{
1800#ifdef USE_DUMMY
1801 return IRECV_E_UNSUPPORTED;
1802#else
1803 irecv_error_t error = IRECV_E_UNABLE_TO_CONNECT;
1804
1805 if (libirecovery_debug) {
1806 irecv_set_debug_level(libirecovery_debug);
1807 }
1808#ifndef WIN32
1809#ifdef HAVE_IOKIT
1810 error = iokit_open_with_ecid(pclient, ecid);
1811#else
1812 error = libusb_open_with_ecid(pclient, ecid);
1813#endif
1814#else
1815 error = win32_open_with_ecid(pclient, ecid);
1816#endif
1817 irecv_client_t client = *pclient;
1818 if (error != IRECV_E_SUCCESS) {
1819 irecv_close(client);
1820 return error;
1821 }
80 1822
81 memset(client, '\0', sizeof(struct irecv_client)); 1823 error = irecv_usb_set_configuration(client, 1);
82 client->interface = 0; 1824 if (error != IRECV_E_SUCCESS) {
83 client->handle = usb_handle; 1825 debug("Failed to set configuration, error %d\n", error);
84 client->mode = usb_descriptor.idProduct; 1826 irecv_close(client);
1827 return error;
1828 }
85 1829
86 error = irecv_set_configuration(client, 1); 1830 if (client->mode == IRECV_K_DFU_MODE || client->mode == IRECV_K_PORT_DFU_MODE || client->mode == IRECV_K_WTF_MODE || client->mode == KIS_PRODUCT_ID) {
87 if (error != IRECV_E_SUCCESS) { 1831 error = irecv_usb_set_interface(client, 0, 0);
88 return error; 1832 } else {
89 } 1833 error = irecv_usb_set_interface(client, 0, 0);
1834 if (error == IRECV_E_SUCCESS && client->mode > IRECV_K_RECOVERY_MODE_2) {
1835 error = irecv_usb_set_interface(client, 1, 1);
1836 }
1837 }
90 1838
91 error = irecv_set_interface(client, 1, 1); 1839 if (error != IRECV_E_SUCCESS) {
92 if (error != IRECV_E_SUCCESS) { 1840 debug("Failed to set interface, error %d\n", error);
93 return error; 1841 irecv_close(client);
94 } 1842 return error;
1843 }
95 1844
96 /* cache usb serial */ 1845 if (client->mode == KIS_PRODUCT_ID) {
97 libusb_get_string_descriptor_ascii(client->handle, usb_descriptor.iSerialNumber, client->serial, 255); 1846 error = irecv_kis_init(client);
1847 if (error != IRECV_E_SUCCESS) {
1848 debug("irecv_kis_init failed, error %d\n", error);
1849 irecv_close(client);
1850 return error;
1851 }
98 1852
99 *pclient = client; 1853 error = irecv_kis_load_device_info(client);
100 return IRECV_E_SUCCESS; 1854 if (error != IRECV_E_SUCCESS) {
101 } 1855 debug("irecv_kis_load_device_info failed, error %d\n", error);
1856 irecv_close(client);
1857 return error;
1858 }
1859 if (ecid != 0 && client->device_info.ecid != ecid) {
1860 irecv_close(client);
1861 return IRECV_E_NO_DEVICE; //wrong device
102 } 1862 }
1863 debug("found device with ECID %016" PRIx64 "\n", (uint64_t)client->device_info.ecid);
1864 } else {
1865 irecv_copy_nonce_with_tag(client, "NONC", &client->device_info.ap_nonce, &client->device_info.ap_nonce_size);
1866 irecv_copy_nonce_with_tag(client, "SNON", &client->device_info.sep_nonce, &client->device_info.sep_nonce_size);
103 } 1867 }
104 1868
105 return IRECV_E_UNABLE_TO_CONNECT; 1869 if (error == IRECV_E_SUCCESS) {
1870 if ((*pclient)->connected_callback != NULL) {
1871 irecv_event_t event;
1872 event.size = 0;
1873 event.data = NULL;
1874 event.progress = 0;
1875 event.type = IRECV_CONNECTED;
1876 (*pclient)->connected_callback(*pclient, &event);
1877 }
1878 }
1879 return error;
1880#endif
106} 1881}
107 1882
108irecv_error_t irecv_set_configuration(irecv_client_t client, int configuration) { 1883irecv_error_t irecv_usb_set_configuration(irecv_client_t client, int configuration)
109 if (client == NULL || client->handle == NULL) { 1884{
1885#ifdef USE_DUMMY
1886 return IRECV_E_UNSUPPORTED;
1887#else
1888 if (check_context(client) != IRECV_E_SUCCESS)
110 return IRECV_E_NO_DEVICE; 1889 return IRECV_E_NO_DEVICE;
111 }
112 1890
1891#ifndef WIN32
113 debug("Setting to configuration %d\n", configuration); 1892 debug("Setting to configuration %d\n", configuration);
114 1893
1894#ifdef HAVE_IOKIT
1895 IOReturn result;
1896
1897 result = (*client->handle)->SetConfiguration(client->handle, configuration);
1898 if (result != kIOReturnSuccess) {
1899 debug("error setting configuration: %#x\n", result);
1900 return IRECV_E_USB_CONFIGURATION;
1901 }
1902#else
115 int current = 0; 1903 int current = 0;
116 libusb_get_configuration(client->handle, &current); 1904 libusb_get_configuration(client->handle, &current);
117 if (current != configuration) { 1905 if (current != configuration) {
@@ -119,45 +1907,199 @@ irecv_error_t irecv_set_configuration(irecv_client_t client, int configuration)
119 return IRECV_E_USB_CONFIGURATION; 1907 return IRECV_E_USB_CONFIGURATION;
120 } 1908 }
121 } 1909 }
1910#endif
1911 client->usb_config = configuration;
1912#endif
122 1913
123 client->config = configuration;
124 return IRECV_E_SUCCESS; 1914 return IRECV_E_SUCCESS;
1915#endif
125} 1916}
126 1917
127irecv_error_t irecv_set_interface(irecv_client_t client, int interface, int alt_interface) { 1918#ifndef USE_DUMMY
128 if (client == NULL || client->handle == NULL) { 1919#ifdef HAVE_IOKIT
129 return IRECV_E_NO_DEVICE; 1920static IOReturn iokit_usb_get_interface(IOUSBDeviceInterface320 **device, uint8_t ifc, io_service_t *usbInterfacep)
1921{
1922 IOUSBFindInterfaceRequest request;
1923 uint8_t current_interface;
1924 kern_return_t kresult;
1925 io_iterator_t interface_iterator;
1926
1927 *usbInterfacep = IO_OBJECT_NULL;
1928
1929 request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
1930 request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
1931 request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
1932 request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
1933
1934 kresult = (*device)->CreateInterfaceIterator(device, &request, &interface_iterator);
1935 if (kresult)
1936 return kresult;
1937
1938 for ( current_interface = 0 ; current_interface <= ifc ; current_interface++ ) {
1939 *usbInterfacep = IOIteratorNext(interface_iterator);
1940 if (current_interface != ifc)
1941 (void) IOObjectRelease (*usbInterfacep);
130 } 1942 }
1943 IOObjectRelease(interface_iterator);
131 1944
132 if (client->interface == interface) { 1945 return kIOReturnSuccess;
133 return IRECV_E_SUCCESS; 1946}
1947
1948static irecv_error_t iokit_usb_set_interface(irecv_client_t client, int usb_interface, int usb_alt_interface)
1949{
1950 IOReturn result;
1951 io_service_t interface_service = IO_OBJECT_NULL;
1952 IOCFPlugInInterface **plugInInterface = NULL;
1953 SInt32 score;
1954
1955 // Close current interface
1956 if (client->usbInterface) {
1957 result = (*client->usbInterface)->USBInterfaceClose(client->usbInterface);
1958 result = (*client->usbInterface)->Release(client->usbInterface);
1959 client->usbInterface = NULL;
134 } 1960 }
135 1961
136 debug("Setting to interface %d:%d\n", interface, alt_interface); 1962 result = iokit_usb_get_interface(client->handle, usb_interface, &interface_service);
137 if (libusb_claim_interface(client->handle, interface) < 0) { 1963 if (result != kIOReturnSuccess) {
1964 debug("failed to find requested interface: %d\n", usb_interface);
138 return IRECV_E_USB_INTERFACE; 1965 return IRECV_E_USB_INTERFACE;
139 } 1966 }
140 1967
141 if (libusb_set_interface_alt_setting(client->handle, interface, alt_interface) < 0) { 1968 result = IOCreatePlugInInterfaceForService(interface_service, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score);
1969 IOObjectRelease(interface_service);
1970 if (result != kIOReturnSuccess) {
1971 debug("error creating plug-in interface: %#x\n", result);
142 return IRECV_E_USB_INTERFACE; 1972 return IRECV_E_USB_INTERFACE;
143 } 1973 }
144 1974
145 client->interface = interface; 1975 result = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID300), (LPVOID)&client->usbInterface);
146 client->alt_interface = alt_interface; 1976 IODestroyPlugInInterface(plugInInterface);
1977 if (result != kIOReturnSuccess) {
1978 debug("error creating interface interface: %#x\n", result);
1979 return IRECV_E_USB_INTERFACE;
1980 }
1981
1982 result = (*client->usbInterface)->USBInterfaceOpen(client->usbInterface);
1983 if (result != kIOReturnSuccess) {
1984 debug("error opening interface: %#x\n", result);
1985 return IRECV_E_USB_INTERFACE;
1986 }
1987
1988 if (usb_interface == 1) {
1989 result = (*client->usbInterface)->SetAlternateInterface(client->usbInterface, usb_alt_interface);
1990 if (result != kIOReturnSuccess) {
1991 debug("error setting alternate interface: %#x\n", result);
1992 return IRECV_E_USB_INTERFACE;
1993 }
1994 }
1995
147 return IRECV_E_SUCCESS; 1996 return IRECV_E_SUCCESS;
148} 1997}
1998#endif
1999#endif
2000
2001irecv_error_t irecv_usb_set_interface(irecv_client_t client, int usb_interface, int usb_alt_interface)
2002{
2003#ifdef USE_DUMMY
2004 return IRECV_E_UNSUPPORTED;
2005#else
2006 if (check_context(client) != IRECV_E_SUCCESS)
2007 return IRECV_E_NO_DEVICE;
149 2008
150irecv_error_t irecv_reset(irecv_client_t client) { 2009 debug("Setting to interface %d:%d\n", usb_interface, usb_alt_interface);
151 if (client == NULL || client->handle == NULL) { 2010#ifndef WIN32
2011#ifdef HAVE_IOKIT
2012 if (iokit_usb_set_interface(client, usb_interface, usb_alt_interface) < 0) {
2013 return IRECV_E_USB_INTERFACE;
2014 }
2015#else
2016 if (libusb_claim_interface(client->handle, usb_interface) < 0) {
2017 return IRECV_E_USB_INTERFACE;
2018 }
2019
2020 if (usb_interface == 1) {
2021 if (libusb_set_interface_alt_setting(client->handle, usb_interface, usb_alt_interface) < 0) {
2022 return IRECV_E_USB_INTERFACE;
2023 }
2024 }
2025#endif
2026#else
2027 if (usb_interface == 1) {
2028 if (irecv_usb_control_transfer(client, 0, 0x0B, usb_alt_interface, usb_interface, NULL, 0, USB_TIMEOUT) < 0) {
2029 return IRECV_E_USB_INTERFACE;
2030 }
2031 }
2032#endif
2033 client->usb_interface = usb_interface;
2034 client->usb_alt_interface = usb_alt_interface;
2035
2036 return IRECV_E_SUCCESS;
2037#endif
2038}
2039
2040irecv_error_t irecv_reset(irecv_client_t client)
2041{
2042#ifdef USE_DUMMY
2043 return IRECV_E_UNSUPPORTED;
2044#else
2045 if (check_context(client) != IRECV_E_SUCCESS)
152 return IRECV_E_NO_DEVICE; 2046 return IRECV_E_NO_DEVICE;
2047
2048#ifndef WIN32
2049#ifdef HAVE_IOKIT
2050 IOReturn result;
2051
2052 result = (*client->handle)->ResetDevice(client->handle);
2053 if (result != kIOReturnSuccess && result != kIOReturnNotResponding) {
2054 debug("error sending device reset: %#x\n", result);
2055 return IRECV_E_UNKNOWN_ERROR;
153 } 2056 }
154 2057
2058 result = (*client->handle)->USBDeviceReEnumerate(client->handle, 0);
2059 if (result != kIOReturnSuccess && result != kIOReturnNotResponding) {
2060 debug("error re-enumerating device: %#x (ignored)\n", result);
2061 }
2062#else
155 libusb_reset_device(client->handle); 2063 libusb_reset_device(client->handle);
2064#endif
2065#else
2066 DWORD count;
2067 DeviceIoControl(client->handle, 0x22000C, NULL, 0, NULL, 0, &count, NULL);
2068#endif
156 2069
157 return IRECV_E_SUCCESS; 2070 return IRECV_E_SUCCESS;
2071#endif
158} 2072}
159 2073
160irecv_error_t irecv_event_subscribe(irecv_client_t client, irecv_event_type type, irecv_event_cb_t callback, void* user_data) { 2074irecv_error_t irecv_open_with_ecid_and_attempts(irecv_client_t* pclient, uint64_t ecid, int attempts)
2075{
2076#ifdef USE_DUMMY
2077 return IRECV_E_UNSUPPORTED;
2078#else
2079 int i;
2080
2081 for (i = 0; i < attempts; i++) {
2082 if (*pclient) {
2083 irecv_close(*pclient);
2084 *pclient = NULL;
2085 }
2086 if (irecv_open_with_ecid(pclient, ecid) != IRECV_E_SUCCESS) {
2087 debug("Connection failed. Waiting 1 sec before retry.\n");
2088 sleep(1);
2089 } else {
2090 return IRECV_E_SUCCESS;
2091 }
2092 }
2093
2094 return IRECV_E_UNABLE_TO_CONNECT;
2095#endif
2096}
2097
2098irecv_error_t irecv_event_subscribe(irecv_client_t client, irecv_event_type type, irecv_event_cb_t callback, void* user_data)
2099{
2100#ifdef USE_DUMMY
2101 return IRECV_E_UNSUPPORTED;
2102#else
161 switch(type) { 2103 switch(type) {
162 case IRECV_RECEIVED: 2104 case IRECV_RECEIVED:
163 client->received_callback = callback; 2105 client->received_callback = callback;
@@ -165,9 +2107,11 @@ irecv_error_t irecv_event_subscribe(irecv_client_t client, irecv_event_type type
165 2107
166 case IRECV_PROGRESS: 2108 case IRECV_PROGRESS:
167 client->progress_callback = callback; 2109 client->progress_callback = callback;
2110 break;
168 2111
169 case IRECV_CONNECTED: 2112 case IRECV_CONNECTED:
170 client->connected_callback = callback; 2113 client->connected_callback = callback;
2114 break;
171 2115
172 case IRECV_PRECOMMAND: 2116 case IRECV_PRECOMMAND:
173 client->precommand_callback = callback; 2117 client->precommand_callback = callback;
@@ -179,15 +2123,21 @@ irecv_error_t irecv_event_subscribe(irecv_client_t client, irecv_event_type type
179 2123
180 case IRECV_DISCONNECTED: 2124 case IRECV_DISCONNECTED:
181 client->disconnected_callback = callback; 2125 client->disconnected_callback = callback;
2126 break;
182 2127
183 default: 2128 default:
184 return IRECV_E_UNKNOWN_ERROR; 2129 return IRECV_E_UNKNOWN_ERROR;
185 } 2130 }
186 2131
187 return IRECV_E_SUCCESS; 2132 return IRECV_E_SUCCESS;
2133#endif
188} 2134}
189 2135
190irecv_error_t irecv_event_unsubscribe(irecv_client_t client, irecv_event_type type) { 2136irecv_error_t irecv_event_unsubscribe(irecv_client_t client, irecv_event_type type)
2137{
2138#ifdef USE_DUMMY
2139 return IRECV_E_UNSUPPORTED;
2140#else
191 switch(type) { 2141 switch(type) {
192 case IRECV_RECEIVED: 2142 case IRECV_RECEIVED:
193 client->received_callback = NULL; 2143 client->received_callback = NULL;
@@ -195,9 +2145,11 @@ irecv_error_t irecv_event_unsubscribe(irecv_client_t client, irecv_event_type ty
195 2145
196 case IRECV_PROGRESS: 2146 case IRECV_PROGRESS:
197 client->progress_callback = NULL; 2147 client->progress_callback = NULL;
2148 break;
198 2149
199 case IRECV_CONNECTED: 2150 case IRECV_CONNECTED:
200 client->connected_callback = NULL; 2151 client->connected_callback = NULL;
2152 break;
201 2153
202 case IRECV_PRECOMMAND: 2154 case IRECV_PRECOMMAND:
203 client->precommand_callback = NULL; 2155 client->precommand_callback = NULL;
@@ -209,17 +2161,844 @@ irecv_error_t irecv_event_unsubscribe(irecv_client_t client, irecv_event_type ty
209 2161
210 case IRECV_DISCONNECTED: 2162 case IRECV_DISCONNECTED:
211 client->disconnected_callback = NULL; 2163 client->disconnected_callback = NULL;
2164 break;
212 2165
213 default: 2166 default:
214 return IRECV_E_UNKNOWN_ERROR; 2167 return IRECV_E_UNKNOWN_ERROR;
215 } 2168 }
216 2169
217 return IRECV_E_SUCCESS; 2170 return IRECV_E_SUCCESS;
2171#endif
2172}
2173
2174#ifndef USE_DUMMY
2175struct irecv_device_event_context {
2176 irecv_device_event_cb_t callback;
2177 void *user_data;
2178};
2179
2180struct irecv_usb_device_info {
2181 struct irecv_device_info device_info;
2182 enum irecv_mode mode;
2183 uint32_t location;
2184 int alive;
2185};
2186
2187#ifdef WIN32
2188struct irecv_win_dev_ctx {
2189 PSP_DEVICE_INTERFACE_DETAIL_DATA_A details;
2190 uint32_t location;
2191};
2192#else
2193#ifdef HAVE_IOKIT
2194struct irecv_iokit_dev_ctx {
2195 io_service_t device;
2196 IOUSBDeviceInterface **dev;
2197};
2198#endif
2199#endif
2200
2201static int _irecv_is_recovery_device(void *device)
2202{
2203 uint16_t vendor_id = 0;
2204 uint16_t product_id = 0;
2205#ifdef WIN32
2206 const char *path = (const char*)device;
2207 unsigned int vendor = 0;
2208 unsigned int product = 0;
2209 if (sscanf(path, "\\usb#vid_%04x&pid_%04x#", &vendor, &product) != 2) {
2210 return 0;
2211 }
2212 vendor_id = (uint16_t)vendor;
2213 product_id = (uint16_t)product;
2214#else
2215#ifdef HAVE_IOKIT
2216 kern_return_t kr;
2217 IOUSBDeviceInterface **dev = device;
2218 kr = (*dev)->GetDeviceVendor(dev, &vendor_id);
2219 if (kr != kIOReturnSuccess) {
2220 debug("%s: Failed to get vendor id\n", __func__);
2221 return 0;
2222 }
2223 kr = (*dev)->GetDeviceProduct(dev, &product_id);
2224 if (kr != kIOReturnSuccess) {
2225 debug("%s: Failed to get product id\n", __func__);
2226 return 0;
2227 }
2228#else
2229 libusb_device *device_ = (libusb_device*)device;
2230 struct libusb_device_descriptor devdesc;
2231 int libusb_error;
2232
2233 libusb_error = libusb_get_device_descriptor(device_, &devdesc);
2234 if (libusb_error != 0) {
2235 debug("%s: failed to get device descriptor: %s\n", __func__, libusb_error_name(libusb_error));
2236 return 0;
2237 }
2238 vendor_id = devdesc.idVendor;
2239 product_id = devdesc.idProduct;
2240#endif
2241#endif
2242
2243 if (vendor_id != APPLE_VENDOR_ID) {
2244 return 0;
2245 }
2246
2247 switch (product_id) {
2248 case IRECV_K_DFU_MODE:
2249 case IRECV_K_WTF_MODE:
2250 case IRECV_K_RECOVERY_MODE_1:
2251 case IRECV_K_RECOVERY_MODE_2:
2252 case IRECV_K_RECOVERY_MODE_3:
2253 case IRECV_K_RECOVERY_MODE_4:
2254 case IRECV_K_PORT_DFU_MODE:
2255 case KIS_PRODUCT_ID:
2256 break;
2257 default:
2258 return 0;
2259 }
2260 return 1;
2261}
2262
2263static void* _irecv_handle_device_add(void *userdata)
2264{
2265 struct irecv_client_private client_loc;
2266 char serial_str[256];
2267 uint32_t location = 0;
2268 uint16_t product_id = 0;
2269 irecv_error_t error = 0;
2270 irecv_client_t client = NULL;
2271
2272 memset(serial_str, 0, 256);
2273#ifdef WIN32
2274 struct irecv_win_dev_ctx *win_ctx = (struct irecv_win_dev_ctx*)userdata;
2275 PSP_DEVICE_INTERFACE_DETAIL_DATA_A details = win_ctx->details;
2276 LPSTR result = (LPSTR)details->DevicePath;
2277 location = win_ctx->location;
2278
2279 unsigned int pid = 0;
2280
2281 if (strncmp(result, "\\\\?\\kis#", 8) == 0) {
2282 pid = KIS_PRODUCT_ID;
2283 } else {
2284 char *p = result;
2285 while ((p = strstr(p, "\\usb"))) {
2286 if (sscanf(p, "\\usb#vid_05ac&pid_%04x#%s", &pid, serial_str) == 2)
2287 break;
2288 p += 4;
2289 }
2290
2291 if (serial_str[0] == '\0') {
2292 debug("%s: ERROR: failed to parse DevicePath?!\n", __func__);
2293 return NULL;
2294 }
2295
2296 if (!_irecv_is_recovery_device(p)) {
2297 return NULL;
2298 }
2299 }
2300
2301 product_id = (uint16_t)pid;
2302
2303 if (product_id == KIS_PRODUCT_ID) {
2304 client = (irecv_client_t)malloc(sizeof(struct irecv_client_private));
2305 client->handle = CreateFileA(result, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
2306 if (client->handle == INVALID_HANDLE_VALUE) {
2307 debug("%s: Failed to open device path %s\n", __func__, result);
2308 free(client);
2309 return NULL;
2310 }
2311 client->mode = pid;
2312 } else {
2313 char* p = strchr(serial_str, '#');
2314 if (p) {
2315 *p = '\0';
2316 }
2317
2318 unsigned int j;
2319 for (j = 0; j < strlen(serial_str); j++) {
2320 if (serial_str[j] == '_') {
2321 serial_str[j] = ' ';
2322 } else {
2323 serial_str[j] = toupper(serial_str[j]);
2324 }
2325 }
2326 }
2327
2328#else /* !WIN32 */
2329#ifdef HAVE_IOKIT
2330 struct irecv_iokit_dev_ctx* iokit_ctx = (struct irecv_iokit_dev_ctx*)userdata;
2331 io_service_t device = iokit_ctx->device;
2332 IOUSBDeviceInterface **dev = iokit_ctx->dev;
2333
2334 if (!device) {
2335 debug("%s: ERROR: no device?!\n", __func__);
2336 return NULL;
2337 }
2338 if (!dev) {
2339 debug("%s: ERROR: no device interface?!\n", __func__);
2340 return NULL;
2341 }
2342
2343 (*dev)->GetDeviceProduct(dev, &product_id);
2344 if (!product_id) {
2345 debug("%s: ERROR: could not get product id?!\n", __func__);
2346 return NULL;
2347 }
2348 CFNumberRef locationNum = (CFNumberRef)IORegistryEntryCreateCFProperty(device, CFSTR(kUSBDevicePropertyLocationID), kCFAllocatorDefault, 0);
2349 if (locationNum) {
2350 CFNumberGetValue(locationNum, kCFNumberSInt32Type, &location);
2351 CFRelease(locationNum);
2352 }
2353 if (!location) {
2354 debug("%s: ERROR: could not get locationID?!\n", __func__);
2355 return NULL;
2356 }
2357
2358 if (product_id == KIS_PRODUCT_ID) {
2359 IOObjectRetain(device);
2360
2361 error = iokit_usb_open_service(&client, device);
2362 if (error != IRECV_E_SUCCESS) {
2363 debug("%s: ERROR: could not open KIS device!\n", __func__);
2364 return NULL;
2365 }
2366
2367 product_id = client->mode;
2368 } else {
2369 CFStringRef serialString = (CFStringRef)IORegistryEntryCreateCFProperty(device, CFSTR(kUSBSerialNumberString), kCFAllocatorDefault, 0);
2370 if (serialString) {
2371 CFStringGetCString(serialString, serial_str, sizeof(serial_str), kCFStringEncodingUTF8);
2372 CFRelease(serialString);
2373 }
2374 }
2375#else /* !HAVE_IOKIT */
2376 libusb_device *device = (libusb_device*)userdata;
2377 struct libusb_device_descriptor devdesc;
2378 struct libusb_device_handle* usb_handle = NULL;
2379 int libusb_error;
2380
2381 libusb_error = libusb_get_device_descriptor(device, &devdesc);
2382 if (libusb_error != 0) {
2383 debug("%s: ERROR: failed to get device descriptor: %s\n", __func__, libusb_error_name(libusb_error));
2384 return NULL;
2385 }
2386 product_id = devdesc.idProduct;
2387
2388 uint8_t bus = libusb_get_bus_number(device);
2389 uint8_t address = libusb_get_device_address(device);
2390 location = (bus << 16) | address;
2391
2392 libusb_error = libusb_open(device, &usb_handle);
2393 if (usb_handle == NULL || libusb_error != 0) {
2394 debug("%s: ERROR: can't connect to device: %s\n", __func__, libusb_error_name(libusb_error));
2395 libusb_close(usb_handle);
2396 return 0;
2397 }
2398
2399 if (product_id == KIS_PRODUCT_ID) {
2400 error = libusb_usb_open_handle_with_descriptor_and_ecid(&client, usb_handle, &devdesc, 0);
2401 if (error != IRECV_E_SUCCESS) {
2402 debug("%s: ERROR: could not open KIS device!\n", __func__);
2403 return NULL;
2404 }
2405
2406 product_id = client->mode;
2407 } else {
2408 libusb_error = libusb_get_string_descriptor_ascii(usb_handle, devdesc.iSerialNumber, (unsigned char*)serial_str, 255);
2409 if (libusb_error < 0) {
2410 debug("%s: Failed to get string descriptor: %s\n", __func__, libusb_error_name(libusb_error));
2411 return 0;
2412 }
2413 libusb_close(usb_handle);
2414 }
2415#endif /* !HAVE_IOKIT */
2416#endif /* !WIN32 */
2417 memset(&client_loc, '\0', sizeof(client_loc));
2418 if (product_id == KIS_PRODUCT_ID) {
2419 error = irecv_usb_set_configuration(client, 1);
2420 if (error != IRECV_E_SUCCESS) {
2421 debug("Failed to set configuration, error %d\n", error);
2422 irecv_close(client);
2423 return NULL;
2424 }
2425
2426 error = irecv_usb_set_interface(client, 0, 0);
2427 if (error != IRECV_E_SUCCESS) {
2428 debug("Failed to set interface, error %d\n", error);
2429 irecv_close(client);
2430 return NULL;
2431 }
2432
2433 error = irecv_kis_init(client);
2434 if (error != IRECV_E_SUCCESS) {
2435 debug("irecv_kis_init failed, error %d\n", error);
2436 irecv_close(client);
2437 return NULL;
2438 }
2439
2440 error = irecv_kis_load_device_info(client);
2441 if (error != IRECV_E_SUCCESS) {
2442 debug("irecv_kis_load_device_info failed, error %d\n", error);
2443 irecv_close(client);
2444 return NULL;
2445 }
2446 debug("found device with ECID %016" PRIx64 "\n", (uint64_t)client->device_info.ecid);
2447 strncpy(serial_str, client->device_info.serial_string, 255);
2448 product_id = client->mode;
2449 client_loc.isKIS = 1;
2450 }
2451 if (client) {
2452 irecv_close(client);
2453 }
2454
2455 client_loc.mode = product_id;
2456 irecv_load_device_info_from_iboot_string(&client_loc, serial_str);
2457
2458 struct irecv_usb_device_info *usb_dev_info = (struct irecv_usb_device_info*)malloc(sizeof(struct irecv_usb_device_info));
2459 memcpy(&(usb_dev_info->device_info), &(client_loc.device_info), sizeof(struct irecv_device_info));
2460 usb_dev_info->location = location;
2461 usb_dev_info->alive = 1;
2462 usb_dev_info->mode = client_loc.mode;
2463
2464 collection_add(&devices, usb_dev_info);
2465
2466 irecv_device_event_t dev_event;
2467 dev_event.type = IRECV_DEVICE_ADD;
2468 dev_event.mode = client_loc.mode;
2469 dev_event.device_info = &(usb_dev_info->device_info);
2470
2471 mutex_lock(&listener_mutex);
2472 FOREACH(struct irecv_device_event_context* context, &listeners) {
2473 context->callback(&dev_event, context->user_data);
2474 } ENDFOREACH
2475 mutex_unlock(&listener_mutex);
2476
2477 return NULL;
2478}
2479
2480static void _irecv_handle_device_remove(struct irecv_usb_device_info *devinfo)
2481{
2482 irecv_device_event_t dev_event;
2483 dev_event.type = IRECV_DEVICE_REMOVE;
2484 dev_event.mode = 0;
2485 dev_event.device_info = &(devinfo->device_info);
2486 mutex_lock(&listener_mutex);
2487 FOREACH(struct irecv_device_event_context* context, &listeners) {
2488 context->callback(&dev_event, context->user_data);
2489 } ENDFOREACH
2490 mutex_unlock(&listener_mutex);
2491 free(devinfo->device_info.srnm);
2492 devinfo->device_info.srnm = NULL;
2493 free(devinfo->device_info.imei);
2494 devinfo->device_info.imei = NULL;
2495 free(devinfo->device_info.srtg);
2496 devinfo->device_info.srtg = NULL;
2497 free(devinfo->device_info.serial_string);
2498 devinfo->device_info.serial_string = NULL;
2499 devinfo->alive = 0;
2500 collection_remove(&devices, devinfo);
2501 free(devinfo);
2502}
2503
2504#ifndef WIN32
2505#ifdef HAVE_IOKIT
2506static void iokit_device_added(void *refcon, io_iterator_t iterator)
2507{
2508 kern_return_t kr;
2509 io_service_t device;
2510 IOCFPlugInInterface **plugInInterface = NULL;
2511 IOUSBDeviceInterface **dev = NULL;
2512 HRESULT result;
2513 SInt32 score;
2514
2515 while ((device = IOIteratorNext(iterator))) {
2516 kr = IOCreatePlugInInterfaceForService(device, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score);
2517 if ((kIOReturnSuccess != kr) || !plugInInterface) {
2518 debug("%s: ERROR: Unable to create a plug-in (%08x)\n", __func__, kr);
2519 IOObjectRelease(device);
2520 continue;
2521 }
2522 result = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID320), (LPVOID *)&dev);
2523 (*plugInInterface)->Release(plugInInterface);
2524
2525 if (result || !dev) {
2526 debug("%s: ERROR: Couldn't create a device interface (%08x)\n", __func__, (int)result);
2527 IOObjectRelease(device);
2528 continue;
2529 }
2530
2531 if (!_irecv_is_recovery_device(dev)) {
2532 (void) (*dev)->Release(dev);
2533 IOObjectRelease(device);
2534 continue;
2535 }
2536
2537 struct irecv_iokit_dev_ctx idev;
2538 idev.device = device;
2539 idev.dev = dev;
2540 _irecv_handle_device_add(&idev);
2541 (void) (*dev)->Release(dev);
2542 IOObjectRelease(device);
2543 }
2544}
2545
2546static void iokit_device_removed(void *refcon, io_iterator_t iterator)
2547{
2548 io_service_t device;
2549
2550 while ((device = IOIteratorNext(iterator))) {
2551 uint32_t location = 0;
2552 CFNumberRef locationNum = (CFNumberRef)IORegistryEntryCreateCFProperty(device, CFSTR(kUSBDevicePropertyLocationID), kCFAllocatorDefault, 0);
2553 if (locationNum) {
2554 CFNumberGetValue(locationNum, kCFNumberSInt32Type, &location);
2555 CFRelease(locationNum);
2556 }
2557 IOObjectRelease(device);
2558
2559 if (!location) {
2560 continue;
2561 }
2562
2563 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2564 if (devinfo->location == location) {
2565 _irecv_handle_device_remove(devinfo);
2566 break;
2567 }
2568 } ENDFOREACH
2569 }
2570}
2571#else /* !HAVE_IOKIT */
2572#ifdef HAVE_LIBUSB_HOTPLUG_API
2573static int _irecv_usb_hotplug_cb(libusb_context *ctx, libusb_device *device, libusb_hotplug_event event, void *user_data)
2574{
2575 if (!_irecv_is_recovery_device(device)) {
2576 return 0;
2577 }
2578 if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) {
2579 THREAD_T th_device;
2580 if (thread_new(&th_device, _irecv_handle_device_add, device) != 0) {
2581 debug("%s: FATAL: failed to create thread to handle device add\n", __func__);
2582 return 0;
2583 }
2584 thread_detach(th_device);
2585 } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) {
2586 uint8_t bus = libusb_get_bus_number(device);
2587 uint8_t address = libusb_get_device_address(device);
2588 uint32_t location = (bus << 16) | address;
2589 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2590 if (devinfo->location == location) {
2591 _irecv_handle_device_remove(devinfo);
2592 break;
2593 }
2594 } ENDFOREACH
2595 }
2596
2597 return 0;
2598}
2599#endif /* HAVE_LIBUSB_HOTPLUG_API */
2600#endif /* !HAVE_IOKIT */
2601#endif /* !WIN32 */
2602
2603struct _irecv_event_handler_info {
2604 cond_t startup_cond;
2605 mutex_t startup_mutex;
2606};
2607
2608static void *_irecv_event_handler(void* data)
2609{
2610 struct _irecv_event_handler_info* info = (struct _irecv_event_handler_info*)data;
2611#ifdef WIN32
2612 struct collection newDevices;
2613 const GUID *guids[] = { &GUID_DEVINTERFACE_KIS, &GUID_DEVINTERFACE_PORTDFU, &GUID_DEVINTERFACE_DFU, &GUID_DEVINTERFACE_IBOOT, NULL };
2614 int running = 1;
2615
2616 collection_init(&newDevices);
2617
2618 mutex_lock(&(info->startup_mutex));
2619 cond_signal(&(info->startup_cond));
2620 mutex_unlock(&(info->startup_mutex));
2621
2622 do {
2623 SP_DEVICE_INTERFACE_DATA currentInterface;
2624 HDEVINFO usbDevices;
2625 DWORD i;
2626 int k;
2627
2628 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2629 devinfo->alive = 0;
2630 } ENDFOREACH
2631
2632 for (k = 0; guids[k]; k++) {
2633 usbDevices = SetupDiGetClassDevs(guids[k], NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
2634 if (!usbDevices) {
2635 debug("%s: ERROR: SetupDiGetClassDevs failed\n", __func__);
2636 // cleanup/free newDevices
2637 FOREACH(struct irecv_win_dev_ctx *win_ctx, &newDevices) {
2638 free(win_ctx->details);
2639 collection_remove(&newDevices, win_ctx);
2640 free(win_ctx);
2641 } ENDFOREACH
2642 collection_free(&newDevices);
2643 return NULL;
2644 }
2645
2646
2647 memset(&currentInterface, '\0', sizeof(SP_DEVICE_INTERFACE_DATA));
2648 currentInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
2649 for (i = 0; usbDevices && SetupDiEnumDeviceInterfaces(usbDevices, NULL, guids[k], i, &currentInterface); i++) {
2650 DWORD requiredSize = 0;
2651 PSP_DEVICE_INTERFACE_DETAIL_DATA_A details;
2652 SetupDiGetDeviceInterfaceDetail(usbDevices, &currentInterface, NULL, 0, &requiredSize, NULL);
2653 details = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A) malloc(requiredSize);
2654 details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
2655 SP_DEVINFO_DATA devinfodata;
2656 devinfodata.cbSize = sizeof(SP_DEVINFO_DATA);
2657 if (!SetupDiGetDeviceInterfaceDetailA(usbDevices, &currentInterface, details, requiredSize, NULL, &devinfodata)) {
2658 free(details);
2659 continue;
2660 }
2661
2662 DWORD sz = REG_SZ;
2663 char driver[256];
2664 driver[0] = '\0';
2665 if (!SetupDiGetDeviceRegistryPropertyA(usbDevices, &devinfodata, SPDRP_DRIVER, &sz, (PBYTE)driver, sizeof(driver), NULL)) {
2666 debug("%s: ERROR: Failed to get driver key\n", __func__);
2667 free(details);
2668 continue;
2669 }
2670
2671 char *p = strrchr(driver, '\\');
2672 if (!p) {
2673 debug("%s: ERROR: Failed to parse device location\n", __func__);
2674 free(details);
2675 continue;
2676 }
2677 p++;
2678 uint32_t location = 0;
2679 if (!*p || strlen(p) < 4) {
2680 debug("%s: ERROR: Driver location suffix too short\n", __func__);
2681 free(details);
2682 continue;
2683 }
2684 memcpy(&location, p, 4);
2685 int found = 0;
2686
2687 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2688 if (devinfo->location == location) {
2689 devinfo->alive = 1;
2690 found = 1;
2691 break;
2692 }
2693 } ENDFOREACH
2694
2695 unsigned int pid = 0;
2696 unsigned int vid = 0;
2697 if (sscanf(details->DevicePath, "\\\\?\\%*3s#vid_%04x&pid_%04x", &vid, &pid)!= 2) {
2698 debug("%s: ERROR: failed to parse VID/PID! path: %s\n", __func__, details->DevicePath);
2699 free(details);
2700 continue;
2701 }
2702 if (vid != APPLE_VENDOR_ID) {
2703 free(details);
2704 continue;
2705 }
2706
2707 // make sure the current device is actually in the right mode for the given driver interface
2708 int skip = 0;
2709 if ((guids[k] == &GUID_DEVINTERFACE_DFU && pid != IRECV_K_DFU_MODE && pid != IRECV_K_WTF_MODE)
2710 || (guids[k] == &GUID_DEVINTERFACE_PORTDFU && pid != IRECV_K_PORT_DFU_MODE)
2711 || (guids[k] == &GUID_DEVINTERFACE_IBOOT && (pid < IRECV_K_RECOVERY_MODE_1 || pid > IRECV_K_RECOVERY_MODE_4))
2712 || (guids[k] == &GUID_DEVINTERFACE_KIS && pid != 1)
2713 ) {
2714 skip = 1;
2715 }
2716
2717 if (!found && !skip) {
2718 // Add device to newDevices list, and deliver the notification later, when removed devices are first handled.
2719 struct irecv_win_dev_ctx *win_ctx = (struct irecv_win_dev_ctx*)malloc(sizeof(struct irecv_win_dev_ctx));
2720 win_ctx->details = details;
2721 win_ctx->location = location;
2722 collection_add(&newDevices, win_ctx);
2723 details = NULL;
2724 }
2725 free(details);
2726 }
2727 SetupDiDestroyDeviceInfoList(usbDevices);
2728 }
2729
2730 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2731 if (!devinfo->alive) {
2732 debug("%s: removed ecid: %016" PRIx64 ", location: %d\n",__func__, (uint64_t)devinfo->device_info.ecid, devinfo->location);
2733 _irecv_handle_device_remove(devinfo);
2734 }
2735 } ENDFOREACH
2736
2737 // handle newly added devices and remove from local list
2738 FOREACH(struct irecv_win_dev_ctx *win_ctx, &newDevices) {
2739 debug("%s: found new: %s, location: %d\n", __func__, win_ctx->details->DevicePath, win_ctx->location);
2740 _irecv_handle_device_add(win_ctx);
2741 free(win_ctx->details);
2742 collection_remove(&newDevices, win_ctx);
2743 free(win_ctx);
2744 } ENDFOREACH
2745
2746 Sleep(500);
2747 mutex_lock(&listener_mutex);
2748 if (collection_count(&listeners) == 0) {
2749 running = 0;
2750 }
2751 mutex_unlock(&listener_mutex);
2752 } while (running);
2753
2754 collection_free(&newDevices);
2755#else /* !WIN32 */
2756#ifdef HAVE_IOKIT
2757 kern_return_t kr;
2758
2759 IONotificationPortRef notifyPort = IONotificationPortCreate(MACH_PORT_NULL);
2760 CFRunLoopSourceRef runLoopSource = IONotificationPortGetRunLoopSource(notifyPort);
2761 iokit_runloop = CFRunLoopGetCurrent();
2762 CFRunLoopAddSource(iokit_runloop, runLoopSource, kCFRunLoopDefaultMode);
2763
2764 uint16_t pids[9] = { IRECV_K_WTF_MODE, IRECV_K_DFU_MODE, IRECV_K_RECOVERY_MODE_1, IRECV_K_RECOVERY_MODE_2, IRECV_K_RECOVERY_MODE_3, IRECV_K_RECOVERY_MODE_4, IRECV_K_PORT_DFU_MODE, KIS_PRODUCT_ID, 0 };
2765 int i = 0;
2766 while (pids[i] > 0) {
2767 CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
2768 iokit_cfdictionary_set_short(matchingDict, CFSTR(kUSBVendorID), kAppleVendorID);
2769 iokit_cfdictionary_set_short(matchingDict, CFSTR(kUSBProductID), pids[i]);
2770
2771 matchingDict = (CFMutableDictionaryRef)CFRetain(matchingDict);
2772
2773 io_iterator_t devAddedIter;
2774 kr = IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, matchingDict, iokit_device_added, NULL, &devAddedIter);
2775 if (kr != kIOReturnSuccess) {
2776 debug("%s: Failed to register device add notification callback\n", __func__);
2777 }
2778 iokit_device_added(NULL, devAddedIter);
2779
2780 io_iterator_t devRemovedIter;
2781 kr = IOServiceAddMatchingNotification(notifyPort, kIOTerminatedNotification, matchingDict, iokit_device_removed, NULL, &devRemovedIter);
2782 if (kr != kIOReturnSuccess) {
2783 debug("%s: Failed to register device remove notification callback\n", __func__);
2784 }
2785 iokit_device_removed(NULL, devRemovedIter);
2786
2787 i++;
2788 }
2789
2790 mutex_lock(&(info->startup_mutex));
2791 cond_signal(&(info->startup_cond));
2792 mutex_unlock(&(info->startup_mutex));
2793
2794 CFRunLoopRun();
2795
2796#else /* !HAVE_IOKIT */
2797#ifdef HAVE_LIBUSB_HOTPLUG_API
2798 static libusb_hotplug_callback_handle usb_hotplug_cb_handle;
2799 libusb_hotplug_register_callback(irecv_hotplug_ctx, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, LIBUSB_HOTPLUG_ENUMERATE, APPLE_VENDOR_ID, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, _irecv_usb_hotplug_cb, NULL, &usb_hotplug_cb_handle);
2800 int running = 1;
2801
2802 mutex_lock(&(info->startup_mutex));
2803 cond_signal(&(info->startup_cond));
2804 mutex_unlock(&(info->startup_mutex));
2805
2806 do {
2807 struct timeval tv;
2808 tv.tv_sec = tv.tv_usec = 0;
2809 libusb_handle_events_timeout(irecv_hotplug_ctx, &tv);
2810
2811 mutex_lock(&listener_mutex);
2812 if (collection_count(&listeners) == 0) {
2813 running = 0;
2814 }
2815 mutex_unlock(&listener_mutex);
2816
2817 usleep(100000);
2818 } while (running);
2819 libusb_hotplug_deregister_callback(irecv_hotplug_ctx, usb_hotplug_cb_handle);
2820#else /* !HAVE_LIBUSB_HOTPLUG_API */
2821 int i, cnt;
2822 libusb_device **devs;
2823 int running = 1;
2824
2825 mutex_lock(&(info->startup_mutex));
2826 cond_signal(&(info->startup_cond));
2827 mutex_unlock(&(info->startup_mutex));
2828
2829 do {
2830 cnt = libusb_get_device_list(irecv_hotplug_ctx, &devs);
2831 if (cnt < 0) {
2832 debug("%s: FATAL: Failed to get device list: %s\n", __func__, libusb_error_name(cnt));
2833 return NULL;
2834 }
2835
2836 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2837 devinfo->alive = 0;
2838 } ENDFOREACH
2839
2840 for (i = 0; i < cnt; i++) {
2841 libusb_device *dev = devs[i];
2842 if (!_irecv_is_recovery_device(dev)) {
2843 continue;
2844 }
2845 uint8_t bus = libusb_get_bus_number(dev);
2846 uint8_t address = libusb_get_device_address(dev);
2847 uint32_t location = (bus << 16) | address;
2848 int found = 0;
2849 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2850 if (devinfo->location == location) {
2851 devinfo->alive = 1;
2852 found = 1;
2853 break;
2854 }
2855 } ENDFOREACH
2856 if (!found) {
2857 _irecv_handle_device_add(dev);
2858 }
2859 }
2860
2861 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2862 if (!devinfo->alive) {
2863 _irecv_handle_device_remove(devinfo);
2864 }
2865 } ENDFOREACH
2866
2867 libusb_free_device_list(devs, 1);
2868
2869 mutex_lock(&listener_mutex);
2870 if (collection_count(&listeners) == 0) {
2871 running = 0;
2872 }
2873 mutex_unlock(&listener_mutex);
2874 if (!running)
2875 break;
2876 usleep(500000);
2877 } while (running);
2878#endif /* !HAVE_LIBUSB_HOTPLUG_API */
2879#endif /* !HAVE_IOKIT */
2880#endif /* !WIN32 */
2881 return NULL;
2882}
2883#endif /* !USE_DUMMY */
2884
2885irecv_error_t irecv_device_event_subscribe(irecv_device_event_context_t *context, irecv_device_event_cb_t callback, void *user_data)
2886{
2887#ifdef USE_DUMMY
2888 return IRECV_E_UNSUPPORTED;
2889#else
2890 if (!context || !callback)
2891 return IRECV_E_INVALID_INPUT;
2892
2893 struct irecv_device_event_context* _context = malloc(sizeof(struct irecv_device_event_context));
2894 if (!_context) {
2895 return IRECV_E_OUT_OF_MEMORY;
2896 }
2897
2898 _context->callback = callback;
2899 _context->user_data = user_data;
2900
2901 mutex_lock(&listener_mutex);
2902 collection_add(&listeners, _context);
2903
2904 if (th_event_handler == THREAD_T_NULL || !thread_alive(th_event_handler)) {
2905 mutex_unlock(&listener_mutex);
2906 struct _irecv_event_handler_info info;
2907 cond_init(&info.startup_cond);
2908 mutex_init(&info.startup_mutex);
2909#ifndef WIN32
2910#ifndef HAVE_IOKIT
2911 libusb_init(&irecv_hotplug_ctx);
2912#endif
2913#endif
2914 collection_init(&devices);
2915 mutex_init(&device_mutex);
2916 mutex_lock(&info.startup_mutex);
2917 if (thread_new(&th_event_handler, _irecv_event_handler, &info) == 0) {
2918 cond_wait(&info.startup_cond, &info.startup_mutex);
2919 }
2920 mutex_unlock(&info.startup_mutex);
2921 cond_destroy(&info.startup_cond);
2922 mutex_destroy(&info.startup_mutex);
2923 } else {
2924 /* send DEVICE_ADD events to the new listener */
2925 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2926 if (devinfo && devinfo->alive) {
2927 irecv_device_event_t ev;
2928 ev.type = IRECV_DEVICE_ADD;
2929 ev.mode = devinfo->mode;
2930 ev.device_info = &(devinfo->device_info);
2931 _context->callback(&ev, _context->user_data);
2932 }
2933 } ENDFOREACH
2934 mutex_unlock(&listener_mutex);
2935 }
2936
2937 *context = _context;
2938
2939 return IRECV_E_SUCCESS;
2940#endif
2941}
2942
2943irecv_error_t irecv_device_event_unsubscribe(irecv_device_event_context_t context)
2944{
2945#ifdef USE_DUMMY
2946 return IRECV_E_UNSUPPORTED;
2947#else
2948 if (!context)
2949 return IRECV_E_INVALID_INPUT;
2950
2951 mutex_lock(&listener_mutex);
2952 collection_remove(&listeners, context);
2953 int num = collection_count(&listeners);
2954 mutex_unlock(&listener_mutex);
2955
2956 if (num == 0 && th_event_handler != THREAD_T_NULL && thread_alive(th_event_handler)) {
2957#ifdef HAVE_IOKIT
2958 if (iokit_runloop) {
2959 CFRunLoopStop(iokit_runloop);
2960 iokit_runloop = NULL;
2961 }
2962#endif
2963 thread_join(th_event_handler);
2964 thread_free(th_event_handler);
2965 th_event_handler = THREAD_T_NULL;
2966 mutex_lock(&device_mutex);
2967 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2968 free(devinfo->device_info.srnm);
2969 devinfo->device_info.srnm = NULL;
2970 free(devinfo->device_info.imei);
2971 devinfo->device_info.imei = NULL;
2972 free(devinfo->device_info.srtg);
2973 devinfo->device_info.srtg = NULL;
2974 free(devinfo->device_info.serial_string);
2975 devinfo->device_info.serial_string = NULL;
2976 free(devinfo);
2977 } ENDFOREACH
2978 collection_free(&devices);
2979 mutex_unlock(&device_mutex);
2980 mutex_destroy(&device_mutex);
2981#ifndef WIN32
2982#ifndef HAVE_IOKIT
2983 libusb_exit(irecv_hotplug_ctx);
2984 irecv_hotplug_ctx = NULL;
2985#endif
2986#endif
2987 }
2988
2989 free(context);
2990
2991 return IRECV_E_SUCCESS;
2992#endif
218} 2993}
219 2994
220irecv_error_t irecv_close(irecv_client_t client) { 2995irecv_error_t irecv_close(irecv_client_t client)
2996{
2997#ifdef USE_DUMMY
2998 return IRECV_E_UNSUPPORTED;
2999#else
221 if (client != NULL) { 3000 if (client != NULL) {
222 if(client->disconnected_callback != NULL) { 3001 if (client->disconnected_callback != NULL) {
223 irecv_event_t event; 3002 irecv_event_t event;
224 event.size = 0; 3003 event.size = 0;
225 event.data = NULL; 3004 event.data = NULL;
@@ -227,114 +3006,164 @@ irecv_error_t irecv_close(irecv_client_t client) {
227 event.type = IRECV_DISCONNECTED; 3006 event.type = IRECV_DISCONNECTED;
228 client->disconnected_callback(client, &event); 3007 client->disconnected_callback(client, &event);
229 } 3008 }
230 3009#ifndef WIN32
3010#ifdef HAVE_IOKIT
3011 if (client->usbInterface) {
3012 (*client->usbInterface)->USBInterfaceClose(client->usbInterface);
3013 (*client->usbInterface)->Release(client->usbInterface);
3014 client->usbInterface = NULL;
3015 }
3016 if (client->handle) {
3017 (*client->handle)->USBDeviceClose(client->handle);
3018 (*client->handle)->Release(client->handle);
3019 client->handle = NULL;
3020 }
3021#else
231 if (client->handle != NULL) { 3022 if (client->handle != NULL) {
232 libusb_release_interface(client->handle, client->interface); 3023 if ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_PORT_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE) && (client->isKIS == 0)) {
3024 libusb_release_interface(client->handle, client->usb_interface);
3025 }
233 libusb_close(client->handle); 3026 libusb_close(client->handle);
234 client->handle = NULL; 3027 client->handle = NULL;
235 } 3028 }
236 3029#endif
237 if (libirecovery_context != NULL) { 3030#else
238 libusb_exit(libirecovery_context); 3031 CloseHandle(client->handle);
239 libirecovery_context = NULL; 3032#endif
240 } 3033 free(client->device_info.srnm);
3034 free(client->device_info.imei);
3035 free(client->device_info.srtg);
3036 free(client->device_info.serial_string);
3037 free(client->device_info.ap_nonce);
3038 free(client->device_info.sep_nonce);
241 3039
242 free(client); 3040 free(client);
243 client = NULL; 3041 client = NULL;
244 } 3042 }
245 3043
246 return IRECV_E_SUCCESS; 3044 return IRECV_E_SUCCESS;
3045#endif
247} 3046}
248 3047
249void irecv_set_debug_level(int level) { 3048void irecv_set_debug_level(int level)
3049{
250 libirecovery_debug = level; 3050 libirecovery_debug = level;
251 if(libirecovery_context) { 3051#ifndef USE_DUMMY
252 libusb_set_debug(libirecovery_context, libirecovery_debug); 3052#ifndef WIN32
3053#ifndef HAVE_IOKIT
3054 if (libirecovery_context) {
3055#if LIBUSB_API_VERSION >= 0x01000106
3056 libusb_set_option(libirecovery_context, LIBUSB_OPTION_LOG_LEVEL, libirecovery_debug > 2 ? 1: 0);
3057#else
3058 libusb_set_debug(libirecovery_context, libirecovery_debug > 2 ? 1: 0);
3059#endif
253 } 3060 }
3061#endif
3062#endif
3063#endif
254} 3064}
255 3065
256static irecv_error_t irecv_send_command_raw(irecv_client_t client, unsigned char* command) { 3066const char* irecv_version()
3067{
3068#ifndef PACKAGE_VERSION
3069#error PACKAGE_VERSION is not defined!
3070#endif
3071 return PACKAGE_VERSION;
3072}
3073
3074
3075#ifndef USE_DUMMY
3076static irecv_error_t irecv_send_command_raw(irecv_client_t client, const char* command, uint8_t b_request)
3077{
257 unsigned int length = strlen(command); 3078 unsigned int length = strlen(command);
258 if (length >= 0x100) { 3079 if (length >= 0x100) {
259 length = 0xFF; 3080 return IRECV_E_INVALID_INPUT;
260 } 3081 }
261 3082
262 if (length > 0) { 3083 if (length > 0) {
263 int ret = libusb_control_transfer(client->handle, 0x40, 0, 0, 0, command, length + 1, 100); 3084 irecv_usb_control_transfer(client, 0x40, b_request, 0, 0, (unsigned char*) command, length + 1, USB_TIMEOUT);
264 if ((ret < 0) || (ret != (length + 1))) {
265 if (ret == LIBUSB_ERROR_PIPE)
266 return IRECV_E_PIPE;
267 if (ret == LIBUSB_ERROR_TIMEOUT)
268 return IRECV_E_TIMEOUT;
269 return IRECV_E_UNKNOWN_ERROR;
270 }
271 } 3085 }
272 3086
273 return IRECV_E_SUCCESS; 3087 return IRECV_E_SUCCESS;
274} 3088}
3089#endif
275 3090
276irecv_error_t irecv_send_command(irecv_client_t client, unsigned char* command) { 3091irecv_error_t irecv_send_command_breq(irecv_client_t client, const char* command, uint8_t b_request)
3092{
3093#ifdef USE_DUMMY
3094 return IRECV_E_UNSUPPORTED;
3095#else
277 irecv_error_t error = 0; 3096 irecv_error_t error = 0;
278 3097
279 if (client == NULL || client->handle == NULL) { 3098 if (check_context(client) != IRECV_E_SUCCESS)
280 return IRECV_E_NO_DEVICE; 3099 return IRECV_E_NO_DEVICE;
281 }
282 3100
283 unsigned int length = strlen(command); 3101 unsigned int length = strlen(command);
284 if (length >= 0x100) { 3102 if (length >= 0x100) {
285 length = 0xFF; 3103 return IRECV_E_INVALID_INPUT;
286 } 3104 }
287 3105
288 irecv_event_t event; 3106 irecv_event_t event;
289 if(client->precommand_callback != NULL) { 3107 if (client->precommand_callback != NULL) {
290 event.size = length; 3108 event.size = length;
291 event.data = command; 3109 event.data = command;
292 event.type = IRECV_PRECOMMAND; 3110 event.type = IRECV_PRECOMMAND;
293 if(client->precommand_callback(client, &event)) { 3111 if (client->precommand_callback(client, &event)) {
294 return IRECV_E_SUCCESS; 3112 return IRECV_E_SUCCESS;
295 } 3113 }
296 } 3114 }
297 3115
298 error = irecv_send_command_raw(client, command); 3116 error = irecv_send_command_raw(client, command, b_request);
299 if (error != IRECV_E_SUCCESS) { 3117 if (error != IRECV_E_SUCCESS) {
300 debug("Failed to send command %s\n", command); 3118 debug("Failed to send command %s\n", command);
301 if (error != IRECV_E_PIPE) 3119 if (error != IRECV_E_PIPE)
302 return error; 3120 return error;
303 } 3121 }
304 3122
305 if(client->postcommand_callback != NULL) { 3123 if (client->postcommand_callback != NULL) {
306 event.size = length; 3124 event.size = length;
307 event.data = command; 3125 event.data = command;
308 event.type = IRECV_POSTCOMMAND; 3126 event.type = IRECV_POSTCOMMAND;
309 if(client->postcommand_callback(client, &event)) { 3127 if (client->postcommand_callback(client, &event)) {
310 return IRECV_E_SUCCESS; 3128 return IRECV_E_SUCCESS;
311 } 3129 }
312 } 3130 }
313 3131
314 return IRECV_E_SUCCESS; 3132 return IRECV_E_SUCCESS;
3133#endif
315} 3134}
316 3135
317irecv_error_t irecv_send_file(irecv_client_t client, const char* filename) { 3136irecv_error_t irecv_send_command(irecv_client_t client, const char* command)
318 if (client == NULL || client->handle == NULL) { 3137{
3138 return irecv_send_command_breq(client, command, 0);
3139}
3140
3141irecv_error_t irecv_send_file(irecv_client_t client, const char* filename, unsigned int options)
3142{
3143#ifdef USE_DUMMY
3144 return IRECV_E_UNSUPPORTED;
3145#else
3146 if (check_context(client) != IRECV_E_SUCCESS)
319 return IRECV_E_NO_DEVICE; 3147 return IRECV_E_NO_DEVICE;
320 }
321 3148
322 FILE* file = fopen(filename, "rb"); 3149 FILE* file = fopen(filename, "rb");
323 if (file == NULL) { 3150 if (file == NULL) {
324 return IRECV_E_FILE_NOT_FOUND; 3151 return IRECV_E_FILE_NOT_FOUND;
325 } 3152 }
326 3153
327 fseek(file, 0, SEEK_END); 3154 struct stat fst;
328 long length = ftell(file); 3155 if (fstat(fileno(file), &fst) < 0) {
329 fseek(file, 0, SEEK_SET); 3156 return IRECV_E_UNKNOWN_ERROR;
3157 }
3158 size_t length = fst.st_size;
330 3159
331 unsigned char* buffer = (unsigned char*) malloc(length); 3160 char* buffer = (char*)malloc(length);
332 if (buffer == NULL) { 3161 if (buffer == NULL) {
333 fclose(file); 3162 fclose(file);
334 return IRECV_E_OUT_OF_MEMORY; 3163 return IRECV_E_OUT_OF_MEMORY;
335 } 3164 }
336 3165
337 long bytes = fread(buffer, 1, length, file); 3166 size_t bytes = fread(buffer, 1, length, file);
338 fclose(file); 3167 fclose(file);
339 3168
340 if (bytes != length) { 3169 if (bytes != length) {
@@ -342,53 +3171,179 @@ irecv_error_t irecv_send_file(irecv_client_t client, const char* filename) {
342 return IRECV_E_UNKNOWN_ERROR; 3171 return IRECV_E_UNKNOWN_ERROR;
343 } 3172 }
344 3173
345 irecv_error_t error = irecv_send_buffer(client, buffer, length); 3174 irecv_error_t error = irecv_send_buffer(client, (unsigned char*)buffer, length, options);
346 free(buffer); 3175 free(buffer);
3176
347 return error; 3177 return error;
3178#endif
348} 3179}
349 3180
350irecv_error_t irecv_get_status(irecv_client_t client, unsigned int* status) { 3181#ifndef USE_DUMMY
351 if (client == NULL || client->handle == NULL) { 3182static irecv_error_t irecv_get_status(irecv_client_t client, unsigned int* status)
3183{
3184 if (check_context(client) != IRECV_E_SUCCESS) {
352 *status = 0; 3185 *status = 0;
353 return IRECV_E_NO_DEVICE; 3186 return IRECV_E_NO_DEVICE;
354 } 3187 }
355 3188
356 unsigned char buffer[6]; 3189 unsigned char buffer[6];
357 memset(buffer, '\0', 6); 3190 memset(buffer, '\0', 6);
358 if (libusb_control_transfer(client->handle, 0xA1, 3, 0, 0, buffer, 6, 1000) != 6) { 3191 if (irecv_usb_control_transfer(client, 0xA1, 3, 0, 0, buffer, 6, USB_TIMEOUT) != 6) {
359 *status = 0; 3192 *status = 0;
360 return IRECV_E_USB_STATUS; 3193 return IRECV_E_USB_STATUS;
361 } 3194 }
362 3195
363 *status = (unsigned int) buffer[4]; 3196 *status = (unsigned int) buffer[4];
3197
3198 return IRECV_E_SUCCESS;
3199}
3200
3201static irecv_error_t irecv_kis_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned long length, unsigned int options)
3202{
3203 if (client->mode != IRECV_K_DFU_MODE) {
3204 return IRECV_E_UNSUPPORTED;
3205 }
3206
3207 unsigned long origLen = length;
3208
3209 KIS_upload_chunk *chunk = calloc(1, sizeof(KIS_upload_chunk));
3210 uint64_t address = 0;
3211 while (length) {
3212 unsigned long toUpload = length;
3213 if (toUpload > 0x4000)
3214 toUpload = 0x4000;
3215
3216#ifdef WIN32
3217 memcpy(chunk->data, buffer, toUpload);
3218 chunk->size = toUpload;
3219 chunk->address = address;
3220#else
3221 irecv_error_t error = irecv_kis_request_init(&chunk->hdr, KIS_PORTAL_RSM, KIS_INDEX_UPLOAD, 3, toUpload, 0);
3222 if (error != IRECV_E_SUCCESS) {
3223 free(chunk);
3224 debug("Failed to init chunk header, error %d\n", error);
3225 return error;
3226 }
3227
3228 chunk->address = address;
3229 chunk->size = toUpload;
3230 memcpy(chunk->data, buffer, toUpload);
3231#endif
3232
3233#ifdef WIN32
3234 DWORD transferred = 0;
3235 int ret = DeviceIoControl(client->handle, 0x220008, chunk, sizeof(*chunk), NULL, 0, (PDWORD)&transferred, NULL);
3236 irecv_error_t error = (ret) ? IRECV_E_SUCCESS : IRECV_E_USB_UPLOAD;
3237#else
3238 KIS_generic_reply reply;
3239 size_t rcvSize = sizeof(reply);
3240 error = irecv_kis_request(client, &chunk->hdr, sizeof(*chunk) - (0x4000 - toUpload), &reply.hdr, &rcvSize);
3241#endif
3242 if (error != IRECV_E_SUCCESS) {
3243 free(chunk);
3244 debug("Failed to upload chunk, error %d\n", error);
3245 return error;
3246 }
3247
3248 address += toUpload;
3249 buffer += toUpload;
3250 length -= toUpload;
3251
3252 if (client->progress_callback != NULL) {
3253 irecv_event_t event;
3254 event.progress = ((double) (origLen - length) / (double) origLen) * 100.0;
3255 event.type = IRECV_PROGRESS;
3256 event.data = (char*)"Uploading";
3257 event.size = origLen - length;
3258 client->progress_callback(client, &event);
3259 } else {
3260 debug("Sent: %lu bytes - %lu of %lu\n", toUpload, origLen - length, origLen);
3261 }
3262 }
3263 free(chunk);
3264
3265 if (options & IRECV_SEND_OPT_DFU_NOTIFY_FINISH) {
3266#ifdef WIN32
3267 DWORD amount = (DWORD)origLen;
3268 DWORD transferred = 0;
3269 int ret = DeviceIoControl(client->handle, 0x22000C, &amount, 4, NULL, 0, (PDWORD)&transferred, NULL);
3270 irecv_error_t error = (ret) ? IRECV_E_SUCCESS : IRECV_E_USB_UPLOAD;
3271#else
3272 irecv_error_t error = irecv_kis_config_write32(client, KIS_PORTAL_RSM, KIS_INDEX_BOOT_IMG, origLen);
3273#endif
3274 if (error != IRECV_E_SUCCESS) {
3275 debug("Failed to boot image, error %d\n", error);
3276 return error;
3277 }
3278 }
3279
364 return IRECV_E_SUCCESS; 3280 return IRECV_E_SUCCESS;
365} 3281}
3282#endif
3283
3284irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned long length, unsigned int options)
3285{
3286#ifdef USE_DUMMY
3287 return IRECV_E_UNSUPPORTED;
3288#else
3289 if (client->isKIS)
3290 return irecv_kis_send_buffer(client, buffer, length, options);
366 3291
367irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned long length) {
368 irecv_error_t error = 0; 3292 irecv_error_t error = 0;
369 int recovery_mode = (client->mode != kDfuMode); 3293 int recovery_mode = ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_PORT_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE));
370 3294
371 if (client == NULL || client->handle == NULL) { 3295 if (check_context(client) != IRECV_E_SUCCESS)
372 return IRECV_E_NO_DEVICE; 3296 return IRECV_E_NO_DEVICE;
373 }
374 3297
375 int packet_size = recovery_mode ? 0x4000: 0x800; 3298 unsigned int h1 = 0xFFFFFFFF;
3299 unsigned char dfu_xbuf[12] = {0xff, 0xff, 0xff, 0xff, 0xac, 0x05, 0x00, 0x01, 0x55, 0x46, 0x44, 0x10};
3300 int dfu_crc = 1;
3301 int packet_size = recovery_mode ? 0x8000 : 0x800;
3302 if (!recovery_mode && (options & IRECV_SEND_OPT_DFU_SMALL_PKT)) {
3303 packet_size = 0x40;
3304 dfu_crc = 0;
3305 }
376 int last = length % packet_size; 3306 int last = length % packet_size;
377 int packets = length / packet_size; 3307 int packets = length / packet_size;
3308
378 if (last != 0) { 3309 if (last != 0) {
379 packets++; 3310 packets++;
3311 } else {
3312 last = packet_size;
380 } 3313 }
381 3314
382 /* initiate transfer */ 3315 /* initiate transfer */
383 if (recovery_mode) { 3316 if (recovery_mode) {
384 error = libusb_control_transfer(client->handle, 0x41, 0, 0, 0, NULL, 0, 1000); 3317 error = irecv_usb_control_transfer(client, 0x41, 0, 0, 0, NULL, 0, USB_TIMEOUT);
385 if (error != IRECV_E_SUCCESS) { 3318 } else {
386 return error; 3319 uint8_t state = 0;
3320 if (irecv_usb_control_transfer(client, 0xa1, 5, 0, 0, (unsigned char*)&state, 1, USB_TIMEOUT) == 1) {
3321 error = IRECV_E_SUCCESS;
3322 } else {
3323 return IRECV_E_USB_UPLOAD;
3324 }
3325 switch (state) {
3326 case 2:
3327 /* DFU IDLE */
3328 break;
3329 case 10:
3330 debug("DFU ERROR, issuing CLRSTATUS\n");
3331 irecv_usb_control_transfer(client, 0x21, 4, 0, 0, NULL, 0, USB_TIMEOUT);
3332 error = IRECV_E_USB_UPLOAD;
3333 break;
3334 default:
3335 debug("Unexpected state %d, issuing ABORT\n", state);
3336 irecv_usb_control_transfer(client, 0x21, 6, 0, 0, NULL, 0, USB_TIMEOUT);
3337 error = IRECV_E_USB_UPLOAD;
3338 break;
387 } 3339 }
388 } 3340 }
389 3341
3342 if (error != IRECV_E_SUCCESS) {
3343 return error;
3344 }
3345
390 int i = 0; 3346 int i = 0;
391 double progress = 0;
392 unsigned long count = 0; 3347 unsigned long count = 0;
393 unsigned int status = 0; 3348 unsigned int status = 0;
394 int bytes = 0; 3349 int bytes = 0;
@@ -397,9 +3352,48 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un
397 3352
398 /* Use bulk transfer for recovery mode and control transfer for DFU and WTF mode */ 3353 /* Use bulk transfer for recovery mode and control transfer for DFU and WTF mode */
399 if (recovery_mode) { 3354 if (recovery_mode) {
400 error = libusb_bulk_transfer(client->handle, 0x04, &buffer[i * packet_size], size, &bytes, 1000); 3355 error = irecv_usb_bulk_transfer(client, 0x04, &buffer[i * packet_size], size, &bytes, USB_TIMEOUT);
401 } else { 3356 } else {
402 bytes = libusb_control_transfer(client->handle, 0x21, 1, 0, 0, &buffer[i * packet_size], size, 1000); 3357 if (dfu_crc) {
3358 int j;
3359 for (j = 0; j < size; j++) {
3360 crc32_step(h1, buffer[i*packet_size + j]);
3361 }
3362 }
3363 if (dfu_crc && i+1 == packets) {
3364 int j;
3365 if (size+16 > packet_size) {
3366 bytes = irecv_usb_control_transfer(client, 0x21, 1, i, 0, &buffer[i * packet_size], size, USB_TIMEOUT);
3367 if (bytes != size) {
3368 return IRECV_E_USB_UPLOAD;
3369 }
3370 count += size;
3371 size = 0;
3372 }
3373 for (j = 0; j < 2; j++) {
3374 crc32_step(h1, dfu_xbuf[j*6 + 0]);
3375 crc32_step(h1, dfu_xbuf[j*6 + 1]);
3376 crc32_step(h1, dfu_xbuf[j*6 + 2]);
3377 crc32_step(h1, dfu_xbuf[j*6 + 3]);
3378 crc32_step(h1, dfu_xbuf[j*6 + 4]);
3379 crc32_step(h1, dfu_xbuf[j*6 + 5]);
3380 }
3381
3382 char* newbuf = (char*)malloc(size + 16);
3383 if (size > 0) {
3384 memcpy(newbuf, &buffer[i * packet_size], size);
3385 }
3386 memcpy(newbuf+size, dfu_xbuf, 12);
3387 newbuf[size+12] = h1 & 0xFF;
3388 newbuf[size+13] = (h1 >> 8) & 0xFF;
3389 newbuf[size+14] = (h1 >> 16) & 0xFF;
3390 newbuf[size+15] = (h1 >> 24) & 0xFF;
3391 size += 16;
3392 bytes = irecv_usb_control_transfer(client, 0x21, 1, i, 0, (unsigned char*)newbuf, size, USB_TIMEOUT);
3393 free(newbuf);
3394 } else {
3395 bytes = irecv_usb_control_transfer(client, 0x21, 1, i, 0, &buffer[i * packet_size], size, USB_TIMEOUT);
3396 }
403 } 3397 }
404 3398
405 if (bytes != size) { 3399 if (bytes != size) {
@@ -415,44 +3409,81 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un
415 } 3409 }
416 3410
417 if (!recovery_mode && status != 5) { 3411 if (!recovery_mode && status != 5) {
418 return IRECV_E_USB_UPLOAD; 3412 int retry = 0;
3413
3414 while (retry++ < 20) {
3415 irecv_get_status(client, &status);
3416 if (status == 5) {
3417 break;
3418 }
3419 sleep(1);
3420 }
3421
3422 if (status != 5) {
3423 return IRECV_E_USB_UPLOAD;
3424 }
419 } 3425 }
420 3426
421 count += size; 3427 count += size;
422 if(client->progress_callback != NULL) { 3428 if (client->progress_callback != NULL) {
423 irecv_event_t event; 3429 irecv_event_t event;
424 event.progress = ((double) count/ (double) length) * 100.0; 3430 event.progress = ((double) count/ (double) length) * 100.0;
425 event.type = IRECV_PROGRESS; 3431 event.type = IRECV_PROGRESS;
426 event.data = "Uploading"; 3432 event.data = (char*)"Uploading";
427 event.size = count; 3433 event.size = count;
428 client->progress_callback(client, &event); 3434 client->progress_callback(client, &event);
429 } else { 3435 } else {
430 debug("Sent: %d bytes - %d of %d\n", bytes, count, length); 3436 debug("Sent: %d bytes - %lu of %lu\n", bytes, count, length);
431 } 3437 }
432 } 3438 }
433 3439
434 if (!recovery_mode) { 3440 if (recovery_mode && length % 512 == 0) {
435 libusb_control_transfer(client->handle, 0x21, 1, 0, 0, buffer, 0, 1000); 3441 /* send a ZLP */
436 for (i = 0; i < 3; i++) { 3442 bytes = 0;
3443 irecv_usb_bulk_transfer(client, 0x04, buffer, 0, &bytes, USB_TIMEOUT);
3444 }
3445
3446 if ((options & IRECV_SEND_OPT_DFU_NOTIFY_FINISH) && !recovery_mode) {
3447 irecv_usb_control_transfer(client, 0x21, 1, packets, 0, (unsigned char*) buffer, 0, USB_TIMEOUT);
3448
3449 for (i = 0; i < 2; i++) {
437 error = irecv_get_status(client, &status); 3450 error = irecv_get_status(client, &status);
438 if (error != IRECV_E_SUCCESS) { 3451 if (error != IRECV_E_SUCCESS) {
439 return error; 3452 return error;
440 } 3453 }
441 } 3454 }
3455
3456 if ((options & IRECV_SEND_OPT_DFU_FORCE_ZLP)) {
3457 /* we send a pseudo ZLP here just in case */
3458 irecv_usb_control_transfer(client, 0x21, 1, 0, 0, 0, 0, USB_TIMEOUT);
3459 }
3460
3461 irecv_reset(client);
442 } 3462 }
443 3463
444 return IRECV_E_SUCCESS; 3464 return IRECV_E_SUCCESS;
3465#endif
445} 3466}
446 3467
447irecv_error_t irecv_receive(irecv_client_t client) { 3468irecv_error_t irecv_receive(irecv_client_t client)
448 unsigned char buffer[BUFFER_SIZE]; 3469{
3470#ifdef USE_DUMMY
3471 return IRECV_E_UNSUPPORTED;
3472#else
3473 char buffer[BUFFER_SIZE];
449 memset(buffer, '\0', BUFFER_SIZE); 3474 memset(buffer, '\0', BUFFER_SIZE);
450 if (client == NULL || client->handle == NULL) { 3475
3476 if (check_context(client) != IRECV_E_SUCCESS)
451 return IRECV_E_NO_DEVICE; 3477 return IRECV_E_NO_DEVICE;
452 }
453 3478
454 int bytes = 0; 3479 int bytes = 0;
455 while (libusb_bulk_transfer(client->handle, 0x81, buffer, BUFFER_SIZE, &bytes, 100) == 0) { 3480 while (1) {
3481 irecv_usb_set_interface(client, 1, 1);
3482 int r = irecv_usb_bulk_transfer(client, 0x81, (unsigned char*) buffer, BUFFER_SIZE, &bytes, 500);
3483 irecv_usb_set_interface(client, 0, 0);
3484 if (r != 0) {
3485 break;
3486 }
456 if (bytes > 0) { 3487 if (bytes > 0) {
457 if (client->received_callback != NULL) { 3488 if (client->received_callback != NULL) {
458 irecv_event_t event; 3489 irecv_event_t event;
@@ -460,155 +3491,288 @@ irecv_error_t irecv_receive(irecv_client_t client) {
460 event.data = buffer; 3491 event.data = buffer;
461 event.type = IRECV_RECEIVED; 3492 event.type = IRECV_RECEIVED;
462 if (client->received_callback(client, &event) != 0) { 3493 if (client->received_callback(client, &event) != 0) {
463 return IRECV_E_SUCCESS; 3494 break;
464 } 3495 }
465 } 3496 }
466 } else break; 3497 } else break;
467 } 3498 }
468
469 return IRECV_E_SUCCESS; 3499 return IRECV_E_SUCCESS;
3500#endif
470} 3501}
471 3502
472irecv_error_t irecv_getenv(irecv_client_t client, const char* variable, char** value) { 3503irecv_error_t irecv_getenv(irecv_client_t client, const char* variable, char** value)
3504{
3505#ifdef USE_DUMMY
3506 return IRECV_E_UNSUPPORTED;
3507#else
473 char command[256]; 3508 char command[256];
474 if (client == NULL || client->handle == NULL) { 3509
3510 if (check_context(client) != IRECV_E_SUCCESS)
475 return IRECV_E_NO_DEVICE; 3511 return IRECV_E_NO_DEVICE;
476 }
477 3512
478 *value = NULL; 3513 *value = NULL;
479 3514
480 if(variable == NULL) { 3515 if (variable == NULL) {
481 return IRECV_E_UNKNOWN_ERROR; 3516 return IRECV_E_INVALID_INPUT;
482 } 3517 }
483 3518
484 memset(command, '\0', sizeof(command)); 3519 memset(command, '\0', sizeof(command));
485 snprintf(command, sizeof(command)-1, "getenv %s", variable); 3520 snprintf(command, sizeof(command)-1, "getenv %s", variable);
486 irecv_error_t error = irecv_send_command_raw(client, command); 3521 irecv_error_t error = irecv_send_command_raw(client, command, 0);
487 if(error == IRECV_E_PIPE) 3522 if (error == IRECV_E_PIPE) {
488 return IRECV_E_SUCCESS; 3523 return IRECV_E_SUCCESS;
489 if(error != IRECV_E_SUCCESS) 3524 }
3525
3526 if (error != IRECV_E_SUCCESS) {
490 return error; 3527 return error;
3528 }
491 3529
492 unsigned char* response = (unsigned char*) malloc(256); 3530 char* response = (char*) malloc(256);
493 if (response == NULL) { 3531 if (response == NULL) {
494 return IRECV_E_OUT_OF_MEMORY; 3532 return IRECV_E_OUT_OF_MEMORY;
495 } 3533 }
496 3534
497 memset(response, '\0', 256); 3535 memset(response, '\0', 256);
498 int ret = libusb_control_transfer(client->handle, 0xC0, 0, 0, 0, response, 255, 500); 3536 irecv_usb_control_transfer(client, 0xC0, 0, 0, 0, (unsigned char*) response, 255, USB_TIMEOUT);
499 if (ret < 0)
500 return IRECV_E_UNKNOWN_ERROR;
501 3537
502 *value = response; 3538 *value = response;
3539
503 return IRECV_E_SUCCESS; 3540 return IRECV_E_SUCCESS;
3541#endif
504} 3542}
505 3543
506irecv_error_t irecv_get_cpid(irecv_client_t client, unsigned int* cpid) { 3544irecv_error_t irecv_getret(irecv_client_t client, unsigned int* value)
507 if (client == NULL || client->handle == NULL) { 3545{
3546#ifdef USE_DUMMY
3547 return IRECV_E_UNSUPPORTED;
3548#else
3549 if (check_context(client) != IRECV_E_SUCCESS)
508 return IRECV_E_NO_DEVICE; 3550 return IRECV_E_NO_DEVICE;
509 }
510 3551
511 unsigned char* cpid_string = strstr(client->serial, "CPID:"); 3552 *value = 0;
512 if (cpid_string == NULL) { 3553
513 *cpid = 0; 3554 char* response = (char*) malloc(256);
514 return IRECV_E_UNKNOWN_ERROR; 3555 if (response == NULL) {
3556 return IRECV_E_OUT_OF_MEMORY;
515 } 3557 }
516 sscanf(cpid_string, "CPID:%d", cpid); 3558
3559 memset(response, '\0', 256);
3560 irecv_usb_control_transfer(client, 0xC0, 0, 0, 0, (unsigned char*) response, 255, USB_TIMEOUT);
3561
3562 *value = (unsigned int) *response;
517 3563
518 return IRECV_E_SUCCESS; 3564 return IRECV_E_SUCCESS;
3565#endif
519} 3566}
520 3567
521irecv_error_t irecv_get_bdid(irecv_client_t client, unsigned int* bdid) { 3568irecv_error_t irecv_get_mode(irecv_client_t client, int* mode)
522 if (client == NULL || client->handle == NULL) { 3569{
3570#ifdef USE_DUMMY
3571 return IRECV_E_UNSUPPORTED;
3572#else
3573 if (check_context(client) != IRECV_E_SUCCESS)
523 return IRECV_E_NO_DEVICE; 3574 return IRECV_E_NO_DEVICE;
524 }
525 3575
526 unsigned char* bdid_string = strstr(client->serial, "BDID:"); 3576 *mode = client->mode;
527 if (bdid_string == NULL) {
528 *bdid = 0;
529 return IRECV_E_UNKNOWN_ERROR;
530 }
531 sscanf(bdid_string, "BDID:%d", bdid);
532 3577
533 return IRECV_E_SUCCESS; 3578 return IRECV_E_SUCCESS;
3579#endif
534} 3580}
535 3581
536irecv_error_t irecv_get_ecid(irecv_client_t client, unsigned long long* ecid) { 3582const struct irecv_device_info* irecv_get_device_info(irecv_client_t client)
537 if (client == NULL || client->handle == NULL) { 3583{
538 return IRECV_E_NO_DEVICE; 3584#ifdef USE_DUMMY
539 } 3585 return NULL;
540 3586#else
541 unsigned char* ecid_string = strstr(client->serial, "ECID:"); 3587 if (check_context(client) != IRECV_E_SUCCESS)
542 if (ecid_string == NULL) { 3588 return NULL;
543 *ecid = 0;
544 return IRECV_E_UNKNOWN_ERROR;
545 }
546 sscanf(ecid_string, "ECID:%qX", ecid);
547 3589
548 return IRECV_E_SUCCESS; 3590 return &client->device_info;
3591#endif
549} 3592}
550 3593
551irecv_error_t irecv_send_exploit(irecv_client_t client) { 3594#ifndef USE_DUMMY
552 if (client == NULL || client->handle == NULL) { 3595#ifdef HAVE_IOKIT
3596static void *iokit_limera1n_usb_submit_request(void *argv)
3597{
3598 void **args = argv;
3599 IOUSBDeviceInterface320 **dev = args[0];
3600 IOUSBDevRequest *req = args[1];
3601
3602 IOReturn result = (*dev)->DeviceRequest(dev, req);
3603 if (result != kIOReturnSuccess)
3604 debug("%s result: %#x\n", __func__, result);
3605
3606 return NULL;
3607}
3608#endif
3609#endif
3610
3611irecv_error_t irecv_trigger_limera1n_exploit(irecv_client_t client)
3612{
3613#ifdef USE_DUMMY
3614 return IRECV_E_UNSUPPORTED;
3615#else
3616 if (check_context(client) != IRECV_E_SUCCESS)
553 return IRECV_E_NO_DEVICE; 3617 return IRECV_E_NO_DEVICE;
3618
3619#ifdef HAVE_IOKIT
3620 IOReturn result;
3621 IOUSBDevRequestTO req;
3622 bzero(&req, sizeof(req));
3623
3624 req.bmRequestType = 0x21;
3625 req.bRequest = 2;
3626 req.wValue = 0;
3627 req.wIndex = 0;
3628 req.wLength = 0;
3629 req.pData = NULL;
3630 req.noDataTimeout = USB_TIMEOUT;
3631 req.completionTimeout = USB_TIMEOUT;
3632
3633 // The original version uses an async request, but we don't have an async event
3634 // source set up. The hack relies on aborting the transaction before it times out,
3635 // which can be accomplished by sending on another thread.
3636
3637 void *args[2] = { client->handle, &req };
3638 THREAD_T thread;
3639 thread_new(&thread, iokit_limera1n_usb_submit_request, args);
3640
3641 usleep(5 * 1000);
3642 result = (*client->handle)->USBDeviceAbortPipeZero(client->handle);
3643 if (result != kIOReturnSuccess)
3644 debug("USBDeviceAbortPipeZero returned %#x\n", result);
3645
3646 switch (result) {
3647 case kIOReturnSuccess: return req.wLenDone;
3648 case kIOReturnTimeout: return IRECV_E_TIMEOUT;
3649 case kIOUSBTransactionTimeout: return IRECV_E_TIMEOUT;
3650 case kIOReturnNotResponding: return IRECV_E_NO_DEVICE;
3651 case kIOReturnNoDevice: return IRECV_E_NO_DEVICE;
3652 default:
3653 return IRECV_E_UNKNOWN_ERROR;
554 } 3654 }
3655#else
3656 irecv_usb_control_transfer(client, 0x21, 2, 0, 0, NULL, 0, USB_TIMEOUT);
3657#endif
555 3658
556 libusb_control_transfer(client->handle, 0x21, 2, 0, 0, NULL, 0, 100);
557 return IRECV_E_SUCCESS; 3659 return IRECV_E_SUCCESS;
3660#endif
558} 3661}
559 3662
560irecv_error_t irecv_execute_script(irecv_client_t client, const char* filename) { 3663irecv_error_t irecv_execute_script(irecv_client_t client, const char* script)
3664{
3665#ifdef USE_DUMMY
3666 return IRECV_E_UNSUPPORTED;
3667#else
561 irecv_error_t error = IRECV_E_SUCCESS; 3668 irecv_error_t error = IRECV_E_SUCCESS;
562 if (client == NULL || client->handle == NULL) { 3669 if (check_context(client) != IRECV_E_SUCCESS)
563 return IRECV_E_NO_DEVICE; 3670 return IRECV_E_NO_DEVICE;
564 }
565 3671
566 int file_size = 0; 3672 char* body = strdup(script);
567 char* file_data = NULL; 3673 char* line = strtok(body, "\n");
568 if(irecv_read_file(filename, &file_data, &file_size) < 0) {
569 return IRECV_E_FILE_NOT_FOUND;
570 }
571 3674
572 char* line = strtok(file_data, "\n"); 3675 while (line != NULL) {
573 while(line != NULL) { 3676 if (line[0] != '#') {
574 if(line[0] != '#') {
575 error = irecv_send_command(client, line); 3677 error = irecv_send_command(client, line);
576 if(error != IRECV_E_SUCCESS) { 3678 if (error != IRECV_E_SUCCESS) {
577 return error; 3679 break;
578 } 3680 }
579 3681
580 error = irecv_receive(client); 3682 error = irecv_receive(client);
581 if(error != IRECV_E_SUCCESS) { 3683 if (error != IRECV_E_SUCCESS) {
582 return error; 3684 break;
583 } 3685 }
584 } 3686 }
585 line = strtok(NULL, "\n"); 3687 line = strtok(NULL, "\n");
586 } 3688 }
587 3689
3690 free(body);
3691
3692 return error;
3693#endif
3694}
3695
3696irecv_error_t irecv_saveenv(irecv_client_t client)
3697{
3698#ifdef USE_DUMMY
3699 return IRECV_E_UNSUPPORTED;
3700#else
3701 irecv_error_t error = irecv_send_command_raw(client, "saveenv", 0);
3702 if (error != IRECV_E_SUCCESS) {
3703 return error;
3704 }
3705
588 return IRECV_E_SUCCESS; 3706 return IRECV_E_SUCCESS;
3707#endif
589} 3708}
590 3709
591irecv_error_t irecv_setenv(irecv_client_t client, const char* variable, const char* value) { 3710irecv_error_t irecv_setenv(irecv_client_t client, const char* variable, const char* value)
3711{
3712#ifdef USE_DUMMY
3713 return IRECV_E_UNSUPPORTED;
3714#else
592 char command[256]; 3715 char command[256];
593 if (client == NULL || client->handle == NULL) { 3716
3717 if (check_context(client) != IRECV_E_SUCCESS)
594 return IRECV_E_NO_DEVICE; 3718 return IRECV_E_NO_DEVICE;
595 }
596 3719
597 if(variable == NULL || value == NULL) { 3720 if (variable == NULL || value == NULL) {
598 return IRECV_E_UNKNOWN_ERROR; 3721 return IRECV_E_UNKNOWN_ERROR;
599 } 3722 }
600 3723
601 memset(command, '\0', sizeof(command)); 3724 memset(command, '\0', sizeof(command));
602 snprintf(command, sizeof(command)-1, "setenv %s %s", variable, value); 3725 snprintf(command, sizeof(command)-1, "setenv %s %s", variable, value);
603 irecv_error_t error = irecv_send_command_raw(client, command); 3726 irecv_error_t error = irecv_send_command_raw(client, command, 0);
604 if(error != IRECV_E_SUCCESS) { 3727 if (error != IRECV_E_SUCCESS) {
3728 return error;
3729 }
3730
3731 return IRECV_E_SUCCESS;
3732#endif
3733}
3734
3735irecv_error_t irecv_setenv_np(irecv_client_t client, const char* variable, const char* value)
3736{
3737#ifdef USE_DUMMY
3738 return IRECV_E_UNSUPPORTED;
3739#else
3740 char command[256];
3741
3742 if (check_context(client) != IRECV_E_SUCCESS)
3743 return IRECV_E_NO_DEVICE;
3744
3745 if (variable == NULL || value == NULL) {
3746 return IRECV_E_UNKNOWN_ERROR;
3747 }
3748
3749 memset(command, '\0', sizeof(command));
3750 snprintf(command, sizeof(command)-1, "setenvnp %s %s", variable, value);
3751 irecv_error_t error = irecv_send_command_raw(client, command, 0);
3752 if (error != IRECV_E_SUCCESS) {
3753 return error;
3754 }
3755
3756 return IRECV_E_SUCCESS;
3757#endif
3758}
3759
3760irecv_error_t irecv_reboot(irecv_client_t client)
3761{
3762#ifdef USE_DUMMY
3763 return IRECV_E_UNSUPPORTED;
3764#else
3765 irecv_error_t error = irecv_send_command_raw(client, "reboot", 0);
3766 if (error != IRECV_E_SUCCESS) {
605 return error; 3767 return error;
606 } 3768 }
607 3769
608 return IRECV_E_SUCCESS; 3770 return IRECV_E_SUCCESS;
3771#endif
609} 3772}
610 3773
611const char* irecv_strerror(irecv_error_t error) { 3774const char* irecv_strerror(irecv_error_t error)
3775{
612 switch (error) { 3776 switch (error) {
613 case IRECV_E_SUCCESS: 3777 case IRECV_E_SUCCESS:
614 return "Command completed successfully"; 3778 return "Command completed successfully";
@@ -646,6 +3810,9 @@ const char* irecv_strerror(irecv_error_t error) {
646 case IRECV_E_TIMEOUT: 3810 case IRECV_E_TIMEOUT:
647 return "Timeout talking to device"; 3811 return "Timeout talking to device";
648 3812
3813 case IRECV_E_UNSUPPORTED:
3814 return "Operation unsupported by driver";
3815
649 default: 3816 default:
650 return "Unknown error"; 3817 return "Unknown error";
651 } 3818 }
@@ -653,64 +3820,215 @@ const char* irecv_strerror(irecv_error_t error) {
653 return NULL; 3820 return NULL;
654} 3821}
655 3822
656int irecv_write_file(const char* filename, const void* data, size_t size) { 3823irecv_error_t irecv_reset_counters(irecv_client_t client)
657 size_t bytes = 0; 3824{
658 FILE* file = NULL; 3825#ifdef USE_DUMMY
3826 return IRECV_E_UNSUPPORTED;
3827#else
3828 if (check_context(client) != IRECV_E_SUCCESS)
3829 return IRECV_E_NO_DEVICE;
659 3830
660 debug("Writing data to %s\n", filename); 3831 if ((client->mode == IRECV_K_DFU_MODE) || (client->mode == IRECV_K_PORT_DFU_MODE) || (client->mode == IRECV_K_WTF_MODE)) {
661 file = fopen(filename, "wb"); 3832 irecv_usb_control_transfer(client, 0x21, 4, 0, 0, 0, 0, USB_TIMEOUT);
662 if (file == NULL) {
663 error("read_file: Unable to open file %s\n", filename);
664 return -1;
665 } 3833 }
666 3834
667 bytes = fwrite(data, 1, size, file); 3835 return IRECV_E_SUCCESS;
668 fclose(file); 3836#endif
3837}
669 3838
670 if (bytes != size) { 3839irecv_error_t irecv_recv_buffer(irecv_client_t client, char* buffer, unsigned long length)
671 error("ERROR: Unable to write entire file: %s: %d of %d\n", filename, bytes, size); 3840{
672 return -1; 3841#ifdef USE_DUMMY
3842 return IRECV_E_UNSUPPORTED;
3843#else
3844 int recovery_mode = ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_PORT_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE));
3845
3846 if (check_context(client) != IRECV_E_SUCCESS)
3847 return IRECV_E_NO_DEVICE;
3848
3849 int packet_size = recovery_mode ? 0x2000: 0x800;
3850 int last = length % packet_size;
3851 int packets = length / packet_size;
3852 if (last != 0) {
3853 packets++;
3854 } else {
3855 last = packet_size;
673 } 3856 }
674 3857
675 return size; 3858 int i = 0;
3859 int bytes = 0;
3860 unsigned long count = 0;
3861 for (i = 0; i < packets; i++) {
3862 unsigned short size = (i+1) < packets ? packet_size : last;
3863 bytes = irecv_usb_control_transfer(client, 0xA1, 2, 0, 0, (unsigned char*)&buffer[i * packet_size], size, USB_TIMEOUT);
3864
3865 if (bytes != size) {
3866 return IRECV_E_USB_UPLOAD;
3867 }
3868
3869 count += size;
3870 if (client->progress_callback != NULL) {
3871 irecv_event_t event;
3872 event.progress = ((double) count/ (double) length) * 100.0;
3873 event.type = IRECV_PROGRESS;
3874 event.data = (char*)"Downloading";
3875 event.size = count;
3876 client->progress_callback(client, &event);
3877 } else {
3878 debug("Sent: %d bytes - %lu of %lu\n", bytes, count, length);
3879 }
3880 }
3881
3882 return IRECV_E_SUCCESS;
3883#endif
676} 3884}
677 3885
678int irecv_read_file(const char* filename, char** data, uint32_t* size) { 3886irecv_error_t irecv_finish_transfer(irecv_client_t client)
679 size_t bytes = 0; 3887{
680 size_t length = 0; 3888#ifdef USE_DUMMY
681 FILE* file = NULL; 3889 return IRECV_E_UNSUPPORTED;
682 char* buffer = NULL; 3890#else
683 debug("Reading data from %s\n", filename); 3891 int i = 0;
3892 unsigned int status = 0;
684 3893
685 *size = 0; 3894 if (check_context(client) != IRECV_E_SUCCESS)
686 *data = NULL; 3895 return IRECV_E_NO_DEVICE;
687 3896
688 file = fopen(filename, "rb"); 3897 irecv_usb_control_transfer(client, 0x21, 1, 0, 0, 0, 0, USB_TIMEOUT);
689 if (file == NULL) { 3898
690 error("read_file: File %s not found\n", filename); 3899 for (i = 0; i < 3; i++){
691 return -1; 3900 irecv_get_status(client, &status);
692 } 3901 }
693 3902
694 fseek(file, 0, SEEK_END); 3903 irecv_reset(client);
695 length = ftell(file);
696 rewind(file);
697 3904
698 buffer = (char*) malloc(length); 3905 return IRECV_E_SUCCESS;
699 if(buffer == NULL) { 3906#endif
700 error("ERROR: Out of memory\n"); 3907}
701 fclose(file); 3908
702 return -1; 3909irecv_device_t irecv_devices_get_all(void)
3910{
3911 return irecv_devices;
3912}
3913
3914irecv_error_t irecv_devices_get_device_by_client(irecv_client_t client, irecv_device_t* device)
3915{
3916#ifdef USE_DUMMY
3917 return IRECV_E_UNSUPPORTED;
3918#else
3919 int i = 0;
3920
3921 if (!client || !device)
3922 return IRECV_E_INVALID_INPUT;
3923
3924 *device = NULL;
3925
3926 if (client->device_info.cpid == 0) {
3927 return IRECV_E_UNKNOWN_ERROR;
703 } 3928 }
704 bytes = fread(buffer, 1, length, file);
705 fclose(file);
706 3929
707 if(bytes != length) { 3930 unsigned int cpid_match = client->device_info.cpid;
708 error("ERROR: Unable to read entire file\n"); 3931 unsigned int bdid_match = client->device_info.bdid;
709 free(buffer); 3932 if (client->mode == IRECV_K_PORT_DFU_MODE) {
710 return -1; 3933 cpid_match = (client->device_info.bdid >> 8) & 0xFFFF;
3934 bdid_match = (client->device_info.bdid >> 24) & 0xFF;
711 } 3935 }
712 3936
713 *size = length; 3937 for (i = 0; irecv_devices[i].hardware_model != NULL; i++) {
714 *data = buffer; 3938 if (irecv_devices[i].chip_id == cpid_match && irecv_devices[i].board_id == bdid_match) {
715 return 0; 3939 *device = &irecv_devices[i];
3940 return IRECV_E_SUCCESS;
3941 }
3942 }
3943
3944 return IRECV_E_NO_DEVICE;
3945#endif
3946}
3947
3948irecv_error_t irecv_devices_get_device_by_product_type(const char* product_type, irecv_device_t* device)
3949{
3950 int i = 0;
3951
3952 if (!product_type || !device)
3953 return IRECV_E_INVALID_INPUT;
3954
3955 *device = NULL;
3956
3957 for (i = 0; irecv_devices[i].product_type != NULL; i++) {
3958 if (!strcmp(product_type, irecv_devices[i].product_type)) {
3959 *device = &irecv_devices[i];
3960 return IRECV_E_SUCCESS;
3961 }
3962 }
3963
3964 return IRECV_E_NO_DEVICE;
3965}
3966
3967irecv_error_t irecv_devices_get_device_by_hardware_model(const char* hardware_model, irecv_device_t* device)
3968{
3969 int i = 0;
3970
3971 if (!hardware_model || !device)
3972 return IRECV_E_INVALID_INPUT;
3973
3974 *device = NULL;
3975
3976 for (i = 0; irecv_devices[i].hardware_model != NULL; i++) {
3977 if (!strcasecmp(hardware_model, irecv_devices[i].hardware_model)) {
3978 *device = &irecv_devices[i];
3979 return IRECV_E_SUCCESS;
3980 }
3981 }
3982
3983 return IRECV_E_NO_DEVICE;
3984}
3985
3986irecv_client_t irecv_reconnect(irecv_client_t client, int initial_pause)
3987{
3988#ifdef USE_DUMMY
3989 return NULL;
3990#else
3991 irecv_error_t error = 0;
3992 irecv_client_t new_client = NULL;
3993 irecv_event_cb_t progress_callback = client->progress_callback;
3994 irecv_event_cb_t received_callback = client->received_callback;
3995 irecv_event_cb_t connected_callback = client->connected_callback;
3996 irecv_event_cb_t precommand_callback = client->precommand_callback;
3997 irecv_event_cb_t postcommand_callback = client->postcommand_callback;
3998 irecv_event_cb_t disconnected_callback = client->disconnected_callback;
3999
4000 uint64_t ecid = client->device_info.ecid;
4001
4002 if (check_context(client) == IRECV_E_SUCCESS) {
4003 irecv_close(client);
4004 }
4005
4006 if (initial_pause > 0) {
4007 debug("Waiting %d seconds for the device to pop up...\n", initial_pause);
4008 sleep(initial_pause);
4009 }
4010
4011 error = irecv_open_with_ecid_and_attempts(&new_client, ecid, 10);
4012 if (error != IRECV_E_SUCCESS) {
4013 return NULL;
4014 }
4015
4016 new_client->progress_callback = progress_callback;
4017 new_client->received_callback = received_callback;
4018 new_client->connected_callback = connected_callback;
4019 new_client->precommand_callback = precommand_callback;
4020 new_client->postcommand_callback = postcommand_callback;
4021 new_client->disconnected_callback = disconnected_callback;
4022
4023 if (new_client->connected_callback != NULL) {
4024 irecv_event_t event;
4025 event.size = 0;
4026 event.data = NULL;
4027 event.progress = 0;
4028 event.type = IRECV_CONNECTED;
4029 new_client->connected_callback(new_client, &event);
4030 }
4031
4032 return new_client;
4033#endif
716} 4034}