diff options
| author | 2010-05-16 14:15:26 -0400 | |
|---|---|---|
| committer | 2010-05-16 14:15:26 -0400 | |
| commit | 3491ef9c41f1cd867028881a8beebf1ad55373c7 (patch) | |
| tree | a8a0621e59f897544b1218eaf0ca513e1775a5cb | |
| parent | e7cc5716d941ee2c1ec554926e76448092d9e0c5 (diff) | |
| download | libirecovery-3491ef9c41f1cd867028881a8beebf1ad55373c7.tar.gz libirecovery-3491ef9c41f1cd867028881a8beebf1ad55373c7.tar.bz2 | |
Added irecv_set_configuration() and irecv_set_interface() functions and implemented bulk read
| -rw-r--r-- | include/libirecovery.h | 67 | ||||
| -rw-r--r-- | src/irecovery.c | 14 | ||||
| -rw-r--r-- | 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 <libusb-1.0/libusb.h> -#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 <stdio.h>  #include <stdlib.h>  #include <string.h> +#include <unistd.h>  #include <libusb-1.0/libusb.h>  #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;  } | 
