blob: dc23bcff74d1ff3ebc574035f3942c1c68de3069 [file] [log] [blame]
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