diff options
author | ikarienator@chromium.org <ikarienator@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-25 00:05:51 +0000 |
---|---|---|
committer | ikarienator@chromium.org <ikarienator@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-25 00:05:51 +0000 |
commit | 7681a3aa3eb1d377f5ef2d17bb639dc7684828a7 (patch) | |
tree | 1bf1f67314847dde2b4369c56b405b3cc775ad99 | |
parent | bc38b33a093b41f4ba1fbb9188530c3784a4540a (diff) | |
download | chromium_src-7681a3aa3eb1d377f5ef2d17bb639dc7684828a7.zip chromium_src-7681a3aa3eb1d377f5ef2d17bb639dc7684828a7.tar.gz chromium_src-7681a3aa3eb1d377f5ef2d17bb639dc7684828a7.tar.bz2 |
Roll libusbx to 1.0.17
R=meacer@chromium.org
Review URL: https://codereview.chromium.org/24227008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@225105 0039d316-1c4b-4281-b951-d872f2087c98
20 files changed, 585 insertions, 321 deletions
diff --git a/third_party/libusb/src/libusb/core.c b/third_party/libusb/src/libusb/core.c index e29e8df..e816284 100644 --- a/third_party/libusb/src/libusb/core.c +++ b/third_party/libusb/src/libusb/core.c @@ -33,6 +33,9 @@ #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #endif +#ifdef HAVE_SYSLOG_H +#include <syslog.h> +#endif #ifdef __ANDROID__ #include <android/log.h> @@ -47,6 +50,8 @@ const struct usbi_os_backend * const usbi_backend = &linux_usbfs_backend; const struct usbi_os_backend * const usbi_backend = &darwin_backend; #elif defined(OS_OPENBSD) const struct usbi_os_backend * const usbi_backend = &openbsd_backend; +#elif defined(OS_NETBSD) +const struct usbi_os_backend * const usbi_backend = &netbsd_backend; #elif defined(OS_WINDOWS) const struct usbi_os_backend * const usbi_backend = &windows_backend; #elif defined(OS_WINCE) @@ -56,7 +61,7 @@ const struct usbi_os_backend * const usbi_backend = &wince_backend; #endif struct libusb_context *usbi_default_context = NULL; -const struct libusb_version libusb_version_internal = +static const struct libusb_version libusb_version_internal = { LIBUSB_MAJOR, LIBUSB_MINOR, LIBUSB_MICRO, LIBUSB_NANO, LIBUSB_RC, "http://libusbx.org" }; static int default_context_refcnt = 0; @@ -564,6 +569,10 @@ void usbi_disconnect_device(struct libusb_device *dev) dev->attached = 0; usbi_mutex_unlock(&dev->lock); + usbi_mutex_lock(&ctx->usb_devs_lock); + list_del(&dev->list); + usbi_mutex_unlock(&ctx->usb_devs_lock); + /* Signal that an event has occurred for this device if we support hotplug AND * the hotplug pipe is ready. This prevents an event from getting raised during * initial enumeration. libusb_handle_events will take care of dereferencing the @@ -574,10 +583,6 @@ void usbi_disconnect_device(struct libusb_device *dev) usbi_err(DEVICE_CTX(dev), "error writing hotplug message"); } } - - usbi_mutex_lock(&ctx->usb_devs_lock); - list_del(&dev->list); - usbi_mutex_unlock(&ctx->usb_devs_lock); } /* Perform some final sanity checks on a newly discovered device. If this @@ -1873,10 +1878,6 @@ err_free_ctx: if (ctx == usbi_default_context) usbi_default_context = NULL; - usbi_mutex_destroy(&ctx->open_devs_lock); - usbi_mutex_destroy(&ctx->usb_devs_lock); - usbi_mutex_destroy(&ctx->hotplug_cbs_lock); - usbi_mutex_static_lock(&active_contexts_lock); list_del (&ctx->list); usbi_mutex_static_unlock(&active_contexts_lock); @@ -1888,6 +1889,10 @@ err_free_ctx: } usbi_mutex_unlock(&ctx->usb_devs_lock); + usbi_mutex_destroy(&ctx->open_devs_lock); + usbi_mutex_destroy(&ctx->usb_devs_lock); + usbi_mutex_destroy(&ctx->hotplug_cbs_lock); + free(ctx); err_unlock: usbi_mutex_static_unlock(&default_context_lock); @@ -2026,10 +2031,42 @@ int usbi_gettimeofday(struct timeval *tp, void *tzp) } #endif -static void usbi_log_str(struct libusb_context *ctx, const char * str) +static void usbi_log_str(struct libusb_context *ctx, + enum libusb_log_level level, const char * str) { - UNUSED(ctx); +#if defined(USE_SYSTEM_LOGGING_FACILITY) +#if defined(OS_WINDOWS) || defined(OS_WINCE) + /* Windows CE only supports the Unicode version of OutputDebugString. */ + WCHAR wbuf[USBI_MAX_LOG_LEN]; + MultiByteToWideChar(CP_UTF8, 0, str, -1, wbuf, sizeof(wbuf)); + OutputDebugStringW(wbuf); +#elif defined(__ANDROID__) + int priority = ANDROID_LOG_UNKNOWN; + switch (level) { + case LIBUSB_LOG_LEVEL_INFO: priority = ANDROID_LOG_INFO; break; + case LIBUSB_LOG_LEVEL_WARNING: priority = ANDROID_LOG_WARN; break; + case LIBUSB_LOG_LEVEL_ERROR: priority = ANDROID_LOG_ERROR; break; + case LIBUSB_LOG_LEVEL_DEBUG: priority = ANDROID_LOG_DEBUG; break; + } + __android_log_write(priority, "libusb", str); +#elif defined(HAVE_SYSLOG_FUNC) + int syslog_level = LOG_INFO; + switch (level) { + case LIBUSB_LOG_LEVEL_INFO: syslog_level = LOG_INFO; break; + case LIBUSB_LOG_LEVEL_WARNING: syslog_level = LOG_WARNING; break; + case LIBUSB_LOG_LEVEL_ERROR: syslog_level = LOG_ERR; break; + case LIBUSB_LOG_LEVEL_DEBUG: syslog_level = LOG_DEBUG; break; + } + syslog(syslog_level, "%s", str); +#else /* All of gcc, Clang, XCode seem to use #warning */ +#warning System logging is not supported on this platform. Logging to stderr will be used instead. + fputs(str, stderr); +#endif +#else fputs(str, stderr); +#endif /* USE_SYSTEM_LOGGING_FACILITY */ + UNUSED(ctx); + UNUSED(level); } void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, @@ -2059,33 +2096,11 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, return; #endif -#ifdef __ANDROID__ - int prio; - switch (level) { - case LOG_LEVEL_INFO: - prio = ANDROID_LOG_INFO; - break; - case LOG_LEVEL_WARNING: - prio = ANDROID_LOG_WARN; - break; - case LOG_LEVEL_ERROR: - prio = ANDROID_LOG_ERROR; - break; - case LOG_LEVEL_DEBUG: - prio = ANDROID_LOG_DEBUG; - break; - default: - prio = ANDROID_LOG_UNKNOWN; - break; - } - - __android_log_vprint(prio, "LibUsb", format, args); -#else usbi_gettimeofday(&now, NULL); if ((global_debug) && (!has_debug_header_been_displayed)) { has_debug_header_been_displayed = 1; - usbi_log_str(ctx, "[timestamp] [threadID] facility level [function call] <message>\n"); - usbi_log_str(ctx, "--------------------------------------------------------------------------------\n"); + usbi_log_str(ctx, LIBUSB_LOG_LEVEL_DEBUG, "[timestamp] [threadID] facility level [function call] <message>\n"); + usbi_log_str(ctx, LIBUSB_LOG_LEVEL_DEBUG, "--------------------------------------------------------------------------------\n"); } if (now.tv_usec < timestamp_origin.tv_usec) { now.tv_sec--; @@ -2108,7 +2123,7 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, prefix = "debug"; break; case LIBUSB_LOG_LEVEL_NONE: - break; + return; default: prefix = "unknown"; break; @@ -2143,8 +2158,7 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, } strcpy(buf + header_len + text_len, USBI_LOG_LINE_END); - usbi_log_str(ctx, buf); -#endif + usbi_log_str(ctx, level, buf); } void usbi_log(struct libusb_context *ctx, enum libusb_log_level level, diff --git a/third_party/libusb/src/libusb/descriptor.c b/third_party/libusb/src/libusb/descriptor.c index ba6d1467..e1c4915 100644 --- a/third_party/libusb/src/libusb/descriptor.c +++ b/third_party/libusb/src/libusb/descriptor.c @@ -660,7 +660,7 @@ int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev, /* iterate through all configurations, returning the index of the configuration * matching a specific bConfigurationValue in the idx output parameter, or -1 * if the config was not found. - * returns 0 or a LIBUSB_ERROR code + * returns 0 on success or a LIBUSB_ERROR code */ int usbi_get_config_index_by_value(struct libusb_device *dev, uint8_t bConfigurationValue, int *idx) @@ -673,8 +673,10 @@ int usbi_get_config_index_by_value(struct libusb_device *dev, int host_endian; int r = usbi_backend->get_config_descriptor(dev, i, tmp, sizeof(tmp), &host_endian); - if (r < 0) + if (r < 0) { + *idx = -1; return r; + } if (tmp[5] == bConfigurationValue) { *idx = i; return 0; diff --git a/third_party/libusb/src/libusb/hotplug.c b/third_party/libusb/src/libusb/hotplug.c index 6b04342..081bc79 100644 --- a/third_party/libusb/src/libusb/hotplug.c +++ b/third_party/libusb/src/libusb/hotplug.c @@ -59,7 +59,11 @@ * * A callback function must return an int (0 or 1) indicating whether the callback is * expecting additional events. Returning 0 will rearm the callback and 1 will cause - * the callback to be deregistered. + * the callback to be deregistered. Note that when callbacks are called from + * libusb_hotplug_register_callback() because of the \ref LIBUSB_HOTPLUG_ENUMERATE + * flag, the callback return value is ignored, iow you cannot cause a callback + * to be deregistered by returning 1 when it is called from + * libusb_hotplug_register_callback(). * * Callbacks for a particular context are automatically deregistered by libusb_exit(). * @@ -167,8 +171,7 @@ static int usbi_hotplug_match_cb (struct libusb_context *ctx, return 0; } - return hotplug_cb->cb (ctx == usbi_default_context ? NULL : ctx, - dev, event, hotplug_cb->user_data); + return hotplug_cb->cb (ctx, dev, event, hotplug_cb->user_data); } void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev, @@ -192,18 +195,7 @@ void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev, usbi_mutex_unlock(&ctx->hotplug_cbs_lock); - /* loop through and disconnect all open handles for this device */ - if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == event) { - struct libusb_device_handle *handle; - - usbi_mutex_lock(&ctx->open_devs_lock); - list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) { - if (dev == handle->dev) { - usbi_handle_disconnect (handle); - } - } - usbi_mutex_unlock(&ctx->open_devs_lock); - } + /* the backend is expected to call the callback for each active transfer */ } int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx, @@ -253,19 +245,29 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx, list_add(&new_callback->list, &ctx->hotplug_cbs); - if (flags & LIBUSB_HOTPLUG_ENUMERATE) { - struct libusb_device *dev; + usbi_mutex_unlock(&ctx->hotplug_cbs_lock); - usbi_mutex_lock(&ctx->usb_devs_lock); - list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) { - (void) usbi_hotplug_match_cb (ctx, dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, new_callback); + if (flags & LIBUSB_HOTPLUG_ENUMERATE) { + int i, len; + struct libusb_device **devs; + + len = (int) libusb_get_device_list(ctx, &devs); + if (len < 0) { + libusb_hotplug_deregister_callback(ctx, + new_callback->handle); + return len; + } + + for (i = 0; i < len; i++) { + usbi_hotplug_match_cb(ctx, devs[i], + LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, + new_callback); } - usbi_mutex_unlock(&ctx->usb_devs_lock); + libusb_free_device_list(devs, 1); } - usbi_mutex_unlock(&ctx->hotplug_cbs_lock); if (handle) { *handle = new_callback->handle; diff --git a/third_party/libusb/src/libusb/io.c b/third_party/libusb/src/libusb/io.c index 4368b99..4f22963 100644 --- a/third_party/libusb/src/libusb/io.c +++ b/third_party/libusb/src/libusb/io.c @@ -787,7 +787,7 @@ void cb(struct libusb_transfer *transfer) void myfunc() { struct libusb_transfer *transfer; - unsigned char buffer[LIBUSB_CONTROL_SETUP_SIZE]; + unsigned char buffer[LIBUSB_CONTROL_SETUP_SIZE] __attribute__ ((aligned (2))); int completed = 0; transfer = libusb_alloc_transfer(0); @@ -1459,6 +1459,8 @@ int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer) } usbi_mutex_unlock(&ctx->flying_transfers_lock); + /* keep a reference to this device */ + libusb_ref_device(transfer->dev_handle->dev); out: updated_fds = (itransfer->flags & USBI_TRANSFER_UPDATED_FDS); usbi_mutex_unlock(&itransfer->lock); @@ -1522,6 +1524,7 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct libusb_context *ctx = TRANSFER_CTX(transfer); + struct libusb_device_handle *handle = transfer->dev_handle; uint8_t flags; int r = 0; @@ -1562,6 +1565,7 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, usbi_mutex_lock(&ctx->event_waiters_lock); usbi_cond_broadcast(&ctx->event_waiters_cond); usbi_mutex_unlock(&ctx->event_waiters_lock); + libusb_unref_device(handle->dev); return 0; } @@ -1996,8 +2000,8 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv) /* read the message from the hotplug thread */ ret = usbi_read(ctx->hotplug_pipe[0], &message, sizeof (message)); - if (ret < sizeof(message)) { - usbi_err(ctx, "hotplug pipe read error %d < %d", + if (ret != sizeof(message)) { + usbi_err(ctx, "hotplug pipe read error %d != %u", ret, sizeof(message)); r = LIBUSB_ERROR_OTHER; goto handled; diff --git a/third_party/libusb/src/libusb/libusb.h b/third_party/libusb/src/libusb/libusb.h index 15bd0d5..d144b3e 100644 --- a/third_party/libusb/src/libusb/libusb.h +++ b/third_party/libusb/src/libusb/libusb.h @@ -156,7 +156,7 @@ typedef unsigned __int32 uint32_t; extern "C" { #endif -/** \def libusb_cpu_to_le16 +/** \fn libusb_cpu_to_le16 * \ingroup misc * Convert a 16-bit value from host-endian to little-endian format. On * little endian systems, this function does nothing. On big endian systems, @@ -1434,7 +1434,7 @@ static inline unsigned char *libusb_control_transfer_get_data( static inline struct libusb_control_setup *libusb_control_transfer_get_setup( struct libusb_transfer *transfer) { - return (struct libusb_control_setup *) transfer->buffer; + return (struct libusb_control_setup *)(void *) transfer->buffer; } /** \ingroup asyncio @@ -1443,6 +1443,7 @@ static inline struct libusb_control_setup *libusb_control_transfer_get_setup( * be given in host-endian byte order. * * \param buffer buffer to output the setup packet into + * This pointer must be aligned to at least 2 bytes boundary. * \param bmRequestType see the * \ref libusb_control_setup::bmRequestType "bmRequestType" field of * \ref libusb_control_setup @@ -1463,7 +1464,7 @@ static inline void libusb_fill_control_setup(unsigned char *buffer, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength) { - struct libusb_control_setup *setup = (struct libusb_control_setup *) buffer; + struct libusb_control_setup *setup = (struct libusb_control_setup *)(void *) buffer; setup->bmRequestType = bmRequestType; setup->bRequest = bRequest; setup->wValue = libusb_cpu_to_le16(wValue); @@ -1499,6 +1500,7 @@ void LIBUSB_CALL libusb_free_transfer(struct libusb_transfer *transfer); * \param dev_handle handle of the device that will handle the transfer * \param buffer data buffer. If provided, this function will interpret the * first 8 bytes as a setup packet and infer the transfer length from that. + * This pointer must be aligned to at least 2 bytes boundary. * \param callback callback function to be invoked on transfer completion * \param user_data user data to pass to callback function * \param timeout timeout for the transfer in milliseconds @@ -1508,7 +1510,7 @@ static inline void libusb_fill_control_transfer( unsigned char *buffer, libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) { - struct libusb_control_setup *setup = (struct libusb_control_setup *) buffer; + struct libusb_control_setup *setup = (struct libusb_control_setup *)(void *) buffer; transfer->dev_handle = dev_handle; transfer->endpoint = 0; transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL; @@ -1883,7 +1885,7 @@ typedef enum { * * Since version 1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102 * - * \param libusb_context context of this notification + * \param ctx context of this notification * \param device libusb_device this event occurred on * \param event event that occurred * \param user_data user data provided when this callback was registered @@ -1903,6 +1905,18 @@ typedef int (LIBUSB_CALL *libusb_hotplug_callback_fn)(libusb_context *ctx, * armed until either it is deregistered with libusb_hotplug_deregister_callback() * or the supplied callback returns 1 to indicate it is finished processing events. * + * If the \ref LIBUSB_HOTPLUG_ENUMERATE is passed the callback will be + * called with a \ref LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED for all devices + * already plugged into the machine. Note that libusbx modifies its internal + * device list from a separate thread, while calling hotplug callbacks from + * libusb_handle_events(), so it is possible for a device to already be present + * on, or removed from, its internal device list, while the hotplug callbacks + * still need to be dispatched. This means that when using \ref + * LIBUSB_HOTPLUG_ENUMERATE, your callback may be called twice for the arrival + * of the same device, once from libusb_hotplug_register_callback() and once + * from libusb_handle_events(); and/or your callback may be called for the + * removal of a device for which an arrived call was never made. + * * Since version 1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102 * * \param[in] ctx context to register this callback with diff --git a/third_party/libusb/src/libusb/libusbi.h b/third_party/libusb/src/libusb/libusbi.h index 02efae30..bc608b92 100644 --- a/third_party/libusb/src/libusb/libusbi.h +++ b/third_party/libusb/src/libusb/libusbi.h @@ -23,6 +23,8 @@ #include "config.h" +#include <stdlib.h> + #include <stddef.h> #include <stdint.h> #include <time.h> @@ -433,7 +435,7 @@ void usbi_connect_device (struct libusb_device *dev); void usbi_disconnect_device (struct libusb_device *dev); /* Internal abstraction for poll (needs struct usbi_transfer on Windows) */ -#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) +#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) || defined(OS_NETBSD) #include <unistd.h> #include "os/poll_posix.h" #elif defined(OS_WINDOWS) || defined(OS_WINCE) @@ -995,6 +997,7 @@ extern const struct usbi_os_backend * const usbi_backend; extern const struct usbi_os_backend linux_usbfs_backend; extern const struct usbi_os_backend darwin_backend; extern const struct usbi_os_backend openbsd_backend; +extern const struct usbi_os_backend netbsd_backend; extern const struct usbi_os_backend windows_backend; extern const struct usbi_os_backend wince_backend; diff --git a/third_party/libusb/src/libusb/os/darwin_usb.c b/third_party/libusb/src/libusb/os/darwin_usb.c index 3f315e8..58467c3 100644 --- a/third_party/libusb/src/libusb/os/darwin_usb.c +++ b/third_party/libusb/src/libusb/os/darwin_usb.c @@ -210,6 +210,7 @@ static int usb_setup_device_iterator (io_iterator_t *deviceIterator, UInt32 loca return IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, deviceIterator); } +/* Returns 1 on success, 0 on failure. */ static int get_ioregistry_value_number (io_service_t service, CFStringRef property, CFNumberType type, void *p) { CFTypeRef cfNumber = IORegistryEntryCreateCFProperty (service, property, kCFAllocatorDefault, 0); int ret = 0; @@ -287,7 +288,7 @@ static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) { list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) { usbi_dbg ("notifying context %p of device disconnect", ctx); - dev = usbi_get_device_by_session_id(ctx, session); + dev = usbi_get_device_by_session_id(ctx, (unsigned long) session); if (dev) { /* signal the core that this device has been disconnected. the core will tear down this device when the reference count reaches 0 */ @@ -701,7 +702,7 @@ static int darwin_cache_device_descriptor (struct libusb_context *ctx, struct da else usbi_warn (ctx, "could not retrieve device descriptor %.4x:%.4x: %s (%x). skipping device", idVendor, idProduct, darwin_error_str (ret), ret); - return -1; + return darwin_to_libusb (ret); } /* catch buggy hubs (which appear to be virtual). Apple's own USB prober has problems with these devices. */ @@ -709,7 +710,7 @@ static int darwin_cache_device_descriptor (struct libusb_context *ctx, struct da /* not a valid device */ usbi_warn (ctx, "idProduct from iokit (%04x) does not match idProduct in descriptor (%04x). skipping device", idProduct, libusb_le16_to_cpu (dev->dev_descriptor.idProduct)); - return -1; + return LIBUSB_ERROR_NO_DEVICE; } usbi_dbg ("cached device descriptor:"); @@ -729,21 +730,19 @@ static int darwin_cache_device_descriptor (struct libusb_context *ctx, struct da dev->can_enumerate = 1; - return 0; + return LIBUSB_SUCCESS; } static int darwin_get_cached_device(struct libusb_context *ctx, io_service_t service, struct darwin_cached_device **cached_out) { struct darwin_cached_device *new_device; - UInt64 sessionID, parent_sessionID; + UInt64 sessionID = 0, parent_sessionID = 0; int ret = LIBUSB_SUCCESS; usb_device_t **device; io_service_t parent; kern_return_t result; UInt8 port = 0; - *cached_out = NULL; - /* get some info from the io registry */ (void) get_ioregistry_value_number (service, CFSTR("sessionID"), kCFNumberSInt64Type, &sessionID); (void) get_ioregistry_value_number (service, CFSTR("PortNum"), kCFNumberSInt8Type, &port); @@ -759,6 +758,8 @@ static int darwin_get_cached_device(struct libusb_context *ctx, io_service_t ser usbi_mutex_lock(&darwin_cached_devices_lock); do { + *cached_out = NULL; + list_for_each_entry(new_device, &darwin_cached_devices, list, struct darwin_cached_device) { usbi_dbg("matching sessionID 0x%x against cached device with sessionID 0x%x", sessionID, new_device->session); if (new_device->session == sessionID) { @@ -773,17 +774,15 @@ static int darwin_get_cached_device(struct libusb_context *ctx, io_service_t ser usbi_dbg("caching new device with sessionID 0x%x\n", sessionID); - new_device = calloc (1, sizeof (*new_device)); - if (!new_device) { - ret = LIBUSB_ERROR_NO_MEM; - break; - } - device = darwin_device_from_service (service); if (!device) { ret = LIBUSB_ERROR_NO_DEVICE; - free (new_device); - new_device = NULL; + break; + } + + new_device = calloc (1, sizeof (*new_device)); + if (!new_device) { + ret = LIBUSB_ERROR_NO_MEM; break; } @@ -833,7 +832,7 @@ static int process_new_device (struct libusb_context *ctx, io_service_t service) do { ret = darwin_get_cached_device (ctx, service, &cached_device); - if (ret < 0 || (cached_device && !cached_device->can_enumerate)) { + if (ret < 0 || !cached_device->can_enumerate) { return ret; } @@ -846,7 +845,7 @@ static int process_new_device (struct libusb_context *ctx, io_service_t service) usbi_dbg ("allocating new device in context %p for with session 0x%08x", ctx, cached_device->session); - dev = usbi_alloc_device(ctx, cached_device->session); + dev = usbi_alloc_device(ctx, (unsigned long) cached_device->session); if (!dev) { return LIBUSB_ERROR_NO_MEM; } @@ -857,7 +856,7 @@ static int process_new_device (struct libusb_context *ctx, io_service_t service) darwin_ref_cached_device (priv->dev); if (cached_device->parent_session > 0) { - dev->parent_dev = usbi_get_device_by_session_id (ctx, cached_device->parent_session); + dev->parent_dev = usbi_get_device_by_session_id (ctx, (unsigned long) cached_device->parent_session); } else { dev->parent_dev = NULL; } diff --git a/third_party/libusb/src/libusb/os/linux_netlink.c b/third_party/libusb/src/libusb/os/linux_netlink.c index 3a68f69..f1c1be1 100644 --- a/third_party/libusb/src/libusb/os/linux_netlink.c +++ b/third_party/libusb/src/libusb/os/linux_netlink.c @@ -21,6 +21,10 @@ */ #include "config.h" +#include "libusb.h" +#include "libusbi.h" +#include "linux_usbfs.h" + #include <ctype.h> #include <dirent.h> #include <errno.h> @@ -30,46 +34,113 @@ #include <stdlib.h> #include <string.h> #include <sys/types.h> + +#ifdef HAVE_ASM_TYPES_H +#include <asm/types.h> +#endif + +#ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> -#include <arpa/inet.h> +#endif -#include "libusb.h" -#include "libusbi.h" -#include "linux_usbfs.h" +#include <arpa/inet.h> +#ifdef HAVE_LINUX_NETLINK_H #include <linux/netlink.h> +#endif + +#ifdef HAVE_LINUX_FILTER_H #include <linux/filter.h> +#endif #define KERNEL 1 static int linux_netlink_socket = -1; +static int netlink_control_pipe[2] = { -1, -1 }; static pthread_t libusb_linux_event_thread; static void *linux_netlink_event_thread_main(void *arg); struct sockaddr_nl snl = { .nl_family=AF_NETLINK, .nl_groups=KERNEL }; +static int set_fd_cloexec_nb (int fd) +{ + int flags; + +#if defined(FD_CLOEXEC) + flags = fcntl (linux_netlink_socket, F_GETFD); + if (0 > flags) { + return -1; + } + + if (!(flags & FD_CLOEXEC)) { + fcntl (linux_netlink_socket, F_SETFD, flags | FD_CLOEXEC); + } +#endif + + flags = fcntl (linux_netlink_socket, F_GETFL); + if (0 > flags) { + return -1; + } + + if (!(flags & O_NONBLOCK)) { + fcntl (linux_netlink_socket, F_SETFL, flags | O_NONBLOCK); + } + + return 0; +} + int linux_netlink_start_event_monitor(void) { + int socktype = SOCK_RAW; int ret; snl.nl_groups = KERNEL; - linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT); +#if defined(SOCK_CLOEXEC) + socktype |= SOCK_CLOEXEC; +#endif +#if defined(SOCK_NONBLOCK) + socktype |= SOCK_NONBLOCK; +#endif + + linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT); + if (-1 == linux_netlink_socket && EINVAL == errno) { + linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT); + } + if (-1 == linux_netlink_socket) { return LIBUSB_ERROR_OTHER; } + ret = set_fd_cloexec_nb (linux_netlink_socket); + if (0 != ret) { + close (linux_netlink_socket); + linux_netlink_socket = -1; + return LIBUSB_ERROR_OTHER; + } + ret = bind(linux_netlink_socket, (struct sockaddr *) &snl, sizeof(snl)); if (0 != ret) { + close(linux_netlink_socket); return LIBUSB_ERROR_OTHER; } /* TODO -- add authentication */ /* setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); */ + ret = usbi_pipe(netlink_control_pipe); + if (ret) { + usbi_err(NULL, "could not create netlink control pipe"); + close(linux_netlink_socket); + return LIBUSB_ERROR_OTHER; + } + ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL); if (0 != ret) { + close(netlink_control_pipe[0]); + close(netlink_control_pipe[1]); + close(linux_netlink_socket); return LIBUSB_ERROR_OTHER; } @@ -79,22 +150,30 @@ int linux_netlink_start_event_monitor(void) int linux_netlink_stop_event_monitor(void) { int r; + char dummy = 1; if (-1 == linux_netlink_socket) { /* already closed. nothing to do */ return LIBUSB_SUCCESS; } - r = close(linux_netlink_socket); - if (0 > r) { - usbi_err(NULL, "error closing netlink socket. %s", strerror(errno)); - return LIBUSB_ERROR_OTHER; + /* Write some dummy data to the control pipe and + * wait for the thread to exit */ + r = usbi_write(netlink_control_pipe[1], &dummy, sizeof(dummy)); + if (r <= 0) { + usbi_warn(NULL, "netlink control pipe signal failed"); } + pthread_join(libusb_linux_event_thread, NULL); - pthread_cancel(libusb_linux_event_thread); - + close(linux_netlink_socket); linux_netlink_socket = -1; + /* close and reset control pipe */ + close(netlink_control_pipe[0]); + close(netlink_control_pipe[1]); + netlink_control_pipe[0] = -1; + netlink_control_pipe[1] = -1; + return LIBUSB_SUCCESS; } @@ -214,7 +293,7 @@ static int linux_netlink_read_message(void) /* signal device is available (or not) to all contexts */ if (detached) - linux_hotplug_disconnected(busnum, devaddr, sys_name); + linux_device_disconnected(busnum, devaddr, sys_name); else linux_hotplug_enumerate(busnum, devaddr, sys_name); @@ -223,20 +302,32 @@ static int linux_netlink_read_message(void) static void *linux_netlink_event_thread_main(void *arg) { - struct pollfd fds = {.fd = linux_netlink_socket, - .events = POLLIN}; + char dummy; + int r; + struct pollfd fds[] = { + { .fd = netlink_control_pipe[0], + .events = POLLIN }, + { .fd = linux_netlink_socket, + .events = POLLIN }, + }; /* silence compiler warning */ (void) arg; - while (1 == poll(&fds, 1, -1)) { - if (POLLIN != fds.revents) { + while (poll(fds, 2, -1) >= 0) { + if (fds[0].revents & POLLIN) { + /* activity on control pipe, read the byte and exit */ + r = usbi_read(netlink_control_pipe[0], &dummy, sizeof(dummy)); + if (r <= 0) { + usbi_warn(NULL, "netlink control pipe read failed"); + } break; } - - usbi_mutex_static_lock(&linux_hotplug_lock); - linux_netlink_read_message(); - usbi_mutex_static_unlock(&linux_hotplug_lock); + if (fds[1].revents & POLLIN) { + usbi_mutex_static_lock(&linux_hotplug_lock); + linux_netlink_read_message(); + usbi_mutex_static_unlock(&linux_hotplug_lock); + } } return NULL; diff --git a/third_party/libusb/src/libusb/os/linux_udev.c b/third_party/libusb/src/libusb/os/linux_udev.c index 5a2aadf..99ac943 100644 --- a/third_party/libusb/src/libusb/os/linux_udev.c +++ b/third_party/libusb/src/libusb/os/linux_udev.c @@ -46,6 +46,7 @@ /* udev context */ static struct udev *udev_ctx = NULL; static int udev_monitor_fd = -1; +static int udev_control_pipe[2] = {-1, -1}; static struct udev_monitor *udev_monitor = NULL; static pthread_t linux_event_thread; @@ -95,14 +96,23 @@ int linux_udev_start_event_monitor(void) goto err_free_monitor; } + r = usbi_pipe(udev_control_pipe); + if (r) { + usbi_err(NULL, "could not create udev control pipe"); + goto err_free_monitor; + } + r = pthread_create(&linux_event_thread, NULL, linux_udev_event_thread_main, NULL); if (r) { usbi_err(NULL, "creating hotplug event thread (%d)", r); - goto err_free_monitor; + goto err_close_pipe; } return LIBUSB_SUCCESS; +err_close_pipe: + close(udev_control_pipe[0]); + close(udev_control_pipe[1]); err_free_monitor: udev_monitor_unref(udev_monitor); udev_monitor = NULL; @@ -115,14 +125,19 @@ err_free_ctx: int linux_udev_stop_event_monitor(void) { + char dummy = 1; + int r; + assert(udev_ctx != NULL); assert(udev_monitor != NULL); assert(udev_monitor_fd != -1); - /* Cancel the event thread. This is the only way to guarantee the - thread exits since closing the monitor fd won't necessarily cause - poll to return. */ - pthread_cancel(linux_event_thread); + /* Write some dummy data to the control pipe and + * wait for the thread to exit */ + r = usbi_write(udev_control_pipe[1], &dummy, sizeof(dummy)); + if (r <= 0) { + usbi_warn(NULL, "udev control pipe signal failed"); + } pthread_join(linux_event_thread, NULL); /* Release the udev monitor */ @@ -134,27 +149,45 @@ int linux_udev_stop_event_monitor(void) udev_unref(udev_ctx); udev_ctx = NULL; + /* close and reset control pipe */ + close(udev_control_pipe[0]); + close(udev_control_pipe[1]); + udev_control_pipe[0] = -1; + udev_control_pipe[1] = -1; + return LIBUSB_SUCCESS; } static void *linux_udev_event_thread_main(void *arg) { + char dummy; + int r; struct udev_device* udev_dev; - struct pollfd fds = {.fd = udev_monitor_fd, - .events = POLLIN}; + struct pollfd fds[] = { + {.fd = udev_control_pipe[0], + .events = POLLIN}, + {.fd = udev_monitor_fd, + .events = POLLIN}, + }; usbi_dbg("udev event thread entering."); - while (1 == poll(&fds, 1, -1)) { - if (NULL == udev_monitor || POLLIN != fds.revents) { + while (poll(fds, 2, -1) >= 0) { + if (fds[0].revents & POLLIN) { + /* activity on control pipe, read the byte and exit */ + r = usbi_read(udev_control_pipe[0], &dummy, sizeof(dummy)); + if (r <= 0) { + usbi_warn(NULL, "udev control pipe read failed"); + } break; } - - usbi_mutex_static_lock(&linux_hotplug_lock); - udev_dev = udev_monitor_receive_device(udev_monitor); - if (udev_dev) - udev_hotplug_event(udev_dev); - usbi_mutex_static_unlock(&linux_hotplug_lock); + if (fds[1].revents & POLLIN) { + usbi_mutex_static_lock(&linux_hotplug_lock); + udev_dev = udev_monitor_receive_device(udev_monitor); + if (udev_dev) + udev_hotplug_event(udev_dev); + usbi_mutex_static_unlock(&linux_hotplug_lock); + } } usbi_dbg("udev event thread exiting"); @@ -207,7 +240,7 @@ static void udev_hotplug_event(struct udev_device* udev_dev) if (strncmp(udev_action, "add", 3) == 0) { linux_hotplug_enumerate(busnum, devaddr, sys_name); } else if (detached) { - linux_hotplug_disconnected(busnum, devaddr, sys_name); + linux_device_disconnected(busnum, devaddr, sys_name); } else { usbi_err(NULL, "ignoring udev action %s", udev_action); } diff --git a/third_party/libusb/src/libusb/os/linux_usbfs.c b/third_party/libusb/src/libusb/os/linux_usbfs.c index 09288af..142fa2b 100644 --- a/third_party/libusb/src/libusb/os/linux_usbfs.c +++ b/third_party/libusb/src/libusb/os/linux_usbfs.c @@ -1,3 +1,4 @@ +/* -*- Mode: C; c-basic-offset:8 ; indent-tabs-mode:t -*- */ /* * Linux usbfs backend for libusbx * Copyright © 2007-2009 Daniel Drake <dsd@gentoo.org> @@ -120,7 +121,9 @@ static int sysfs_has_descriptors = -1; /* how many times have we initted (and not exited) ? */ static volatile int init_count = 0; -/* Serialize hotplug start/stop, scan-devices, event-thread, and poll */ +/* Serialize hotplug start/stop */ +usbi_mutex_static_t linux_hotplug_startstop_lock = USBI_MUTEX_INITIALIZER; +/* Serialize scan-devices, event-thread, and poll */ usbi_mutex_static_t linux_hotplug_lock = USBI_MUTEX_INITIALIZER; static int linux_start_event_monitor(void); @@ -419,7 +422,7 @@ static int op_init(struct libusb_context *ctx) if (sysfs_has_descriptors) usbi_dbg("sysfs has complete descriptors"); - usbi_mutex_static_lock(&linux_hotplug_lock); + usbi_mutex_static_lock(&linux_hotplug_startstop_lock); r = LIBUSB_SUCCESS; if (init_count == 0) { /* start up hotplug event handler */ @@ -433,20 +436,20 @@ static int op_init(struct libusb_context *ctx) linux_stop_event_monitor(); } else usbi_err(ctx, "error starting hotplug event monitor"); - usbi_mutex_static_unlock(&linux_hotplug_lock); + usbi_mutex_static_unlock(&linux_hotplug_startstop_lock); return r; } static void op_exit(void) { - usbi_mutex_static_lock(&linux_hotplug_lock); + usbi_mutex_static_lock(&linux_hotplug_startstop_lock); assert(init_count != 0); if (!--init_count) { /* tear down event handler */ (void)linux_stop_event_monitor(); } - usbi_mutex_static_unlock(&linux_hotplug_lock); + usbi_mutex_static_unlock(&linux_hotplug_startstop_lock); } static int linux_start_event_monitor(void) @@ -469,11 +472,19 @@ static int linux_stop_event_monitor(void) static int linux_scan_devices(struct libusb_context *ctx) { + int ret; + + usbi_mutex_static_lock(&linux_hotplug_lock); + #if defined(USE_UDEV) - return linux_udev_scan_devices(ctx); + ret = linux_udev_scan_devices(ctx); #else - return linux_default_scan_devices(ctx); + ret = linux_default_scan_devices(ctx); #endif + + usbi_mutex_static_unlock(&linux_hotplug_lock); + + return ret; } static void op_hotplug_poll(void) @@ -596,6 +607,8 @@ 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) { + int sysfs_attr; + 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 */ @@ -616,17 +629,22 @@ int linux_get_device_address (struct libusb_context *ctx, int detached, usbi_dbg("scan %s", sys_name); - *busnum = __read_sysfs_attr(ctx, sys_name, "busnum"); - if (0 > *busnum) - return *busnum; + sysfs_attr = __read_sysfs_attr(ctx, sys_name, "busnum"); + if (0 > sysfs_attr) + return sysfs_attr; + if (sysfs_attr > 255) + return LIBUSB_ERROR_INVALID_PARAM; + *busnum = (uint8_t) sysfs_attr; + + sysfs_attr = __read_sysfs_attr(ctx, sys_name, "devnum"); + if (0 > sysfs_attr) + return sysfs_attr; + if (sysfs_attr > 255) + return LIBUSB_ERROR_INVALID_PARAM; - *devaddr = __read_sysfs_attr(ctx, sys_name, "devnum"); - if (0 > *devaddr) - return *devaddr; + *devaddr = (uint8_t) sysfs_attr; usbi_dbg("bus=%d dev=%d", *busnum, *devaddr); - if (*busnum > 255 || *devaddr > 255) - return LIBUSB_ERROR_INVALID_PARAM; return LIBUSB_SUCCESS; } @@ -1072,7 +1090,7 @@ void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_na usbi_mutex_static_unlock(&active_contexts_lock); } -void linux_hotplug_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name) +void linux_device_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name) { struct libusb_context *ctx; struct libusb_device *dev; @@ -1247,8 +1265,20 @@ static int op_open(struct libusb_device_handle *handle) int r; hpriv->fd = _get_usbfs_fd(handle->dev, O_RDWR, 0); - if (hpriv->fd < 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, NULL); + } + usbi_mutex_static_unlock(&linux_hotplug_lock); + } return hpriv->fd; + } r = ioctl(hpriv->fd, IOCTL_USBFS_GET_CAPABILITIES, &hpriv->caps); if (r < 0) { @@ -2482,6 +2512,13 @@ static int op_handle_events(struct libusb_context *ctx, if (pollfd->revents & POLLERR) { usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fd); usbi_handle_disconnect(handle); + /* 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) + linux_device_disconnected(handle->dev->bus_number, + handle->dev->device_address, NULL); + usbi_mutex_static_unlock(&linux_hotplug_lock); continue; } diff --git a/third_party/libusb/src/libusb/os/linux_usbfs.h b/third_party/libusb/src/libusb/os/linux_usbfs.h index 499bab7..1f5b191 100644 --- a/third_party/libusb/src/libusb/os/linux_usbfs.h +++ b/third_party/libusb/src/libusb/os/linux_usbfs.h @@ -170,7 +170,7 @@ void linux_netlink_hotplug_poll(void); #endif void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name); -void linux_hotplug_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name); +void linux_device_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name); int linux_get_device_address (struct libusb_context *ctx, int detached, uint8_t *busnum, uint8_t *devaddr, const char *dev_node, diff --git a/third_party/libusb/src/libusb/os/openbsd_usb.c b/third_party/libusb/src/libusb/os/openbsd_usb.c index f4fd454..2997e53 100644 --- a/third_party/libusb/src/libusb/os/openbsd_usb.c +++ b/third_party/libusb/src/libusb/os/openbsd_usb.c @@ -1,5 +1,5 @@ /* - * Copyright © 2011 Martin Pieuchot <mpi@openbsd.org> + * Copyright © 2011-2013 Martin Pieuchot <mpi@openbsd.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -32,8 +32,8 @@ #include "libusbi.h" struct device_priv { - char devnode[16]; - int fd; + char *devname; /* name of the ugen(4) node */ + int fd; /* device file descriptor */ unsigned char *cdesc; /* active config descriptor */ usb_device_descriptor_t ddesc; /* usb device descriptor */ @@ -82,11 +82,14 @@ static int obsd_clock_gettime(int, struct timespec *); * Private functions */ static int _errno_to_libusb(int); -static int _cache_active_config_descriptor(struct libusb_device *, int); +static int _cache_active_config_descriptor(struct libusb_device *); static int _sync_control_transfer(struct usbi_transfer *); static int _sync_gen_transfer(struct usbi_transfer *); static int _access_endpoint(struct libusb_transfer *); +static int _bus_open(int); + + const struct usbi_os_backend openbsd_backend = { "Synchronous OpenBSD backend", 0, @@ -131,79 +134,105 @@ const struct usbi_os_backend openbsd_backend = { 0, /* add_iso_packet_size */ }; +#define DEVPATH "/dev/" +#define USBDEV DEVPATH "usb" + int obsd_get_device_list(struct libusb_context * ctx, struct discovered_devs **discdevs) { + struct discovered_devs *ddd; struct libusb_device *dev; struct device_priv *dpriv; struct usb_device_info di; + struct usb_device_ddesc dd; unsigned long session_id; - char devnode[16]; - int fd, err, i; + char devices[USB_MAX_DEVICES]; + char busnode[16]; + char *udevname; + int fd, addr, i, j; usbi_dbg(""); - /* Only ugen(4) is supported */ - for (i = 0; i < USB_MAX_DEVICES; i++) { - /* Control endpoint is always .00 */ - snprintf(devnode, sizeof(devnode), "/dev/ugen%d.00", i); + for (i = 0; i < 8; i++) { + snprintf(busnode, sizeof(busnode), USBDEV "%d", i); - if ((fd = open(devnode, O_RDONLY)) < 0) { + if ((fd = open(busnode, O_RDWR)) < 0) { if (errno != ENOENT && errno != ENXIO) - usbi_err(ctx, "could not open %s", devnode); + usbi_err(ctx, "could not open %s", busnode); continue; } - if (ioctl(fd, USB_GET_DEVICEINFO, &di) < 0) - continue; - - session_id = (di.udi_bus << 8 | di.udi_addr); - dev = usbi_get_device_by_session_id(ctx, session_id); - - if (dev) { - dev = libusb_ref_device(dev); - } else { - dev = usbi_alloc_device(ctx, session_id); - if (dev == NULL) - return (LIBUSB_ERROR_NO_MEM); - - dev->bus_number = di.udi_bus; - dev->device_address = di.udi_addr; - dev->speed = di.udi_speed; - - dpriv = (struct device_priv *)dev->os_priv; - strlcpy(dpriv->devnode, devnode, sizeof(devnode)); - dpriv->fd = -1; - - if (ioctl(fd, USB_GET_DEVICE_DESC, &dpriv->ddesc) < 0) { - err = errno; - goto error; + bzero(devices, sizeof(devices)); + for (addr = 1; addr < USB_MAX_DEVICES; addr++) { + if (devices[addr]) + continue; + + di.udi_addr = addr; + if (ioctl(fd, USB_DEVICEINFO, &di) < 0) + continue; + + /* + * XXX If ugen(4) is attached to the USB device + * it will be used. + */ + udevname = NULL; + for (j = 0; j < USB_MAX_DEVNAMES; j++) + if (!strncmp("ugen", di.udi_devnames[j], 4)) { + udevname = strdup(di.udi_devnames[j]); + break; + } + + session_id = (di.udi_bus << 8 | di.udi_addr); + dev = usbi_get_device_by_session_id(ctx, session_id); + + if (dev == NULL) { + dev = usbi_alloc_device(ctx, session_id); + if (dev == NULL) { + close(fd); + return (LIBUSB_ERROR_NO_MEM); + } + + dev->bus_number = di.udi_bus; + dev->device_address = di.udi_addr; + dev->speed = di.udi_speed; + + dpriv = (struct device_priv *)dev->os_priv; + dpriv->fd = -1; + dpriv->cdesc = NULL; + dpriv->devname = udevname; + + dd.udd_bus = di.udi_bus; + dd.udd_addr = di.udi_addr; + if (ioctl(fd, USB_DEVICE_GET_DDESC, &dd) < 0) { + libusb_unref_device(dev); + continue; + } + dpriv->ddesc = dd.udd_desc; + + if (_cache_active_config_descriptor(dev)) { + libusb_unref_device(dev); + continue; + } + + if (usbi_sanitize_device(dev)) + libusb_unref_device(dev); } - dpriv->cdesc = NULL; - if (_cache_active_config_descriptor(dev, fd)) { - err = errno; - goto error; + ddd = discovered_devs_append(*discdevs, dev); + if (ddd == NULL) { + close(fd); + return (LIBUSB_ERROR_NO_MEM); } - if ((err = usbi_sanitize_device(dev))) - goto error; + *discdevs = ddd; + devices[addr] = 1; } - close(fd); - if (discovered_devs_append(*discdevs, dev) == NULL) - return (LIBUSB_ERROR_NO_MEM); - - libusb_unref_device(dev); + close(fd); } return (LIBUSB_SUCCESS); - -error: - close(fd); - libusb_unref_device(dev); - return _errno_to_libusb(err); } int @@ -211,15 +240,21 @@ obsd_open(struct libusb_device_handle *handle) { struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; + char devnode[16]; - dpriv->fd = open(dpriv->devnode, O_RDWR); - if (dpriv->fd < 0) { - dpriv->fd = open(dpriv->devnode, O_RDONLY); + if (dpriv->devname) { + /* + * Only open ugen(4) attached devices read-write, all + * read-only operations are done through the bus node. + */ + snprintf(devnode, sizeof(devnode), DEVPATH "%s.00", + dpriv->devname); + dpriv->fd = open(devnode, O_RDWR); if (dpriv->fd < 0) return _errno_to_libusb(errno); - } - usbi_dbg("open %s: fd %d", dpriv->devnode, dpriv->fd); + usbi_dbg("open %s: fd %d", devnode, dpriv->fd); + } if (pipe(hpriv->pipe) < 0) return _errno_to_libusb(errno); @@ -233,10 +268,12 @@ obsd_close(struct libusb_device_handle *handle) struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; - usbi_dbg("close: fd %d", dpriv->fd); + if (dpriv->devname) { + usbi_dbg("close: fd %d", dpriv->fd); - close(dpriv->fd); - dpriv->fd = -1; + close(dpriv->fd); + dpriv->fd = -1; + } usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->pipe[0]); @@ -264,9 +301,8 @@ obsd_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buf, size_t len, int *host_endian) { struct device_priv *dpriv = (struct device_priv *)dev->os_priv; - usb_config_descriptor_t *ucd; + usb_config_descriptor_t *ucd = (usb_config_descriptor_t *)dpriv->cdesc; - ucd = (usb_config_descriptor_t *) dpriv->cdesc; len = MIN(len, UGETW(ucd->wTotalLength)); usbi_dbg("len %d", len); @@ -275,58 +311,48 @@ obsd_get_active_config_descriptor(struct libusb_device *dev, *host_endian = 0; - return len; + return (len); } int obsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx, unsigned char *buf, size_t len, int *host_endian) { - struct device_priv *dpriv = (struct device_priv *)dev->os_priv; - struct usb_full_desc ufd; + struct usb_device_fdesc udf; int fd, err; - usbi_dbg("index %d, len %d", idx, len); + if ((fd = _bus_open(dev->bus_number)) < 0) + return _errno_to_libusb(errno); - /* A config descriptor may be requested before opening the device */ - if (dpriv->fd >= 0) { - fd = dpriv->fd; - } else { - fd = open(dpriv->devnode, O_RDONLY); - if (fd < 0) - return _errno_to_libusb(errno); - } + udf.udf_bus = dev->bus_number; + udf.udf_addr = dev->device_address; + udf.udf_config_index = idx; + udf.udf_size = len; + udf.udf_data = buf; - ufd.ufd_config_index = idx; - ufd.ufd_size = len; - ufd.ufd_data = buf; + usbi_dbg("index %d, len %d", udf.udf_config_index, len); - if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) { + if (ioctl(fd, USB_DEVICE_GET_FDESC, &udf) < 0) { err = errno; - if (dpriv->fd < 0) - close(fd); + close(fd); return _errno_to_libusb(err); } - - if (dpriv->fd < 0) - close(fd); + close(fd); *host_endian = 0; - return len; + return (len); } int obsd_get_configuration(struct libusb_device_handle *handle, int *config) { struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; + usb_config_descriptor_t *ucd = (usb_config_descriptor_t *)dpriv->cdesc; - usbi_dbg(""); + *config = ucd->bConfigurationValue; - if (ioctl(dpriv->fd, USB_GET_CONFIG, config) < 0) - return _errno_to_libusb(errno); - - usbi_dbg("configuration %d", *config); + usbi_dbg("bConfigurationValue %d", *config); return (LIBUSB_SUCCESS); } @@ -336,12 +362,15 @@ obsd_set_configuration(struct libusb_device_handle *handle, int config) { struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; - usbi_dbg("configuration %d", config); + if (dpriv->devname == NULL) + return (LIBUSB_ERROR_NOT_SUPPORTED); + + usbi_dbg("bConfigurationValue %d", config); if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0) return _errno_to_libusb(errno); - return _cache_active_config_descriptor(handle->dev, dpriv->fd); + return _cache_active_config_descriptor(handle->dev); } int @@ -376,6 +405,9 @@ obsd_set_interface_altsetting(struct libusb_device_handle *handle, int iface, struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; struct usb_alt_interface intf; + if (dpriv->devname == NULL) + return (LIBUSB_ERROR_NOT_SUPPORTED); + usbi_dbg("iface %d, setting %d", iface, altsetting); memset(&intf, 0, sizeof(intf)); @@ -392,19 +424,27 @@ obsd_set_interface_altsetting(struct libusb_device_handle *handle, int iface, int obsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint) { - struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; struct usb_ctl_request req; + int fd, err; + + if ((fd = _bus_open(handle->dev->bus_number)) < 0) + return _errno_to_libusb(errno); usbi_dbg(""); + req.ucr_addr = handle->dev->device_address; req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT; req.ucr_request.bRequest = UR_CLEAR_FEATURE; USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT); USETW(req.ucr_request.wIndex, endpoint); USETW(req.ucr_request.wLength, 0); - if (ioctl(dpriv->fd, USB_DO_REQUEST, &req) < 0) - return _errno_to_libusb(errno); + if (ioctl(fd, USB_REQUEST, &req) < 0) { + err = errno; + close(fd); + return _errno_to_libusb(err); + } + close(fd); return (LIBUSB_SUCCESS); } @@ -425,6 +465,7 @@ obsd_destroy_device(struct libusb_device *dev) usbi_dbg(""); free(dpriv->cdesc); + free(dpriv->devname); } int @@ -564,6 +605,8 @@ obsd_clock_gettime(int clkid, struct timespec *tp) int _errno_to_libusb(int err) { + usbi_dbg("error: %s (%d)", strerror(err), err); + switch (err) { case EIO: return (LIBUSB_ERROR_IO); @@ -573,52 +616,64 @@ _errno_to_libusb(int err) return (LIBUSB_ERROR_NO_DEVICE); case ENOMEM: return (LIBUSB_ERROR_NO_MEM); + case ETIMEDOUT: + return (LIBUSB_ERROR_TIMEOUT); } - usbi_dbg("error: %s", strerror(err)); - return (LIBUSB_ERROR_OTHER); } int -_cache_active_config_descriptor(struct libusb_device *dev, int fd) +_cache_active_config_descriptor(struct libusb_device *dev) { struct device_priv *dpriv = (struct device_priv *)dev->os_priv; - struct usb_config_desc ucd; - struct usb_full_desc ufd; + struct usb_device_cdesc udc; + struct usb_device_fdesc udf; unsigned char* buf; - int len; + int fd, len, err; - usbi_dbg("fd %d", fd); + if ((fd = _bus_open(dev->bus_number)) < 0) + return _errno_to_libusb(errno); - ucd.ucd_config_index = USB_CURRENT_CONFIG_INDEX; + usbi_dbg("fd %d, addr %d", fd, dev->device_address); - if ((ioctl(fd, USB_GET_CONFIG_DESC, &ucd)) < 0) + udc.udc_bus = dev->bus_number; + udc.udc_addr = dev->device_address; + udc.udc_config_index = USB_CURRENT_CONFIG_INDEX; + if (ioctl(fd, USB_DEVICE_GET_CDESC, &udc) < 0) { + err = errno; + close(fd); return _errno_to_libusb(errno); + } - usbi_dbg("active bLength %d", ucd.ucd_desc.bLength); + usbi_dbg("active bLength %d", udc.udc_desc.bLength); - len = UGETW(ucd.ucd_desc.wTotalLength); + len = UGETW(udc.udc_desc.wTotalLength); buf = malloc(len); if (buf == NULL) return (LIBUSB_ERROR_NO_MEM); - ufd.ufd_config_index = ucd.ucd_config_index; - ufd.ufd_size = len; - ufd.ufd_data = buf; + udf.udf_bus = dev->bus_number; + udf.udf_addr = dev->device_address; + udf.udf_config_index = udc.udc_config_index; + udf.udf_size = len; + udf.udf_data = buf; - usbi_dbg("index %d, len %d", ufd.ufd_config_index, len); + usbi_dbg("index %d, len %d", udf.udf_config_index, len); - if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) { + if (ioctl(fd, USB_DEVICE_GET_FDESC, &udf) < 0) { + err = errno; + close(fd); free(buf); - return _errno_to_libusb(errno); + return _errno_to_libusb(err); } + close(fd); if (dpriv->cdesc) free(dpriv->cdesc); dpriv->cdesc = buf; - return (0); + return (LIBUSB_SUCCESS); } int @@ -633,12 +688,13 @@ _sync_control_transfer(struct usbi_transfer *itransfer) dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv; setup = (struct libusb_control_setup *)transfer->buffer; - usbi_dbg("type %d request %d value %d index %d length %d timeout %d", + usbi_dbg("type %x request %x value %x index %d length %d timeout %d", setup->bmRequestType, setup->bRequest, libusb_le16_to_cpu(setup->wValue), libusb_le16_to_cpu(setup->wIndex), libusb_le16_to_cpu(setup->wLength), transfer->timeout); + req.ucr_addr = transfer->dev_handle->dev->device_address; req.ucr_request.bmRequestType = setup->bmRequestType; req.ucr_request.bRequest = setup->bRequest; /* Don't use USETW, libusbx already deals with the endianness */ @@ -650,11 +706,30 @@ _sync_control_transfer(struct usbi_transfer *itransfer) if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0) req.ucr_flags = USBD_SHORT_XFER_OK; - if ((ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0) - return _errno_to_libusb(errno); + if (dpriv->devname == NULL) { + /* + * XXX If the device is not attached to ugen(4) it is + * XXX still possible to submit a control transfer but + * XXX with the default timeout only. + */ + int fd, err; - if ((ioctl(dpriv->fd, USB_DO_REQUEST, &req)) < 0) - return _errno_to_libusb(errno); + if ((fd = _bus_open(transfer->dev_handle->dev->bus_number)) < 0) + return _errno_to_libusb(errno); + + if ((ioctl(fd, USB_REQUEST, &req)) < 0) { + err = errno; + close(fd); + return _errno_to_libusb(err); + } + close(fd); + } else { + if ((ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0) + return _errno_to_libusb(errno); + + if ((ioctl(dpriv->fd, USB_DO_REQUEST, &req)) < 0) + return _errno_to_libusb(errno); + } itransfer->transferred = req.ucr_actlen; @@ -668,7 +743,7 @@ _access_endpoint(struct libusb_transfer *transfer) { struct handle_priv *hpriv; struct device_priv *dpriv; - char *s, devnode[16]; + char devnode[16]; int fd, endpt; mode_t mode; @@ -681,10 +756,9 @@ _access_endpoint(struct libusb_transfer *transfer) usbi_dbg("endpoint %d mode %d", endpt, mode); if (hpriv->endpoints[endpt] < 0) { - /* Pick the right node given the control one */ - strlcpy(devnode, dpriv->devnode, sizeof(devnode)); - s = strchr(devnode, '.'); - snprintf(s, 4, ".%02d", endpt); + /* Pick the right endpoint node */ + snprintf(devnode, sizeof(devnode), DEVPATH "%s.%02d", + dpriv->devname, endpt); /* We may need to read/write to the same endpoint later. */ if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO)) @@ -701,9 +775,14 @@ int _sync_gen_transfer(struct usbi_transfer *itransfer) { struct libusb_transfer *transfer; + struct device_priv *dpriv; int fd, nr = 1; transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv; + + if (dpriv->devname == NULL) + return (LIBUSB_ERROR_NOT_SUPPORTED); /* * Bulk, Interrupt or Isochronous transfer depends on the @@ -732,3 +811,13 @@ _sync_gen_transfer(struct usbi_transfer *itransfer) return (0); } + +int +_bus_open(int number) +{ + char busnode[16]; + + snprintf(busnode, sizeof(busnode), USBDEV "%d", number); + + return open(busnode, O_RDWR); +} diff --git a/third_party/libusb/src/libusb/os/poll_posix.h b/third_party/libusb/src/libusb/os/poll_posix.h index 64c9bb7..5b4b2c9 100644 --- a/third_party/libusb/src/libusb/os/poll_posix.h +++ b/third_party/libusb/src/libusb/os/poll_posix.h @@ -1,19 +1,3 @@ -/* - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - #ifndef LIBUSB_POLL_POSIX_H #define LIBUSB_POLL_POSIX_H diff --git a/third_party/libusb/src/libusb/os/poll_windows.c b/third_party/libusb/src/libusb/os/poll_windows.c index 7ed19ba..abe8761 100644 --- a/third_party/libusb/src/libusb/os/poll_windows.c +++ b/third_party/libusb/src/libusb/os/poll_windows.c @@ -428,7 +428,7 @@ struct winfd fd_to_winfd(int fd) CHECK_INIT_POLLING; - if (fd <= 0) + if (fd < 0) return INVALID_WINFD; for (i=0; i<MAX_FDS; i++) { diff --git a/third_party/libusb/src/libusb/os/threads_posix.c b/third_party/libusb/src/libusb/os/threads_posix.c index 46f6db7..cd985fa 100644 --- a/third_party/libusb/src/libusb/os/threads_posix.c +++ b/third_party/libusb/src/libusb/os/threads_posix.c @@ -58,7 +58,9 @@ finish: int usbi_get_tid(void) { int ret = -1; -#if defined(__linux__) +#if defined(__ANDROID__) + ret = gettid(); +#elif defined(__linux__) ret = syscall(SYS_gettid); #elif defined(__OpenBSD__) /* The following only works with OpenBSD > 5.1 as it requires diff --git a/third_party/libusb/src/libusb/os/wince_usb.c b/third_party/libusb/src/libusb/os/wince_usb.c index e4a6633..90c129b 100644 --- a/third_party/libusb/src/libusb/os/wince_usb.c +++ b/third_party/libusb/src/libusb/os/wince_usb.c @@ -234,6 +234,12 @@ static int wince_init(struct libusb_context *ctx) usbi_err(ctx, "Unable to create timer thread - aborting"); goto init_exit; } + + // Wait for timer thread to init before continuing. + if (WaitForSingleObject(timer_response, INFINITE) != WAIT_OBJECT_0) { + usbi_err(ctx, "Failed to wait for timer thread to become ready - aborting"); + goto init_exit; + } } // At this stage, either we went through full init successfully, or didn't need to r = LIBUSB_SUCCESS; @@ -877,6 +883,11 @@ unsigned __stdcall wince_clock_gettime_threaded(void* param) usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency); } + // Signal wince_init() that we're ready to service requests + if (ReleaseSemaphore(timer_response, 1, NULL) == 0) { + usbi_dbg("unable to release timer semaphore: %s", windows_error_str(0)); + } + // Main loop - wait for requests while (1) { timer_index = WaitForMultipleObjects(2, timer_request, FALSE, INFINITE) - WAIT_OBJECT_0; @@ -911,7 +922,7 @@ unsigned __stdcall wince_clock_gettime_threaded(void* param) nb_responses = InterlockedExchange((LONG*)&request_count[0], 0); if ( (nb_responses) && (ReleaseSemaphore(timer_response, nb_responses, NULL) == 0) ) { - usbi_dbg("unable to release timer semaphore %d: %s", windows_error_str(0)); + usbi_dbg("unable to release timer semaphore: %s", windows_error_str(0)); } continue; case 1: // time to quit diff --git a/third_party/libusb/src/libusb/os/windows_usb.c b/third_party/libusb/src/libusb/os/windows_usb.c index 51ce55d..9ae11b1 100644 --- a/third_party/libusb/src/libusb/os/windows_usb.c +++ b/third_party/libusb/src/libusb/os/windows_usb.c @@ -886,6 +886,12 @@ static int windows_init(struct libusb_context *ctx) } SetThreadAffinityMask(timer_thread, 0); + // Wait for timer thread to init before continuing. + if (WaitForSingleObject(timer_response, INFINITE) != WAIT_OBJECT_0) { + usbi_err(ctx, "Failed to wait for timer thread to become ready - aborting"); + goto init_exit; + } + // Create a hash table to store session ids. Second parameter is better if prime htab_create(ctx, HTAB_SIZE); } @@ -1759,7 +1765,7 @@ static int windows_get_config_descriptor(struct libusb_device *dev, uint8_t conf memcpy(buffer, priv->config_descriptor[config_index], size); *host_endian = 0; - return size; + return (int)size; } /* @@ -2173,6 +2179,11 @@ unsigned __stdcall windows_clock_gettime_threaded(void* param) usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency); } + // Signal windows_init() that we're ready to service requests + if (ReleaseSemaphore(timer_response, 1, NULL) == 0) { + usbi_dbg("unable to release timer semaphore: %s", windows_error_str(0)); + } + // Main loop - wait for requests while (1) { timer_index = WaitForMultipleObjects(2, timer_request, FALSE, INFINITE) - WAIT_OBJECT_0; @@ -2207,7 +2218,7 @@ unsigned __stdcall windows_clock_gettime_threaded(void* param) nb_responses = InterlockedExchange((LONG*)&request_count[0], 0); if ( (nb_responses) && (ReleaseSemaphore(timer_response, nb_responses, NULL) == 0) ) { - usbi_dbg("unable to release timer semaphore %d: %s", windows_error_str(0)); + usbi_dbg("unable to release timer semaphore: %s", windows_error_str(0)); } continue; case 1: // time to quit diff --git a/third_party/libusb/src/libusb/strerror.c b/third_party/libusb/src/libusb/strerror.c index a3c3afa..0212df8 100644 --- a/third_party/libusb/src/libusb/strerror.c +++ b/third_party/libusb/src/libusb/strerror.c @@ -53,7 +53,7 @@ static size_t usbi_locale = 0; * } * };\endcode </li> * <li> Translate each of the English messages from the section you copied into your language </li> - * <li> Save the file (in UTF-8 format) and send it to \c libusbx-devel@lists.sourceforge.net </li> + * <li> Save the file (in UTF-8 format) and send it to \c libusbx-devel\@lists.sourceforge.net </li> * </ol> */ diff --git a/third_party/libusb/src/libusb/version.h b/third_party/libusb/src/libusb/version.h index fbb9f4c..09d9a9f 100644 --- a/third_party/libusb/src/libusb/version.h +++ b/third_party/libusb/src/libusb/version.h @@ -1,19 +1,3 @@ -/* - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - /* This file is parsed by m4 and windres and RC.EXE so please keep it simple. */ #include "version_nano.h" #ifndef LIBUSB_MAJOR @@ -23,7 +7,7 @@ #define LIBUSB_MINOR 0 #endif #ifndef LIBUSB_MICRO -#define LIBUSB_MICRO 16 +#define LIBUSB_MICRO 17 #endif #ifndef LIBUSB_NANO #define LIBUSB_NANO 0 diff --git a/third_party/libusb/src/libusb/version_nano.h b/third_party/libusb/src/libusb/version_nano.h index 522c6fd..dfa5664 100644 --- a/third_party/libusb/src/libusb/version_nano.h +++ b/third_party/libusb/src/libusb/version_nano.h @@ -1,17 +1 @@ -/* - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#define LIBUSB_NANO 10774 +#define LIBUSB_NANO 10830 |