#include "libusbi.h"
#include "hotplug.h"
-#if defined(OS_LINUX)
-const struct usbi_os_backend * const usbi_backend = &linux_usbfs_backend;
-#elif defined(OS_DARWIN)
-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)
-
-#if defined(USE_USBDK)
-const struct usbi_os_backend * const usbi_backend = &usbdk_backend;
-#else
-const struct usbi_os_backend * const usbi_backend = &windows_backend;
-#endif
-
-#elif defined(OS_WINCE)
-const struct usbi_os_backend * const usbi_backend = &wince_backend;
-#elif defined(OS_HAIKU)
-const struct usbi_os_backend * const usbi_backend = &haiku_usb_raw_backend;
-#else
-#error "Unsupported OS"
-#endif
-
struct libusb_context *usbi_default_context = NULL;
static const struct libusb_version libusb_version_internal =
{ LIBUSB_MAJOR, LIBUSB_MINOR, LIBUSB_MICRO, LIBUSB_NANO,
LIBUSB_RC, "http://libusb.info" };
static int default_context_refcnt = 0;
static usbi_mutex_static_t default_context_lock = USBI_MUTEX_INITIALIZER;
-static struct timeval timestamp_origin = { 0, 0 };
+static struct timespec timestamp_origin = { 0, 0 };
usbi_mutex_static_t active_contexts_lock = USBI_MUTEX_INITIALIZER;
struct list_head active_contexts_list;
/**
* \page libusb_caveats Caveats
*
+ * \section fork Fork considerations
+ *
+ * libusb is <em>not</em> designed to work across fork() calls. Depending on
+ * the platform, there may be resources in the parent process that are not
+ * available to the child (e.g. the hotplug monitor thread on Linux). In
+ * addition, since the parent and child will share libusb's internal file
+ * descriptors, using libusb in any way from the child could cause the parent
+ * process's \ref libusb_context to get into an inconsistent state.
+ *
+ * On Linux, libusb's file descriptors will be marked as CLOEXEC, which means
+ * that it is safe to fork() and exec() without worrying about the child
+ * process needing to clean up state or having access to these file descriptors.
+ * Other platforms may not be so forgiving, so consider yourself warned!
+ *
* \section devresets Device resets
*
* The libusb_reset_device() function allows you to reset a device. If your
* information about the end of the short packet, and the user probably wanted
* that surplus data to arrive in the next logical transfer.
*
- *
* \section zlp Zero length packets
*
* - libusb is able to send a packet of zero length to an endpoint simply by
return ret;
}
+static void discovered_devs_free(struct discovered_devs *discdevs)
+{
+ size_t i;
+
+ for (i = 0; i < discdevs->len; i++)
+ libusb_unref_device(discdevs->devices[i]);
+
+ free(discdevs);
+}
+
/* append a device to the discovered devices collection. may realloc itself,
* returning new discdevs. returns NULL on realloc failure. */
struct discovered_devs *discovered_devs_append(
{
size_t len = discdevs->len;
size_t capacity;
+ struct discovered_devs *new_discdevs;
/* if there is space, just append the device */
if (len < discdevs->capacity) {
/* exceeded capacity, need to grow */
usbi_dbg("need to increase capacity");
capacity = discdevs->capacity + DISCOVERED_DEVICES_SIZE_STEP;
- discdevs = usbi_reallocf(discdevs,
+ /* can't use usbi_reallocf here because in failure cases it would
+ * free the existing discdevs without unreferencing its devices. */
+ new_discdevs = realloc(discdevs,
sizeof(*discdevs) + (sizeof(void *) * capacity));
- if (discdevs) {
- discdevs->capacity = capacity;
- discdevs->devices[len] = libusb_ref_device(dev);
- discdevs->len++;
+ if (!new_discdevs) {
+ discovered_devs_free(discdevs);
+ return NULL;
}
- return discdevs;
-}
+ discdevs = new_discdevs;
+ discdevs->capacity = capacity;
+ discdevs->devices[len] = libusb_ref_device(dev);
+ discdevs->len++;
-static void discovered_devs_free(struct discovered_devs *discdevs)
-{
- size_t i;
-
- for (i = 0; i < discdevs->len; i++)
- libusb_unref_device(discdevs->devices[i]);
-
- free(discdevs);
+ return discdevs;
}
/* Allocate a new device with a specific session ID. The returned device has
struct libusb_device *usbi_alloc_device(struct libusb_context *ctx,
unsigned long session_id)
{
- size_t priv_size = usbi_backend->device_priv_size;
+ size_t priv_size = usbi_backend.device_priv_size;
struct libusb_device *dev = calloc(1, sizeof(*dev) + priv_size);
int r;
/* backend provides hotplug support */
struct libusb_device *dev;
- if (usbi_backend->hotplug_poll)
- usbi_backend->hotplug_poll();
+ if (usbi_backend.hotplug_poll)
+ usbi_backend.hotplug_poll();
usbi_mutex_lock(&ctx->usb_devs_lock);
list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) {
usbi_mutex_unlock(&ctx->usb_devs_lock);
} else {
/* backend does not provide hotplug support */
- r = usbi_backend->get_device_list(ctx, &discdevs);
+ r = usbi_backend.get_device_list(ctx, &discdevs);
}
if (r < 0) {
*list = ret;
out:
- discovered_devs_free(discdevs);
+ if (discdevs)
+ discovered_devs_free(discdevs);
return len;
}
libusb_unref_device(dev->parent_dev);
- if (usbi_backend->destroy_device)
- usbi_backend->destroy_device(dev);
+ if (usbi_backend.destroy_device)
+ usbi_backend.destroy_device(dev);
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
/* backend does not support hotplug */
{
struct libusb_context *ctx = DEVICE_CTX(dev);
struct libusb_device_handle *_dev_handle;
- size_t priv_size = usbi_backend->device_handle_priv_size;
+ size_t priv_size = usbi_backend.device_handle_priv_size;
int r;
usbi_dbg("open %d.%d", dev->bus_number, dev->device_address);
_dev_handle->claimed_interfaces = 0;
memset(&_dev_handle->os_priv, 0, priv_size);
- r = usbi_backend->open(_dev_handle);
+ r = usbi_backend.open(_dev_handle);
if (r < 0) {
usbi_dbg("open %d.%d returns %d", dev->bus_number, dev->device_address, r);
libusb_unref_device(dev);
struct usbi_transfer *itransfer;
struct usbi_transfer *tmp;
- libusb_lock_events(ctx);
-
/* remove any transfers in flight that are for this device */
usbi_mutex_lock(&ctx->flying_transfers_lock);
if (transfer->dev_handle != dev_handle)
continue;
- if (!(itransfer->flags & USBI_TRANSFER_DEVICE_DISAPPEARED)) {
+ usbi_mutex_lock(&itransfer->lock);
+ if (!(itransfer->state_flags & USBI_TRANSFER_DEVICE_DISAPPEARED)) {
usbi_err(ctx, "Device handle closed while transfer was still being processed, but the device is still connected as far as we know");
- if (itransfer->flags & USBI_TRANSFER_CANCELLING)
+ if (itransfer->state_flags & USBI_TRANSFER_CANCELLING)
usbi_warn(ctx, "A cancellation for an in-flight transfer hasn't completed but closing the device handle");
else
usbi_err(ctx, "A cancellation hasn't even been scheduled on the transfer for which the device is closing");
}
+ usbi_mutex_unlock(&itransfer->lock);
/* remove from the list of in-flight transfers and make sure
* we don't accidentally use the device handle in the future
* (or that such accesses will be easily caught and identified as a crash)
*/
- usbi_mutex_lock(&itransfer->lock);
list_del(&itransfer->list);
transfer->dev_handle = NULL;
- usbi_mutex_unlock(&itransfer->lock);
/* it is up to the user to free up the actual transfer struct. this is
* just making sure that we don't attempt to process the transfer after
}
usbi_mutex_unlock(&ctx->flying_transfers_lock);
- libusb_unlock_events(ctx);
-
usbi_mutex_lock(&ctx->open_devs_lock);
list_del(&dev_handle->list);
usbi_mutex_unlock(&ctx->open_devs_lock);
- usbi_backend->close(dev_handle);
+ usbi_backend.close(dev_handle);
libusb_unref_device(dev_handle->dev);
usbi_mutex_destroy(&dev_handle->lock);
free(dev_handle);
void API_EXPORTED libusb_close(libusb_device_handle *dev_handle)
{
struct libusb_context *ctx;
+ int handling_events;
int pending_events;
if (!dev_handle)
usbi_dbg("");
ctx = HANDLE_CTX(dev_handle);
+ handling_events = usbi_handling_events(ctx);
/* Similarly to libusb_open(), we want to interrupt all event handlers
* at this point. More importantly, we want to perform the actual close of
* the device while holding the event handling lock (preventing any other
* thread from doing event handling) because we will be removing a file
- * descriptor from the polling loop. */
-
- /* Record that we are closing a device.
- * Only signal an event if there are no prior pending events. */
- usbi_mutex_lock(&ctx->event_data_lock);
- pending_events = usbi_pending_events(ctx);
- ctx->device_close++;
- if (!pending_events)
- usbi_signal_event(ctx);
- usbi_mutex_unlock(&ctx->event_data_lock);
-
- /* take event handling lock */
- libusb_lock_events(ctx);
+ * descriptor from the polling loop. If this is being called by the current
+ * event handler, we can bypass the interruption code because we already
+ * hold the event handling lock. */
+
+ if (!handling_events) {
+ /* Record that we are closing a device.
+ * Only signal an event if there are no prior pending events. */
+ usbi_mutex_lock(&ctx->event_data_lock);
+ pending_events = usbi_pending_events(ctx);
+ ctx->device_close++;
+ if (!pending_events)
+ usbi_signal_event(ctx);
+ usbi_mutex_unlock(&ctx->event_data_lock);
+
+ /* take event handling lock */
+ libusb_lock_events(ctx);
+ }
/* Close the device */
do_close(ctx, dev_handle);
- /* We're done with closing this device.
- * Clear the event pipe if there are no further pending events. */
- usbi_mutex_lock(&ctx->event_data_lock);
- ctx->device_close--;
- pending_events = usbi_pending_events(ctx);
- if (!pending_events)
- usbi_clear_event(ctx);
- usbi_mutex_unlock(&ctx->event_data_lock);
-
- /* Release event handling lock and wake up event waiters */
- libusb_unlock_events(ctx);
+ if (!handling_events) {
+ /* We're done with closing this device.
+ * Clear the event pipe if there are no further pending events. */
+ usbi_mutex_lock(&ctx->event_data_lock);
+ ctx->device_close--;
+ pending_events = usbi_pending_events(ctx);
+ if (!pending_events)
+ usbi_clear_event(ctx);
+ usbi_mutex_unlock(&ctx->event_data_lock);
+
+ /* Release event handling lock and wake up event waiters */
+ libusb_unlock_events(ctx);
+ }
}
/** \ingroup libusb_dev
int r = LIBUSB_ERROR_NOT_SUPPORTED;
usbi_dbg("");
- if (usbi_backend->get_configuration)
- r = usbi_backend->get_configuration(dev_handle, config);
+ if (usbi_backend.get_configuration)
+ r = usbi_backend.get_configuration(dev_handle, config);
if (r == LIBUSB_ERROR_NOT_SUPPORTED) {
uint8_t tmp = 0;
int configuration)
{
usbi_dbg("configuration %d", configuration);
- return usbi_backend->set_configuration(dev_handle, configuration);
+ return usbi_backend.set_configuration(dev_handle, configuration);
}
/** \ingroup libusb_dev
if (dev_handle->claimed_interfaces & (1 << interface_number))
goto out;
- r = usbi_backend->claim_interface(dev_handle, interface_number);
+ r = usbi_backend.claim_interface(dev_handle, interface_number);
if (r == 0)
dev_handle->claimed_interfaces |= 1 << interface_number;
goto out;
}
- r = usbi_backend->release_interface(dev_handle, interface_number);
+ r = usbi_backend.release_interface(dev_handle, interface_number);
if (r == 0)
dev_handle->claimed_interfaces &= ~(1 << interface_number);
}
usbi_mutex_unlock(&dev_handle->lock);
- return usbi_backend->set_interface_altsetting(dev_handle, interface_number,
+ return usbi_backend.set_interface_altsetting(dev_handle, interface_number,
alternate_setting);
}
if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE;
- return usbi_backend->clear_halt(dev_handle, endpoint);
+ return usbi_backend.clear_halt(dev_handle, endpoint);
}
/** \ingroup libusb_dev
if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE;
- return usbi_backend->reset_device(dev_handle);
+ return usbi_backend.reset_device(dev_handle);
}
/** \ingroup libusb_asyncio
if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE;
- if (usbi_backend->alloc_streams)
- return usbi_backend->alloc_streams(dev_handle, num_streams, endpoints,
+ if (usbi_backend.alloc_streams)
+ return usbi_backend.alloc_streams(dev_handle, num_streams, endpoints,
num_endpoints);
else
return LIBUSB_ERROR_NOT_SUPPORTED;
if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE;
- if (usbi_backend->free_streams)
- return usbi_backend->free_streams(dev_handle, endpoints,
+ if (usbi_backend.free_streams)
+ return usbi_backend.free_streams(dev_handle, endpoints,
num_endpoints);
else
return LIBUSB_ERROR_NOT_SUPPORTED;
if (!dev_handle->dev->attached)
return NULL;
- if (usbi_backend->dev_mem_alloc)
- return usbi_backend->dev_mem_alloc(dev_handle, length);
+ if (usbi_backend.dev_mem_alloc)
+ return usbi_backend.dev_mem_alloc(dev_handle, length);
else
return NULL;
}
int API_EXPORTED libusb_dev_mem_free(libusb_device_handle *dev_handle,
unsigned char *buffer, size_t length)
{
- if (usbi_backend->dev_mem_free)
- return usbi_backend->dev_mem_free(dev_handle, buffer, length);
+ if (usbi_backend.dev_mem_free)
+ return usbi_backend.dev_mem_free(dev_handle, buffer, length);
else
return LIBUSB_ERROR_NOT_SUPPORTED;
}
if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE;
- if (usbi_backend->kernel_driver_active)
- return usbi_backend->kernel_driver_active(dev_handle, interface_number);
+ if (usbi_backend.kernel_driver_active)
+ return usbi_backend.kernel_driver_active(dev_handle, interface_number);
else
return LIBUSB_ERROR_NOT_SUPPORTED;
}
if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE;
- if (usbi_backend->detach_kernel_driver)
- return usbi_backend->detach_kernel_driver(dev_handle, interface_number);
+ if (usbi_backend.detach_kernel_driver)
+ return usbi_backend.detach_kernel_driver(dev_handle, interface_number);
else
return LIBUSB_ERROR_NOT_SUPPORTED;
}
if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE;
- if (usbi_backend->attach_kernel_driver)
- return usbi_backend->attach_kernel_driver(dev_handle, interface_number);
+ if (usbi_backend.attach_kernel_driver)
+ return usbi_backend.attach_kernel_driver(dev_handle, interface_number);
else
return LIBUSB_ERROR_NOT_SUPPORTED;
}
int API_EXPORTED libusb_set_auto_detach_kernel_driver(
libusb_device_handle *dev_handle, int enable)
{
- if (!(usbi_backend->caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER))
+ if (!(usbi_backend.caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER))
return LIBUSB_ERROR_NOT_SUPPORTED;
dev_handle->auto_detach_kernel_driver = enable;
{
struct libusb_device *dev, *next;
char *dbg = getenv("LIBUSB_DEBUG");
+ size_t priv_size = usbi_backend.context_priv_size;
struct libusb_context *ctx;
static int first_init = 1;
int r = 0;
usbi_mutex_static_lock(&default_context_lock);
if (!timestamp_origin.tv_sec) {
- usbi_gettimeofday(×tamp_origin, NULL);
+ usbi_backend.clock_gettime(USBI_CLOCK_REALTIME, ×tamp_origin);
}
if (!context && usbi_default_context) {
return 0;
}
- ctx = calloc(1, sizeof(*ctx));
+ ctx = calloc(1, sizeof(*ctx) + priv_size);
if (!ctx) {
r = LIBUSB_ERROR_NO_MEM;
goto err_unlock;
list_add (&ctx->list, &active_contexts_list);
usbi_mutex_static_unlock(&active_contexts_lock);
- if (usbi_backend->init) {
- r = usbi_backend->init(ctx);
+ if (usbi_backend.init) {
+ r = usbi_backend.init(ctx);
if (r)
goto err_free_ctx;
}
return 0;
err_backend_exit:
- if (usbi_backend->exit)
- usbi_backend->exit();
+ if (usbi_backend.exit)
+ usbi_backend.exit();
err_free_ctx:
if (ctx == usbi_default_context) {
usbi_default_context = NULL;
usbi_warn(ctx, "application left some devices open");
usbi_io_exit(ctx);
- if (usbi_backend->exit)
- usbi_backend->exit();
+ if (usbi_backend.exit)
+ usbi_backend.exit();
usbi_mutex_destroy(&ctx->open_devs_lock);
usbi_mutex_destroy(&ctx->usb_devs_lock);
case LIBUSB_CAP_HAS_CAPABILITY:
return 1;
case LIBUSB_CAP_HAS_HOTPLUG:
- return !(usbi_backend->get_device_list);
+ return !(usbi_backend.get_device_list);
case LIBUSB_CAP_HAS_HID_ACCESS:
- return (usbi_backend->caps & USBI_CAP_HAS_HID_ACCESS);
+ return (usbi_backend.caps & USBI_CAP_HAS_HID_ACCESS);
case LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER:
- return (usbi_backend->caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER);
+ return (usbi_backend.caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER);
}
return 0;
}
/* this is defined in libusbi.h if needed */
-#ifdef LIBUSB_GETTIMEOFDAY_WIN32
-/*
- * gettimeofday
- * Implementation according to:
- * The Open Group Base Specifications Issue 6
- * IEEE Std 1003.1, 2004 Edition
- */
-
+#ifdef LIBUSB_PRINTF_WIN32
/*
- * THIS SOFTWARE IS NOT COPYRIGHTED
- *
- * This source code is offered for use in the public domain. You may
- * use, modify or distribute it freely.
- *
- * This code is distributed in the hope that it will be useful but
- * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
- * DISCLAIMED. This includes but is not limited to warranties of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * Prior to VS2015, Microsoft did not provide the snprintf() function and
+ * provided a vsnprintf() that did not guarantee NULL-terminated output.
+ * Microsoft did provide a _snprintf() function, but again it did not
+ * guarantee NULL-terminated output.
*
- * Contributed by:
- * Danny Smith <dannysmith@users.sourceforge.net>
+ * The below implementations guarantee NULL-terminated output and are
+ * C99 compliant.
*/
-/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */
-#define _W32_FT_OFFSET (116444736000000000)
+int usbi_snprintf(char *str, size_t size, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = usbi_vsnprintf(str, size, format, ap);
+ va_end(ap);
-int usbi_gettimeofday(struct timeval *tp, void *tzp)
+ return ret;
+}
+
+int usbi_vsnprintf(char *str, size_t size, const char *format, va_list ap)
{
- union {
- unsigned __int64 ns100; /* Time since 1 Jan 1601, in 100ns units */
- FILETIME ft;
- } _now;
- UNUSED(tzp);
-
- if(tp) {
-#if defined(OS_WINCE)
- SYSTEMTIME st;
- GetSystemTime(&st);
- SystemTimeToFileTime(&st, &_now.ft);
-#else
- GetSystemTimeAsFileTime (&_now.ft);
-#endif
- tp->tv_usec=(long)((_now.ns100 / 10) % 1000000 );
- tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000);
+ int ret;
+
+ ret = _vsnprintf(str, size, format, ap);
+ if (ret < 0 || ret == (int)size) {
+ /* Output is truncated, ensure buffer is NULL-terminated and
+ * determine how many characters would have been written. */
+ str[size - 1] = '\0';
+ if (ret < 0)
+ ret = _vsnprintf(NULL, 0, format, ap);
}
- /* Always return 0 as per Open Group Base Specifications Issue 6.
- Do not set errno on error. */
- return 0;
+
+ return ret;
}
#endif
enum libusb_log_level level, const char * str)
{
#if defined(USE_SYSTEM_LOGGING_FACILITY)
-#if defined(OS_WINDOWS) || defined(OS_WINCE)
+#if defined(OS_WINDOWS)
+ OutputDebugString(str);
+#elif 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));
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;
+ case LIBUSB_LOG_LEVEL_NONE: return;
}
__android_log_write(priority, "libusb", str);
#elif defined(HAVE_SYSLOG_FUNC)
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;
+ case LIBUSB_LOG_LEVEL_NONE: return;
}
syslog(syslog_level, "%s", str);
#else /* All of gcc, Clang, XCode seem to use #warning */
{
const char *prefix = "";
char buf[USBI_MAX_LOG_LEN];
- struct timeval now;
+ struct timespec now;
int global_debug, header_len, text_len;
static int has_debug_header_been_displayed = 0;
return;
#endif
- usbi_gettimeofday(&now, NULL);
+ usbi_backend.clock_gettime(USBI_CLOCK_REALTIME, &now);
if ((global_debug) && (!has_debug_header_been_displayed)) {
has_debug_header_been_displayed = 1;
usbi_log_str(ctx, LIBUSB_LOG_LEVEL_DEBUG, "[timestamp] [threadID] facility level [function call] <message>" USBI_LOG_LINE_END);
usbi_log_str(ctx, LIBUSB_LOG_LEVEL_DEBUG, "--------------------------------------------------------------------------------" USBI_LOG_LINE_END);
}
- if (now.tv_usec < timestamp_origin.tv_usec) {
+ if (now.tv_nsec < timestamp_origin.tv_nsec) {
now.tv_sec--;
- now.tv_usec += 1000000;
+ now.tv_nsec += 1000000000L;
}
now.tv_sec -= timestamp_origin.tv_sec;
- now.tv_usec -= timestamp_origin.tv_usec;
+ now.tv_nsec -= timestamp_origin.tv_nsec;
switch (level) {
case LIBUSB_LOG_LEVEL_INFO:
if (global_debug) {
header_len = snprintf(buf, sizeof(buf),
"[%2d.%06d] [%08x] libusb: %s [%s] ",
- (int)now.tv_sec, (int)now.tv_usec, usbi_get_tid(), prefix, function);
+ (int)now.tv_sec, (int)(now.tv_nsec / 1000L), usbi_get_tid(), prefix, function);
} else {
header_len = snprintf(buf, sizeof(buf),
"libusb: %s [%s] ", prefix, function);