static int darwin_claim_interface(struct libusb_device_handle *dev_handle, uint8_t iface);
static int darwin_release_interface(struct libusb_device_handle *dev_handle, uint8_t iface);
static int darwin_reenumerate_device(struct libusb_device_handle *dev_handle, bool capture);
+static int darwin_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint);
static int darwin_reset_device(struct libusb_device_handle *dev_handle);
static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0);
list_for_each_entry_safe(dev, next, &darwin_cached_devices, list, struct darwin_cached_device) {
darwin_deref_cached_device(dev);
}
-
- darwin_cached_devices.prev = darwin_cached_devices.next = NULL;
}
static int darwin_init(struct libusb_context *ctx) {
do {
if (first_init) {
- assert (NULL == darwin_cached_devices.next);
- list_init (&darwin_cached_devices);
-
+ if (NULL == darwin_cached_devices.next) {
+ list_init (&darwin_cached_devices);
+ }
+ assert(list_empty(&darwin_cached_devices));
#if !defined(HAVE_CLOCK_GETTIME)
/* create the clocks that will be used if clock_gettime() is not available */
host_name_port_t host_self;
usbi_localize_device_descriptor(&dev->device_descriptor);
dev->session_data = cached_device->session;
+ if (NULL != dev->parent_dev) {
+ libusb_unref_device(dev->parent_dev);
+ dev->parent_dev = NULL;
+ }
+
if (cached_device->parent_session > 0) {
dev->parent_dev = usbi_get_device_by_session_id (ctx, (unsigned long) cached_device->parent_session);
- } else {
- dev->parent_dev = NULL;
}
(*(priv->dev->device))->GetDeviceSpeed (priv->dev->device, &devSpeed);
case kUSBDeviceSpeedLow: dev->speed = LIBUSB_SPEED_LOW; break;
case kUSBDeviceSpeedFull: dev->speed = LIBUSB_SPEED_FULL; break;
case kUSBDeviceSpeedHigh: dev->speed = LIBUSB_SPEED_HIGH; break;
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
case kUSBDeviceSpeedSuper: dev->speed = LIBUSB_SPEED_SUPER; break;
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
IOReturn kresult;
enum libusb_error ret;
+ int i;
+ uint8_t old_alt_setting;
/* current interface */
struct darwin_interface *cInterface = &priv->interfaces[iface];
return LIBUSB_ERROR_NO_DEVICE;
kresult = (*(cInterface->interface))->SetAlternateInterface (cInterface->interface, altsetting);
+ if (kresult != kIOReturnSuccess)
+ usbi_warn (HANDLE_CTX (dev_handle), "SetAlternateInterface: %s", darwin_error_str(kresult));
+
+ if (kresult != kIOUSBPipeStalled)
+ return darwin_to_libusb (kresult);
+
/* If a device only supports a default setting for the specified interface, then a STALL
(kIOUSBPipeStalled) may be returned. Ref: USB 2.0 specs 9.4.10.
- Mimick the behaviour in e.g. the Linux kernel: in such case, reset all endpoints,
- and hide errors.Current implementation resets the entire device, instead of single
- interface, due to historic reasons. */
- if (kresult != kIOReturnSuccess) {
- usbi_warn (HANDLE_CTX (dev_handle), "SetAlternateInterface: %s", darwin_error_str(kresult));
- darwin_reset_device (dev_handle);
- }
+ Mimick the behaviour in e.g. the Linux kernel: in such case, reset all endpoints
+ of the interface (as would have been done per 9.1.1.5) and return success. */
+
+ /* For some reason we need to reclaim the interface after the pipe error */
+ ret = darwin_claim_interface (dev_handle, iface);
- /* update list of endpoints */
- ret = get_endpoints (dev_handle, iface);
if (ret) {
- /* this should not happen */
darwin_release_interface (dev_handle, iface);
- usbi_err (HANDLE_CTX (dev_handle), "could not build endpoint table");
+ usbi_err (HANDLE_CTX (dev_handle), "could not reclaim interface");
}
- return ret;
+ /* Return error if a change to another value was attempted */
+ kresult = (*(cInterface->interface))->GetAlternateSetting (cInterface->interface, &old_alt_setting);
+ if (kresult == kIOReturnSuccess && altsetting != old_alt_setting)
+ return LIBUSB_ERROR_PIPE;
+
+ for (i = 0 ; i < cInterface->num_endpoints ; i++)
+ darwin_clear_halt(dev_handle, cInterface->endpoint_addrs[i]);
+
+ return LIBUSB_SUCCESS;
}
static int darwin_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) {