summaryrefslogtreecommitdiffstats
path: root/src/libirecovery.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libirecovery.c')
-rw-r--r--src/libirecovery.c209
1 files changed, 45 insertions, 164 deletions
diff --git a/src/libirecovery.c b/src/libirecovery.c
index f6ff480..16330d2 100644
--- a/src/libirecovery.c
+++ b/src/libirecovery.c
@@ -77,10 +77,6 @@ struct irecv_client_private {
77#endif 77#endif
78#else 78#else
79 HANDLE handle; 79 HANDLE handle;
80 HANDLE hDFU;
81 HANDLE hIB;
82 LPSTR iBootPath;
83 LPSTR DfuPath;
84#endif 80#endif
85 irecv_event_cb_t progress_callback; 81 irecv_event_cb_t progress_callback;
86 irecv_event_cb_t received_callback; 82 irecv_event_cb_t received_callback;
@@ -1089,196 +1085,85 @@ typedef struct usb_control_request {
1089 char data[]; 1085 char data[];
1090} usb_control_request; 1086} usb_control_request;
1091 1087
1092static irecv_error_t win32_openpipes(irecv_client_t client)
1093{
1094 if (client->iBootPath && !(client->hIB = CreateFileA(client->iBootPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL))) {
1095 irecv_close(client);
1096 return IRECV_E_UNABLE_TO_CONNECT;
1097 }
1098
1099 if (client->DfuPath && !(client->hDFU = CreateFileA(client->DfuPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL))) {
1100 irecv_close(client);
1101 return IRECV_E_UNABLE_TO_CONNECT;
1102 }
1103
1104 client->mode = 0;
1105 if (client->iBootPath == NULL) {
1106 if (strncmp(client->DfuPath, "\\\\?\\usb#vid_05ac&pid_", 21) == 0) {
1107 sscanf(client->DfuPath+21, "%x#", &client->mode);
1108 }
1109 client->handle = client->hDFU;
1110 } else {
1111 if (strncmp(client->iBootPath, "\\\\?\\usb#vid_05ac&pid_", 21) == 0) {
1112 sscanf(client->iBootPath+21, "%x#", &client->mode);
1113 }
1114 client->handle = client->hIB;
1115 }
1116
1117 if (client->mode == 0) {
1118 irecv_close(client);
1119 return IRECV_E_UNABLE_TO_CONNECT;
1120 }
1121
1122 return IRECV_E_SUCCESS;
1123}
1124
1125static void win32_closepipes(irecv_client_t client)
1126{
1127 if (client->hDFU!=NULL) {
1128 CloseHandle(client->hDFU);
1129 client->hDFU = NULL;
1130 }
1131 if (client->hIB!=NULL) {
1132 CloseHandle(client->hIB);
1133 client->hIB = NULL;
1134 }
1135}
1136
1137static irecv_error_t win32_open_with_ecid(irecv_client_t* client, uint64_t ecid) 1088static irecv_error_t win32_open_with_ecid(irecv_client_t* client, uint64_t ecid)
1138{ 1089{
1139 int found = 0; 1090 int found = 0;
1091 const GUID *guids[] = { &GUID_DEVINTERFACE_DFU, &GUID_DEVINTERFACE_IBOOT, NULL };
1140 SP_DEVICE_INTERFACE_DATA currentInterface; 1092 SP_DEVICE_INTERFACE_DATA currentInterface;
1141 HDEVINFO usbDevices; 1093 HDEVINFO usbDevices;
1142 DWORD i; 1094 DWORD i;
1143 irecv_client_t _client = (irecv_client_t) malloc(sizeof(struct irecv_client_private)); 1095 irecv_client_t _client = (irecv_client_t) malloc(sizeof(struct irecv_client_private));
1144 memset(_client, 0, sizeof(struct irecv_client_private)); 1096 memset(_client, 0, sizeof(struct irecv_client_private));
1145 1097
1146 /* get DFU paths */ 1098 int k;
1147 usbDevices = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DFU, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); 1099 for (k = 0; !found && guids[k]; k++) {
1148 memset(&currentInterface, '\0', sizeof(SP_DEVICE_INTERFACE_DATA)); 1100 usbDevices = SetupDiGetClassDevs(guids[k], NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
1149 currentInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); 1101 memset(&currentInterface, '\0', sizeof(SP_DEVICE_INTERFACE_DATA));
1150 for (i = 0; usbDevices && SetupDiEnumDeviceInterfaces(usbDevices, NULL, &GUID_DEVINTERFACE_DFU, i, &currentInterface); i++) { 1102 currentInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
1151 free(_client->DfuPath); 1103 for (i = 0; usbDevices && SetupDiEnumDeviceInterfaces(usbDevices, NULL, guids[k], i, &currentInterface); i++) {
1152 _client->DfuPath = NULL; 1104 _client->handle = INVALID_HANDLE_VALUE;
1153 _client->handle = NULL; 1105 DWORD requiredSize = 0;
1154 DWORD requiredSize = 0; 1106 PSP_DEVICE_INTERFACE_DETAIL_DATA_A details;
1155 PSP_DEVICE_INTERFACE_DETAIL_DATA_A details; 1107 SetupDiGetDeviceInterfaceDetailA(usbDevices, &currentInterface, NULL, 0, &requiredSize, NULL);
1156 SetupDiGetDeviceInterfaceDetailA(usbDevices, &currentInterface, NULL, 0, &requiredSize, NULL); 1108 details = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A) malloc(requiredSize);
1157 details = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A) malloc(requiredSize); 1109 details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
1158 details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); 1110 if (!SetupDiGetDeviceInterfaceDetailA(usbDevices, &currentInterface, details, requiredSize, NULL, NULL)) {
1159 if (!SetupDiGetDeviceInterfaceDetailA(usbDevices, &currentInterface, details, requiredSize, NULL, NULL)) { 1111 free(details);
1160 free(details);
1161 continue;
1162 } else {
1163 LPSTR result = (LPSTR) malloc(requiredSize - sizeof(DWORD));
1164 memcpy((void*) result, details->DevicePath, requiredSize - sizeof(DWORD));
1165 free(details);
1166
1167 _client->DfuPath = result;
1168 if (win32_openpipes(_client) != IRECV_E_SUCCESS) {
1169 win32_closepipes(_client);
1170 continue; 1112 continue;
1171 } 1113 }
1172 1114
1173 if (ecid == IRECV_K_WTF_MODE) { 1115 unsigned int pid = 0;
1174 if (_client->mode != IRECV_K_WTF_MODE) { 1116 if (sscanf(details->DevicePath, "\\\\?\\usb#vid_05ac&pid_%04x", &pid)!= 1) {
1175 /* special ecid case, ignore !IRECV_K_WTF_MODE */ 1117 debug("%s: ERROR: failed to parse PID! path: %s\n", __func__, details->DevicePath);
1176 continue; 1118 free(details);
1177 } else {
1178 ecid = 0;
1179 }
1180 }
1181
1182 if ((ecid != 0) && (_client->mode == IRECV_K_WTF_MODE)) {
1183 /* we can't get ecid in WTF mode */
1184 win32_closepipes(_client);
1185 continue; 1119 continue;
1186 } 1120 }
1187 1121 // make sure the current device is actually in the right mode for the given driver interface
1188 char serial_str[256]; 1122 if ((guids[k] == &GUID_DEVINTERFACE_DFU && pid != IRECV_K_DFU_MODE && pid != IRECV_K_WTF_MODE)
1189 serial_str[0] = '\0'; 1123 || (guids[k] == &GUID_DEVINTERFACE_IBOOT && (pid < IRECV_K_RECOVERY_MODE_1 || pid > IRECV_K_RECOVERY_MODE_4))
1190 1124 ) {
1191 char *p = result; 1125 free(details);
1192 while ((p = strstr(p, "\\usb"))) {
1193 if (sscanf(p, "\\usb#vid_%*04x&pid_%*04x#%s", serial_str) == 1)
1194 break;
1195 p += 4;
1196 }
1197
1198 if (serial_str[0] == '\0') {
1199 win32_closepipes(_client);
1200 continue; 1126 continue;
1201 } 1127 }
1202 1128
1203 p = strchr(serial_str, '#'); 1129 _client->handle = CreateFileA(details->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
1204 if (p) { 1130 if (_client->handle == INVALID_HANDLE_VALUE) {
1205 *p = '\0'; 1131 free(details);
1206 } 1132 continue;
1207
1208 unsigned int j;
1209 for (j = 0; j < strlen(serial_str); j++) {
1210 if (serial_str[j] == '_') {
1211 serial_str[j] = ' ';
1212 } else {
1213 serial_str[j] = toupper(serial_str[j]);
1214 }
1215 } 1133 }
1134 _client->mode = pid;
1216 1135
1217 irecv_load_device_info_from_iboot_string(_client, serial_str); 1136 if (ecid == IRECV_K_WTF_MODE) {
1218 1137 if (_client->mode != IRECV_K_WTF_MODE) {
1219 if (ecid != 0) { 1138 /* special ecid case, ignore !IRECV_K_WTF_MODE */
1220 if (_client->device_info.ecid != ecid) { 1139 CloseHandle(_client->handle);
1221 win32_closepipes(_client); 1140 free(details);
1222 continue; 1141 continue;
1142 } else {
1143 ecid = 0;
1223 } 1144 }
1224 debug("found device with ECID %016" PRIx64 "\n", (uint64_t)ecid);
1225 }
1226 found = 1;
1227 break;
1228 }
1229 }
1230 SetupDiDestroyDeviceInfoList(usbDevices);
1231
1232 if (found) {
1233 *client = _client;
1234 return IRECV_E_SUCCESS;
1235 }
1236
1237 /* get iBoot path */
1238 usbDevices = SetupDiGetClassDevs(&GUID_DEVINTERFACE_IBOOT, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
1239 memset(&currentInterface, '\0', sizeof(SP_DEVICE_INTERFACE_DATA));
1240 currentInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
1241 for (i = 0; usbDevices && SetupDiEnumDeviceInterfaces(usbDevices, NULL, &GUID_DEVINTERFACE_IBOOT, i, &currentInterface); i++) {
1242 free(_client->iBootPath);
1243 _client->iBootPath = NULL;
1244 _client->handle = NULL;
1245 DWORD requiredSize = 0;
1246 PSP_DEVICE_INTERFACE_DETAIL_DATA_A details;
1247 SetupDiGetDeviceInterfaceDetailA(usbDevices, &currentInterface, NULL, 0, &requiredSize, NULL);
1248 details = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A) malloc(requiredSize);
1249 details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
1250 if (!SetupDiGetDeviceInterfaceDetailA(usbDevices, &currentInterface, details, requiredSize, NULL, NULL)) {
1251 free(details);
1252 continue;
1253 } else {
1254 LPSTR result = (LPSTR) malloc(requiredSize - sizeof(DWORD));
1255 memcpy((void*) result, details->DevicePath, requiredSize - sizeof(DWORD));
1256 free(details);
1257
1258 _client->iBootPath = result;
1259 if (win32_openpipes(_client) != IRECV_E_SUCCESS) {
1260 win32_closepipes(_client);
1261 continue;
1262 } 1145 }
1263 1146
1264 if ((ecid != 0) && (_client->mode == IRECV_K_WTF_MODE)) { 1147 if ((ecid != 0) && (_client->mode == IRECV_K_WTF_MODE)) {
1265 /* we can't get ecid in WTF mode */ 1148 /* we can't get ecid in WTF mode */
1266 win32_closepipes(_client); 1149 CloseHandle(_client->handle);
1150 free(details);
1267 continue; 1151 continue;
1268 } 1152 }
1269 1153
1270 char serial_str[256]; 1154 char serial_str[256];
1271 serial_str[0] = '\0'; 1155 serial_str[0] = '\0';
1272 1156
1273 char *p = result; 1157 char *p = (char*)details->DevicePath;
1274 while ((p = strstr(p, "\\usb"))) { 1158 while ((p = strstr(p, "\\usb"))) {
1275 if (sscanf(p, "\\usb#vid_%*04x&pid_%*04x#%s", serial_str) == 1) 1159 if (sscanf(p, "\\usb#vid_05ac&pid_%*04x#%s", serial_str) == 1)
1276 break; 1160 break;
1277 p += 4; 1161 p += 4;
1278 } 1162 }
1163 free(details);
1279 1164
1280 if (serial_str[0] == '\0') { 1165 if (serial_str[0] == '\0') {
1281 win32_closepipes(_client); 1166 CloseHandle(_client->handle);
1282 continue; 1167 continue;
1283 } 1168 }
1284 1169
@@ -1300,7 +1185,7 @@ static irecv_error_t win32_open_with_ecid(irecv_client_t* client, uint64_t ecid)
1300 1185
1301 if (ecid != 0) { 1186 if (ecid != 0) {
1302 if (_client->device_info.ecid != ecid) { 1187 if (_client->device_info.ecid != ecid) {
1303 win32_closepipes(_client); 1188 CloseHandle(_client->handle);
1304 continue; 1189 continue;
1305 } 1190 }
1306 debug("found device with ECID %016" PRIx64 "\n", (uint64_t)ecid); 1191 debug("found device with ECID %016" PRIx64 "\n", (uint64_t)ecid);
@@ -2317,7 +2202,7 @@ static void* _irecv_handle_device_add(void *userdata)
2317 2202
2318 char *p = result; 2203 char *p = result;
2319 while ((p = strstr(p, "\\usb"))) { 2204 while ((p = strstr(p, "\\usb"))) {
2320 if (sscanf(p, "\\usb#vid_%*04x&pid_%04x#%s", &pid, serial_str) == 2) 2205 if (sscanf(p, "\\usb#vid_05ac&pid_%04x#%s", &pid, serial_str) == 2)
2321 break; 2206 break;
2322 p += 4; 2207 p += 4;
2323 } 2208 }
@@ -2981,11 +2866,7 @@ irecv_error_t irecv_close(irecv_client_t client)
2981 } 2866 }
2982#endif 2867#endif
2983#else 2868#else
2984 free(client->iBootPath); 2869 CloseHandle(client->handle);
2985 client->iBootPath = NULL;
2986 free(client->DfuPath);
2987 client->DfuPath = NULL;
2988 win32_closepipes(client);
2989#endif 2870#endif
2990 free(client->device_info.srnm); 2871 free(client->device_info.srnm);
2991 free(client->device_info.imei); 2872 free(client->device_info.imei);