diff options
| author | 2010-05-23 17:20:50 -0400 | |
|---|---|---|
| committer | 2010-05-23 17:20:50 -0400 | |
| commit | 53142922b14fe36f950eb28d3b42683ddedb7669 (patch) | |
| tree | 936df7c71a646d310e97c5378b217c2b86a9757a | |
| parent | 442363a01ef44e84eda3e22c71dd2de424f5121e (diff) | |
| download | libirecovery-53142922b14fe36f950eb28d3b42683ddedb7669.tar.gz libirecovery-53142922b14fe36f950eb28d3b42683ddedb7669.tar.bz2 | |
Quite a few bug fixes, updated to be used with the latest version of idevicerestore. Still quite a few issues to be ironed out though.
| -rw-r--r-- | include/libirecovery.h | 35 | ||||
| -rw-r--r-- | src/libirecovery.c | 115 |
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 | ||
| 21 | typedef 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 | ||
| 37 | typedef enum { | 23 | enum { |
| 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 | |||
| 31 | typedef 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 | ||
| 45 | struct irecv_client; | 45 | struct irecv_client; |
| 46 | typedef struct irecv_client* irecv_client_t; | 46 | typedef 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 | ||
| 30 | const char* irecv_error_invalid_input = "Invalid input"; | ||
| 31 | const char* irecv_error_unknown = "Unknown error"; | ||
| 32 | const char* irecv_error_file_not_found = "Unable to find file"; | ||
| 33 | const char* irecv_error_usb_status = "Invalid device status"; | ||
| 34 | const char* irecv_error_no_device = "Unable to find device"; | ||
| 35 | const char* irecv_error_out_of_memory = "Unable to allocate memory"; | ||
| 36 | const char* irecv_error_unable_to_connect = "Unable to connect to device"; | ||
| 37 | const char* irecv_error_usb_interface = "Unable to set device interface"; | ||
| 38 | const char* irecv_error_success = "Command completed successfully"; | ||
| 39 | const char* irecv_error_usb_upload = "Unable to upload data to device"; | ||
| 40 | const char* irecv_error_usb_configuration = "Unable to set device configuration"; | ||
| 41 | |||
| 42 | int irecv_default_sender(irecv_client_t client, unsigned char* data, int size); | 30 | int irecv_default_sender(irecv_client_t client, unsigned char* data, int size); |
| 43 | int irecv_default_receiver(irecv_client_t client, unsigned char* data, int size); | 31 | int 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 | ||
| 152 | irecv_error_t irecv_reset(irecv_client_t client) { | 137 | irecv_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) { | |||
| 161 | irecv_error_t irecv_close(irecv_client_t client) { | 146 | irecv_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 | ||
| 382 | irecv_error_t irecv_getenv(irecv_client_t client, unsigned char** var) { | 385 | irecv_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) { | |||
| 398 | irecv_error_t irecv_get_ecid(irecv_client_t client, unsigned long long* ecid) { | 410 | irecv_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 | ||
| 414 | const char* irecv_strerror(irecv_error_t error) { | 432 | const 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; |
