@@ -0,0 +1,41 @@
Notes related to git compilation:
--------------------------------

If you retrieved the libusb repository from git and are using a gcc based
toolchain, be mindful that you should have the autotools installed (autoconf,
automake) and will need to run either ./autogen.sh or ./bootstrap.sh to produce
the configure file.

The difference between autogen.sh and bootstrap.sh is that the former invokes
configure with a default set of options, and will therefore generate a Makefile,
whereas the latter does not invoke configure at all. If using autogen.sh, note
that you can also append options, that will be passed as is to configure.

OS X-specific notes:
-------------------

Starting with Xcode 4.3, neither Xcode.app nor the Xcode 'command line tools'
includes autotools and so running either autogen.sh or bootstrap.sh will result
in the message:

libtoolize or glibtoolize was not found! Please install libtool.

To proceed, you must find and install it from somewhere.

Alternatively, you can use the Xcode project at Xcode/libusb.xcodeproj.

Notes related to submitting new developments:
--------------------------------------------

If you submit a new development to libusb (eg: new backend), that is unlikely
to fit in a couple of small patches, we would kindly suggest that you create a
public account on github, if you don't have one already, and then fork a new
libusb repository under this account from https://github.com/libusb/libusb.

Then you can create a git branch for your work, that we will be able to better
reference and test.

We also suggest that, if you are planning to bring in a large development, you
try to involve the libusb community early by letting the mailing list know, as
you may find that other people might be eager to help you out.
See http://mailing-list.libusb.info for details on how to join the mailing list.
@@ -0,0 +1,32 @@
# libusb

[![Build Status](https://travis-ci.org/libusb/libusb.svg?branch=master)](https://travis-ci.org/libusb/libusb)
[![Build status](https://ci.appveyor.com/api/projects/status/xvrfam94jii4a6lw?svg=true)](https://ci.appveyor.com/project/LudovicRousseau/libusb)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/2180/badge.svg)](https://scan.coverity.com/projects/libusb-libusb)

libusb is a library for USB device access from Linux, macOS,
Windows, OpenBSD/NetBSD and Haiku userspace.
It is written in C (Haiku backend in C++) and licensed under the GNU
Lesser General Public License version 2.1 or, at your option, any later
version (see [COPYING](COPYING)).

libusb is abstracted internally in such a way that it can hopefully
be ported to other operating systems. Please see the [PORTING](PORTING)
file for more information.

libusb homepage:
http://libusb.info/

Developers will wish to consult the API documentation:
http://api.libusb.info

Use the mailing list for questions, comments, etc:
http://mailing-list.libusb.info

- Hans de Goede <hdegoede@redhat.com>
- Xiaofan Chen <xiaofanc@gmail.com>
- Ludovic Rousseau <ludovic.rousseau@gmail.com>
- Nathan Hjelm <hjelmn@cs.unm.edu>
- Chris Dickens <christopher.a.dickens@gmail.com>

(Please use the mailing list rather than mailing developers directly)
@@ -0,0 +1,8 @@
#!/bin/sh

set -e

./bootstrap.sh
if test -z "$NOCONFIGURE"; then
exec ./configure --enable-examples-build --enable-tests-build "$@"
fi
@@ -0,0 +1,6 @@
#!/bin/sh

if ! test -d m4 ; then
mkdir m4
fi
autoreconf -ivf || exit 1
@@ -0,0 +1,332 @@
dnl These m4 macros are whitespace sensitive and break if moved around much.
m4_define([LU_VERSION_H], m4_include([libusb/version.h]))
m4_define([LU_DEFINE_VERSION_ATOM],
[m4_define([$1], m4_bregexp(LU_VERSION_H,
[^#define\s*$1\s*\([0-9]*\).*], [\1]))])
m4_define([LU_DEFINE_VERSION_RC_ATOM],
[m4_define([$1], m4_bregexp(LU_VERSION_H,
[^#define\s*$1\s*"\(-rc[0-9]*\)".*], [\1]))])
dnl The m4_bregexp() returns (only) the numbers following the #define named
dnl in the first macro parameter. m4_define() then defines the name for use
dnl in AC_INIT.

LU_DEFINE_VERSION_ATOM([LIBUSB_MAJOR])
LU_DEFINE_VERSION_ATOM([LIBUSB_MINOR])
LU_DEFINE_VERSION_ATOM([LIBUSB_MICRO])
LU_DEFINE_VERSION_RC_ATOM([LIBUSB_RC])

AC_INIT([libusb],[LIBUSB_MAJOR[.]LIBUSB_MINOR[.]LIBUSB_MICRO[]LIBUSB_RC],[libusb-devel@lists.sourceforge.net],[libusb],[http://libusb.info])

# Library versioning
# These numbers should be tweaked on every release. Read carefully:
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
# http://sourceware.org/autobook/autobook/autobook_91.html
lt_current=2
lt_revision=0
lt_age=1
LTLDFLAGS="-version-info ${lt_current}:${lt_revision}:${lt_age}"

AM_INIT_AUTOMAKE

AC_CONFIG_SRCDIR([libusb/core.c])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])

AC_PREREQ([2.69])
AC_PROG_CC
AC_PROG_CXX
LT_INIT
LT_LANG([Windows Resource])
AC_C_INLINE
AM_PROG_CC_C_O
AC_DEFINE([_GNU_SOURCE], 1, [Use GNU extensions])

LTLDFLAGS="${LTLDFLAGS} -no-undefined"

AC_MSG_CHECKING([operating system])

dnl on linux-android platform, some functions are in different places
case $host in
*-linux-android*)
AC_MSG_RESULT([This is a Linux-Android system])
is_backend_android=yes
;;
*)
is_backend_android=no
esac

case $host in
*-linux* | *-uclinux*)
AC_MSG_RESULT([Linux])
backend=linux
threads=posix
;;
*-darwin*)
AC_MSG_RESULT([Darwin/Mac OS X])
backend=darwin
threads=posix
;;
*-openbsd*)
AC_MSG_RESULT([OpenBSD])
backend=openbsd
threads=posix
;;
*-netbsd*)
AC_MSG_RESULT([NetBSD])
backend=netbsd
threads=posix
;;
*-mingw* | *msys*)
AC_MSG_RESULT([Windows])
backend=windows
threads=windows
create_import_lib=yes
AM_CFLAGS="${AM_CFLAGS} -fno-omit-frame-pointer"
;;
*-cygwin*)
AC_MSG_RESULT([Cygwin (using Windows backend)])
backend=windows
threads=posix
;;
*-haiku*)
AC_MSG_RESULT([Haiku])
backend=haiku
threads=posix
;;
*-solaris*)
AC_MSG_RESULT([SunOS])
backend=sunos
threads=posix
;;
*)
AC_MSG_ERROR([unsupported operating system $host])
esac

case $backend in
linux)
AC_DEFINE(OS_LINUX, 1, [Linux backend])
AC_SUBST(OS_LINUX)
AC_SEARCH_LIBS([clock_gettime], [rt], [], [], [-pthread])
AC_ARG_ENABLE([udev],
[AC_HELP_STRING([--enable-udev], [use udev for device enumeration and hotplug support (recommended) [default=yes]])],
[], [enable_udev=yes])
if test "x$enable_udev" = xyes ; then
# system has udev. use it or fail!
AC_CHECK_HEADERS([libudev.h], [], [AC_MSG_ERROR([udev support requested but libudev header not installed])])
AC_CHECK_LIB([udev], [udev_new], [], [AC_MSG_ERROR([udev support requested but libudev not installed])])
AC_DEFINE(USE_UDEV, 1, [Use udev for device enumeration/hotplug])
else
AC_CHECK_HEADERS([asm/types.h], [], [])
AC_CHECK_HEADERS([sys/socket.h linux/netlink.h], [], [AC_MSG_ERROR([Linux netlink headers not found])], [
#ifdef HAVE_ASM_TYPES_H
#include <asm/types.h>
#endif
#include <sys/socket.h>
])
fi
AC_SUBST(USE_UDEV)

if test "x$is_backend_android" != xyes; then
THREAD_CFLAGS="-pthread"
LIBS="${LIBS} -pthread"
fi

AC_CHECK_HEADERS([poll.h])
AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])
;;
darwin)
AC_DEFINE(OS_DARWIN, 1, [Darwin backend])
AC_SUBST(OS_DARWIN)
LIBS="-lobjc -Wl,-framework,IOKit -Wl,-framework,CoreFoundation"
LTLDFLAGS="${LTLDFLAGS} -Wl,-prebind"
AC_CHECK_HEADERS([poll.h])
AC_CHECK_TYPE([nfds_t],
[AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])],
[AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument])],
[#include <poll.h>])
;;
openbsd)
AC_DEFINE(OS_OPENBSD, 1, [OpenBSD backend])
AC_SUBST(OS_OPENBSD)
THREAD_CFLAGS="-pthread"
LIBS="-pthread"
AC_CHECK_HEADERS([poll.h])
AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])
;;
sunos)
AC_DEFINE(OS_SUNOS, 1, [SunOS backend])
AC_SUBST(OS_SUNOS)
THREAD_CFLAGS="-pthread"
LIBS="-pthread -ldevinfo"
AC_CHECK_HEADERS([poll.h])
AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])
;;
netbsd)
AC_DEFINE(OS_NETBSD, 1, [NetBSD backend])
AC_SUBST(OS_NETBSD)
THREAD_CFLAGS="-pthread"
LIBS="-pthread"
AC_CHECK_HEADERS([poll.h])
AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])
;;
windows)
AC_DEFINE(OS_WINDOWS, 1, [Windows backend])
AC_SUBST(OS_WINDOWS)
LIBS=""
LTLDFLAGS="${LTLDFLAGS} -avoid-version -Wl,--add-stdcall-alias"
AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument])
AC_DEFINE([WINVER], 0x0501, [Oldest Windows version supported])
AC_DEFINE([_WIN32_WINNT], 0x0501, [Oldest Windows version supported])
;;
haiku)
AC_DEFINE(OS_HAIKU, 1, [Haiku backend])
AC_SUBST(OS_HAIKU)
LIBS="${LIBS} -lbe"
AC_CHECK_HEADERS([poll.h])
AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])
;;
esac

AC_SUBST(LIBS)

AM_CONDITIONAL(OS_LINUX, test "x$backend" = xlinux)
AM_CONDITIONAL(OS_DARWIN, test "x$backend" = xdarwin)
AM_CONDITIONAL(OS_OPENBSD, test "x$backend" = xopenbsd)
AM_CONDITIONAL(OS_SUNOS, test "x$backend" = xsunos)
AM_CONDITIONAL(OS_NETBSD, test "x$backend" = xnetbsd)
AM_CONDITIONAL(OS_WINDOWS, test "x$backend" = xwindows)
AM_CONDITIONAL(OS_HAIKU, test "x$backend" = xhaiku)
AM_CONDITIONAL(THREADS_POSIX, test "x$threads" = xposix)
AM_CONDITIONAL(CREATE_IMPORT_LIB, test "x$create_import_lib" = xyes)
AM_CONDITIONAL(USE_UDEV, test "x$enable_udev" = xyes)
if test "x$threads" = xposix; then
AC_DEFINE(THREADS_POSIX, 1, [Use POSIX Threads])
fi

# timerfd
AC_CHECK_HEADER([sys/timerfd.h], [timerfd_h=1], [timerfd_h=0])
AC_ARG_ENABLE([timerfd],
[AS_HELP_STRING([--enable-timerfd],
[use timerfd for timing [default=auto]])],
[use_timerfd=$enableval], [use_timerfd=auto])

if test "x$use_timerfd" = xyes -a "x$timerfd_h" = x0; then
AC_MSG_ERROR([timerfd header not available; glibc 2.9+ required])
fi

AC_CHECK_DECLS([TFD_NONBLOCK, TFD_CLOEXEC], [tfd_hdr_ok=yes], [tfd_hdr_ok=no], [#include <sys/timerfd.h>])
if test "x$use_timerfd" = xyes -a "x$tfd_hdr_ok" = xno; then
AC_MSG_ERROR([timerfd header not usable; glibc 2.9+ required])
fi

AC_MSG_CHECKING([whether to use timerfd for timing])
if test "x$use_timerfd" = xno; then
AC_MSG_RESULT([no (disabled by user)])
else
if test "x$timerfd_h" = x1 -a "x$tfd_hdr_ok" = xyes; then
AC_MSG_RESULT([yes])
AC_DEFINE(USBI_TIMERFD_AVAILABLE, 1, [timerfd headers available])
else
AC_MSG_RESULT([no (header not available)])
fi
fi

AC_CHECK_FUNCS([pipe2])
AC_CHECK_TYPES([struct timespec])

# Message logging
AC_ARG_ENABLE([log], [AS_HELP_STRING([--disable-log], [disable all logging])],
[log_enabled=$enableval],
[log_enabled=yes])
if test "x$log_enabled" != xno; then
AC_DEFINE([ENABLE_LOGGING], 1, [Message logging])
fi

AC_ARG_ENABLE([debug-log], [AS_HELP_STRING([--enable-debug-log],
[start with debug message logging enabled [default=no]])],
[debug_log_enabled=$enableval],
[debug_log_enabled=no])
if test "x$debug_log_enabled" != xno; then
AC_DEFINE([ENABLE_DEBUG_LOGGING], 1, [Start with debug message logging enabled])
fi

AC_ARG_ENABLE([system-log], [AS_HELP_STRING([--enable-system-log],
[output logging messages to system wide log, if supported by the OS [default=no]])],
[system_log_enabled=$enableval],
[system_log_enabled=no])
if test "x$system_log_enabled" != xno; then
AC_DEFINE([USE_SYSTEM_LOGGING_FACILITY], 1, [Enable output to system log])

# Check if syslog is available in standard C library
AC_CHECK_HEADERS(syslog.h)
AC_CHECK_FUNC([syslog], [have_syslog=yes], [have_syslog=no])
if test "x$have_syslog" != xno; then
AC_DEFINE([HAVE_SYSLOG_FUNC], 1, [syslog() function available])
fi
fi

# Examples build
AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build],
[build example applications [default=no]])],
[build_examples=$enableval],
[build_examples=no])
AM_CONDITIONAL(BUILD_EXAMPLES, test "x$build_examples" != xno)

# Tests build
AC_ARG_ENABLE([tests-build], [AS_HELP_STRING([--enable-tests-build],
[build test applications [default=no]])],
[build_tests=$enableval],
[build_tests=no])
AM_CONDITIONAL(BUILD_TESTS, test "x$build_tests" != xno)

# headers not available on all platforms but required on others
AC_CHECK_HEADERS([sys/time.h])

# sigaction not available on MinGW
AC_CHECK_FUNC([sigaction], [have_sigaction=yes], [have_sigaction=no])
AM_CONDITIONAL(HAVE_SIGACTION, test "x$have_sigaction" = xyes)

# check for -fvisibility=hidden compiler support (GCC >= 3.4)
saved_cflags="$CFLAGS"
# -Werror required for cygwin
CFLAGS="$CFLAGS -Werror -fvisibility=hidden"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
[VISIBILITY_CFLAGS="-fvisibility=hidden"
AC_DEFINE([DEFAULT_VISIBILITY], [__attribute__((visibility("default")))], [Default visibility])],
[VISIBILITY_CFLAGS=""
AC_DEFINE([DEFAULT_VISIBILITY], [], [Default visibility])],
])
CFLAGS="$saved_cflags"

# check for -Wno-pointer-sign compiler support (GCC >= 4)
saved_cflags="$CFLAGS"
CFLAGS="$CFLAGS -Wno-pointer-sign"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
nopointersign_cflags="-Wno-pointer-sign", nopointersign_cflags="")
CFLAGS="$saved_cflags"

# check for -std=gnu99 compiler support
saved_cflags="$CFLAGS"
CFLAGS="-std=gnu99"
AC_MSG_CHECKING([whether CC supports -std=gnu99])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_RESULT([yes])]
[AM_CFLAGS="${AM_CFLAGS} -std=gnu99"],
[AC_MSG_RESULT([no])]
)
CFLAGS="$saved_cflags"

AM_CFLAGS="${AM_CFLAGS} -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration $nopointersign_cflags -Wshadow ${THREAD_CFLAGS} ${VISIBILITY_CFLAGS}"

AC_SUBST(AM_CFLAGS)
AC_SUBST(LTLDFLAGS)

AC_CONFIG_FILES([libusb-1.0.pc])
AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([libusb/Makefile])
AC_CONFIG_FILES([examples/Makefile])
AC_CONFIG_FILES([tests/Makefile])
AC_CONFIG_FILES([doc/Makefile])
AC_CONFIG_FILES([doc/doxygen.cfg])
AC_OUTPUT
@@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@

Name: libusb-1.0
Description: C API for USB device access from Linux, Mac OS X, Windows, OpenBSD/NetBSD and Solaris userspace
Version: @VERSION@
Libs: -L${libdir} -lusb-1.0
Libs.private: @LIBS@
Cflags: -I${includedir}/libusb-1.0
@@ -13,10 +13,12 @@ DARWIN_USB_SRC = os/darwin_usb.h os/darwin_usb.c
OPENBSD_USB_SRC = os/openbsd_usb.c
NETBSD_USB_SRC = os/netbsd_usb.c
SUNOS_USB_SRC = os/sunos_usb.c os/sunos_usb.h
WINDOWS_COMMON_SRC = os/windows_nt_common.h os/windows_nt_common.c \
os/windows_common.h libusb-1.0.rc libusb-1.0.def
WINDOWS_USB_SRC = os/windows_winusb.h os/windows_winusb.c os/windows_usbdk.h \
os/windows_usbdk.c $(COMMON_WINDOWS_SRC)
WINDOWS_USB_SRC = libusb-1.0.def libusb-1.0.rc \
os/windows_common.h \
os/windows_nt_common.h os/windows_nt_common.c \
os/windows_nt_shared_types.h \
os/windows_usbdk.h os/windows_usbdk.c \
os/windows_winusb.h os/windows_winusb.c
WINCE_USB_SRC = os/wince_usb.h os/wince_usb.c
HAIKU_USB_SRC = os/haiku_usb.h os/haiku_usb_backend.cpp \
os/haiku_usb_raw.h os/haiku_usb_raw.cpp os/haiku_pollfs.cpp
@@ -25,8 +27,8 @@ EXTRA_DIST = $(POSIX_POLL_SRC) $(POSIX_THREADS_SRC) \
$(WINDOWS_POLL_SRC) $(WINDOWS_THREADS_SRC) \
$(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) \
$(OPENBSD_USB_SRC) $(NETBSD_USB_SRC) \
$(WINDOWS_COMMON_SRC) $(WINDOWS_USB_SRC) $(WINDOWS_USBDK_SRC) \
$(WINCE_USB_SRC) $(HAIKU_USB_SRC) \
$(WINDOWS_USB_SRC) $(WINCE_USB_SRC) \
$(HAIKU_USB_SRC) \
os/linux_udev.c os/linux_netlink.c

if OS_LINUX
@@ -63,7 +65,7 @@ libusb_1_0_la_LIBADD = libusb_haiku.la
endif

if OS_WINDOWS
OS_SRC = $(WINDOWS_USB_SRC) $(WINDOWS_COMMON_SRC)
OS_SRC = $(WINDOWS_USB_SRC)

.rc.lo:
$(AM_V_GEN)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --tag=RC --mode=compile $(RC) $(RCFLAGS) -i $< -o $@

Large diffs are not rendered by default.

@@ -62,7 +62,7 @@ int usbi_parse_descriptor(const unsigned char *source, const char *descriptor,
if (host_endian) {
memcpy(dp, sp, 2);
} else {
w = (sp[1] << 8) | sp[0];
w = (uint16_t)((sp[1] << 8) | sp[0]);
*((uint16_t *)dp) = w;
}
sp += 2;
@@ -74,8 +74,8 @@ int usbi_parse_descriptor(const unsigned char *source, const char *descriptor,
if (host_endian) {
memcpy(dp, sp, 4);
} else {
d = (sp[3] << 24) | (sp[2] << 16) |
(sp[1] << 8) | sp[0];
d = (uint32_t)((sp[3] << 24) | (sp[2] << 16) |
(sp[1] << 8) | sp[0]);
*((uint32_t *)dp) = d;
}
sp += 4;
@@ -168,13 +168,13 @@ static int parse_endpoint(struct libusb_context *ctx,
/* Copy any unknown descriptors into a storage area for drivers */
/* to later parse */
len = (int)(buffer - begin);
if (!len) {
if (len <= 0) {
endpoint->extra = NULL;
endpoint->extra_length = 0;
return parsed;
}

extra = malloc(len);
extra = malloc((size_t)len);
endpoint->extra = extra;
if (!extra) {
endpoint->extra_length = 0;
@@ -230,7 +230,7 @@ static int parse_interface(libusb_context *ctx,
(struct libusb_interface_descriptor *) usb_interface->altsetting;
altsetting = usbi_reallocf(altsetting,
sizeof(struct libusb_interface_descriptor) *
(usb_interface->num_altsetting + 1));
((size_t)usb_interface->num_altsetting + 1));
if (!altsetting) {
r = LIBUSB_ERROR_NO_MEM;
goto err;
@@ -307,8 +307,8 @@ static int parse_interface(libusb_context *ctx,
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len = (int)(buffer - begin);
if (len) {
ifp->extra = malloc(len);
if (len > 0) {
ifp->extra = malloc((size_t)len);
if (!ifp->extra) {
r = LIBUSB_ERROR_NO_MEM;
goto err;
@@ -333,7 +333,7 @@ static int parse_interface(libusb_context *ctx,
goto err;
if (r == 0) {
ifp->bNumEndpoints = (uint8_t)i;
break;;
break;
}

buffer += r;
@@ -453,10 +453,10 @@ static int parse_configuration(struct libusb_context *ctx,
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len = (int)(buffer - begin);
if (len) {
if (len > 0) {
/* FIXME: We should realloc and append here */
if (!config->extra_length) {
config->extra = malloc(len);
config->extra = malloc((size_t)len);
if (!config->extra) {
r = LIBUSB_ERROR_NO_MEM;
goto err;
@@ -492,7 +492,7 @@ static int raw_desc_to_config(struct libusb_context *ctx,
{
struct libusb_config_descriptor *_config = malloc(sizeof(*_config));
int r;

if (!_config)
return LIBUSB_ERROR_NO_MEM;

@@ -504,7 +504,7 @@ static int raw_desc_to_config(struct libusb_context *ctx,
} else if (r > 0) {
usbi_warn(ctx, "still %d bytes of descriptor data left", r);
}

*config = _config;
return LIBUSB_SUCCESS;
}
@@ -513,7 +513,7 @@ int usbi_device_cache_descriptor(libusb_device *dev)
{
int r, host_endian = 0;

r = usbi_backend->get_device_descriptor(dev, (unsigned char *) &dev->device_descriptor,
r = usbi_backend.get_device_descriptor(dev, (unsigned char *) &dev->device_descriptor,
&host_endian);
if (r < 0)
return r;
@@ -572,7 +572,7 @@ int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev,
int host_endian = 0;
int r;

r = usbi_backend->get_active_config_descriptor(dev, tmp,
r = usbi_backend.get_active_config_descriptor(dev, tmp,
LIBUSB_DT_CONFIG_SIZE, &host_endian);
if (r < 0)
return r;
@@ -587,7 +587,7 @@ int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev,
if (!buf)
return LIBUSB_ERROR_NO_MEM;

r = usbi_backend->get_active_config_descriptor(dev, buf,
r = usbi_backend.get_active_config_descriptor(dev, buf,
_config.wTotalLength, &host_endian);
if (r >= 0)
r = raw_desc_to_config(dev->ctx, buf, r, host_endian, config);
@@ -625,7 +625,7 @@ int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev,
if (config_index >= dev->num_configurations)
return LIBUSB_ERROR_NOT_FOUND;

r = usbi_backend->get_config_descriptor(dev, config_index, tmp,
r = usbi_backend.get_config_descriptor(dev, config_index, tmp,
LIBUSB_DT_CONFIG_SIZE, &host_endian);
if (r < 0)
return r;
@@ -640,7 +640,7 @@ int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev,
if (!buf)
return LIBUSB_ERROR_NO_MEM;

r = usbi_backend->get_config_descriptor(dev, config_index, buf,
r = usbi_backend.get_config_descriptor(dev, config_index, buf,
_config.wTotalLength, &host_endian);
if (r >= 0)
r = raw_desc_to_config(dev->ctx, buf, r, host_endian, config);
@@ -663,7 +663,7 @@ int usbi_get_config_index_by_value(struct libusb_device *dev,
for (i = 0; i < dev->num_configurations; i++) {
unsigned char tmp[6];
int host_endian;
int r = usbi_backend->get_config_descriptor(dev, i, tmp, sizeof(tmp),
int r = usbi_backend.get_config_descriptor(dev, i, tmp, sizeof(tmp),
&host_endian);
if (r < 0) {
*idx = -1;
@@ -702,8 +702,8 @@ int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev,
int r, idx, host_endian;
unsigned char *buf = NULL;

if (usbi_backend->get_config_descriptor_by_value) {
r = usbi_backend->get_config_descriptor_by_value(dev,
if (usbi_backend.get_config_descriptor_by_value) {
r = usbi_backend.get_config_descriptor_by_value(dev,
bConfigurationValue, &buf, &host_endian);
if (r < 0)
return r;
@@ -1060,7 +1060,8 @@ int API_EXPORTED libusb_get_ss_usb_device_capability_descriptor(
* It is safe to call this function with a NULL ss_usb_device_cap
* parameter, in which case the function simply returns.
*
* \param ss_usb_device_cap the USB 2.0 Extension descriptor to free
* \param ss_usb_device_cap the SuperSpeed USB Device Capability descriptor
* to free
*/
void API_EXPORTED libusb_free_ss_usb_device_capability_descriptor(
struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_cap)
@@ -1117,7 +1118,7 @@ int API_EXPORTED libusb_get_container_id_descriptor(struct libusb_context *ctx,
* It is safe to call this function with a NULL container_id parameter,
* in which case the function simply returns.
*
* \param container_id the USB 2.0 Extension descriptor to free
* \param container_id the Container ID descriptor to free
*/
void API_EXPORTED libusb_free_container_id_descriptor(
struct libusb_container_id_descriptor *container_id)
@@ -1163,7 +1164,7 @@ int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev_ha
if (r < 4)
return LIBUSB_ERROR_IO;

langid = tbuf[2] | (tbuf[3] << 8);
langid = (uint16_t)(tbuf[2] | (tbuf[3] << 8));

r = libusb_get_string_descriptor(dev_handle, desc_index, langid, tbuf,
sizeof(tbuf));
@@ -1176,7 +1177,8 @@ int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev_ha
if (tbuf[0] > r)
return LIBUSB_ERROR_IO;

for (di = 0, si = 2; si < tbuf[0]; si += 2) {
di = 0;
for (si = 2; si < tbuf[0]; si += 2) {
if (di >= (length - 1))
break;

@@ -154,36 +154,30 @@ int main (void) {
\endcode
*/

static int usbi_hotplug_match_cb (struct libusb_context *ctx,
static int usbi_hotplug_match_cb(struct libusb_context *ctx,
struct libusb_device *dev, libusb_hotplug_event event,
struct libusb_hotplug_callback *hotplug_cb)
{
/* Handle lazy deregistration of callback */
if (hotplug_cb->needs_free) {
/* Free callback */
return 1;
}

if (!(hotplug_cb->events & event)) {
if (!(hotplug_cb->flags & event)) {
return 0;
}

if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->vendor_id &&
if ((hotplug_cb->flags & USBI_HOTPLUG_VENDOR_ID_VALID) &&
hotplug_cb->vendor_id != dev->device_descriptor.idVendor) {
return 0;
}

if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->product_id &&
if ((hotplug_cb->flags & USBI_HOTPLUG_PRODUCT_ID_VALID) &&
hotplug_cb->product_id != dev->device_descriptor.idProduct) {
return 0;
}

if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->dev_class &&
if ((hotplug_cb->flags & USBI_HOTPLUG_DEV_CLASS_VALID) &&
hotplug_cb->dev_class != dev->device_descriptor.bDeviceClass) {
return 0;
}

return hotplug_cb->cb (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,
@@ -195,8 +189,13 @@ void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
usbi_mutex_lock(&ctx->hotplug_cbs_lock);

list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
if (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE) {
/* process deregistration in usbi_hotplug_deregister() */
continue;
}

usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
ret = usbi_hotplug_match_cb (ctx, dev, event, hotplug_cb);
ret = usbi_hotplug_match_cb(ctx, dev, event, hotplug_cb);
usbi_mutex_lock(&ctx->hotplug_cbs_lock);

if (ret) {
@@ -206,15 +205,13 @@ void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
}

usbi_mutex_unlock(&ctx->hotplug_cbs_lock);

/* the backend is expected to call the callback for each active transfer */
}

void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev,
libusb_hotplug_event event)
{
int pending_events;
libusb_hotplug_message *message = calloc(1, sizeof(*message));
struct libusb_hotplug_message *message = calloc(1, sizeof(*message));

if (!message) {
usbi_err(ctx, "error allocating hotplug message");
@@ -240,59 +237,70 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
libusb_hotplug_callback_fn cb_fn, void *user_data,
libusb_hotplug_callback_handle *callback_handle)
{
libusb_hotplug_callback *new_callback;
static int handle_id = 1;

/* check for hotplug support */
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
return LIBUSB_ERROR_NOT_SUPPORTED;
}
struct libusb_hotplug_callback *new_callback;

/* check for sane values */
if ((LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) ||
if ((!events || (~(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) & events)) ||
(flags && (~LIBUSB_HOTPLUG_ENUMERATE & flags)) ||
(LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) ||
(LIBUSB_HOTPLUG_MATCH_ANY != product_id && (~0xffff & product_id)) ||
(LIBUSB_HOTPLUG_MATCH_ANY != dev_class && (~0xff & dev_class)) ||
!cb_fn) {
return LIBUSB_ERROR_INVALID_PARAM;
}

/* check for hotplug support */
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
return LIBUSB_ERROR_NOT_SUPPORTED;
}

USBI_GET_CONTEXT(ctx);

new_callback = (libusb_hotplug_callback *)calloc(1, sizeof (*new_callback));
new_callback = calloc(1, sizeof(*new_callback));
if (!new_callback) {
return LIBUSB_ERROR_NO_MEM;
}

new_callback->ctx = ctx;
new_callback->vendor_id = vendor_id;
new_callback->product_id = product_id;
new_callback->dev_class = dev_class;
new_callback->flags = flags;
new_callback->events = events;
new_callback->flags = (uint8_t)events;
if (LIBUSB_HOTPLUG_MATCH_ANY != vendor_id) {
new_callback->flags |= USBI_HOTPLUG_VENDOR_ID_VALID;
new_callback->vendor_id = (uint16_t)vendor_id;
}
if (LIBUSB_HOTPLUG_MATCH_ANY != product_id) {
new_callback->flags |= USBI_HOTPLUG_PRODUCT_ID_VALID;
new_callback->product_id = (uint16_t)product_id;
}
if (LIBUSB_HOTPLUG_MATCH_ANY != dev_class) {
new_callback->flags |= USBI_HOTPLUG_DEV_CLASS_VALID;
new_callback->dev_class = (uint8_t)dev_class;
}
new_callback->cb = cb_fn;
new_callback->user_data = user_data;
new_callback->needs_free = 0;

usbi_mutex_lock(&ctx->hotplug_cbs_lock);

/* protect the handle by the context hotplug lock. it doesn't matter if the same handle
* is used for different contexts only that the handle is unique for this context */
new_callback->handle = handle_id++;
/* protect the handle by the context hotplug lock */
new_callback->handle = ctx->next_hotplug_cb_handle++;

/* handle the unlikely case of overflow */
if (ctx->next_hotplug_cb_handle < 0)
ctx->next_hotplug_cb_handle = 1;

list_add(&new_callback->list, &ctx->hotplug_cbs);

usbi_mutex_unlock(&ctx->hotplug_cbs_lock);

usbi_dbg("new hotplug cb %p with handle %d", new_callback, new_callback->handle);

if (flags & LIBUSB_HOTPLUG_ENUMERATE) {
int i, len;
if ((flags & LIBUSB_HOTPLUG_ENUMERATE) && (events & LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)) {
ssize_t i, len;
struct libusb_device **devs;

len = (int) libusb_get_device_list(ctx, &devs);
len = libusb_get_device_list(ctx, &devs);
if (len < 0) {
libusb_hotplug_deregister_callback(ctx,
new_callback->handle);
return len;
return (int)len;
}

for (i = 0; i < len; i++) {
@@ -311,10 +319,11 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
return LIBUSB_SUCCESS;
}

void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx,
void API_EXPORTED libusb_hotplug_deregister_callback(struct libusb_context *ctx,
libusb_hotplug_callback_handle callback_handle)
{
struct libusb_hotplug_callback *hotplug_cb;
int deregistered = 0;

/* check for hotplug support */
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
@@ -323,28 +332,42 @@ void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx

USBI_GET_CONTEXT(ctx);

usbi_dbg("deregister hotplug cb %d", callback_handle);

usbi_mutex_lock(&ctx->hotplug_cbs_lock);
list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list,
struct libusb_hotplug_callback) {
list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
if (callback_handle == hotplug_cb->handle) {
/* Mark this callback for deregistration */
hotplug_cb->needs_free = 1;
hotplug_cb->flags |= USBI_HOTPLUG_NEEDS_FREE;
deregistered = 1;
}
}
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);

usbi_hotplug_notification(ctx, NULL, 0);
if (deregistered) {
int pending_events;

usbi_mutex_lock(&ctx->event_data_lock);
pending_events = usbi_pending_events(ctx);
ctx->event_flags |= USBI_EVENT_HOTPLUG_CB_DEREGISTERED;
if (!pending_events)
usbi_signal_event(ctx);
usbi_mutex_unlock(&ctx->event_data_lock);
}
}

void usbi_hotplug_deregister_all(struct libusb_context *ctx) {
void usbi_hotplug_deregister(struct libusb_context *ctx, int forced)
{
struct libusb_hotplug_callback *hotplug_cb, *next;

usbi_mutex_lock(&ctx->hotplug_cbs_lock);
list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list,
struct libusb_hotplug_callback) {
list_del(&hotplug_cb->list);
free(hotplug_cb);
list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
if (forced || (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE)) {
usbi_dbg("freeing hotplug cb %p with handle %d", hotplug_cb,
hotplug_cb->handle);
list_del(&hotplug_cb->list);
free(hotplug_cb);
}
}

usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
}
@@ -19,36 +19,52 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#if !defined(USBI_HOTPLUG_H)
#ifndef USBI_HOTPLUG_H
#define USBI_HOTPLUG_H

#ifndef LIBUSBI_H
#include "libusbi.h"
#endif

enum usbi_hotplug_flags {
/* This callback is interested in device arrivals */
USBI_HOTPLUG_DEVICE_ARRIVED = LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED,

/* This callback is interested in device removals */
USBI_HOTPLUG_DEVICE_LEFT = LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,

/* IMPORTANT: The values for the below entries must start *after*
* the highest value of the above entries!!!
*/

/* The vendor_id field is valid for matching */
USBI_HOTPLUG_VENDOR_ID_VALID = (1U << 3),

/* The product_id field is valid for matching */
USBI_HOTPLUG_PRODUCT_ID_VALID = (1U << 4),

/* The dev_class field is valid for matching */
USBI_HOTPLUG_DEV_CLASS_VALID = (1U << 5),

/* This callback has been unregistered and needs to be freed */
USBI_HOTPLUG_NEEDS_FREE = (1U << 6),
};

/** \ingroup hotplug
* The hotplug callback structure. The user populates this structure with
* libusb_hotplug_prepare_callback() and then calls libusb_hotplug_register_callback()
* to receive notification of hotplug events.
*/
struct libusb_hotplug_callback {
/** Context this callback is associated with */
struct libusb_context *ctx;

/** Vendor ID to match or LIBUSB_HOTPLUG_MATCH_ANY */
int vendor_id;

/** Product ID to match or LIBUSB_HOTPLUG_MATCH_ANY */
int product_id;
/** Flags that control how this callback behaves */
uint8_t flags;

/** Device class to match or LIBUSB_HOTPLUG_MATCH_ANY */
int dev_class;
/** Vendor ID to match (if flags says this is valid) */
uint16_t vendor_id;

/** Hotplug callback flags */
libusb_hotplug_flag flags;
/** Product ID to match (if flags says this is valid) */
uint16_t product_id;

/** Event(s) that will trigger this callback */
libusb_hotplug_event events;
/** Device class to match (if flags says this is valid) */
uint8_t dev_class;

/** Callback function to invoke for matching event/device */
libusb_hotplug_callback_fn cb;
@@ -59,15 +75,10 @@ struct libusb_hotplug_callback {
/** User data that will be passed to the callback function */
void *user_data;

/** Callback is marked for deletion */
int needs_free;

/** List this callback is registered in (ctx->hotplug_cbs) */
struct list_head list;
};

typedef struct libusb_hotplug_callback libusb_hotplug_callback;

struct libusb_hotplug_message {
/** The hotplug event that occurred */
libusb_hotplug_event event;
@@ -79,9 +90,7 @@ struct libusb_hotplug_message {
struct list_head list;
};

typedef struct libusb_hotplug_message libusb_hotplug_message;

void usbi_hotplug_deregister_all(struct libusb_context *ctx);
void usbi_hotplug_deregister(struct libusb_context *ctx, int forced);
void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
libusb_hotplug_event event);
void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev,
@@ -27,9 +27,6 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
@@ -1147,8 +1144,8 @@ int usbi_io_init(struct libusb_context *ctx)
goto err_close_pipe;

#ifdef USBI_TIMERFD_AVAILABLE
ctx->timerfd = timerfd_create(usbi_backend->get_timerfd_clockid(),
TFD_NONBLOCK);
ctx->timerfd = timerfd_create(usbi_backend.get_timerfd_clockid(),
TFD_NONBLOCK | TFD_CLOEXEC);
if (ctx->timerfd >= 0) {
usbi_dbg("using timerfd for timeouts");
r = usbi_add_pollfd(ctx, ctx->timerfd, POLLIN);
@@ -1197,8 +1194,7 @@ void usbi_io_exit(struct libusb_context *ctx)
usbi_cond_destroy(&ctx->event_waiters_cond);
usbi_mutex_destroy(&ctx->event_data_lock);
usbi_tls_key_delete(ctx->event_handling_key);
if (ctx->pollfds)
free(ctx->pollfds);
free(ctx->pollfds);
}

static int calculate_timeout(struct usbi_transfer *transfer)
@@ -1208,10 +1204,12 @@ static int calculate_timeout(struct usbi_transfer *transfer)
unsigned int timeout =
USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)->timeout;

if (!timeout)
if (!timeout) {
timerclear(&transfer->timeout);
return 0;
}

r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &current_time);
r = usbi_backend.clock_gettime(USBI_CLOCK_MONOTONIC, &current_time);
if (r < 0) {
usbi_err(ITRANSFER_CTX(transfer),
"failed to read monotonic clock, errno=%d", errno);
@@ -1250,20 +1248,26 @@ static int calculate_timeout(struct usbi_transfer *transfer)
* use it on a non-isochronous endpoint. If you do this, ensure that at time
* of submission, num_iso_packets is 0 and that type is set appropriately.
*
* \param iso_packets number of isochronous packet descriptors to allocate
* \param iso_packets number of isochronous packet descriptors to allocate. Must be non-negative.
* \returns a newly allocated transfer, or NULL on error
*/
DEFAULT_VISIBILITY
struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(
int iso_packets)
{
struct libusb_transfer *transfer;
size_t os_alloc_size = usbi_backend->transfer_priv_size;
size_t alloc_size = sizeof(struct usbi_transfer)
size_t os_alloc_size;
size_t alloc_size;
struct usbi_transfer *itransfer;

assert(iso_packets >= 0);

os_alloc_size = usbi_backend.transfer_priv_size;
alloc_size = sizeof(struct usbi_transfer)
+ sizeof(struct libusb_transfer)
+ (sizeof(struct libusb_iso_packet_descriptor) * iso_packets)
+ (sizeof(struct libusb_iso_packet_descriptor) * (size_t)iso_packets)
+ os_alloc_size;
struct usbi_transfer *itransfer = calloc(1, alloc_size);
itransfer = calloc(1, alloc_size);
if (!itransfer)
return NULL;

@@ -1298,7 +1302,7 @@ void API_EXPORTED libusb_free_transfer(struct libusb_transfer *transfer)
return;

usbi_dbg("transfer %p", transfer);
if (transfer->flags & LIBUSB_TRANSFER_FREE_BUFFER && transfer->buffer)
if (transfer->flags & LIBUSB_TRANSFER_FREE_BUFFER)
free(transfer->buffer);

itransfer = LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);
@@ -1529,7 +1533,7 @@ int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer)
*/
usbi_mutex_unlock(&ctx->flying_transfers_lock);

r = usbi_backend->submit_transfer(itransfer);
r = usbi_backend.submit_transfer(itransfer);
if (r == LIBUSB_SUCCESS) {
itransfer->state_flags |= USBI_TRANSFER_IN_FLIGHT;
/* keep a reference to this device */
@@ -1570,7 +1574,7 @@ int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer)
r = LIBUSB_ERROR_NOT_FOUND;
goto out;
}
r = usbi_backend->cancel_transfer(itransfer);
r = usbi_backend.cancel_transfer(itransfer);
if (r < 0) {
if (r != LIBUSB_ERROR_NOT_FOUND &&
r != LIBUSB_ERROR_NO_DEVICE)
@@ -1707,15 +1711,19 @@ int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer)
* function will be called the next time an event handler runs. */
void usbi_signal_transfer_completion(struct usbi_transfer *transfer)
{
struct libusb_context *ctx = ITRANSFER_CTX(transfer);
int pending_events;
libusb_device_handle *dev_handle = USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)->dev_handle;

usbi_mutex_lock(&ctx->event_data_lock);
pending_events = usbi_pending_events(ctx);
list_add_tail(&transfer->completed_list, &ctx->completed_transfers);
if (!pending_events)
usbi_signal_event(ctx);
usbi_mutex_unlock(&ctx->event_data_lock);
if (dev_handle) {
struct libusb_context *ctx = HANDLE_CTX(dev_handle);
int pending_events;

usbi_mutex_lock(&ctx->event_data_lock);
pending_events = usbi_pending_events(ctx);
list_add_tail(&transfer->completed_list, &ctx->completed_transfers);
if (!pending_events)
usbi_signal_event(ctx);
usbi_mutex_unlock(&ctx->event_data_lock);
}
}

/** \ingroup libusb_poll
@@ -1887,14 +1895,17 @@ int API_EXPORTED libusb_event_handler_active(libusb_context *ctx)
*/
void API_EXPORTED libusb_interrupt_event_handler(libusb_context *ctx)
{
int pending_events;
USBI_GET_CONTEXT(ctx);

usbi_dbg("");
usbi_mutex_lock(&ctx->event_data_lock);
if (!usbi_pending_events(ctx)) {
ctx->event_flags |= USBI_EVENT_USER_INTERRUPT;

pending_events = usbi_pending_events(ctx);
ctx->event_flags |= USBI_EVENT_USER_INTERRUPT;
if (!pending_events)
usbi_signal_event(ctx);
}

usbi_mutex_unlock(&ctx->event_data_lock);
}

@@ -2004,7 +2015,7 @@ static int handle_timeouts_locked(struct libusb_context *ctx)
return 0;

/* get current time */
r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &systime_ts);
r = usbi_backend.clock_gettime(USBI_CLOCK_MONOTONIC, &systime_ts);
if (r < 0)
return r;

@@ -2077,13 +2088,19 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
struct pollfd *fds = NULL;
int i = -1;
int timeout_ms;
int special_event;

/* prevent attempts to recursively handle events (e.g. calling into
* libusb_handle_events() from within a hotplug or transfer callback) */
usbi_mutex_lock(&ctx->event_data_lock);
r = 0;
if (usbi_handling_events(ctx))
return LIBUSB_ERROR_BUSY;
usbi_start_event_handling(ctx);
r = LIBUSB_ERROR_BUSY;
else
usbi_start_event_handling(ctx);
usbi_mutex_unlock(&ctx->event_data_lock);

if (r)
return r;

/* there are certain fds that libusb uses internally, currently:
*
@@ -2105,10 +2122,8 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
if (ctx->event_flags & USBI_EVENT_POLLFDS_MODIFIED) {
usbi_dbg("poll fds modified, reallocating");

if (ctx->pollfds) {
free(ctx->pollfds);
ctx->pollfds = NULL;
}
free(ctx->pollfds);
ctx->pollfds = NULL;

/* sanity check - it is invalid for a context to have fewer than the
* required internal fds (memory corruption?) */
@@ -2138,6 +2153,7 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
}
fds = ctx->pollfds;
nfds = ctx->pollfds_cnt;
usbi_inc_fds_ref(fds, nfds);
usbi_mutex_unlock(&ctx->event_data_lock);

timeout_ms = (int)(tv->tv_sec * 1000) + (tv->tv_usec / 1000);
@@ -2146,32 +2162,30 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
if (tv->tv_usec % 1000)
timeout_ms++;

redo_poll:
usbi_dbg("poll() %d fds with timeout in %dms", nfds, timeout_ms);
r = usbi_poll(fds, nfds, timeout_ms);
usbi_dbg("poll() returned %d", r);
if (r == 0) {
r = handle_timeouts(ctx);
goto done;
}
else if (r == -1 && errno == EINTR) {
} else if (r == -1 && errno == EINTR) {
r = LIBUSB_ERROR_INTERRUPTED;
goto done;
}
else if (r < 0) {
} else if (r < 0) {
usbi_err(ctx, "poll failed %d err=%d", r, errno);
r = LIBUSB_ERROR_IO;
goto done;
}

special_event = 0;

/* fds[0] is always the event pipe */
if (fds[0].revents) {
libusb_hotplug_message *message = NULL;
struct list_head hotplug_msgs;
struct usbi_transfer *itransfer;
int hotplug_cb_deregistered = 0;
int ret = 0;

list_init(&hotplug_msgs);

usbi_dbg("caught a fish on the event pipe");

/* take the the event data lock while processing events */
@@ -2186,24 +2200,28 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
ctx->event_flags &= ~USBI_EVENT_USER_INTERRUPT;
}

if (ctx->event_flags & USBI_EVENT_HOTPLUG_CB_DEREGISTERED) {
usbi_dbg("someone unregistered a hotplug cb");
ctx->event_flags &= ~USBI_EVENT_HOTPLUG_CB_DEREGISTERED;
hotplug_cb_deregistered = 1;
}

/* check if someone is closing a device */
if (ctx->device_close)
usbi_dbg("someone is closing a device");

/* check for any pending hotplug messages */
if (!list_empty(&ctx->hotplug_msgs)) {
usbi_dbg("hotplug message received");
special_event = 1;
message = list_first_entry(&ctx->hotplug_msgs, libusb_hotplug_message, list);
list_del(&message->list);
list_cut(&hotplug_msgs, &ctx->hotplug_msgs);
}

/* complete any pending transfers */
while (ret == 0 && !list_empty(&ctx->completed_transfers)) {
itransfer = list_first_entry(&ctx->completed_transfers, struct usbi_transfer, completed_list);
list_del(&itransfer->completed_list);
usbi_mutex_unlock(&ctx->event_data_lock);
ret = usbi_backend->handle_transfer_completion(itransfer);
ret = usbi_backend.handle_transfer_completion(itransfer);
if (ret)
usbi_err(ctx, "backend handle_transfer_completion failed with error %d", ret);
usbi_mutex_lock(&ctx->event_data_lock);
@@ -2215,14 +2233,21 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)

usbi_mutex_unlock(&ctx->event_data_lock);

/* process the hotplug message, if any */
if (message) {
if (hotplug_cb_deregistered)
usbi_hotplug_deregister(ctx, 0);

/* process the hotplug messages, if any */
while (!list_empty(&hotplug_msgs)) {
struct libusb_hotplug_message *message =
list_first_entry(&hotplug_msgs, struct libusb_hotplug_message, list);

usbi_hotplug_match(ctx, message->device, message->event);

/* the device left, dereference the device */
if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == message->event)
libusb_unref_device(message->device);

list_del(&message->list);
free(message);
}

@@ -2233,7 +2258,7 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
}

if (0 == --r)
goto handled;
goto done;
}

#ifdef USBI_TIMERFD_AVAILABLE
@@ -2242,7 +2267,6 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
/* timerfd indicates that a timeout has expired */
int ret;
usbi_dbg("timerfd triggered");
special_event = 1;

ret = handle_timerfd_trigger(ctx);
if (ret < 0) {
@@ -2252,22 +2276,17 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
}

if (0 == --r)
goto handled;
goto done;
}
#endif

r = usbi_backend->handle_events(ctx, fds + internal_nfds, nfds - internal_nfds, r);
r = usbi_backend.handle_events(ctx, fds + internal_nfds, nfds - internal_nfds, r);
if (r)
usbi_err(ctx, "backend handle_events failed with error %d", r);

handled:
if (r == 0 && special_event) {
timeout_ms = 0;
goto redo_poll;
}

done:
usbi_end_event_handling(ctx);
usbi_dec_fds_ref(fds, nfds);
return r;
}

@@ -2583,7 +2602,7 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx,
return 0;
}

r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &cur_ts);
r = usbi_backend.clock_gettime(USBI_CLOCK_MONOTONIC, &cur_ts);
if (r < 0) {
usbi_err(ctx, "failed to read monotonic clock, errno=%d", errno);
return 0;
@@ -2595,7 +2614,7 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx,
timerclear(tv);
} else {
timersub(&next_timeout, &cur_tv, tv);
usbi_dbg("next timeout in %d.%06ds", tv->tv_sec, tv->tv_usec);
usbi_dbg("next timeout in %ld.%06lds", (long)tv->tv_sec, (long)tv->tv_usec);
}

return 1;
@@ -2752,15 +2771,12 @@ const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds(
* Since version 1.0.20, \ref LIBUSB_API_VERSION >= 0x01000104
*
* It is legal to call this function with a NULL pollfd list. In this case,
* the function will simply return safely.
* the function will simply do nothing.
*
* \param pollfds the list of libusb_pollfd structures to free
*/
void API_EXPORTED libusb_free_pollfds(const struct libusb_pollfd **pollfds)
{
if (!pollfds)
return;

free((void *)pollfds);
}

@@ -2811,7 +2827,7 @@ void usbi_handle_disconnect(struct libusb_device_handle *dev_handle)
USBI_TRANSFER_TO_LIBUSB_TRANSFER(to_cancel));

usbi_mutex_lock(&to_cancel->lock);
usbi_backend->clear_transfer_priv(to_cancel);
usbi_backend.clear_transfer_priv(to_cancel);
usbi_mutex_unlock(&to_cancel->lock);
usbi_handle_transfer_completion(to_cancel, LIBUSB_TRANSFER_NO_DEVICE);
}
@@ -126,10 +126,10 @@ EXPORTS
libusb_interrupt_transfer@24 = libusb_interrupt_transfer
libusb_kernel_driver_active
libusb_kernel_driver_active@8 = libusb_kernel_driver_active
libusb_lock_events
libusb_lock_events@4 = libusb_lock_events
libusb_lock_event_waiters
libusb_lock_event_waiters@4 = libusb_lock_event_waiters
libusb_lock_events
libusb_lock_events@4 = libusb_lock_events
libusb_open
libusb_open@8 = libusb_open
libusb_open_device_with_vid_pid
@@ -148,12 +148,16 @@ EXPORTS
libusb_set_configuration@8 = libusb_set_configuration
libusb_set_debug
libusb_set_debug@8 = libusb_set_debug
libusb_set_log_cb
libusb_set_log_cb@12 = libusb_set_log_cb
libusb_set_interface_alt_setting
libusb_set_interface_alt_setting@12 = libusb_set_interface_alt_setting
libusb_setlocale
libusb_setlocale@4 = libusb_setlocale
libusb_set_option
_libusb_set_option = libusb_set_option
libusb_set_pollfd_notifiers
libusb_set_pollfd_notifiers@16 = libusb_set_pollfd_notifiers
libusb_setlocale
libusb_setlocale@4 = libusb_setlocale
libusb_strerror
libusb_strerror@4 = libusb_strerror
libusb_submit_transfer
@@ -164,10 +168,10 @@ EXPORTS
libusb_transfer_set_stream_id@8 = libusb_transfer_set_stream_id
libusb_try_lock_events
libusb_try_lock_events@4 = libusb_try_lock_events
libusb_unlock_events
libusb_unlock_events@4 = libusb_unlock_events
libusb_unlock_event_waiters
libusb_unlock_event_waiters@4 = libusb_unlock_event_waiters
libusb_unlock_events
libusb_unlock_events@4 = libusb_unlock_events
libusb_unref_device
libusb_unref_device@4 = libusb_unref_device
libusb_wait_for_event
@@ -3,7 +3,7 @@
* Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com>
* Copyright © 2007-2008 Daniel Drake <dsd@gentoo.org>
* Copyright © 2012 Pete Batard <pete@akeo.ie>
* Copyright © 2012 Nathan Hjelm <hjelmn@cs.unm.edu>
* Copyright © 2012-2018 Nathan Hjelm <hjelmn@cs.unm.edu>
* For more information, please visit: http://libusb.info
*
* This library is free software; you can redistribute it and/or
@@ -54,13 +54,19 @@ typedef unsigned __int32 uint32_t;
#include <sys/types.h>
#endif

#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__HAIKU__)
#if defined(__linux__) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__HAIKU__)
#include <sys/time.h>
#endif

#include <time.h>
#include <limits.h>

#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
#define ZERO_SIZED_ARRAY /* [] - valid C99 code */
#else
#define ZERO_SIZED_ARRAY 0 /* [0] - non-standard, but usually working code */
#endif

/* 'interface' might be defined as a macro on Windows, so we need to
* undefine it so as not to break the current libusb API, because
* libusb_config_descriptor has an 'interface' member
@@ -79,6 +85,8 @@ typedef unsigned __int32 uint32_t;
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
#define LIBUSB_DEPRECATED_FOR(f) \
__attribute__((deprecated("Use " #f " instead")))
#elif __GNUC__ >= 3
#define LIBUSB_DEPRECATED_FOR(f) __attribute__((deprecated))
#else
#define LIBUSB_DEPRECATED_FOR(f)
#endif /* __GNUC__ */
@@ -141,7 +149,7 @@ typedef unsigned __int32 uint32_t;
* Internally, LIBUSB_API_VERSION is defined as follows:
* (libusb major << 24) | (libusb minor << 16) | (16 bit incremental)
*/
#define LIBUSB_API_VERSION 0x01000105
#define LIBUSB_API_VERSION 0x01000107

/* The following is kept for compatibility, but will be deprecated in the future */
#define LIBUSBX_API_VERSION LIBUSB_API_VERSION
@@ -569,7 +577,7 @@ struct libusb_endpoint_descriptor {
* it will store them here, should you wish to parse them. */
const unsigned char *extra;

/** Length of the extra descriptors, in bytes. */
/** Length of the extra descriptors, in bytes. Must be non-negative. */
int extra_length;
};

@@ -619,7 +627,7 @@ struct libusb_interface_descriptor {
* it will store them here, should you wish to parse them. */
const unsigned char *extra;

/** Length of the extra descriptors, in bytes. */
/** Length of the extra descriptors, in bytes. Must be non-negative. */
int extra_length;
};

@@ -631,7 +639,8 @@ struct libusb_interface {
* by the num_altsetting field. */
const struct libusb_interface_descriptor *altsetting;

/** The number of alternate settings that belong to this interface */
/** The number of alternate settings that belong to this interface.
* Must be non-negative. */
int num_altsetting;
};

@@ -678,7 +687,7 @@ struct libusb_config_descriptor {
* descriptors, it will store them here, should you wish to parse them. */
const unsigned char *extra;

/** Length of the extra descriptors, in bytes. */
/** Length of the extra descriptors, in bytes. Must be non-negative. */
int extra_length;
};

@@ -729,13 +738,7 @@ struct libusb_bos_dev_capability_descriptor {
/** Device Capability type */
uint8_t bDevCapabilityType;
/** Device Capability data (bLength - 3 bytes) */
uint8_t dev_capability_data
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
[] /* valid C99 code */
#else
[0] /* non-standard, but usually working code */
#endif
;
uint8_t dev_capability_data[ZERO_SIZED_ARRAY];
};

/** \ingroup libusb_desc
@@ -760,13 +763,7 @@ struct libusb_bos_descriptor {
uint8_t bNumDeviceCaps;

/** bNumDeviceCap Device Capability Descriptors */
struct libusb_bos_dev_capability_descriptor *dev_capability
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
[] /* valid C99 code */
#else
[0] /* non-standard, but usually working code */
#endif
;
struct libusb_bos_dev_capability_descriptor *dev_capability[ZERO_SIZED_ARRAY];
};

/** \ingroup libusb_desc
@@ -927,7 +924,7 @@ struct libusb_version {
* sessions allows for your program to use two libraries (or dynamically
* load two modules) which both independently use libusb. This will prevent
* interference between the individual libusb users - for example
* libusb_set_debug() will not affect the other user of the library, and
* libusb_set_option() will not affect the other user of the library, and
* libusb_exit() will not destroy resources that the other user is still
* using.
*
@@ -987,6 +984,9 @@ enum libusb_speed {

/** The device is operating at super speed (5000MBit/s). */
LIBUSB_SPEED_SUPER = 4,

/** The device is operating at super speed plus (10000MBit/s). */
LIBUSB_SPEED_SUPER_PLUS = 5,
};

/** \ingroup libusb_dev
@@ -1135,19 +1135,19 @@ enum libusb_transfer_status {
* libusb_transfer.flags values */
enum libusb_transfer_flags {
/** Report short frames as errors */
LIBUSB_TRANSFER_SHORT_NOT_OK = 1<<0,
LIBUSB_TRANSFER_SHORT_NOT_OK = 1U << 0,

/** Automatically free() transfer buffer during libusb_free_transfer().
* Note that buffers allocated with libusb_dev_mem_alloc() should not
* be attempted freed in this way, since free() is not an appropriate
* way to release such memory. */
LIBUSB_TRANSFER_FREE_BUFFER = 1<<1,
LIBUSB_TRANSFER_FREE_BUFFER = 1U << 1,

/** Automatically call libusb_free_transfer() after callback returns.
* If this flag is set, it is illegal to call libusb_free_transfer()
* from your transfer callback, as this will result in a double-free
* when this flag is acted upon. */
LIBUSB_TRANSFER_FREE_TRANSFER = 1<<2,
LIBUSB_TRANSFER_FREE_TRANSFER = 1U << 2,

/** Terminate transfers that are a multiple of the endpoint's
* wMaxPacketSize with an extra zero length packet. This is useful
@@ -1172,7 +1172,7 @@ enum libusb_transfer_flags {
*
* Available since libusb-1.0.9.
*/
LIBUSB_TRANSFER_ADD_ZERO_PACKET = 1 << 3,
LIBUSB_TRANSFER_ADD_ZERO_PACKET = 1U << 3,
};

/** \ingroup libusb_asyncio
@@ -1220,7 +1220,7 @@ struct libusb_transfer {
/** Type of the endpoint from \ref libusb_transfer_type */
unsigned char type;

/** Timeout for this transfer in millseconds. A value of 0 indicates no
/** Timeout for this transfer in milliseconds. A value of 0 indicates no
* timeout. */
unsigned int timeout;

@@ -1233,7 +1233,7 @@ struct libusb_transfer {
* to determine if errors occurred. */
enum libusb_transfer_status status;

/** Length of the data buffer */
/** Length of the data buffer. Must be non-negative. */
int length;

/** Actual length of data that was transferred. Read-only, and only for
@@ -1252,17 +1252,11 @@ struct libusb_transfer {
unsigned char *buffer;

/** Number of isochronous packets. Only used for I/O with isochronous
* endpoints. */
* endpoints. Must be non-negative. */
int num_iso_packets;

/** Isochronous packet descriptors, for isochronous transfers only. */
struct libusb_iso_packet_descriptor iso_packet_desc
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
[] /* valid C99 code */
#else
[0] /* non-standard, but usually working code */
#endif
;
struct libusb_iso_packet_descriptor iso_packet_desc[ZERO_SIZED_ARRAY];
};

/** \ingroup libusb_misc
@@ -1290,22 +1284,46 @@ enum libusb_capability {
* - LIBUSB_LOG_LEVEL_NONE (0) : no messages ever printed by the library (default)
* - LIBUSB_LOG_LEVEL_ERROR (1) : error messages are printed to stderr
* - LIBUSB_LOG_LEVEL_WARNING (2) : warning and error messages are printed to stderr
* - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stdout, warning
* and error messages are printed to stderr
* - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stdout,
* warnings and errors to stderr
* - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stderr
* - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stderr
*/
enum libusb_log_level {
LIBUSB_LOG_LEVEL_NONE = 0,
LIBUSB_LOG_LEVEL_ERROR,
LIBUSB_LOG_LEVEL_WARNING,
LIBUSB_LOG_LEVEL_INFO,
LIBUSB_LOG_LEVEL_DEBUG,
LIBUSB_LOG_LEVEL_ERROR = 1,
LIBUSB_LOG_LEVEL_WARNING = 2,
LIBUSB_LOG_LEVEL_INFO = 3,
LIBUSB_LOG_LEVEL_DEBUG = 4,
};

/** \ingroup libusb_lib
* Log callback mode.
* \see libusb_set_log_cb()
*/
enum libusb_log_cb_mode {

/** Callback function handling all log mesages. */
LIBUSB_LOG_CB_GLOBAL = 1 << 0,

/** Callback function handling context related log mesages. */
LIBUSB_LOG_CB_CONTEXT = 1 << 1
};

/** \ingroup libusb_lib
* Callback function for handling log messages.
* \param ctx the context which is related to the log message, or NULL if it
* is a global log message
* \param level the log level, see \ref libusb_log_level for a description
* \param str the log message
* \see libusb_set_log_cb()
*/
typedef void (LIBUSB_CALL *libusb_log_cb)(libusb_context *ctx,
enum libusb_log_level level, const char *str);

int LIBUSB_CALL libusb_init(libusb_context **ctx);
void LIBUSB_CALL libusb_exit(libusb_context *ctx);
LIBUSB_DEPRECATED_FOR(libusb_set_option)
void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level);
void LIBUSB_CALL libusb_set_log_cb(libusb_context *ctx, libusb_log_cb cb, int mode);
const struct libusb_version * LIBUSB_CALL libusb_get_version(void);
int LIBUSB_CALL libusb_has_capability(uint32_t capability);
const char * LIBUSB_CALL libusb_error_name(int errcode);
@@ -1370,6 +1388,7 @@ int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev,
int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev,
unsigned char endpoint);

int LIBUSB_CALL libusb_wrap_sys_device(libusb_context *ctx, intptr_t sys_dev, libusb_device_handle **dev_handle);
int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **dev_handle);
void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle);
libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle);
@@ -1892,10 +1911,10 @@ typedef int libusb_hotplug_callback_handle;
* Flags for hotplug events */
typedef enum {
/** Default value when not using any flags. */
LIBUSB_HOTPLUG_NO_FLAGS = 0,
LIBUSB_HOTPLUG_NO_FLAGS = 0U,

/** Arm the callback and fire it for all matching currently attached devices. */
LIBUSB_HOTPLUG_ENUMERATE = 1<<0,
LIBUSB_HOTPLUG_ENUMERATE = 1U << 0,
} libusb_hotplug_flag;

/** \ingroup libusb_hotplug
@@ -1905,12 +1924,12 @@ typedef enum {
* Hotplug events */
typedef enum {
/** A device has been plugged in and is ready to use */
LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED = 0x01,
LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED = 0x01U,

/** A device has left and is no longer available.
* It is the user's responsibility to call libusb_close on any handle associated with a disconnected device.
* It is safe to call libusb_get_device_descriptor on a device that has left */
LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT = 0x02,
LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT = 0x02U,
} libusb_hotplug_event;

/** \ingroup libusb_hotplug
@@ -2001,6 +2020,45 @@ int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx,
void LIBUSB_CALL libusb_hotplug_deregister_callback(libusb_context *ctx,
libusb_hotplug_callback_handle callback_handle);

/** \ingroup libusb_lib
* Available option values for libusb_set_option().
*/
enum libusb_option {
/** Set the log message verbosity.
*
* The default level is LIBUSB_LOG_LEVEL_NONE, which means no messages are ever
* printed. If you choose to increase the message verbosity level, ensure
* that your application does not close the stderr file descriptor.
*
* You are advised to use level LIBUSB_LOG_LEVEL_WARNING. libusb is conservative
* with its message logging and most of the time, will only log messages that
* explain error conditions and other oddities. This will help you debug
* your software.
*
* If the LIBUSB_DEBUG environment variable was set when libusb was
* initialized, this function does nothing: the message verbosity is fixed
* to the value in the environment variable.
*
* If libusb was compiled without any message logging, this function does
* nothing: you'll never get any messages.
*
* If libusb was compiled with verbose debug message logging, this function
* does nothing: you'll always get messages from all levels.
*/
LIBUSB_OPTION_LOG_LEVEL,

/** Use the UsbDk backend for a specific context, if available.
*
* This option should be set immediately after calling libusb_init(), otherwise
* unspecified behavior may occur.
*
* Only valid on Windows.
*/
LIBUSB_OPTION_USE_USBDK,
};

int LIBUSB_CALL libusb_set_option(libusb_context *ctx, enum libusb_option option, ...);

#ifdef __cplusplus
}
#endif

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -1,6 +1,7 @@
/*
* darwin backend for libusb 1.0
* Copyright © 2008-2015 Nathan Hjelm <hjelmn@users.sourceforge.net>
* Copyright © 2008-2019 Nathan Hjelm <hjelmn@users.sourceforge.net>
* Copyright © 2019 Google LLC. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,6 +21,8 @@
#if !defined(LIBUSB_DARWIN_H)
#define LIBUSB_DARWIN_H

#include <stdbool.h>

#include "libusbi.h"

#include <IOKit/IOTypes.h>
@@ -28,81 +31,116 @@
#include <IOKit/IOCFPlugIn.h>

/* IOUSBInterfaceInferface */
#if defined (kIOUSBInterfaceInterfaceID700) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9

/* New in OS 10.12.0. */
#if defined (kIOUSBInterfaceInterfaceID800) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)

#define usb_interface_t IOUSBInterfaceInterface800
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID800
#define InterfaceVersion 800

/* New in OS 10.10.0. */
#elif defined (kIOUSBInterfaceInterfaceID700) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 101000)

#define usb_interface_t IOUSBInterfaceInterface700
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID700
#define InterfaceVersion 700

#elif defined (kIOUSBInterfaceInterfaceID550) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
/* New in OS 10.9.0. */
#elif defined (kIOUSBInterfaceInterfaceID650) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1090)

#define usb_interface_t IOUSBInterfaceInterface650
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID650
#define InterfaceVersion 650

/* New in OS 10.8.2 but can't test deployment target to that granularity, so round up. */
#elif defined (kIOUSBInterfaceInterfaceID550) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1090)

#define usb_interface_t IOUSBInterfaceInterface550
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID550
#define InterfaceVersion 550

#elif defined (kIOUSBInterfaceInterfaceID500)
/* New in OS 10.7.3 but can't test deployment target to that granularity, so round up. */
#elif defined (kIOUSBInterfaceInterfaceID500) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)

#define usb_interface_t IOUSBInterfaceInterface500
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID500
#define InterfaceVersion 500

#elif defined (kIOUSBInterfaceInterfaceID300)
/* New in OS 10.5.0. */
#elif defined (kIOUSBInterfaceInterfaceID300) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)

#define usb_interface_t IOUSBInterfaceInterface300
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID300
#define InterfaceVersion 300

#elif defined (kIOUSBInterfaceInterfaceID245)
/* New in OS 10.4.5 (or 10.4.6?) but can't test deployment target to that granularity, so round up. */
#elif defined (kIOUSBInterfaceInterfaceID245) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)

#define usb_interface_t IOUSBInterfaceInterface245
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID245
#define InterfaceVersion 245

#elif defined (kIOUSBInterfaceInterfaceID220)
/* New in OS 10.4.0. */
#elif defined (kIOUSBInterfaceInterfaceID220) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1040)

#define usb_interface_t IOUSBInterfaceInterface220
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220
#define InterfaceVersion 220

#else

#error "IOUSBFamily is too old. Please upgrade your OS"
#error "IOUSBFamily is too old. Please upgrade your SDK and/or deployment target"

#endif

/* IOUSBDeviceInterface */
#if defined (kIOUSBDeviceInterfaceID500) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9

/* New in OS 10.9.0. */
#if defined (kIOUSBDeviceInterfaceID650) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1090)

#define usb_device_t IOUSBDeviceInterface650
#define DeviceInterfaceID kIOUSBDeviceInterfaceID650
#define DeviceVersion 650

/* New in OS 10.7.3 but can't test deployment target to that granularity, so round up. */
#elif defined (kIOUSBDeviceInterfaceID500) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)

#define usb_device_t IOUSBDeviceInterface500
#define DeviceInterfaceID kIOUSBDeviceInterfaceID500
#define DeviceVersion 500

#elif defined (kIOUSBDeviceInterfaceID320)
/* New in OS 10.5.4 but can't test deployment target to that granularity, so round up. */
#elif defined (kIOUSBDeviceInterfaceID320) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1060)

#define usb_device_t IOUSBDeviceInterface320
#define DeviceInterfaceID kIOUSBDeviceInterfaceID320
#define DeviceVersion 320

#elif defined (kIOUSBDeviceInterfaceID300)
/* New in OS 10.5.0. */
#elif defined (kIOUSBDeviceInterfaceID300) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)

#define usb_device_t IOUSBDeviceInterface300
#define DeviceInterfaceID kIOUSBDeviceInterfaceID300
#define DeviceVersion 300

#elif defined (kIOUSBDeviceInterfaceID245)
/* New in OS 10.4.5 (or 10.4.6?) but can't test deployment target to that granularity, so round up. */
#elif defined (kIOUSBDeviceInterfaceID245) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)

#define usb_device_t IOUSBDeviceInterface245
#define DeviceInterfaceID kIOUSBDeviceInterfaceID245
#define DeviceVersion 245

#elif defined (kIOUSBDeviceInterfaceID220)
/* New in OS 10.2.3 but can't test deployment target to that granularity, so round up. */
#elif defined (kIOUSBDeviceInterfaceID197) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1030)

#define usb_device_t IOUSBDeviceInterface197
#define DeviceInterfaceID kIOUSBDeviceInterfaceID197
#define DeviceVersion 197

#else

#error "IOUSBFamily is too old. Please upgrade your OS"
#error "IOUSBFamily is too old. Please upgrade your SDK and/or deployment target"

#endif

@@ -120,21 +158,22 @@ struct darwin_cached_device {
UInt32 location;
UInt64 parent_session;
UInt64 session;
UInt16 address;
USBDeviceAddress address;
char sys_path[21];
usb_device_t **device;
int open_count;
UInt8 first_config, active_config, port;
int can_enumerate;
int refcount;
bool in_reenumerate;
};

struct darwin_device_priv {
struct darwin_cached_device *dev;
};

struct darwin_device_handle_priv {
int is_open;
bool is_open;
CFRunLoopSourceRef cfSource;

struct darwin_interface {
@@ -243,7 +243,7 @@ USBDeviceHandle::~USBDeviceHandle()
if (fRawFD > 0)
close(fRawFD);
for(int i = 0; i < 32; i++) {
if (fClaimedInterfaces & (1 << i))
if (fClaimedInterfaces & (1U << i))
ReleaseInterface(i);
}
delete_sem(fTransfersSem);
@@ -256,15 +256,15 @@ USBDeviceHandle::ClaimInterface(int inumber)
{
int status = fUSBDevice->ClaimInterface(inumber);
if (status == LIBUSB_SUCCESS)
fClaimedInterfaces |= (1 << inumber);
fClaimedInterfaces |= (1U << inumber);
return status;
}

int
USBDeviceHandle::ReleaseInterface(int inumber)
{
fUSBDevice->ReleaseInterface(inumber);
fClaimedInterfaces &= ~(1 << inumber);
fClaimedInterfaces &= ~(1U << inumber);
return LIBUSB_SUCCESS;
}

@@ -388,15 +388,15 @@ int USBDevice::ClaimInterface(int interface)
{
if (interface > ActiveConfiguration()->number_interfaces)
return LIBUSB_ERROR_NOT_FOUND;
if (fClaimedInterfaces & (1 << interface))
if (fClaimedInterfaces & (1U << interface))
return LIBUSB_ERROR_BUSY;
fClaimedInterfaces |= (1 << interface);
fClaimedInterfaces |= (1U << interface);
return LIBUSB_SUCCESS;
}

int USBDevice::ReleaseInterface(int interface)
{
fClaimedInterfaces &= ~(1 << interface);
fClaimedInterfaces &= ~(1U << interface);
return LIBUSB_SUCCESS;
}

@@ -29,6 +29,9 @@
USBRoster gUsbRoster;
int32 gInitCount = 0;

static int haiku_get_config_descriptor(struct libusb_device *, uint8_t,
unsigned char *, size_t, int *);

static int
haiku_init(struct libusb_context *ctx)
{
@@ -38,8 +41,9 @@ haiku_init(struct libusb_context *ctx)
}

static void
haiku_exit(void)
haiku_exit(struct libusb_context *ctx)
{
UNUSED(ctx);
if (atomic_add(&gInitCount, -1) == 1)
gUsbRoster.Stop();
}
@@ -82,12 +86,7 @@ static int
haiku_get_active_config_descriptor(struct libusb_device *device, unsigned char *buffer, size_t len, int *host_endian)
{
USBDevice *dev = *((USBDevice **)device->os_priv);
const usb_configuration_descriptor *act_config = dev->ActiveConfiguration();
if (len > act_config->total_length)
return LIBUSB_ERROR_OVERFLOW;
memcpy(buffer, act_config, len);
*host_endian = 0;
return LIBUSB_SUCCESS;
return haiku_get_config_descriptor(device, dev->ActiveConfigurationIndex(), buffer, len, host_endian);
}

static int
@@ -99,8 +98,9 @@ haiku_get_config_descriptor(struct libusb_device *device, uint8_t config_index,
usbi_err(DEVICE_CTX(device), "failed getting configuration descriptor");
return LIBUSB_ERROR_INVALID_PARAM;
}
if (len > config->total_length)
if (len > config->total_length) {
len = config->total_length;
}
memcpy(buffer, config, len);
*host_endian = 0;
return len;
@@ -195,56 +195,59 @@ haiku_clock_gettime(int clkid, struct timespec *tp)
return LIBUSB_ERROR_INVALID_PARAM;
}

const struct usbi_os_backend haiku_usb_raw_backend = {
/*.name =*/ "Haiku usbfs",
/*.caps =*/ 0,
/*.init =*/ haiku_init,
/*.exit =*/ haiku_exit,
/*.get_device_list =*/ NULL,
/*.hotplug_poll =*/ NULL,
/*.open =*/ haiku_open,
/*.close =*/ haiku_close,
/*.get_device_descriptor =*/ haiku_get_device_descriptor,
/*.get_active_config_descriptor =*/ haiku_get_active_config_descriptor,
/*.get_config_descriptor =*/ haiku_get_config_descriptor,
/*.get_config_descriptor_by_value =*/ NULL,
const struct usbi_os_backend usbi_backend = {
.name = "Haiku usbfs",
.caps = 0,
.init = haiku_init,
.exit = haiku_exit,
.set_option = NULL,
.get_device_list = NULL,
.hotplug_poll = NULL,
.wrap_sys_device = NULL,
.open = haiku_open,
.close = haiku_close,
.get_device_descriptor = haiku_get_device_descriptor,
.get_active_config_descriptor = haiku_get_active_config_descriptor,
.get_config_descriptor = haiku_get_config_descriptor,
.get_config_descriptor_by_value = NULL,


/*.get_configuration =*/ NULL,
/*.set_configuration =*/ haiku_set_configuration,
/*.claim_interface =*/ haiku_claim_interface,
/*.release_interface =*/ haiku_release_interface,
.get_configuration = NULL,
.set_configuration = haiku_set_configuration,
.claim_interface = haiku_claim_interface,
.release_interface = haiku_release_interface,

/*.set_interface_altsetting =*/ haiku_set_altsetting,
/*.clear_halt =*/ NULL,
/*.reset_device =*/ NULL,
.set_interface_altsetting = haiku_set_altsetting,
.clear_halt = NULL,
.reset_device = NULL,

/*.alloc_streams =*/ NULL,
/*.free_streams =*/ NULL,
.alloc_streams = NULL,
.free_streams = NULL,

/*.dev_mem_alloc =*/ NULL,
/*.dev_mem_free =*/ NULL,
.dev_mem_alloc = NULL,
.dev_mem_free = NULL,

/*.kernel_driver_active =*/ NULL,
/*.detach_kernel_driver =*/ NULL,
/*.attach_kernel_driver =*/ NULL,
.kernel_driver_active = NULL,
.detach_kernel_driver = NULL,
.attach_kernel_driver = NULL,

/*.destroy_device =*/ NULL,
.destroy_device = NULL,

/*.submit_transfer =*/ haiku_submit_transfer,
/*.cancel_transfer =*/ haiku_cancel_transfer,
/*.clear_transfer_priv =*/ haiku_clear_transfer_priv,
.submit_transfer = haiku_submit_transfer,
.cancel_transfer = haiku_cancel_transfer,
.clear_transfer_priv = haiku_clear_transfer_priv,

/*.handle_events =*/ NULL,
/*.handle_transfer_completion =*/ haiku_handle_transfer_completion,
.handle_events = NULL,
.handle_transfer_completion = haiku_handle_transfer_completion,

/*.clock_gettime =*/ haiku_clock_gettime,
.clock_gettime = haiku_clock_gettime,

#ifdef USBI_TIMERFD_AVAILABLE
/*.get_timerfd_clockid =*/ NULL,
.get_timerfd_clockid = NULL,
#endif

/*.device_priv_size =*/ sizeof(USBDevice *),
/*.device_handle_priv_size =*/ sizeof(USBDeviceHandle *),
/*.transfer_priv_size =*/ sizeof(USBTransfer *),
.context_priv_size = 0,
.device_priv_size = sizeof(USBDevice *),
.device_handle_priv_size = sizeof(USBDeviceHandle *),
.transfer_priv_size = sizeof(USBTransfer *),
};
@@ -45,38 +45,48 @@

#define NL_GROUP_KERNEL 1

#ifndef SOCK_CLOEXEC
#define SOCK_CLOEXEC 0
#endif

#ifndef SOCK_NONBLOCK
#define SOCK_NONBLOCK 0
#endif

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);

static int set_fd_cloexec_nb(int fd)
static int set_fd_cloexec_nb(int fd, int socktype)
{
int flags;

#if defined(FD_CLOEXEC)
flags = fcntl(fd, F_GETFD);
if (flags == -1) {
usbi_err(NULL, "failed to get netlink fd flags (%d)", errno);
return -1;
}
/* Make sure the netlink socket file descriptor is marked as CLOEXEC */
if (!(socktype & SOCK_CLOEXEC)) {
flags = fcntl(fd, F_GETFD);
if (flags == -1) {
usbi_err(NULL, "failed to get netlink fd flags (%d)", errno);
return -1;
}

if (!(flags & FD_CLOEXEC)) {
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
usbi_err(NULL, "failed to set netlink fd flags (%d)", errno);
return -1;
}
}
#endif

flags = fcntl(fd, F_GETFL);
if (flags == -1) {
usbi_err(NULL, "failed to get netlink fd status flags (%d)", errno);
return -1;
}
/* Make sure the netlink socket is non-blocking */
if (!(socktype & SOCK_NONBLOCK)) {
flags = fcntl(fd, F_GETFL);
if (flags == -1) {
usbi_err(NULL, "failed to get netlink fd status flags (%d)", errno);
return -1;
}

if (!(flags & O_NONBLOCK)) {
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
usbi_err(NULL, "failed to set netlink fd status flags (%d)", errno);
return -1;
@@ -89,29 +99,23 @@ static int set_fd_cloexec_nb(int fd)
int linux_netlink_start_event_monitor(void)
{
struct sockaddr_nl sa_nl = { .nl_family = AF_NETLINK, .nl_groups = NL_GROUP_KERNEL };
int socktype = SOCK_RAW;
int socktype = SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC;
int opt = 1;
int ret;

#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 (linux_netlink_socket == -1 && errno == EINVAL) {
usbi_dbg("failed to create netlink socket of type %d, attempting SOCK_RAW", socktype);
linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
socktype = SOCK_RAW;
linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT);
}

if (linux_netlink_socket == -1) {
usbi_err(NULL, "failed to create netlink socket (%d)", errno);
goto err;
}

ret = set_fd_cloexec_nb(linux_netlink_socket);
ret = set_fd_cloexec_nb(linux_netlink_socket, socktype);
if (ret == -1)
goto err_close_socket;

@@ -162,7 +166,7 @@ int linux_netlink_stop_event_monitor(void)

/* 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));
r = write(netlink_control_pipe[1], &dummy, sizeof(dummy));
if (r <= 0)
usbi_warn(NULL, "netlink control pipe signal failed");

@@ -356,7 +360,8 @@ static int linux_netlink_read_message(void)
static void *linux_netlink_event_thread_main(void *arg)
{
char dummy;
ssize_t r;
int r;
ssize_t nb;
struct pollfd fds[] = {
{ .fd = netlink_control_pipe[0],
.events = POLLIN },
@@ -368,11 +373,15 @@ static void *linux_netlink_event_thread_main(void *arg)

usbi_dbg("netlink event thread entering");

while (poll(fds, 2, -1) >= 0) {
while ((r = poll(fds, 2, -1)) >= 0 || errno == EINTR) {
if (r < 0) {
/* temporary failure */
continue;
}
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)
nb = read(netlink_control_pipe[0], &dummy, sizeof(dummy));
if (nb <= 0)
usbi_warn(NULL, "netlink control pipe read failed");
break;
}
@@ -82,17 +82,33 @@ int linux_udev_start_event_monitor(void)

udev_monitor_fd = udev_monitor_get_fd(udev_monitor);

#if defined(FD_CLOEXEC)
/* Make sure the udev file descriptor is marked as CLOEXEC */
r = fcntl(udev_monitor_fd, F_GETFD);
if (r == -1) {
usbi_err(NULL, "geting udev monitor fd flags (%d)", errno);
goto err_free_monitor;
}
if (!(r & FD_CLOEXEC)) {
if (fcntl(udev_monitor_fd, F_SETFD, r | FD_CLOEXEC) == -1) {
usbi_err(NULL, "setting udev monitor fd flags (%d)", errno);
goto err_free_monitor;
}
}
#endif

/* Some older versions of udev are not non-blocking by default,
* so make sure this is set */
r = fcntl(udev_monitor_fd, F_GETFL);
if (r == -1) {
usbi_err(NULL, "getting udev monitor fd flags (%d)", errno);
usbi_err(NULL, "getting udev monitor fd status flags (%d)", errno);
goto err_free_monitor;
}
r = fcntl(udev_monitor_fd, F_SETFL, r | O_NONBLOCK);
if (r) {
usbi_err(NULL, "setting udev monitor fd flags (%d)", errno);
goto err_free_monitor;
if (!(r & O_NONBLOCK)) {
if (fcntl(udev_monitor_fd, F_SETFL, r | O_NONBLOCK) == -1) {
usbi_err(NULL, "setting udev monitor fd status flags (%d)", errno);
goto err_free_monitor;
}
}

r = usbi_pipe(udev_control_pipe);
@@ -134,7 +150,7 @@ int linux_udev_stop_event_monitor(void)

/* 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));
r = write(udev_control_pipe[1], &dummy, sizeof(dummy));
if (r <= 0) {
usbi_warn(NULL, "udev control pipe signal failed");
}
@@ -162,6 +178,7 @@ static void *linux_udev_event_thread_main(void *arg)
{
char dummy;
int r;
ssize_t nb;
struct udev_device* udev_dev;
struct pollfd fds[] = {
{.fd = udev_control_pipe[0],
@@ -172,11 +189,15 @@ static void *linux_udev_event_thread_main(void *arg)

usbi_dbg("udev event thread entering.");

while (poll(fds, 2, -1) >= 0) {
while ((r = poll(fds, 2, -1)) >= 0 || errno == EINTR) {
if (r < 0) {
/* temporary failure */
continue;
}
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) {
nb = read(udev_control_pipe[0], &dummy, sizeof(dummy));
if (nb <= 0) {
usbi_warn(NULL, "udev control pipe read failed");
}
break;
@@ -211,7 +232,7 @@ static int udev_device_info(struct libusb_context *ctx, int detached,
}

return linux_get_device_address(ctx, detached, busnum, devaddr,
dev_node, *sys_name);
dev_node, *sys_name, -1);
}

static void udev_hotplug_event(struct udev_device* udev_dev)
@@ -270,6 +291,7 @@ int linux_udev_scan_devices(struct libusb_context *ctx)
udev_enumerate_scan_devices(enumerator);
devices = udev_enumerate_get_list_entry(enumerator);

entry = NULL;
udev_list_entry_foreach(entry, devices) {
const char *path = udev_list_entry_get_name(entry);
uint8_t busnum = 0, devaddr = 0;

Large diffs are not rendered by default.

@@ -81,10 +81,11 @@ struct usbfs_iso_packet_desc {
unsigned int status;
};

#define MAX_ISO_BUFFER_LENGTH 49152 * 128
#define MAX_BULK_BUFFER_LENGTH 16384
#define MAX_CTRL_BUFFER_LENGTH 4096

#define MAX_ISO_PACKETS_PER_URB 128

struct usbfs_urb {
unsigned char type;
unsigned char endpoint;
@@ -186,7 +187,7 @@ void linux_device_disconnected(uint8_t busnum, uint8_t devaddr);

int linux_get_device_address (struct libusb_context *ctx, int detached,
uint8_t *busnum, uint8_t *devaddr, const char *dev_node,
const char *sys_name);
const char *sys_name, int fd);
int linux_enumerate_device(struct libusb_context *ctx,
uint8_t busnum, uint8_t devaddr, const char *sysfs_dir);

@@ -86,11 +86,12 @@ static int _sync_control_transfer(struct usbi_transfer *);
static int _sync_gen_transfer(struct usbi_transfer *);
static int _access_endpoint(struct libusb_transfer *);

const struct usbi_os_backend netbsd_backend = {
const struct usbi_os_backend usbi_backend = {
"Synchronous NetBSD backend",
0,
NULL, /* init() */
NULL, /* exit() */
NULL, /* set_option() */
netbsd_get_device_list,
NULL, /* hotplug_poll */
netbsd_open,
@@ -131,6 +132,7 @@ const struct usbi_os_backend netbsd_backend = {
netbsd_handle_transfer_completion,

netbsd_clock_gettime,
0, /* context_priv_size */
sizeof(struct device_priv),
sizeof(struct handle_priv),
0, /* transfer_priv_size */
@@ -212,8 +214,9 @@ netbsd_get_device_list(struct libusb_context * ctx,
int
netbsd_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;
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
int i;

dpriv->fd = open(dpriv->devnode, O_RDWR);
if (dpriv->fd < 0) {
@@ -222,6 +225,9 @@ netbsd_open(struct libusb_device_handle *handle)
return _errno_to_libusb(errno);
}

for (i = 0; i < USB_MAX_ENDPOINTS; i++)
hpriv->endpoints[i] = -1;

usbi_dbg("open %s: fd %d", dpriv->devnode, dpriv->fd);

return (LIBUSB_SUCCESS);
@@ -230,7 +236,6 @@ netbsd_open(struct libusb_device_handle *handle)
void
netbsd_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);
@@ -89,11 +89,12 @@ static int _access_endpoint(struct libusb_transfer *);
static int _bus_open(int);


const struct usbi_os_backend openbsd_backend = {
const struct usbi_os_backend usbi_backend = {
"Synchronous OpenBSD backend",
0,
NULL, /* init() */
NULL, /* exit() */
NULL, /* set_option() */
obsd_get_device_list,
NULL, /* hotplug_poll */
obsd_open,
@@ -134,6 +135,7 @@ const struct usbi_os_backend openbsd_backend = {
obsd_handle_transfer_completion,

obsd_clock_gettime,
0, /* context_priv_size */
sizeof(struct device_priv),
sizeof(struct handle_priv),
0, /* transfer_priv_size */
@@ -246,7 +248,6 @@ obsd_get_device_list(struct libusb_context * ctx,
int
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];

@@ -270,7 +271,6 @@ obsd_open(struct libusb_device_handle *handle)
void
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;

if (dpriv->devname) {
@@ -29,25 +29,56 @@

int usbi_pipe(int pipefd[2])
{
#if defined(HAVE_PIPE2)
int ret = pipe2(pipefd, O_CLOEXEC);
#else
int ret = pipe(pipefd);
#endif

if (ret != 0) {
usbi_err(NULL, "failed to create pipe (%d)", errno);
return ret;
}

#if !defined(HAVE_PIPE2) && defined(FD_CLOEXEC)
ret = fcntl(pipefd[0], F_GETFD);
if (ret == -1) {
usbi_err(NULL, "failed to get pipe fd flags (%d)", errno);
goto err_close_pipe;
}
ret = fcntl(pipefd[0], F_SETFD, ret | FD_CLOEXEC);
if (ret == -1) {
usbi_err(NULL, "failed to set pipe fd flags (%d)", errno);
goto err_close_pipe;
}

ret = fcntl(pipefd[1], F_GETFD);
if (ret == -1) {
usbi_err(NULL, "failed to get pipe fd flags (%d)", errno);
goto err_close_pipe;
}
ret = fcntl(pipefd[1], F_SETFD, ret | FD_CLOEXEC);
if (ret == -1) {
usbi_err(NULL, "failed to set pipe fd flags (%d)", errno);
goto err_close_pipe;
}
#endif

ret = fcntl(pipefd[1], F_GETFL);
if (ret == -1) {
usbi_dbg("Failed to get pipe fd flags: %d", errno);
usbi_err(NULL, "failed to get pipe fd status flags (%d)", errno);
goto err_close_pipe;
}
ret = fcntl(pipefd[1], F_SETFL, ret | O_NONBLOCK);
if (ret != 0) {
usbi_dbg("Failed to set non-blocking on new pipe: %d", errno);
if (ret == -1) {
usbi_err(NULL, "failed to set pipe fd status flags (%d)", errno);
goto err_close_pipe;
}

return 0;

err_close_pipe:
usbi_close(pipefd[0]);
usbi_close(pipefd[1]);
close(pipefd[0]);
close(pipefd[1]);
return ret;
}
@@ -8,4 +8,7 @@

int usbi_pipe(int pipefd[2]);

#define usbi_inc_fds_ref(x, y)
#define usbi_dec_fds_ref(x, y)

#endif /* LIBUSB_POLL_POSIX_H */

Large diffs are not rendered by default.

@@ -2,6 +2,7 @@
* Windows compat: POSIX compatibility wrapper
* Copyright © 2012-2013 RealVNC Ltd.
* Copyright © 2009-2010 Pete Batard <pete@akeo.ie>
* Copyright © 2016-2018 Chris Dickens <christopher.a.dickens@gmail.com>
* With contributions from Michael Plante, Orin Eman et al.
* Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
*
@@ -40,21 +41,6 @@

#define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2)

/* Windows versions */
enum windows_version {
WINDOWS_CE = -2,
WINDOWS_UNDEFINED = -1,
WINDOWS_UNSUPPORTED = 0,
WINDOWS_XP = 0x51,
WINDOWS_2003 = 0x52, // Also XP x64
WINDOWS_VISTA = 0x60,
WINDOWS_7 = 0x61,
WINDOWS_8 = 0x62,
WINDOWS_8_1_OR_LATER = 0x63,
WINDOWS_MAX
};
extern int windows_version;

#define MAX_FDS 256

#define POLLIN 0x0001 /* There is data to read */
@@ -65,45 +51,28 @@ extern int windows_version;
#define POLLNVAL 0x0020 /* Invalid request: fd not open */

struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};

// access modes
enum rw_type {
RW_NONE,
RW_READ,
RW_WRITE,
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};

// fd struct that can be used for polling on Windows
typedef int cancel_transfer(struct usbi_transfer *itransfer);

struct winfd {
int fd; // what's exposed to libusb core
HANDLE handle; // what we need to attach overlapped to the I/O op, so we can poll it
OVERLAPPED* overlapped; // what will report our I/O status
struct usbi_transfer *itransfer; // Associated transfer, or NULL if completed
cancel_transfer *cancel_fn; // Function pointer to cancel transfer API
enum rw_type rw; // I/O transfer direction: read *XOR* write (NOT BOTH)
int fd; // what's exposed to libusb core
OVERLAPPED *overlapped; // what will report our I/O status
};

extern const struct winfd INVALID_WINFD;

struct winfd usbi_create_fd(void);

int usbi_pipe(int pipefd[2]);
int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout);
ssize_t usbi_write(int fd, const void *buf, size_t count);
ssize_t usbi_read(int fd, void *buf, size_t count);
int usbi_close(int fd);

void init_polling(void);
void exit_polling(void);
struct winfd usbi_create_fd(HANDLE handle, int access_mode,
struct usbi_transfer *transfer, cancel_transfer *cancel_fn);
void usbi_free_fd(struct winfd* winfd);
struct winfd fd_to_winfd(int fd);
struct winfd handle_to_winfd(HANDLE handle);
struct winfd overlapped_to_winfd(OVERLAPPED* overlapped);
int usbi_inc_fds_ref(struct pollfd *fds, unsigned int nfds);
int usbi_dec_fds_ref(struct pollfd *fds, unsigned int nfds);

/*
* Timeval operations