From: Vianney le C. de Saint-M. <co...@qu...> - 2018-12-05 21:42:42
|
This patch series adds support for recent Android devices (tested up to 8.1). On such devices, SELinux policies prevent the use of sysfs and reading /dev/bus/usb. The only way to use libusb as a regular user is to get a file descriptor through the Android Platform API and pass it on. All operations must use that file descriptor. This series adds an API function to libusb to wrap an open platform-specific device handle as a libusb_device_handle. On Linux, the only platform supported in this series, a platform-specific device handle is a file descriptor. To ease reviewing, the series is decomposed as follows: * Patches 1-3 contain light refactoring and small utility extensions needed later on. * Patch 4 adds the public API function. * Patch 5 implements the new API for the Linux platform. * Patch 6-7 ensure the libusb library is able to initialize on Android. Please note that patch 7 (disable hotplug events on Android) means that libusb cannot be used anymore standalone on a rooted Android device. Is that an issue? If so, I guess the way to go is to make it a compile-time option. Could you please keep me in CC when reviewing the patches, as I am not subscribed to the list. Thanks. Vianney le Clément de Saint-Marcq (7): linux_usbfs: Fallback to usbfs if device has no sysfs_dir linux_usbfs: Extract device handle initialization from op_open() linux_usbfs: Get device address from file descriptor core: Add libusb_wrap_sys_device() API linux_usbfs: Implement libusb_wrap_sys_device() linux_usbfs: Use fallback usbfs path on Android linux_usbfs: Disable hotplug events and scanning on Android libusb/core.c | 72 +++++++++++++++ libusb/libusb.h | 1 + libusb/libusbi.h | 28 ++++++ libusb/os/linux_udev.c | 2 +- libusb/os/linux_usbfs.c | 196 ++++++++++++++++++++++++++++++---------- libusb/os/linux_usbfs.h | 2 +- 6 files changed, 249 insertions(+), 52 deletions(-) -- 2.19.2 |
From: Vianney le C. de Saint-M. <co...@qu...> - 2018-12-05 21:41:58
|
Introduce a new API function for wrapping an existing platform-specific device handle as a libusb_device_handle. Signed-off-by: Vianney le Clément de Saint-Marcq <co...@qu...> --- libusb/core.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++ libusb/libusb.h | 1 + libusb/libusbi.h | 28 +++++++++++++++++++ 3 files changed, 101 insertions(+) diff --git a/libusb/core.c b/libusb/core.c index 8cb598d7..f839b6a3 100644 --- a/libusb/core.c +++ b/libusb/core.c @@ -1215,6 +1215,78 @@ int usbi_clear_event(struct libusb_context *ctx) return 0; } +/** \ingroup libusb_dev + * Wrap a platform-specific system device handle and obtain a libusb device + * handle for the underlying device. The handle allows you to use libusb to + * perform I/O on the device in question. + * + * On Linux, the system device handle must be a valid file descriptor opened + * on the device node. + * + * The system device handle must remain open until libusb_close() is called. + * The system device handle will not be closed by libusb_close(). + * + * Internally, this function creates a temporary device and makes it + * available to you through libusb_get_device(). This device is destroyed + * during libusb_close(). The device shall not be opened through libusb_open(). + * + * This is a non-blocking function; no requests are sent over the bus. + * + * \param ctx the context to operate on, or NULL for the default context + * \param sys_dev the platform-specific system device handle + * \param dev_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_NOT_SUPPORTED if the operation is not supported on this + * platform + * \returns another LIBUSB_ERROR code on other failure + */ +int API_EXPORTED libusb_wrap_sys_device(libusb_context *ctx, intptr_t sys_dev, + libusb_device_handle **dev_handle) +{ + struct libusb_device_handle *_dev_handle; + size_t priv_size = usbi_backend.device_handle_priv_size; + int r; + usbi_dbg("wrap_sys_device %p", sys_dev); + + USBI_GET_CONTEXT(ctx); + + if (!usbi_backend.wrap_sys_device) + return LIBUSB_ERROR_NOT_SUPPORTED; + + _dev_handle = malloc(sizeof(*_dev_handle) + priv_size); + if (!_dev_handle) + return LIBUSB_ERROR_NO_MEM; + + r = usbi_mutex_init(&_dev_handle->lock); + if (r) { + free(_dev_handle); + return LIBUSB_ERROR_OTHER; + } + + _dev_handle->dev = NULL; + _dev_handle->auto_detach_kernel_driver = 0; + _dev_handle->claimed_interfaces = 0; + memset(&_dev_handle->os_priv, 0, priv_size); + + r = usbi_backend.wrap_sys_device(ctx, _dev_handle, sys_dev); + if (r < 0) { + usbi_dbg("wrap_sys_device %p returns %d", sys_dev, r); + usbi_mutex_destroy(&_dev_handle->lock); + free(_dev_handle); + return r; + } + + usbi_mutex_lock(&ctx->open_devs_lock); + list_add(&_dev_handle->list, &ctx->open_devs); + usbi_mutex_unlock(&ctx->open_devs_lock); + *dev_handle = _dev_handle; + + 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. diff --git a/libusb/libusb.h b/libusb/libusb.h index a81209a4..12298273 100644 --- a/libusb/libusb.h +++ b/libusb/libusb.h @@ -1387,6 +1387,7 @@ int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev, int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev, unsigned char endpoint); +int LIBUSB_CALL libusb_wrap_sys_device(libusb_context *ctx, intptr_t sys_dev, libusb_device_handle **dev_handle); int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **dev_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 da54ff18..60182e96 100644 --- a/libusb/libusbi.h +++ b/libusb/libusbi.h @@ -702,6 +702,34 @@ struct usbi_os_backend { */ void (*hotplug_poll)(void); + /* Wrap a platform-specific device handle for I/O and other USB + * operations. The device handle is preallocated for you. + * + * Your backend should allocate any internal resources required for I/O + * and other operations so that those operations can happen (hopefully) + * without hiccup. This is also a good place to inform libusb that it + * should monitor certain file descriptors related to this device - + * see the usbi_add_pollfd() function. + * + * Your backend should also initialize the device structure + * (dev_handle->dev), which is NULL at the beginning of the call. + * + * This function should not generate any bus I/O and should not block. + * + * This function is called when the user attempts to wrap an existing + * platform-specific device handle for a device. + * + * Return: + * - 0 on success + * - LIBUSB_ERROR_ACCESS if the user has insufficient permissions + * - another LIBUSB_ERROR code on other failure + * + * Do not worry about freeing the handle on failed open, the upper layers + * do this for you. + */ + int (*wrap_sys_device)(struct libusb_context *ctx, + struct libusb_device_handle *dev_handle, intptr_t sys_dev); + /* Open a device for I/O and other USB operations. The device handle * is preallocated for you, you can retrieve the device in question * through handle->dev. -- 2.19.2 |
From: Vianney le C. de Saint-M. <co...@qu...> - 2018-12-05 21:42:10
|
On Android, the platform API should be used to scan for and open devices and pass file descriptors to libusb. Newer devices (Android 5+) even prohibit listening for hotplug events, resulting in libusb failing to initialize without this patch. Note that this patch effectively renders libusb useless on older devices that do not have USB support in the platform API (anything before Android 5). Signed-off-by: Vianney le Clément de Saint-Marcq <co...@qu...> --- libusb/os/linux_usbfs.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c index 1689c4ec..a6b7963f 100644 --- a/libusb/os/linux_usbfs.c +++ b/libusb/os/linux_usbfs.c @@ -534,8 +534,10 @@ static int linux_start_event_monitor(void) { #if defined(USE_UDEV) return linux_udev_start_event_monitor(); -#else +#elif !defined(__ANDROID__) return linux_netlink_start_event_monitor(); +#else + return LIBUSB_SUCCESS; #endif } @@ -543,20 +545,22 @@ static int linux_stop_event_monitor(void) { #if defined(USE_UDEV) return linux_udev_stop_event_monitor(); -#else +#elif !defined(__ANDROID__) return linux_netlink_stop_event_monitor(); +#else + return LIBUSB_SUCCESS; #endif } static int linux_scan_devices(struct libusb_context *ctx) { - int ret; + int ret = 0; usbi_mutex_static_lock(&linux_hotplug_lock); #if defined(USE_UDEV) ret = linux_udev_scan_devices(ctx); -#else +#elif !defined(__ANDROID__) ret = linux_default_scan_devices(ctx); #endif @@ -569,7 +573,7 @@ static void op_hotplug_poll(void) { #if defined(USE_UDEV) linux_udev_hotplug_poll(); -#else +#elif !defined(__ANDROID__) linux_netlink_hotplug_poll(); #endif } -- 2.19.2 |
From: Vianney le C. de Saint-M. <co...@qu...> - 2018-12-05 21:42:18
|
On newer Android devices (5+), SELinux policies block normal processes from reading /dev. The consequence is that the usbfs path cannot be found. Rather than failing to initialize libusb in such case, fall back to /dev/bus/usb. This path will actually not be used, as USB devices should be opened through the Android API, passing the file descriptor to libusb_wrap_sys_device. Signed-off-by: Vianney le Clément de Saint-Marcq <co...@qu...> --- libusb/os/linux_usbfs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c index 2e7add45..1689c4ec 100644 --- a/libusb/os/linux_usbfs.c +++ b/libusb/os/linux_usbfs.c @@ -341,8 +341,10 @@ static const char *find_usbfs_path(void) /* On udev based systems without any usb-devices /dev/bus/usb will not * exist. So if we've not found anything and we're using udev for hotplug - * simply assume /dev/bus/usb rather then making libusb_init fail. */ -#if defined(USE_UDEV) + * simply assume /dev/bus/usb rather then making libusb_init fail. + * Make the same assumption for Android where SELinux policies might block us + * from reading /dev on newer devices. */ +#if defined(USE_UDEV) || defined(__ANDROID__) if (ret == NULL) ret = "/dev/bus/usb"; #endif -- 2.19.2 |
From: Vianney le C. de Saint-M. <co...@qu...> - 2018-12-05 21:42:26
|
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 <co...@qu...> --- 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 addde884..2e7add45 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.19.2 |
From: Vianney le C. de Saint-M. <co...@qu...> - 2018-12-05 21:42:37
|
Slightly refactor op_open() to extract the device handle initialization code into a new initialize_handle() function, similar to the initialize_device() function. Signed-off-by: Vianney le Clément de Saint-Marcq <co...@qu...> --- libusb/os/linux_usbfs.c | 48 +++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c index 7bda951e..dfbb6c4b 100644 --- a/libusb/os/linux_usbfs.c +++ b/libusb/os/linux_usbfs.c @@ -1352,28 +1352,14 @@ static int linux_default_scan_devices (struct libusb_context *ctx) } #endif -static int op_open(struct libusb_device_handle *handle) +static int initialize_handle(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); + r = ioctl(fd, IOCTL_USBFS_GET_CAPABILITIES, &hpriv->caps); if (r < 0) { if (errno == ENOTTY) usbi_dbg("getcap not available"); @@ -1386,9 +1372,33 @@ static int op_open(struct libusb_device_handle *handle) hpriv->caps |= USBFS_CAP_BULK_CONTINUATION; } - r = usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT); + return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT); +} + +static int op_open(struct libusb_device_handle *handle) +{ + struct linux_device_handle_priv *hpriv = _device_handle_priv(handle); + int fd, r; + + 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; + } + + r = initialize_handle(handle, fd); if (r < 0) - close(hpriv->fd); + close(fd); return r; } -- 2.19.2 |
From: Vianney le C. de Saint-M. <co...@qu...> - 2018-12-05 21:42:55
|
Extend linux_get_device_address() to try to read the device address from a file descriptor as a last resort, if provided. Additionally, linux_get_device_address() will now return an error if the path could not be parsed. Signed-off-by: Vianney le Clément de Saint-Marcq <co...@qu...> --- libusb/os/linux_udev.c | 2 +- libusb/os/linux_usbfs.c | 15 +++++++++++++-- libusb/os/linux_usbfs.h | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/libusb/os/linux_udev.c b/libusb/os/linux_udev.c index c97806ba..bea03e3a 100644 --- a/libusb/os/linux_udev.c +++ b/libusb/os/linux_udev.c @@ -232,7 +232,7 @@ static int udev_device_info(struct libusb_context *ctx, int detached, } return linux_get_device_address(ctx, detached, busnum, devaddr, - dev_node, *sys_name); + dev_node, *sys_name, -1); } static void udev_hotplug_event(struct udev_device* udev_dev) diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c index dfbb6c4b..addde884 100644 --- a/libusb/os/linux_usbfs.c +++ b/libusb/os/linux_usbfs.c @@ -687,14 +687,23 @@ static int sysfs_get_active_config(struct libusb_device *dev, int *config) int linux_get_device_address (struct libusb_context *ctx, int detached, uint8_t *busnum, uint8_t *devaddr,const char *dev_node, - const char *sys_name) + const char *sys_name, int fd) { + char proc_path[PATH_MAX], fd_path[PATH_MAX]; int sysfs_attr; + ssize_t r; usbi_dbg("getting address for device: %s detached: %d", sys_name, detached); /* can't use sysfs to read the bus and device number if the * device has been detached */ if (!sysfs_can_relate_devices || detached || NULL == sys_name) { + if (NULL == dev_node && fd >= 0) { + /* try to retrieve the device node from fd */ + snprintf(proc_path, PATH_MAX, "/proc/self/fd/%d", fd); + r = readlink(proc_path, fd_path, PATH_MAX); + if (r > 0) + dev_node = fd_path; + } if (NULL == dev_node) { return LIBUSB_ERROR_OTHER; } @@ -704,6 +713,8 @@ int linux_get_device_address (struct libusb_context *ctx, int detached, sscanf (dev_node, "/dev/bus/usb/%hhu/%hhu", busnum, devaddr); } else if (!strncmp(dev_node, "/proc/bus/usb", 13)) { sscanf (dev_node, "/proc/bus/usb/%hhu/%hhu", busnum, devaddr); + } else { + return LIBUSB_ERROR_OTHER; } return LIBUSB_SUCCESS; @@ -1287,7 +1298,7 @@ static int sysfs_scan_device(struct libusb_context *ctx, const char *devname) uint8_t busnum, devaddr; int ret; - ret = linux_get_device_address (ctx, 0, &busnum, &devaddr, NULL, devname); + ret = linux_get_device_address (ctx, 0, &busnum, &devaddr, NULL, devname, -1); if (LIBUSB_SUCCESS != ret) { return ret; } diff --git a/libusb/os/linux_usbfs.h b/libusb/os/linux_usbfs.h index 24496325..a57eb413 100644 --- a/libusb/os/linux_usbfs.h +++ b/libusb/os/linux_usbfs.h @@ -187,7 +187,7 @@ void linux_device_disconnected(uint8_t busnum, uint8_t devaddr); int linux_get_device_address (struct libusb_context *ctx, int detached, uint8_t *busnum, uint8_t *devaddr, const char *dev_node, - const char *sys_name); + const char *sys_name, int fd); int linux_enumerate_device(struct libusb_context *ctx, uint8_t busnum, uint8_t devaddr, const char *sysfs_dir); -- 2.19.2 |
From: Vianney le C. de Saint-M. <co...@qu...> - 2018-12-05 21:43:02
|
Handle devices that are initialized with NULL as sysfs_dir. For such devices, the usbfs functions should be used instead of their sysfs counterparts. Signed-off-by: Vianney le Clément de Saint-Marcq <co...@qu...> --- libusb/os/linux_usbfs.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c index 768e7d5a..7bda951e 100644 --- a/libusb/os/linux_usbfs.c +++ b/libusb/os/linux_usbfs.c @@ -636,7 +636,7 @@ static int op_get_device_descriptor(struct libusb_device *dev, { struct linux_device_priv *priv = _device_priv(dev); - *host_endian = sysfs_has_descriptors ? 0 : 1; + *host_endian = (priv->sysfs_dir && sysfs_has_descriptors) ? 0 : 1; memcpy(buffer, priv->descriptors, DEVICE_DESC_LENGTH); return 0; @@ -756,9 +756,11 @@ static int seek_to_next_descriptor(struct libusb_context *ctx, } /* Return offset to next config */ -static int seek_to_next_config(struct libusb_context *ctx, +static int seek_to_next_config(struct libusb_device *dev, unsigned char *buffer, int size) { + struct libusb_context *ctx = DEVICE_CTX(dev); + struct linux_device_priv *priv = _device_priv(dev); struct libusb_config_descriptor config; if (size == 0) @@ -785,7 +787,7 @@ static int seek_to_next_config(struct libusb_context *ctx, * config descriptor with verified bLength fields, with descriptors * with an invalid bLength removed. */ - if (sysfs_has_descriptors) { + if (priv->sysfs_dir && sysfs_has_descriptors) { int next = seek_to_next_descriptor(ctx, LIBUSB_DT_CONFIG, buffer, size); if (next == LIBUSB_ERROR_NOT_FOUND) @@ -814,7 +816,6 @@ static int seek_to_next_config(struct libusb_context *ctx, static int op_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t value, unsigned char **buffer, int *host_endian) { - struct libusb_context *ctx = DEVICE_CTX(dev); struct linux_device_priv *priv = _device_priv(dev); unsigned char *descriptors = priv->descriptors; int size = priv->descriptors_len; @@ -830,7 +831,7 @@ static int op_get_config_descriptor_by_value(struct libusb_device *dev, /* Seek till the config is found, or till "EOF" */ while (1) { - int next = seek_to_next_config(ctx, descriptors, size); + int next = seek_to_next_config(dev, descriptors, size); if (next < 0) return next; config = (struct libusb_config_descriptor *)descriptors; @@ -846,16 +847,16 @@ static int op_get_config_descriptor_by_value(struct libusb_device *dev, static int op_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) { + struct linux_device_priv *priv = _device_priv(dev); int r, config; unsigned char *config_desc; - if (sysfs_can_relate_devices) { + if (priv->sysfs_dir && sysfs_can_relate_devices) { r = sysfs_get_active_config(dev, &config); if (r < 0) return r; } else { /* Use cached bConfigurationValue */ - struct linux_device_priv *priv = _device_priv(dev); config = priv->active_config; } if (config == -1) @@ -887,7 +888,7 @@ static int op_get_config_descriptor(struct libusb_device *dev, /* Seek till the config is found, or till "EOF" */ for (i = 0; ; i++) { - r = seek_to_next_config(DEVICE_CTX(dev), descriptors, size); + r = seek_to_next_config(dev, descriptors, size); if (r < 0) return r; if (i == config_index) @@ -979,7 +980,7 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, } /* cache descriptors in memory */ - if (sysfs_has_descriptors) + if (sysfs_dir && sysfs_has_descriptors) fd = _open_sysfs_attr(dev, "descriptors"); else fd = _get_usbfs_fd(dev, O_RDONLY, 0); @@ -995,7 +996,7 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, return LIBUSB_ERROR_NO_MEM; } /* usbfs has holes in the file */ - if (!sysfs_has_descriptors) { + if (!(sysfs_dir && sysfs_has_descriptors)) { memset(priv->descriptors + priv->descriptors_len, 0, descriptors_size - priv->descriptors_len); } @@ -1018,7 +1019,7 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, return LIBUSB_ERROR_IO; } - if (sysfs_can_relate_devices) + if (sysfs_dir && sysfs_can_relate_devices) return LIBUSB_SUCCESS; /* cache active config */ @@ -1404,15 +1405,16 @@ static void op_close(struct libusb_device_handle *dev_handle) static int op_get_configuration(struct libusb_device_handle *handle, int *config) { + struct linux_device_priv *priv = _device_priv(handle->dev); int r; - if (sysfs_can_relate_devices) { + if (priv->sysfs_dir && sysfs_can_relate_devices) { r = sysfs_get_active_config(handle->dev, config); } else { r = usbfs_get_active_config(handle->dev, _device_handle_priv(handle)->fd); if (r == LIBUSB_SUCCESS) - *config = _device_priv(handle->dev)->active_config; + *config = priv->active_config; } if (r < 0) return r; -- 2.19.2 |