/** * iRecovery - Utility for DFU 2.0, WTF and Recovery Mode * Copyright (C) 2008 - 2009 westbaer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . **/ #include #include #include #include #include "libirecovery.h" static unsigned int irecv_debug = 0; int irecv_init(irecv_device** p_device) { struct libusb_context* usb_context = NULL; libusb_init(&usb_context); if (irecv_debug) libusb_set_debug(usb_context, 3); irecv_device* device = (irecv_device*) malloc(sizeof(irecv_device)); if (device == NULL) { *p_device = NULL; return IRECV_ERROR_OUT_OF_MEMORY; } memset(device, '\0', sizeof(irecv_device)); device->context = usb_context; *p_device = device; return IRECV_SUCCESS; } int irecv_open(irecv_device* device) { int i = 0; int usb_device_count = 0; struct libusb_device* usb_device = NULL; struct libusb_device** usb_device_list = NULL; struct libusb_device_handle* usb_handle = NULL; struct libusb_device_descriptor usb_descriptor; if (device == NULL || device->context == NULL) { return IRECV_ERROR_NO_DEVICE; } 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]; libusb_get_device_descriptor(usb_device, &usb_descriptor); if (usb_descriptor.idVendor == kAppleId) { libusb_open(usb_device, &usb_handle); if (usb_handle == NULL) { 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; return IRECV_SUCCESS; } } return IRECV_ERROR_NO_DEVICE; } int irecv_reset(irecv_device* device) { if (device == NULL || device->handle != NULL) { return IRECV_ERROR_NO_DEVICE; } libusb_reset_device(device->handle); return IRECV_SUCCESS; } int irecv_close(irecv_device* device) { if (device == NULL || device->handle != NULL) { return IRECV_ERROR_NO_DEVICE; } libusb_close(device->handle); device->handle = NULL; return IRECV_SUCCESS; } int irecv_exit(irecv_device* device) { if (device != NULL) { if (device->handle != NULL) { libusb_close(device->handle); device->handle = NULL; } if (device->context != NULL) { libusb_exit(device->context); device->context = NULL; } free(device); device = NULL; } return IRECV_SUCCESS; } void irecv_set_debug(int level) { printf("Debug has been set to %d\n", level); irecv_debug = level; } int irecv_send_command(irecv_device* device, const char* command) { if(device == NULL || device->handle == NULL) { return IRECV_ERROR_NO_DEVICE; } ssize_t length = strlen(command); if(length >= 0x100) { return IRECV_ERROR_INVALID_INPUT; } int ret = libusb_control_transfer(device->handle, 0x40, 0, 0, 0, (unsigned char*) command, length+1, 100); if(ret < 0) { return IRECV_ERROR_UNKNOWN; } return IRECV_SUCCESS; } int irecv_send_file(irecv_device* device, const char* filename) { FILE* file = fopen(filename, "rb"); if (file == NULL) { return IRECV_ERROR_FILE_NOT_FOUND; } fseek(file, 0, SEEK_END); int length = ftell(file); fseek(file, 0, SEEK_SET); unsigned char* buffer = (unsigned char*) malloc(length); if (buffer == NULL) { fclose(file); return IRECV_ERROR_OUT_OF_MEMORY; } int bytes = fread(buffer, 1, length, file); fclose(file); if(bytes != length) { free(buffer); return IRECV_ERROR_UNKNOWN; } return irecv_send_buffer(device, buffer, length); } unsigned int irecv_get_status(irecv_device* device) { unsigned char status[6]; memset(status, '\0', 6); if(libusb_control_transfer(device->handle, 0xA1, 3, 0, 0, status, 6, 500) != 6) { return IRECV_ERROR_USB_STATUS; } return (unsigned int) status[4]; } int irecv_send_buffer(irecv_device* device, unsigned char* buffer, int length) { int packets = length / 0x800; if (length % 0x800) { packets++; } int last = length % 0x800; if (!last) { last = 0x800; } int i = 0; char status[6]; 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); if (bytes != size) { free(buffer); return IRECV_ERROR_USB_UPLOAD; } if (irecv_get_status(device) != 5) { free(buffer); return IRECV_ERROR_USB_STATUS; } } libusb_control_transfer(device->handle, 0x21, 1, i, 0, buffer, 0, 1000); for (i = 6; i <= 8; i++) { if (irecv_get_status(device) != i) { free(buffer); return IRECV_ERROR_USB_STATUS; } } free(buffer); return IRECV_SUCCESS; } /* int send_file(struct libusb_device_handle *handle, const char* filename, int loadOffset) { FILE* file = fopen(filename, "rb"); if (file == NULL) { printf("send_file: File %s not found.\n", filename); return -1; } fseek(file, 0, SEEK_END); int len = ftell(file); fseek(file, 0, SEEK_SET); char* buffer = malloc(len + loadOffset); if (buffer == NULL) { printf("send_file: Error allocating memory!\n"); fclose(file); return -1; } fread(&buffer[loadOffset], 1, len, file); fclose(file); len += loadOffset; int packets = len / 0x800; if (len % 0x800) { packets++; } int last = len % 0x800; if (!last) { last = 0x800; } int i = 0; char response[6]; for (i = 0; i < packets; i++) { int size = i + 1 < packets ? 0x800 : last; if (!libusb_control_transfer(handle, 0x21, 1, i, 0, &buffer[i * 0x800], size, 1000)) { printf("send_file: Error sending packet!\n"); return -1; } if (libusb_control_transfer(handle, 0xA1, 3, 0, 0, response, 6, 1000) != 6) { printf("send_file: Error receiving status!\n"); return -1; } else { if (response[4] != 5) { printf("send_file: Status error!\n"); return -1; } } } libusb_control_transfer(handle, 0x21, 1, i, 0, buffer, 0, 1000); for (i = 6; i <= 8; i++) { if (libusb_control_transfer(handle, 0xA1, 3, 0, 0, response, 6, 1000) != 6) { printf("send_file: Error receiving status!\n"); return -1; } else { if (response[4] != i) { printf("send_file: Status error!\n"); return -1; } } } free(buffer); return 0; } */