diff --git a/android/jni/examples.mk b/android/jni/examples.mk
index 05609cc8e..031ab9bb8 100644
--- a/android/jni/examples.mk
+++ b/android/jni/examples.mk
@@ -28,9 +28,9 @@ LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/listdevs.c
LOCAL_C_INCLUDES += \
- $(LIBUSB_ROOT_ABS)
+ $(LIBUSB_ROOT_ABS)/libusb
-LOCAL_SHARED_LIBRARIES += libusb1.0
+LOCAL_SHARED_LIBRARIES += libusb-1.0.0
LOCAL_MODULE:= listdevs
@@ -44,9 +44,9 @@ LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/xusb.c
LOCAL_C_INCLUDES += \
- $(LIBUSB_ROOT_ABS)
+ $(LIBUSB_ROOT_ABS)/libusb
-LOCAL_SHARED_LIBRARIES += libusb1.0
+LOCAL_SHARED_LIBRARIES += libusb-1.0.0
LOCAL_MODULE:= xusb
@@ -60,9 +60,9 @@ LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/hotplugtest.c
LOCAL_C_INCLUDES += \
- $(LIBUSB_ROOT_ABS)
+ $(LIBUSB_ROOT_ABS)/libusb
-LOCAL_SHARED_LIBRARIES += libusb1.0
+LOCAL_SHARED_LIBRARIES += libusb-1.0.0
LOCAL_MODULE:= hotplugtest
@@ -77,9 +77,9 @@ LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/ezusb.c
LOCAL_C_INCLUDES += \
- $(LIBUSB_ROOT_ABS)
+ $(LIBUSB_ROOT_ABS)/libusb
-LOCAL_SHARED_LIBRARIES += libusb1.0
+LOCAL_SHARED_LIBRARIES += libusb-1.0.0
LOCAL_MODULE:= fxload
@@ -93,9 +93,9 @@ LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/sam3u_benchmark.c
LOCAL_C_INCLUDES += \
- $(LIBUSB_ROOT_ABS)
+ $(LIBUSB_ROOT_ABS)/libusb
-LOCAL_SHARED_LIBRARIES += libusb1.0
+LOCAL_SHARED_LIBRARIES += libusb-1.0.0
LOCAL_MODULE:= sam3u_benchmark
@@ -109,9 +109,9 @@ LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/dpfp.c
LOCAL_C_INCLUDES += \
- $(LIBUSB_ROOT_ABS)
+ $(LIBUSB_ROOT_ABS)/libusb
-LOCAL_SHARED_LIBRARIES += libusb1.0
+LOCAL_SHARED_LIBRARIES += libusb-1.0.0
LOCAL_MODULE:= dpfp
@@ -125,9 +125,9 @@ LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/dpfp_threaded.c
LOCAL_C_INCLUDES += \
- $(LIBUSB_ROOT_ABS)
+ $(LIBUSB_ROOT_ABS)/libusb
-LOCAL_SHARED_LIBRARIES += libusb1.0
+LOCAL_SHARED_LIBRARIES += libusb-1.0.0
LOCAL_MODULE:= dpfp_threaded
diff --git a/android/jni/libusb.mk b/android/jni/libusb.mk
index f4896b2ef..5516c5da5 100644
--- a/android/jni/libusb.mk
+++ b/android/jni/libusb.mk
@@ -49,6 +49,6 @@ LOCAL_EXPORT_C_INCLUDES := \
LOCAL_LDLIBS := -llog
-LOCAL_MODULE := libusb1.0
+LOCAL_MODULE := libusb-1.0.0
include $(BUILD_SHARED_LIBRARY)
diff --git a/android/jni/tests.mk b/android/jni/tests.mk
index 93d55161b..c94c74466 100644
--- a/android/jni/tests.mk
+++ b/android/jni/tests.mk
@@ -48,7 +48,7 @@ LOCAL_SRC_FILES := \
LOCAL_C_INCLUDES += \
$(LIBUSB_ROOT_ABS)
-LOCAL_SHARED_LIBRARIES += libusb1.0
+LOCAL_SHARED_LIBRARIES += libusb-1.0.0
LOCAL_STATIC_LIBRARIES += testlib
LOCAL_MODULE:= stress
diff --git a/libusb/core.c b/libusb/core.c
index 50f92f6b1..21b796c86 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -832,6 +832,10 @@ ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx,
usbi_mutex_unlock(&ctx->usb_devs_lock);
} else {
/* backend does not provide hotplug support */
+ if (!usbi_backend.get_device_list) {
+ len = -1;
+ goto out;
+ }
r = usbi_backend.get_device_list(ctx, &discdevs);
}
@@ -1276,6 +1280,74 @@ int API_EXPORTED libusb_open(libusb_device *dev,
}
/** \ingroup libusb_dev
+ * Open a device with a file descriptor and obtain a device handle.
+ * A handle allows you to perform I/O on the device in question.
+ *
+ * UseCase: Android, after permission granted from Android Device Manager.
+ * The fd can be obtained by calling UsbDeviceConnection.getFileDescriptor().
+ *
+ * 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 the file descriptor for 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_open2(libusb_device *dev, int fd,
+ libusb_device_handle **handle)
+{
+ if (usbi_backend.open2 == NULL) {
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+ }
+
+ 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);
+
+ _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.open2(_handle, fd);
+ if (r < 0) {
+ usbi_dbg("open2 %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 dev
* Convenience function for finding a device with a particular
* idVendor/idProduct combination. This function is intended
* for those scenarios where you are using libusb to knock up a quick test
@@ -1459,6 +1531,27 @@ libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle)
}
/** \ingroup libusb_dev
+ * Get the underlying device for a dev_node.
+ * UseCase: Android
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param dev_node device path
+ * \param descriptors the raw USB descriptors for the device
+ * \param descriptors_size the size of the descriptors array
+ * \returns the underlying device
+ */
+DEFAULT_VISIBILITY
+libusb_device * LIBUSB_CALL libusb_get_device2(libusb_context *ctx, const char *dev_node,
+ const char* descriptors, size_t descriptors_size)
+{
+ if (usbi_backend.get_device2 == NULL) {
+ /* Not supported on this platform */
+ return NULL;
+ }
+
+ return usbi_backend.get_device2(ctx, dev_node, descriptors, descriptors_size);
+}
+
+/** \ingroup dev
* Determine the bConfigurationValue of the currently active configuration.
*
* You could formulate your own control request to obtain this information,
@@ -2306,7 +2399,11 @@ int API_EXPORTED libusb_has_capability(uint32_t capability)
case LIBUSB_CAP_HAS_CAPABILITY:
return 1;
case LIBUSB_CAP_HAS_HOTPLUG:
+#ifdef __ANDROID__
+ return 0;
+#else
return !(usbi_backend.get_device_list);
+#endif
case LIBUSB_CAP_HAS_HID_ACCESS:
return (usbi_backend.caps & USBI_CAP_HAS_HID_ACCESS);
case LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER:
diff --git a/libusb/libusb.h b/libusb/libusb.h
index 430136b2e..81321d2c7 100644
--- a/libusb/libusb.h
+++ b/libusb/libusb.h
@@ -1363,8 +1363,11 @@ 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_open2(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);
+libusb_device * LIBUSB_CALL libusb_get_device2(libusb_context *ctx, const char *dev_node,
+ const char* descriptors, size_t descriptors_len);
int LIBUSB_CALL libusb_set_configuration(libusb_device_handle *dev_handle,
int configuration);
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index 31d6ce98d..067907e86 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -148,9 +148,11 @@ static inline void list_add_tail(struct list_head *entry,
static inline void list_del(struct list_head *entry)
{
- entry->next->prev = entry->prev;
- entry->prev->next = entry->next;
- entry->next = entry->prev = NULL;
+ if (entry->next && entry->prev) {
+ entry->next->prev = entry->prev;
+ entry->prev->next = entry->next;
+ entry->next = entry->prev = NULL;
+ }
}
static inline void list_cut(struct list_head *list, struct list_head *head)
@@ -701,6 +703,9 @@ struct usbi_os_backend {
*/
void (*hotplug_poll)(void);
+ struct libusb_device* (*get_device2)(struct libusb_context *ctx, const char *dev_node,
+ const char* descriptors, size_t descriptors_len);
+
/* 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.
@@ -728,6 +733,8 @@ struct usbi_os_backend {
*/
int (*open)(struct libusb_device_handle *dev_handle);
+ int (*open2)(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/darwin_usb.c b/libusb/os/darwin_usb.c
index 35ea1c321..765264c42 100644
--- a/libusb/os/darwin_usb.c
+++ b/libusb/os/darwin_usb.c
@@ -743,7 +743,7 @@ static int darwin_request_descriptor (usb_device_t **device, UInt8 desc, UInt8 d
static int darwin_cache_device_descriptor (struct libusb_context *ctx, struct darwin_cached_device *dev) {
usb_device_t **device = dev->device;
- int retries = 1, delay = 30000;
+ int retries = 2, delay = 30000;
int unsuspended = 0, try_unsuspend = 1, try_reconfigure = 1;
int is_open = 0;
int ret = 0, ret2;
@@ -756,11 +756,6 @@ static int darwin_cache_device_descriptor (struct libusb_context *ctx, struct da
(*device)->GetDeviceProduct (device, &idProduct);
(*device)->GetDeviceVendor (device, &idVendor);
- /* According to Apple's documentation the device must be open for DeviceRequest but we may not be able to open some
- * devices and Apple's USB Prober doesn't bother to open the device before issuing a descriptor request. Still,
- * to follow the spec as closely as possible, try opening the device */
- is_open = ((*device)->USBDeviceOpenSeize(device) == kIOReturnSuccess);
-
do {
/**** retrieve device descriptor ****/
ret = darwin_request_descriptor (device, kUSBDeviceDesc, 0, &dev->dev_descriptor, sizeof(dev->dev_descriptor));
@@ -790,6 +785,13 @@ static int darwin_cache_device_descriptor (struct libusb_context *ctx, struct da
ret = kIOUSBPipeStalled;
}
+ if (kIOReturnSuccess != ret && !is_open) {
+ /* if the device descriptor request failed on the unopened device, try again with the device opened */
+ is_open = ((*device)->USBDeviceOpenSeize(device) == kIOReturnSuccess);
+ if (is_open)
+ continue;
+ }
+
if (kIOReturnSuccess != ret && is_open && try_unsuspend) {
/* device may be suspended. unsuspend it and try again */
#if DeviceVersion >= 320
@@ -1618,7 +1620,7 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer) {
return darwin_to_libusb (ret);
}
- if (0 != (transfer->length % maxPacketSize)) {
+ if (0 != maxPacketSize && 0 != (transfer->length % maxPacketSize)) {
/* do not need a zero packet */
transfer->flags &= ~LIBUSB_TRANSFER_ADD_ZERO_PACKET;
}
diff --git a/libusb/os/darwin_usb.h b/libusb/os/darwin_usb.h
index 474567f6a..b633c9763 100644
--- a/libusb/os/darwin_usb.h
+++ b/libusb/os/darwin_usb.h
@@ -27,6 +27,9 @@
#include
#include
+/* Include support for Mac OS X 10.6 */
+#undef kIOUSBDeviceInterfaceID500
+
/* IOUSBInterfaceInferface */
/* New in OS 10.12.0. */
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index 768e7d5a6..781429e0c 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -38,6 +38,11 @@
#include
#include
#include
+#ifdef __ANDROID__
+#include
+#include
+#include
+#endif
#include "libusbi.h"
#include "linux_usbfs.h"
@@ -199,6 +204,114 @@ struct linux_transfer_priv {
int iso_packet_offset;
};
+
+#ifdef __ANDROID__
+#define PROC_SELF_FD "/proc/self/fd"
+
+/* Android will likely require elevated permissions to open a USB device.
+ * If possible, duplicate an already opened file descriptor for the device. */
+static int _dup_open_fd(const char *path)
+{
+ struct stat status;
+ DIR *dir;
+ struct dirent *entry;
+ int fd = -1;
+
+ /* if file doesn't exist, don't bother trying to find an open file descriptor for it */
+ if (stat(path, &status) != 0)
+ return -1;
+
+ dir = opendir(PROC_SELF_FD);
+ if (dir) {
+ while ((entry = readdir(dir)) != NULL) {
+ char fullpath[PATH_MAX];
+ char filepath[PATH_MAX];
+ ssize_t len;
+
+ if (entry->d_type != DT_LNK)
+ continue;
+
+ if ((len = (ssize_t)snprintf(fullpath, sizeof(fullpath), "%s/%s", PROC_SELF_FD, entry->d_name)) < 0 ||
+ len == sizeof(fullpath))
+ continue;
+
+ if (lstat(fullpath, &status) != 0 || status.st_size >= sizeof(filepath))
+ continue;
+
+ if ((len = readlink(fullpath, filepath, sizeof(filepath))) < 0 ||
+ len == sizeof(filepath))
+ continue;
+ filepath[len] = '\0';
+
+ if (strcmp(path, filepath) != 0)
+ continue;
+
+ fd = atoi(entry->d_name);
+ if (fd >= 0)
+ fd = dup(fd);
+ break;
+ }
+ closedir(dir);
+ } else {
+ /* we don't have access to the directory holding a list of the open file descriptors, use brute force */
+ struct rlimit rlim = {0};
+ const ino_t device_inode = status.st_ino;
+ const int max_fd = (getrlimit(RLIMIT_NOFILE, &rlim) == 0) ? (int)rlim.rlim_cur : 1024;
+ int i;
+
+ /* loop through the possible file descriptors for this process and look for a matching inode */
+ for (i = 0; i < max_fd; i++) {
+ if (fstat(i, &status) == 0 && status.st_ino == device_inode) {
+ fd = dup(i);
+ break;
+ }
+ }
+ }
+
+ return fd;
+}
+
+/* The major and minor device numbers for the devie are stored in the "dev"
+ * attributes of the sysfs. Due to limited permissions on Android, we will
+ * loop through our open file descriptors and obtain the major and minor
+ * device numbers (using fstat), looking for a match to the device we are
+ * attempting to open. If they match, we dup the file descriptor.
+ */
+static int _open_sysfs_attr(struct libusb_device *dev, const char *attr);
+static int _dup_sysfs_fd(struct libusb_device *dev)
+{
+ char tmp[64];
+ int fd = _open_sysfs_attr(dev, "dev");
+ int r = read(fd, tmp, sizeof(tmp) - 1);
+ close(fd);
+ if (r < 0)
+ return -1;
+
+ tmp[r] = '\0';
+ int devMajor = 0, devMinor = 0;
+ if (sscanf(tmp, "%d:%d", &devMajor, &devMinor) != 2 || (devMajor <= 0 && devMinor <= 0))
+ return -1;
+
+ struct stat status = {0};
+ struct rlimit rlim = {0};
+ const int max_fd = (getrlimit(RLIMIT_NOFILE, &rlim) == 0) ? (int)rlim.rlim_cur : 1024;
+ int i;
+
+ fd = -1;
+
+ /* loop through the possible file descriptors for this process and look for a matching device */
+ for (i = 0; i < max_fd; i++) {
+ if (fstat(i, &status) == 0 &&
+ major(status.st_rdev) == devMajor &&
+ minor(status.st_rdev) == devMinor) {
+ fd = dup(i);
+ break;
+ }
+ }
+ return fd;
+}
+#endif
+
static int _open(const char *path, int flags)
{
#if defined(O_CLOEXEC)
@@ -219,18 +332,28 @@ static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent)
if (usbdev_names)
snprintf(path, PATH_MAX, "%s/usbdev%d.%d",
usbfs_path, dev->bus_number, dev->device_address);
- else
+ else if (usbfs_path)
snprintf(path, PATH_MAX, "%s/%03d/%03d",
usbfs_path, dev->bus_number, dev->device_address);
+ else
+#ifdef __ANDROID__
+ return _dup_sysfs_fd(dev);
+#else
+ return LIBUSB_ERROR_ACCESS;
+#endif
fd = _open(path, mode);
+#ifdef __ANDROID__
+ if (fd == -1)
+ fd = _dup_open_fd(path);
+#endif
if (fd != -1)
return fd; /* Success */
if (errno == ENOENT) {
- if (!silent)
+ if (!silent)
usbi_err(ctx, "File doesn't exist, wait %d ms and try again", delay/1000);
-
+
/* Wait 10ms for USB device path creation.*/
nanosleep(&(struct timespec){delay / 1000000, (delay * 1000) % 1000000000UL}, NULL);
@@ -238,7 +361,7 @@ static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent)
if (fd != -1)
return fd; /* Success */
}
-
+
if (!silent) {
usbi_err(ctx, "libusb couldn't open USB device %s: %s",
path, strerror(errno));
@@ -427,12 +550,6 @@ static int op_init(struct libusb_context *ctx)
struct stat statbuf;
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();
@@ -496,11 +613,26 @@ static int op_init(struct libusb_context *ctx)
if (sysfs_has_descriptors)
usbi_dbg("sysfs has complete descriptors");
+ usbfs_path = find_usbfs_path();
+ if (!usbfs_path) {
+#if defined(__ANDROID__)
+ if (!sysfs_can_relate_devices)
+#endif
+ {
+ usbi_err(ctx, "could not find usbfs");
+ return LIBUSB_ERROR_OTHER;
+ }
+ }
+
usbi_mutex_static_lock(&linux_hotplug_startstop_lock);
r = LIBUSB_SUCCESS;
if (init_count == 0) {
/* start up hotplug event handler */
r = linux_start_event_monitor();
+#if defined(__ANDROID__)
+ if (r != LIBUSB_SUCCESS && !usbfs_path && sysfs_can_relate_devices)
+ r = LIBUSB_SUCCESS;
+#endif
}
if (r == LIBUSB_SUCCESS) {
r = linux_scan_devices(ctx);
@@ -529,6 +661,8 @@ static void op_exit(struct libusb_context *ctx)
static int linux_start_event_monitor(void)
{
+ if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))
+ return LIBUSB_SUCCESS;
#if defined(USE_UDEV)
return linux_udev_start_event_monitor();
#else
@@ -538,6 +672,8 @@ static int linux_start_event_monitor(void)
static int linux_stop_event_monitor(void)
{
+ if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))
+ return LIBUSB_SUCCESS;
#if defined(USE_UDEV)
return linux_udev_stop_event_monitor();
#else
@@ -548,6 +684,8 @@ static int linux_stop_event_monitor(void)
static int linux_scan_devices(struct libusb_context *ctx)
{
int ret;
+ if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))
+ return LIBUSB_SUCCESS;
usbi_mutex_static_lock(&linux_hotplug_lock);
@@ -564,6 +702,18 @@ static int linux_scan_devices(struct libusb_context *ctx)
static void op_hotplug_poll(void)
{
+#if defined(__ANDROID__)
+ if (!usbfs_path && sysfs_can_relate_devices) {
+ struct libusb_context *ctx;
+
+ usbi_mutex_static_lock(&active_contexts_lock);
+ list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
+ linux_default_scan_devices(ctx);
+ }
+ usbi_mutex_static_unlock(&active_contexts_lock);
+ return;
+ }
+#endif
#if defined(USE_UDEV)
linux_udev_hotplug_poll();
#else
@@ -1392,13 +1542,24 @@ static int op_open(struct libusb_device_handle *handle)
return r;
}
+#ifdef __ANDROID__
+static int op_open2(struct libusb_device_handle *handle, int fd)
+{
+ struct linux_device_handle_priv *hpriv = _device_handle_priv(handle);
+ hpriv->fd = fd;
+ return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT);
+}
+#endif
+
static void op_close(struct libusb_device_handle *dev_handle)
{
struct linux_device_handle_priv *hpriv = _device_handle_priv(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);
+#ifndef __ANDROID
+ close(hpriv->fd);
+#endif
}
static int op_get_configuration(struct libusb_device_handle *handle,
@@ -2747,6 +2908,92 @@ static clockid_t op_get_timerfd_clockid(void)
}
#endif
+#ifdef __ANDROID__
+struct libusb_device* op_get_device2(struct libusb_context *ctx, const char *dev_node,
+ const char* descriptors, size_t descriptors_size)
+{
+ uint8_t busnum, devaddr;
+ unsigned int session_id;
+ if (linux_get_device_address(ctx, 0, &busnum, &devaddr,
+ dev_node, NULL) != LIBUSB_SUCCESS) {
+ usbi_dbg("failed to get device address (%s)", dev_node);
+ return NULL;
+ }
+
+ /* make sure device is enumerated */
+ if (linux_enumerate_device2(ctx, busnum, devaddr, descriptors, descriptors_size) < 0) {
+ usbi_dbg("failed to enumerate (%s)", dev_node);
+ return NULL;
+ }
+
+ /* retrieve the device */
+ session_id = busnum << 8 | devaddr;
+ usbi_dbg("busnum %d devaddr %d session_id %ld", busnum, devaddr,
+ session_id);
+
+ return usbi_get_device_by_session_id(ctx, session_id);
+}
+
+static int initialize_device2(struct libusb_device *dev, uint8_t busnum,
+ uint8_t devaddr, const char* descriptors, size_t descriptors_size)
+{
+ struct linux_device_priv *priv = _device_priv(dev);
+
+ dev->bus_number = busnum;
+ dev->device_address = devaddr;
+
+ priv->descriptors = usbi_reallocf(priv->descriptors,
+ descriptors_size);
+ if (!priv->descriptors) {
+ return LIBUSB_ERROR_NO_MEM;
+ }
+ memcpy(priv->descriptors, descriptors, descriptors_size);
+ priv->descriptors_len = descriptors_size;
+ return LIBUSB_SUCCESS;
+}
+
+int linux_enumerate_device2(struct libusb_context *ctx, uint8_t busnum, uint8_t devaddr,
+ const char* descriptors, size_t descriptors_size)
+{
+ unsigned long session_id;
+ struct libusb_device *dev;
+ int r = 0;
+
+ /* FIXME: session ID is not guaranteed unique as addresses can wrap and
+ * will be reused. instead we should add a simple sysfs attribute with
+ * a session ID. */
+ session_id = busnum << 8 | devaddr;
+ usbi_dbg("busnum %d devaddr %d session_id %ld", busnum, devaddr,
+ session_id);
+
+ dev = usbi_get_device_by_session_id(ctx, session_id);
+ if (dev) {
+ /* device already exists in the context */
+ usbi_dbg("session_id %ld already exists", session_id);
+ libusb_unref_device(dev);
+ return LIBUSB_SUCCESS;
+ }
+
+ usbi_dbg("allocating new device for %d/%d (session %ld)",
+ busnum, devaddr, session_id);
+ dev = usbi_alloc_device(ctx, session_id);
+ if (!dev)
+ return LIBUSB_ERROR_NO_MEM;
+
+ r = initialize_device2(dev, busnum, devaddr, descriptors, descriptors_size);
+ if (r < 0)
+ goto out;
+ r = usbi_sanitize_device(dev);
+ if (r < 0)
+ goto out;
+
+out:
+ if (r < 0)
+ libusb_unref_device(dev);
+ return r;
+}
+#endif
+
const struct usbi_os_backend usbi_backend = {
.name = "Linux usbfs",
.caps = USBI_CAP_HAS_HID_ACCESS|USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER,
@@ -2759,7 +3006,17 @@ 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,
+#ifdef __ANDROID__
+ .get_device2 = op_get_device2,
+#else
+ .get_device2 = NULL,
+#endif
.open = op_open,
+#ifdef __ANDROID__
+ .open2 = op_open2,
+#else
+ .open2 = NULL,
+#endif
.close = op_close,
.get_configuration = op_get_configuration,
.set_configuration = op_set_configuration,
diff --git a/libusb/os/linux_usbfs.h b/libusb/os/linux_usbfs.h
index 24496325f..f2586167e 100644
--- a/libusb/os/linux_usbfs.h
+++ b/libusb/os/linux_usbfs.h
@@ -190,5 +190,6 @@ int linux_get_device_address (struct libusb_context *ctx, int detached,
const char *sys_name);
int linux_enumerate_device(struct libusb_context *ctx,
uint8_t busnum, uint8_t devaddr, const char *sysfs_dir);
-
+int linux_enumerate_device2(struct libusb_context *ctx, uint8_t busnum, uint8_t devaddr,
+ const char* descriptors, size_t descriptors_size);
#endif