summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2012-07-04 13:53:07 +0200
committerGravatar Nikias Bassen2012-07-04 13:53:07 +0200
commitd3232fcba2f1267723bc087e0751ab463489b25b (patch)
treecae8028cdf6f6da87e6bc2f8f0ac27554bed8469
parent09ddfb9c0b3f9ee5ad399ef860976295fb4dc890 (diff)
downloadlibirecovery-d3232fcba2f1267723bc087e0751ab463489b25b.tar.gz
libirecovery-d3232fcba2f1267723bc087e0751ab463489b25b.tar.bz2
win32: fix device detection/selection by ecid
-rw-r--r--include/libirecovery.h1
-rw-r--r--libirecovery.c162
2 files changed, 123 insertions, 40 deletions
diff --git a/include/libirecovery.h b/include/libirecovery.h
index 9272ab4..0af73e6 100644
--- a/include/libirecovery.h
+++ b/include/libirecovery.h
@@ -29,6 +29,7 @@ extern "C" {
29#else 29#else
30#define WIN32_LEAN_AND_MEAN 30#define WIN32_LEAN_AND_MEAN
31#include <windows.h> 31#include <windows.h>
32#undef interface
32#define sleep(n) Sleep(1000 * n) 33#define sleep(n) Sleep(1000 * n)
33#endif 34#endif
34 35
diff --git a/libirecovery.c b/libirecovery.c
index f8f33ca..0c166ff 100644
--- a/libirecovery.c
+++ b/libirecovery.c
@@ -25,10 +25,14 @@
25 25
26#ifndef WIN32 26#ifndef WIN32
27#include <libusb-1.0/libusb.h> 27#include <libusb-1.0/libusb.h>
28#define _FMT_qX "%qX"
29#define _FMT_016llx "%016llx"
28#else 30#else
29#define WIN32_LEAN_AND_MEAN 31#define WIN32_LEAN_AND_MEAN
30#include <windows.h> 32#include <windows.h>
31#include <setupapi.h> 33#include <setupapi.h>
34#define _FMT_qX "%I64X"
35#define _FMT_016llx "%016I64x"
32#endif 36#endif
33 37
34#include "libirecovery.h" 38#include "libirecovery.h"
@@ -130,86 +134,157 @@ typedef struct usb_control_request {
130 char data[]; 134 char data[];
131} usb_control_request; 135} usb_control_request;
132 136
137int irecv_get_string_descriptor_ascii(irecv_client_t client, uint8_t desc_index, unsigned char * buffer, int size);
138
133irecv_error_t mobiledevice_openpipes(irecv_client_t client); 139irecv_error_t mobiledevice_openpipes(irecv_client_t client);
134void mobiledevice_closepipes(irecv_client_t client); 140void mobiledevice_closepipes(irecv_client_t client);
135 141
136irecv_error_t mobiledevice_connect(irecv_client_t* client) { 142irecv_error_t mobiledevice_connect(irecv_client_t* client, unsigned long long ecid) {
137 irecv_error_t ret; 143 irecv_error_t ret;
138 144 int found = 0;
139 SP_DEVICE_INTERFACE_DATA currentInterface; 145 SP_DEVICE_INTERFACE_DATA currentInterface;
140 HDEVINFO usbDevices; 146 HDEVINFO usbDevices;
141 DWORD i; 147 DWORD i;
142 LPSTR path;
143 irecv_client_t _client = (irecv_client_t) malloc(sizeof(struct irecv_client)); 148 irecv_client_t _client = (irecv_client_t) malloc(sizeof(struct irecv_client));
144 memset(_client, 0, sizeof(struct irecv_client)); 149 memset(_client, 0, sizeof(struct irecv_client));
145 150
146 // Get DFU paths 151 // Get DFU paths
147 usbDevices = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DFU, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); 152 usbDevices = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DFU, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
148 if(!usbDevices) { 153 memset(&currentInterface, '\0', sizeof(SP_DEVICE_INTERFACE_DATA));
149 return IRECV_E_UNABLE_TO_CONNECT;
150 }
151 currentInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); 154 currentInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
152 for(i = 0; SetupDiEnumDeviceInterfaces(usbDevices, NULL, &GUID_DEVINTERFACE_DFU, i, &currentInterface); i++) { 155 for(i = 0; usbDevices && SetupDiEnumDeviceInterfaces(usbDevices, NULL, &GUID_DEVINTERFACE_DFU, i, &currentInterface); i++) {
156 if (_client->DfuPath) {
157 free(_client->DfuPath);
158 _client->DfuPath = NULL;
159 }
160 _client->handle = NULL;
153 DWORD requiredSize = 0; 161 DWORD requiredSize = 0;
154 PSP_DEVICE_INTERFACE_DETAIL_DATA details; 162 PSP_DEVICE_INTERFACE_DETAIL_DATA details;
155 SetupDiGetDeviceInterfaceDetail(usbDevices, &currentInterface, NULL, 0, &requiredSize, NULL); 163 SetupDiGetDeviceInterfaceDetail(usbDevices, &currentInterface, NULL, 0, &requiredSize, NULL);
156 details = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(requiredSize); 164 details = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(requiredSize);
157 details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); 165 details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
158 if(!SetupDiGetDeviceInterfaceDetail(usbDevices, &currentInterface, details, requiredSize, NULL, NULL)) { 166 if(!SetupDiGetDeviceInterfaceDetail(usbDevices, &currentInterface, details, requiredSize, NULL, NULL)) {
159 irecv_close(_client);
160 free(details); 167 free(details);
161 SetupDiDestroyDeviceInfoList(usbDevices); 168 continue;
162 return IRECV_E_UNABLE_TO_CONNECT;
163 } else { 169 } else {
164 LPSTR result = (LPSTR) malloc(requiredSize - sizeof(DWORD)); 170 LPSTR result = (LPSTR) malloc(requiredSize - sizeof(DWORD));
165 memcpy((void*) result, details->DevicePath, requiredSize - sizeof(DWORD)); 171 memcpy((void*) result, details->DevicePath, requiredSize - sizeof(DWORD));
166 free(details); 172 free(details);
167 path = (LPSTR) malloc(requiredSize - sizeof(DWORD)); 173
168 memcpy((void*) path, (void*) result, requiredSize - sizeof(DWORD));
169 TCHAR* pathEnd = strstr(path, "#{");
170 *pathEnd = '\0';
171 _client->DfuPath = result; 174 _client->DfuPath = result;
175 if (mobiledevice_openpipes(_client) != IRECV_E_SUCCESS) {
176 mobiledevice_closepipes(_client);
177 continue;
178 }
179
180 if ((ecid != 0) && (_client->mode == kWTFMode)) {
181 // we can't get ecid in WTF mode
182 mobiledevice_closepipes(_client);
183 continue;
184 }
185
186 _client->serial[0] = '\0';
187 irecv_get_string_descriptor_ascii(_client, 3, (unsigned char*)_client->serial, 255);
188 if (_client->serial[0] == '\0') {
189 mobiledevice_closepipes(_client);
190 continue;
191 }
192
193 if (ecid != 0) {
194 char* ecid_string = strstr(_client->serial, "ECID:");
195 if (ecid_string == NULL) {
196 debug("%s: could not get ECID for device\n", __func__);
197 mobiledevice_closepipes(_client);
198 continue;
199 }
200
201 unsigned long long this_ecid = 0;
202 sscanf(ecid_string, "ECID:" _FMT_qX, (unsigned long long*)&this_ecid);
203 if (this_ecid != ecid) {
204 mobiledevice_closepipes(_client);
205 continue;
206 }
207 debug("found device with ECID " _FMT_016llx "\n", (unsigned long long)ecid);
208 }
209 found = 1;
172 break; 210 break;
173 } 211 }
174 } 212 }
175 SetupDiDestroyDeviceInfoList(usbDevices); 213 SetupDiDestroyDeviceInfoList(usbDevices);
214
215 if (found) {
216 *client = _client;
217 return IRECV_E_SUCCESS;
218 }
219
176 // Get iBoot path 220 // Get iBoot path
177 usbDevices = SetupDiGetClassDevs(&GUID_DEVINTERFACE_IBOOT, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); 221 usbDevices = SetupDiGetClassDevs(&GUID_DEVINTERFACE_IBOOT, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
178 if(!usbDevices) { 222 memset(&currentInterface, '\0', sizeof(SP_DEVICE_INTERFACE_DATA));
179 irecv_close(_client);
180 return IRECV_E_UNABLE_TO_CONNECT;
181 }
182 currentInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); 223 currentInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
183 for(i = 0; SetupDiEnumDeviceInterfaces(usbDevices, NULL, &GUID_DEVINTERFACE_IBOOT, i, &currentInterface); i++) { 224 for(i = 0; usbDevices && SetupDiEnumDeviceInterfaces(usbDevices, NULL, &GUID_DEVINTERFACE_IBOOT, i, &currentInterface); i++) {
225 if (_client->iBootPath) {
226 free(_client->iBootPath);
227 _client->iBootPath = NULL;
228 }
229 _client->handle = NULL;
184 DWORD requiredSize = 0; 230 DWORD requiredSize = 0;
185 PSP_DEVICE_INTERFACE_DETAIL_DATA details; 231 PSP_DEVICE_INTERFACE_DETAIL_DATA details;
186 SetupDiGetDeviceInterfaceDetail(usbDevices, &currentInterface, NULL, 0, &requiredSize, NULL); 232 SetupDiGetDeviceInterfaceDetail(usbDevices, &currentInterface, NULL, 0, &requiredSize, NULL);
187 details = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(requiredSize); 233 details = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(requiredSize);
188 details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); 234 details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
189 if(!SetupDiGetDeviceInterfaceDetail(usbDevices, &currentInterface, details, requiredSize, NULL, NULL)) { 235 if(!SetupDiGetDeviceInterfaceDetail(usbDevices, &currentInterface, details, requiredSize, NULL, NULL)) {
190 irecv_close(_client);
191 free(details); 236 free(details);
192 SetupDiDestroyDeviceInfoList(usbDevices); 237 continue;
193 return IRECV_E_UNABLE_TO_CONNECT;
194 } else { 238 } else {
195 LPSTR result = (LPSTR) malloc(requiredSize - sizeof(DWORD)); 239 LPSTR result = (LPSTR) malloc(requiredSize - sizeof(DWORD));
196 memcpy((void*) result, details->DevicePath, requiredSize - sizeof(DWORD)); 240 memcpy((void*) result, details->DevicePath, requiredSize - sizeof(DWORD));
197 free(details); 241 free(details);
198 242
199 if(strstr(result, path) == NULL) { 243 _client->iBootPath = result;
200 free(result); 244 if (mobiledevice_openpipes(_client) != IRECV_E_SUCCESS) {
245 mobiledevice_closepipes(_client);
201 continue; 246 continue;
202 } 247 }
203 248
204 _client->iBootPath = result; 249 if ((ecid != 0) && (_client->mode == kWTFMode)) {
250 // we can't get ecid in WTF mode
251 mobiledevice_closepipes(_client);
252 continue;
253 }
254
255 _client->serial[0] = '\0';
256 irecv_get_string_descriptor_ascii(_client, 3, (unsigned char*)_client->serial, 255);
257 if (_client->serial[0] == '\0') {
258 mobiledevice_closepipes(_client);
259 continue;
260 }
261
262 if (ecid != 0) {
263 char* ecid_string = strstr(_client->serial, "ECID:");
264 if (ecid_string == NULL) {
265 debug("%s: could not get ECID for device\n", __func__);
266 mobiledevice_closepipes(_client);
267 continue;
268 }
269
270 unsigned long long this_ecid = 0;
271 sscanf(ecid_string, "ECID:" _FMT_qX, (unsigned long long*)&this_ecid);
272 if (this_ecid != ecid) {
273 mobiledevice_closepipes(_client);
274 continue;
275 }
276 debug("found device with ECID " _FMT_016llx" \n", (unsigned long long)ecid);
277 }
278 found = 1;
205 break; 279 break;
206 } 280 }
207 } 281 }
208 SetupDiDestroyDeviceInfoList(usbDevices); 282 SetupDiDestroyDeviceInfoList(usbDevices);
209 free(path); 283
210 284 if (!found) {
211 ret = mobiledevice_openpipes(_client); 285 irecv_close(_client);
212 if (ret != IRECV_E_SUCCESS) return ret; 286 return IRECV_E_UNABLE_TO_CONNECT;
287 }
213 288
214 *client = _client; 289 *client = _client;
215 return IRECV_E_SUCCESS; 290 return IRECV_E_SUCCESS;
@@ -225,14 +300,24 @@ irecv_error_t mobiledevice_openpipes(irecv_client_t client) {
225 return IRECV_E_UNABLE_TO_CONNECT; 300 return IRECV_E_UNABLE_TO_CONNECT;
226 } 301 }
227 302
303 client->mode = 0;
228 if (client->iBootPath == NULL) { 304 if (client->iBootPath == NULL) {
229 client->mode = kDfuMode; 305 if (strncmp(client->DfuPath, "\\\\?\\usb#vid_05ac&pid_", 21) == 0) {
306 sscanf(client->DfuPath+21, "%x#", &client->mode);
307 }
230 client->handle = client->hDFU; 308 client->handle = client->hDFU;
231 } else { 309 } else {
232 client->mode = kRecoveryMode2; 310 if (strncmp(client->iBootPath, "\\\\?\\usb#vid_05ac&pid_", 21) == 0) {
311 sscanf(client->iBootPath+21, "%x#", &client->mode);
312 }
233 client->handle = client->hIB; 313 client->handle = client->hIB;
234 } 314 }
235 315
316 if (client->mode == 0) {
317 irecv_close(client);
318 return IRECV_E_UNABLE_TO_CONNECT;
319 }
320
236 return IRECV_E_SUCCESS; 321 return IRECV_E_SUCCESS;
237} 322}
238 323
@@ -346,7 +431,7 @@ int irecv_bulk_transfer(irecv_client_t client,
346 } else { 431 } else {
347 ret = 0; 432 ret = 0;
348 } 433 }
349 ret==0?-1:0; 434 ret = (ret==0) ? -1 : 0;
350#endif 435#endif
351 436
352 return ret; 437 return ret;
@@ -455,12 +540,12 @@ irecv_error_t irecv_open(irecv_client_t* pclient, unsigned long long ecid) {
455 } 540 }
456 541
457 unsigned long long this_ecid = 0; 542 unsigned long long this_ecid = 0;
458 sscanf(ecid_string, "ECID:%qX", (unsigned long long*)&this_ecid); 543 sscanf(ecid_string, "ECID:" _FMT_qX, (unsigned long long*)&this_ecid);
459 if (this_ecid != ecid) { 544 if (this_ecid != ecid) {
460 irecv_close(client); 545 irecv_close(client);
461 continue; 546 continue;
462 } 547 }
463 debug("found device with ECID %016llx\n", (unsigned long long)ecid); 548 debug("found device with ECID " _FMT_016llx "\n", (unsigned long long)ecid);
464 } 549 }
465 550
466 error = irecv_set_configuration(client, 1); 551 error = irecv_set_configuration(client, 1);
@@ -489,10 +574,7 @@ irecv_error_t irecv_open(irecv_client_t* pclient, unsigned long long ecid) {
489 574
490 return IRECV_E_UNABLE_TO_CONNECT; 575 return IRECV_E_UNABLE_TO_CONNECT;
491#else 576#else
492 int ret = mobiledevice_connect(pclient); 577 int ret = mobiledevice_connect(pclient, ecid);
493 if (ret == IRECV_E_SUCCESS) {
494 irecv_get_string_descriptor_ascii(*pclient, 3, (unsigned char*) (*pclient)->serial, 255);
495 }
496 return ret; 578 return ret;
497#endif 579#endif
498} 580}
@@ -1015,7 +1097,7 @@ irecv_error_t irecv_get_ecid(irecv_client_t client, unsigned long long* ecid) {
1015 *ecid = 0; 1097 *ecid = 0;
1016 return IRECV_E_UNKNOWN_ERROR; 1098 return IRECV_E_UNKNOWN_ERROR;
1017 } 1099 }
1018 sscanf(ecid_string, "ECID:%qX", ecid); 1100 sscanf(ecid_string, "ECID:" _FMT_qX, ecid);
1019 1101
1020 return IRECV_E_SUCCESS; 1102 return IRECV_E_SUCCESS;
1021} 1103}