diff options
-rw-r--r-- | include/libirecovery.h | 2 | ||||
-rw-r--r-- | src/libirecovery.c | 54 |
2 files changed, 40 insertions, 16 deletions
diff --git a/include/libirecovery.h b/include/libirecovery.h index 534d2a8..3e03626 100644 --- a/include/libirecovery.h +++ b/include/libirecovery.h @@ -101,7 +101,7 @@ irecv_error_t irecv_event_unsubscribe(irecv_client_t client, irecv_event_type ty irecv_error_t irecv_send_file(irecv_client_t client, const char* filename); irecv_error_t irecv_send_command(irecv_client_t client, unsigned char* command); -irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned int length); +irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned long length); irecv_error_t irecv_getenv(irecv_client_t client, const char* variable, char** value); irecv_error_t irecv_setenv(irecv_client_t client, const char* variable, const char* value); diff --git a/src/libirecovery.c b/src/libirecovery.c index 61b0eb1..18683f1 100644 --- a/src/libirecovery.c +++ b/src/libirecovery.c @@ -322,7 +322,7 @@ irecv_error_t irecv_send_file(irecv_client_t client, const char* filename) { } fseek(file, 0, SEEK_END); - int length = ftell(file); + long length = ftell(file); fseek(file, 0, SEEK_SET); unsigned char* buffer = (unsigned char*) malloc(length); @@ -331,7 +331,7 @@ irecv_error_t irecv_send_file(irecv_client_t client, const char* filename) { return IRECV_E_OUT_OF_MEMORY; } - int bytes = fread(buffer, 1, length, file); + long bytes = fread(buffer, 1, length, file); fclose(file); if (bytes != length) { @@ -361,35 +361,57 @@ irecv_error_t irecv_get_status(irecv_client_t client, unsigned int* status) { return IRECV_E_SUCCESS; } -irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned int length) { +irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned long length) { irecv_error_t error = 0; + int recovery_mode = (client->mode != kDfuMode); + if (client == NULL || client->handle == NULL) { return IRECV_E_NO_DEVICE; } - int last = length % 0x800; - int packets = length / 0x800; + int packet_size = recovery_mode ? 0x4000: 0x800; + int last = length % packet_size; + int packets = length / packet_size; if (last != 0) { packets++; } + /* initiate transfer */ + if (recovery_mode) { + error = libusb_control_transfer(client->handle, 0x41, 0, 0, 0, NULL, 0, 1000); + if (error != IRECV_E_SUCCESS) { + return error; + } + } + int i = 0; double progress = 0; - unsigned int count = 0; + unsigned long count = 0; unsigned int status = 0; + int bytes = 0; for (i = 0; i < packets; i++) { - int size = i + 1 < packets ? 0x800 : last; - int bytes = libusb_control_transfer(client->handle, 0x21, 1, 0, 0, &buffer[i * 0x800], size, 1000); + int size = (i + 1) < packets ? packet_size : last; + + /* Use bulk transfer for recovery mode and control transfer for DFU and WTF mode */ + if (recovery_mode) { + error = libusb_bulk_transfer(client->handle, 0x04, &buffer[i * packet_size], size, &bytes, 1000); + } else { + bytes = libusb_control_transfer(client->handle, 0x21, 1, 0, 0, &buffer[i * packet_size], size, 1000); + } + if (bytes != size) { return IRECV_E_USB_UPLOAD; } - error = irecv_get_status(client, &status); + if (!recovery_mode) { + error = irecv_get_status(client, &status); + } + if (error != IRECV_E_SUCCESS) { return error; } - if (status != 5) { + if (!recovery_mode && status != 5) { return IRECV_E_USB_UPLOAD; } @@ -406,11 +428,13 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un } } - libusb_control_transfer(client->handle, 0x21, 1, 0, 0, buffer, 0, 1000); - for (i = 0; i < 3; i++) { - error = irecv_get_status(client, &status); - if (error != IRECV_E_SUCCESS) { - return error; + if (!recovery_mode) { + libusb_control_transfer(client->handle, 0x21, 1, 0, 0, buffer, 0, 1000); + for (i = 0; i < 3; i++) { + error = irecv_get_status(client, &status); + if (error != IRECV_E_SUCCESS) { + return error; + } } } |