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