/**
* GreenPois0n Syringe - libirecovery.c
* Copyright (C) 2010 Chronic-Dev Team
* Copyright (C) 2010 Joshua Hill
*
* 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 <http://www.gnu.org/licenses/>.
**/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifndef WIN32
#include <libusb-1.0/libusb.h>
#ifdef __APPLE__
#include <libusb-1.0/os/darwin_usb.h>
#endif
#else
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <setupapi.h>
#endif
#include "libirecovery.h"
#define BUFFER_SIZE 0x1000
#define debug(...) if(libirecovery_debug) fprintf(stderr, __VA_ARGS__)
static int libirecovery_debug = 0;
#ifndef WIN32
static libusb_context* libirecovery_context = NULL;
#endif
int irecv_write_file(const char* filename, const void* data, size_t size);
int irecv_read_file(const char* filename, char** data, uint32_t* size);
#ifdef WIN32
static const GUID GUID_DEVINTERFACE_IBOOT = {0xED82A167L, 0xD61A, 0x4AF6, {0x9A, 0xB6, 0x11, 0xE5, 0x22, 0x36, 0xC5, 0x76}};
static const GUID GUID_DEVINTERFACE_DFU = {0xB8085869L, 0xFEB9, 0x404B, {0x8C, 0xB1, 0x1E, 0x5C, 0x14, 0xFA, 0x8C, 0x54}};
typedef struct usb_control_request {
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
char data[];
} usb_control_request;
irecv_error_t mobiledevice_openpipes(irecv_client_t client);
void mobiledevice_closepipes(irecv_client_t client);
irecv_error_t mobiledevice_connect(irecv_client_t* client) {
irecv_error_t ret;
SP_DEVICE_INTERFACE_DATA currentInterface;
HDEVINFO usbDevices;
DWORD i;
LPSTR path;
irecv_client_t _client = (irecv_client_t) malloc(sizeof(struct irecv_client));
memset(_client, 0, sizeof(struct irecv_client));
// Get DFU paths
usbDevices = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DFU, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if(!usbDevices) {
return IRECV_E_UNABLE_TO_CONNECT;
}
currentInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
for(i = 0; SetupDiEnumDeviceInterfaces(usbDevices, NULL, &GUID_DEVINTERFACE_DFU, i, ¤tInterface); i++) {
DWORD requiredSize = 0;
PSP_DEVICE_INTERFACE_DETAIL_DATA details;
SetupDiGetDeviceInterfaceDetail(usbDevices, ¤tInterface, NULL, 0, &requiredSize, NULL);
details = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(requiredSize);
details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if(!SetupDiGetDeviceInterfaceDetail(usbDevices, ¤tInterface, details, requiredSize, NULL, NULL)) {
irecv_close(_client);
free(details);
SetupDiDestroyDeviceInfoList(usbDevices);
return IRECV_E_UNABLE_TO_CONNECT;
} else {
LPSTR result = (LPSTR) malloc(requiredSize - sizeof(DWORD));
memcpy((void*) result, details->DevicePath, requiredSize - sizeof(DWORD));
free(details);
path = (LPSTR) malloc(requiredSize - sizeof(DWORD));
memcpy((void*) path, (void*) result, requiredSize - sizeof(DWORD));
TCHAR* pathEnd = strstr(path, "#{");
*pathEnd = '\0';
_client->DfuPath = result;
break;
}
}
SetupDiDestroyDeviceInfoList(usbDevices);
// Get iBoot path
usbDevices = SetupDiGetClassDevs(&GUID_DEVINTERFACE_IBOOT, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if(!usbDevices) {
irecv_close(_client);
return IRECV_E_UNABLE_TO_CONNECT;
}
currentInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
for(i = 0; SetupDiEnumDeviceInterfaces(usbDevices, NULL, &GUID_DEVINTERFACE_IBOOT, i, ¤tInterface); i++) {
DWORD requiredSize = 0;
PSP_DEVICE_INTERFACE_DETAIL_DATA details;
SetupDiGetDeviceInterfaceDetail(usbDevices, ¤tInterface, NULL, 0, &requiredSize, NULL);
details = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(requiredSize);
details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if(!SetupDiGetDeviceInterfaceDetail(usbDevices, ¤tInterface, details, requiredSize, NULL, NULL)) {
irecv_close(_client);
free(details);
SetupDiDestroyDeviceInfoList(usbDevices);
return IRECV_E_UNABLE_TO_CONNECT;
} else {
LPSTR result = (LPSTR) malloc(requiredSize - sizeof(DWORD));
memcpy((void*) result, details->DevicePath, requiredSize - sizeof(DWORD));
free(details);
if(strstr(result, path) == NULL) {
free(result);
continue;
}
_client->iBootPath = result;
break;
}
}
SetupDiDestroyDeviceInfoList(usbDevices);
free(path);
ret = mobiledevice_openpipes(_client);
if (ret != IRECV_E_SUCCESS) return ret;
*client = _client;
return IRECV_E_SUCCESS;
}
irecv_error_t mobiledevice_openpipes(irecv_client_t client) {
if (client->iBootPath && !(client->hIB = CreateFile(client->iBootPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL))) {
irecv_close(client);
return IRECV_E_UNABLE_TO_CONNECT;
}
if (client->DfuPath && !(client->hDFU = CreateFile(client->DfuPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL))) {
irecv_close(client);
return IRECV_E_UNABLE_TO_CONNECT;
}
if (client->iBootPath == NULL) {
client->mode = kDfuMode;
client->handle = client->hDFU;
} else {
client->mode = kRecoveryMode2;
client->handle = client->hIB;
}
return IRECV_E_SUCCESS;
}
void mobiledevice_closepipes(irecv_client_t client) {
if (client->hDFU!=NULL) {
CloseHandle(client->hDFU);
client->hDFU = NULL;
}
if (client->hIB!=NULL) {
CloseHandle(client->hIB);
client->hIB = NULL;
}
}
#endif
int check_context(irecv_client_t client) {
if (client == NULL || client->handle == NULL) {
return IRECV_E_NO_DEVICE;
}
return IRECV_E_SUCCESS;
}
void irecv_init() {
#ifndef WIN32
libusb_init(&libirecovery_context);
#endif
}
void irecv_exit() {
#ifndef WIN32
if (libirecovery_context != NULL) {
libusb_exit(libirecovery_context);
libirecovery_context = NULL;
}
#endif
}
#ifdef __APPLE__
void dummy_callback() { }
#endif
int irecv_control_transfer( irecv_client_t client,
uint8_t bmRequestType,
uint8_t bRequest,
uint16_t wValue,
uint16_t wIndex,
unsigned char *data,
uint16_t wLength,
unsigned int timeout) {
#ifndef WIN32
#ifndef __APPLE__
return libusb_control_transfer(client->handle, bmRequestType, bRequest, wValue, wIndex, data, wLength, timeout);
#else
if (timeout <= 10) {
// pod2g: dirty hack for limera1n support.
IOReturn kresult;
IOUSBDevRequest req;
bzero(&req, sizeof(req));
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)client->handle->os_priv;
struct darwin_device_priv *dpriv = (struct darwin_device_priv *)client->handle->dev->os_priv;
req.bmRequestType = bmRequestType;
req.bRequest = bRequest;
req.wValue = OSSwapLittleToHostInt16 (wValue);
req.wIndex = OSSwapLittleToHostInt16 (wIndex);
req.wLength = OSSwapLittleToHostInt16 (wLength);
req.pData = data + LIBUSB_CONTROL_SETUP_SIZE;
kresult = (*(dpriv->device))->DeviceRequestAsync(dpriv->device, &req, (IOAsyncCallback1) dummy_callback, NULL);
usleep(5 * 1000);
kresult = (*(dpriv->device))->USBDeviceAbortPipeZero (dpriv->device);
} else {
return libusb_control_transfer(client->handle, bmRequestType, bRequest, wValue, wIndex, data, wLength, timeout);
}
#endif
#else
DWORD count = 0;
DWORD ret;
BOOL bRet;
OVERLAPPED overlapped;
if (data == NULL) wLength = 0;
usb_control_request* packet = (usb_c
评论0