summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/libirecovery.h35
-rw-r--r--src/libirecovery.c115
2 files changed, 82 insertions, 68 deletions
diff --git a/include/libirecovery.h b/include/libirecovery.h
index 9d30497..9848655 100644
--- a/include/libirecovery.h
+++ b/include/libirecovery.h
@@ -18,29 +18,29 @@
18 18
19#include <libusb-1.0/libusb.h> 19#include <libusb-1.0/libusb.h>
20 20
21typedef enum {
22 IRECV_E_SUCCESS = 0,
23 IRECV_E_NO_DEVICE = -1,
24 IRECV_E_OUT_OF_MEMORY = -2,
25 IRECV_E_UNABLE_TO_CONNECT = -3,
26 IRECV_E_INVALID_INPUT = -4,
27 IRECV_E_UNKNOWN = -5,
28 IRECV_E_FILE_NOT_FOUND = -6,
29 IRECV_E_USB_UPLOAD = -7,
30 IRECV_E_USB_STATUS = -8,
31 IRECV_E_USB_INTERFACE = -9,
32 IRECV_E_USB_CONFIGURATION = -10
33} irecv_error_t;
34
35#define APPLE_VENDOR_ID 0x05AC 21#define APPLE_VENDOR_ID 0x05AC
36 22
37typedef enum { 23enum {
38 kRecoveryMode1 = 0x1280, 24 kRecoveryMode1 = 0x1280,
39 kRecoveryMode2 = 0x1281, 25 kRecoveryMode2 = 0x1281,
40 kRecoveryMode3 = 0x1282, 26 kRecoveryMode3 = 0x1282,
41 kRecoveryMode4 = 0x1283, 27 kRecoveryMode4 = 0x1283,
42 kDfuMode = 0x1227 28 kDfuMode = 0x1227
43} irecv_mode_t; 29};
30
31typedef enum {
32 IRECV_E_SUCCESS = 0,
33 IRECV_E_NO_DEVICE = -1,
34 IRECV_E_OUT_OF_MEMORY = -2,
35 IRECV_E_UNABLE_TO_CONNECT = -3,
36 IRECV_E_INVALID_INPUT = -4,
37 IRECV_E_FILE_NOT_FOUND = -5,
38 IRECV_E_USB_UPLOAD = -6,
39 IRECV_E_USB_STATUS = -7,
40 IRECV_E_USB_INTERFACE = -8,
41 IRECV_E_USB_CONFIGURATION = -9,
42 IRECV_E_UNKNOWN_ERROR = -255
43} irecv_error_t;
44 44
45struct irecv_client; 45struct irecv_client;
46typedef struct irecv_client* irecv_client_t; 46typedef struct irecv_client* irecv_client_t;
@@ -53,8 +53,7 @@ struct irecv_client {
53 int config; 53 int config;
54 int interface; 54 int interface;
55 int alt_interface; 55 int alt_interface;
56 char *uuid; 56 unsigned short mode;
57 irecv_mode_t mode;
58 libusb_context* context; 57 libusb_context* context;
59 libusb_device_handle* handle; 58 libusb_device_handle* handle;
60 irecv_send_callback send_callback; 59 irecv_send_callback send_callback;
diff --git a/src/libirecovery.c b/src/libirecovery.c
index a2ec9c9..131032c 100644
--- a/src/libirecovery.c
+++ b/src/libirecovery.c
@@ -27,18 +27,6 @@
27#define BUFFER_SIZE 0x1000 27#define BUFFER_SIZE 0x1000
28#define debug(...) if(client->debug) fprintf(stderr, __VA_ARGS__) 28#define debug(...) if(client->debug) fprintf(stderr, __VA_ARGS__)
29 29
30const char* irecv_error_invalid_input = "Invalid input";
31const char* irecv_error_unknown = "Unknown error";
32const char* irecv_error_file_not_found = "Unable to find file";
33const char* irecv_error_usb_status = "Invalid device status";
34const char* irecv_error_no_device = "Unable to find device";
35const char* irecv_error_out_of_memory = "Unable to allocate memory";
36const char* irecv_error_unable_to_connect = "Unable to connect to device";
37const char* irecv_error_usb_interface = "Unable to set device interface";
38const char* irecv_error_success = "Command completed successfully";
39const char* irecv_error_usb_upload = "Unable to upload data to device";
40const char* irecv_error_usb_configuration = "Unable to set device configuration";
41
42int irecv_default_sender(irecv_client_t client, unsigned char* data, int size); 30int irecv_default_sender(irecv_client_t client, unsigned char* data, int size);
43int irecv_default_receiver(irecv_client_t client, unsigned char* data, int size); 31int irecv_default_receiver(irecv_client_t client, unsigned char* data, int size);
44 32
@@ -85,22 +73,17 @@ irecv_error_t irecv_open(irecv_client_t* pclient, const char* uuid) {
85 return IRECV_E_OUT_OF_MEMORY; 73 return IRECV_E_OUT_OF_MEMORY;
86 } 74 }
87 memset(client, '\0', sizeof(irecv_client_t)); 75 memset(client, '\0', sizeof(irecv_client_t));
76 client->interface = -1;
88 client->handle = usb_handle; 77 client->handle = usb_handle;
89 client->context = usb_context; 78 client->context = usb_context;
90 client->mode = (irecv_mode_t) usb_descriptor.idProduct; 79 client->mode = usb_descriptor.idProduct;
91 80
92 error = irecv_set_configuration(client, 1); 81 error = irecv_set_configuration(client, 1);
93 if(error != IRECV_E_SUCCESS) { 82 if(error != IRECV_E_SUCCESS) {
94 return error; 83 return error;
95 } 84 }
96 85
97 error = irecv_set_interface(client, 1, 1);
98 if(error != IRECV_E_SUCCESS) {
99 return error;
100 }
101
102 *pclient = client; 86 *pclient = client;
103 printf("done");
104 return IRECV_E_SUCCESS; 87 return IRECV_E_SUCCESS;
105 } 88 }
106 } 89 }
@@ -133,9 +116,11 @@ irecv_error_t irecv_set_interface(irecv_client_t client, int interface, int alt_
133 return IRECV_E_NO_DEVICE; 116 return IRECV_E_NO_DEVICE;
134 } 117 }
135 118
136 debug("Setting to interface %d:%d", interface, alt_interface); 119 if(client->interface == interface) {
137 libusb_reset_device(client->handle); 120 return IRECV_E_SUCCESS;
121 }
138 122
123 debug("Setting to interface %d:%d", interface, alt_interface);
139 if (libusb_claim_interface(client->handle, interface) < 0) { 124 if (libusb_claim_interface(client->handle, interface) < 0) {
140 return IRECV_E_USB_INTERFACE; 125 return IRECV_E_USB_INTERFACE;
141 } 126 }
@@ -150,7 +135,7 @@ irecv_error_t irecv_set_interface(irecv_client_t client, int interface, int alt_
150} 135}
151 136
152irecv_error_t irecv_reset(irecv_client_t client) { 137irecv_error_t irecv_reset(irecv_client_t client) {
153 if (client == NULL || client->handle != NULL) { 138 if (client == NULL || client->handle == NULL) {
154 return IRECV_E_NO_DEVICE; 139 return IRECV_E_NO_DEVICE;
155 } 140 }
156 141
@@ -161,7 +146,9 @@ irecv_error_t irecv_reset(irecv_client_t client) {
161irecv_error_t irecv_close(irecv_client_t client) { 146irecv_error_t irecv_close(irecv_client_t client) {
162 if (client != NULL) { 147 if (client != NULL) {
163 if (client->handle != NULL) { 148 if (client->handle != NULL) {
164 libusb_release_interface(client->handle, 1); 149 if(client->interface >= 0) {
150 libusb_release_interface(client->handle, client->interface);
151 }
165 libusb_close(client->handle); 152 libusb_close(client->handle);
166 client->handle = NULL; 153 client->handle = NULL;
167 } 154 }
@@ -171,10 +158,6 @@ irecv_error_t irecv_close(irecv_client_t client) {
171 client->context = NULL; 158 client->context = NULL;
172 } 159 }
173 160
174 if(client->uuid != NULL) {
175 free(client->uuid);
176 }
177
178 free(client); 161 free(client);
179 client = NULL; 162 client = NULL;
180 } 163 }
@@ -220,6 +203,11 @@ irecv_error_t irecv_send_command(irecv_client_t client, unsigned char* command)
220 return IRECV_E_NO_DEVICE; 203 return IRECV_E_NO_DEVICE;
221 } 204 }
222 205
206 irecv_error_t error = irecv_set_interface(client, 1, 1);
207 if(error != IRECV_E_SUCCESS) {
208 return error;
209 }
210
223 unsigned int length = strlen(command); 211 unsigned int length = strlen(command);
224 if(length >= 0x100) { 212 if(length >= 0x100) {
225 length = 0xFF; 213 length = 0xFF;
@@ -257,7 +245,7 @@ irecv_error_t irecv_send_file(irecv_client_t client, const char* filename) {
257 245
258 if(bytes != length) { 246 if(bytes != length) {
259 free(buffer); 247 free(buffer);
260 return IRECV_E_UNKNOWN; 248 return IRECV_E_UNKNOWN_ERROR;
261 } 249 }
262 250
263 irecv_error_t error = irecv_send_buffer(client, buffer, length); 251 irecv_error_t error = irecv_send_buffer(client, buffer, length);
@@ -271,6 +259,11 @@ irecv_error_t irecv_get_status(irecv_client_t client, unsigned int* status) {
271 return IRECV_E_NO_DEVICE; 259 return IRECV_E_NO_DEVICE;
272 } 260 }
273 261
262 irecv_error_t error = irecv_set_interface(client, 1, 1);
263 if(error != IRECV_E_SUCCESS) {
264 return error;
265 }
266
274 unsigned char buffer[6]; 267 unsigned char buffer[6];
275 memset(buffer, '\0', 6); 268 memset(buffer, '\0', 6);
276 if(libusb_control_transfer(client->handle, 0xA1, 3, 0, 0, buffer, 6, 1000) != 6) { 269 if(libusb_control_transfer(client->handle, 0xA1, 3, 0, 0, buffer, 6, 1000) != 6) {
@@ -289,6 +282,11 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un
289 return IRECV_E_NO_DEVICE; 282 return IRECV_E_NO_DEVICE;
290 } 283 }
291 284
285 error = irecv_set_interface(client, 1, 1);
286 if(error != IRECV_E_SUCCESS) {
287 return error;
288 }
289
292 int last = length % 0x800; 290 int last = length % 0x800;
293 int packets = length / 0x800; 291 int packets = length / 0x800;
294 if (last != 0) { 292 if (last != 0) {
@@ -312,7 +310,7 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un
312 } 310 }
313 311
314 if(status != 5) { 312 if(status != 5) {
315 return IRECV_E_USB_STATUS; 313 return IRECV_E_USB_UPLOAD;
316 } 314 }
317 315
318 } 316 }
@@ -335,12 +333,17 @@ irecv_error_t irecv_receive(irecv_client_t client) {
335 return IRECV_E_NO_DEVICE; 333 return IRECV_E_NO_DEVICE;
336 } 334 }
337 335
336 irecv_error_t error = irecv_set_interface(client, 1, 1);
337 if(error != IRECV_E_SUCCESS) {
338 return error;
339 }
340
338 int bytes = 0; 341 int bytes = 0;
339 while(libusb_bulk_transfer(client->handle, 0x81, buffer, BUFFER_SIZE, &bytes, 100) == 0) { 342 while(libusb_bulk_transfer(client->handle, 0x81, buffer, BUFFER_SIZE, &bytes, 100) == 0) {
340 if(bytes > 0) { 343 if(bytes > 0) {
341 if(client->receive_callback != NULL) { 344 if(client->receive_callback != NULL) {
342 if(client->receive_callback(client, buffer, bytes) != bytes) { 345 if(client->receive_callback(client, buffer, bytes) != bytes) {
343 return IRECV_E_UNKNOWN; 346 return IRECV_E_UNKNOWN_ERROR;
344 } 347 }
345 } 348 }
346 } else break; 349 } else break;
@@ -380,14 +383,23 @@ irecv_error_t irecv_set_sender(irecv_client_t client, irecv_send_callback callba
380} 383}
381 384
382irecv_error_t irecv_getenv(irecv_client_t client, unsigned char** var) { 385irecv_error_t irecv_getenv(irecv_client_t client, unsigned char** var) {
383 unsigned char* value = (unsigned char*) malloc(0x200); 386 if(client == NULL || client->handle == NULL) {
387 return IRECV_E_NO_DEVICE;
388 }
389
390 irecv_error_t error = irecv_set_interface(client, 1, 1);
391 if(error != IRECV_E_SUCCESS) {
392 return error;
393 }
394
395 unsigned char* value = (unsigned char*) malloc(256);
384 if(value == NULL) { 396 if(value == NULL) {
385 return IRECV_E_OUT_OF_MEMORY; 397 return IRECV_E_OUT_OF_MEMORY;
386 } 398 }
387 399
388 int ret = libusb_control_transfer(client->handle, 0xC0, 0, 0, 0, value, 0x200, 500); 400 int ret = libusb_control_transfer(client->handle, 0xC0, 0, 0, 0, value, 256, 500);
389 if(ret < 0) { 401 if(ret < 0) {
390 return IRECV_E_UNKNOWN; 402 return IRECV_E_UNKNOWN_ERROR;
391 } 403 }
392 404
393 *var = value; 405 *var = value;
@@ -398,56 +410,59 @@ irecv_error_t irecv_getenv(irecv_client_t client, unsigned char** var) {
398irecv_error_t irecv_get_ecid(irecv_client_t client, unsigned long long* ecid) { 410irecv_error_t irecv_get_ecid(irecv_client_t client, unsigned long long* ecid) {
399 char info[256]; 411 char info[256];
400 memset(info, '\0', 256); 412 memset(info, '\0', 256);
401 libusb_get_string_descriptor_ascii(client->handle, 3, info, 0x100); 413
402 debug("%s\n", info); 414 if(client == NULL || client->handle == NULL) {
415 return IRECV_E_NO_DEVICE;
416 }
417
418 libusb_get_string_descriptor_ascii(client->handle, 3, info, 255);
419 printf("%d: %s\n", strlen(info), info);
403 420
404 unsigned char* ecid_string = strstr(info, "ECID:"); 421 unsigned char* ecid_string = strstr(info, "ECID:");
405 if(ecid_string == NULL) { 422 if(ecid_string == NULL) {
406 *ecid = 0; 423 *ecid = 0;
407 return IRECV_E_UNKNOWN; 424 return IRECV_E_UNKNOWN_ERROR;
408 } 425 }
409 sscanf(ecid_string, "ECID:%qX", ecid); 426 sscanf(ecid_string, "ECID:%qX", ecid);
410 427
428 irecv_reset(client);
411 return IRECV_E_SUCCESS; 429 return IRECV_E_SUCCESS;
412} 430}
413 431
414const char* irecv_strerror(irecv_error_t error) { 432const char* irecv_strerror(irecv_error_t error) {
415 switch(error) { 433 switch(error) {
416 case IRECV_E_SUCCESS: 434 case IRECV_E_SUCCESS:
417 return irecv_error_success; 435 return "Command completed successfully";
418 436
419 case IRECV_E_NO_DEVICE: 437 case IRECV_E_NO_DEVICE:
420 return irecv_error_no_device; 438 return "Unable to find device";
421 439
422 case IRECV_E_OUT_OF_MEMORY: 440 case IRECV_E_OUT_OF_MEMORY:
423 return irecv_error_out_of_memory; 441 return "Out of memory";
424 442
425 case IRECV_E_UNABLE_TO_CONNECT: 443 case IRECV_E_UNABLE_TO_CONNECT:
426 return irecv_error_unable_to_connect; 444 return "Unable to connect to device";
427 445
428 case IRECV_E_INVALID_INPUT: 446 case IRECV_E_INVALID_INPUT:
429 return irecv_error_invalid_input; 447 return "Invalid input";
430
431 case IRECV_E_UNKNOWN:
432 return irecv_error_unknown;
433 448
434 case IRECV_E_FILE_NOT_FOUND: 449 case IRECV_E_FILE_NOT_FOUND:
435 return irecv_error_file_not_found; 450 return "File not found";
436 451
437 case IRECV_E_USB_UPLOAD: 452 case IRECV_E_USB_UPLOAD:
438 return irecv_error_usb_upload; 453 return "Unable to upload data to device";
439 454
440 case IRECV_E_USB_STATUS: 455 case IRECV_E_USB_STATUS:
441 return irecv_error_usb_status; 456 return "Unable to get device status";
442 457
443 case IRECV_E_USB_INTERFACE: 458 case IRECV_E_USB_INTERFACE:
444 return irecv_error_usb_interface; 459 return "Unable to set device interface";
445 460
446 case IRECV_E_USB_CONFIGURATION: 461 case IRECV_E_USB_CONFIGURATION:
447 return irecv_error_usb_configuration; 462 return "Unable to set device configuration";
448 463
449 default: 464 default:
450 return irecv_error_unknown; 465 return "Unknown error";
451 } 466 }
452 467
453 return NULL; 468 return NULL;