diff --git a/.gitignore b/.gitignore
index 5fc74a5..b270a47 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/libusbx-1.0.15.tar.bz2
+SOURCES/libusb-1.0.20.tar.bz2
diff --git a/.libusbx.metadata b/.libusbx.metadata
index 9daa697..86cb0b6 100644
--- a/.libusbx.metadata
+++ b/.libusbx.metadata
@@ -1 +1 @@
-1ca868f775093b0109d9240cb3ccd36367764dc6 SOURCES/libusbx-1.0.15.tar.bz2
+9537243f165927bde74ad742e6b3effb0bd50cd2 SOURCES/libusb-1.0.20.tar.bz2
diff --git a/SOURCES/0001-core-Store-different-event-types-as-a-bitmask-within.patch b/SOURCES/0001-core-Store-different-event-types-as-a-bitmask-within.patch
new file mode 100644
index 0000000..f60357c
--- /dev/null
+++ b/SOURCES/0001-core-Store-different-event-types-as-a-bitmask-within.patch
@@ -0,0 +1,113 @@
+From 9e2e370574ddedc1ad2e47a20bb0a8a85bd2249d Mon Sep 17 00:00:00 2001
+From: Chris Dickens <christopher.a.dickens@gmail.com>
+Date: Wed, 9 Dec 2015 23:45:21 -0800
+Subject: [PATCH 1/3] core: Store different event types as a bitmask within the
+ context
+
+This change introduces a new event_flags member to the libusb_context
+that holds a bitmask of different events that have occurred. This will
+allow multiple "one-shot" events (those that don't require counting) to
+be stored in a single variable. The only existing event of this type,
+pollfds_modified, has been converted to use this bitmask instead.
+
+Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
+---
+ libusb/io.c           |  8 ++++----
+ libusb/libusbi.h      | 16 +++++++++++-----
+ libusb/version_nano.h |  2 +-
+ 3 files changed, 16 insertions(+), 10 deletions(-)
+
+diff --git a/libusb/io.c b/libusb/io.c
+index 279288c..ce0abb9 100644
+--- a/libusb/io.c
++++ b/libusb/io.c
+@@ -2055,7 +2055,7 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
+ 	/* only reallocate the poll fds when the list of poll fds has been modified
+ 	 * since the last poll, otherwise reuse them to save the additional overhead */
+ 	usbi_mutex_lock(&ctx->event_data_lock);
+-	if (ctx->pollfds_modified) {
++	if (ctx->event_flags & USBI_EVENT_POLLFDS_MODIFIED) {
+ 		usbi_dbg("poll fds modified, reallocating");
+ 
+ 		if (ctx->pollfds) {
+@@ -2081,7 +2081,7 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
+ 		}
+ 
+ 		/* reset the flag now that we have the updated list */
+-		ctx->pollfds_modified = 0;
++		ctx->event_flags &= ~USBI_EVENT_POLLFDS_MODIFIED;
+ 
+ 		/* if no further pending events, clear the event pipe so that we do
+ 		 * not immediately return from poll */
+@@ -2125,7 +2125,7 @@ redo_poll:
+ 		usbi_mutex_lock(&ctx->event_data_lock);
+ 
+ 		/* check if someone added a new poll fd */
+-		if (ctx->pollfds_modified)
++		if (ctx->event_flags & USBI_EVENT_POLLFDS_MODIFIED)
+ 			usbi_dbg("someone updated the poll fds");
+ 
+ 		/* check if someone is closing a device */
+@@ -2583,7 +2583,7 @@ static void usbi_fd_notification(struct libusb_context *ctx)
+ 	/* Record that there is a new poll fd.
+ 	 * Only signal an event if there are no prior pending events. */
+ 	pending_events = usbi_pending_events(ctx);
+-	ctx->pollfds_modified = 1;
++	ctx->event_flags |= USBI_EVENT_POLLFDS_MODIFIED;
+ 	if (!pending_events)
+ 		usbi_signal_event(ctx);
+ }
+diff --git a/libusb/libusbi.h b/libusb/libusbi.h
+index 822612e..40ae608 100644
+--- a/libusb/libusbi.h
++++ b/libusb/libusbi.h
+@@ -287,18 +287,19 @@ struct libusb_context {
+ 	/* A lock to protect internal context event data. */
+ 	usbi_mutex_t event_data_lock;
+ 
++	/* A bitmask of flags that are set to indicate specific events that need to
++	 * be handled. Protected by event_data_lock. */
++	unsigned int event_flags;
++
+ 	/* A counter that is set when we want to interrupt and prevent event handling,
+ 	 * in order to safely close a device. Protected by event_data_lock. */
+ 	unsigned int device_close;
+ 
+ 	/* list and count of poll fds and an array of poll fd structures that is
+-	 * (re)allocated as necessary prior to polling, and a flag to indicate
+-	 * when the list of poll fds has changed since the last poll.
+-	 * Protected by event_data_lock. */
++	 * (re)allocated as necessary prior to polling. Protected by event_data_lock. */
+ 	struct list_head ipollfds;
+ 	struct pollfd *pollfds;
+ 	POLL_NFDS_TYPE pollfds_cnt;
+-	unsigned int pollfds_modified;
+ 
+ 	/* A list of pending hotplug messages. Protected by event_data_lock. */
+ 	struct list_head hotplug_msgs;
+@@ -315,9 +316,14 @@ struct libusb_context {
+ 	struct list_head list;
+ };
+ 
++enum usbi_event_flags {
++	/* The list of pollfds has been modified */
++	USBI_EVENT_POLLFDS_MODIFIED = 1 << 0,
++};
++
+ /* Update the following macro if new event sources are added */
+ #define usbi_pending_events(ctx) \
+-	((ctx)->device_close || (ctx)->pollfds_modified \
++	((ctx)->event_flags || (ctx)->device_close \
+ 	 || !list_empty(&(ctx)->hotplug_msgs) || !list_empty(&(ctx)->completed_transfers))
+ 
+ #ifdef USBI_TIMERFD_AVAILABLE
+diff --git a/libusb/version_nano.h b/libusb/version_nano.h
+index 4afcd97..7abae0e 100644
+--- a/libusb/version_nano.h
++++ b/libusb/version_nano.h
+@@ -1 +1 @@
+-#define LIBUSB_NANO 11004
++#define LIBUSB_NANO 11005
+-- 
+2.7.4
+
diff --git a/SOURCES/0001-linux_usbfs-Work-around-a-driver-binding-race-in-res.patch b/SOURCES/0001-linux_usbfs-Work-around-a-driver-binding-race-in-res.patch
deleted file mode 100644
index 3a39c1c..0000000
--- a/SOURCES/0001-linux_usbfs-Work-around-a-driver-binding-race-in-res.patch
+++ /dev/null
@@ -1,86 +0,0 @@
-From 78a150bfbbd84eb524e878bf05101c1ad2eac0b8 Mon Sep 17 00:00:00 2001
-From: Hans de Goede <hdegoede@redhat.com>
-Date: Fri, 6 Jul 2012 14:35:53 +0200
-Subject: [PATCH 3/3] linux_usbfs: Work around a driver binding race in reset
- handling
-
-I've been seeing these intermittent failures to reclaim an interface after
-a device reset. After much debugging and inserting sleeps in strategic
-places to make the race window larger I've found the following race:
-1) A user is running some software using libusb which will automatically
-   detect, and "bind" to, any newly plugged in USB-devices. For example
-   a virtual machine viewer with automatic USB-redirection
-2) The user plugs in a new usb-storage device
-3) The usb-storage driver is not yet loaded, udev spawns
-   "modprobe usb-storage", this blocks on disk-io
-4) The libusb app opens the device, claims all interfaces, does a device-reset
-5) While the IOCTL_USBFS_RESET is running the modprobe completes
-6) The driver registration blocks on an USB lock held by the reset code path
-7) When the reset finishes the driver registration completes and the driver
-   binds itself to the device, before IOCTL_USBFS_RESET returns to userspace
-8) libusb tries to re-claim all interfaces it had claimed before the reset
-9) libusb fails as usb-storage is now bound to it
-
-This patch works around this issue by simply unbinding the driver for all
-interfaces which were claimed before the reset. Normally this is a no-op as
-no driver (other then usbfs) can be bound for claimed interfaces before the
-reset.
-
-But as the above example shows, the exception is a driver completing
-registration, and as part of this binding to any elegible devices, between
-IOCTL_USBFS_RESET and our re-claiming of the interface. The largest part
-of the race window here is the time IOCTL_USBFS_RESET takes, as that does a
-fair amount of IO with the device. This part of the race window is
-worked around by this patch.
-
-This still leaves a theoretical race window where the driver registration
-finishes between our driver-unbind and interface-reclaim, I'm afraid there
-is nothing we can against this.
-
-This patch also improves the error logging, and makes libusb_device_reset
-properly return an error when re-claiming fails.
-
-Signed-off-by: Hans de Goede <hdegoede@redhat.com>
----
- libusb/os/linux_usbfs.c | 14 +++++++++++++-
- 1 file changed, 13 insertions(+), 1 deletion(-)
-
-diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
-index 3894554..10d138a 100644
---- a/libusb/os/linux_usbfs.c
-+++ b/libusb/os/linux_usbfs.c
-@@ -108,6 +108,9 @@ static int sysfs_can_relate_devices = 0;
- /* do we have a descriptors file? */
- static int sysfs_has_descriptors = 0;
- 
-+static int op_detach_kernel_driver(struct libusb_device_handle *handle,
-+	int interface);
-+
- struct linux_device_priv {
- 	char *sysfs_dir;
- 	unsigned char *dev_descriptor;
-@@ -1497,11 +1500,20 @@ static int op_reset_device(struct libusb_device_handle *handle)
- 	/* And re-claim any interfaces which were claimed before the reset */
- 	for (i = 0; i < USB_MAXINTERFACES; i++) {
- 		if (handle->claimed_interfaces & (1L << i)) {
-+			/*
-+			 * A driver may have completed modprobing during
-+			 * IOCTL_USBFS_RESET, and bound itself as soon as
-+			 * IOCTL_USBFS_RESET released the device lock
-+			 */
-+			op_detach_kernel_driver(handle, i);
-+
- 			r = op_claim_interface(handle, i);
- 			if (r) {
- 				usbi_warn(HANDLE_CTX(handle),
--					"failed to re-claim interface %d after reset", i);
-+					"failed to re-claim interface %d after reset: %s",
-+					i, libusb_error_name(r));
- 				handle->claimed_interfaces &= ~(1L << i);
-+				ret = LIBUSB_ERROR_NOT_FOUND;
- 			}
- 		}
- 	}
--- 
-1.7.11.2
-
diff --git a/SOURCES/0002-API-Add-libusb_interrupt_event_handler-function.patch b/SOURCES/0002-API-Add-libusb_interrupt_event_handler-function.patch
new file mode 100644
index 0000000..776ad21
--- /dev/null
+++ b/SOURCES/0002-API-Add-libusb_interrupt_event_handler-function.patch
@@ -0,0 +1,123 @@
+From 3daf9625c7f9212a762927239b2f0f14d68f4361 Mon Sep 17 00:00:00 2001
+From: Chris Dickens <christopher.a.dickens@gmail.com>
+Date: Thu, 10 Dec 2015 00:20:18 -0800
+Subject: [PATCH 2/3] API: Add libusb_interrupt_event_handler() function
+
+This new function will allow the user to purposely interrupt an
+event handling thread, causing it to return from the event handling
+function. This is mainly useful for cleanly exiting from a dedicated
+event handling thread during application shutdown.
+
+Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
+---
+ libusb/io.c           | 28 ++++++++++++++++++++++++++++
+ libusb/libusb-1.0.def |  2 ++
+ libusb/libusb.h       |  3 ++-
+ libusb/libusbi.h      |  3 +++
+ libusb/version_nano.h |  2 +-
+ 5 files changed, 36 insertions(+), 2 deletions(-)
+
+diff --git a/libusb/io.c b/libusb/io.c
+index ce0abb9..bc85438 100644
+--- a/libusb/io.c
++++ b/libusb/io.c
+@@ -1848,6 +1848,29 @@ int API_EXPORTED libusb_event_handler_active(libusb_context *ctx)
+ }
+ 
+ /** \ingroup poll
++ * Interrupt any active thread that is handling events. This is mainly useful
++ * for interrupting a dedicated event handling thread when an application
++ * wishes to call libusb_exit().
++ *
++ * Since version 1.0.21, \ref LIBUSB_API_VERSION >= 0x01000105
++ *
++ * \param ctx the context to operate on, or NULL for the default context
++ * \ref mtasync
++ */
++void API_EXPORTED libusb_interrupt_event_handler(libusb_context *ctx)
++{
++	USBI_GET_CONTEXT(ctx);
++
++	usbi_dbg("");
++	usbi_mutex_lock(&ctx->event_data_lock);
++	if (!usbi_pending_events(ctx)) {
++		ctx->event_flags |= USBI_EVENT_USER_INTERRUPT;
++		usbi_signal_event(ctx);
++	}
++	usbi_mutex_unlock(&ctx->event_data_lock);
++}
++
++/** \ingroup poll
+  * Acquire the event waiters lock. This lock is designed to be obtained under
+  * the situation where you want to be aware when events are completed, but
+  * some other thread is event handling so calling libusb_handle_events() is not
+@@ -2128,6 +2151,11 @@ redo_poll:
+ 		if (ctx->event_flags & USBI_EVENT_POLLFDS_MODIFIED)
+ 			usbi_dbg("someone updated the poll fds");
+ 
++		if (ctx->event_flags & USBI_EVENT_USER_INTERRUPT) {
++			usbi_dbg("someone purposely interrupted");
++			ctx->event_flags &= ~USBI_EVENT_USER_INTERRUPT;
++		}
++
+ 		/* check if someone is closing a device */
+ 		if (ctx->device_close)
+ 			usbi_dbg("someone is closing a device");
+diff --git a/libusb/libusb-1.0.def b/libusb/libusb-1.0.def
+index cbcf3e9..050b4b9 100644
+--- a/libusb/libusb-1.0.def
++++ b/libusb/libusb-1.0.def
+@@ -116,6 +116,8 @@ EXPORTS
+   libusb_hotplug_register_callback@36 = libusb_hotplug_register_callback
+   libusb_init
+   libusb_init@4 = libusb_init
++  libusb_interrupt_event_handler
++  libusb_interrupt_event_handler@4 = libusb_interrupt_event_handler
+   libusb_interrupt_transfer
+   libusb_interrupt_transfer@24 = libusb_interrupt_transfer
+   libusb_kernel_driver_active
+diff --git a/libusb/libusb.h b/libusb/libusb.h
+index 513945f..ba82c36 100644
+--- a/libusb/libusb.h
++++ b/libusb/libusb.h
+@@ -141,7 +141,7 @@ typedef unsigned __int32  uint32_t;
+  * Internally, LIBUSB_API_VERSION is defined as follows:
+  * (libusb major << 24) | (libusb minor << 16) | (16 bit incremental)
+  */
+-#define LIBUSB_API_VERSION 0x01000104
++#define LIBUSB_API_VERSION 0x01000105
+ 
+ /* The following is kept for compatibility, but will be deprecated in the future */
+ #define LIBUSBX_API_VERSION LIBUSB_API_VERSION
+@@ -1801,6 +1801,7 @@ void LIBUSB_CALL libusb_lock_events(libusb_context *ctx);
+ void LIBUSB_CALL libusb_unlock_events(libusb_context *ctx);
+ int LIBUSB_CALL libusb_event_handling_ok(libusb_context *ctx);
+ int LIBUSB_CALL libusb_event_handler_active(libusb_context *ctx);
++void LIBUSB_CALL libusb_interrupt_event_handler(libusb_context *ctx);
+ void LIBUSB_CALL libusb_lock_event_waiters(libusb_context *ctx);
+ void LIBUSB_CALL libusb_unlock_event_waiters(libusb_context *ctx);
+ int LIBUSB_CALL libusb_wait_for_event(libusb_context *ctx, struct timeval *tv);
+diff --git a/libusb/libusbi.h b/libusb/libusbi.h
+index 40ae608..a39cbe1 100644
+--- a/libusb/libusbi.h
++++ b/libusb/libusbi.h
+@@ -319,6 +319,9 @@ struct libusb_context {
+ enum usbi_event_flags {
+ 	/* The list of pollfds has been modified */
+ 	USBI_EVENT_POLLFDS_MODIFIED = 1 << 0,
++
++	/* The user has interrupted the event handler */
++	USBI_EVENT_USER_INTERRUPT = 1 << 1,
+ };
+ 
+ /* Update the following macro if new event sources are added */
+diff --git a/libusb/version_nano.h b/libusb/version_nano.h
+index 7abae0e..ea79210 100644
+--- a/libusb/version_nano.h
++++ b/libusb/version_nano.h
+@@ -1 +1 @@
+-#define LIBUSB_NANO 11005
++#define LIBUSB_NANO 11006
+-- 
+2.7.4
+
diff --git a/SOURCES/0003-core-Refactor-code-related-to-transfer-flags-and-tim.patch b/SOURCES/0003-core-Refactor-code-related-to-transfer-flags-and-tim.patch
new file mode 100644
index 0000000..4421640
--- /dev/null
+++ b/SOURCES/0003-core-Refactor-code-related-to-transfer-flags-and-tim.patch
@@ -0,0 +1,494 @@
+From 65115ea3b437612c5c75408d9a4028cdb070e406 Mon Sep 17 00:00:00 2001
+From: Chris Dickens <christopher.a.dickens@gmail.com>
+Date: Mon, 26 Oct 2015 14:18:33 +0100
+Subject: [PATCH 3/3] core: Refactor code related to transfer flags and timeout
+ handling
+
+Commit a886bb02 sped up the library a bit by removing the serialization
+of transfer submission with respect to the flying_transfers list, but
+it introduced two separate issues.
+
+1) A deadlock scenario is possible given the following sequence:
+
+   - Thread A submits transfer with very short timeout (say 1ms)
+     -> takes transfer->lock
+     -> adds transfer to flying_transfers list and arms timerfd
+     -> actually calls backend to submit transfer, but it fails
+   <context switch>
+   - Thread B is doing event handling and sees the timerfd trigger
+     -> takes ctx->flying_transfers_lock
+     -> finds the transfer above on the list
+     -> calls libusb_cancel_transfer() for this transfer
+       --> takes transfer->lock
+   <context switch>
+   - Thread A sees the transfer failed to submit
+     -> removes transfer from flying_transfers list
+       --> takes ctx->flying_transfers_lock (still holding transfer->lock)
+   ** DEADLOCK **
+
+2) The transfer state flags (e.g. submitting, in-flight) were protected
+    by transfer->flags_lock, but the timeout-related flags were OR'ed in
+    during timeout handling operations outside of the lock. This leads to
+    the possibility that transfer state might get overwritten.
+
+This change corrects these issues and simplifies the transfer submission
+code a bit by separating the state and timeout flags into their own flag
+variables. The state flags are protected by the transfer lock. The timeout
+flags are protected by the flying_transfers_lock.
+
+The transfer submission code sheds some weight because it no longer needs
+to worry about the timing of events that modify the transfer state flags.
+These flags are always viewed and modified under the protection of the
+transfer lock. Since libusb_submit_transfer() holds the transfer lock for
+the entire duration of the operation, the other code paths that would
+possibly touch the transfer (e.g. usbi_handle_disconnect() and
+usbi_handle_transfer_completion()) have to wait for transfer submission
+to fully complete. This eliminates any possible race conditions.
+
+Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
+[hdegoede@redhat.com: Reworked libusb_submit_transfer changes so that in
+ case both flying_transfer_lock and itransfer->lock are taken
+ flying_transfers_lock is always taken first]
+[hdegoede@redhat.com: Removed some unrelated changes (will be submitted
+ as separate patches)]
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ libusb/core.c          |   4 +-
+ libusb/io.c            | 144 ++++++++++++++++++++++++++-----------------------
+ libusb/libusbi.h       |  43 +++++++--------
+ libusb/os/darwin_usb.c |  10 ++--
+ libusb/version_nano.h  |   2 +-
+ 5 files changed, 104 insertions(+), 99 deletions(-)
+
+diff --git a/libusb/core.c b/libusb/core.c
+index 5884dcf..837e8f2 100644
+--- a/libusb/core.c
++++ b/libusb/core.c
+@@ -1331,10 +1331,10 @@ static void do_close(struct libusb_context *ctx,
+ 		if (transfer->dev_handle != dev_handle)
+ 			continue;
+ 
+-		if (!(itransfer->flags & USBI_TRANSFER_DEVICE_DISAPPEARED)) {
++		if (!(itransfer->state_flags & USBI_TRANSFER_DEVICE_DISAPPEARED)) {
+ 			usbi_err(ctx, "Device handle closed while transfer was still being processed, but the device is still connected as far as we know");
+ 
+-			if (itransfer->flags & USBI_TRANSFER_CANCELLING)
++			if (itransfer->state_flags & USBI_TRANSFER_CANCELLING)
+ 				usbi_warn(ctx, "A cancellation for an in-flight transfer hasn't completed but closing the device handle");
+ 			else
+ 				usbi_err(ctx, "A cancellation hasn't even been scheduled on the transfer for which the device is closing");
+diff --git a/libusb/io.c b/libusb/io.c
+index bc85438..c216814 100644
+--- a/libusb/io.c
++++ b/libusb/io.c
+@@ -1260,7 +1260,6 @@ struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(
+ 
+ 	itransfer->num_iso_packets = iso_packets;
+ 	usbi_mutex_init(&itransfer->lock, NULL);
+-	usbi_mutex_init(&itransfer->flags_lock, NULL);
+ 	transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ 	usbi_dbg("transfer %p", transfer);
+ 	return transfer;
+@@ -1295,7 +1294,6 @@ void API_EXPORTED libusb_free_transfer(struct libusb_transfer *transfer)
+ 
+ 	itransfer = LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);
+ 	usbi_mutex_destroy(&itransfer->lock);
+-	usbi_mutex_destroy(&itransfer->flags_lock);
+ 	free(itransfer);
+ }
+ 
+@@ -1330,8 +1328,8 @@ static int arm_timerfd_for_next_timeout(struct libusb_context *ctx)
+ 		if (!timerisset(cur_tv))
+ 			goto disarm;
+ 
+-		/* act on first transfer that is not already cancelled */
+-		if (!(transfer->flags & USBI_TRANSFER_TIMEOUT_HANDLED)) {
++		/* act on first transfer that has not already been handled */
++		if (!(transfer->timeout_flags & USBI_TRANSFER_TIMEOUT_HANDLED)) {
+ 			int r;
+ 			const struct itimerspec it = { {0, 0},
+ 				{ cur_tv->tv_sec, cur_tv->tv_usec * 1000 } };
+@@ -1365,8 +1363,6 @@ static int add_to_flying_list(struct usbi_transfer *transfer)
+ 	int r = 0;
+ 	int first = 1;
+ 
+-	usbi_mutex_lock(&ctx->flying_transfers_lock);
+-
+ 	/* if we have no other flying transfers, start the list with this one */
+ 	if (list_empty(&ctx->flying_transfers)) {
+ 		list_add(&transfer->list, &ctx->flying_transfers);
+@@ -1419,7 +1415,6 @@ out:
+ 	if (r)
+ 		list_del(&transfer->list);
+ 
+-	usbi_mutex_unlock(&ctx->flying_transfers_lock);
+ 	return r;
+ }
+ 
+@@ -1460,62 +1455,79 @@ int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer)
+ {
+ 	struct usbi_transfer *itransfer =
+ 		LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);
+-	int remove = 0;
++	struct libusb_context *ctx = TRANSFER_CTX(transfer);
+ 	int r;
+ 
+ 	usbi_dbg("transfer %p", transfer);
++
++	/*
++	 * Important note on locking, this function takes / releases locks
++	 * in the following order:
++	 *  take flying_transfers_lock
++	 *  take itransfer->lock
++	 *  clear transfer
++	 *  add to flying_transfers list
++	 *  release flying_transfers_lock
++	 *  submit transfer
++	 *  release itransfer->lock
++	 *  if submit failed:
++	 *   take flying_transfers_lock
++	 *   remove from flying_transfers list
++	 *   release flying_transfers_lock
++	 *
++	 * Note that it takes locks in the order a-b and then releases them
++	 * in the same order a-b. This is somewhat unusual but not wrong,
++	 * release order is not important as long as *all* locks are released
++	 * before re-acquiring any locks.
++	 *
++	 * This means that the ordering of first releasing itransfer->lock
++	 * and then re-acquiring the flying_transfers_list on error is
++	 * important and must not be changed!
++	 *
++	 * This is done this way because when we take both locks we must always
++	 * take flying_transfers_lock first to avoid ab-ba style deadlocks with
++	 * the timeout handling and usbi_handle_disconnect paths.
++	 *
++	 * And we cannot release itransfer->lock before the submission is
++	 * complete otherwise timeout handling for transfers with short
++	 * timeouts may run before submission.
++	 */
++	usbi_mutex_lock(&ctx->flying_transfers_lock);
+ 	usbi_mutex_lock(&itransfer->lock);
+-	usbi_mutex_lock(&itransfer->flags_lock);
+-	if (itransfer->flags & USBI_TRANSFER_IN_FLIGHT) {
+-		r = LIBUSB_ERROR_BUSY;
+-		goto out;
++	if (itransfer->state_flags & USBI_TRANSFER_IN_FLIGHT) {
++		usbi_mutex_unlock(&ctx->flying_transfers_lock);
++		usbi_mutex_unlock(&itransfer->lock);
++		return LIBUSB_ERROR_BUSY;
+ 	}
+ 	itransfer->transferred = 0;
+-	itransfer->flags = 0;
++	itransfer->state_flags = 0;
++	itransfer->timeout_flags = 0;
+ 	r = calculate_timeout(itransfer);
+ 	if (r < 0) {
+-		r = LIBUSB_ERROR_OTHER;
+-		goto out;
++		usbi_mutex_unlock(&ctx->flying_transfers_lock);
++		usbi_mutex_unlock(&itransfer->lock);
++		return LIBUSB_ERROR_OTHER;
+ 	}
+-	itransfer->flags |= USBI_TRANSFER_SUBMITTING;
+-	usbi_mutex_unlock(&itransfer->flags_lock);
+ 
+ 	r = add_to_flying_list(itransfer);
+ 	if (r) {
+-		usbi_mutex_lock(&itransfer->flags_lock);
+-		itransfer->flags = 0;
+-		goto out;
++		usbi_mutex_unlock(&ctx->flying_transfers_lock);
++		usbi_mutex_unlock(&itransfer->lock);
++		return r;
+ 	}
++	usbi_mutex_unlock(&ctx->flying_transfers_lock);
+ 
+-	/* keep a reference to this device */
+-	libusb_ref_device(transfer->dev_handle->dev);
+ 	r = usbi_backend->submit_transfer(itransfer);
+-
+-	usbi_mutex_lock(&itransfer->flags_lock);
+-	itransfer->flags &= ~USBI_TRANSFER_SUBMITTING;
+ 	if (r == LIBUSB_SUCCESS) {
+-		/* check for two possible special conditions:
+-		 *   1) device disconnect occurred immediately after submission
+-		 *   2) transfer completed before we got here to update the flags
+-		 */
+-		if (itransfer->flags & USBI_TRANSFER_DEVICE_DISAPPEARED) {
+-			usbi_backend->clear_transfer_priv(itransfer);
+-			remove = 1;
+-			r = LIBUSB_ERROR_NO_DEVICE;
+-		}
+-		else if (!(itransfer->flags & USBI_TRANSFER_COMPLETED)) {
+-			itransfer->flags |= USBI_TRANSFER_IN_FLIGHT;
+-		}
+-	} else {
+-		remove = 1;
+-	}
+-out:
+-	usbi_mutex_unlock(&itransfer->flags_lock);
+-	if (remove) {
+-		libusb_unref_device(transfer->dev_handle->dev);
+-		remove_from_flying_list(itransfer);
++		itransfer->state_flags |= USBI_TRANSFER_IN_FLIGHT;
++		/* keep a reference to this device */
++		libusb_ref_device(transfer->dev_handle->dev);
+ 	}
+ 	usbi_mutex_unlock(&itransfer->lock);
++
++	if (r != LIBUSB_SUCCESS)
++		remove_from_flying_list(itransfer);
++
+ 	return r;
+ }
+ 
+@@ -1541,9 +1553,8 @@ int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer)
+ 
+ 	usbi_dbg("transfer %p", transfer );
+ 	usbi_mutex_lock(&itransfer->lock);
+-	usbi_mutex_lock(&itransfer->flags_lock);
+-	if (!(itransfer->flags & USBI_TRANSFER_IN_FLIGHT)
+-			|| (itransfer->flags & USBI_TRANSFER_CANCELLING)) {
++	if (!(itransfer->state_flags & USBI_TRANSFER_IN_FLIGHT)
++			|| (itransfer->state_flags & USBI_TRANSFER_CANCELLING)) {
+ 		r = LIBUSB_ERROR_NOT_FOUND;
+ 		goto out;
+ 	}
+@@ -1557,13 +1568,12 @@ int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer)
+ 			usbi_dbg("cancel transfer failed error %d", r);
+ 
+ 		if (r == LIBUSB_ERROR_NO_DEVICE)
+-			itransfer->flags |= USBI_TRANSFER_DEVICE_DISAPPEARED;
++			itransfer->state_flags |= USBI_TRANSFER_DEVICE_DISAPPEARED;
+ 	}
+ 
+-	itransfer->flags |= USBI_TRANSFER_CANCELLING;
++	itransfer->state_flags |= USBI_TRANSFER_CANCELLING;
+ 
+ out:
+-	usbi_mutex_unlock(&itransfer->flags_lock);
+ 	usbi_mutex_unlock(&itransfer->lock);
+ 	return r;
+ }
+@@ -1626,10 +1636,9 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer,
+ 	if (r < 0)
+ 		usbi_err(ITRANSFER_CTX(itransfer), "failed to set timer for next timeout, errno=%d", errno);
+ 
+-	usbi_mutex_lock(&itransfer->flags_lock);
+-	itransfer->flags &= ~USBI_TRANSFER_IN_FLIGHT;
+-	itransfer->flags |= USBI_TRANSFER_COMPLETED;
+-	usbi_mutex_unlock(&itransfer->flags_lock);
++	usbi_mutex_lock(&itransfer->lock);
++	itransfer->state_flags &= ~USBI_TRANSFER_IN_FLIGHT;
++	usbi_mutex_unlock(&itransfer->lock);
+ 
+ 	if (status == LIBUSB_TRANSFER_COMPLETED
+ 			&& transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {
+@@ -1665,7 +1674,7 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer,
+ int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer)
+ {
+ 	/* if the URB was cancelled due to timeout, report timeout to the user */
+-	if (transfer->flags & USBI_TRANSFER_TIMED_OUT) {
++	if (transfer->timeout_flags & USBI_TRANSFER_TIMED_OUT) {
+ 		usbi_dbg("detected timeout cancellation");
+ 		return usbi_handle_transfer_completion(transfer, LIBUSB_TRANSFER_TIMED_OUT);
+ 	}
+@@ -1966,10 +1975,10 @@ static void handle_timeout(struct usbi_transfer *itransfer)
+ 		USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ 	int r;
+ 
+-	itransfer->flags |= USBI_TRANSFER_TIMEOUT_HANDLED;
++	itransfer->timeout_flags |= USBI_TRANSFER_TIMEOUT_HANDLED;
+ 	r = libusb_cancel_transfer(transfer);
+ 	if (r == 0)
+-		itransfer->flags |= USBI_TRANSFER_TIMED_OUT;
++		itransfer->timeout_flags |= USBI_TRANSFER_TIMED_OUT;
+ 	else
+ 		usbi_warn(TRANSFER_CTX(transfer),
+ 			"async cancel failed %d errno=%d", r, errno);
+@@ -2002,7 +2011,7 @@ static int handle_timeouts_locked(struct libusb_context *ctx)
+ 			return 0;
+ 
+ 		/* ignore timeouts we've already handled */
+-		if (transfer->flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT))
++		if (transfer->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT))
+ 			continue;
+ 
+ 		/* if transfer has non-expired timeout, nothing more to do */
+@@ -2534,7 +2543,7 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx,
+ 
+ 	/* find next transfer which hasn't already been processed as timed out */
+ 	list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
+-		if (transfer->flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT))
++		if (transfer->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT))
+ 			continue;
+ 
+ 		/* if we've reached transfers of infinte timeout, we're done looking */
+@@ -2751,9 +2760,10 @@ void usbi_handle_disconnect(struct libusb_device_handle *handle)
+ 	 * possible scenarios:
+ 	 * 1. the transfer is currently in-flight, in which case we terminate the
+ 	 *    transfer here
+-	 * 2. the transfer is not in-flight (or is but hasn't been marked as such),
+-	 *    in which case we record that the device disappeared and this will be
+-	 *    handled by libusb_submit_transfer()
++	 * 2. the transfer has been added to the flying transfer list by
++	 *    libusb_submit_transfer, has failed to submit and
++	 *    libusb_submit_transfer is waiting for us to release the
++	 *    flying_transfers_lock to remove it, so we ignore it
+ 	 */
+ 
+ 	while (1) {
+@@ -2761,12 +2771,10 @@ void usbi_handle_disconnect(struct libusb_device_handle *handle)
+ 		usbi_mutex_lock(&HANDLE_CTX(handle)->flying_transfers_lock);
+ 		list_for_each_entry(cur, &HANDLE_CTX(handle)->flying_transfers, list, struct usbi_transfer)
+ 			if (USBI_TRANSFER_TO_LIBUSB_TRANSFER(cur)->dev_handle == handle) {
+-				usbi_mutex_lock(&cur->flags_lock);
+-				if (cur->flags & USBI_TRANSFER_IN_FLIGHT)
++				usbi_mutex_lock(&cur->lock);
++				if (cur->state_flags & USBI_TRANSFER_IN_FLIGHT)
+ 					to_cancel = cur;
+-				else
+-					cur->flags |= USBI_TRANSFER_DEVICE_DISAPPEARED;
+-				usbi_mutex_unlock(&cur->flags_lock);
++				usbi_mutex_unlock(&cur->lock);
+ 
+ 				if (to_cancel)
+ 					break;
+diff --git a/libusb/libusbi.h b/libusb/libusbi.h
+index a39cbe1..95badd3 100644
+--- a/libusb/libusbi.h
++++ b/libusb/libusbi.h
+@@ -266,6 +266,8 @@ struct libusb_context {
+ 	 * the list, URBs that will time out later are placed after, and urbs with
+ 	 * infinite timeout are always placed at the very end. */
+ 	struct list_head flying_transfers;
++	/* Note paths taking both this and usbi_transfer->lock must always
++	 * take this lock first */
+ 	usbi_mutex_t flying_transfers_lock;
+ 
+ 	/* user callbacks for pollfd changes */
+@@ -407,7 +409,8 @@ struct usbi_transfer {
+ 	struct timeval timeout;
+ 	int transferred;
+ 	uint32_t stream_id;
+-	uint8_t flags;
++	uint8_t state_flags;   /* Protected by usbi_transfer->lock */
++	uint8_t timeout_flags; /* Protected by the flying_stransfers_lock */
+ 
+ 	/* this lock is held during libusb_submit_transfer() and
+ 	 * libusb_cancel_transfer() (allowing the OS backend to prevent duplicate
+@@ -415,38 +418,32 @@ struct usbi_transfer {
+ 	 * should also take this lock in the handle_events path, to prevent the user
+ 	 * cancelling the transfer from another thread while you are processing
+ 	 * its completion (presumably there would be races within your OS backend
+-	 * if this were possible). */
++	 * if this were possible).
++	 * Note paths taking both this and the flying_transfers_lock must
++	 * always take the flying_transfers_lock first */
+ 	usbi_mutex_t lock;
+-
+-	/* this lock should be held whenever viewing or modifying flags
+-	 * relating to the transfer state */
+-	usbi_mutex_t flags_lock;
+ };
+ 
+-enum usbi_transfer_flags {
+-	/* The transfer has timed out */
+-	USBI_TRANSFER_TIMED_OUT = 1 << 0,
+-
+-	/* Set by backend submit_transfer() if the OS handles timeout */
+-	USBI_TRANSFER_OS_HANDLES_TIMEOUT = 1 << 1,
++enum usbi_transfer_state_flags {
++	/* Transfer successfully submitted by backend */
++	USBI_TRANSFER_IN_FLIGHT = 1 << 0,
+ 
+ 	/* Cancellation was requested via libusb_cancel_transfer() */
+-	USBI_TRANSFER_CANCELLING = 1 << 2,
++	USBI_TRANSFER_CANCELLING = 1 << 1,
+ 
+ 	/* Operation on the transfer failed because the device disappeared */
+-	USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 3,
+-
+-	/* Transfer is currently being submitted */
+-	USBI_TRANSFER_SUBMITTING = 1 << 4,
+-
+-	/* Transfer successfully submitted by backend */
+-	USBI_TRANSFER_IN_FLIGHT = 1 << 5,
++	USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 2,
++};
+ 
+-	/* Completion handler has run */
+-	USBI_TRANSFER_COMPLETED = 1 << 6,
++enum usbi_transfer_timeout_flags {
++	/* Set by backend submit_transfer() if the OS handles timeout */
++	USBI_TRANSFER_OS_HANDLES_TIMEOUT = 1 << 0,
+ 
+ 	/* The transfer timeout has been handled */
+-	USBI_TRANSFER_TIMEOUT_HANDLED = 1 << 7,
++	USBI_TRANSFER_TIMEOUT_HANDLED = 1 << 1,
++
++	/* The transfer timeout was successfully processed */
++	USBI_TRANSFER_TIMED_OUT = 1 << 2,
+ };
+ 
+ #define USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer) \
+diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
+index 6794509..736bcc1 100644
+--- a/libusb/os/darwin_usb.c
++++ b/libusb/os/darwin_usb.c
+@@ -1471,7 +1471,7 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer) {
+       ret = (*(cInterface->interface))->WritePipeAsync(cInterface->interface, pipeRef, transfer->buffer,
+                                                        transfer->length, darwin_async_io_callback, itransfer);
+   } else {
+-    itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
++    itransfer->timeout_flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
+ 
+     if (IS_XFERIN(transfer))
+       ret = (*(cInterface->interface))->ReadPipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer,
+@@ -1503,7 +1503,7 @@ static int submit_stream_transfer(struct usbi_transfer *itransfer) {
+     return LIBUSB_ERROR_NOT_FOUND;
+   }
+ 
+-  itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
++  itransfer->timeout_flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
+ 
+   if (IS_XFERIN(transfer))
+     ret = (*(cInterface->interface))->ReadStreamsPipeAsyncTO(cInterface->interface, pipeRef, itransfer->stream_id,
+@@ -1631,7 +1631,7 @@ static int submit_control_transfer(struct usbi_transfer *itransfer) {
+   tpriv->req.completionTimeout = transfer->timeout;
+   tpriv->req.noDataTimeout     = transfer->timeout;
+ 
+-  itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
++  itransfer->timeout_flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
+ 
+   /* all transfers in libusb-1.0 are async */
+ 
+@@ -1780,7 +1780,7 @@ static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0)
+ }
+ 
+ static int darwin_transfer_status (struct usbi_transfer *itransfer, kern_return_t result) {
+-  if (itransfer->flags & USBI_TRANSFER_TIMED_OUT)
++  if (itransfer->timeout_flags & USBI_TRANSFER_TIMED_OUT)
+     result = kIOUSBTransactionTimeout;
+ 
+   switch (result) {
+@@ -1797,7 +1797,7 @@ static int darwin_transfer_status (struct usbi_transfer *itransfer, kern_return_
+     return LIBUSB_TRANSFER_OVERFLOW;
+   case kIOUSBTransactionTimeout:
+     usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: timed out");
+-    itransfer->flags |= USBI_TRANSFER_TIMED_OUT;
++    itransfer->timeout_flags |= USBI_TRANSFER_TIMED_OUT;
+     return LIBUSB_TRANSFER_TIMED_OUT;
+   default:
+     usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: %s (value = 0x%08x)", darwin_error_str (result), result);
+diff --git a/libusb/version_nano.h b/libusb/version_nano.h
+index ea79210..3adf53e 100644
+--- a/libusb/version_nano.h
++++ b/libusb/version_nano.h
+@@ -1 +1 @@
+-#define LIBUSB_NANO 11006
++#define LIBUSB_NANO 11007
+-- 
+2.7.4
+
diff --git a/SPECS/libusbx.spec b/SPECS/libusbx.spec
index a4732bd..660a5e9 100644
--- a/SPECS/libusbx.spec
+++ b/SPECS/libusbx.spec
@@ -1,13 +1,16 @@
 Summary:        Library for accessing USB devices
 Name:           libusbx
-Version:        1.0.15
-Release:        4%{?dist}
-Source0:        http://downloads.sourceforge.net/libusbx/libusbx-%{version}.tar.bz2
-Patch1:         0001-linux_usbfs-Work-around-a-driver-binding-race-in-res.patch
+Version:        1.0.20
+Release:        1%{?dist}
+Source0:        http://downloads.sourceforge.net/libusb/libusb-%{version}.tar.bz2
+# A couple of fixes from upstream
+Patch1:         0001-core-Store-different-event-types-as-a-bitmask-within.patch
+Patch2:         0002-API-Add-libusb_interrupt_event_handler-function.patch
+Patch3:         0003-core-Refactor-code-related-to-transfer-flags-and-tim.patch
 License:        LGPLv2+
 Group:          System Environment/Libraries
-URL:            http://sourceforge.net/apps/mediawiki/libusbx/
-BuildRequires:  doxygen
+URL:            http://libusb.info/
+BuildRequires:  systemd-devel doxygen
 Provides:       libusb1 = %{version}-%{release}
 Obsoletes:      libusb1 <= 1.0.9
 
@@ -47,13 +50,16 @@ This package contains API documentation for %{name}.
 
 
 %prep
-%setup -q
+%setup -q -n libusb-%{version}
 %patch1 -p1
+%patch2 -p1
+%patch3 -p1
 
 
 %build
 %configure --disable-static --enable-examples-build
-make %{?_smp_mflags}
+# Parallel builds seem to be broken
+make
 pushd doc
 make docs
 popd
@@ -82,6 +88,11 @@ rm $RPM_BUILD_ROOT%{_libdir}/*.la
 
 
 %changelog
+* Wed Jun  8 2016 Hans de Goede <hdegoede@redhat.com> - 1.0.20-1
+- Upgrade to 1.0.20
+- Resolves: rhbz#1033092
+- Resolves: rhbz#1115797
+
 * Fri Jan 24 2014 Daniel Mach <dmach@redhat.com> - 1.0.15-4
 - Mass rebuild 2014-01-24