From 4c706d2fb6b2c43b10d72ac5dff51cac4d939f1a Mon Sep 17 00:00:00 2001 From: Nathan Hjelm Date: Sat, 21 Nov 2009 17:06:43 +0000 Subject: [PATCH] Darwin: allow devices to be opened multiple times Allows libusb applications to access multiple interfaces of the same device in the same application. Also fixes a set alt interface bug. --- libusb/os/darwin_usb.c | 128 +++++++++++++++++++++++++++++-------------------- libusb/os/darwin_usb.h | 1 + 2 files changed, 77 insertions(+), 52 deletions(-) diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c index 9c64b60..88c4962 100644 --- a/libusb/os/darwin_usb.c +++ b/libusb/os/darwin_usb.c @@ -231,19 +231,17 @@ static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) { pthread_mutex_lock(&ctx->open_devs_lock); list_for_each_entry(handle, &ctx->open_devs, list) { dpriv = (struct darwin_device_priv *)handle->dev->os_priv; - if (dpriv->location == location) - break; - } - if (handle && handle->os_priv) { - priv = (struct darwin_device_handle_priv *)handle->os_priv; + /* the device may have been opened several times. write to each handle's event descriptor */ + if (dpriv->location == location && handle->os_priv) { + priv = (struct darwin_device_handle_priv *)handle->os_priv; - message = MESSAGE_DEVICE_GONE; - write (priv->fds[1], &message, sizeof (message)); + message = MESSAGE_DEVICE_GONE; + write (priv->fds[1], &message, sizeof (message)); + } } pthread_mutex_unlock(&ctx->open_devs_lock); - } } @@ -568,43 +566,48 @@ static int darwin_open (struct libusb_device_handle *dev_handle) { usb_device_t **darwin_device; IOReturn kresult; - kresult = darwin_get_device (dpriv->location, &darwin_device); - if (kresult) { - _usbi_log (HANDLE_CTX (dev_handle), LOG_LEVEL_ERROR, "could not find device: %s", darwin_error_str (kresult)); - return darwin_to_libusb (kresult); - } + if (0 == dpriv->open_count) { + kresult = darwin_get_device (dpriv->location, &darwin_device); + if (kresult) { + _usbi_log (HANDLE_CTX (dev_handle), LOG_LEVEL_ERROR, "could not find device: %s", darwin_error_str (kresult)); + return darwin_to_libusb (kresult); + } - dpriv->device = darwin_device; + dpriv->device = darwin_device; - /* try to open the device */ - kresult = (*(dpriv->device))->USBDeviceOpenSeize (dpriv->device); + /* try to open the device */ + kresult = (*(dpriv->device))->USBDeviceOpenSeize (dpriv->device); - if (kresult != kIOReturnSuccess) { - _usbi_log (HANDLE_CTX (dev_handle), LOG_LEVEL_ERROR, "USBDeviceOpen: %s", darwin_error_str(kresult)); + if (kresult != kIOReturnSuccess) { + _usbi_log (HANDLE_CTX (dev_handle), LOG_LEVEL_ERROR, "USBDeviceOpen: %s", darwin_error_str(kresult)); - switch (kresult) { - case kIOReturnExclusiveAccess: - /* it is possible to perform some actions on a device that is not open so do not return an error */ - priv->is_open = 0; + switch (kresult) { + case kIOReturnExclusiveAccess: + /* it is possible to perform some actions on a device that is not open so do not return an error */ + priv->is_open = 0; - break; - default: - (*(dpriv->device))->Release (dpriv->device); - dpriv->device = NULL; - return darwin_to_libusb (kresult); - } - } else { - priv->is_open = 1; + break; + default: + (*(dpriv->device))->Release (dpriv->device); + dpriv->device = NULL; + return darwin_to_libusb (kresult); + } + } else { + priv->is_open = 1; - /* create async event source */ - kresult = (*(dpriv->device))->CreateDeviceAsyncEventSource (dpriv->device, &priv->cfSource); + /* create async event source */ + kresult = (*(dpriv->device))->CreateDeviceAsyncEventSource (dpriv->device, &priv->cfSource); - CFRetain (libusb_darwin_acfl); + CFRetain (libusb_darwin_acfl); - /* add the cfSource to the aync run loop */ - CFRunLoopAddSource(libusb_darwin_acfl, priv->cfSource, kCFRunLoopCommonModes); + /* add the cfSource to the aync run loop */ + CFRunLoopAddSource(libusb_darwin_acfl, priv->cfSource, kCFRunLoopCommonModes); + } } + /* device opened successfully */ + dpriv->open_count++; + /* create a file descriptor for notifications */ pipe (priv->fds); @@ -624,39 +627,51 @@ static void darwin_close (struct libusb_device_handle *dev_handle) { IOReturn kresult; int i; + if (dpriv->open_count == 0) { + /* something is probably very wrong if this is the case */ + _usbi_log (HANDLE_CTX (dev_handle), LOG_LEVEL_ERROR, "Close called on a device that was not open!\n"); + return; + } + + dpriv->open_count--; + /* make sure all interfaces are released */ for (i = 0 ; i < USB_MAXINTERFACES ; i++) if (dev_handle->claimed_interfaces & (1 << i)) libusb_release_interface (dev_handle, i); - if (priv->is_open) { - /* delete the device's async event source */ - if (priv->cfSource) { - CFRunLoopRemoveSource (libusb_darwin_acfl, priv->cfSource, kCFRunLoopDefaultMode); - CFRelease (priv->cfSource); - } + if (0 == dpriv->open_count) { + if (priv->is_open) { + /* delete the device's async event source */ + if (priv->cfSource) { + CFRunLoopRemoveSource (libusb_darwin_acfl, priv->cfSource, kCFRunLoopDefaultMode); + CFRelease (priv->cfSource); + } - /* close the device */ - kresult = (*(dpriv->device))->USBDeviceClose(dpriv->device); + /* close the device */ + kresult = (*(dpriv->device))->USBDeviceClose(dpriv->device); + if (kresult) { + /* Log the fact that we had a problem closing the file, however failing a + * close isn't really an error, so return success anyway */ + _usbi_log (HANDLE_CTX (dev_handle), LOG_LEVEL_ERROR, "USBDeviceClose: %s", darwin_error_str(kresult)); + } + } + + kresult = (*(dpriv->device))->Release(dpriv->device); if (kresult) { /* Log the fact that we had a problem closing the file, however failing a * close isn't really an error, so return success anyway */ - _usbi_log (HANDLE_CTX (dev_handle), LOG_LEVEL_ERROR, "USBDeviceClose: %s", darwin_error_str(kresult)); + _usbi_log (HANDLE_CTX (dev_handle), LOG_LEVEL_ERROR, "Release: %s", darwin_error_str(kresult)); } - } - - kresult = (*(dpriv->device))->Release(dpriv->device); - if (kresult) { - /* Log the fact that we had a problem closing the file, however failing a - * close isn't really an error, so return success anyway */ - _usbi_log (HANDLE_CTX (dev_handle), LOG_LEVEL_ERROR, "Release: %s", darwin_error_str(kresult)); + + dpriv->device = NULL; } + /* file descriptors are maintained per-instance */ usbi_remove_pollfd (HANDLE_CTX (dev_handle), priv->fds[0]); close (priv->fds[1]); close (priv->fds[0]); - dpriv->device = NULL; priv->fds[0] = priv->fds[1] = -1; } @@ -950,6 +965,15 @@ static int darwin_set_interface_altsetting(struct libusb_device_handle *dev_hand if (kresult != kIOReturnSuccess) darwin_reset_device (dev_handle); + /* update list of endpoints */ + kresult = get_endpoints (dev_handle, iface); + if (kresult) { + /* this should not happen */ + darwin_release_interface (dev_handle, iface); + _usbi_log (HANDLE_CTX (dev_handle), LOG_LEVEL_ERROR, "could not build endpoint table"); + return kresult; + } + return darwin_to_libusb (kresult); } diff --git a/libusb/os/darwin_usb.h b/libusb/os/darwin_usb.h index bd64f89..a7b31eb 100644 --- a/libusb/os/darwin_usb.h +++ b/libusb/os/darwin_usb.h @@ -121,6 +121,7 @@ struct darwin_device_priv { UInt32 location; char sys_path[21]; usb_device_t **device; + int open_count; }; struct darwin_device_handle_priv { -- 2.7.4