summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Hjelm <hjelmn@mac.com>2009-06-07 22:29:35 +0100
committerDaniel Drake <dsd@gentoo.org>2009-06-07 22:31:49 +0100
commitc4a905022f684da9a4a853eb9232a81a53df2652 (patch)
treea7d3e03e469454fc37174afd3f551fbbd8e972fa
parent6b69f54451762ef590b9c938ab000c07cf9099a3 (diff)
downloadlibusb-c4a905022f684da9a4a853eb9232a81a53df2652.tar.gz
Darwin: improve handling of disconnected devices
-rw-r--r--libusb/os/darwin_usb.c78
1 files changed, 53 insertions, 25 deletions
diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
index a9eff05..9e12e07 100644
--- a/libusb/os/darwin_usb.c
+++ b/libusb/os/darwin_usb.c
@@ -225,22 +225,22 @@ static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) {
CFRelease (locationCF);
IOObjectRelease (device);
+ 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) {
+ if (handle && handle->os_priv) {
priv = (struct darwin_device_handle_priv *)handle->os_priv;
message = MESSAGE_DEVICE_GONE;
write (priv->fds[1], &message, sizeof (message));
-
- CFRunLoopRemoveSource (libusb_darwin_acfl, priv->cfSource, kCFRunLoopDefaultMode);
- CFRelease (priv->cfSource);
- priv->cfSource = NULL;
}
+
+ pthread_mutex_unlock(&ctx->open_devs_lock);
+
}
}
@@ -262,6 +262,8 @@ static void *event_thread_main (void *arg0) {
_usbi_log (ctx, LOG_LEVEL_INFO, "creating hotplug event source");
+ CFRetain (CFRunLoopGetCurrent ());
+
/* add the notification port to the run loop */
libusb_notification_port = IONotificationPortCreate (libusb_darwin_mp);
libusb_notification_cfsource = IONotificationPortGetRunLoopSource (libusb_notification_port);
@@ -295,7 +297,9 @@ static void *event_thread_main (void *arg0) {
/* delete notification port */
CFRunLoopSourceInvalidate (libusb_notification_cfsource);
IONotificationPortDestroy (libusb_notification_port);
-
+
+ CFRelease (CFRunLoopGetCurrent ());
+
libusb_darwin_acfl = NULL;
pthread_exit (0);
@@ -461,10 +465,10 @@ static int process_new_device (struct libusb_context *ctx, usb_device_t **device
ret = (*(device))->DeviceRequest (device, &req);
if (ret != kIOReturnSuccess) {
int try_unsuspend = 1;
+#if DeviceVersion >= 320
UInt32 info;
/* device may be suspended. unsuspend it and try again */
-#if DeviceVersion >= 320
/* IOUSBFamily 320+ provides a way to detect device suspension but earlier versions do not */
(void)(*device)->GetUSBDeviceInformation (device, &info);
@@ -831,9 +835,18 @@ static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int i
/* get an interface to the device's interface */
kresult = IOCreatePlugInInterfaceForService (usbInterface, kIOUSBInterfaceUserClientTypeID,
kIOCFPlugInInterfaceID, &plugInInterface, &score);
- kresult = IOObjectRelease(usbInterface);
- if (kresult || !plugInInterface)
+ if (kresult) {
+ _usbi_log (HANDLE_CTX (dev_handle), LOG_LEVEL_ERROR, "IOCreatePlugInInterfaceForService: %s", darwin_error_str(kresult));
return darwin_to_libusb (kresult);
+ }
+
+ if (!plugInInterface) {
+ _usbi_log (HANDLE_CTX (dev_handle), LOG_LEVEL_ERROR, "plugin interface not found");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ /* ignore release error */
+ (void)IOObjectRelease (usbInterface);
/* Do the actual claim */
kresult = (*plugInInterface)->QueryInterface(plugInInterface,
@@ -863,11 +876,20 @@ static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int i
return kresult;
}
+ cInterface->cfSource = NULL;
+
/* create async event source */
kresult = (*(cInterface->interface))->CreateInterfaceAsyncEventSource (cInterface->interface, &cInterface->cfSource);
-
- /* add the cfSource to the aync run loop */
- CFRetain (libusb_darwin_acfl);
+ if (kresult != kIOReturnSuccess) {
+ _usbi_log (HANDLE_CTX (dev_handle), LOG_LEVEL_ERROR, "could not create async event source");
+
+ /* can't continue without an async event source */
+ (void)darwin_release_interface (dev_handle, iface);
+
+ return darwin_to_libusb (kresult);
+ }
+
+ /* add the cfSource to the async thread's run loop */
CFRunLoopAddSource(libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode);
_usbi_log (HANDLE_CTX (dev_handle), LOG_LEVEL_INFO, "interface opened");
@@ -890,8 +912,10 @@ static int darwin_release_interface(struct libusb_device_handle *dev_handle, int
cInterface->num_endpoints = 0;
/* delete the interface's async event source */
- CFRunLoopRemoveSource (libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode);
- CFRelease (cInterface->cfSource);
+ if (cInterface->cfSource) {
+ CFRunLoopRemoveSource (libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode);
+ CFRelease (cInterface->cfSource);
+ }
kresult = (*(cInterface->interface))->USBInterfaceClose(cInterface->interface);
if (kresult)
@@ -1391,20 +1415,24 @@ static int op_handle_events(struct libusb_context *ctx, struct pollfd *fds, nfds
break;
}
- if (pollfd->revents & POLLERR) {
- usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fds[0]);
- usbi_handle_disconnect(handle);
-
- /* done with this device */
- continue;
- }
-
- ret = read (hpriv->fds[0], &message, sizeof (message));
- if (ret < sizeof (message))
- continue;
+ if (!(pollfd->revents & POLLERR)) {
+ ret = read (hpriv->fds[0], &message, sizeof (message));
+ if (ret < sizeof (message))
+ continue;
+ } else
+ /* could not poll the device-- response is to delete the device (this seems a little heavy-handed) */
+ message = MESSAGE_DEVICE_GONE;
switch (message) {
case MESSAGE_DEVICE_GONE:
+ /* remove the device's async port from the runloop */
+ if (hpriv->cfSource) {
+ if (libusb_darwin_acfl)
+ CFRunLoopRemoveSource (libusb_darwin_acfl, hpriv->cfSource, kCFRunLoopDefaultMode);
+ CFRelease (hpriv->cfSource);
+ hpriv->cfSource = NULL;
+ }
+
usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fds[0]);
usbi_handle_disconnect(handle);