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 | ||
