summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar synackuk2025-11-27 20:53:30 +0000
committerGravatar synackuk2025-11-27 21:16:37 +0000
commite7aadfe47394eaf81f6e76e49be8b300b5f23763 (patch)
tree383f19a9652244a86cf9cf52717ed284b078481e /src
parentb59ef4814525f487287da1609864f432cd79e3ed (diff)
downloadlibirecovery-e7aadfe47394eaf81f6e76e49be8b300b5f23763.tar.gz
libirecovery-e7aadfe47394eaf81f6e76e49be8b300b5f23763.tar.bz2
Added detection of stalled pipes for IOKIT and added functions for async requests
Diffstat (limited to 'src')
-rw-r--r--src/libirecovery.c179
1 files changed, 179 insertions, 0 deletions
diff --git a/src/libirecovery.c b/src/libirecovery.c
index bf9a0d6..390f5cc 100644
--- a/src/libirecovery.c
+++ b/src/libirecovery.c
@@ -98,6 +98,18 @@
98 static void f(void) 98 static void f(void)
99#endif 99#endif
100 100
101#ifndef WIN32
102struct irecv_async_transfer {
103 uint32_t len;
104 #ifdef HAVE_IOKIT
105 kern_return_t ret;
106 #else
107 enum libusb_transfer_status ret;
108 #endif
109};
110
111#endif
112
101struct irecv_client_private { 113struct irecv_client_private {
102 int debug; 114 int debug;
103 int usb_config; 115 int usb_config;
@@ -113,6 +125,7 @@ struct irecv_client_private {
113#else 125#else
114 IOUSBDeviceInterface320 **handle; 126 IOUSBDeviceInterface320 **handle;
115 IOUSBInterfaceInterface300 **usbInterface; 127 IOUSBInterfaceInterface300 **usbInterface;
128 CFRunLoopSourceRef async_event_source;
116#endif 129#endif
117#else 130#else
118 HANDLE handle; 131 HANDLE handle;
@@ -1402,6 +1415,7 @@ static int iokit_usb_control_transfer(irecv_client_t client, uint8_t bm_request_
1402 result = (*client->handle)->DeviceRequestTO(client->handle, &req); 1415 result = (*client->handle)->DeviceRequestTO(client->handle, &req);
1403 switch (result) { 1416 switch (result) {
1404 case kIOReturnSuccess: return req.wLenDone; 1417 case kIOReturnSuccess: return req.wLenDone;
1418 case kIOUSBPipeStalled: return IRECV_E_PIPE;
1405 case kIOReturnTimeout: return IRECV_E_TIMEOUT; 1419 case kIOReturnTimeout: return IRECV_E_TIMEOUT;
1406 case kIOUSBTransactionTimeout: return IRECV_E_TIMEOUT; 1420 case kIOUSBTransactionTimeout: return IRECV_E_TIMEOUT;
1407 case kIOReturnNotResponding: return IRECV_E_NO_DEVICE; 1421 case kIOReturnNotResponding: return IRECV_E_NO_DEVICE;
@@ -1472,6 +1486,158 @@ int irecv_usb_control_transfer(irecv_client_t client, uint8_t bm_request_type, u
1472#endif 1486#endif
1473} 1487}
1474 1488
1489#ifndef WIN32
1490#ifdef HAVE_IOKIT
1491
1492static void iokit_async_cb(void *refcon, kern_return_t ret, void *arg_0)
1493{
1494 struct irecv_async_transfer* transfer = refcon;
1495
1496 if(transfer != NULL) {
1497 transfer->ret = ret;
1498 memcpy(&transfer->len, &arg_0, sizeof(transfer->len));
1499 CFRunLoopStop(CFRunLoopGetCurrent());
1500 }
1501}
1502
1503static int iokit_async_usb_control_transfer(irecv_client_t client, uint8_t bm_request_type, uint8_t b_request, uint16_t w_value, uint16_t w_index, unsigned char *data, uint16_t w_length, struct irecv_async_transfer* transfer)
1504{
1505 IOReturn result;
1506 IOUSBDevRequest req;
1507
1508 bzero(&req, sizeof(req));
1509 req.bmRequestType = bm_request_type;
1510 req.bRequest = b_request;
1511 req.wValue = OSSwapLittleToHostInt16(w_value);
1512 req.wIndex = OSSwapLittleToHostInt16(w_index);
1513 req.wLength = OSSwapLittleToHostInt16(w_length);
1514 req.pData = data;
1515 result = (*client->handle)->DeviceRequestAsync(client->handle, &req, iokit_async_cb, transfer);
1516 switch (result) {
1517 case kIOReturnSuccess: return IRECV_E_SUCCESS;
1518 case kIOUSBPipeStalled: return IRECV_E_PIPE;
1519 case kIOReturnTimeout: return IRECV_E_TIMEOUT;
1520 case kIOUSBTransactionTimeout: return IRECV_E_TIMEOUT;
1521 case kIOReturnNotResponding: return IRECV_E_NO_DEVICE;
1522 case kIOReturnNoDevice: return IRECV_E_NO_DEVICE;
1523 default:
1524 return IRECV_E_UNKNOWN_ERROR;
1525 }
1526}
1527
1528#else
1529
1530static void async_cb(struct libusb_transfer* usb_transfer) {
1531 struct irecv_async_transfer* transfer = usb_transfer->user_data;
1532 transfer->ret = usb_transfer->status;
1533 transfer->len += usb_transfer->actual_length;
1534}
1535
1536#endif
1537#endif
1538
1539IRECV_API int irecv_async_usb_control_transfer(irecv_client_t client, uint8_t bm_request_type, uint8_t b_request, uint16_t w_value, uint16_t w_index, unsigned char *data, uint16_t w_length) {
1540#ifdef USE_DUMMY
1541 return IRECV_E_UNSUPPORTED;
1542#else
1543#ifndef _WIN32
1544#ifdef HAVE_IOKIT
1545 return iokit_async_usb_control_transfer(client, bm_request_type, b_request, w_value, w_index, data, w_length, NULL);
1546#else
1547 irecv_error_t error;
1548
1549 unsigned char* buffer = malloc(w_length + 8);
1550 if(!buffer) {
1551 return IRECV_E_OUT_OF_MEMORY;
1552 }
1553 struct libusb_transfer* usb_transfer = libusb_alloc_transfer(0);
1554 if(!usb_transfer) {
1555 free(buffer);
1556 return IRECV_E_OUT_OF_MEMORY;
1557 }
1558 memcpy((buffer + 8), data, w_length);
1559 libusb_fill_control_setup(buffer, bm_request_type, b_request, w_value, w_index, w_length);
1560 libusb_fill_control_transfer(usb_transfer, client->handle, buffer, NULL, NULL, 0);
1561 usb_transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER;
1562 error = libusb_submit_transfer(usb_transfer);
1563 if(error != 0) {
1564 free(buffer);
1565 return error;
1566 }
1567 free(buffer);
1568 return IRECV_E_SUCCESS;
1569#endif
1570#else
1571 return IRECV_E_UNSUPPORTED;
1572#endif
1573#endif
1574
1575}
1576
1577IRECV_API int irecv_async_usb_control_transfer_with_cancel(irecv_client_t client, uint8_t bm_request_type, uint8_t b_request, uint16_t w_value, uint16_t w_index, unsigned char *data, uint16_t w_length, unsigned int u_time) {
1578#ifdef USE_DUMMY
1579 return IRECV_E_UNSUPPORTED;
1580#else
1581#ifndef _WIN32
1582 irecv_error_t error;
1583 struct irecv_async_transfer transfer;
1584 bzero(&transfer, sizeof(struct irecv_async_transfer));
1585
1586#ifdef HAVE_IOKIT
1587
1588 error = iokit_async_usb_control_transfer(client, bm_request_type, b_request, w_value, w_index, data, w_length, &transfer);
1589 if(error != IRECV_E_SUCCESS) {
1590 return error;
1591 }
1592 usleep(u_time);
1593 error = (*client->handle)->USBDeviceAbortPipeZero(client->handle);
1594 if(error != kIOReturnSuccess) {
1595 return IRECV_E_UNKNOWN_ERROR;
1596 }
1597 while(transfer.ret != kIOReturnAborted){
1598 CFRunLoopRun();
1599 }
1600 return transfer.len;
1601#else
1602 unsigned char* buffer = malloc(w_length + 8);
1603 if(!buffer) {
1604 return IRECV_E_OUT_OF_MEMORY;
1605 }
1606 struct libusb_transfer* usb_transfer = libusb_alloc_transfer(0);
1607 if(!usb_transfer) {
1608 free(buffer);
1609 return IRECV_E_OUT_OF_MEMORY;
1610 }
1611 memcpy((buffer + 8), data, w_length);
1612 libusb_fill_control_setup(buffer, bm_request_type, b_request, w_value, w_index, w_length);
1613 libusb_fill_control_transfer(usb_transfer, client->handle, buffer, async_cb, &transfer, 0);
1614 usb_transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER;
1615 error = libusb_submit_transfer(usb_transfer);
1616 if(error != 0) {
1617 free(buffer);
1618 return error;
1619 }
1620
1621 usleep(u_time);
1622
1623 error = libusb_cancel_transfer(usb_transfer);
1624 if(error != 0) {
1625 free(buffer);
1626 return error;
1627 }
1628 free(buffer);
1629
1630 while(transfer.ret != LIBUSB_TRANSFER_CANCELLED){
1631 libusb_handle_events_completed(libirecovery_context, NULL);
1632 }
1633 return transfer.len;
1634#endif
1635#else
1636 return IRECV_E_UNSUPPORTED;
1637#endif
1638#endif
1639}
1640
1475#ifndef USE_DUMMY 1641#ifndef USE_DUMMY
1476#ifdef HAVE_IOKIT 1642#ifdef HAVE_IOKIT
1477static int iokit_usb_bulk_transfer(irecv_client_t client, 1643static int iokit_usb_bulk_transfer(irecv_client_t client,
@@ -1978,6 +2144,15 @@ irecv_error_t irecv_open_with_ecid(irecv_client_t* pclient, uint64_t ecid)
1978 return error; 2144 return error;
1979 } 2145 }
1980 2146
2147#ifdef HAVE_IOKIT
2148 error = (*client->handle)->CreateDeviceAsyncEventSource(client->handle, &client->async_event_source);
2149 if (error != IRECV_E_SUCCESS) {
2150 free(client);
2151 return error;
2152 }
2153 CFRunLoopAddSource(CFRunLoopGetCurrent(), client->async_event_source, kCFRunLoopDefaultMode);
2154#endif
2155
1981 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) { 2156 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) {
1982 error = irecv_usb_set_interface(client, 0, 0); 2157 error = irecv_usb_set_interface(client, 0, 0);
1983 } else { 2158 } else {
@@ -3196,6 +3371,10 @@ static irecv_error_t irecv_cleanup(irecv_client_t client)
3196 (*client->handle)->Release(client->handle); 3371 (*client->handle)->Release(client->handle);
3197 client->handle = NULL; 3372 client->handle = NULL;
3198 } 3373 }
3374 if(client->async_event_source) {
3375 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), client->async_event_source, kCFRunLoopDefaultMode);
3376 CFRelease(client->async_event_source);
3377 }
3199#else 3378#else
3200 if (client->handle != NULL) { 3379 if (client->handle != NULL) {
3201 if ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_PORT_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE) && (client->isKIS == 0)) { 3380 if ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_PORT_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE) && (client->isKIS == 0)) {