Skip to content

Commit d3198a5

Browse files
committed
Add support for Port DFU
Note: This does not allow restoring devices in Port DFU mode, this is handled in idevicerestore.
1 parent b55d215 commit d3198a5

3 files changed

Lines changed: 30 additions & 12 deletions

File tree

include/libirecovery.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ enum irecv_mode {
4343
IRECV_K_RECOVERY_MODE_3 = 0x1282,
4444
IRECV_K_RECOVERY_MODE_4 = 0x1283,
4545
IRECV_K_WTF_MODE = 0x1222,
46-
IRECV_K_DFU_MODE = 0x1227
46+
IRECV_K_DFU_MODE = 0x1227,
47+
IRECV_K_PORT_DFU_MODE = 0xf014
4748
};
4849

4950
typedef enum {

src/libirecovery.c

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,9 @@ static void irecv_load_device_info_from_iboot_string(irecv_client_t client, cons
768768

769769
ptr = strstr(iboot_string, "BDID:");
770770
if (ptr != NULL) {
771-
sscanf(ptr, "BDID:%x", &client->device_info.bdid);
771+
uint64_t bdid = 0;
772+
sscanf(ptr, "BDID:%" SCNx64, &bdid);
773+
client->device_info.bdid = (unsigned int)bdid;
772774
}
773775

774776
ptr = strstr(iboot_string, "ECID:");
@@ -1136,6 +1138,7 @@ static irecv_error_t irecv_kis_load_device_info(irecv_client_t client)
11361138
static const GUID GUID_DEVINTERFACE_IBOOT = {0xED82A167L, 0xD61A, 0x4AF6, {0x9A, 0xB6, 0x11, 0xE5, 0x22, 0x36, 0xC5, 0x76}};
11371139
static const GUID GUID_DEVINTERFACE_DFU = {0xB8085869L, 0xFEB9, 0x404B, {0x8C, 0xB1, 0x1E, 0x5C, 0x14, 0xFA, 0x8C, 0x54}};
11381140
static const GUID GUID_DEVINTERFACE_KIS = {0xB36F4137L, 0xF4EF, 0x4BFC, {0xA2, 0x5A, 0xC2, 0x41, 0x07, 0x68, 0xEE, 0x37}};
1141+
static const GUID GUID_DEVINTERFACE_PORTDFU = {0xAF633FF1L, 0x1170, 0x4CA6, {0xAE, 0x9E, 0x08, 0xD0, 0x01, 0x42, 0x1E, 0xAA}};
11391142

11401143
typedef struct usb_control_request {
11411144
uint8_t bmRequestType;
@@ -1150,7 +1153,7 @@ typedef struct usb_control_request {
11501153
static irecv_error_t win32_open_with_ecid(irecv_client_t* client, uint64_t ecid)
11511154
{
11521155
int found = 0;
1153-
const GUID *guids[] = { &GUID_DEVINTERFACE_KIS, &GUID_DEVINTERFACE_DFU, &GUID_DEVINTERFACE_IBOOT, NULL };
1156+
const GUID *guids[] = { &GUID_DEVINTERFACE_KIS, &GUID_DEVINTERFACE_PORTDFU, &GUID_DEVINTERFACE_DFU, &GUID_DEVINTERFACE_IBOOT, NULL };
11541157
irecv_client_t _client = (irecv_client_t) malloc(sizeof(struct irecv_client_private));
11551158
memset(_client, 0, sizeof(struct irecv_client_private));
11561159

@@ -1187,6 +1190,7 @@ static irecv_error_t win32_open_with_ecid(irecv_client_t* client, uint64_t ecid)
11871190

11881191
// make sure the current device is actually in the right mode for the given driver interface
11891192
if ((guids[k] == &GUID_DEVINTERFACE_DFU && pid != IRECV_K_DFU_MODE && pid != IRECV_K_WTF_MODE)
1193+
|| (guids[k] == &GUID_DEVINTERFACE_PORTDFU && pid != IRECV_K_PORT_DFU_MODE)
11901194
|| (guids[k] == &GUID_DEVINTERFACE_IBOOT && (pid < IRECV_K_RECOVERY_MODE_1 || pid > IRECV_K_RECOVERY_MODE_4))
11911195
|| (guids[k] == &GUID_DEVINTERFACE_KIS && pid != 1)
11921196
) {
@@ -1599,7 +1603,7 @@ static irecv_error_t iokit_open_with_ecid(irecv_client_t* pclient, uint64_t ecid
15991603
CFRange range;
16001604

16011605
UInt16 wtf_pids[] = { IRECV_K_WTF_MODE, 0};
1602-
UInt16 all_pids[] = { IRECV_K_WTF_MODE, IRECV_K_DFU_MODE, IRECV_K_RECOVERY_MODE_1, IRECV_K_RECOVERY_MODE_2, IRECV_K_RECOVERY_MODE_3, IRECV_K_RECOVERY_MODE_4, KIS_PRODUCT_ID, 0 };
1606+
UInt16 all_pids[] = { IRECV_K_WTF_MODE, IRECV_K_DFU_MODE, IRECV_K_PORT_DFU_MODE, IRECV_K_RECOVERY_MODE_1, IRECV_K_RECOVERY_MODE_2, IRECV_K_RECOVERY_MODE_3, IRECV_K_RECOVERY_MODE_4, KIS_PRODUCT_ID, 0 };
16031607
UInt16 *pids = all_pids;
16041608
int i;
16051609

@@ -1737,6 +1741,7 @@ static irecv_error_t libusb_open_with_ecid(irecv_client_t* pclient, uint64_t eci
17371741
usb_descriptor.idProduct == IRECV_K_RECOVERY_MODE_4 ||
17381742
usb_descriptor.idProduct == IRECV_K_WTF_MODE ||
17391743
usb_descriptor.idProduct == IRECV_K_DFU_MODE ||
1744+
usb_descriptor.idProduct == IRECV_K_PORT_DFU_MODE ||
17401745
usb_descriptor.idProduct == KIS_PRODUCT_ID) {
17411746

17421747
if (ecid == IRECV_K_WTF_MODE) {
@@ -1814,7 +1819,7 @@ irecv_error_t irecv_open_with_ecid(irecv_client_t* pclient, uint64_t ecid)
18141819
return error;
18151820
}
18161821

1817-
if (client->mode == IRECV_K_DFU_MODE || client->mode == IRECV_K_WTF_MODE || client->mode == KIS_PRODUCT_ID) {
1822+
if (client->mode == IRECV_K_DFU_MODE || client->mode == IRECV_K_PORT_DFU_MODE || client->mode == IRECV_K_WTF_MODE || client->mode == KIS_PRODUCT_ID) {
18181823
error = irecv_usb_set_interface(client, 0, 0);
18191824
} else {
18201825
error = irecv_usb_set_interface(client, 0, 0);
@@ -2238,6 +2243,7 @@ static int _irecv_is_recovery_device(void *device)
22382243
case IRECV_K_RECOVERY_MODE_2:
22392244
case IRECV_K_RECOVERY_MODE_3:
22402245
case IRECV_K_RECOVERY_MODE_4:
2246+
case IRECV_K_PORT_DFU_MODE:
22412247
case KIS_PRODUCT_ID:
22422248
break;
22432249
default:
@@ -2596,7 +2602,7 @@ static void *_irecv_event_handler(void* data)
25962602
struct _irecv_event_handler_info* info = (struct _irecv_event_handler_info*)data;
25972603
#ifdef WIN32
25982604
struct collection newDevices;
2599-
const GUID *guids[] = { &GUID_DEVINTERFACE_KIS, &GUID_DEVINTERFACE_DFU, &GUID_DEVINTERFACE_IBOOT, NULL };
2605+
const GUID *guids[] = { &GUID_DEVINTERFACE_KIS, &GUID_DEVINTERFACE_PORTDFU, &GUID_DEVINTERFACE_DFU, &GUID_DEVINTERFACE_IBOOT, NULL };
26002606
int running = 1;
26012607

26022608
collection_init(&newDevices);
@@ -2693,6 +2699,7 @@ static void *_irecv_event_handler(void* data)
26932699
// make sure the current device is actually in the right mode for the given driver interface
26942700
int skip = 0;
26952701
if ((guids[k] == &GUID_DEVINTERFACE_DFU && pid != IRECV_K_DFU_MODE && pid != IRECV_K_WTF_MODE)
2702+
|| (guids[k] == &GUID_DEVINTERFACE_PORTDFU && pid != IRECV_K_PORT_DFU_MODE)
26962703
|| (guids[k] == &GUID_DEVINTERFACE_IBOOT && (pid < IRECV_K_RECOVERY_MODE_1 || pid > IRECV_K_RECOVERY_MODE_4))
26972704
|| (guids[k] == &GUID_DEVINTERFACE_KIS && pid != 1)
26982705
) {
@@ -2746,7 +2753,7 @@ static void *_irecv_event_handler(void* data)
27462753
iokit_runloop = CFRunLoopGetCurrent();
27472754
CFRunLoopAddSource(iokit_runloop, runLoopSource, kCFRunLoopDefaultMode);
27482755

2749-
uint16_t pids[8] = { IRECV_K_WTF_MODE, IRECV_K_DFU_MODE, IRECV_K_RECOVERY_MODE_1, IRECV_K_RECOVERY_MODE_2, IRECV_K_RECOVERY_MODE_3, IRECV_K_RECOVERY_MODE_4, KIS_PRODUCT_ID, 0 };
2756+
uint16_t pids[9] = { IRECV_K_WTF_MODE, IRECV_K_DFU_MODE, IRECV_K_RECOVERY_MODE_1, IRECV_K_RECOVERY_MODE_2, IRECV_K_RECOVERY_MODE_3, IRECV_K_RECOVERY_MODE_4, IRECV_K_PORT_DFU_MODE, KIS_PRODUCT_ID, 0 };
27502757
int i = 0;
27512758
while (pids[i] > 0) {
27522759
CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
@@ -3005,7 +3012,7 @@ irecv_error_t irecv_close(irecv_client_t client)
30053012
}
30063013
#else
30073014
if (client->handle != NULL) {
3008-
if ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE) && (client->isKIS == 0)) {
3015+
if ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_PORT_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE) && (client->isKIS == 0)) {
30093016
libusb_release_interface(client->handle, client->usb_interface);
30103017
}
30113018
libusb_close(client->handle);
@@ -3275,7 +3282,7 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un
32753282
return irecv_kis_send_buffer(client, buffer, length, dfu_notify_finished);
32763283

32773284
irecv_error_t error = 0;
3278-
int recovery_mode = ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE));
3285+
int recovery_mode = ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_PORT_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE));
32793286

32803287
if (check_context(client) != IRECV_E_SUCCESS)
32813288
return IRECV_E_NO_DEVICE;
@@ -3806,7 +3813,7 @@ irecv_error_t irecv_reset_counters(irecv_client_t client)
38063813
if (check_context(client) != IRECV_E_SUCCESS)
38073814
return IRECV_E_NO_DEVICE;
38083815

3809-
if ((client->mode == IRECV_K_DFU_MODE) || (client->mode == IRECV_K_WTF_MODE)) {
3816+
if ((client->mode == IRECV_K_DFU_MODE) || (client->mode == IRECV_K_PORT_DFU_MODE) || (client->mode == IRECV_K_WTF_MODE)) {
38103817
irecv_usb_control_transfer(client, 0x21, 4, 0, 0, 0, 0, USB_TIMEOUT);
38113818
}
38123819

@@ -3819,7 +3826,7 @@ irecv_error_t irecv_recv_buffer(irecv_client_t client, char* buffer, unsigned lo
38193826
#ifdef USE_DUMMY
38203827
return IRECV_E_UNSUPPORTED;
38213828
#else
3822-
int recovery_mode = ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE));
3829+
int recovery_mode = ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_PORT_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE));
38233830

38243831
if (check_context(client) != IRECV_E_SUCCESS)
38253832
return IRECV_E_NO_DEVICE;
@@ -3905,8 +3912,15 @@ irecv_error_t irecv_devices_get_device_by_client(irecv_client_t client, irecv_de
39053912
return IRECV_E_UNKNOWN_ERROR;
39063913
}
39073914

3915+
unsigned int cpid_match = client->device_info.cpid;
3916+
unsigned int bdid_match = client->device_info.bdid;
3917+
if (client->mode == IRECV_K_PORT_DFU_MODE) {
3918+
cpid_match = (client->device_info.bdid >> 8) & 0xFFFF;
3919+
bdid_match = (client->device_info.bdid >> 24) & 0xFF;
3920+
}
3921+
39083922
for (i = 0; irecv_devices[i].hardware_model != NULL; i++) {
3909-
if (irecv_devices[i].chip_id == client->device_info.cpid && irecv_devices[i].board_id == client->device_info.bdid) {
3923+
if (irecv_devices[i].chip_id == cpid_match && irecv_devices[i].board_id == bdid_match) {
39103924
*device = &irecv_devices[i];
39113925
return IRECV_E_SUCCESS;
39123926
}

tools/irecovery.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ static const char* mode_to_str(int mode)
9090
case IRECV_K_DFU_MODE:
9191
return "DFU";
9292
break;
93+
case IRECV_K_PORT_DFU_MODE:
94+
return "Port DFU";
95+
break;
9396
case IRECV_K_WTF_MODE:
9497
return "WTF";
9598
break;

0 commit comments

Comments
 (0)