| From bcda70ea60b19e0226ebd8d2368de17185eb63b2 Mon Sep 17 00:00:00 2001 |
| From: Jingkui Wang <jkwang@google.com> |
| Date: Tue, 30 Oct 2018 15:29:02 -0700 |
| Subject: [PATCH] add libusb_open_fd |
| |
| libusb_open_fd will take an external fd to construct device handle. This will |
| all sandboxing libusb. |
| |
| This patch is adapted from chromium repo: |
| src/third_party/libusb/open-fd.patch |
| --- |
| libusb/core.c | 69 +++++++++++++++++++++++++++++++++++++++++ |
| libusb/libusb.h | 2 ++ |
| libusb/libusbi.h | 5 +++ |
| libusb/os/linux_usbfs.c | 62 +++++++++++++++++++++++------------- |
| 4 files changed, 117 insertions(+), 21 deletions(-) |
| |
| diff --git a/libusb/core.c b/libusb/core.c |
| index 99aab7b..8c9b8e9 100644 |
| --- a/libusb/core.c |
| +++ b/libusb/core.c |
| @@ -1282,6 +1282,75 @@ int API_EXPORTED libusb_open(libusb_device *dev, |
| return 0; |
| } |
| |
| +/** \ingroup libusb_dev |
| +* Open a device and obtain a device handle. A handle allows you to perform |
| +* I/O on the device in question. |
| +* |
| +* Instead of opening the device itself this function accepts an open file |
| +* descriptor that it will take ownership of. |
| +* |
| +* Internally, this function adds a reference to the device and makes it |
| +* available to you through libusb_get_device(). This reference is removed |
| +* during libusb_close(). |
| +* |
| +* This is a non-blocking function; no requests are sent over the bus. |
| +* |
| +* \param dev the device to open |
| +* \param fd open file handle to the device |
| +* \param handle output location for the returned device handle pointer. Only |
| +* populated when the return code is 0. |
| +* \returns 0 on success |
| +* \returns LIBUSB_ERROR_NO_MEM on memory allocation failure |
| +* \returns LIBUSB_ERROR_ACCESS if the user has insufficient permissions |
| +* \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected |
| +* \returns another LIBUSB_ERROR code on other failure |
| +*/ |
| +int API_EXPORTED libusb_open_fd(libusb_device *dev, |
| + int fd, |
| + libusb_device_handle **handle) |
| +{ |
| + struct libusb_context *ctx = DEVICE_CTX(dev); |
| + struct libusb_device_handle *_handle; |
| + size_t priv_size = usbi_backend->device_handle_priv_size; |
| + int r; |
| + usbi_dbg("open %d.%d", dev->bus_number, dev->device_address); |
| + |
| + if (!dev->attached) { |
| + return LIBUSB_ERROR_NO_DEVICE; |
| + } |
| + |
| + _handle = malloc(sizeof(*_handle) + priv_size); |
| + if (!_handle) |
| + return LIBUSB_ERROR_NO_MEM; |
| + |
| + r = usbi_mutex_init(&_handle->lock); |
| + if (r) { |
| + free(_handle); |
| + return LIBUSB_ERROR_OTHER; |
| + } |
| + |
| + _handle->dev = libusb_ref_device(dev); |
| + _handle->auto_detach_kernel_driver = 0; |
| + _handle->claimed_interfaces = 0; |
| + memset(&_handle->os_priv, 0, priv_size); |
| + |
| + r = usbi_backend->open_fd(_handle, fd); |
| + if (r < 0) { |
| + usbi_dbg("open %d.%d returns %d", dev->bus_number, dev->device_address, r); |
| + libusb_unref_device(dev); |
| + usbi_mutex_destroy(&_handle->lock); |
| + free(_handle); |
| + return r; |
| + } |
| + |
| + usbi_mutex_lock(&ctx->open_devs_lock); |
| + list_add(&_handle->list, &ctx->open_devs); |
| + usbi_mutex_unlock(&ctx->open_devs_lock); |
| + *handle = _handle; |
| + |
| + return 0; |
| +} |
| + |
| /** \ingroup libusb_dev |
| * Convenience function for finding a device with a particular |
| * <tt>idVendor</tt>/<tt>idProduct</tt> combination. This function is intended |
| diff --git a/libusb/libusb.h b/libusb/libusb.h |
| index f73e31c..34d0784 100644 |
| --- a/libusb/libusb.h |
| +++ b/libusb/libusb.h |
| @@ -1371,6 +1371,8 @@ int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev, |
| unsigned char endpoint); |
| |
| int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **dev_handle); |
| +int LIBUSB_CALL libusb_open_fd(libusb_device *dev, int fd, |
| + libusb_device_handle **handle); |
| void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle); |
| libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle); |
| |
| diff --git a/libusb/libusbi.h b/libusb/libusbi.h |
| index cc0906c..ca5e86a 100644 |
| --- a/libusb/libusbi.h |
| +++ b/libusb/libusbi.h |
| @@ -712,6 +712,11 @@ struct usbi_os_backend { |
| */ |
| int (*open)(struct libusb_device_handle *dev_handle); |
| |
| + /* Like open() above but uses the file descriptor provided instead of opening |
| + * one on its own. |
| + */ |
| + int (*open_fd)(struct libusb_device_handle *handle, int fd); |
| + |
| /* Close a device such that the handle cannot be used again. Your backend |
| * should destroy any resources that were allocated in the open path. |
| * This may also be a good place to call usbi_remove_pollfd() to inform |
| diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c |
| index 9cbeb80..89102ef 100644 |
| --- a/libusb/os/linux_usbfs.c |
| +++ b/libusb/os/linux_usbfs.c |
| @@ -187,6 +187,11 @@ static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent) |
| int fd; |
| int delay = 10000; |
| |
| + if (!usbfs_path) { |
| + usbi_err(ctx, "could not find usbfs"); |
| + return LIBUSB_ERROR_OTHER; |
| + } |
| + |
| if (usbdev_names) |
| snprintf(path, PATH_MAX, "%s/usbdev%d.%d", |
| usbfs_path, dev->bus_number, dev->device_address); |
| @@ -379,10 +384,6 @@ static int op_init(struct libusb_context *ctx) |
| int r; |
| |
| usbfs_path = find_usbfs_path(); |
| - if (!usbfs_path) { |
| - usbi_err(ctx, "could not find usbfs"); |
| - return LIBUSB_ERROR_OTHER; |
| - } |
| |
| if (monotonic_clkid == -1) |
| monotonic_clkid = find_monotonic_clock(); |
| @@ -1138,6 +1139,11 @@ static int usbfs_scan_busdir(struct libusb_context *ctx, uint8_t busnum) |
| struct dirent *entry; |
| int r = LIBUSB_ERROR_IO; |
| |
| + if (!usbfs_path) { |
| + usbi_err(ctx, "could not find usbfs"); |
| + return LIBUSB_ERROR_OTHER; |
| + } |
| + |
| snprintf(dirpath, PATH_MAX, "%s/%03d", usbfs_path, busnum); |
| usbi_dbg("%s", dirpath); |
| dir = opendir(dirpath); |
| @@ -1175,6 +1181,12 @@ static int usbfs_scan_busdir(struct libusb_context *ctx, uint8_t busnum) |
| static int usbfs_get_device_list(struct libusb_context *ctx) |
| { |
| struct dirent *entry; |
| + |
| + if (!usbfs_path) { |
| + usbi_err(ctx, "could not find usbfs"); |
| + return LIBUSB_ERROR_OTHER; |
| + } |
| + |
| DIR *buses = opendir(usbfs_path); |
| int r = 0; |
| |
| @@ -1280,26 +1292,12 @@ static int linux_default_scan_devices (struct libusb_context *ctx) |
| } |
| #endif |
| |
| -static int op_open(struct libusb_device_handle *handle) |
| +static int op_open_fd(struct libusb_device_handle *handle, int fd) |
| { |
| struct linux_device_handle_priv *hpriv = _device_handle_priv(handle); |
| int r; |
| |
| - hpriv->fd = _get_usbfs_fd(handle->dev, O_RDWR, 0); |
| - if (hpriv->fd < 0) { |
| - if (hpriv->fd == LIBUSB_ERROR_NO_DEVICE) { |
| - /* device will still be marked as attached if hotplug monitor thread |
| - * hasn't processed remove event yet */ |
| - usbi_mutex_static_lock(&linux_hotplug_lock); |
| - if (handle->dev->attached) { |
| - usbi_dbg("open failed with no device, but device still attached"); |
| - linux_device_disconnected(handle->dev->bus_number, |
| - handle->dev->device_address); |
| - } |
| - usbi_mutex_static_unlock(&linux_hotplug_lock); |
| - } |
| - return hpriv->fd; |
| - } |
| + hpriv->fd = fd; |
| |
| r = ioctl(hpriv->fd, IOCTL_USBFS_GET_CAPABILITIES, &hpriv->caps); |
| if (r < 0) { |
| @@ -1317,10 +1315,31 @@ static int op_open(struct libusb_device_handle *handle) |
| r = usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT); |
| if (r < 0) |
| close(hpriv->fd); |
| - |
| return r; |
| } |
| |
| +static int op_open(struct libusb_device_handle *handle) |
| +{ |
| + int fd = _get_usbfs_fd(handle->dev, O_RDWR, 0); |
| + |
| + if (fd < 0) { |
| + if (fd == LIBUSB_ERROR_NO_DEVICE) { |
| + /* device will still be marked as attached if hotplug monitor thread |
| + * hasn't processed remove event yet */ |
| + usbi_mutex_static_lock(&linux_hotplug_lock); |
| + if (handle->dev->attached) { |
| + usbi_dbg("open failed with no device, but device still attached"); |
| + linux_device_disconnected(handle->dev->bus_number, |
| + handle->dev->device_address); |
| + } |
| + usbi_mutex_static_unlock(&linux_hotplug_lock); |
| + } |
| + return fd; |
| + } |
| + |
| + return op_open_fd(handle, fd); |
| +} |
| + |
| static void op_close(struct libusb_device_handle *dev_handle) |
| { |
| struct linux_device_handle_priv *hpriv = _device_handle_priv(dev_handle); |
| @@ -2696,6 +2715,7 @@ const struct usbi_os_backend linux_usbfs_backend = { |
| .get_config_descriptor_by_value = op_get_config_descriptor_by_value, |
| |
| .open = op_open, |
| + .open_fd = op_open_fd, |
| .close = op_close, |
| .get_configuration = op_get_configuration, |
| .set_configuration = op_set_configuration, |
| -- |
| 2.20.0.rc0.387.gc7a69e6b6c-goog |
| |