diff options
author | 2024-03-21 01:31:48 +0100 | |
---|---|---|
committer | 2024-03-21 01:31:48 +0100 | |
commit | d3198a50e51674e0ec19284f44f4aeb027d160a3 (patch) | |
tree | e6b33b0757ba9ed14e5fcafb67bb83e62990138f | |
parent | b55d215c25fd415b49430dc3c8423dde7d8f12aa (diff) | |
download | libirecovery-d3198a50e51674e0ec19284f44f4aeb027d160a3.tar.gz libirecovery-d3198a50e51674e0ec19284f44f4aeb027d160a3.tar.bz2 |
Add support for Port DFU
Note: This does not allow restoring devices in Port DFU mode, this is
handled in idevicerestore.
-rw-r--r-- | include/libirecovery.h | 3 | ||||
-rw-r--r-- | src/libirecovery.c | 36 | ||||
-rw-r--r-- | tools/irecovery.c | 3 |
3 files changed, 30 insertions, 12 deletions
diff --git a/include/libirecovery.h b/include/libirecovery.h index 7b89d1f..04892c4 100644 --- a/include/libirecovery.h +++ b/include/libirecovery.h | |||
@@ -43,7 +43,8 @@ enum irecv_mode { | |||
43 | IRECV_K_RECOVERY_MODE_3 = 0x1282, | 43 | IRECV_K_RECOVERY_MODE_3 = 0x1282, |
44 | IRECV_K_RECOVERY_MODE_4 = 0x1283, | 44 | IRECV_K_RECOVERY_MODE_4 = 0x1283, |
45 | IRECV_K_WTF_MODE = 0x1222, | 45 | IRECV_K_WTF_MODE = 0x1222, |
46 | IRECV_K_DFU_MODE = 0x1227 | 46 | IRECV_K_DFU_MODE = 0x1227, |
47 | IRECV_K_PORT_DFU_MODE = 0xf014 | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | typedef enum { | 50 | typedef enum { |
diff --git a/src/libirecovery.c b/src/libirecovery.c index 7d6c46c..b1b81e0 100644 --- a/src/libirecovery.c +++ b/src/libirecovery.c | |||
@@ -768,7 +768,9 @@ static void irecv_load_device_info_from_iboot_string(irecv_client_t client, cons | |||
768 | 768 | ||
769 | ptr = strstr(iboot_string, "BDID:"); | 769 | ptr = strstr(iboot_string, "BDID:"); |
770 | if (ptr != NULL) { | 770 | 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; | ||
772 | } | 774 | } |
773 | 775 | ||
774 | ptr = strstr(iboot_string, "ECID:"); | 776 | ptr = strstr(iboot_string, "ECID:"); |
@@ -1136,6 +1138,7 @@ static irecv_error_t irecv_kis_load_device_info(irecv_client_t client) | |||
1136 | static const GUID GUID_DEVINTERFACE_IBOOT = {0xED82A167L, 0xD61A, 0x4AF6, {0x9A, 0xB6, 0x11, 0xE5, 0x22, 0x36, 0xC5, 0x76}}; | 1138 | static const GUID GUID_DEVINTERFACE_IBOOT = {0xED82A167L, 0xD61A, 0x4AF6, {0x9A, 0xB6, 0x11, 0xE5, 0x22, 0x36, 0xC5, 0x76}}; |
1137 | static const GUID GUID_DEVINTERFACE_DFU = {0xB8085869L, 0xFEB9, 0x404B, {0x8C, 0xB1, 0x1E, 0x5C, 0x14, 0xFA, 0x8C, 0x54}}; | 1139 | static const GUID GUID_DEVINTERFACE_DFU = {0xB8085869L, 0xFEB9, 0x404B, {0x8C, 0xB1, 0x1E, 0x5C, 0x14, 0xFA, 0x8C, 0x54}}; |
1138 | static const GUID GUID_DEVINTERFACE_KIS = {0xB36F4137L, 0xF4EF, 0x4BFC, {0xA2, 0x5A, 0xC2, 0x41, 0x07, 0x68, 0xEE, 0x37}}; | 1140 | 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}}; | ||
1139 | 1142 | ||
1140 | typedef struct usb_control_request { | 1143 | typedef struct usb_control_request { |
1141 | uint8_t bmRequestType; | 1144 | uint8_t bmRequestType; |
@@ -1150,7 +1153,7 @@ typedef struct usb_control_request { | |||
1150 | static irecv_error_t win32_open_with_ecid(irecv_client_t* client, uint64_t ecid) | 1153 | static irecv_error_t win32_open_with_ecid(irecv_client_t* client, uint64_t ecid) |
1151 | { | 1154 | { |
1152 | int found = 0; | 1155 | 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 }; |
1154 | irecv_client_t _client = (irecv_client_t) malloc(sizeof(struct irecv_client_private)); | 1157 | irecv_client_t _client = (irecv_client_t) malloc(sizeof(struct irecv_client_private)); |
1155 | memset(_client, 0, sizeof(struct irecv_client_private)); | 1158 | memset(_client, 0, sizeof(struct irecv_client_private)); |
1156 | 1159 | ||
@@ -1187,6 +1190,7 @@ static irecv_error_t win32_open_with_ecid(irecv_client_t* client, uint64_t ecid) | |||
1187 | 1190 | ||
1188 | // make sure the current device is actually in the right mode for the given driver interface | 1191 | // make sure the current device is actually in the right mode for the given driver interface |
1189 | if ((guids[k] == &GUID_DEVINTERFACE_DFU && pid != IRECV_K_DFU_MODE && pid != IRECV_K_WTF_MODE) | 1192 | 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) | ||
1190 | || (guids[k] == &GUID_DEVINTERFACE_IBOOT && (pid < IRECV_K_RECOVERY_MODE_1 || pid > IRECV_K_RECOVERY_MODE_4)) | 1194 | || (guids[k] == &GUID_DEVINTERFACE_IBOOT && (pid < IRECV_K_RECOVERY_MODE_1 || pid > IRECV_K_RECOVERY_MODE_4)) |
1191 | || (guids[k] == &GUID_DEVINTERFACE_KIS && pid != 1) | 1195 | || (guids[k] == &GUID_DEVINTERFACE_KIS && pid != 1) |
1192 | ) { | 1196 | ) { |
@@ -1599,7 +1603,7 @@ static irecv_error_t iokit_open_with_ecid(irecv_client_t* pclient, uint64_t ecid | |||
1599 | CFRange range; | 1603 | CFRange range; |
1600 | 1604 | ||
1601 | UInt16 wtf_pids[] = { IRECV_K_WTF_MODE, 0}; | 1605 | 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 }; |
1603 | UInt16 *pids = all_pids; | 1607 | UInt16 *pids = all_pids; |
1604 | int i; | 1608 | int i; |
1605 | 1609 | ||
@@ -1737,6 +1741,7 @@ static irecv_error_t libusb_open_with_ecid(irecv_client_t* pclient, uint64_t eci | |||
1737 | usb_descriptor.idProduct == IRECV_K_RECOVERY_MODE_4 || | 1741 | usb_descriptor.idProduct == IRECV_K_RECOVERY_MODE_4 || |
1738 | usb_descriptor.idProduct == IRECV_K_WTF_MODE || | 1742 | usb_descriptor.idProduct == IRECV_K_WTF_MODE || |
1739 | usb_descriptor.idProduct == IRECV_K_DFU_MODE || | 1743 | usb_descriptor.idProduct == IRECV_K_DFU_MODE || |
1744 | usb_descriptor.idProduct == IRECV_K_PORT_DFU_MODE || | ||
1740 | usb_descriptor.idProduct == KIS_PRODUCT_ID) { | 1745 | usb_descriptor.idProduct == KIS_PRODUCT_ID) { |
1741 | 1746 | ||
1742 | if (ecid == IRECV_K_WTF_MODE) { | 1747 | if (ecid == IRECV_K_WTF_MODE) { |
@@ -1814,7 +1819,7 @@ irecv_error_t irecv_open_with_ecid(irecv_client_t* pclient, uint64_t ecid) | |||
1814 | return error; | 1819 | return error; |
1815 | } | 1820 | } |
1816 | 1821 | ||
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) { |
1818 | error = irecv_usb_set_interface(client, 0, 0); | 1823 | error = irecv_usb_set_interface(client, 0, 0); |
1819 | } else { | 1824 | } else { |
1820 | error = irecv_usb_set_interface(client, 0, 0); | 1825 | error = irecv_usb_set_interface(client, 0, 0); |
@@ -2238,6 +2243,7 @@ static int _irecv_is_recovery_device(void *device) | |||
2238 | case IRECV_K_RECOVERY_MODE_2: | 2243 | case IRECV_K_RECOVERY_MODE_2: |
2239 | case IRECV_K_RECOVERY_MODE_3: | 2244 | case IRECV_K_RECOVERY_MODE_3: |
2240 | case IRECV_K_RECOVERY_MODE_4: | 2245 | case IRECV_K_RECOVERY_MODE_4: |
2246 | case IRECV_K_PORT_DFU_MODE: | ||
2241 | case KIS_PRODUCT_ID: | 2247 | case KIS_PRODUCT_ID: |
2242 | break; | 2248 | break; |
2243 | default: | 2249 | default: |
@@ -2596,7 +2602,7 @@ static void *_irecv_event_handler(void* data) | |||
2596 | struct _irecv_event_handler_info* info = (struct _irecv_event_handler_info*)data; | 2602 | struct _irecv_event_handler_info* info = (struct _irecv_event_handler_info*)data; |
2597 | #ifdef WIN32 | 2603 | #ifdef WIN32 |
2598 | struct collection newDevices; | 2604 | 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 }; |
2600 | int running = 1; | 2606 | int running = 1; |
2601 | 2607 | ||
2602 | collection_init(&newDevices); | 2608 | collection_init(&newDevices); |
@@ -2693,6 +2699,7 @@ static void *_irecv_event_handler(void* data) | |||
2693 | // make sure the current device is actually in the right mode for the given driver interface | 2699 | // make sure the current device is actually in the right mode for the given driver interface |
2694 | int skip = 0; | 2700 | int skip = 0; |
2695 | if ((guids[k] == &GUID_DEVINTERFACE_DFU && pid != IRECV_K_DFU_MODE && pid != IRECV_K_WTF_MODE) | 2701 | 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) | ||
2696 | || (guids[k] == &GUID_DEVINTERFACE_IBOOT && (pid < IRECV_K_RECOVERY_MODE_1 || pid > IRECV_K_RECOVERY_MODE_4)) | 2703 | || (guids[k] == &GUID_DEVINTERFACE_IBOOT && (pid < IRECV_K_RECOVERY_MODE_1 || pid > IRECV_K_RECOVERY_MODE_4)) |
2697 | || (guids[k] == &GUID_DEVINTERFACE_KIS && pid != 1) | 2704 | || (guids[k] == &GUID_DEVINTERFACE_KIS && pid != 1) |
2698 | ) { | 2705 | ) { |
@@ -2746,7 +2753,7 @@ static void *_irecv_event_handler(void* data) | |||
2746 | iokit_runloop = CFRunLoopGetCurrent(); | 2753 | iokit_runloop = CFRunLoopGetCurrent(); |
2747 | CFRunLoopAddSource(iokit_runloop, runLoopSource, kCFRunLoopDefaultMode); | 2754 | CFRunLoopAddSource(iokit_runloop, runLoopSource, kCFRunLoopDefaultMode); |
2748 | 2755 | ||
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 }; |
2750 | int i = 0; | 2757 | int i = 0; |
2751 | while (pids[i] > 0) { | 2758 | while (pids[i] > 0) { |
2752 | CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName); | 2759 | CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName); |
@@ -3005,7 +3012,7 @@ irecv_error_t irecv_close(irecv_client_t client) | |||
3005 | } | 3012 | } |
3006 | #else | 3013 | #else |
3007 | if (client->handle != NULL) { | 3014 | 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)) { |
3009 | libusb_release_interface(client->handle, client->usb_interface); | 3016 | libusb_release_interface(client->handle, client->usb_interface); |
3010 | } | 3017 | } |
3011 | libusb_close(client->handle); | 3018 | libusb_close(client->handle); |
@@ -3275,7 +3282,7 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un | |||
3275 | return irecv_kis_send_buffer(client, buffer, length, dfu_notify_finished); | 3282 | return irecv_kis_send_buffer(client, buffer, length, dfu_notify_finished); |
3276 | 3283 | ||
3277 | irecv_error_t error = 0; | 3284 | 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)); |
3279 | 3286 | ||
3280 | if (check_context(client) != IRECV_E_SUCCESS) | 3287 | if (check_context(client) != IRECV_E_SUCCESS) |
3281 | return IRECV_E_NO_DEVICE; | 3288 | return IRECV_E_NO_DEVICE; |
@@ -3806,7 +3813,7 @@ irecv_error_t irecv_reset_counters(irecv_client_t client) | |||
3806 | if (check_context(client) != IRECV_E_SUCCESS) | 3813 | if (check_context(client) != IRECV_E_SUCCESS) |
3807 | return IRECV_E_NO_DEVICE; | 3814 | return IRECV_E_NO_DEVICE; |
3808 | 3815 | ||
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)) { |
3810 | irecv_usb_control_transfer(client, 0x21, 4, 0, 0, 0, 0, USB_TIMEOUT); | 3817 | irecv_usb_control_transfer(client, 0x21, 4, 0, 0, 0, 0, USB_TIMEOUT); |
3811 | } | 3818 | } |
3812 | 3819 | ||
@@ -3819,7 +3826,7 @@ irecv_error_t irecv_recv_buffer(irecv_client_t client, char* buffer, unsigned lo | |||
3819 | #ifdef USE_DUMMY | 3826 | #ifdef USE_DUMMY |
3820 | return IRECV_E_UNSUPPORTED; | 3827 | return IRECV_E_UNSUPPORTED; |
3821 | #else | 3828 | #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)); |
3823 | 3830 | ||
3824 | if (check_context(client) != IRECV_E_SUCCESS) | 3831 | if (check_context(client) != IRECV_E_SUCCESS) |
3825 | return IRECV_E_NO_DEVICE; | 3832 | return IRECV_E_NO_DEVICE; |
@@ -3905,8 +3912,15 @@ irecv_error_t irecv_devices_get_device_by_client(irecv_client_t client, irecv_de | |||
3905 | return IRECV_E_UNKNOWN_ERROR; | 3912 | return IRECV_E_UNKNOWN_ERROR; |
3906 | } | 3913 | } |
3907 | 3914 | ||
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 | |||
3908 | for (i = 0; irecv_devices[i].hardware_model != NULL; i++) { | 3922 | 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) { |
3910 | *device = &irecv_devices[i]; | 3924 | *device = &irecv_devices[i]; |
3911 | return IRECV_E_SUCCESS; | 3925 | return IRECV_E_SUCCESS; |
3912 | } | 3926 | } |
diff --git a/tools/irecovery.c b/tools/irecovery.c index 6303b55..955d3ca 100644 --- a/tools/irecovery.c +++ b/tools/irecovery.c | |||
@@ -90,6 +90,9 @@ static const char* mode_to_str(int mode) | |||
90 | case IRECV_K_DFU_MODE: | 90 | case IRECV_K_DFU_MODE: |
91 | return "DFU"; | 91 | return "DFU"; |
92 | break; | 92 | break; |
93 | case IRECV_K_PORT_DFU_MODE: | ||
94 | return "Port DFU"; | ||
95 | break; | ||
93 | case IRECV_K_WTF_MODE: | 96 | case IRECV_K_WTF_MODE: |
94 | return "WTF"; | 97 | return "WTF"; |
95 | break; | 98 | break; |