summaryrefslogtreecommitdiff
path: root/libusb/os/darwin_usb.c
diff options
context:
space:
mode:
authorNathan Hjelm <hjelmn@mac.com>2009-11-21 17:06:43 +0000
committerDaniel Drake <dan@reactivated.net>2009-11-21 17:06:43 +0000
commit4c706d2fb6b2c43b10d72ac5dff51cac4d939f1a (patch)
tree9f4a04699a18f1c99e54885431232f006642b682 /libusb/os/darwin_usb.c
parent0232fc559cdacb9561f982dd6d28feb4435b3e4e (diff)
downloadlibusb-4c706d2fb6b2c43b10d72ac5dff51cac4d939f1a.tar.gz
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.
Diffstat (limited to 'libusb/os/darwin_usb.c')
-rw-r--r--libusb/os/darwin_usb.c128
1 files changed, 76 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);
}