| From 6729c3a54db0023ac2afd89df91e02eb06a87a26 Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Vianney=20le=20Cl=C3=A9ment=20de=20Saint-Marcq?= |
| <code@quartic.eu> |
| Date: Tue, 13 Dec 2016 15:59:23 +0100 |
| Subject: [PATCH 05/11] UPSTREAM: linux_usbfs: Implement |
| libusb_wrap_sys_device() |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| Add support for the libusb_wrap_sys_device() API on Linux. Because |
| sysfs_dir is set to NULL, only the provided file descriptor will be |
| used. This is needed on some platforms (e.g., Android) where sysfs |
| might not be available. |
| |
| Signed-off-by: Vianney le Clément de Saint-Marcq <code@quartic.eu> |
| Signed-off-by: Nathan Hjelm <hjelmn@me.com> |
| (cherry picked from commit 7e8edaf9cb790b0129258d2224d1b7072889f401) |
| Signed-off-by: Dmitry Torokhov <dtor@chromium.org> |
| --- |
| libusb/os/linux_usbfs.c | 89 ++++++++++++++++++++++++++++++++++++----- |
| 1 file changed, 78 insertions(+), 11 deletions(-) |
| |
| diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c |
| index addde88..2e7add4 100644 |
| --- a/libusb/os/linux_usbfs.c |
| +++ b/libusb/os/linux_usbfs.c |
| @@ -165,6 +165,7 @@ struct linux_device_priv { |
| struct linux_device_handle_priv { |
| int fd; |
| int fd_removed; |
| + int fd_keep; |
| uint32_t caps; |
| }; |
| |
| @@ -958,7 +959,7 @@ static int usbfs_get_active_config(struct libusb_device *dev, int fd) |
| } |
| |
| static int initialize_device(struct libusb_device *dev, uint8_t busnum, |
| - uint8_t devaddr, const char *sysfs_dir) |
| + uint8_t devaddr, const char *sysfs_dir, int wrapped_fd) |
| { |
| struct linux_device_priv *priv = _device_priv(dev); |
| struct libusb_context *ctx = DEVICE_CTX(dev); |
| @@ -991,10 +992,18 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, |
| } |
| |
| /* cache descriptors in memory */ |
| - if (sysfs_dir && sysfs_has_descriptors) |
| + if (sysfs_dir && sysfs_has_descriptors) { |
| fd = _open_sysfs_attr(dev, "descriptors"); |
| - else |
| + } else if (wrapped_fd < 0) { |
| fd = _get_usbfs_fd(dev, O_RDONLY, 0); |
| + } else { |
| + fd = wrapped_fd; |
| + r = lseek(fd, 0, SEEK_SET); |
| + if (r < 0) { |
| + usbi_err(ctx, "seek failed ret=%d errno=%d", r, errno); |
| + return LIBUSB_ERROR_IO; |
| + } |
| + } |
| if (fd < 0) |
| return fd; |
| |
| @@ -1003,7 +1012,8 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, |
| priv->descriptors = usbi_reallocf(priv->descriptors, |
| descriptors_size); |
| if (!priv->descriptors) { |
| - close(fd); |
| + if (fd != wrapped_fd) |
| + close(fd); |
| return LIBUSB_ERROR_NO_MEM; |
| } |
| /* usbfs has holes in the file */ |
| @@ -1016,13 +1026,15 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, |
| if (r < 0) { |
| usbi_err(ctx, "read descriptor failed ret=%d errno=%d", |
| fd, errno); |
| - close(fd); |
| + if (fd != wrapped_fd) |
| + close(fd); |
| return LIBUSB_ERROR_IO; |
| } |
| priv->descriptors_len += r; |
| } while (priv->descriptors_len == descriptors_size); |
| |
| - close(fd); |
| + if (fd != wrapped_fd) |
| + close(fd); |
| |
| if (priv->descriptors_len < DEVICE_DESC_LENGTH) { |
| usbi_err(ctx, "short descriptor read (%d)", |
| @@ -1034,7 +1046,10 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, |
| return LIBUSB_SUCCESS; |
| |
| /* cache active config */ |
| - fd = _get_usbfs_fd(dev, O_RDWR, 1); |
| + if (wrapped_fd < 0) |
| + fd = _get_usbfs_fd(dev, O_RDWR, 1); |
| + else |
| + fd = wrapped_fd; |
| if (fd < 0) { |
| /* cannot send a control message to determine the active |
| * config. just assume the first one is active. */ |
| @@ -1054,7 +1069,8 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, |
| } |
| |
| r = usbfs_get_active_config(dev, fd); |
| - close(fd); |
| + if (wrapped_fd < 0) |
| + close(fd); |
| |
| return r; |
| } |
| @@ -1155,7 +1171,7 @@ int linux_enumerate_device(struct libusb_context *ctx, |
| if (!dev) |
| return LIBUSB_ERROR_NO_MEM; |
| |
| - r = initialize_device(dev, busnum, devaddr, sysfs_dir); |
| + r = initialize_device(dev, busnum, devaddr, sysfs_dir, -1); |
| if (r < 0) |
| goto out; |
| r = usbi_sanitize_device(dev); |
| @@ -1386,9 +1402,58 @@ static int initialize_handle(struct libusb_device_handle *handle, int fd) |
| return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT); |
| } |
| |
| -static int op_open(struct libusb_device_handle *handle) |
| +static int op_wrap_sys_device(struct libusb_context *ctx, |
| + struct libusb_device_handle *handle, intptr_t sys_dev) |
| { |
| struct linux_device_handle_priv *hpriv = _device_handle_priv(handle); |
| + int fd = (int)sys_dev; |
| + uint8_t busnum, devaddr; |
| + struct usbfs_connectinfo ci; |
| + struct libusb_device *dev; |
| + int r; |
| + |
| + r = linux_get_device_address(ctx, 1, &busnum, &devaddr, NULL, NULL, fd); |
| + if (r < 0) { |
| + r = ioctl(fd, IOCTL_USBFS_CONNECTINFO, &ci); |
| + if (r < 0) { |
| + usbi_err(ctx, "connectinfo failed (%d)", errno); |
| + return LIBUSB_ERROR_IO; |
| + } |
| + /* There is no ioctl to get the bus number. We choose 0 here |
| + * as linux starts numbering buses from 1. */ |
| + busnum = 0; |
| + devaddr = ci.devnum; |
| + } |
| + |
| + /* Session id is unused as we do not add the device to the list of |
| + * connected devices. */ |
| + usbi_dbg("allocating new device for fd %d", fd); |
| + dev = usbi_alloc_device(ctx, 0); |
| + if (!dev) |
| + return LIBUSB_ERROR_NO_MEM; |
| + |
| + r = initialize_device(dev, busnum, devaddr, NULL, fd); |
| + if (r < 0) |
| + goto out; |
| + r = usbi_sanitize_device(dev); |
| + if (r < 0) |
| + goto out; |
| + /* Consider the device as connected, but do not add it to the managed |
| + * device list. */ |
| + dev->attached = 1; |
| + handle->dev = dev; |
| + |
| + r = initialize_handle(handle, fd); |
| + hpriv->fd_keep = 1; |
| + |
| +out: |
| + if (r < 0) |
| + libusb_unref_device(dev); |
| + return r; |
| +} |
| + |
| +static int op_open(struct libusb_device_handle *handle) |
| +{ |
| int fd, r; |
| |
| fd = _get_usbfs_fd(handle->dev, O_RDWR, 0); |
| @@ -1420,7 +1485,8 @@ static void op_close(struct libusb_device_handle *dev_handle) |
| /* fd may have already been removed by POLLERR condition in op_handle_events() */ |
| if (!hpriv->fd_removed) |
| usbi_remove_pollfd(HANDLE_CTX(dev_handle), hpriv->fd); |
| - close(hpriv->fd); |
| + if (!hpriv->fd_keep) |
| + close(hpriv->fd); |
| } |
| |
| static int op_get_configuration(struct libusb_device_handle *handle, |
| @@ -2782,6 +2848,7 @@ const struct usbi_os_backend usbi_backend = { |
| .get_config_descriptor = op_get_config_descriptor, |
| .get_config_descriptor_by_value = op_get_config_descriptor_by_value, |
| |
| + .wrap_sys_device = op_wrap_sys_device, |
| .open = op_open, |
| .close = op_close, |
| .get_configuration = op_get_configuration, |
| -- |
| 2.22.0.rc2.383.gf4fbbf30c2-goog |
| |