diff options
-rw-r--r-- | include/libirecovery.h | 11 | ||||
-rw-r--r-- | src/libirecovery.c | 33 | ||||
-rw-r--r-- | tools/irecovery.c | 2 |
3 files changed, 30 insertions, 16 deletions
diff --git a/include/libirecovery.h b/include/libirecovery.h index 04892c4..ec9255b 100644 --- a/include/libirecovery.h +++ b/include/libirecovery.h | |||
@@ -122,6 +122,13 @@ typedef struct { | |||
122 | typedef struct irecv_client_private irecv_client_private; | 122 | typedef struct irecv_client_private irecv_client_private; |
123 | typedef irecv_client_private* irecv_client_t; | 123 | typedef irecv_client_private* irecv_client_t; |
124 | 124 | ||
125 | enum { | ||
126 | IRECV_SEND_OPT_NONE = 0, | ||
127 | IRECV_SEND_OPT_DFU_NOTIFY_FINISH = (1 << 0), | ||
128 | IRECV_SEND_OPT_DFU_FORCE_ZLP = (1 << 1), | ||
129 | IRECV_SEND_OPT_DFU_SMALL_PKT = (1 << 2) | ||
130 | }; | ||
131 | |||
125 | /* library */ | 132 | /* library */ |
126 | IRECV_API void irecv_set_debug_level(int level); | 133 | IRECV_API void irecv_set_debug_level(int level); |
127 | IRECV_API const char* irecv_strerror(irecv_error_t error); | 134 | IRECV_API const char* irecv_strerror(irecv_error_t error); |
@@ -160,10 +167,10 @@ IRECV_API irecv_error_t irecv_event_subscribe(irecv_client_t client, irecv_event | |||
160 | IRECV_API irecv_error_t irecv_event_unsubscribe(irecv_client_t client, irecv_event_type type); | 167 | IRECV_API irecv_error_t irecv_event_unsubscribe(irecv_client_t client, irecv_event_type type); |
161 | 168 | ||
162 | /* I/O */ | 169 | /* I/O */ |
163 | IRECV_API irecv_error_t irecv_send_file(irecv_client_t client, const char* filename, int dfu_notify_finished); | 170 | IRECV_API irecv_error_t irecv_send_file(irecv_client_t client, const char* filename, unsigned int options); |
164 | IRECV_API irecv_error_t irecv_send_command(irecv_client_t client, const char* command); | 171 | IRECV_API irecv_error_t irecv_send_command(irecv_client_t client, const char* command); |
165 | IRECV_API irecv_error_t irecv_send_command_breq(irecv_client_t client, const char* command, uint8_t b_request); | 172 | IRECV_API irecv_error_t irecv_send_command_breq(irecv_client_t client, const char* command, uint8_t b_request); |
166 | IRECV_API irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned long length, int dfu_notify_finished); | 173 | IRECV_API irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned long length, unsigned int options); |
167 | IRECV_API irecv_error_t irecv_recv_buffer(irecv_client_t client, char* buffer, unsigned long length); | 174 | IRECV_API irecv_error_t irecv_recv_buffer(irecv_client_t client, char* buffer, unsigned long length); |
168 | 175 | ||
169 | /* commands */ | 176 | /* commands */ |
diff --git a/src/libirecovery.c b/src/libirecovery.c index b1b81e0..a60782c 100644 --- a/src/libirecovery.c +++ b/src/libirecovery.c | |||
@@ -3130,7 +3130,7 @@ irecv_error_t irecv_send_command(irecv_client_t client, const char* command) | |||
3130 | return irecv_send_command_breq(client, command, 0); | 3130 | return irecv_send_command_breq(client, command, 0); |
3131 | } | 3131 | } |
3132 | 3132 | ||
3133 | irecv_error_t irecv_send_file(irecv_client_t client, const char* filename, int dfu_notify_finished) | 3133 | irecv_error_t irecv_send_file(irecv_client_t client, const char* filename, unsigned int options) |
3134 | { | 3134 | { |
3135 | #ifdef USE_DUMMY | 3135 | #ifdef USE_DUMMY |
3136 | return IRECV_E_UNSUPPORTED; | 3136 | return IRECV_E_UNSUPPORTED; |
@@ -3163,7 +3163,7 @@ irecv_error_t irecv_send_file(irecv_client_t client, const char* filename, int d | |||
3163 | return IRECV_E_UNKNOWN_ERROR; | 3163 | return IRECV_E_UNKNOWN_ERROR; |
3164 | } | 3164 | } |
3165 | 3165 | ||
3166 | irecv_error_t error = irecv_send_buffer(client, (unsigned char*)buffer, length, dfu_notify_finished); | 3166 | irecv_error_t error = irecv_send_buffer(client, (unsigned char*)buffer, length, options); |
3167 | free(buffer); | 3167 | free(buffer); |
3168 | 3168 | ||
3169 | return error; | 3169 | return error; |
@@ -3190,7 +3190,7 @@ static irecv_error_t irecv_get_status(irecv_client_t client, unsigned int* statu | |||
3190 | return IRECV_E_SUCCESS; | 3190 | return IRECV_E_SUCCESS; |
3191 | } | 3191 | } |
3192 | 3192 | ||
3193 | static irecv_error_t irecv_kis_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned long length, int dfu_notify_finished) | 3193 | static irecv_error_t irecv_kis_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned long length, unsigned int options) |
3194 | { | 3194 | { |
3195 | if (client->mode != IRECV_K_DFU_MODE) { | 3195 | if (client->mode != IRECV_K_DFU_MODE) { |
3196 | return IRECV_E_UNSUPPORTED; | 3196 | return IRECV_E_UNSUPPORTED; |
@@ -3254,7 +3254,7 @@ static irecv_error_t irecv_kis_send_buffer(irecv_client_t client, unsigned char* | |||
3254 | } | 3254 | } |
3255 | free(chunk); | 3255 | free(chunk); |
3256 | 3256 | ||
3257 | if (dfu_notify_finished) { | 3257 | if (options & IRECV_SEND_OPT_DFU_NOTIFY_FINISH) { |
3258 | #ifdef WIN32 | 3258 | #ifdef WIN32 |
3259 | DWORD amount = (DWORD)origLen; | 3259 | DWORD amount = (DWORD)origLen; |
3260 | DWORD transferred = 0; | 3260 | DWORD transferred = 0; |
@@ -3273,13 +3273,13 @@ static irecv_error_t irecv_kis_send_buffer(irecv_client_t client, unsigned char* | |||
3273 | } | 3273 | } |
3274 | #endif | 3274 | #endif |
3275 | 3275 | ||
3276 | irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned long length, int dfu_notify_finished) | 3276 | irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned long length, unsigned int options) |
3277 | { | 3277 | { |
3278 | #ifdef USE_DUMMY | 3278 | #ifdef USE_DUMMY |
3279 | return IRECV_E_UNSUPPORTED; | 3279 | return IRECV_E_UNSUPPORTED; |
3280 | #else | 3280 | #else |
3281 | if (client->isKIS) | 3281 | if (client->isKIS) |
3282 | return irecv_kis_send_buffer(client, buffer, length, dfu_notify_finished); | 3282 | return irecv_kis_send_buffer(client, buffer, length, options); |
3283 | 3283 | ||
3284 | irecv_error_t error = 0; | 3284 | irecv_error_t error = 0; |
3285 | int recovery_mode = ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_PORT_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE)); | 3285 | int recovery_mode = ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_PORT_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE)); |
@@ -3289,7 +3289,12 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un | |||
3289 | 3289 | ||
3290 | unsigned int h1 = 0xFFFFFFFF; | 3290 | unsigned int h1 = 0xFFFFFFFF; |
3291 | unsigned char dfu_xbuf[12] = {0xff, 0xff, 0xff, 0xff, 0xac, 0x05, 0x00, 0x01, 0x55, 0x46, 0x44, 0x10}; | 3291 | unsigned char dfu_xbuf[12] = {0xff, 0xff, 0xff, 0xff, 0xac, 0x05, 0x00, 0x01, 0x55, 0x46, 0x44, 0x10}; |
3292 | int dfu_crc = 1; | ||
3292 | int packet_size = recovery_mode ? 0x8000 : 0x800; | 3293 | int packet_size = recovery_mode ? 0x8000 : 0x800; |
3294 | if (!recovery_mode && (options & IRECV_SEND_OPT_DFU_SMALL_PKT)) { | ||
3295 | packet_size = 0x40; | ||
3296 | dfu_crc = 0; | ||
3297 | } | ||
3293 | int last = length % packet_size; | 3298 | int last = length % packet_size; |
3294 | int packets = length / packet_size; | 3299 | int packets = length / packet_size; |
3295 | 3300 | ||
@@ -3341,11 +3346,14 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un | |||
3341 | if (recovery_mode) { | 3346 | if (recovery_mode) { |
3342 | error = irecv_usb_bulk_transfer(client, 0x04, &buffer[i * packet_size], size, &bytes, USB_TIMEOUT); | 3347 | error = irecv_usb_bulk_transfer(client, 0x04, &buffer[i * packet_size], size, &bytes, USB_TIMEOUT); |
3343 | } else { | 3348 | } else { |
3344 | int j; | 3349 | if (dfu_crc) { |
3345 | for (j = 0; j < size; j++) { | 3350 | int j; |
3346 | crc32_step(h1, buffer[i*packet_size + j]); | 3351 | for (j = 0; j < size; j++) { |
3352 | crc32_step(h1, buffer[i*packet_size + j]); | ||
3353 | } | ||
3347 | } | 3354 | } |
3348 | if (i+1 == packets) { | 3355 | if (dfu_crc && i+1 == packets) { |
3356 | int j; | ||
3349 | if (size+16 > packet_size) { | 3357 | if (size+16 > packet_size) { |
3350 | bytes = irecv_usb_control_transfer(client, 0x21, 1, i, 0, &buffer[i * packet_size], size, USB_TIMEOUT); | 3358 | bytes = irecv_usb_control_transfer(client, 0x21, 1, i, 0, &buffer[i * packet_size], size, USB_TIMEOUT); |
3351 | if (bytes != size) { | 3359 | if (bytes != size) { |
@@ -3354,7 +3362,6 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un | |||
3354 | count += size; | 3362 | count += size; |
3355 | size = 0; | 3363 | size = 0; |
3356 | } | 3364 | } |
3357 | |||
3358 | for (j = 0; j < 2; j++) { | 3365 | for (j = 0; j < 2; j++) { |
3359 | crc32_step(h1, dfu_xbuf[j*6 + 0]); | 3366 | crc32_step(h1, dfu_xbuf[j*6 + 0]); |
3360 | crc32_step(h1, dfu_xbuf[j*6 + 1]); | 3367 | crc32_step(h1, dfu_xbuf[j*6 + 1]); |
@@ -3428,7 +3435,7 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un | |||
3428 | irecv_usb_bulk_transfer(client, 0x04, buffer, 0, &bytes, USB_TIMEOUT); | 3435 | irecv_usb_bulk_transfer(client, 0x04, buffer, 0, &bytes, USB_TIMEOUT); |
3429 | } | 3436 | } |
3430 | 3437 | ||
3431 | if (dfu_notify_finished && !recovery_mode) { | 3438 | if ((options & IRECV_SEND_OPT_DFU_NOTIFY_FINISH) && !recovery_mode) { |
3432 | irecv_usb_control_transfer(client, 0x21, 1, packets, 0, (unsigned char*) buffer, 0, USB_TIMEOUT); | 3439 | irecv_usb_control_transfer(client, 0x21, 1, packets, 0, (unsigned char*) buffer, 0, USB_TIMEOUT); |
3433 | 3440 | ||
3434 | for (i = 0; i < 2; i++) { | 3441 | for (i = 0; i < 2; i++) { |
@@ -3438,7 +3445,7 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un | |||
3438 | } | 3445 | } |
3439 | } | 3446 | } |
3440 | 3447 | ||
3441 | if (dfu_notify_finished == 2) { | 3448 | if ((options & IRECV_SEND_OPT_DFU_FORCE_ZLP)) { |
3442 | /* we send a pseudo ZLP here just in case */ | 3449 | /* we send a pseudo ZLP here just in case */ |
3443 | irecv_usb_control_transfer(client, 0x21, 1, 0, 0, 0, 0, USB_TIMEOUT); | 3450 | irecv_usb_control_transfer(client, 0x21, 1, 0, 0, 0, 0, USB_TIMEOUT); |
3444 | } | 3451 | } |
diff --git a/tools/irecovery.c b/tools/irecovery.c index 955d3ca..61d053a 100644 --- a/tools/irecovery.c +++ b/tools/irecovery.c | |||
@@ -596,7 +596,7 @@ int main(int argc, char* argv[]) | |||
596 | 596 | ||
597 | case kSendFile: | 597 | case kSendFile: |
598 | irecv_event_subscribe(client, IRECV_PROGRESS, &progress_cb, NULL); | 598 | irecv_event_subscribe(client, IRECV_PROGRESS, &progress_cb, NULL); |
599 | error = irecv_send_file(client, argument, 1); | 599 | error = irecv_send_file(client, argument, IRECV_SEND_OPT_DFU_NOTIFY_FINISH); |
600 | debug("%s\n", irecv_strerror(error)); | 600 | debug("%s\n", irecv_strerror(error)); |
601 | break; | 601 | break; |
602 | 602 | ||