From 3491ef9c41f1cd867028881a8beebf1ad55373c7 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Sun, 16 May 2010 14:15:26 -0400 Subject: Added irecv_set_configuration() and irecv_set_interface() functions and implemented bulk read --- include/libirecovery.h | 67 +++++++++++--------- src/irecovery.c | 14 ++--- src/libirecovery.c | 161 ++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 176 insertions(+), 66 deletions(-) diff --git a/include/libirecovery.h b/include/libirecovery.h index e3360f0..822d0e1 100644 --- a/include/libirecovery.h +++ b/include/libirecovery.h @@ -18,48 +18,57 @@ #include -#define IRECV_SUCCESS 0 -#define IRECV_ERROR_NO_DEVICE -1 -#define IRECV_ERROR_OUT_OF_MEMORY -2 -#define IRECV_ERROR_UNABLE_TO_CONNECT -3 -#define IRECV_ERROR_INVALID_INPUT -4 -#define IRECV_ERROR_UNKNOWN -5 -#define IRECV_ERROR_FILE_NOT_FOUND -6 -#define IRECV_ERROR_USB_UPLOAD -7 -#define IRECV_ERROR_USB_STATUS -8 +typedef enum { + IRECV_SUCCESS = 0, + IRECV_ERROR_NO_DEVICE = -1, + IRECV_ERROR_OUT_OF_MEMORY = -2, + IRECV_ERROR_UNABLE_TO_CONNECT = -3, + IRECV_ERROR_INVALID_INPUT = -4, + IRECV_ERROR_UNKNOWN = -5, + IRECV_ERROR_FILE_NOT_FOUND = -6, + IRECV_ERROR_USB_UPLOAD = -7, + IRECV_ERROR_USB_STATUS = -8, + IRECV_ERROR_USB_INTERFACE = -9, + IRECV_ERROR_USB_CONFIGURATION = -10 +} irecv_error_t; -enum { +typedef enum { kAppleId = 0x05AC, kKernelMode = 0x1294, kRecoveryMode = 0x1281, kDfuMode = 0x1227 -}; +} irecv_mode_t; struct irecv_device; typedef struct irecv_device irecv_device_t; -typedef int(*irecv_send_callback)(irecv_device_t* device, unsigned char* data, unsigned int size); -typedef int(*irecv_receive_callback)(irecv_device_t* device, unsigned char* data, unsigned int size); +typedef int(*irecv_send_callback)(irecv_device_t* device, unsigned char* data, int size); +typedef int(*irecv_receive_callback)(irecv_device_t* device, unsigned char* data, int size); struct irecv_device { - unsigned int mode; - unsigned int debug; - struct libusb_context* context; - struct libusb_device_handle* handle; - irecv_receive_callback receive_callback; + int debug; + int config; + int interface; + int alt_interface; + irecv_mode_t mode; + libusb_context* context; + libusb_device_handle* handle; irecv_send_callback send_callback; + irecv_receive_callback receive_callback; }; irecv_device_t* irecv_init(); -int irecv_open(irecv_device_t* device); -int irecv_exit(irecv_device_t* device); -int irecv_reset(irecv_device_t* device); -int irecv_close(irecv_device_t* device); -void irecv_update(irecv_device_t* device); -void irecv_set_debug(irecv_device_t* device, int level); -int irecv_send_file(irecv_device_t* device, const char* filename); -int irecv_send_command(irecv_device_t* device, unsigned char* command); -int irecv_send_buffer(irecv_device_t* device, unsigned char* buffer, int length); -int irecv_set_sender(irecv_device_t* device, irecv_send_callback callback); -int irecv_set_receiver(irecv_device_t* device, irecv_receive_callback callback); +irecv_error_t irecv_open(irecv_device_t* device); +irecv_error_t irecv_exit(irecv_device_t* device); +irecv_error_t irecv_reset(irecv_device_t* device); +irecv_error_t irecv_close(irecv_device_t* device); +irecv_error_t irecv_update(irecv_device_t* device); +irecv_error_t irecv_set_debug(irecv_device_t* device, int level); +irecv_error_t irecv_send_file(irecv_device_t* device, const char* filename); +irecv_error_t irecv_send_command(irecv_device_t* device, unsigned char* command); +irecv_error_t irecv_set_configuration(irecv_device_t* device, int configuration); +irecv_error_t irecv_set_sender(irecv_device_t* device, irecv_send_callback callback); +irecv_error_t irecv_set_receiver(irecv_device_t* device, irecv_receive_callback callback); +irecv_error_t irecv_set_interface(irecv_device_t* device, int interface, int alt_interface); +irecv_error_t irecv_send_buffer(irecv_device_t* device, unsigned char* buffer, unsigned int length); diff --git a/src/irecovery.c b/src/irecovery.c index 2ab0aaa..8ffe86b 100644 --- a/src/irecovery.c +++ b/src/irecovery.c @@ -29,7 +29,8 @@ enum { kResetDevice, kStartShell, kSendCommand, kSendFile }; -static unsigned int exit_shell = 0; +static unsigned int quit = 0; +static unsigned int debug = 0; void print_shell_usage() { printf("Usage:\n"); @@ -41,7 +42,7 @@ void print_shell_usage() { void parse_command(irecv_device_t* device, unsigned char* command, unsigned int size) { char* cmd = strtok(command, " "); if(!strcmp(command, "/exit")) { - exit_shell = 1; + quit = 1; } else if(!strcmp(command, "/help")) { @@ -56,7 +57,7 @@ void parse_command(irecv_device_t* device, unsigned char* command, unsigned int } } -int recv_callback(irecv_device_t* device, unsigned char* data, unsigned int size) { +int recv_callback(irecv_device_t* device, unsigned char* data, int size) { int i = 0; for(i = 0; i < size; i++) { printf("%c", data[i]); @@ -64,7 +65,7 @@ int recv_callback(irecv_device_t* device, unsigned char* data, unsigned int size return size; } -int send_callback(irecv_device_t* device, unsigned char* command, unsigned int size) { +int send_callback(irecv_device_t* device, unsigned char* command, int size) { if(command[0] == '/') { parse_command(device, command, size); return 0; @@ -85,14 +86,14 @@ void init_shell(irecv_device_t* device) { load_command_history(); irecv_set_sender(device, &send_callback); irecv_set_receiver(device, &recv_callback); - while(!exit_shell) { + while(!quit) { + irecv_update(device); char* cmd = readline("> "); if(cmd && *cmd) { irecv_send_command(device, cmd); append_command_to_history(cmd); free(cmd); } - irecv_update(device); } } @@ -110,7 +111,6 @@ void print_usage() { int main(int argc, char** argv) { int opt = 0; - int debug = 0; int action = 0; char* argument = NULL; if(argc == 1) print_usage(); diff --git a/src/libirecovery.c b/src/libirecovery.c index c31a424..21cdfcf 100644 --- a/src/libirecovery.c +++ b/src/libirecovery.c @@ -19,10 +19,14 @@ #include #include #include +#include #include #include "libirecovery.h" +#define BUFFER_SIZE 0x1000 +#define debug(...) if(device->debug) fprintf(stderr, __VA_ARGS__) + irecv_device_t* irecv_init() { struct libusb_context* usb_context = NULL; @@ -37,7 +41,7 @@ irecv_device_t* irecv_init() { return device; } -int irecv_open(irecv_device_t* device) { +irecv_error_t irecv_open(irecv_device_t* device) { int i = 0; int usb_device_count = 0; struct libusb_device* usb_device = NULL; @@ -49,6 +53,7 @@ int irecv_open(irecv_device_t* device) { return IRECV_ERROR_NO_DEVICE; } + irecv_error_t error = 0; usb_device_count = libusb_get_device_list(device->context, &usb_device_list); for (i = 0; i < usb_device_count; i++) { usb_device = usb_device_list[i]; @@ -60,10 +65,20 @@ int irecv_open(irecv_device_t* device) { libusb_free_device_list(usb_device_list, 1); return IRECV_ERROR_UNABLE_TO_CONNECT; } - libusb_free_device_list(usb_device_list, 1); - device->mode = usb_descriptor.idProduct; + device->handle = usb_handle; + device->mode = (irecv_mode_t) usb_descriptor.idProduct; + error = irecv_set_configuration(device, 1); + if(error != IRECV_SUCCESS) { + return error; + } + + error = irecv_set_interface(device, 1, 1); + if(error != IRECV_SUCCESS) { + return error; + } + return IRECV_SUCCESS; } } @@ -71,7 +86,42 @@ int irecv_open(irecv_device_t* device) { return IRECV_ERROR_NO_DEVICE; } -int irecv_reset(irecv_device_t* device) { +irecv_error_t irecv_set_configuration(irecv_device_t* device, int configuration) { + if(device == NULL || device->handle == NULL) { + return IRECV_ERROR_NO_DEVICE; + } + + int current = 0; + libusb_get_configuration(device->handle, ¤t); + if(current != configuration) { + if (libusb_set_configuration(device->handle, configuration) < 0) { + return IRECV_ERROR_USB_CONFIGURATION; + } + } + + device->config = configuration; + return IRECV_SUCCESS; +} + +irecv_error_t irecv_set_interface(irecv_device_t* device, int interface, int alt_interface) { + if(device == NULL || device->handle == NULL) { + return IRECV_ERROR_NO_DEVICE; + } + + if (libusb_claim_interface(device->handle, interface) < 0) { + return IRECV_ERROR_USB_INTERFACE; + } + + if(libusb_set_interface_alt_setting(device->handle, interface, alt_interface) < 0) { + return IRECV_ERROR_USB_INTERFACE; + } + + device->interface = interface; + device->alt_interface = alt_interface; + return IRECV_SUCCESS; +} + +irecv_error_t irecv_reset(irecv_device_t* device) { if (device == NULL || device->handle != NULL) { return IRECV_ERROR_NO_DEVICE; } @@ -80,21 +130,25 @@ int irecv_reset(irecv_device_t* device) { return IRECV_SUCCESS; } -int irecv_close(irecv_device_t* device) { - if (device == NULL || device->handle != NULL) { +irecv_error_t irecv_close(irecv_device_t* device) { + if (device == NULL) { return IRECV_ERROR_NO_DEVICE; } - libusb_close(device->handle); - device->handle = NULL; + if(device->handle != NULL) { + libusb_release_interface(device->handle, 0); + libusb_release_interface(device->handle, 1); + libusb_close(device->handle); + device->handle = NULL; + } + return IRECV_SUCCESS; } -int irecv_exit(irecv_device_t* device) { +irecv_error_t irecv_exit(irecv_device_t* device) { if (device != NULL) { if (device->handle != NULL) { - libusb_close(device->handle); - device->handle = NULL; + irecv_close(device); } if (device->context != NULL) { @@ -109,12 +163,16 @@ int irecv_exit(irecv_device_t* device) { return IRECV_SUCCESS; } -void irecv_set_debug(irecv_device_t* device, int level) { +irecv_error_t irecv_set_debug(irecv_device_t* device, int level) { + if(device == NULL || device->context == NULL) { + return IRECV_ERROR_NO_DEVICE; + } + libusb_set_debug(device->context, level); device->debug = level; } -int irecv_send_command(irecv_device_t* device, unsigned char* command) { +irecv_error_t irecv_send_command(irecv_device_t* device, unsigned char* command) { if(device == NULL || device->handle == NULL) { return IRECV_ERROR_NO_DEVICE; } @@ -139,7 +197,11 @@ int irecv_send_command(irecv_device_t* device, unsigned char* command) { return IRECV_SUCCESS; } -int irecv_send_file(irecv_device_t* device, const char* filename) { +irecv_error_t irecv_send_file(irecv_device_t* device, const char* filename) { + if(device == NULL || device->handle == NULL) { + return IRECV_ERROR_NO_DEVICE; + } + FILE* file = fopen(filename, "rb"); if (file == NULL) { return IRECV_ERROR_FILE_NOT_FOUND; @@ -166,16 +228,29 @@ int irecv_send_file(irecv_device_t* device, const char* filename) { return irecv_send_buffer(device, buffer, length); } -unsigned int irecv_get_status(irecv_device_t* device) { - unsigned char status[6]; - memset(status, '\0', 6); - if(libusb_control_transfer(device->handle, 0xA1, 3, 0, 0, status, 6, 500) != 6) { +irecv_error_t irecv_get_status(irecv_device_t* device, unsigned int* status) { + if(device == NULL || device->handle == NULL) { + *status = 0; + return IRECV_ERROR_NO_DEVICE; + } + + unsigned char buffer[6]; + memset(buffer, '\0', 6); + if(libusb_control_transfer(device->handle, 0xA1, 3, 0, 0, buffer, 6, 500) != 6) { + *status = 0; return IRECV_ERROR_USB_STATUS; } - return (unsigned int) status[4]; + + *status = (unsigned int) buffer[4]; + return IRECV_SUCCESS; } -int irecv_send_buffer(irecv_device_t* device, unsigned char* buffer, int length) { +irecv_error_t irecv_send_buffer(irecv_device_t* device, unsigned char* buffer, unsigned int length) { + irecv_error_t error = 0; + if(device == NULL || device->handle == NULL) { + return IRECV_ERROR_NO_DEVICE; + } + int last = length % 0x800; int packets = length / 0x800; if (last != 0) { @@ -185,7 +260,7 @@ int irecv_send_buffer(irecv_device_t* device, unsigned char* buffer, int length) } int i = 0; - char status[6]; + unsigned int status = 0; for (i = 0; i < packets; i++) { int size = i + 1 < packets ? 0x800 : last; int bytes = libusb_control_transfer(device->handle, 0x21, 1, i, 0, &buffer[i * 0x800], size, 500); @@ -193,34 +268,60 @@ int irecv_send_buffer(irecv_device_t* device, unsigned char* buffer, int length) free(buffer); return IRECV_ERROR_USB_UPLOAD; } - - if (irecv_get_status(device) != 5) { + + error = irecv_get_status(device, &status); + if (error != IRECV_SUCCESS || status != 5) { free(buffer); - return IRECV_ERROR_USB_STATUS; + return error; } } libusb_control_transfer(device->handle, 0x21, 1, i, 0, buffer, 0, 1000); for (i = 0; i < 3; i++) { - irecv_get_status(device); + error = irecv_get_status(device, &status); + if(error != IRECV_SUCCESS) { + free(buffer); + return error; + } } free(buffer); return IRECV_SUCCESS; } -void irecv_update(irecv_device_t* device) { - if(device->receive_callback == NULL) { - return; +irecv_error_t irecv_update(irecv_device_t* device) { + unsigned char buffer[BUFFER_SIZE]; + memset(buffer, '\0', BUFFER_SIZE); + if(device == NULL || device->handle == NULL) { + return IRECV_ERROR_NO_DEVICE; + } + + int bytes = 0; + while(libusb_bulk_transfer(device->handle, 0x81, buffer, BUFFER_SIZE, &bytes, 100) == 0) { + if(bytes > 0) { + if(device->receive_callback(device, buffer, bytes) != bytes) { + return IRECV_ERROR_UNKNOWN; + } + } else break; } + + return IRECV_SUCCESS; } -int irecv_set_receiver(irecv_device_t* device, irecv_receive_callback callback) { +irecv_error_t irecv_set_receiver(irecv_device_t* device, irecv_receive_callback callback) { + if(device == NULL) { + return IRECV_ERROR_NO_DEVICE; + } + device->receive_callback = callback; return IRECV_SUCCESS; } -int irecv_set_sender(irecv_device_t* device, irecv_send_callback callback) { +irecv_error_t irecv_set_sender(irecv_device_t* device, irecv_send_callback callback) { + if(device == NULL) { + return IRECV_ERROR_NO_DEVICE; + } + device->send_callback = callback; return IRECV_SUCCESS; } -- cgit v1.1-32-gdbae