1diff --git a/third_party/libusb/src/libusb/core.c b/third_party/libusb/src/libusb/core.c 2index e816284..abc4f89 100644 3--- a/third_party/libusb/src/libusb/core.c 4+++ b/third_party/libusb/src/libusb/core.c 5@@ -1129,6 +1129,83 @@ int API_EXPORTED libusb_open(libusb_device *dev, 6 } 7 8 /** \ingroup dev 9+ * Open a device and obtain a device handle. A handle allows you to perform 10+ * I/O on the device in question. 11+ * 12+ * Instead of opening the device itself this function accepts an open file 13+ * descriptor that it will take ownership of. 14+ * 15+ * Internally, this function adds a reference to the device and makes it 16+ * available to you through libusb_get_device(). This reference is removed 17+ * during libusb_close(). 18+ * 19+ * This is a non-blocking function; no requests are sent over the bus. 20+ * 21+ * \param dev the device to open 22+ * \param fd open file handle to the device 23+ * \param handle output location for the returned device handle pointer. Only 24+ * populated when the return code is 0. 25+ * \returns 0 on success 26+ * \returns LIBUSB_ERROR_NO_MEM on memory allocation failure 27+ * \returns LIBUSB_ERROR_ACCESS if the user has insufficient permissions 28+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected 29+ * \returns another LIBUSB_ERROR code on other failure 30+ */ 31+int API_EXPORTED libusb_open_fd(libusb_device *dev, 32+ int fd, 33+ libusb_device_handle **handle) 34+{ 35+ struct libusb_context *ctx = DEVICE_CTX(dev); 36+ struct libusb_device_handle *_handle; 37+ size_t priv_size = usbi_backend->device_handle_priv_size; 38+ int r; 39+ usbi_dbg("open %d.%d", dev->bus_number, dev->device_address); 40+ 41+ if (!dev->attached) { 42+ return LIBUSB_ERROR_NO_DEVICE; 43+ } 44+ 45+ _handle = malloc(sizeof(*_handle) + priv_size); 46+ if (!_handle) 47+ return LIBUSB_ERROR_NO_MEM; 48+ 49+ r = usbi_mutex_init(&_handle->lock, NULL); 50+ if (r) { 51+ free(_handle); 52+ return LIBUSB_ERROR_OTHER; 53+ } 54+ 55+ _handle->dev = libusb_ref_device(dev); 56+ _handle->auto_detach_kernel_driver = 0; 57+ _handle->claimed_interfaces = 0; 58+ memset(&_handle->os_priv, 0, priv_size); 59+ 60+ r = usbi_backend->open_fd(_handle, fd); 61+ if (r < 0) { 62+ usbi_dbg("open %d.%d returns %d", dev->bus_number, dev->device_address, r); 63+ libusb_unref_device(dev); 64+ usbi_mutex_destroy(&_handle->lock); 65+ free(_handle); 66+ return r; 67+ } 68+ 69+ usbi_mutex_lock(&ctx->open_devs_lock); 70+ list_add(&_handle->list, &ctx->open_devs); 71+ usbi_mutex_unlock(&ctx->open_devs_lock); 72+ *handle = _handle; 73+ 74+ /* At this point, we want to interrupt any existing event handlers so 75+ * that they realise the addition of the new device's poll fd. One 76+ * example when this is desirable is if the user is running a separate 77+ * dedicated libusbx events handling thread, which is running with a long 78+ * or infinite timeout. We want to interrupt that iteration of the loop, 79+ * so that it picks up the new fd, and then continues. */ 80+ usbi_fd_notification(ctx); 81+ 82+ return 0; 83+} 84+ 85+/** \ingroup dev 86 * Convenience function for finding a device with a particular 87 * <tt>idVendor</tt>/<tt>idProduct</tt> combination. This function is intended 88 * for those scenarios where you are using libusbx to knock up a quick test 89diff --git a/third_party/libusb/src/libusb/libusb.h b/third_party/libusb/src/libusb/libusb.h 90index d144b3e..5d60951 100644 91--- a/third_party/libusb/src/libusb/libusb.h 92+++ b/third_party/libusb/src/libusb/libusb.h 93@@ -1371,6 +1371,8 @@ int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev, 94 unsigned char endpoint); 95 96 int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **handle); 97+int LIBUSB_CALL libusb_open_fd(libusb_device *dev, int fd, 98+ libusb_device_handle **handle); 99 void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle); 100 libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle); 101 102diff --git a/third_party/libusb/src/libusb/libusbi.h b/third_party/libusb/src/libusb/libusbi.h 103index bc608b92..eb2f0e6 100644 104--- a/third_party/libusb/src/libusb/libusbi.h 105+++ b/third_party/libusb/src/libusb/libusbi.h 106@@ -615,6 +615,11 @@ struct usbi_os_backend { 107 */ 108 int (*open)(struct libusb_device_handle *handle); 109 110+ /* Like open() above but uses the file descriptor provided instead of opening 111+ * one on its own. 112+ */ 113+ int (*open_fd)(struct libusb_device_handle *handle, int fd); 114+ 115 /* Close a device such that the handle cannot be used again. Your backend 116 * should destroy any resources that were allocated in the open path. 117 * This may also be a good place to call usbi_remove_pollfd() to inform 118diff --git a/third_party/libusb/src/libusb/os/darwin_usb.c b/third_party/libusb/src/libusb/os/darwin_usb.c 119index f95706a..f6b397e 100644 120--- a/third_party/libusb/src/libusb/os/darwin_usb.c 121+++ b/third_party/libusb/src/libusb/os/darwin_usb.c 122@@ -1877,6 +1877,7 @@ const struct usbi_os_backend darwin_backend = { 123 .get_config_descriptor = darwin_get_config_descriptor, 124 125 .open = darwin_open, 126+ .open_fd = NULL, /* not implemented */ 127 .close = darwin_close, 128 .get_configuration = darwin_get_configuration, 129 .set_configuration = darwin_set_configuration, 130diff --git a/third_party/libusb/src/libusb/os/linux_usbfs.c b/third_party/libusb/src/libusb/os/linux_usbfs.c 131index 142fa2b..e965856 100644 132--- a/third_party/libusb/src/libusb/os/linux_usbfs.c 133+++ b/third_party/libusb/src/libusb/os/linux_usbfs.c 134@@ -1259,26 +1259,12 @@ static int linux_default_scan_devices (struct libusb_context *ctx) 135 } 136 #endif 137 138-static int op_open(struct libusb_device_handle *handle) 139+static int op_open_fd(struct libusb_device_handle *handle, int fd) 140 { 141 struct linux_device_handle_priv *hpriv = _device_handle_priv(handle); 142 int r; 143 144- hpriv->fd = _get_usbfs_fd(handle->dev, O_RDWR, 0); 145- if (hpriv->fd < 0) { 146- if (hpriv->fd == LIBUSB_ERROR_NO_DEVICE) { 147- /* device will still be marked as attached if hotplug monitor thread 148- * hasn't processed remove event yet */ 149- usbi_mutex_static_lock(&linux_hotplug_lock); 150- if (handle->dev->attached) { 151- usbi_dbg("open failed with no device, but device still attached"); 152- linux_device_disconnected(handle->dev->bus_number, 153- handle->dev->device_address, NULL); 154- } 155- usbi_mutex_static_unlock(&linux_hotplug_lock); 156- } 157- return hpriv->fd; 158- } 159+ hpriv->fd = fd; 160 161 r = ioctl(hpriv->fd, IOCTL_USBFS_GET_CAPABILITIES, &hpriv->caps); 162 if (r < 0) { 163@@ -1296,6 +1282,29 @@ static int op_open(struct libusb_device_handle *handle) 164 return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT); 165 } 166 167+static int op_open(struct libusb_device_handle *handle) 168+{ 169+ struct linux_device_handle_priv *hpriv = _device_handle_priv(handle); 170+ int fd = _get_usbfs_fd(handle->dev, O_RDWR, 0); 171+ 172+ if (fd < 0) { 173+ if (fd == LIBUSB_ERROR_NO_DEVICE) { 174+ /* device will still be marked as attached if hotplug monitor thread 175+ * hasn't processed remove event yet */ 176+ usbi_mutex_static_lock(&linux_hotplug_lock); 177+ if (handle->dev->attached) { 178+ usbi_dbg("open failed with no device, but device still attached"); 179+ linux_device_disconnected(handle->dev->bus_number, 180+ handle->dev->device_address, NULL); 181+ } 182+ usbi_mutex_static_unlock(&linux_hotplug_lock); 183+ } 184+ return fd; 185+ } 186+ 187+ return op_open_fd(handle, fd); 188+} 189+ 190 static void op_close(struct libusb_device_handle *dev_handle) 191 { 192 int fd = _device_handle_priv(dev_handle)->fd; 193@@ -2570,6 +2579,7 @@ const struct usbi_os_backend linux_usbfs_backend = { 194 .get_config_descriptor_by_value = op_get_config_descriptor_by_value, 195 196 .open = op_open, 197+ .open_fd = op_open_fd, 198 .close = op_close, 199 .get_configuration = op_get_configuration, 200 .set_configuration = op_set_configuration, 201diff --git a/third_party/libusb/src/libusb/os/openbsd_usb.c b/third_party/libusb/src/libusb/os/openbsd_usb.c 202index 2997e53..2d24f2c 100644 203--- a/third_party/libusb/src/libusb/os/openbsd_usb.c 204+++ b/third_party/libusb/src/libusb/os/openbsd_usb.c 205@@ -98,6 +98,7 @@ const struct usbi_os_backend openbsd_backend = { 206 obsd_get_device_list, 207 NULL, /* hotplug_poll */ 208 obsd_open, 209+ NULL, /* open_fd */ 210 obsd_close, 211 212 obsd_get_device_descriptor, 213diff --git a/third_party/libusb/src/libusb/os/wince_usb.c b/third_party/libusb/src/libusb/os/wince_usb.c 214index 90c129b..c069c56 100644 215--- a/third_party/libusb/src/libusb/os/wince_usb.c 216+++ b/third_party/libusb/src/libusb/os/wince_usb.c 217@@ -990,6 +990,7 @@ const struct usbi_os_backend wince_backend = { 218 wince_get_device_list, 219 NULL, /* hotplug_poll */ 220 wince_open, 221+ NULL, /* open_fd */ 222 wince_close, 223 224 wince_get_device_descriptor, 225diff --git a/third_party/libusb/src/libusb/os/windows_usb.c b/third_party/libusb/src/libusb/os/windows_usb.c 226index 4469992..bc4def6 100644 227--- a/third_party/libusb/src/libusb/os/windows_usb.c 228+++ b/third_party/libusb/src/libusb/os/windows_usb.c 229@@ -2290,6 +2290,7 @@ const struct usbi_os_backend windows_backend = { 230 windows_get_device_list, 231 NULL, /* hotplug_poll */ 232 windows_open, 233+ NULL, /* open_fd */ 234 windows_close, 235 236 windows_get_device_descriptor, 237