diff options
| -rw-r--r-- | configure.ac | 32 | ||||
| -rw-r--r-- | include/libirecovery.h | 1 | ||||
| -rw-r--r-- | src/libirecovery.c | 143 | ||||
| -rw-r--r-- | tools/irecovery.c | 8 | 
4 files changed, 172 insertions, 12 deletions
| diff --git a/configure.ac b/configure.ac index e13c571..1f10bb7 100644 --- a/configure.ac +++ b/configure.ac @@ -59,6 +59,11 @@ case "$host_os" in  esac  AC_SUBST(LIBIRECOVERYLDFLAGS) +AC_ARG_WITH([dummy], +	[AS_HELP_STRING([--with-dummy], [Use no USB driver at all [default=no]. This is only useful if you just want to query the device list by product type or hardware model. All other operations are no-ops or will return IRECV_E_UNSUPPORTED.])], +	[], +	[with_dummy=no]) +  AS_IF([test "x$have_iokit" = "xyes"], [  	AC_ARG_WITH([iokit],  		[AS_HELP_STRING([--with-iokit], [Use IOKit instead of libusb on OS X [default=yes]])], @@ -67,17 +72,22 @@ AS_IF([test "x$have_iokit" = "xyes"], [  	], []  ) -AS_IF([test "x$with_iokit" = "xyes" && test "x$have_iokit" = "xyes"] , [ -		AC_DEFINE(HAVE_IOKIT, 1, [Define if we have IOKit]) -		USB_BACKEND="IOKit" -	], -	[ -		PKG_CHECK_MODULES(libusb, libusb-1.0 >= $LIBUSB_VERSION) -		USB_BACKEND="libusb `$PKG_CONFIG --modversion libusb-1.0`" -		LIBUSB_REQUIRED="libusb-1.0 >= $LIBUSB_VERSION" -		AC_SUBST(LIBUSB_REQUIRED) -	] -) +AS_IF([test "x$with_dummy" = "xyes"], [ +	AC_DEFINE(USE_DUMMY, 1, [Define if we are using dummy USB driver]) +	USB_BACKEND="dummy" +], [ +	AS_IF([test "x$with_iokit" = "xyes" && test "x$have_iokit" = "xyes"] , [ +			AC_DEFINE(HAVE_IOKIT, 1, [Define if we have IOKit]) +			USB_BACKEND="IOKit" +		], +		[ +			PKG_CHECK_MODULES(libusb, libusb-1.0 >= $LIBUSB_VERSION) +			USB_BACKEND="libusb `$PKG_CONFIG --modversion libusb-1.0`" +			LIBUSB_REQUIRED="libusb-1.0 >= $LIBUSB_VERSION" +			AC_SUBST(LIBUSB_REQUIRED) +		] +	) +])  # Checks for header files.  AC_HEADER_STDC diff --git a/include/libirecovery.h b/include/libirecovery.h index 7f9c2b4..73fe6f0 100644 --- a/include/libirecovery.h +++ b/include/libirecovery.h @@ -49,6 +49,7 @@ typedef enum {  	IRECV_E_USB_CONFIGURATION = -9,  	IRECV_E_PIPE              = -10,  	IRECV_E_TIMEOUT           = -11, +	IRECV_E_UNSUPPORTED       = -254,  	IRECV_E_UNKNOWN_ERROR     = -255  } irecv_error_t; diff --git a/src/libirecovery.c b/src/libirecovery.c index bf96408..945e591 100644 --- a/src/libirecovery.c +++ b/src/libirecovery.c @@ -31,6 +31,7 @@  #include <unistd.h>  #include <sys/stat.h> +#ifndef USE_DUMMY  #ifndef WIN32  #ifndef HAVE_IOKIT  #include <libusb.h> @@ -52,6 +53,7 @@  #define sleep(n) Sleep(1000 * n)  #endif  #endif +#endif  #ifdef WIN32  #define IRECV_API __declspec( dllexport ) @@ -72,6 +74,7 @@ struct irecv_client_private {  	int usb_alt_interface;  	unsigned int mode;  	struct irecv_device_info device_info; +#ifndef USE_DUMMY  #ifndef WIN32  #ifndef HAVE_IOKIT  	libusb_device_handle* handle; @@ -92,6 +95,7 @@ struct irecv_client_private {  	irecv_event_cb_t precommand_callback;  	irecv_event_cb_t postcommand_callback;  	irecv_event_cb_t disconnected_callback; +#endif  };  #define USB_TIMEOUT 10000 @@ -101,11 +105,13 @@ struct irecv_client_private {  #define debug(...) if(libirecovery_debug) fprintf(stderr, __VA_ARGS__)  static int libirecovery_debug = 0; +#ifndef USE_DUMMY  #ifndef WIN32  #ifndef HAVE_IOKIT  static libusb_context* libirecovery_context = NULL;  #endif  #endif +#endif  static struct irecv_device irecv_devices[] = {  	{"iPhone1,1",  "m68ap", 0x00, 0x8900 }, @@ -197,6 +203,7 @@ static struct irecv_device irecv_devices[] = {  	{        NULL,    NULL,   -1,     -1 }  }; +#ifndef USE_DUMMY  static unsigned int dfu_hash_t1[256] = {  	0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,  	0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, @@ -772,16 +779,20 @@ static int check_context(irecv_client_t client) {  	return IRECV_E_SUCCESS;  } +#endif  IRECV_API void irecv_init(void) { +#ifndef USE_DUMMY  #ifndef WIN32  #ifndef HAVE_IOKIT  	libusb_init(&libirecovery_context);  #endif  #endif +#endif  }  IRECV_API void irecv_exit(void) { +#ifndef USE_DUMMY  #ifndef WIN32  #ifndef HAVE_IOKIT  	if (libirecovery_context != NULL) { @@ -790,8 +801,10 @@ IRECV_API void irecv_exit(void) {  	}  #endif  #endif +#endif  } +#ifndef USE_DUMMY  #ifdef HAVE_IOKIT  static int iokit_usb_control_transfer(irecv_client_t client, uint8_t bm_request_type, uint8_t b_request, uint16_t w_value, uint16_t w_index, unsigned char *data, uint16_t w_length, unsigned int timeout)  { @@ -824,8 +837,12 @@ static int iokit_usb_control_transfer(irecv_client_t client, uint8_t bm_request_  	void dummy_callback(void) { }  #endif  #endif +#endif  IRECV_API int irecv_usb_control_transfer(irecv_client_t client, uint8_t bm_request_type, uint8_t b_request, uint16_t w_value, uint16_t w_index, unsigned char *data, uint16_t w_length, unsigned int timeout) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  #ifndef WIN32  #ifdef HAVE_IOKIT  	return iokit_usb_control_transfer(client, bm_request_type, b_request, w_value, w_index, data, w_length, timeout); @@ -873,8 +890,10 @@ IRECV_API int irecv_usb_control_transfer(irecv_client_t client, uint8_t bm_reque  	return count;  #endif +#endif  } +#ifndef USE_DUMMY  #ifdef HAVE_IOKIT  static int iokit_usb_bulk_transfer(irecv_client_t client,  						unsigned char endpoint, @@ -928,6 +947,7 @@ static int iokit_usb_bulk_transfer(irecv_client_t client,  	return IRECV_E_USB_INTERFACE;  }  #endif +#endif  IRECV_API int irecv_usb_bulk_transfer(irecv_client_t client,  							unsigned char endpoint, @@ -935,6 +955,9 @@ IRECV_API int irecv_usb_bulk_transfer(irecv_client_t client,  							int length,  							int *transferred,  							unsigned int timeout) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	int ret;  #ifndef WIN32 @@ -956,8 +979,10 @@ IRECV_API int irecv_usb_bulk_transfer(irecv_client_t client,  #endif  	return ret; +#endif  } +#ifndef USE_DUMMY  #ifdef HAVE_IOKIT  static irecv_error_t iokit_usb_open_service(irecv_client_t *pclient, io_service_t service) { @@ -1143,8 +1168,12 @@ UInt16 *pids = all_pids;  	return iokit_usb_open_service(pclient, ret_service);  }  #endif +#endif  IRECV_API irecv_error_t irecv_open_with_ecid(irecv_client_t* pclient, unsigned long long ecid) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	if(libirecovery_debug) {  		irecv_set_debug_level(libirecovery_debug);  	} @@ -1282,9 +1311,13 @@ IRECV_API irecv_error_t irecv_open_with_ecid(irecv_client_t* pclient, unsigned l  	return ret;  #endif +#endif  }  IRECV_API irecv_error_t irecv_usb_set_configuration(irecv_client_t client, int configuration) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	if (check_context(client) != IRECV_E_SUCCESS)  		return IRECV_E_NO_DEVICE; @@ -1312,8 +1345,10 @@ IRECV_API irecv_error_t irecv_usb_set_configuration(irecv_client_t client, int c  #endif  	return IRECV_E_SUCCESS; +#endif  } +#ifndef USE_DUMMY  #ifdef HAVE_IOKIT  static IOReturn iokit_usb_get_interface(IOUSBDeviceInterface320 **device, uint8_t ifc, io_service_t *usbInterfacep) { @@ -1393,8 +1428,12 @@ static irecv_error_t iokit_usb_set_interface(irecv_client_t client, int usb_inte  	return IRECV_E_SUCCESS;  }  #endif +#endif  IRECV_API irecv_error_t irecv_usb_set_interface(irecv_client_t client, int usb_interface, int usb_alt_interface) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	if (check_context(client) != IRECV_E_SUCCESS)  		return IRECV_E_NO_DEVICE; @@ -1424,9 +1463,13 @@ IRECV_API irecv_error_t irecv_usb_set_interface(irecv_client_t client, int usb_i  	client->usb_alt_interface = usb_alt_interface;  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API irecv_error_t irecv_reset(irecv_client_t client) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	if (check_context(client) != IRECV_E_SUCCESS)  		return IRECV_E_NO_DEVICE; @@ -1453,9 +1496,13 @@ IRECV_API irecv_error_t irecv_reset(irecv_client_t client) {  #endif  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API irecv_error_t irecv_open_with_ecid_and_attempts(irecv_client_t* pclient, unsigned long long ecid, int attempts) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	int i;  	for (i = 0; i < attempts; i++) { @@ -1472,9 +1519,13 @@ IRECV_API irecv_error_t irecv_open_with_ecid_and_attempts(irecv_client_t* pclien  	}  	return IRECV_E_UNABLE_TO_CONNECT; +#endif  }  IRECV_API irecv_error_t irecv_event_subscribe(irecv_client_t client, irecv_event_type type, irecv_event_cb_t callback, void* user_data) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	switch(type) {  	case IRECV_RECEIVED:  		client->received_callback = callback; @@ -1502,9 +1553,13 @@ IRECV_API irecv_error_t irecv_event_subscribe(irecv_client_t client, irecv_event  	}  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API irecv_error_t irecv_event_unsubscribe(irecv_client_t client, irecv_event_type type) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	switch(type) {  	case IRECV_RECEIVED:  		client->received_callback = NULL; @@ -1532,9 +1587,13 @@ IRECV_API irecv_error_t irecv_event_unsubscribe(irecv_client_t client, irecv_eve  	}  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API irecv_error_t irecv_close(irecv_client_t client) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	if (client != NULL) {  		if(client->disconnected_callback != NULL) {  			irecv_event_t event; @@ -1582,10 +1641,12 @@ IRECV_API irecv_error_t irecv_close(irecv_client_t client) {  	}  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API void irecv_set_debug_level(int level) {  	libirecovery_debug = level; +#ifndef USE_DUMMY  #ifndef WIN32  #ifndef HAVE_IOKIT  	if(libirecovery_context) { @@ -1593,8 +1654,10 @@ IRECV_API void irecv_set_debug_level(int level) {  	}  #endif  #endif +#endif  } +#ifndef USE_DUMMY  static irecv_error_t irecv_send_command_raw(irecv_client_t client, const char* command) {  	unsigned int length = strlen(command);  	if (length >= 0x100) { @@ -1607,8 +1670,12 @@ static irecv_error_t irecv_send_command_raw(irecv_client_t client, const char* c  	return IRECV_E_SUCCESS;  } +#endif  IRECV_API irecv_error_t irecv_send_command(irecv_client_t client, const char* command) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	irecv_error_t error = 0;  	if (check_context(client) != IRECV_E_SUCCESS) @@ -1646,9 +1713,13 @@ IRECV_API irecv_error_t irecv_send_command(irecv_client_t client, const char* co  	}  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API irecv_error_t irecv_send_file(irecv_client_t client, const char* filename, int dfu_notify_finished) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	if (check_context(client) != IRECV_E_SUCCESS)  		return IRECV_E_NO_DEVICE; @@ -1681,8 +1752,10 @@ IRECV_API irecv_error_t irecv_send_file(irecv_client_t client, const char* filen  	free(buffer);  	return error; +#endif  } +#ifndef USE_DUMMY  static irecv_error_t irecv_get_status(irecv_client_t client, unsigned int* status) {  	if (check_context(client) != IRECV_E_SUCCESS) {  		*status = 0; @@ -1700,8 +1773,12 @@ static irecv_error_t irecv_get_status(irecv_client_t client, unsigned int* statu  	return IRECV_E_SUCCESS;  } +#endif  IRECV_API irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned long length, int dfu_notify_finished) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	irecv_error_t error = 0;  	int recovery_mode = ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE)); @@ -1862,9 +1939,13 @@ IRECV_API irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char*  	}  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API irecv_error_t irecv_receive(irecv_client_t client) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	char buffer[BUFFER_SIZE];  	memset(buffer, '\0', BUFFER_SIZE); @@ -1887,9 +1968,13 @@ IRECV_API irecv_error_t irecv_receive(irecv_client_t client) {  	}  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API irecv_error_t irecv_getenv(irecv_client_t client, const char* variable, char** value) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	char command[256];  	if (check_context(client) != IRECV_E_SUCCESS) @@ -1923,9 +2008,13 @@ IRECV_API irecv_error_t irecv_getenv(irecv_client_t client, const char* variable  	*value = response;  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API irecv_error_t irecv_getret(irecv_client_t client, unsigned int* value) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	if (check_context(client) != IRECV_E_SUCCESS)  		return IRECV_E_NO_DEVICE; @@ -1942,25 +2031,35 @@ IRECV_API irecv_error_t irecv_getret(irecv_client_t client, unsigned int* value)  	*value = (unsigned int) *response;  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API irecv_error_t irecv_get_mode(irecv_client_t client, int* mode) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	if (check_context(client) != IRECV_E_SUCCESS)  		return IRECV_E_NO_DEVICE;  	*mode = client->mode;  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API const struct irecv_device_info* irecv_get_device_info(irecv_client_t client)  { +#ifdef USE_DUMMY +	return NULL; +#else  	if (check_context(client) != IRECV_E_SUCCESS)  		return NULL;  	return &client->device_info; +#endif  } +#ifndef USE_DUMMY  #ifdef HAVE_IOKIT  static void *iokit_limera1n_usb_submit_request(void *argv) {  	void **args = argv; @@ -1974,8 +2073,12 @@ static void *iokit_limera1n_usb_submit_request(void *argv) {  	return NULL;  }  #endif +#endif  IRECV_API irecv_error_t irecv_trigger_limera1n_exploit(irecv_client_t client) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	if (check_context(client) != IRECV_E_SUCCESS)  		return IRECV_E_NO_DEVICE; @@ -2020,9 +2123,13 @@ IRECV_API irecv_error_t irecv_trigger_limera1n_exploit(irecv_client_t client) {  #endif  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API irecv_error_t irecv_execute_script(irecv_client_t client, const char* script) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	irecv_error_t error = IRECV_E_SUCCESS;  	if (check_context(client) != IRECV_E_SUCCESS)  		return IRECV_E_NO_DEVICE; @@ -2048,18 +2155,26 @@ IRECV_API irecv_error_t irecv_execute_script(irecv_client_t client, const char*  	free(body);  	return error; +#endif  }  IRECV_API irecv_error_t irecv_saveenv(irecv_client_t client) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	irecv_error_t error = irecv_send_command_raw(client, "saveenv");  	if(error != IRECV_E_SUCCESS) {  		return error;  	}  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API irecv_error_t irecv_setenv(irecv_client_t client, const char* variable, const char* value) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	char command[256];  	if (check_context(client) != IRECV_E_SUCCESS) @@ -2077,15 +2192,20 @@ IRECV_API irecv_error_t irecv_setenv(irecv_client_t client, const char* variable  	}  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API irecv_error_t irecv_reboot(irecv_client_t client) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	irecv_error_t error = irecv_send_command_raw(client, "reboot");  	if(error != IRECV_E_SUCCESS) {  		return error;  	}  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API const char* irecv_strerror(irecv_error_t error) { @@ -2126,6 +2246,9 @@ IRECV_API const char* irecv_strerror(irecv_error_t error) {  	case IRECV_E_TIMEOUT:  		return "Timeout talking to device"; +	case IRECV_E_UNSUPPORTED: +		return "Operation unsupported by driver"; +  	default:  		return "Unknown error";  	} @@ -2134,6 +2257,9 @@ IRECV_API const char* irecv_strerror(irecv_error_t error) {  }  IRECV_API irecv_error_t irecv_reset_counters(irecv_client_t client) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	if (check_context(client) != IRECV_E_SUCCESS)  		return IRECV_E_NO_DEVICE; @@ -2142,9 +2268,13 @@ IRECV_API irecv_error_t irecv_reset_counters(irecv_client_t client) {  	}  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API irecv_error_t irecv_recv_buffer(irecv_client_t client, char* buffer, unsigned long length) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	int recovery_mode = ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE));  	if (check_context(client) != IRECV_E_SUCCESS) @@ -2184,9 +2314,13 @@ IRECV_API irecv_error_t irecv_recv_buffer(irecv_client_t client, char* buffer, u  	}  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API irecv_error_t irecv_finish_transfer(irecv_client_t client) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	int i = 0;  	unsigned int status = 0; @@ -2202,6 +2336,7 @@ IRECV_API irecv_error_t irecv_finish_transfer(irecv_client_t client) {  	irecv_reset(client);  	return IRECV_E_SUCCESS; +#endif  }  IRECV_API irecv_device_t irecv_devices_get_all(void) { @@ -2209,6 +2344,9 @@ IRECV_API irecv_device_t irecv_devices_get_all(void) {  }  IRECV_API irecv_error_t irecv_devices_get_device_by_client(irecv_client_t client, irecv_device_t* device) { +#ifdef USE_DUMMY +	return IRECV_E_UNSUPPORTED; +#else  	int i = 0;  	*device = NULL; @@ -2225,6 +2363,7 @@ IRECV_API irecv_error_t irecv_devices_get_device_by_client(irecv_client_t client  	}  	return IRECV_E_NO_DEVICE; +#endif  }  IRECV_API irecv_error_t irecv_devices_get_device_by_product_type(const char* product_type, irecv_device_t* device) { @@ -2264,6 +2403,9 @@ IRECV_API irecv_error_t irecv_devices_get_device_by_hardware_model(const char* h  }  IRECV_API irecv_client_t irecv_reconnect(irecv_client_t client, int initial_pause) { +#ifdef USE_DUMMY +	return NULL; +#else  	irecv_error_t error = 0;  	irecv_client_t new_client = NULL;  	irecv_event_cb_t progress_callback = client->progress_callback; @@ -2287,4 +2429,5 @@ IRECV_API irecv_client_t irecv_reconnect(irecv_client_t client, int initial_paus  	new_client->progress_callback = progress_callback;  	return new_client; +#endif  } diff --git a/tools/irecovery.c b/tools/irecovery.c index f250dc5..2db6f4f 100644 --- a/tools/irecovery.c +++ b/tools/irecovery.c @@ -459,12 +459,18 @@ int main(int argc, char* argv[]) {  	for (i = 0; i <= 5; i++) {  		debug("Attempting to connect... \n"); -		if (irecv_open_with_ecid(&client, ecid) != IRECV_E_SUCCESS) +		irecv_error_t err = irecv_open_with_ecid(&client, ecid); +		if (err == IRECV_E_UNSUPPORTED) { +			fprintf(stderr, "ERROR: %s\n", irecv_strerror(err)); +			return -1; +		} +		else if (err != IRECV_E_SUCCESS)  			sleep(1);  		else  			break;  		if (i == 5) { +			fprintf(stderr, "ERROR: %s\n", irecv_strerror(err));  			return -1;  		}  	} | 
